aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/team/team.c
diff options
context:
space:
mode:
authorJiri Pirko <jiri@resnulli.us>2012-07-17 01:22:36 -0400
committerDavid S. Miller <davem@davemloft.net>2012-07-17 12:02:36 -0400
commitbd2d0837abc0206ecdd3f6b9fc8c25b55b63c96b (patch)
treed420a4e51965ae8b680562535d7ec9aace815f8e /drivers/net/team/team.c
parent30fdd8a082a00126a6feec994e43e8dc12f5bccb (diff)
team: add netpoll support
It's done in very similar way this is done in bonding and bridge. Signed-off-by: Jiri Pirko <jiri@resnulli.us> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/team/team.c')
-rw-r--r--drivers/net/team/team.c113
1 files changed, 113 insertions, 0 deletions
diff --git a/drivers/net/team/team.c b/drivers/net/team/team.c
index 3620c63f9345..1a13470dee07 100644
--- a/drivers/net/team/team.c
+++ b/drivers/net/team/team.c
@@ -18,6 +18,7 @@
18#include <linux/ctype.h> 18#include <linux/ctype.h>
19#include <linux/notifier.h> 19#include <linux/notifier.h>
20#include <linux/netdevice.h> 20#include <linux/netdevice.h>
21#include <linux/netpoll.h>
21#include <linux/if_vlan.h> 22#include <linux/if_vlan.h>
22#include <linux/if_arp.h> 23#include <linux/if_arp.h>
23#include <linux/socket.h> 24#include <linux/socket.h>
@@ -787,6 +788,58 @@ static void team_port_leave(struct team *team, struct team_port *port)
787 dev_put(team->dev); 788 dev_put(team->dev);
788} 789}
789 790
791#ifdef CONFIG_NET_POLL_CONTROLLER
792static int team_port_enable_netpoll(struct team *team, struct team_port *port)
793{
794 struct netpoll *np;
795 int err;
796
797 np = kzalloc(sizeof(*np), GFP_KERNEL);
798 if (!np)
799 return -ENOMEM;
800
801 err = __netpoll_setup(np, port->dev);
802 if (err) {
803 kfree(np);
804 return err;
805 }
806 port->np = np;
807 return err;
808}
809
810static void team_port_disable_netpoll(struct team_port *port)
811{
812 struct netpoll *np = port->np;
813
814 if (!np)
815 return;
816 port->np = NULL;
817
818 /* Wait for transmitting packets to finish before freeing. */
819 synchronize_rcu_bh();
820 __netpoll_cleanup(np);
821 kfree(np);
822}
823
824static struct netpoll_info *team_netpoll_info(struct team *team)
825{
826 return team->dev->npinfo;
827}
828
829#else
830static int team_port_enable_netpoll(struct team *team, struct team_port *port)
831{
832 return 0;
833}
834static void team_port_disable_netpoll(struct team_port *port)
835{
836}
837static struct netpoll_info *team_netpoll_info(struct team *team)
838{
839 return NULL;
840}
841#endif
842
790static void __team_port_change_check(struct team_port *port, bool linkup); 843static void __team_port_change_check(struct team_port *port, bool linkup);
791 844
792static int team_port_add(struct team *team, struct net_device *port_dev) 845static int team_port_add(struct team *team, struct net_device *port_dev)
@@ -853,6 +906,15 @@ static int team_port_add(struct team *team, struct net_device *port_dev)
853 goto err_vids_add; 906 goto err_vids_add;
854 } 907 }
855 908
909 if (team_netpoll_info(team)) {
910 err = team_port_enable_netpoll(team, port);
911 if (err) {
912 netdev_err(dev, "Failed to enable netpoll on device %s\n",
913 portname);
914 goto err_enable_netpoll;
915 }
916 }
917
856 err = netdev_set_master(port_dev, dev); 918 err = netdev_set_master(port_dev, dev);
857 if (err) { 919 if (err) {
858 netdev_err(dev, "Device %s failed to set master\n", portname); 920 netdev_err(dev, "Device %s failed to set master\n", portname);
@@ -892,6 +954,9 @@ err_handler_register:
892 netdev_set_master(port_dev, NULL); 954 netdev_set_master(port_dev, NULL);
893 955
894err_set_master: 956err_set_master:
957 team_port_disable_netpoll(port);
958
959err_enable_netpoll:
895 vlan_vids_del_by_dev(port_dev, dev); 960 vlan_vids_del_by_dev(port_dev, dev);
896 961
897err_vids_add: 962err_vids_add:
@@ -932,6 +997,7 @@ static int team_port_del(struct team *team, struct net_device *port_dev)
932 list_del_rcu(&port->list); 997 list_del_rcu(&port->list);
933 netdev_rx_handler_unregister(port_dev); 998 netdev_rx_handler_unregister(port_dev);
934 netdev_set_master(port_dev, NULL); 999 netdev_set_master(port_dev, NULL);
1000 team_port_disable_netpoll(port);
935 vlan_vids_del_by_dev(port_dev, dev); 1001 vlan_vids_del_by_dev(port_dev, dev);
936 dev_close(port_dev); 1002 dev_close(port_dev);
937 team_port_leave(team, port); 1003 team_port_leave(team, port);
@@ -1307,6 +1373,48 @@ static int team_vlan_rx_kill_vid(struct net_device *dev, uint16_t vid)
1307 return 0; 1373 return 0;
1308} 1374}
1309 1375
1376#ifdef CONFIG_NET_POLL_CONTROLLER
1377static void team_poll_controller(struct net_device *dev)
1378{
1379}
1380
1381static void __team_netpoll_cleanup(struct team *team)
1382{
1383 struct team_port *port;
1384
1385 list_for_each_entry(port, &team->port_list, list)
1386 team_port_disable_netpoll(port);
1387}
1388
1389static void team_netpoll_cleanup(struct net_device *dev)
1390{
1391 struct team *team = netdev_priv(dev);
1392
1393 mutex_lock(&team->lock);
1394 __team_netpoll_cleanup(team);
1395 mutex_unlock(&team->lock);
1396}
1397
1398static int team_netpoll_setup(struct net_device *dev,
1399 struct netpoll_info *npifo)
1400{
1401 struct team *team = netdev_priv(dev);
1402 struct team_port *port;
1403 int err;
1404
1405 mutex_lock(&team->lock);
1406 list_for_each_entry(port, &team->port_list, list) {
1407 err = team_port_enable_netpoll(team, port);
1408 if (err) {
1409 __team_netpoll_cleanup(team);
1410 break;
1411 }
1412 }
1413 mutex_unlock(&team->lock);
1414 return err;
1415}
1416#endif
1417
1310static int team_add_slave(struct net_device *dev, struct net_device *port_dev) 1418static int team_add_slave(struct net_device *dev, struct net_device *port_dev)
1311{ 1419{
1312 struct team *team = netdev_priv(dev); 1420 struct team *team = netdev_priv(dev);
@@ -1363,6 +1471,11 @@ static const struct net_device_ops team_netdev_ops = {
1363 .ndo_get_stats64 = team_get_stats64, 1471 .ndo_get_stats64 = team_get_stats64,
1364 .ndo_vlan_rx_add_vid = team_vlan_rx_add_vid, 1472 .ndo_vlan_rx_add_vid = team_vlan_rx_add_vid,
1365 .ndo_vlan_rx_kill_vid = team_vlan_rx_kill_vid, 1473 .ndo_vlan_rx_kill_vid = team_vlan_rx_kill_vid,
1474#ifdef CONFIG_NET_POLL_CONTROLLER
1475 .ndo_poll_controller = team_poll_controller,
1476 .ndo_netpoll_setup = team_netpoll_setup,
1477 .ndo_netpoll_cleanup = team_netpoll_cleanup,
1478#endif
1366 .ndo_add_slave = team_add_slave, 1479 .ndo_add_slave = team_add_slave,
1367 .ndo_del_slave = team_del_slave, 1480 .ndo_del_slave = team_del_slave,
1368 .ndo_fix_features = team_fix_features, 1481 .ndo_fix_features = team_fix_features,