191da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek/* 291da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek * net/dsa/dsa.c - Hardware switch handling 3e84665c9cb4db963393fafad6fefe5efdd7e4a09Lennert Buytenhek * Copyright (c) 2008-2009 Marvell Semiconductor 45e95329b701c4edf6c4d72487ec0369fa148c0bdFlorian Fainelli * Copyright (c) 2013 Florian Fainelli <florian@openwrt.org> 591da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek * 691da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek * This program is free software; you can redistribute it and/or modify 791da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek * it under the terms of the GNU General Public License as published by 891da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek * the Free Software Foundation; either version 2 of the License, or 991da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek * (at your option) any later version. 1091da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek */ 1191da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek 1291da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek#include <linux/list.h> 1391da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek#include <linux/platform_device.h> 145a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h> 153a9a231d977222eea36eae091df2c358e03ac839Paul Gortmaker#include <linux/module.h> 1691da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek#include <net/dsa.h> 175e95329b701c4edf6c4d72487ec0369fa148c0bdFlorian Fainelli#include <linux/of.h> 185e95329b701c4edf6c4d72487ec0369fa148c0bdFlorian Fainelli#include <linux/of_mdio.h> 195e95329b701c4edf6c4d72487ec0369fa148c0bdFlorian Fainelli#include <linux/of_platform.h> 2091da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek#include "dsa_priv.h" 2191da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek 2291da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhekchar dsa_driver_version[] = "0.1"; 2391da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek 2491da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek 2591da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek/* switch driver registration ***********************************************/ 2691da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhekstatic DEFINE_MUTEX(dsa_switch_drivers_mutex); 2791da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhekstatic LIST_HEAD(dsa_switch_drivers); 2891da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek 2991da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhekvoid register_switch_driver(struct dsa_switch_driver *drv) 3091da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek{ 3191da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek mutex_lock(&dsa_switch_drivers_mutex); 3291da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek list_add_tail(&drv->list, &dsa_switch_drivers); 3391da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek mutex_unlock(&dsa_switch_drivers_mutex); 3491da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek} 35ad293b8a218ca13a9ee3e3c98137fa301987577cBen HutchingsEXPORT_SYMBOL_GPL(register_switch_driver); 3691da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek 3791da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhekvoid unregister_switch_driver(struct dsa_switch_driver *drv) 3891da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek{ 3991da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek mutex_lock(&dsa_switch_drivers_mutex); 4091da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek list_del_init(&drv->list); 4191da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek mutex_unlock(&dsa_switch_drivers_mutex); 4291da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek} 43ad293b8a218ca13a9ee3e3c98137fa301987577cBen HutchingsEXPORT_SYMBOL_GPL(unregister_switch_driver); 4491da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek 4591da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhekstatic struct dsa_switch_driver * 46b4d2394d01bc642e95b2cba956d908423c1bef77Alexander Duyckdsa_switch_probe(struct device *host_dev, int sw_addr, char **_name) 4791da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek{ 4891da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek struct dsa_switch_driver *ret; 4991da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek struct list_head *list; 5091da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek char *name; 5191da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek 5291da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek ret = NULL; 5391da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek name = NULL; 5491da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek 5591da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek mutex_lock(&dsa_switch_drivers_mutex); 5691da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek list_for_each(list, &dsa_switch_drivers) { 5791da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek struct dsa_switch_driver *drv; 5891da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek 5991da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek drv = list_entry(list, struct dsa_switch_driver, list); 6091da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek 61b4d2394d01bc642e95b2cba956d908423c1bef77Alexander Duyck name = drv->probe(host_dev, sw_addr); 6291da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek if (name != NULL) { 6391da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek ret = drv; 6491da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek break; 6591da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek } 6691da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek } 6791da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek mutex_unlock(&dsa_switch_drivers_mutex); 6891da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek 6991da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek *_name = name; 7091da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek 7191da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek return ret; 7291da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek} 7391da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek 7491da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek 7591da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek/* basic switch operations **************************************************/ 7691da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhekstatic struct dsa_switch * 77e84665c9cb4db963393fafad6fefe5efdd7e4a09Lennert Buytenhekdsa_switch_setup(struct dsa_switch_tree *dst, int index, 78b4d2394d01bc642e95b2cba956d908423c1bef77Alexander Duyck struct device *parent, struct device *host_dev) 7991da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek{ 80e84665c9cb4db963393fafad6fefe5efdd7e4a09Lennert Buytenhek struct dsa_chip_data *pd = dst->pd->chip + index; 81e84665c9cb4db963393fafad6fefe5efdd7e4a09Lennert Buytenhek struct dsa_switch_driver *drv; 8291da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek struct dsa_switch *ds; 8391da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek int ret; 8491da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek char *name; 8591da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek int i; 86f9bf5a2ca6cc331f32e3dd9cf16ced7215d0e6e8Florian Fainelli bool valid_name_found = false; 8791da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek 8891da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek /* 8991da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek * Probe for switch model. 9091da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek */ 91b4d2394d01bc642e95b2cba956d908423c1bef77Alexander Duyck drv = dsa_switch_probe(host_dev, pd->sw_addr, &name); 9291da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek if (drv == NULL) { 93e84665c9cb4db963393fafad6fefe5efdd7e4a09Lennert Buytenhek printk(KERN_ERR "%s[%d]: could not detect attached switch\n", 94e84665c9cb4db963393fafad6fefe5efdd7e4a09Lennert Buytenhek dst->master_netdev->name, index); 9591da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek return ERR_PTR(-EINVAL); 9691da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek } 97e84665c9cb4db963393fafad6fefe5efdd7e4a09Lennert Buytenhek printk(KERN_INFO "%s[%d]: detected a %s switch\n", 98e84665c9cb4db963393fafad6fefe5efdd7e4a09Lennert Buytenhek dst->master_netdev->name, index, name); 9991da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek 10091da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek 10191da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek /* 10291da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek * Allocate and initialise switch state. 10391da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek */ 10491da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek ds = kzalloc(sizeof(*ds) + drv->priv_size, GFP_KERNEL); 10591da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek if (ds == NULL) 10691da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek return ERR_PTR(-ENOMEM); 10791da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek 108e84665c9cb4db963393fafad6fefe5efdd7e4a09Lennert Buytenhek ds->dst = dst; 109e84665c9cb4db963393fafad6fefe5efdd7e4a09Lennert Buytenhek ds->index = index; 110e84665c9cb4db963393fafad6fefe5efdd7e4a09Lennert Buytenhek ds->pd = dst->pd->chip + index; 11191da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek ds->drv = drv; 112b4d2394d01bc642e95b2cba956d908423c1bef77Alexander Duyck ds->master_dev = host_dev; 11391da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek 11491da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek /* 11591da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek * Validate supplied switch configuration. 11691da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek */ 11791da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek for (i = 0; i < DSA_MAX_PORTS; i++) { 11891da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek char *name; 11991da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek 12091da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek name = pd->port_names[i]; 12191da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek if (name == NULL) 12291da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek continue; 12391da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek 12491da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek if (!strcmp(name, "cpu")) { 125e84665c9cb4db963393fafad6fefe5efdd7e4a09Lennert Buytenhek if (dst->cpu_switch != -1) { 12691da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek printk(KERN_ERR "multiple cpu ports?!\n"); 12791da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek ret = -EINVAL; 12891da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek goto out; 12991da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek } 130e84665c9cb4db963393fafad6fefe5efdd7e4a09Lennert Buytenhek dst->cpu_switch = index; 131e84665c9cb4db963393fafad6fefe5efdd7e4a09Lennert Buytenhek dst->cpu_port = i; 132e84665c9cb4db963393fafad6fefe5efdd7e4a09Lennert Buytenhek } else if (!strcmp(name, "dsa")) { 133e84665c9cb4db963393fafad6fefe5efdd7e4a09Lennert Buytenhek ds->dsa_port_mask |= 1 << i; 13491da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek } else { 135e84665c9cb4db963393fafad6fefe5efdd7e4a09Lennert Buytenhek ds->phys_port_mask |= 1 << i; 13691da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek } 137f9bf5a2ca6cc331f32e3dd9cf16ced7215d0e6e8Florian Fainelli valid_name_found = true; 13891da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek } 13991da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek 140f9bf5a2ca6cc331f32e3dd9cf16ced7215d0e6e8Florian Fainelli if (!valid_name_found && i == DSA_MAX_PORTS) { 141f9bf5a2ca6cc331f32e3dd9cf16ced7215d0e6e8Florian Fainelli ret = -EINVAL; 142f9bf5a2ca6cc331f32e3dd9cf16ced7215d0e6e8Florian Fainelli goto out; 143f9bf5a2ca6cc331f32e3dd9cf16ced7215d0e6e8Florian Fainelli } 14491da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek 1450d8bcdd383b8865e752a7e8edb4712c2e3902052Florian Fainelli /* Make the built-in MII bus mask match the number of ports, 1460d8bcdd383b8865e752a7e8edb4712c2e3902052Florian Fainelli * switch drivers can override this later 1470d8bcdd383b8865e752a7e8edb4712c2e3902052Florian Fainelli */ 1480d8bcdd383b8865e752a7e8edb4712c2e3902052Florian Fainelli ds->phys_mii_mask = ds->phys_port_mask; 1490d8bcdd383b8865e752a7e8edb4712c2e3902052Florian Fainelli 15091da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek /* 151e84665c9cb4db963393fafad6fefe5efdd7e4a09Lennert Buytenhek * If the CPU connects to this switch, set the switch tree 152e84665c9cb4db963393fafad6fefe5efdd7e4a09Lennert Buytenhek * tagging protocol to the preferred tagging format of this 153e84665c9cb4db963393fafad6fefe5efdd7e4a09Lennert Buytenhek * switch. 15491da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek */ 1555075314e4e4b559cc37675ad8a721a89bccd6284Alexander Duyck if (dst->cpu_switch == index) { 1565075314e4e4b559cc37675ad8a721a89bccd6284Alexander Duyck switch (drv->tag_protocol) { 1575075314e4e4b559cc37675ad8a721a89bccd6284Alexander Duyck#ifdef CONFIG_NET_DSA_TAG_DSA 1585075314e4e4b559cc37675ad8a721a89bccd6284Alexander Duyck case DSA_TAG_PROTO_DSA: 1595075314e4e4b559cc37675ad8a721a89bccd6284Alexander Duyck dst->rcv = dsa_netdev_ops.rcv; 1605075314e4e4b559cc37675ad8a721a89bccd6284Alexander Duyck break; 1615075314e4e4b559cc37675ad8a721a89bccd6284Alexander Duyck#endif 1625075314e4e4b559cc37675ad8a721a89bccd6284Alexander Duyck#ifdef CONFIG_NET_DSA_TAG_EDSA 1635075314e4e4b559cc37675ad8a721a89bccd6284Alexander Duyck case DSA_TAG_PROTO_EDSA: 1645075314e4e4b559cc37675ad8a721a89bccd6284Alexander Duyck dst->rcv = edsa_netdev_ops.rcv; 1655075314e4e4b559cc37675ad8a721a89bccd6284Alexander Duyck break; 1665075314e4e4b559cc37675ad8a721a89bccd6284Alexander Duyck#endif 1675075314e4e4b559cc37675ad8a721a89bccd6284Alexander Duyck#ifdef CONFIG_NET_DSA_TAG_TRAILER 1685075314e4e4b559cc37675ad8a721a89bccd6284Alexander Duyck case DSA_TAG_PROTO_TRAILER: 1695075314e4e4b559cc37675ad8a721a89bccd6284Alexander Duyck dst->rcv = trailer_netdev_ops.rcv; 1705075314e4e4b559cc37675ad8a721a89bccd6284Alexander Duyck break; 1715075314e4e4b559cc37675ad8a721a89bccd6284Alexander Duyck#endif 1725075314e4e4b559cc37675ad8a721a89bccd6284Alexander Duyck#ifdef CONFIG_NET_DSA_TAG_BRCM 1735075314e4e4b559cc37675ad8a721a89bccd6284Alexander Duyck case DSA_TAG_PROTO_BRCM: 1745075314e4e4b559cc37675ad8a721a89bccd6284Alexander Duyck dst->rcv = brcm_netdev_ops.rcv; 1755075314e4e4b559cc37675ad8a721a89bccd6284Alexander Duyck break; 1765075314e4e4b559cc37675ad8a721a89bccd6284Alexander Duyck#endif 177ae439286a0dec99cc8029868243689b5b5f3ff75Andrew Lunn case DSA_TAG_PROTO_NONE: 1785075314e4e4b559cc37675ad8a721a89bccd6284Alexander Duyck break; 179ae439286a0dec99cc8029868243689b5b5f3ff75Andrew Lunn default: 180ae439286a0dec99cc8029868243689b5b5f3ff75Andrew Lunn ret = -ENOPROTOOPT; 181ae439286a0dec99cc8029868243689b5b5f3ff75Andrew Lunn goto out; 1825075314e4e4b559cc37675ad8a721a89bccd6284Alexander Duyck } 18391da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek 1845075314e4e4b559cc37675ad8a721a89bccd6284Alexander Duyck dst->tag_protocol = drv->tag_protocol; 1855075314e4e4b559cc37675ad8a721a89bccd6284Alexander Duyck } 18691da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek 18791da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek /* 18891da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek * Do basic register setup. 18991da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek */ 19091da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek ret = drv->setup(ds); 19191da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek if (ret < 0) 19291da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek goto out; 19391da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek 194e84665c9cb4db963393fafad6fefe5efdd7e4a09Lennert Buytenhek ret = drv->set_addr(ds, dst->master_netdev->dev_addr); 19591da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek if (ret < 0) 19691da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek goto out; 19791da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek 19891da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek ds->slave_mii_bus = mdiobus_alloc(); 19991da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek if (ds->slave_mii_bus == NULL) { 20091da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek ret = -ENOMEM; 20191da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek goto out; 20291da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek } 20391da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek dsa_slave_mii_bus_init(ds); 20491da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek 20591da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek ret = mdiobus_register(ds->slave_mii_bus); 20691da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek if (ret < 0) 20791da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek goto out_free; 20891da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek 20991da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek 21091da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek /* 21191da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek * Create network devices for physical switch ports. 21291da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek */ 21391da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek for (i = 0; i < DSA_MAX_PORTS; i++) { 21491da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek struct net_device *slave_dev; 21591da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek 216e84665c9cb4db963393fafad6fefe5efdd7e4a09Lennert Buytenhek if (!(ds->phys_port_mask & (1 << i))) 21791da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek continue; 21891da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek 21991da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek slave_dev = dsa_slave_create(ds, parent, i, pd->port_names[i]); 22091da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek if (slave_dev == NULL) { 221e84665c9cb4db963393fafad6fefe5efdd7e4a09Lennert Buytenhek printk(KERN_ERR "%s[%d]: can't create dsa " 222e84665c9cb4db963393fafad6fefe5efdd7e4a09Lennert Buytenhek "slave device for port %d(%s)\n", 223e84665c9cb4db963393fafad6fefe5efdd7e4a09Lennert Buytenhek dst->master_netdev->name, 224e84665c9cb4db963393fafad6fefe5efdd7e4a09Lennert Buytenhek index, i, pd->port_names[i]); 22591da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek continue; 22691da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek } 22791da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek 22891da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek ds->ports[i] = slave_dev; 22991da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek } 23091da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek 23191da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek return ds; 23291da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek 23391da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhekout_free: 23491da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek mdiobus_free(ds->slave_mii_bus); 23591da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhekout: 23691da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek kfree(ds); 23791da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek return ERR_PTR(ret); 23891da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek} 23991da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek 24091da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhekstatic void dsa_switch_destroy(struct dsa_switch *ds) 24191da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek{ 24291da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek} 24391da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek 244e506d405ac7d34d03996c97ac68aa2ac010be64aThierry Reding#ifdef CONFIG_PM_SLEEP 2452446254915a7d6f08bba9a755a34cc0402880472Florian Fainellistatic int dsa_switch_suspend(struct dsa_switch *ds) 2462446254915a7d6f08bba9a755a34cc0402880472Florian Fainelli{ 2472446254915a7d6f08bba9a755a34cc0402880472Florian Fainelli int i, ret = 0; 2482446254915a7d6f08bba9a755a34cc0402880472Florian Fainelli 2492446254915a7d6f08bba9a755a34cc0402880472Florian Fainelli /* Suspend slave network devices */ 2502446254915a7d6f08bba9a755a34cc0402880472Florian Fainelli for (i = 0; i < DSA_MAX_PORTS; i++) { 2512446254915a7d6f08bba9a755a34cc0402880472Florian Fainelli if (!(ds->phys_port_mask & (1 << i))) 2522446254915a7d6f08bba9a755a34cc0402880472Florian Fainelli continue; 2532446254915a7d6f08bba9a755a34cc0402880472Florian Fainelli 2542446254915a7d6f08bba9a755a34cc0402880472Florian Fainelli ret = dsa_slave_suspend(ds->ports[i]); 2552446254915a7d6f08bba9a755a34cc0402880472Florian Fainelli if (ret) 2562446254915a7d6f08bba9a755a34cc0402880472Florian Fainelli return ret; 2572446254915a7d6f08bba9a755a34cc0402880472Florian Fainelli } 2582446254915a7d6f08bba9a755a34cc0402880472Florian Fainelli 2592446254915a7d6f08bba9a755a34cc0402880472Florian Fainelli if (ds->drv->suspend) 2602446254915a7d6f08bba9a755a34cc0402880472Florian Fainelli ret = ds->drv->suspend(ds); 2612446254915a7d6f08bba9a755a34cc0402880472Florian Fainelli 2622446254915a7d6f08bba9a755a34cc0402880472Florian Fainelli return ret; 2632446254915a7d6f08bba9a755a34cc0402880472Florian Fainelli} 2642446254915a7d6f08bba9a755a34cc0402880472Florian Fainelli 2652446254915a7d6f08bba9a755a34cc0402880472Florian Fainellistatic int dsa_switch_resume(struct dsa_switch *ds) 2662446254915a7d6f08bba9a755a34cc0402880472Florian Fainelli{ 2672446254915a7d6f08bba9a755a34cc0402880472Florian Fainelli int i, ret = 0; 2682446254915a7d6f08bba9a755a34cc0402880472Florian Fainelli 2692446254915a7d6f08bba9a755a34cc0402880472Florian Fainelli if (ds->drv->resume) 2702446254915a7d6f08bba9a755a34cc0402880472Florian Fainelli ret = ds->drv->resume(ds); 2712446254915a7d6f08bba9a755a34cc0402880472Florian Fainelli 2722446254915a7d6f08bba9a755a34cc0402880472Florian Fainelli if (ret) 2732446254915a7d6f08bba9a755a34cc0402880472Florian Fainelli return ret; 2742446254915a7d6f08bba9a755a34cc0402880472Florian Fainelli 2752446254915a7d6f08bba9a755a34cc0402880472Florian Fainelli /* Resume slave network devices */ 2762446254915a7d6f08bba9a755a34cc0402880472Florian Fainelli for (i = 0; i < DSA_MAX_PORTS; i++) { 2772446254915a7d6f08bba9a755a34cc0402880472Florian Fainelli if (!(ds->phys_port_mask & (1 << i))) 2782446254915a7d6f08bba9a755a34cc0402880472Florian Fainelli continue; 2792446254915a7d6f08bba9a755a34cc0402880472Florian Fainelli 2802446254915a7d6f08bba9a755a34cc0402880472Florian Fainelli ret = dsa_slave_resume(ds->ports[i]); 2812446254915a7d6f08bba9a755a34cc0402880472Florian Fainelli if (ret) 2822446254915a7d6f08bba9a755a34cc0402880472Florian Fainelli return ret; 2832446254915a7d6f08bba9a755a34cc0402880472Florian Fainelli } 2842446254915a7d6f08bba9a755a34cc0402880472Florian Fainelli 2852446254915a7d6f08bba9a755a34cc0402880472Florian Fainelli return 0; 2862446254915a7d6f08bba9a755a34cc0402880472Florian Fainelli} 287e506d405ac7d34d03996c97ac68aa2ac010be64aThierry Reding#endif 2882446254915a7d6f08bba9a755a34cc0402880472Florian Fainelli 28991da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek 29091da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek/* link polling *************************************************************/ 29191da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhekstatic void dsa_link_poll_work(struct work_struct *ugly) 29291da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek{ 293e84665c9cb4db963393fafad6fefe5efdd7e4a09Lennert Buytenhek struct dsa_switch_tree *dst; 294e84665c9cb4db963393fafad6fefe5efdd7e4a09Lennert Buytenhek int i; 295e84665c9cb4db963393fafad6fefe5efdd7e4a09Lennert Buytenhek 296e84665c9cb4db963393fafad6fefe5efdd7e4a09Lennert Buytenhek dst = container_of(ugly, struct dsa_switch_tree, link_poll_work); 29791da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek 298e84665c9cb4db963393fafad6fefe5efdd7e4a09Lennert Buytenhek for (i = 0; i < dst->pd->nr_chips; i++) { 299e84665c9cb4db963393fafad6fefe5efdd7e4a09Lennert Buytenhek struct dsa_switch *ds = dst->ds[i]; 30091da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek 301e84665c9cb4db963393fafad6fefe5efdd7e4a09Lennert Buytenhek if (ds != NULL && ds->drv->poll_link != NULL) 302e84665c9cb4db963393fafad6fefe5efdd7e4a09Lennert Buytenhek ds->drv->poll_link(ds); 303e84665c9cb4db963393fafad6fefe5efdd7e4a09Lennert Buytenhek } 304e84665c9cb4db963393fafad6fefe5efdd7e4a09Lennert Buytenhek 305e84665c9cb4db963393fafad6fefe5efdd7e4a09Lennert Buytenhek mod_timer(&dst->link_poll_timer, round_jiffies(jiffies + HZ)); 30691da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek} 30791da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek 308e84665c9cb4db963393fafad6fefe5efdd7e4a09Lennert Buytenhekstatic void dsa_link_poll_timer(unsigned long _dst) 30991da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek{ 310e84665c9cb4db963393fafad6fefe5efdd7e4a09Lennert Buytenhek struct dsa_switch_tree *dst = (void *)_dst; 31191da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek 312e84665c9cb4db963393fafad6fefe5efdd7e4a09Lennert Buytenhek schedule_work(&dst->link_poll_work); 31391da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek} 31491da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek 31591da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek 31691da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek/* platform driver init and cleanup *****************************************/ 31791da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhekstatic int dev_is_class(struct device *dev, void *class) 31891da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek{ 31991da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek if (dev->class != NULL && !strcmp(dev->class->name, class)) 32091da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek return 1; 32191da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek 32291da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek return 0; 32391da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek} 32491da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek 32591da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhekstatic struct device *dev_find_class(struct device *parent, char *class) 32691da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek{ 32791da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek if (dev_is_class(parent, class)) { 32891da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek get_device(parent); 32991da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek return parent; 33091da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek } 33191da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek 33291da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek return device_find_child(parent, class, dev_is_class); 33391da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek} 33491da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek 335b4d2394d01bc642e95b2cba956d908423c1bef77Alexander Duyckstruct mii_bus *dsa_host_dev_to_mii_bus(struct device *dev) 33691da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek{ 33791da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek struct device *d; 33891da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek 33991da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek d = dev_find_class(dev, "mdio_bus"); 34091da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek if (d != NULL) { 34191da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek struct mii_bus *bus; 34291da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek 34391da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek bus = to_mii_bus(d); 34491da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek put_device(d); 34591da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek 34691da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek return bus; 34791da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek } 34891da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek 34991da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek return NULL; 35091da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek} 351b4d2394d01bc642e95b2cba956d908423c1bef77Alexander DuyckEXPORT_SYMBOL_GPL(dsa_host_dev_to_mii_bus); 35291da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek 35391da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhekstatic struct net_device *dev_to_net_device(struct device *dev) 35491da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek{ 35591da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek struct device *d; 35691da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek 35791da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek d = dev_find_class(dev, "net"); 35891da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek if (d != NULL) { 35991da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek struct net_device *nd; 36091da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek 36191da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek nd = to_net_dev(d); 36291da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek dev_hold(nd); 36391da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek put_device(d); 36491da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek 36591da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek return nd; 36691da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek } 36791da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek 36891da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek return NULL; 36991da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek} 37091da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek 3715e95329b701c4edf6c4d72487ec0369fa148c0bdFlorian Fainelli#ifdef CONFIG_OF 3725e95329b701c4edf6c4d72487ec0369fa148c0bdFlorian Fainellistatic int dsa_of_setup_routing_table(struct dsa_platform_data *pd, 3735e95329b701c4edf6c4d72487ec0369fa148c0bdFlorian Fainelli struct dsa_chip_data *cd, 3745e95329b701c4edf6c4d72487ec0369fa148c0bdFlorian Fainelli int chip_index, 3755e95329b701c4edf6c4d72487ec0369fa148c0bdFlorian Fainelli struct device_node *link) 3765e95329b701c4edf6c4d72487ec0369fa148c0bdFlorian Fainelli{ 3775e95329b701c4edf6c4d72487ec0369fa148c0bdFlorian Fainelli int ret; 3785e95329b701c4edf6c4d72487ec0369fa148c0bdFlorian Fainelli const __be32 *reg; 3795e95329b701c4edf6c4d72487ec0369fa148c0bdFlorian Fainelli int link_port_addr; 3805e95329b701c4edf6c4d72487ec0369fa148c0bdFlorian Fainelli int link_sw_addr; 3815e95329b701c4edf6c4d72487ec0369fa148c0bdFlorian Fainelli struct device_node *parent_sw; 3825e95329b701c4edf6c4d72487ec0369fa148c0bdFlorian Fainelli int len; 3835e95329b701c4edf6c4d72487ec0369fa148c0bdFlorian Fainelli 3845e95329b701c4edf6c4d72487ec0369fa148c0bdFlorian Fainelli parent_sw = of_get_parent(link); 3855e95329b701c4edf6c4d72487ec0369fa148c0bdFlorian Fainelli if (!parent_sw) 3865e95329b701c4edf6c4d72487ec0369fa148c0bdFlorian Fainelli return -EINVAL; 3875e95329b701c4edf6c4d72487ec0369fa148c0bdFlorian Fainelli 3885e95329b701c4edf6c4d72487ec0369fa148c0bdFlorian Fainelli reg = of_get_property(parent_sw, "reg", &len); 3895e95329b701c4edf6c4d72487ec0369fa148c0bdFlorian Fainelli if (!reg || (len != sizeof(*reg) * 2)) 3905e95329b701c4edf6c4d72487ec0369fa148c0bdFlorian Fainelli return -EINVAL; 3915e95329b701c4edf6c4d72487ec0369fa148c0bdFlorian Fainelli 3925e95329b701c4edf6c4d72487ec0369fa148c0bdFlorian Fainelli link_sw_addr = be32_to_cpup(reg + 1); 3935e95329b701c4edf6c4d72487ec0369fa148c0bdFlorian Fainelli 3945e95329b701c4edf6c4d72487ec0369fa148c0bdFlorian Fainelli if (link_sw_addr >= pd->nr_chips) 3955e95329b701c4edf6c4d72487ec0369fa148c0bdFlorian Fainelli return -EINVAL; 3965e95329b701c4edf6c4d72487ec0369fa148c0bdFlorian Fainelli 3975e95329b701c4edf6c4d72487ec0369fa148c0bdFlorian Fainelli /* First time routing table allocation */ 3985e95329b701c4edf6c4d72487ec0369fa148c0bdFlorian Fainelli if (!cd->rtable) { 3995e95329b701c4edf6c4d72487ec0369fa148c0bdFlorian Fainelli cd->rtable = kmalloc(pd->nr_chips * sizeof(s8), GFP_KERNEL); 4005e95329b701c4edf6c4d72487ec0369fa148c0bdFlorian Fainelli if (!cd->rtable) 4015e95329b701c4edf6c4d72487ec0369fa148c0bdFlorian Fainelli return -ENOMEM; 4025e95329b701c4edf6c4d72487ec0369fa148c0bdFlorian Fainelli 4035e95329b701c4edf6c4d72487ec0369fa148c0bdFlorian Fainelli /* default to no valid uplink/downlink */ 4045e95329b701c4edf6c4d72487ec0369fa148c0bdFlorian Fainelli memset(cd->rtable, -1, pd->nr_chips * sizeof(s8)); 4055e95329b701c4edf6c4d72487ec0369fa148c0bdFlorian Fainelli } 4065e95329b701c4edf6c4d72487ec0369fa148c0bdFlorian Fainelli 4075e95329b701c4edf6c4d72487ec0369fa148c0bdFlorian Fainelli reg = of_get_property(link, "reg", NULL); 4085e95329b701c4edf6c4d72487ec0369fa148c0bdFlorian Fainelli if (!reg) { 4095e95329b701c4edf6c4d72487ec0369fa148c0bdFlorian Fainelli ret = -EINVAL; 4105e95329b701c4edf6c4d72487ec0369fa148c0bdFlorian Fainelli goto out; 4115e95329b701c4edf6c4d72487ec0369fa148c0bdFlorian Fainelli } 4125e95329b701c4edf6c4d72487ec0369fa148c0bdFlorian Fainelli 4135e95329b701c4edf6c4d72487ec0369fa148c0bdFlorian Fainelli link_port_addr = be32_to_cpup(reg); 4145e95329b701c4edf6c4d72487ec0369fa148c0bdFlorian Fainelli 4155e95329b701c4edf6c4d72487ec0369fa148c0bdFlorian Fainelli cd->rtable[link_sw_addr] = link_port_addr; 4165e95329b701c4edf6c4d72487ec0369fa148c0bdFlorian Fainelli 4175e95329b701c4edf6c4d72487ec0369fa148c0bdFlorian Fainelli return 0; 4185e95329b701c4edf6c4d72487ec0369fa148c0bdFlorian Fainelliout: 4195e95329b701c4edf6c4d72487ec0369fa148c0bdFlorian Fainelli kfree(cd->rtable); 4205e95329b701c4edf6c4d72487ec0369fa148c0bdFlorian Fainelli return ret; 4215e95329b701c4edf6c4d72487ec0369fa148c0bdFlorian Fainelli} 4225e95329b701c4edf6c4d72487ec0369fa148c0bdFlorian Fainelli 42321168245031062212c0b805d0bd466ee6dd4a16fFlorian Fainellistatic void dsa_of_free_platform_data(struct dsa_platform_data *pd) 42421168245031062212c0b805d0bd466ee6dd4a16fFlorian Fainelli{ 42521168245031062212c0b805d0bd466ee6dd4a16fFlorian Fainelli int i; 42621168245031062212c0b805d0bd466ee6dd4a16fFlorian Fainelli int port_index; 42721168245031062212c0b805d0bd466ee6dd4a16fFlorian Fainelli 42821168245031062212c0b805d0bd466ee6dd4a16fFlorian Fainelli for (i = 0; i < pd->nr_chips; i++) { 42921168245031062212c0b805d0bd466ee6dd4a16fFlorian Fainelli port_index = 0; 4305f64a7dbf593c2317f132c8252d04cdfe8d4b104Florian Fainelli while (port_index < DSA_MAX_PORTS) { 4311f74714f1e34a84fe4ef2a6d9b76c20794fb5dcfFabian Frederick kfree(pd->chip[i].port_names[port_index]); 4325f64a7dbf593c2317f132c8252d04cdfe8d4b104Florian Fainelli port_index++; 4335f64a7dbf593c2317f132c8252d04cdfe8d4b104Florian Fainelli } 43421168245031062212c0b805d0bd466ee6dd4a16fFlorian Fainelli kfree(pd->chip[i].rtable); 43521168245031062212c0b805d0bd466ee6dd4a16fFlorian Fainelli } 43621168245031062212c0b805d0bd466ee6dd4a16fFlorian Fainelli kfree(pd->chip); 43721168245031062212c0b805d0bd466ee6dd4a16fFlorian Fainelli} 43821168245031062212c0b805d0bd466ee6dd4a16fFlorian Fainelli 4395e95329b701c4edf6c4d72487ec0369fa148c0bdFlorian Fainellistatic int dsa_of_probe(struct platform_device *pdev) 4405e95329b701c4edf6c4d72487ec0369fa148c0bdFlorian Fainelli{ 4415e95329b701c4edf6c4d72487ec0369fa148c0bdFlorian Fainelli struct device_node *np = pdev->dev.of_node; 4425e95329b701c4edf6c4d72487ec0369fa148c0bdFlorian Fainelli struct device_node *child, *mdio, *ethernet, *port, *link; 4435e95329b701c4edf6c4d72487ec0369fa148c0bdFlorian Fainelli struct mii_bus *mdio_bus; 4445e95329b701c4edf6c4d72487ec0369fa148c0bdFlorian Fainelli struct platform_device *ethernet_dev; 4455e95329b701c4edf6c4d72487ec0369fa148c0bdFlorian Fainelli struct dsa_platform_data *pd; 4465e95329b701c4edf6c4d72487ec0369fa148c0bdFlorian Fainelli struct dsa_chip_data *cd; 4475e95329b701c4edf6c4d72487ec0369fa148c0bdFlorian Fainelli const char *port_name; 4485e95329b701c4edf6c4d72487ec0369fa148c0bdFlorian Fainelli int chip_index, port_index; 4495e95329b701c4edf6c4d72487ec0369fa148c0bdFlorian Fainelli const unsigned int *sw_addr, *port_reg; 45021168245031062212c0b805d0bd466ee6dd4a16fFlorian Fainelli int ret; 4515e95329b701c4edf6c4d72487ec0369fa148c0bdFlorian Fainelli 4525e95329b701c4edf6c4d72487ec0369fa148c0bdFlorian Fainelli mdio = of_parse_phandle(np, "dsa,mii-bus", 0); 4535e95329b701c4edf6c4d72487ec0369fa148c0bdFlorian Fainelli if (!mdio) 4545e95329b701c4edf6c4d72487ec0369fa148c0bdFlorian Fainelli return -EINVAL; 4555e95329b701c4edf6c4d72487ec0369fa148c0bdFlorian Fainelli 4565e95329b701c4edf6c4d72487ec0369fa148c0bdFlorian Fainelli mdio_bus = of_mdio_find_bus(mdio); 4575e95329b701c4edf6c4d72487ec0369fa148c0bdFlorian Fainelli if (!mdio_bus) 4585e95329b701c4edf6c4d72487ec0369fa148c0bdFlorian Fainelli return -EINVAL; 4595e95329b701c4edf6c4d72487ec0369fa148c0bdFlorian Fainelli 4605e95329b701c4edf6c4d72487ec0369fa148c0bdFlorian Fainelli ethernet = of_parse_phandle(np, "dsa,ethernet", 0); 4615e95329b701c4edf6c4d72487ec0369fa148c0bdFlorian Fainelli if (!ethernet) 4625e95329b701c4edf6c4d72487ec0369fa148c0bdFlorian Fainelli return -EINVAL; 4635e95329b701c4edf6c4d72487ec0369fa148c0bdFlorian Fainelli 4645e95329b701c4edf6c4d72487ec0369fa148c0bdFlorian Fainelli ethernet_dev = of_find_device_by_node(ethernet); 4655e95329b701c4edf6c4d72487ec0369fa148c0bdFlorian Fainelli if (!ethernet_dev) 4665e95329b701c4edf6c4d72487ec0369fa148c0bdFlorian Fainelli return -ENODEV; 4675e95329b701c4edf6c4d72487ec0369fa148c0bdFlorian Fainelli 4685e95329b701c4edf6c4d72487ec0369fa148c0bdFlorian Fainelli pd = kzalloc(sizeof(*pd), GFP_KERNEL); 4695e95329b701c4edf6c4d72487ec0369fa148c0bdFlorian Fainelli if (!pd) 4705e95329b701c4edf6c4d72487ec0369fa148c0bdFlorian Fainelli return -ENOMEM; 4715e95329b701c4edf6c4d72487ec0369fa148c0bdFlorian Fainelli 4725e95329b701c4edf6c4d72487ec0369fa148c0bdFlorian Fainelli pdev->dev.platform_data = pd; 4735e95329b701c4edf6c4d72487ec0369fa148c0bdFlorian Fainelli pd->netdev = ðernet_dev->dev; 4745e95329b701c4edf6c4d72487ec0369fa148c0bdFlorian Fainelli pd->nr_chips = of_get_child_count(np); 4755e95329b701c4edf6c4d72487ec0369fa148c0bdFlorian Fainelli if (pd->nr_chips > DSA_MAX_SWITCHES) 4765e95329b701c4edf6c4d72487ec0369fa148c0bdFlorian Fainelli pd->nr_chips = DSA_MAX_SWITCHES; 4775e95329b701c4edf6c4d72487ec0369fa148c0bdFlorian Fainelli 4785e95329b701c4edf6c4d72487ec0369fa148c0bdFlorian Fainelli pd->chip = kzalloc(pd->nr_chips * sizeof(struct dsa_chip_data), 4795e95329b701c4edf6c4d72487ec0369fa148c0bdFlorian Fainelli GFP_KERNEL); 4805e95329b701c4edf6c4d72487ec0369fa148c0bdFlorian Fainelli if (!pd->chip) { 4815e95329b701c4edf6c4d72487ec0369fa148c0bdFlorian Fainelli ret = -ENOMEM; 4825e95329b701c4edf6c4d72487ec0369fa148c0bdFlorian Fainelli goto out_free; 4835e95329b701c4edf6c4d72487ec0369fa148c0bdFlorian Fainelli } 4845e95329b701c4edf6c4d72487ec0369fa148c0bdFlorian Fainelli 485d1c0b471b340f43fa857d19150e029257d7bb475Fabian Godehardt chip_index = -1; 4865e95329b701c4edf6c4d72487ec0369fa148c0bdFlorian Fainelli for_each_available_child_of_node(np, child) { 487d1c0b471b340f43fa857d19150e029257d7bb475Fabian Godehardt chip_index++; 4885e95329b701c4edf6c4d72487ec0369fa148c0bdFlorian Fainelli cd = &pd->chip[chip_index]; 4895e95329b701c4edf6c4d72487ec0369fa148c0bdFlorian Fainelli 490fa981d9af82e08f316ed25ed43078f995cc4be0aFlorian Fainelli cd->of_node = child; 491c1f570a6abc192f047550743f9957b617af605afFlorian Fainelli cd->host_dev = &mdio_bus->dev; 4925e95329b701c4edf6c4d72487ec0369fa148c0bdFlorian Fainelli 4935e95329b701c4edf6c4d72487ec0369fa148c0bdFlorian Fainelli sw_addr = of_get_property(child, "reg", NULL); 4945e95329b701c4edf6c4d72487ec0369fa148c0bdFlorian Fainelli if (!sw_addr) 4955e95329b701c4edf6c4d72487ec0369fa148c0bdFlorian Fainelli continue; 4965e95329b701c4edf6c4d72487ec0369fa148c0bdFlorian Fainelli 4975e95329b701c4edf6c4d72487ec0369fa148c0bdFlorian Fainelli cd->sw_addr = be32_to_cpup(sw_addr); 4985e95329b701c4edf6c4d72487ec0369fa148c0bdFlorian Fainelli if (cd->sw_addr > PHY_MAX_ADDR) 4995e95329b701c4edf6c4d72487ec0369fa148c0bdFlorian Fainelli continue; 5005e95329b701c4edf6c4d72487ec0369fa148c0bdFlorian Fainelli 5015e95329b701c4edf6c4d72487ec0369fa148c0bdFlorian Fainelli for_each_available_child_of_node(child, port) { 5025e95329b701c4edf6c4d72487ec0369fa148c0bdFlorian Fainelli port_reg = of_get_property(port, "reg", NULL); 5035e95329b701c4edf6c4d72487ec0369fa148c0bdFlorian Fainelli if (!port_reg) 5045e95329b701c4edf6c4d72487ec0369fa148c0bdFlorian Fainelli continue; 5055e95329b701c4edf6c4d72487ec0369fa148c0bdFlorian Fainelli 5065e95329b701c4edf6c4d72487ec0369fa148c0bdFlorian Fainelli port_index = be32_to_cpup(port_reg); 5075e95329b701c4edf6c4d72487ec0369fa148c0bdFlorian Fainelli 5085e95329b701c4edf6c4d72487ec0369fa148c0bdFlorian Fainelli port_name = of_get_property(port, "label", NULL); 5095e95329b701c4edf6c4d72487ec0369fa148c0bdFlorian Fainelli if (!port_name) 5105e95329b701c4edf6c4d72487ec0369fa148c0bdFlorian Fainelli continue; 5115e95329b701c4edf6c4d72487ec0369fa148c0bdFlorian Fainelli 512bd47497a0171b96264927e3377254db13b9fe3e3Florian Fainelli cd->port_dn[port_index] = port; 513bd47497a0171b96264927e3377254db13b9fe3e3Florian Fainelli 5145e95329b701c4edf6c4d72487ec0369fa148c0bdFlorian Fainelli cd->port_names[port_index] = kstrdup(port_name, 5155e95329b701c4edf6c4d72487ec0369fa148c0bdFlorian Fainelli GFP_KERNEL); 5165e95329b701c4edf6c4d72487ec0369fa148c0bdFlorian Fainelli if (!cd->port_names[port_index]) { 5175e95329b701c4edf6c4d72487ec0369fa148c0bdFlorian Fainelli ret = -ENOMEM; 5185e95329b701c4edf6c4d72487ec0369fa148c0bdFlorian Fainelli goto out_free_chip; 5195e95329b701c4edf6c4d72487ec0369fa148c0bdFlorian Fainelli } 5205e95329b701c4edf6c4d72487ec0369fa148c0bdFlorian Fainelli 5215e95329b701c4edf6c4d72487ec0369fa148c0bdFlorian Fainelli link = of_parse_phandle(port, "link", 0); 5225e95329b701c4edf6c4d72487ec0369fa148c0bdFlorian Fainelli 5235e95329b701c4edf6c4d72487ec0369fa148c0bdFlorian Fainelli if (!strcmp(port_name, "dsa") && link && 5245e95329b701c4edf6c4d72487ec0369fa148c0bdFlorian Fainelli pd->nr_chips > 1) { 5255e95329b701c4edf6c4d72487ec0369fa148c0bdFlorian Fainelli ret = dsa_of_setup_routing_table(pd, cd, 5265e95329b701c4edf6c4d72487ec0369fa148c0bdFlorian Fainelli chip_index, link); 5275e95329b701c4edf6c4d72487ec0369fa148c0bdFlorian Fainelli if (ret) 5285e95329b701c4edf6c4d72487ec0369fa148c0bdFlorian Fainelli goto out_free_chip; 5295e95329b701c4edf6c4d72487ec0369fa148c0bdFlorian Fainelli } 5305e95329b701c4edf6c4d72487ec0369fa148c0bdFlorian Fainelli 5315e95329b701c4edf6c4d72487ec0369fa148c0bdFlorian Fainelli if (port_index == DSA_MAX_PORTS) 5325e95329b701c4edf6c4d72487ec0369fa148c0bdFlorian Fainelli break; 5335e95329b701c4edf6c4d72487ec0369fa148c0bdFlorian Fainelli } 5345e95329b701c4edf6c4d72487ec0369fa148c0bdFlorian Fainelli } 5355e95329b701c4edf6c4d72487ec0369fa148c0bdFlorian Fainelli 5365e95329b701c4edf6c4d72487ec0369fa148c0bdFlorian Fainelli return 0; 5375e95329b701c4edf6c4d72487ec0369fa148c0bdFlorian Fainelli 5385e95329b701c4edf6c4d72487ec0369fa148c0bdFlorian Fainelliout_free_chip: 53921168245031062212c0b805d0bd466ee6dd4a16fFlorian Fainelli dsa_of_free_platform_data(pd); 5405e95329b701c4edf6c4d72487ec0369fa148c0bdFlorian Fainelliout_free: 5415e95329b701c4edf6c4d72487ec0369fa148c0bdFlorian Fainelli kfree(pd); 5425e95329b701c4edf6c4d72487ec0369fa148c0bdFlorian Fainelli pdev->dev.platform_data = NULL; 5435e95329b701c4edf6c4d72487ec0369fa148c0bdFlorian Fainelli return ret; 5445e95329b701c4edf6c4d72487ec0369fa148c0bdFlorian Fainelli} 5455e95329b701c4edf6c4d72487ec0369fa148c0bdFlorian Fainelli 5465e95329b701c4edf6c4d72487ec0369fa148c0bdFlorian Fainellistatic void dsa_of_remove(struct platform_device *pdev) 5475e95329b701c4edf6c4d72487ec0369fa148c0bdFlorian Fainelli{ 5485e95329b701c4edf6c4d72487ec0369fa148c0bdFlorian Fainelli struct dsa_platform_data *pd = pdev->dev.platform_data; 5495e95329b701c4edf6c4d72487ec0369fa148c0bdFlorian Fainelli 5505e95329b701c4edf6c4d72487ec0369fa148c0bdFlorian Fainelli if (!pdev->dev.of_node) 5515e95329b701c4edf6c4d72487ec0369fa148c0bdFlorian Fainelli return; 5525e95329b701c4edf6c4d72487ec0369fa148c0bdFlorian Fainelli 55321168245031062212c0b805d0bd466ee6dd4a16fFlorian Fainelli dsa_of_free_platform_data(pd); 5545e95329b701c4edf6c4d72487ec0369fa148c0bdFlorian Fainelli kfree(pd); 5555e95329b701c4edf6c4d72487ec0369fa148c0bdFlorian Fainelli} 5565e95329b701c4edf6c4d72487ec0369fa148c0bdFlorian Fainelli#else 5575e95329b701c4edf6c4d72487ec0369fa148c0bdFlorian Fainellistatic inline int dsa_of_probe(struct platform_device *pdev) 5585e95329b701c4edf6c4d72487ec0369fa148c0bdFlorian Fainelli{ 5595e95329b701c4edf6c4d72487ec0369fa148c0bdFlorian Fainelli return 0; 5605e95329b701c4edf6c4d72487ec0369fa148c0bdFlorian Fainelli} 5615e95329b701c4edf6c4d72487ec0369fa148c0bdFlorian Fainelli 5625e95329b701c4edf6c4d72487ec0369fa148c0bdFlorian Fainellistatic inline void dsa_of_remove(struct platform_device *pdev) 5635e95329b701c4edf6c4d72487ec0369fa148c0bdFlorian Fainelli{ 5645e95329b701c4edf6c4d72487ec0369fa148c0bdFlorian Fainelli} 5655e95329b701c4edf6c4d72487ec0369fa148c0bdFlorian Fainelli#endif 5665e95329b701c4edf6c4d72487ec0369fa148c0bdFlorian Fainelli 56791da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhekstatic int dsa_probe(struct platform_device *pdev) 56891da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek{ 56991da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek static int dsa_version_printed; 57091da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek struct dsa_platform_data *pd = pdev->dev.platform_data; 57191da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek struct net_device *dev; 572e84665c9cb4db963393fafad6fefe5efdd7e4a09Lennert Buytenhek struct dsa_switch_tree *dst; 5735e95329b701c4edf6c4d72487ec0369fa148c0bdFlorian Fainelli int i, ret; 57491da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek 57591da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek if (!dsa_version_printed++) 57691da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek printk(KERN_NOTICE "Distributed Switch Architecture " 57791da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek "driver version %s\n", dsa_driver_version); 57891da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek 5795e95329b701c4edf6c4d72487ec0369fa148c0bdFlorian Fainelli if (pdev->dev.of_node) { 5805e95329b701c4edf6c4d72487ec0369fa148c0bdFlorian Fainelli ret = dsa_of_probe(pdev); 5815e95329b701c4edf6c4d72487ec0369fa148c0bdFlorian Fainelli if (ret) 5825e95329b701c4edf6c4d72487ec0369fa148c0bdFlorian Fainelli return ret; 5835e95329b701c4edf6c4d72487ec0369fa148c0bdFlorian Fainelli 5845e95329b701c4edf6c4d72487ec0369fa148c0bdFlorian Fainelli pd = pdev->dev.platform_data; 5855e95329b701c4edf6c4d72487ec0369fa148c0bdFlorian Fainelli } 5865e95329b701c4edf6c4d72487ec0369fa148c0bdFlorian Fainelli 587e84665c9cb4db963393fafad6fefe5efdd7e4a09Lennert Buytenhek if (pd == NULL || pd->netdev == NULL) 58891da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek return -EINVAL; 58991da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek 59091da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek dev = dev_to_net_device(pd->netdev); 5915e95329b701c4edf6c4d72487ec0369fa148c0bdFlorian Fainelli if (dev == NULL) { 5925e95329b701c4edf6c4d72487ec0369fa148c0bdFlorian Fainelli ret = -EINVAL; 5935e95329b701c4edf6c4d72487ec0369fa148c0bdFlorian Fainelli goto out; 5945e95329b701c4edf6c4d72487ec0369fa148c0bdFlorian Fainelli } 59591da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek 59691da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek if (dev->dsa_ptr != NULL) { 59791da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek dev_put(dev); 5985e95329b701c4edf6c4d72487ec0369fa148c0bdFlorian Fainelli ret = -EEXIST; 5995e95329b701c4edf6c4d72487ec0369fa148c0bdFlorian Fainelli goto out; 60091da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek } 60191da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek 602e84665c9cb4db963393fafad6fefe5efdd7e4a09Lennert Buytenhek dst = kzalloc(sizeof(*dst), GFP_KERNEL); 603e84665c9cb4db963393fafad6fefe5efdd7e4a09Lennert Buytenhek if (dst == NULL) { 60491da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek dev_put(dev); 6055e95329b701c4edf6c4d72487ec0369fa148c0bdFlorian Fainelli ret = -ENOMEM; 6065e95329b701c4edf6c4d72487ec0369fa148c0bdFlorian Fainelli goto out; 60791da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek } 60891da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek 609e84665c9cb4db963393fafad6fefe5efdd7e4a09Lennert Buytenhek platform_set_drvdata(pdev, dst); 610e84665c9cb4db963393fafad6fefe5efdd7e4a09Lennert Buytenhek 611e84665c9cb4db963393fafad6fefe5efdd7e4a09Lennert Buytenhek dst->pd = pd; 612e84665c9cb4db963393fafad6fefe5efdd7e4a09Lennert Buytenhek dst->master_netdev = dev; 613e84665c9cb4db963393fafad6fefe5efdd7e4a09Lennert Buytenhek dst->cpu_switch = -1; 614e84665c9cb4db963393fafad6fefe5efdd7e4a09Lennert Buytenhek dst->cpu_port = -1; 615e84665c9cb4db963393fafad6fefe5efdd7e4a09Lennert Buytenhek 616e84665c9cb4db963393fafad6fefe5efdd7e4a09Lennert Buytenhek for (i = 0; i < pd->nr_chips; i++) { 617e84665c9cb4db963393fafad6fefe5efdd7e4a09Lennert Buytenhek struct dsa_switch *ds; 618e84665c9cb4db963393fafad6fefe5efdd7e4a09Lennert Buytenhek 619b4d2394d01bc642e95b2cba956d908423c1bef77Alexander Duyck ds = dsa_switch_setup(dst, i, &pdev->dev, pd->chip[i].host_dev); 620e84665c9cb4db963393fafad6fefe5efdd7e4a09Lennert Buytenhek if (IS_ERR(ds)) { 621e84665c9cb4db963393fafad6fefe5efdd7e4a09Lennert Buytenhek printk(KERN_ERR "%s[%d]: couldn't create dsa switch " 622e84665c9cb4db963393fafad6fefe5efdd7e4a09Lennert Buytenhek "instance (error %ld)\n", dev->name, i, 623e84665c9cb4db963393fafad6fefe5efdd7e4a09Lennert Buytenhek PTR_ERR(ds)); 624e84665c9cb4db963393fafad6fefe5efdd7e4a09Lennert Buytenhek continue; 625e84665c9cb4db963393fafad6fefe5efdd7e4a09Lennert Buytenhek } 626e84665c9cb4db963393fafad6fefe5efdd7e4a09Lennert Buytenhek 627e84665c9cb4db963393fafad6fefe5efdd7e4a09Lennert Buytenhek dst->ds[i] = ds; 628e84665c9cb4db963393fafad6fefe5efdd7e4a09Lennert Buytenhek if (ds->drv->poll_link != NULL) 629e84665c9cb4db963393fafad6fefe5efdd7e4a09Lennert Buytenhek dst->link_poll_needed = 1; 63091da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek } 63191da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek 632e84665c9cb4db963393fafad6fefe5efdd7e4a09Lennert Buytenhek /* 633e84665c9cb4db963393fafad6fefe5efdd7e4a09Lennert Buytenhek * If we use a tagging format that doesn't have an ethertype 634e84665c9cb4db963393fafad6fefe5efdd7e4a09Lennert Buytenhek * field, make sure that all packets from this point on get 635e84665c9cb4db963393fafad6fefe5efdd7e4a09Lennert Buytenhek * sent to the tag format's receive function. 636e84665c9cb4db963393fafad6fefe5efdd7e4a09Lennert Buytenhek */ 637e84665c9cb4db963393fafad6fefe5efdd7e4a09Lennert Buytenhek wmb(); 638e84665c9cb4db963393fafad6fefe5efdd7e4a09Lennert Buytenhek dev->dsa_ptr = (void *)dst; 639e84665c9cb4db963393fafad6fefe5efdd7e4a09Lennert Buytenhek 640e84665c9cb4db963393fafad6fefe5efdd7e4a09Lennert Buytenhek if (dst->link_poll_needed) { 641e84665c9cb4db963393fafad6fefe5efdd7e4a09Lennert Buytenhek INIT_WORK(&dst->link_poll_work, dsa_link_poll_work); 642e84665c9cb4db963393fafad6fefe5efdd7e4a09Lennert Buytenhek init_timer(&dst->link_poll_timer); 643e84665c9cb4db963393fafad6fefe5efdd7e4a09Lennert Buytenhek dst->link_poll_timer.data = (unsigned long)dst; 644e84665c9cb4db963393fafad6fefe5efdd7e4a09Lennert Buytenhek dst->link_poll_timer.function = dsa_link_poll_timer; 645e84665c9cb4db963393fafad6fefe5efdd7e4a09Lennert Buytenhek dst->link_poll_timer.expires = round_jiffies(jiffies + HZ); 646e84665c9cb4db963393fafad6fefe5efdd7e4a09Lennert Buytenhek add_timer(&dst->link_poll_timer); 647e84665c9cb4db963393fafad6fefe5efdd7e4a09Lennert Buytenhek } 64891da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek 64991da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek return 0; 6505e95329b701c4edf6c4d72487ec0369fa148c0bdFlorian Fainelli 6515e95329b701c4edf6c4d72487ec0369fa148c0bdFlorian Fainelliout: 6525e95329b701c4edf6c4d72487ec0369fa148c0bdFlorian Fainelli dsa_of_remove(pdev); 6535e95329b701c4edf6c4d72487ec0369fa148c0bdFlorian Fainelli 6545e95329b701c4edf6c4d72487ec0369fa148c0bdFlorian Fainelli return ret; 65591da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek} 65691da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek 65791da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhekstatic int dsa_remove(struct platform_device *pdev) 65891da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek{ 659e84665c9cb4db963393fafad6fefe5efdd7e4a09Lennert Buytenhek struct dsa_switch_tree *dst = platform_get_drvdata(pdev); 660e84665c9cb4db963393fafad6fefe5efdd7e4a09Lennert Buytenhek int i; 66191da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek 662e84665c9cb4db963393fafad6fefe5efdd7e4a09Lennert Buytenhek if (dst->link_poll_needed) 663e84665c9cb4db963393fafad6fefe5efdd7e4a09Lennert Buytenhek del_timer_sync(&dst->link_poll_timer); 66491da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek 66543829731dd372d04d6706c51052b9dabab9ca356Tejun Heo flush_work(&dst->link_poll_work); 66691da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek 667e84665c9cb4db963393fafad6fefe5efdd7e4a09Lennert Buytenhek for (i = 0; i < dst->pd->nr_chips; i++) { 668e84665c9cb4db963393fafad6fefe5efdd7e4a09Lennert Buytenhek struct dsa_switch *ds = dst->ds[i]; 669e84665c9cb4db963393fafad6fefe5efdd7e4a09Lennert Buytenhek 670e84665c9cb4db963393fafad6fefe5efdd7e4a09Lennert Buytenhek if (ds != NULL) 671e84665c9cb4db963393fafad6fefe5efdd7e4a09Lennert Buytenhek dsa_switch_destroy(ds); 672e84665c9cb4db963393fafad6fefe5efdd7e4a09Lennert Buytenhek } 67391da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek 6745e95329b701c4edf6c4d72487ec0369fa148c0bdFlorian Fainelli dsa_of_remove(pdev); 6755e95329b701c4edf6c4d72487ec0369fa148c0bdFlorian Fainelli 67691da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek return 0; 67791da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek} 67891da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek 67991da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhekstatic void dsa_shutdown(struct platform_device *pdev) 68091da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek{ 68191da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek} 68291da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek 6833e8a72d1dae374cf6fc1dba97cec663585845ff9Florian Fainellistatic int dsa_switch_rcv(struct sk_buff *skb, struct net_device *dev, 6843e8a72d1dae374cf6fc1dba97cec663585845ff9Florian Fainelli struct packet_type *pt, struct net_device *orig_dev) 6853e8a72d1dae374cf6fc1dba97cec663585845ff9Florian Fainelli{ 6863e8a72d1dae374cf6fc1dba97cec663585845ff9Florian Fainelli struct dsa_switch_tree *dst = dev->dsa_ptr; 6873e8a72d1dae374cf6fc1dba97cec663585845ff9Florian Fainelli 6883e8a72d1dae374cf6fc1dba97cec663585845ff9Florian Fainelli if (unlikely(dst == NULL)) { 6893e8a72d1dae374cf6fc1dba97cec663585845ff9Florian Fainelli kfree_skb(skb); 6903e8a72d1dae374cf6fc1dba97cec663585845ff9Florian Fainelli return 0; 6913e8a72d1dae374cf6fc1dba97cec663585845ff9Florian Fainelli } 6923e8a72d1dae374cf6fc1dba97cec663585845ff9Florian Fainelli 6935075314e4e4b559cc37675ad8a721a89bccd6284Alexander Duyck return dst->rcv(skb, dev, pt, orig_dev); 6943e8a72d1dae374cf6fc1dba97cec663585845ff9Florian Fainelli} 6953e8a72d1dae374cf6fc1dba97cec663585845ff9Florian Fainelli 69661b7363ffa48b36e2ff086c2d2524e40d3766571Florian Fainellistatic struct packet_type dsa_pack_type __read_mostly = { 6973e8a72d1dae374cf6fc1dba97cec663585845ff9Florian Fainelli .type = cpu_to_be16(ETH_P_XDSA), 6983e8a72d1dae374cf6fc1dba97cec663585845ff9Florian Fainelli .func = dsa_switch_rcv, 6993e8a72d1dae374cf6fc1dba97cec663585845ff9Florian Fainelli}; 7003e8a72d1dae374cf6fc1dba97cec663585845ff9Florian Fainelli 7012446254915a7d6f08bba9a755a34cc0402880472Florian Fainelli#ifdef CONFIG_PM_SLEEP 7022446254915a7d6f08bba9a755a34cc0402880472Florian Fainellistatic int dsa_suspend(struct device *d) 7032446254915a7d6f08bba9a755a34cc0402880472Florian Fainelli{ 7042446254915a7d6f08bba9a755a34cc0402880472Florian Fainelli struct platform_device *pdev = to_platform_device(d); 7052446254915a7d6f08bba9a755a34cc0402880472Florian Fainelli struct dsa_switch_tree *dst = platform_get_drvdata(pdev); 7062446254915a7d6f08bba9a755a34cc0402880472Florian Fainelli int i, ret = 0; 7072446254915a7d6f08bba9a755a34cc0402880472Florian Fainelli 7082446254915a7d6f08bba9a755a34cc0402880472Florian Fainelli for (i = 0; i < dst->pd->nr_chips; i++) { 7092446254915a7d6f08bba9a755a34cc0402880472Florian Fainelli struct dsa_switch *ds = dst->ds[i]; 7102446254915a7d6f08bba9a755a34cc0402880472Florian Fainelli 7112446254915a7d6f08bba9a755a34cc0402880472Florian Fainelli if (ds != NULL) 7122446254915a7d6f08bba9a755a34cc0402880472Florian Fainelli ret = dsa_switch_suspend(ds); 7132446254915a7d6f08bba9a755a34cc0402880472Florian Fainelli } 7142446254915a7d6f08bba9a755a34cc0402880472Florian Fainelli 7152446254915a7d6f08bba9a755a34cc0402880472Florian Fainelli return ret; 7162446254915a7d6f08bba9a755a34cc0402880472Florian Fainelli} 7172446254915a7d6f08bba9a755a34cc0402880472Florian Fainelli 7182446254915a7d6f08bba9a755a34cc0402880472Florian Fainellistatic int dsa_resume(struct device *d) 7192446254915a7d6f08bba9a755a34cc0402880472Florian Fainelli{ 7202446254915a7d6f08bba9a755a34cc0402880472Florian Fainelli struct platform_device *pdev = to_platform_device(d); 7212446254915a7d6f08bba9a755a34cc0402880472Florian Fainelli struct dsa_switch_tree *dst = platform_get_drvdata(pdev); 7222446254915a7d6f08bba9a755a34cc0402880472Florian Fainelli int i, ret = 0; 7232446254915a7d6f08bba9a755a34cc0402880472Florian Fainelli 7242446254915a7d6f08bba9a755a34cc0402880472Florian Fainelli for (i = 0; i < dst->pd->nr_chips; i++) { 7252446254915a7d6f08bba9a755a34cc0402880472Florian Fainelli struct dsa_switch *ds = dst->ds[i]; 7262446254915a7d6f08bba9a755a34cc0402880472Florian Fainelli 7272446254915a7d6f08bba9a755a34cc0402880472Florian Fainelli if (ds != NULL) 7282446254915a7d6f08bba9a755a34cc0402880472Florian Fainelli ret = dsa_switch_resume(ds); 7292446254915a7d6f08bba9a755a34cc0402880472Florian Fainelli } 7302446254915a7d6f08bba9a755a34cc0402880472Florian Fainelli 7312446254915a7d6f08bba9a755a34cc0402880472Florian Fainelli return ret; 7322446254915a7d6f08bba9a755a34cc0402880472Florian Fainelli} 7332446254915a7d6f08bba9a755a34cc0402880472Florian Fainelli#endif 7342446254915a7d6f08bba9a755a34cc0402880472Florian Fainelli 7352446254915a7d6f08bba9a755a34cc0402880472Florian Fainellistatic SIMPLE_DEV_PM_OPS(dsa_pm_ops, dsa_suspend, dsa_resume); 7362446254915a7d6f08bba9a755a34cc0402880472Florian Fainelli 7375e95329b701c4edf6c4d72487ec0369fa148c0bdFlorian Fainellistatic const struct of_device_id dsa_of_match_table[] = { 738246d7f773c13cac3e3ab1609fd4ffee520242c63Florian Fainelli { .compatible = "brcm,bcm7445-switch-v4.0" }, 7395e95329b701c4edf6c4d72487ec0369fa148c0bdFlorian Fainelli { .compatible = "marvell,dsa", }, 7405e95329b701c4edf6c4d72487ec0369fa148c0bdFlorian Fainelli {} 7415e95329b701c4edf6c4d72487ec0369fa148c0bdFlorian Fainelli}; 7425e95329b701c4edf6c4d72487ec0369fa148c0bdFlorian FainelliMODULE_DEVICE_TABLE(of, dsa_of_match_table); 7435e95329b701c4edf6c4d72487ec0369fa148c0bdFlorian Fainelli 74491da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhekstatic struct platform_driver dsa_driver = { 74591da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek .probe = dsa_probe, 74691da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek .remove = dsa_remove, 74791da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek .shutdown = dsa_shutdown, 74891da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek .driver = { 74991da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek .name = "dsa", 75091da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek .owner = THIS_MODULE, 7515e95329b701c4edf6c4d72487ec0369fa148c0bdFlorian Fainelli .of_match_table = dsa_of_match_table, 7522446254915a7d6f08bba9a755a34cc0402880472Florian Fainelli .pm = &dsa_pm_ops, 75391da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek }, 75491da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek}; 75591da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek 75691da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhekstatic int __init dsa_init_module(void) 75791da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek{ 7587df899c36cf09678bdef1824ce591ef4ac0e9864Ben Hutchings int rc; 7597df899c36cf09678bdef1824ce591ef4ac0e9864Ben Hutchings 7607df899c36cf09678bdef1824ce591ef4ac0e9864Ben Hutchings rc = platform_driver_register(&dsa_driver); 7617df899c36cf09678bdef1824ce591ef4ac0e9864Ben Hutchings if (rc) 7627df899c36cf09678bdef1824ce591ef4ac0e9864Ben Hutchings return rc; 7637df899c36cf09678bdef1824ce591ef4ac0e9864Ben Hutchings 7643e8a72d1dae374cf6fc1dba97cec663585845ff9Florian Fainelli dev_add_pack(&dsa_pack_type); 7653e8a72d1dae374cf6fc1dba97cec663585845ff9Florian Fainelli 7667df899c36cf09678bdef1824ce591ef4ac0e9864Ben Hutchings return 0; 76791da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek} 76891da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhekmodule_init(dsa_init_module); 76991da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek 77091da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhekstatic void __exit dsa_cleanup_module(void) 77191da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek{ 7723e8a72d1dae374cf6fc1dba97cec663585845ff9Florian Fainelli dev_remove_pack(&dsa_pack_type); 77391da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek platform_driver_unregister(&dsa_driver); 77491da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek} 77591da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhekmodule_exit(dsa_cleanup_module); 77691da11f870f00a3322b81c73042291d7f0be5a17Lennert Buytenhek 777577d6a7c3a0e273e115c65a148b71be6c1950f69Rusty RussellMODULE_AUTHOR("Lennert Buytenhek <buytenh@wantstofly.org>"); 77891da11f870f00a3322b81c73042291d7f0be5a17Lennert BuytenhekMODULE_DESCRIPTION("Driver for Distributed Switch Architecture switch chips"); 77991da11f870f00a3322b81c73042291d7f0be5a17Lennert BuytenhekMODULE_LICENSE("GPL"); 78091da11f870f00a3322b81c73042291d7f0be5a17Lennert BuytenhekMODULE_ALIAS("platform:dsa"); 781