These changes are the raw update to linux-4.4.6-rt14. Kernel sources
[kvmfornfv.git] / kernel / net / dsa / slave.c
index 57978c5..7bc787b 100644 (file)
@@ -18,6 +18,7 @@
 #include <net/rtnetlink.h>
 #include <net/switchdev.h>
 #include <linux/if_bridge.h>
+#include <linux/netpoll.h>
 #include "dsa_priv.h"
 
 /* slave mii_bus handling ***************************************************/
@@ -112,7 +113,7 @@ static int dsa_slave_open(struct net_device *dev)
 
 clear_promisc:
        if (dev->flags & IFF_PROMISC)
-               dev_set_promiscuity(master, 0);
+               dev_set_promiscuity(master, -1);
 clear_allmulti:
        if (dev->flags & IFF_ALLMULTI)
                dev_set_allmulti(master, -1);
@@ -199,103 +200,178 @@ out:
        return 0;
 }
 
-static int dsa_slave_fdb_add(struct ndmsg *ndm, struct nlattr *tb[],
-                            struct net_device *dev,
-                            const unsigned char *addr, u16 vid, u16 nlm_flags)
+static int dsa_bridge_check_vlan_range(struct dsa_switch *ds,
+                                      const struct net_device *bridge,
+                                      u16 vid_begin, u16 vid_end)
+{
+       struct dsa_slave_priv *p;
+       struct net_device *dev, *vlan_br;
+       DECLARE_BITMAP(members, DSA_MAX_PORTS);
+       DECLARE_BITMAP(untagged, DSA_MAX_PORTS);
+       u16 vid;
+       int member, err;
+
+       if (!ds->drv->vlan_getnext || !vid_begin)
+               return -EOPNOTSUPP;
+
+       vid = vid_begin - 1;
+
+       do {
+               err = ds->drv->vlan_getnext(ds, &vid, members, untagged);
+               if (err)
+                       break;
+
+               if (vid > vid_end)
+                       break;
+
+               member = find_first_bit(members, DSA_MAX_PORTS);
+               if (member == DSA_MAX_PORTS)
+                       continue;
+
+               dev = ds->ports[member];
+               p = netdev_priv(dev);
+               vlan_br = p->bridge_dev;
+               if (vlan_br == bridge)
+                       continue;
+
+               netdev_dbg(vlan_br, "hardware VLAN %d already in use\n", vid);
+               return -EOPNOTSUPP;
+       } while (vid < vid_end);
+
+       return err == -ENOENT ? 0 : err;
+}
+
+static int dsa_slave_port_vlan_add(struct net_device *dev,
+                                  const struct switchdev_obj_port_vlan *vlan,
+                                  struct switchdev_trans *trans)
 {
        struct dsa_slave_priv *p = netdev_priv(dev);
        struct dsa_switch *ds = p->parent;
-       int ret = -EOPNOTSUPP;
+       int err;
 
-       if (ds->drv->fdb_add)
-               ret = ds->drv->fdb_add(ds, p->port, addr, vid);
+       if (switchdev_trans_ph_prepare(trans)) {
+               if (!ds->drv->port_vlan_prepare || !ds->drv->port_vlan_add)
+                       return -EOPNOTSUPP;
 
-       return ret;
+               /* If the requested port doesn't belong to the same bridge as
+                * the VLAN members, fallback to software VLAN (hopefully).
+                */
+               err = dsa_bridge_check_vlan_range(ds, p->bridge_dev,
+                                                 vlan->vid_begin,
+                                                 vlan->vid_end);
+               if (err)
+                       return err;
+
+               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_fdb_del(struct ndmsg *ndm, struct nlattr *tb[],
-                            struct net_device *dev,
-                            const unsigned char *addr, u16 vid)
+static int dsa_slave_port_vlan_del(struct net_device *dev,
+                                  const struct switchdev_obj_port_vlan *vlan)
 {
        struct dsa_slave_priv *p = netdev_priv(dev);
        struct dsa_switch *ds = p->parent;
-       int ret = -EOPNOTSUPP;
 
-       if (ds->drv->fdb_del)
-               ret = ds->drv->fdb_del(ds, p->port, addr, vid);
+       if (!ds->drv->port_vlan_del)
+               return -EOPNOTSUPP;
 
-       return ret;
+       return ds->drv->port_vlan_del(ds, p->port, vlan);
 }
 
-static int dsa_slave_fill_info(struct net_device *dev, struct sk_buff *skb,
-                              const unsigned char *addr, u16 vid,
-                              bool is_static,
-                              u32 portid, u32 seq, int type,
-                              unsigned int flags)
+static int dsa_slave_port_vlan_dump(struct net_device *dev,
+                                   struct switchdev_obj_port_vlan *vlan,
+                                   switchdev_obj_dump_cb_t *cb)
 {
-       struct nlmsghdr *nlh;
-       struct ndmsg *ndm;
+       struct dsa_slave_priv *p = netdev_priv(dev);
+       struct dsa_switch *ds = p->parent;
+       DECLARE_BITMAP(members, DSA_MAX_PORTS);
+       DECLARE_BITMAP(untagged, DSA_MAX_PORTS);
+       u16 pvid, vid = 0;
+       int err;
+
+       if (!ds->drv->vlan_getnext || !ds->drv->port_pvid_get)
+               return -EOPNOTSUPP;
+
+       err = ds->drv->port_pvid_get(ds, p->port, &pvid);
+       if (err)
+               return err;
+
+       for (;;) {
+               err = ds->drv->vlan_getnext(ds, &vid, members, untagged);
+               if (err)
+                       break;
 
-       nlh = nlmsg_put(skb, portid, seq, type, sizeof(*ndm), flags);
-       if (!nlh)
-               return -EMSGSIZE;
+               if (!test_bit(p->port, members))
+                       continue;
 
-       ndm = nlmsg_data(nlh);
-       ndm->ndm_family  = AF_BRIDGE;
-       ndm->ndm_pad1    = 0;
-       ndm->ndm_pad2    = 0;
-       ndm->ndm_flags   = NTF_EXT_LEARNED;
-       ndm->ndm_type    = 0;
-       ndm->ndm_ifindex = dev->ifindex;
-       ndm->ndm_state   = is_static ? NUD_NOARP : NUD_REACHABLE;
+               memset(vlan, 0, sizeof(*vlan));
+               vlan->vid_begin = vlan->vid_end = vid;
 
-       if (nla_put(skb, NDA_LLADDR, ETH_ALEN, addr))
-               goto nla_put_failure;
+               if (vid == pvid)
+                       vlan->flags |= BRIDGE_VLAN_INFO_PVID;
 
-       if (vid && nla_put_u16(skb, NDA_VLAN, vid))
-               goto nla_put_failure;
+               if (test_bit(p->port, untagged))
+                       vlan->flags |= BRIDGE_VLAN_INFO_UNTAGGED;
 
-       nlmsg_end(skb, nlh);
-       return 0;
+               err = cb(&vlan->obj);
+               if (err)
+                       break;
+       }
 
-nla_put_failure:
-       nlmsg_cancel(skb, nlh);
-       return -EMSGSIZE;
+       return err == -ENOENT ? 0 : err;
 }
 
-/* Dump information about entries, in response to GETNEIGH */
-static int dsa_slave_fdb_dump(struct sk_buff *skb, struct netlink_callback *cb,
-                             struct net_device *dev,
-                             struct net_device *filter_dev, int idx)
+static int dsa_slave_port_fdb_add(struct net_device *dev,
+                                 const struct switchdev_obj_port_fdb *fdb,
+                                 struct switchdev_trans *trans)
 {
        struct dsa_slave_priv *p = netdev_priv(dev);
        struct dsa_switch *ds = p->parent;
-       unsigned char addr[ETH_ALEN] = { 0 };
        int ret;
 
-       if (!ds->drv->fdb_getnext)
+       if (!ds->drv->port_fdb_prepare || !ds->drv->port_fdb_add)
                return -EOPNOTSUPP;
 
-       for (; ; idx++) {
-               bool is_static;
+       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);
 
-               ret = ds->drv->fdb_getnext(ds, p->port, addr, &is_static);
-               if (ret < 0)
-                       break;
+       return ret;
+}
 
-               if (idx < cb->args[0])
-                       continue;
+static int dsa_slave_port_fdb_del(struct net_device *dev,
+                                 const struct switchdev_obj_port_fdb *fdb)
+{
+       struct dsa_slave_priv *p = netdev_priv(dev);
+       struct dsa_switch *ds = p->parent;
+       int ret = -EOPNOTSUPP;
 
-               ret = dsa_slave_fill_info(dev, skb, addr, 0,
-                                         is_static,
-                                         NETLINK_CB(cb->skb).portid,
-                                         cb->nlh->nlmsg_seq,
-                                         RTM_NEWNEIGH, NLM_F_MULTI);
-               if (ret < 0)
-                       break;
-       }
+       if (ds->drv->port_fdb_del)
+               ret = ds->drv->port_fdb_del(ds, p->port, fdb);
 
-       return idx;
+       return ret;
+}
+
+static int dsa_slave_port_fdb_dump(struct net_device *dev,
+                                  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;
+
+       if (ds->drv->port_fdb_dump)
+               return ds->drv->port_fdb_dump(ds, p->port, fdb, cb);
+
+       return -EOPNOTSUPP;
 }
 
 static int dsa_slave_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
@@ -345,6 +421,107 @@ static int dsa_slave_stp_update(struct net_device *dev, u8 state)
        return ret;
 }
 
+static int dsa_slave_port_attr_set(struct net_device *dev,
+                                  const struct switchdev_attr *attr,
+                                  struct switchdev_trans *trans)
+{
+       struct dsa_slave_priv *p = netdev_priv(dev);
+       struct dsa_switch *ds = p->parent;
+       int ret;
+
+       switch (attr->id) {
+       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;
+               break;
+       }
+
+       return ret;
+}
+
+static int dsa_slave_port_obj_add(struct net_device *dev,
+                                 const struct switchdev_obj *obj,
+                                 struct switchdev_trans *trans)
+{
+       int err;
+
+       /* For the prepare phase, ensure the full set of changes is feasable in
+        * one go in order to signal a failure properly. If an operation is not
+        * supported, return -EOPNOTSUPP.
+        */
+
+       switch (obj->id) {
+       case SWITCHDEV_OBJ_ID_PORT_FDB:
+               err = dsa_slave_port_fdb_add(dev,
+                                            SWITCHDEV_OBJ_PORT_FDB(obj),
+                                            trans);
+               break;
+       case SWITCHDEV_OBJ_ID_PORT_VLAN:
+               err = dsa_slave_port_vlan_add(dev,
+                                             SWITCHDEV_OBJ_PORT_VLAN(obj),
+                                             trans);
+               break;
+       default:
+               err = -EOPNOTSUPP;
+               break;
+       }
+
+       return err;
+}
+
+static int dsa_slave_port_obj_del(struct net_device *dev,
+                                 const struct switchdev_obj *obj)
+{
+       int err;
+
+       switch (obj->id) {
+       case SWITCHDEV_OBJ_ID_PORT_FDB:
+               err = dsa_slave_port_fdb_del(dev,
+                                            SWITCHDEV_OBJ_PORT_FDB(obj));
+               break;
+       case SWITCHDEV_OBJ_ID_PORT_VLAN:
+               err = dsa_slave_port_vlan_del(dev,
+                                             SWITCHDEV_OBJ_PORT_VLAN(obj));
+               break;
+       default:
+               err = -EOPNOTSUPP;
+               break;
+       }
+
+       return err;
+}
+
+static int dsa_slave_port_obj_dump(struct net_device *dev,
+                                  struct switchdev_obj *obj,
+                                  switchdev_obj_dump_cb_t *cb)
+{
+       int err;
+
+       switch (obj->id) {
+       case SWITCHDEV_OBJ_ID_PORT_FDB:
+               err = dsa_slave_port_fdb_dump(dev,
+                                             SWITCHDEV_OBJ_PORT_FDB(obj),
+                                             cb);
+               break;
+       case SWITCHDEV_OBJ_ID_PORT_VLAN:
+               err = dsa_slave_port_vlan_dump(dev,
+                                              SWITCHDEV_OBJ_PORT_VLAN(obj),
+                                              cb);
+               break;
+       default:
+               err = -EOPNOTSUPP;
+               break;
+       }
+
+       return err;
+}
+
 static int dsa_slave_bridge_port_join(struct net_device *dev,
                                      struct net_device *br)
 {
@@ -382,36 +559,71 @@ static int dsa_slave_bridge_port_leave(struct net_device *dev)
        return ret;
 }
 
-static int dsa_slave_parent_id_get(struct net_device *dev,
-                                  struct netdev_phys_item_id *psid)
+static int dsa_slave_port_attr_get(struct net_device *dev,
+                                  struct switchdev_attr *attr)
 {
        struct dsa_slave_priv *p = netdev_priv(dev);
        struct dsa_switch *ds = p->parent;
 
-       psid->id_len = sizeof(ds->index);
-       memcpy(&psid->id, &ds->index, psid->id_len);
+       switch (attr->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;
+       default:
+               return -EOPNOTSUPP;
+       }
 
        return 0;
 }
 
-static netdev_tx_t dsa_slave_xmit(struct sk_buff *skb, struct net_device *dev)
+static inline netdev_tx_t dsa_netpoll_send_skb(struct dsa_slave_priv *p,
+                                              struct sk_buff *skb)
 {
-       struct dsa_slave_priv *p = netdev_priv(dev);
-
-       return p->xmit(skb, dev);
+#ifdef CONFIG_NET_POLL_CONTROLLER
+       if (p->netpoll)
+               netpoll_send_skb(p->netpoll, skb);
+#else
+       BUG();
+#endif
+       return NETDEV_TX_OK;
 }
 
-static netdev_tx_t dsa_slave_notag_xmit(struct sk_buff *skb,
-                                       struct net_device *dev)
+static netdev_tx_t dsa_slave_xmit(struct sk_buff *skb, struct net_device *dev)
 {
        struct dsa_slave_priv *p = netdev_priv(dev);
+       struct sk_buff *nskb;
+
+       dev->stats.tx_packets++;
+       dev->stats.tx_bytes += skb->len;
+
+       /* Transmit function may have to reallocate the original SKB */
+       nskb = p->xmit(skb, dev);
+       if (!nskb)
+               return NETDEV_TX_OK;
+
+       /* SKB for netpoll still need to be mangled with the protocol-specific
+        * tag to be successfully transmitted
+        */
+       if (unlikely(netpoll_tx_running(dev)))
+               return dsa_netpoll_send_skb(p, nskb);
 
-       skb->dev = p->parent->dst->master_netdev;
-       dev_queue_xmit(skb);
+       /* Queue the SKB for transmission on the parent interface, but
+        * do not modify its EtherType
+        */
+       nskb->dev = p->parent->dst->master_netdev;
+       dev_queue_xmit(nskb);
 
        return NETDEV_TX_OK;
 }
 
+static struct sk_buff *dsa_slave_notag_xmit(struct sk_buff *skb,
+                                           struct net_device *dev)
+{
+       /* Just return the original SKB */
+       return skb;
+}
+
 
 /* ethtool operations *******************************************************/
 static int
@@ -641,6 +853,49 @@ static int dsa_slave_get_eee(struct net_device *dev, struct ethtool_eee *e)
        return ret;
 }
 
+#ifdef CONFIG_NET_POLL_CONTROLLER
+static int dsa_slave_netpoll_setup(struct net_device *dev,
+                                  struct netpoll_info *ni)
+{
+       struct dsa_slave_priv *p = netdev_priv(dev);
+       struct dsa_switch *ds = p->parent;
+       struct net_device *master = ds->dst->master_netdev;
+       struct netpoll *netpoll;
+       int err = 0;
+
+       netpoll = kzalloc(sizeof(*netpoll), GFP_KERNEL);
+       if (!netpoll)
+               return -ENOMEM;
+
+       err = __netpoll_setup(netpoll, master);
+       if (err) {
+               kfree(netpoll);
+               goto out;
+       }
+
+       p->netpoll = netpoll;
+out:
+       return err;
+}
+
+static void dsa_slave_netpoll_cleanup(struct net_device *dev)
+{
+       struct dsa_slave_priv *p = netdev_priv(dev);
+       struct netpoll *netpoll = p->netpoll;
+
+       if (!netpoll)
+               return;
+
+       p->netpoll = NULL;
+
+       __netpoll_free_async(netpoll);
+}
+
+static void dsa_slave_poll_controller(struct net_device *dev)
+{
+}
+#endif
+
 static const struct ethtool_ops dsa_slave_ethtool_ops = {
        .get_settings           = dsa_slave_get_settings,
        .set_settings           = dsa_slave_set_settings,
@@ -668,16 +923,31 @@ static const struct net_device_ops dsa_slave_netdev_ops = {
        .ndo_change_rx_flags    = dsa_slave_change_rx_flags,
        .ndo_set_rx_mode        = dsa_slave_set_rx_mode,
        .ndo_set_mac_address    = dsa_slave_set_mac_address,
-       .ndo_fdb_add            = dsa_slave_fdb_add,
-       .ndo_fdb_del            = dsa_slave_fdb_del,
-       .ndo_fdb_dump           = dsa_slave_fdb_dump,
+       .ndo_fdb_add            = switchdev_port_fdb_add,
+       .ndo_fdb_del            = switchdev_port_fdb_del,
+       .ndo_fdb_dump           = switchdev_port_fdb_dump,
        .ndo_do_ioctl           = dsa_slave_ioctl,
        .ndo_get_iflink         = dsa_slave_get_iflink,
+#ifdef CONFIG_NET_POLL_CONTROLLER
+       .ndo_netpoll_setup      = dsa_slave_netpoll_setup,
+       .ndo_netpoll_cleanup    = dsa_slave_netpoll_cleanup,
+       .ndo_poll_controller    = dsa_slave_poll_controller,
+#endif
+       .ndo_bridge_getlink     = switchdev_port_bridge_getlink,
+       .ndo_bridge_setlink     = switchdev_port_bridge_setlink,
+       .ndo_bridge_dellink     = switchdev_port_bridge_dellink,
+};
+
+static const struct switchdev_ops dsa_slave_switchdev_ops = {
+       .switchdev_port_attr_get        = dsa_slave_port_attr_get,
+       .switchdev_port_attr_set        = dsa_slave_port_attr_set,
+       .switchdev_port_obj_add         = dsa_slave_port_obj_add,
+       .switchdev_port_obj_del         = dsa_slave_port_obj_del,
+       .switchdev_port_obj_dump        = dsa_slave_port_obj_dump,
 };
 
-static const struct swdev_ops dsa_slave_swdev_ops = {
-       .swdev_parent_id_get = dsa_slave_parent_id_get,
-       .swdev_port_stp_update = dsa_slave_stp_update,
+static struct device_type dsa_type = {
+       .name   = "dsa",
 };
 
 static void dsa_slave_adjust_link(struct net_device *dev)
@@ -728,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)
@@ -763,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;
@@ -774,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,
@@ -801,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);
@@ -811,12 +1088,19 @@ static int dsa_slave_phy_setup(struct dsa_slave_priv *p,
        return 0;
 }
 
+static struct lock_class_key dsa_slave_netdev_xmit_lock_key;
+static void dsa_slave_set_lockdep_class_one(struct net_device *dev,
+                                           struct netdev_queue *txq,
+                                           void *_unused)
+{
+       lockdep_set_class(&txq->_xmit_lock,
+                         &dsa_slave_netdev_xmit_lock_key);
+}
+
 int dsa_slave_suspend(struct net_device *slave_dev)
 {
        struct dsa_slave_priv *p = netdev_priv(slave_dev);
 
-       netif_device_detach(slave_dev);
-
        if (p->phy) {
                phy_stop(p->phy);
                p->old_pause = -1;
@@ -858,9 +1142,13 @@ int dsa_slave_create(struct dsa_switch *ds, struct device *parent,
        slave_dev->features = master->vlan_features;
        slave_dev->ethtool_ops = &dsa_slave_ethtool_ops;
        eth_hw_addr_inherit(slave_dev, master);
-       slave_dev->tx_queue_len = 0;
+       slave_dev->priv_flags |= IFF_NO_QUEUE;
        slave_dev->netdev_ops = &dsa_slave_netdev_ops;
-       slave_dev->swdev_ops = &dsa_slave_swdev_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);
 
        SET_NETDEV_DEV(slave_dev, parent);
        slave_dev->dev.of_node = ds->pd->port_dn[port];
@@ -903,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;
        }
@@ -956,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;