net: dsa: change FDB routines prototypes
[firefly-linux-kernel-4.4.55.git] / net / dsa / slave.c
index 0917123790eaf09b001c97a733039185fdb0a800..3d341b694ecf68c8b82976377f8b506c1cef9a07 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 ***************************************************/
@@ -207,8 +208,8 @@ static int dsa_slave_fdb_add(struct ndmsg *ndm, struct nlattr *tb[],
        struct dsa_switch *ds = p->parent;
        int ret = -EOPNOTSUPP;
 
-       if (ds->drv->fdb_add)
-               ret = ds->drv->fdb_add(ds, p->port, addr, vid);
+       if (ds->drv->port_fdb_add)
+               ret = ds->drv->port_fdb_add(ds, p->port, addr, vid);
 
        return ret;
 }
@@ -221,8 +222,8 @@ static int dsa_slave_fdb_del(struct ndmsg *ndm, struct nlattr *tb[],
        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_fdb_del)
+               ret = ds->drv->port_fdb_del(ds, p->port, addr, vid);
 
        return ret;
 }
@@ -271,22 +272,24 @@ static int dsa_slave_fdb_dump(struct sk_buff *skb, struct netlink_callback *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->fdb_getnext)
+       if (!ds->drv->port_fdb_getnext)
                return -EOPNOTSUPP;
 
        for (; ; idx++) {
                bool is_static;
 
-               ret = ds->drv->fdb_getnext(ds, p->port, addr, &is_static);
+               ret = ds->drv->port_fdb_getnext(ds, p->port, addr, &vid,
+                                               &is_static);
                if (ret < 0)
                        break;
 
                if (idx < cb->args[0])
                        continue;
 
-               ret = dsa_slave_fill_info(dev, skb, addr, 0,
+               ret = dsa_slave_fill_info(dev, skb, addr, vid,
                                          is_static,
                                          NETLINK_CB(cb->skb).portid,
                                          cb->nlh->nlmsg_seq,
@@ -418,24 +421,53 @@ static int dsa_slave_port_attr_get(struct net_device *dev,
        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;
 
-       skb->dev = p->parent->dst->master_netdev;
-       dev_queue_xmit(skb);
+       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);
+
+       /* 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
@@ -665,6 +697,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,
@@ -697,6 +772,11 @@ static const struct net_device_ops dsa_slave_netdev_ops = {
        .ndo_fdb_dump           = dsa_slave_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
 };
 
 static const struct switchdev_ops dsa_slave_switchdev_ops = {