Skip to content

Commit 04ff53f

Browse files
ffainellidavem330
authored andcommitted
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 <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 4ed70ce commit 04ff53f

File tree

2 files changed

+71
-0
lines changed

2 files changed

+71
-0
lines changed

net/dsa/dsa_priv.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313

1414
#include <linux/phy.h>
1515
#include <linux/netdevice.h>
16+
#include <linux/netpoll.h>
1617

1718
struct dsa_device_ops {
1819
struct sk_buff *(*xmit)(struct sk_buff *skb, struct net_device *dev);
@@ -47,6 +48,9 @@ struct dsa_slave_priv {
4748
int old_duplex;
4849

4950
struct net_device *bridge_dev;
51+
#ifdef CONFIG_NET_POLL_CONTROLLER
52+
struct netpoll *netpoll;
53+
#endif
5054
};
5155

5256
/* dsa.c */

net/dsa/slave.c

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#include <net/rtnetlink.h>
1919
#include <net/switchdev.h>
2020
#include <linux/if_bridge.h>
21+
#include <linux/netpoll.h>
2122
#include "dsa_priv.h"
2223

2324
/* slave mii_bus handling ***************************************************/
@@ -418,6 +419,18 @@ static int dsa_slave_port_attr_get(struct net_device *dev,
418419
return 0;
419420
}
420421

422+
static 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+
421434
static netdev_tx_t dsa_slave_xmit(struct sk_buff *skb, struct net_device *dev)
422435
{
423436
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)
431444
if (!nskb)
432445
return NETDEV_TX_OK;
433446

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+
434453
/* Queue the SKB for transmission on the parent interface, but
435454
* do not modify its EtherType
436455
*/
@@ -676,6 +695,49 @@ static int dsa_slave_get_eee(struct net_device *dev, struct ethtool_eee *e)
676695
return ret;
677696
}
678697

698+
#ifdef CONFIG_NET_POLL_CONTROLLER
699+
static 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;
719+
out:
720+
return err;
721+
}
722+
723+
static 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+
736+
static void dsa_slave_poll_controller(struct net_device *dev)
737+
{
738+
}
739+
#endif
740+
679741
static const struct ethtool_ops dsa_slave_ethtool_ops = {
680742
.get_settings = dsa_slave_get_settings,
681743
.set_settings = dsa_slave_set_settings,
@@ -708,6 +770,11 @@ static const struct net_device_ops dsa_slave_netdev_ops = {
708770
.ndo_fdb_dump = dsa_slave_fdb_dump,
709771
.ndo_do_ioctl = dsa_slave_ioctl,
710772
.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
711778
};
712779

713780
static const struct switchdev_ops dsa_slave_switchdev_ops = {

0 commit comments

Comments
 (0)