From c06ee961d3c0e51009cbd0e123b61fbb97f37d0b Mon Sep 17 00:00:00 2001 From: WANG Cong Date: Thu, 6 May 2010 00:48:24 -0700 Subject: bridge: make bridge support netpoll Based on the previous patch, make bridge support netpoll by: 1) implement the 2 methods to support netpoll for bridge; 2) modify netpoll during forwarding packets via bridge; 3) disable netpoll support of bridge when a netpoll-unabled device is added to bridge; 4) enable netpoll support when all underlying devices support netpoll. Cc: David Miller Cc: Neil Horman Cc: Stephen Hemminger Cc: Matt Mackall Signed-off-by: WANG Cong Signed-off-by: David S. Miller --- net/bridge/br_device.c | 59 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) (limited to 'net/bridge/br_device.c') diff --git a/net/bridge/br_device.c b/net/bridge/br_device.c index 8259940..074c596 100644 --- a/net/bridge/br_device.c +++ b/net/bridge/br_device.c @@ -13,8 +13,10 @@ #include #include +#include #include #include +#include #include #include "br_private.h" @@ -188,6 +190,59 @@ static int br_set_tx_csum(struct net_device *dev, u32 data) return 0; } +#ifdef CONFIG_NET_POLL_CONTROLLER +bool br_devices_support_netpoll(struct net_bridge *br) +{ + struct net_bridge_port *p; + bool ret = true; + int count = 0; + unsigned long flags; + + spin_lock_irqsave(&br->lock, flags); + list_for_each_entry(p, &br->port_list, list) { + count++; + if ((p->dev->priv_flags & IFF_DISABLE_NETPOLL) || + !p->dev->netdev_ops->ndo_poll_controller) + ret = false; + } + spin_unlock_irqrestore(&br->lock, flags); + return count != 0 && ret; +} + +static void br_poll_controller(struct net_device *br_dev) +{ + struct netpoll *np = br_dev->npinfo->netpoll; + + if (np->real_dev != br_dev) + netpoll_poll_dev(np->real_dev); +} + +void br_netpoll_cleanup(struct net_device *br_dev) +{ + struct net_bridge *br = netdev_priv(br_dev); + struct net_bridge_port *p, *n; + const struct net_device_ops *ops; + + br->dev->npinfo = NULL; + list_for_each_entry_safe(p, n, &br->port_list, list) { + if (p->dev) { + ops = p->dev->netdev_ops; + if (ops->ndo_netpoll_cleanup) + ops->ndo_netpoll_cleanup(p->dev); + else + p->dev->npinfo = NULL; + } + } +} + +#else + +void br_netpoll_cleanup(struct net_device *br_dev) +{ +} + +#endif + static const struct ethtool_ops br_ethtool_ops = { .get_drvinfo = br_getinfo, .get_link = ethtool_op_get_link, @@ -211,6 +266,10 @@ static const struct net_device_ops br_netdev_ops = { .ndo_set_multicast_list = br_dev_set_multicast_list, .ndo_change_mtu = br_change_mtu, .ndo_do_ioctl = br_dev_ioctl, +#ifdef CONFIG_NET_POLL_CONTROLLER + .ndo_netpoll_cleanup = br_netpoll_cleanup, + .ndo_poll_controller = br_poll_controller, +#endif }; static void br_dev_free(struct net_device *dev) -- cgit v1.1