aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorFlorian Fainelli <f.fainelli@gmail.com>2015-07-31 14:42:57 -0400
committerDavid S. Miller <davem@davemloft.net>2015-07-31 18:45:37 -0400
commit04ff53f96a931751a70c2bb3926770900b5fbebe (patch)
treee5fe8108bf859f4f57c66a24eaebd8118dcf2778 /net
parent4ed70ce9f01c998999e48642a768d9013bee2c4f (diff)
net: dsa: Add netconsole support
Add support for using DSA slave network devices with netconsole, which requires us to allocate and free custom netpoll instances and invoke the parent network device poll controller callback. In order for netconsole to work, we need to construct the DSA tag, but not queue the skb for transmission on the master network device xmit function. Signed-off-by: Florian Fainelli <f.fainelli@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net')
-rw-r--r--net/dsa/dsa_priv.h4
-rw-r--r--net/dsa/slave.c67
2 files changed, 71 insertions, 0 deletions
diff --git a/net/dsa/dsa_priv.h b/net/dsa/dsa_priv.h
index eeade901e67a..311796c809af 100644
--- a/net/dsa/dsa_priv.h
+++ b/net/dsa/dsa_priv.h
@@ -13,6 +13,7 @@
13 13
14#include <linux/phy.h> 14#include <linux/phy.h>
15#include <linux/netdevice.h> 15#include <linux/netdevice.h>
16#include <linux/netpoll.h>
16 17
17struct dsa_device_ops { 18struct dsa_device_ops {
18 struct sk_buff *(*xmit)(struct sk_buff *skb, struct net_device *dev); 19 struct sk_buff *(*xmit)(struct sk_buff *skb, struct net_device *dev);
@@ -47,6 +48,9 @@ struct dsa_slave_priv {
47 int old_duplex; 48 int old_duplex;
48 49
49 struct net_device *bridge_dev; 50 struct net_device *bridge_dev;
51#ifdef CONFIG_NET_POLL_CONTROLLER
52 struct netpoll *netpoll;
53#endif
50}; 54};
51 55
52/* dsa.c */ 56/* dsa.c */
diff --git a/net/dsa/slave.c b/net/dsa/slave.c
index 5fc87ee53905..0010c690cc67 100644
--- a/net/dsa/slave.c
+++ b/net/dsa/slave.c
@@ -18,6 +18,7 @@
18#include <net/rtnetlink.h> 18#include <net/rtnetlink.h>
19#include <net/switchdev.h> 19#include <net/switchdev.h>
20#include <linux/if_bridge.h> 20#include <linux/if_bridge.h>
21#include <linux/netpoll.h>
21#include "dsa_priv.h" 22#include "dsa_priv.h"
22 23
23/* slave mii_bus handling ***************************************************/ 24/* slave mii_bus handling ***************************************************/
@@ -418,6 +419,18 @@ static int dsa_slave_port_attr_get(struct net_device *dev,
418 return 0; 419 return 0;
419} 420}
420 421
422static inline netdev_tx_t dsa_netpoll_send_skb(struct dsa_slave_priv *p,
423 struct sk_buff *skb)
424{
425#ifdef CONFIG_NET_POLL_CONTROLLER
426 if (p->netpoll)
427 netpoll_send_skb(p->netpoll, skb);
428#else
429 BUG();
430#endif
431 return NETDEV_TX_OK;
432}
433
421static netdev_tx_t dsa_slave_xmit(struct sk_buff *skb, struct net_device *dev) 434static netdev_tx_t dsa_slave_xmit(struct sk_buff *skb, struct net_device *dev)
422{ 435{
423 struct dsa_slave_priv *p = netdev_priv(dev); 436 struct dsa_slave_priv *p = netdev_priv(dev);
@@ -431,6 +444,12 @@ static netdev_tx_t dsa_slave_xmit(struct sk_buff *skb, struct net_device *dev)
431 if (!nskb) 444 if (!nskb)
432 return NETDEV_TX_OK; 445 return NETDEV_TX_OK;
433 446
447 /* SKB for netpoll still need to be mangled with the protocol-specific
448 * tag to be successfully transmitted
449 */
450 if (unlikely(netpoll_tx_running(dev)))
451 return dsa_netpoll_send_skb(p, nskb);
452
434 /* Queue the SKB for transmission on the parent interface, but 453 /* Queue the SKB for transmission on the parent interface, but
435 * do not modify its EtherType 454 * do not modify its EtherType
436 */ 455 */
@@ -676,6 +695,49 @@ static int dsa_slave_get_eee(struct net_device *dev, struct ethtool_eee *e)
676 return ret; 695 return ret;
677} 696}
678 697
698#ifdef CONFIG_NET_POLL_CONTROLLER
699static int dsa_slave_netpoll_setup(struct net_device *dev,
700 struct netpoll_info *ni)
701{
702 struct dsa_slave_priv *p = netdev_priv(dev);
703 struct dsa_switch *ds = p->parent;
704 struct net_device *master = ds->dst->master_netdev;
705 struct netpoll *netpoll;
706 int err = 0;
707
708 netpoll = kzalloc(sizeof(*netpoll), GFP_KERNEL);
709 if (!netpoll)
710 return -ENOMEM;
711
712 err = __netpoll_setup(netpoll, master);
713 if (err) {
714 kfree(netpoll);
715 goto out;
716 }
717
718 p->netpoll = netpoll;
719out:
720 return err;
721}
722
723static void dsa_slave_netpoll_cleanup(struct net_device *dev)
724{
725 struct dsa_slave_priv *p = netdev_priv(dev);
726 struct netpoll *netpoll = p->netpoll;
727
728 if (!netpoll)
729 return;
730
731 p->netpoll = NULL;
732
733 __netpoll_free_async(netpoll);
734}
735
736static void dsa_slave_poll_controller(struct net_device *dev)
737{
738}
739#endif
740
679static const struct ethtool_ops dsa_slave_ethtool_ops = { 741static const struct ethtool_ops dsa_slave_ethtool_ops = {
680 .get_settings = dsa_slave_get_settings, 742 .get_settings = dsa_slave_get_settings,
681 .set_settings = dsa_slave_set_settings, 743 .set_settings = dsa_slave_set_settings,
@@ -708,6 +770,11 @@ static const struct net_device_ops dsa_slave_netdev_ops = {
708 .ndo_fdb_dump = dsa_slave_fdb_dump, 770 .ndo_fdb_dump = dsa_slave_fdb_dump,
709 .ndo_do_ioctl = dsa_slave_ioctl, 771 .ndo_do_ioctl = dsa_slave_ioctl,
710 .ndo_get_iflink = dsa_slave_get_iflink, 772 .ndo_get_iflink = dsa_slave_get_iflink,
773#ifdef CONFIG_NET_POLL_CONTROLLER
774 .ndo_netpoll_setup = dsa_slave_netpoll_setup,
775 .ndo_netpoll_cleanup = dsa_slave_netpoll_cleanup,
776 .ndo_poll_controller = dsa_slave_poll_controller,
777#endif
711}; 778};
712 779
713static const struct switchdev_ops dsa_slave_switchdev_ops = { 780static const struct switchdev_ops dsa_slave_switchdev_ops = {