diff options
author | Benjamin LaHaise <bcrl@kvack.org> | 2011-12-08 01:20:49 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2011-12-08 19:58:30 -0500 |
commit | 6d4cdf47d2cc9d40227c67c79a4942e36ed1b0ba (patch) | |
tree | 5c31e3f1be3ba098f57ae33796e50ea50dcee1e9 /net/8021q | |
parent | 8af2a218de38f51ea4b4fa48cac1273319ae260c (diff) |
vlan: add 802.1q netpoll support
Add netpoll support to 802.1q vlan devices. Based on the netpoll support
in the bridging code. Tested on a forced_eth device with netconsole.
Signed-off-by: Benjamin LaHaise <bcrl@kvack.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/8021q')
-rw-r--r-- | net/8021q/vlan.h | 5 | ||||
-rw-r--r-- | net/8021q/vlan_dev.c | 59 |
2 files changed, 64 insertions, 0 deletions
diff --git a/net/8021q/vlan.h b/net/8021q/vlan.h index 28d8dc20cb6d..a4886d94c40c 100644 --- a/net/8021q/vlan.h +++ b/net/8021q/vlan.h | |||
@@ -41,6 +41,8 @@ struct vlan_pcpu_stats { | |||
41 | u32 tx_dropped; | 41 | u32 tx_dropped; |
42 | }; | 42 | }; |
43 | 43 | ||
44 | struct netpoll; | ||
45 | |||
44 | /** | 46 | /** |
45 | * struct vlan_dev_priv - VLAN private device data | 47 | * struct vlan_dev_priv - VLAN private device data |
46 | * @nr_ingress_mappings: number of ingress priority mappings | 48 | * @nr_ingress_mappings: number of ingress priority mappings |
@@ -68,6 +70,9 @@ struct vlan_dev_priv { | |||
68 | 70 | ||
69 | struct proc_dir_entry *dent; | 71 | struct proc_dir_entry *dent; |
70 | struct vlan_pcpu_stats __percpu *vlan_pcpu_stats; | 72 | struct vlan_pcpu_stats __percpu *vlan_pcpu_stats; |
73 | #ifdef CONFIG_NET_POLL_CONTROLLER | ||
74 | struct netpoll *netpoll; | ||
75 | #endif | ||
71 | }; | 76 | }; |
72 | 77 | ||
73 | static inline struct vlan_dev_priv *vlan_dev_priv(const struct net_device *dev) | 78 | static inline struct vlan_dev_priv *vlan_dev_priv(const struct net_device *dev) |
diff --git a/net/8021q/vlan_dev.c b/net/8021q/vlan_dev.c index 3b4db82b016f..039013923a74 100644 --- a/net/8021q/vlan_dev.c +++ b/net/8021q/vlan_dev.c | |||
@@ -33,6 +33,7 @@ | |||
33 | #include "vlan.h" | 33 | #include "vlan.h" |
34 | #include "vlanproc.h" | 34 | #include "vlanproc.h" |
35 | #include <linux/if_vlan.h> | 35 | #include <linux/if_vlan.h> |
36 | #include <linux/netpoll.h> | ||
36 | 37 | ||
37 | /* | 38 | /* |
38 | * Rebuild the Ethernet MAC header. This is called after an ARP | 39 | * Rebuild the Ethernet MAC header. This is called after an ARP |
@@ -158,6 +159,8 @@ static netdev_tx_t vlan_dev_hard_start_xmit(struct sk_buff *skb, | |||
158 | 159 | ||
159 | skb_set_dev(skb, vlan_dev_priv(dev)->real_dev); | 160 | skb_set_dev(skb, vlan_dev_priv(dev)->real_dev); |
160 | len = skb->len; | 161 | len = skb->len; |
162 | if (netpoll_tx_running(dev)) | ||
163 | return skb->dev->netdev_ops->ndo_start_xmit(skb, skb->dev); | ||
161 | ret = dev_queue_xmit(skb); | 164 | ret = dev_queue_xmit(skb); |
162 | 165 | ||
163 | if (likely(ret == NET_XMIT_SUCCESS || ret == NET_XMIT_CN)) { | 166 | if (likely(ret == NET_XMIT_SUCCESS || ret == NET_XMIT_CN)) { |
@@ -660,6 +663,57 @@ static struct rtnl_link_stats64 *vlan_dev_get_stats64(struct net_device *dev, st | |||
660 | return stats; | 663 | return stats; |
661 | } | 664 | } |
662 | 665 | ||
666 | #ifdef CONFIG_NET_POLL_CONTROLLER | ||
667 | void vlan_dev_poll_controller(struct net_device *dev) | ||
668 | { | ||
669 | return; | ||
670 | } | ||
671 | |||
672 | int vlan_dev_netpoll_setup(struct net_device *dev, struct netpoll_info *npinfo) | ||
673 | { | ||
674 | struct vlan_dev_priv *info = vlan_dev_priv(dev); | ||
675 | struct net_device *real_dev = info->real_dev; | ||
676 | struct netpoll *netpoll; | ||
677 | int err = 0; | ||
678 | |||
679 | netpoll = kzalloc(sizeof(*netpoll), GFP_KERNEL); | ||
680 | err = -ENOMEM; | ||
681 | if (!netpoll) | ||
682 | goto out; | ||
683 | |||
684 | netpoll->dev = real_dev; | ||
685 | strlcpy(netpoll->dev_name, real_dev->name, IFNAMSIZ); | ||
686 | |||
687 | err = __netpoll_setup(netpoll); | ||
688 | if (err) { | ||
689 | kfree(netpoll); | ||
690 | goto out; | ||
691 | } | ||
692 | |||
693 | info->netpoll = netpoll; | ||
694 | |||
695 | out: | ||
696 | return err; | ||
697 | } | ||
698 | |||
699 | void vlan_dev_netpoll_cleanup(struct net_device *dev) | ||
700 | { | ||
701 | struct vlan_dev_priv *info = vlan_dev_priv(dev); | ||
702 | struct netpoll *netpoll = info->netpoll; | ||
703 | |||
704 | if (!netpoll) | ||
705 | return; | ||
706 | |||
707 | info->netpoll = NULL; | ||
708 | |||
709 | /* Wait for transmitting packets to finish before freeing. */ | ||
710 | synchronize_rcu_bh(); | ||
711 | |||
712 | __netpoll_cleanup(netpoll); | ||
713 | kfree(netpoll); | ||
714 | } | ||
715 | #endif /* CONFIG_NET_POLL_CONTROLLER */ | ||
716 | |||
663 | static const struct ethtool_ops vlan_ethtool_ops = { | 717 | static const struct ethtool_ops vlan_ethtool_ops = { |
664 | .get_settings = vlan_ethtool_get_settings, | 718 | .get_settings = vlan_ethtool_get_settings, |
665 | .get_drvinfo = vlan_ethtool_get_drvinfo, | 719 | .get_drvinfo = vlan_ethtool_get_drvinfo, |
@@ -688,6 +742,11 @@ static const struct net_device_ops vlan_netdev_ops = { | |||
688 | .ndo_fcoe_get_wwn = vlan_dev_fcoe_get_wwn, | 742 | .ndo_fcoe_get_wwn = vlan_dev_fcoe_get_wwn, |
689 | .ndo_fcoe_ddp_target = vlan_dev_fcoe_ddp_target, | 743 | .ndo_fcoe_ddp_target = vlan_dev_fcoe_ddp_target, |
690 | #endif | 744 | #endif |
745 | #ifdef CONFIG_NET_POLL_CONTROLLER | ||
746 | .ndo_poll_controller = vlan_dev_poll_controller, | ||
747 | .ndo_netpoll_setup = vlan_dev_netpoll_setup, | ||
748 | .ndo_netpoll_cleanup = vlan_dev_netpoll_cleanup, | ||
749 | #endif | ||
691 | .ndo_fix_features = vlan_dev_fix_features, | 750 | .ndo_fix_features = vlan_dev_fix_features, |
692 | }; | 751 | }; |
693 | 752 | ||