summaryrefslogtreecommitdiff
path: root/net/dsa
diff options
context:
space:
mode:
Diffstat (limited to 'net/dsa')
-rw-r--r--net/dsa/dsa.c115
-rw-r--r--net/dsa/slave.c193
-rw-r--r--net/dsa/tag_trailer.c2
3 files changed, 191 insertions, 119 deletions
diff --git a/net/dsa/dsa.c b/net/dsa/dsa.c
index 76e380076..1eba07f 100644
--- a/net/dsa/dsa.c
+++ b/net/dsa/dsa.c
@@ -22,6 +22,7 @@
#include <linux/of_platform.h>
#include <linux/of_net.h>
#include <linux/sysfs.h>
+#include <linux/phy_fixed.h>
#include "dsa_priv.h"
char dsa_driver_version[] = "0.1";
@@ -305,7 +306,7 @@ static int dsa_switch_setup_one(struct dsa_switch *ds, struct device *parent)
if (ret < 0)
goto out;
- ds->slave_mii_bus = mdiobus_alloc();
+ ds->slave_mii_bus = devm_mdiobus_alloc(parent);
if (ds->slave_mii_bus == NULL) {
ret = -ENOMEM;
goto out;
@@ -314,7 +315,7 @@ static int dsa_switch_setup_one(struct dsa_switch *ds, struct device *parent)
ret = mdiobus_register(ds->slave_mii_bus);
if (ret < 0)
- goto out_free;
+ goto out;
/*
@@ -326,8 +327,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;
}
}
@@ -367,10 +368,7 @@ static int dsa_switch_setup_one(struct dsa_switch *ds, struct device *parent)
return ret;
-out_free:
- mdiobus_free(ds->slave_mii_bus);
out:
- kfree(ds);
return ret;
}
@@ -400,7 +398,7 @@ dsa_switch_setup(struct dsa_switch_tree *dst, int index,
/*
* Allocate and initialise switch state.
*/
- ds = kzalloc(sizeof(*ds) + drv->priv_size, GFP_KERNEL);
+ ds = devm_kzalloc(parent, sizeof(*ds) + drv->priv_size, GFP_KERNEL);
if (ds == NULL)
return ERR_PTR(-ENOMEM);
@@ -420,10 +418,47 @@ dsa_switch_setup(struct dsa_switch_tree *dst, int index,
static void dsa_switch_destroy(struct dsa_switch *ds)
{
+ struct device_node *port_dn;
+ struct phy_device *phydev;
+ struct dsa_chip_data *cd = ds->pd;
+ int port;
+
#ifdef CONFIG_NET_DSA_HWMON
if (ds->hwmon_dev)
hwmon_device_unregister(ds->hwmon_dev);
#endif
+
+ /* Disable configuration of the CPU and DSA ports */
+ for (port = 0; port < DSA_MAX_PORTS; port++) {
+ if (!(dsa_is_cpu_port(ds, port) || dsa_is_dsa_port(ds, port)))
+ continue;
+
+ port_dn = cd->port_dn[port];
+ if (of_phy_is_fixed_link(port_dn)) {
+ phydev = of_phy_find_device(port_dn);
+ if (phydev) {
+ int addr = phydev->addr;
+
+ phy_device_free(phydev);
+ of_node_put(port_dn);
+ fixed_phy_del(addr);
+ }
+ }
+ }
+
+ /* Destroy network devices for physical switch ports. */
+ for (port = 0; port < DSA_MAX_PORTS; port++) {
+ if (!(ds->phys_port_mask & (1 << port)))
+ continue;
+
+ if (!ds->ports[port])
+ continue;
+
+ unregister_netdev(ds->ports[port]);
+ free_netdev(ds->ports[port]);
+ }
+
+ mdiobus_unregister(ds->slave_mii_bus);
}
#ifdef CONFIG_PM_SLEEP
@@ -634,6 +669,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 +700,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 +736,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 +758,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 +797,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 +808,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 +823,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
@@ -775,10 +837,11 @@ static inline void dsa_of_remove(struct device *dev)
}
#endif
-static void dsa_setup_dst(struct dsa_switch_tree *dst, struct net_device *dev,
- struct device *parent, struct dsa_platform_data *pd)
+static int dsa_setup_dst(struct dsa_switch_tree *dst, struct net_device *dev,
+ struct device *parent, struct dsa_platform_data *pd)
{
int i;
+ unsigned configured = 0;
dst->pd = pd;
dst->master_netdev = dev;
@@ -798,9 +861,17 @@ static void dsa_setup_dst(struct dsa_switch_tree *dst, struct net_device *dev,
dst->ds[i] = ds;
if (ds->drv->poll_link != NULL)
dst->link_poll_needed = 1;
+
+ ++configured;
}
/*
+ * If no switch was found, exit cleanly
+ */
+ if (!configured)
+ return -EPROBE_DEFER;
+
+ /*
* If we use a tagging format that doesn't have an ethertype
* field, make sure that all packets from this point on get
* sent to the tag format's receive function.
@@ -816,6 +887,8 @@ static void dsa_setup_dst(struct dsa_switch_tree *dst, struct net_device *dev,
dst->link_poll_timer.expires = round_jiffies(jiffies + HZ);
add_timer(&dst->link_poll_timer);
}
+
+ return 0;
}
static int dsa_probe(struct platform_device *pdev)
@@ -856,7 +929,7 @@ static int dsa_probe(struct platform_device *pdev)
goto out;
}
- dst = kzalloc(sizeof(*dst), GFP_KERNEL);
+ dst = devm_kzalloc(&pdev->dev, sizeof(*dst), GFP_KERNEL);
if (dst == NULL) {
dev_put(dev);
ret = -ENOMEM;
@@ -865,7 +938,9 @@ static int dsa_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, dst);
- dsa_setup_dst(dst, dev, &pdev->dev, pd);
+ ret = dsa_setup_dst(dst, dev, &pdev->dev, pd);
+ if (ret)
+ goto out;
return 0;
@@ -887,7 +962,7 @@ static void dsa_remove_dst(struct dsa_switch_tree *dst)
for (i = 0; i < dst->pd->nr_chips; i++) {
struct dsa_switch *ds = dst->ds[i];
- if (ds != NULL)
+ if (ds)
dsa_switch_destroy(ds);
}
}
diff --git a/net/dsa/slave.c b/net/dsa/slave.c
index cce9738..7bc787b 100644
--- a/net/dsa/slave.c
+++ b/net/dsa/slave.c
@@ -242,17 +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 (!ds->drv->port_vlan_add || !ds->drv->port_pvid_set)
+ if (switchdev_trans_ph_prepare(trans)) {
+ if (!ds->drv->port_vlan_prepare || !ds->drv->port_vlan_add)
return -EOPNOTSUPP;
/* If the requested port doesn't belong to the same bridge as
@@ -263,50 +261,35 @@ static int dsa_slave_port_vlan_add(struct net_device *dev,
vlan->vid_end);
if (err)
return err;
- break;
- case SWITCHDEV_TRANS_COMMIT:
- for (vid = vlan->vid_begin; vid <= vlan->vid_end; ++vid) {
- err = ds->drv->port_vlan_add(ds, p->port, vid,
- vlan->flags &
- BRIDGE_VLAN_INFO_UNTAGGED);
- if (!err && vlan->flags & BRIDGE_VLAN_INFO_PVID)
- err = ds->drv->port_pvid_set(ds, p->port, vid);
- if (err)
- return err;
- }
- break;
- default:
- return -EOPNOTSUPP;
+
+ err = ds->drv->port_vlan_prepare(ds, p->port, vlan, trans);
+ if (err)
+ return err;
+ } else {
+ err = ds->drv->port_vlan_add(ds, p->port, vlan, trans);
+ if (err)
+ return err;
}
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;
- int err;
if (!ds->drv->port_vlan_del)
return -EOPNOTSUPP;
- for (vid = vlan->vid_begin; vid <= vlan->vid_end; ++vid) {
- err = ds->drv->port_vlan_del(ds, p->port, vid);
- if (err)
- return err;
- }
-
- return 0;
+ return ds->drv->port_vlan_del(ds, p->port, vlan);
}
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 +321,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,65 +330,48 @@ 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 (!ds->drv->port_fdb_prepare || !ds->drv->port_fdb_add)
+ return -EOPNOTSUPP;
- 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 (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;
- unsigned char addr[ETH_ALEN] = { 0 };
- u16 vid = 0;
- int ret;
-
- if (!ds->drv->port_fdb_getnext)
- return -EOPNOTSUPP;
-
- for (;;) {
- bool is_static;
-
- ret = ds->drv->port_fdb_getnext(ds, p->port, addr, &vid,
- &is_static);
- 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;
- ret = obj->cb(dev, obj);
- if (ret < 0)
- break;
- }
+ if (ds->drv->port_fdb_dump)
+ return ds->drv->port_fdb_dump(ds, p->port, fdb, cb);
- return ret == -ENOENT ? 0 : ret;
+ return -EOPNOTSUPP;
}
static int dsa_slave_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
@@ -456,14 +422,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)
+ const 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 +446,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 +457,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 +476,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 +498,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 +566,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 +946,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 +998,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 +1035,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 +1046,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 +1076,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 +1145,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 +1191,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;
}
@@ -1248,7 +1245,7 @@ int dsa_slave_netdevice_event(struct notifier_block *unused,
goto out;
err = dsa_slave_master_changed(dev);
- if (err)
+ if (err && err != -EOPNOTSUPP)
netdev_warn(dev, "failed to reflect master change\n");
break;
diff --git a/net/dsa/tag_trailer.c b/net/dsa/tag_trailer.c
index d25efc9..b6ca089 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;