summaryrefslogtreecommitdiff
path: root/net/dsa
diff options
context:
space:
mode:
Diffstat (limited to 'net/dsa')
-rw-r--r--net/dsa/dsa.c45
-rw-r--r--net/dsa/slave.c144
-rw-r--r--net/dsa/tag_trailer.c2
3 files changed, 123 insertions, 68 deletions
diff --git a/net/dsa/dsa.c b/net/dsa/dsa.c
index 76e3800765f8..aa398bcef9e3 100644
--- a/net/dsa/dsa.c
+++ b/net/dsa/dsa.c
@@ -326,8 +326,8 @@ static int dsa_switch_setup_one(struct dsa_switch *ds, struct device *parent)
ret = dsa_slave_create(ds, parent, i, pd->port_names[i]);
if (ret < 0) {
- netdev_err(dst->master_netdev, "[%d]: can't create dsa slave device for port %d(%s)\n",
- index, i, pd->port_names[i]);
+ netdev_err(dst->master_netdev, "[%d]: can't create dsa slave device for port %d(%s): %d\n",
+ index, i, pd->port_names[i], ret);
ret = 0;
}
}
@@ -634,6 +634,10 @@ static void dsa_of_free_platform_data(struct dsa_platform_data *pd)
port_index++;
}
kfree(pd->chip[i].rtable);
+
+ /* Drop our reference to the MDIO bus device */
+ if (pd->chip[i].host_dev)
+ put_device(pd->chip[i].host_dev);
}
kfree(pd->chip);
}
@@ -661,16 +665,22 @@ static int dsa_of_probe(struct device *dev)
return -EPROBE_DEFER;
ethernet = of_parse_phandle(np, "dsa,ethernet", 0);
- if (!ethernet)
- return -EINVAL;
+ if (!ethernet) {
+ ret = -EINVAL;
+ goto out_put_mdio;
+ }
ethernet_dev = of_find_net_device_by_node(ethernet);
- if (!ethernet_dev)
- return -EPROBE_DEFER;
+ if (!ethernet_dev) {
+ ret = -EPROBE_DEFER;
+ goto out_put_mdio;
+ }
pd = kzalloc(sizeof(*pd), GFP_KERNEL);
- if (!pd)
- return -ENOMEM;
+ if (!pd) {
+ ret = -ENOMEM;
+ goto out_put_ethernet;
+ }
dev->platform_data = pd;
pd->of_netdev = ethernet_dev;
@@ -691,7 +701,9 @@ static int dsa_of_probe(struct device *dev)
cd = &pd->chip[chip_index];
cd->of_node = child;
- cd->host_dev = &mdio_bus->dev;
+
+ /* When assigning the host device, increment its refcount */
+ cd->host_dev = get_device(&mdio_bus->dev);
sw_addr = of_get_property(child, "reg", NULL);
if (!sw_addr)
@@ -711,6 +723,12 @@ static int dsa_of_probe(struct device *dev)
ret = -EPROBE_DEFER;
goto out_free_chip;
}
+
+ /* Drop the mdio_bus device ref, replacing the host
+ * device with the mdio_bus_switch device, keeping
+ * the refcount from of_mdio_find_bus() above.
+ */
+ put_device(cd->host_dev);
cd->host_dev = &mdio_bus_switch->dev;
}
@@ -744,6 +762,10 @@ static int dsa_of_probe(struct device *dev)
}
}
+ /* The individual chips hold their own refcount on the mdio bus,
+ * so drop ours */
+ put_device(&mdio_bus->dev);
+
return 0;
out_free_chip:
@@ -751,6 +773,10 @@ out_free_chip:
out_free:
kfree(pd);
dev->platform_data = NULL;
+out_put_ethernet:
+ put_device(&ethernet_dev->dev);
+out_put_mdio:
+ put_device(&mdio_bus->dev);
return ret;
}
@@ -762,6 +788,7 @@ static void dsa_of_remove(struct device *dev)
return;
dsa_of_free_platform_data(pd);
+ put_device(&pd->of_netdev->dev);
kfree(pd);
}
#else
diff --git a/net/dsa/slave.c b/net/dsa/slave.c
index cce97385f743..bb2bd3b56b16 100644
--- a/net/dsa/slave.c
+++ b/net/dsa/slave.c
@@ -242,16 +242,15 @@ static int dsa_bridge_check_vlan_range(struct dsa_switch *ds,
}
static int dsa_slave_port_vlan_add(struct net_device *dev,
- struct switchdev_obj *obj)
+ const struct switchdev_obj_port_vlan *vlan,
+ struct switchdev_trans *trans)
{
- struct switchdev_obj_vlan *vlan = &obj->u.vlan;
struct dsa_slave_priv *p = netdev_priv(dev);
struct dsa_switch *ds = p->parent;
u16 vid;
int err;
- switch (obj->trans) {
- case SWITCHDEV_TRANS_PREPARE:
+ if (switchdev_trans_ph_prepare(trans)) {
if (!ds->drv->port_vlan_add || !ds->drv->port_pvid_set)
return -EOPNOTSUPP;
@@ -263,8 +262,7 @@ static int dsa_slave_port_vlan_add(struct net_device *dev,
vlan->vid_end);
if (err)
return err;
- break;
- case SWITCHDEV_TRANS_COMMIT:
+ } else {
for (vid = vlan->vid_begin; vid <= vlan->vid_end; ++vid) {
err = ds->drv->port_vlan_add(ds, p->port, vid,
vlan->flags &
@@ -274,18 +272,14 @@ static int dsa_slave_port_vlan_add(struct net_device *dev,
if (err)
return err;
}
- break;
- default:
- return -EOPNOTSUPP;
}
return 0;
}
static int dsa_slave_port_vlan_del(struct net_device *dev,
- struct switchdev_obj *obj)
+ const struct switchdev_obj_port_vlan *vlan)
{
- struct switchdev_obj_vlan *vlan = &obj->u.vlan;
struct dsa_slave_priv *p = netdev_priv(dev);
struct dsa_switch *ds = p->parent;
u16 vid;
@@ -304,9 +298,9 @@ static int dsa_slave_port_vlan_del(struct net_device *dev,
}
static int dsa_slave_port_vlan_dump(struct net_device *dev,
- struct switchdev_obj *obj)
+ struct switchdev_obj_port_vlan *vlan,
+ switchdev_obj_dump_cb_t *cb)
{
- struct switchdev_obj_vlan *vlan = &obj->u.vlan;
struct dsa_slave_priv *p = netdev_priv(dev);
struct dsa_switch *ds = p->parent;
DECLARE_BITMAP(members, DSA_MAX_PORTS);
@@ -338,7 +332,7 @@ static int dsa_slave_port_vlan_dump(struct net_device *dev,
if (test_bit(p->port, untagged))
vlan->flags |= BRIDGE_VLAN_INFO_UNTAGGED;
- err = obj->cb(dev, obj);
+ err = cb(&vlan->obj);
if (err)
break;
}
@@ -347,37 +341,40 @@ static int dsa_slave_port_vlan_dump(struct net_device *dev,
}
static int dsa_slave_port_fdb_add(struct net_device *dev,
- struct switchdev_obj *obj)
+ const struct switchdev_obj_port_fdb *fdb,
+ struct switchdev_trans *trans)
{
- struct switchdev_obj_fdb *fdb = &obj->u.fdb;
struct dsa_slave_priv *p = netdev_priv(dev);
struct dsa_switch *ds = p->parent;
- int ret = -EOPNOTSUPP;
+ int ret;
- if (obj->trans == SWITCHDEV_TRANS_PREPARE)
- ret = ds->drv->port_fdb_add ? 0 : -EOPNOTSUPP;
- else if (obj->trans == SWITCHDEV_TRANS_COMMIT)
- ret = ds->drv->port_fdb_add(ds, p->port, fdb->addr, fdb->vid);
+ if (!ds->drv->port_fdb_prepare || !ds->drv->port_fdb_add)
+ return -EOPNOTSUPP;
+
+ if (switchdev_trans_ph_prepare(trans))
+ ret = ds->drv->port_fdb_prepare(ds, p->port, fdb, trans);
+ else
+ ret = ds->drv->port_fdb_add(ds, p->port, fdb, trans);
return ret;
}
static int dsa_slave_port_fdb_del(struct net_device *dev,
- struct switchdev_obj *obj)
+ const struct switchdev_obj_port_fdb *fdb)
{
- struct switchdev_obj_fdb *fdb = &obj->u.fdb;
struct dsa_slave_priv *p = netdev_priv(dev);
struct dsa_switch *ds = p->parent;
int ret = -EOPNOTSUPP;
if (ds->drv->port_fdb_del)
- ret = ds->drv->port_fdb_del(ds, p->port, fdb->addr, fdb->vid);
+ ret = ds->drv->port_fdb_del(ds, p->port, fdb);
return ret;
}
static int dsa_slave_port_fdb_dump(struct net_device *dev,
- struct switchdev_obj *obj)
+ struct switchdev_obj_port_fdb *fdb,
+ switchdev_obj_dump_cb_t *cb)
{
struct dsa_slave_priv *p = netdev_priv(dev);
struct dsa_switch *ds = p->parent;
@@ -396,11 +393,11 @@ static int dsa_slave_port_fdb_dump(struct net_device *dev,
if (ret < 0)
break;
- obj->u.fdb.addr = addr;
- obj->u.fdb.vid = vid;
- obj->u.fdb.ndm_state = is_static ? NUD_NOARP : NUD_REACHABLE;
+ fdb->addr = addr;
+ fdb->vid = vid;
+ fdb->ndm_state = is_static ? NUD_NOARP : NUD_REACHABLE;
- ret = obj->cb(dev, obj);
+ ret = cb(&fdb->obj);
if (ret < 0)
break;
}
@@ -456,14 +453,20 @@ static int dsa_slave_stp_update(struct net_device *dev, u8 state)
}
static int dsa_slave_port_attr_set(struct net_device *dev,
- struct switchdev_attr *attr)
+ struct switchdev_attr *attr,
+ struct switchdev_trans *trans)
{
- int ret = 0;
+ struct dsa_slave_priv *p = netdev_priv(dev);
+ struct dsa_switch *ds = p->parent;
+ int ret;
switch (attr->id) {
- case SWITCHDEV_ATTR_PORT_STP_STATE:
- if (attr->trans == SWITCHDEV_TRANS_COMMIT)
- ret = dsa_slave_stp_update(dev, attr->u.stp_state);
+ case SWITCHDEV_ATTR_ID_PORT_STP_STATE:
+ if (switchdev_trans_ph_prepare(trans))
+ ret = ds->drv->port_stp_update ? 0 : -EOPNOTSUPP;
+ else
+ ret = ds->drv->port_stp_update(ds, p->port,
+ attr->u.stp_state);
break;
default:
ret = -EOPNOTSUPP;
@@ -474,7 +477,8 @@ static int dsa_slave_port_attr_set(struct net_device *dev,
}
static int dsa_slave_port_obj_add(struct net_device *dev,
- struct switchdev_obj *obj)
+ const struct switchdev_obj *obj,
+ struct switchdev_trans *trans)
{
int err;
@@ -484,11 +488,15 @@ static int dsa_slave_port_obj_add(struct net_device *dev,
*/
switch (obj->id) {
- case SWITCHDEV_OBJ_PORT_FDB:
- err = dsa_slave_port_fdb_add(dev, obj);
+ case SWITCHDEV_OBJ_ID_PORT_FDB:
+ err = dsa_slave_port_fdb_add(dev,
+ SWITCHDEV_OBJ_PORT_FDB(obj),
+ trans);
break;
- case SWITCHDEV_OBJ_PORT_VLAN:
- err = dsa_slave_port_vlan_add(dev, obj);
+ case SWITCHDEV_OBJ_ID_PORT_VLAN:
+ err = dsa_slave_port_vlan_add(dev,
+ SWITCHDEV_OBJ_PORT_VLAN(obj),
+ trans);
break;
default:
err = -EOPNOTSUPP;
@@ -499,16 +507,18 @@ static int dsa_slave_port_obj_add(struct net_device *dev,
}
static int dsa_slave_port_obj_del(struct net_device *dev,
- struct switchdev_obj *obj)
+ const struct switchdev_obj *obj)
{
int err;
switch (obj->id) {
- case SWITCHDEV_OBJ_PORT_FDB:
- err = dsa_slave_port_fdb_del(dev, obj);
+ case SWITCHDEV_OBJ_ID_PORT_FDB:
+ err = dsa_slave_port_fdb_del(dev,
+ SWITCHDEV_OBJ_PORT_FDB(obj));
break;
- case SWITCHDEV_OBJ_PORT_VLAN:
- err = dsa_slave_port_vlan_del(dev, obj);
+ case SWITCHDEV_OBJ_ID_PORT_VLAN:
+ err = dsa_slave_port_vlan_del(dev,
+ SWITCHDEV_OBJ_PORT_VLAN(obj));
break;
default:
err = -EOPNOTSUPP;
@@ -519,16 +529,21 @@ static int dsa_slave_port_obj_del(struct net_device *dev,
}
static int dsa_slave_port_obj_dump(struct net_device *dev,
- struct switchdev_obj *obj)
+ struct switchdev_obj *obj,
+ switchdev_obj_dump_cb_t *cb)
{
int err;
switch (obj->id) {
- case SWITCHDEV_OBJ_PORT_FDB:
- err = dsa_slave_port_fdb_dump(dev, obj);
+ case SWITCHDEV_OBJ_ID_PORT_FDB:
+ err = dsa_slave_port_fdb_dump(dev,
+ SWITCHDEV_OBJ_PORT_FDB(obj),
+ cb);
break;
- case SWITCHDEV_OBJ_PORT_VLAN:
- err = dsa_slave_port_vlan_dump(dev, obj);
+ case SWITCHDEV_OBJ_ID_PORT_VLAN:
+ err = dsa_slave_port_vlan_dump(dev,
+ SWITCHDEV_OBJ_PORT_VLAN(obj),
+ cb);
break;
default:
err = -EOPNOTSUPP;
@@ -582,7 +597,7 @@ static int dsa_slave_port_attr_get(struct net_device *dev,
struct dsa_switch *ds = p->parent;
switch (attr->id) {
- case SWITCHDEV_ATTR_PORT_PARENT_ID:
+ case SWITCHDEV_ATTR_ID_PORT_PARENT_ID:
attr->u.ppid.id_len = sizeof(ds->index);
memcpy(&attr->u.ppid.id, &ds->index, attr->u.ppid.id_len);
break;
@@ -962,6 +977,10 @@ static const struct switchdev_ops dsa_slave_switchdev_ops = {
.switchdev_port_obj_dump = dsa_slave_port_obj_dump,
};
+static struct device_type dsa_type = {
+ .name = "dsa",
+};
+
static void dsa_slave_adjust_link(struct net_device *dev)
{
struct dsa_slave_priv *p = netdev_priv(dev);
@@ -1010,8 +1029,10 @@ static int dsa_slave_phy_connect(struct dsa_slave_priv *p,
struct dsa_switch *ds = p->parent;
p->phy = ds->slave_mii_bus->phy_map[addr];
- if (!p->phy)
+ if (!p->phy) {
+ netdev_err(slave_dev, "no phy at %d\n", addr);
return -ENODEV;
+ }
/* Use already configured phy mode */
if (p->phy_interface == PHY_INTERFACE_MODE_NA)
@@ -1045,7 +1066,7 @@ static int dsa_slave_phy_setup(struct dsa_slave_priv *p,
*/
ret = of_phy_register_fixed_link(port_dn);
if (ret) {
- netdev_err(slave_dev, "failed to register fixed PHY\n");
+ netdev_err(slave_dev, "failed to register fixed PHY: %d\n", ret);
return ret;
}
phy_is_fixed = true;
@@ -1056,17 +1077,20 @@ static int dsa_slave_phy_setup(struct dsa_slave_priv *p,
phy_flags = ds->drv->get_phy_flags(ds, p->port);
if (phy_dn) {
- ret = of_mdio_parse_addr(&slave_dev->dev, phy_dn);
+ int phy_id = of_mdio_parse_addr(&slave_dev->dev, phy_dn);
+
/* If this PHY address is part of phys_mii_mask, which means
* that we need to divert reads and writes to/from it, then we
* want to bind this device using the slave MII bus created by
* DSA to make that happen.
*/
- if (!phy_is_fixed && ret >= 0 &&
- (ds->phys_mii_mask & (1 << ret))) {
- ret = dsa_slave_phy_connect(p, slave_dev, ret);
- if (ret)
+ if (!phy_is_fixed && phy_id >= 0 &&
+ (ds->phys_mii_mask & (1 << phy_id))) {
+ ret = dsa_slave_phy_connect(p, slave_dev, phy_id);
+ if (ret) {
+ netdev_err(slave_dev, "failed to connect to phy%d: %d\n", phy_id, ret);
return ret;
+ }
} else {
p->phy = of_phy_connect(slave_dev, phy_dn,
dsa_slave_adjust_link,
@@ -1083,8 +1107,10 @@ static int dsa_slave_phy_setup(struct dsa_slave_priv *p,
*/
if (!p->phy) {
ret = dsa_slave_phy_connect(p, slave_dev, p->port);
- if (ret)
+ if (ret) {
+ netdev_err(slave_dev, "failed to connect to port %d: %d\n", p->port, ret);
return ret;
+ }
} else {
netdev_info(slave_dev, "attached PHY at address %d [%s]\n",
p->phy->addr, p->phy->drv->name);
@@ -1150,6 +1176,7 @@ int dsa_slave_create(struct dsa_switch *ds, struct device *parent,
slave_dev->priv_flags |= IFF_NO_QUEUE;
slave_dev->netdev_ops = &dsa_slave_netdev_ops;
slave_dev->switchdev_ops = &dsa_slave_switchdev_ops;
+ SET_NETDEV_DEVTYPE(slave_dev, &dsa_type);
netdev_for_each_tx_queue(slave_dev, dsa_slave_set_lockdep_class_one,
NULL);
@@ -1195,6 +1222,7 @@ int dsa_slave_create(struct dsa_switch *ds, struct device *parent,
ret = dsa_slave_phy_setup(p, slave_dev);
if (ret) {
+ netdev_err(master, "error %d setting up slave phy\n", ret);
free_netdev(slave_dev);
return ret;
}
diff --git a/net/dsa/tag_trailer.c b/net/dsa/tag_trailer.c
index d25efc93d8f1..b6ca0890d018 100644
--- a/net/dsa/tag_trailer.c
+++ b/net/dsa/tag_trailer.c
@@ -78,7 +78,7 @@ static int trailer_rcv(struct sk_buff *skb, struct net_device *dev,
trailer = skb_tail_pointer(skb) - 4;
if (trailer[0] != 0x80 || (trailer[1] & 0xf8) != 0x00 ||
- (trailer[3] & 0xef) != 0x00 || trailer[3] != 0x00)
+ (trailer[2] & 0xef) != 0x00 || trailer[3] != 0x00)
goto out_drop;
source_port = trailer[1] & 7;