diff options
Diffstat (limited to 'drivers/net/hyperv/netvsc_drv.c')
-rw-r--r-- | drivers/net/hyperv/netvsc_drv.c | 62 |
1 files changed, 52 insertions, 10 deletions
diff --git a/drivers/net/hyperv/netvsc_drv.c b/drivers/net/hyperv/netvsc_drv.c index c5584c2d440e..cdb78eefab67 100644 --- a/drivers/net/hyperv/netvsc_drv.c +++ b/drivers/net/hyperv/netvsc_drv.c | |||
@@ -66,10 +66,36 @@ static int debug = -1; | |||
66 | module_param(debug, int, S_IRUGO); | 66 | module_param(debug, int, S_IRUGO); |
67 | MODULE_PARM_DESC(debug, "Debug level (0=none,...,16=all)"); | 67 | MODULE_PARM_DESC(debug, "Debug level (0=none,...,16=all)"); |
68 | 68 | ||
69 | static void netvsc_set_multicast_list(struct net_device *net) | 69 | static void netvsc_change_rx_flags(struct net_device *net, int change) |
70 | { | 70 | { |
71 | struct net_device_context *net_device_ctx = netdev_priv(net); | 71 | struct net_device_context *ndev_ctx = netdev_priv(net); |
72 | struct netvsc_device *nvdev = rtnl_dereference(net_device_ctx->nvdev); | 72 | struct net_device *vf_netdev = rtnl_dereference(ndev_ctx->vf_netdev); |
73 | int inc; | ||
74 | |||
75 | if (!vf_netdev) | ||
76 | return; | ||
77 | |||
78 | if (change & IFF_PROMISC) { | ||
79 | inc = (net->flags & IFF_PROMISC) ? 1 : -1; | ||
80 | dev_set_promiscuity(vf_netdev, inc); | ||
81 | } | ||
82 | |||
83 | if (change & IFF_ALLMULTI) { | ||
84 | inc = (net->flags & IFF_ALLMULTI) ? 1 : -1; | ||
85 | dev_set_allmulti(vf_netdev, inc); | ||
86 | } | ||
87 | } | ||
88 | |||
89 | static void netvsc_set_rx_mode(struct net_device *net) | ||
90 | { | ||
91 | struct net_device_context *ndev_ctx = netdev_priv(net); | ||
92 | struct net_device *vf_netdev = rtnl_dereference(ndev_ctx->vf_netdev); | ||
93 | struct netvsc_device *nvdev = rtnl_dereference(ndev_ctx->nvdev); | ||
94 | |||
95 | if (vf_netdev) { | ||
96 | dev_uc_sync(vf_netdev, net); | ||
97 | dev_mc_sync(vf_netdev, net); | ||
98 | } | ||
73 | 99 | ||
74 | rndis_filter_update(nvdev); | 100 | rndis_filter_update(nvdev); |
75 | } | 101 | } |
@@ -91,12 +117,11 @@ static int netvsc_open(struct net_device *net) | |||
91 | return ret; | 117 | return ret; |
92 | } | 118 | } |
93 | 119 | ||
94 | netif_tx_wake_all_queues(net); | ||
95 | |||
96 | rdev = nvdev->extension; | 120 | rdev = nvdev->extension; |
97 | 121 | if (!rdev->link_state) { | |
98 | if (!rdev->link_state) | ||
99 | netif_carrier_on(net); | 122 | netif_carrier_on(net); |
123 | netif_tx_wake_all_queues(net); | ||
124 | } | ||
100 | 125 | ||
101 | if (vf_netdev) { | 126 | if (vf_netdev) { |
102 | /* Setting synthetic device up transparently sets | 127 | /* Setting synthetic device up transparently sets |
@@ -299,8 +324,19 @@ static u16 netvsc_select_queue(struct net_device *ndev, struct sk_buff *skb, | |||
299 | rcu_read_lock(); | 324 | rcu_read_lock(); |
300 | vf_netdev = rcu_dereference(ndc->vf_netdev); | 325 | vf_netdev = rcu_dereference(ndc->vf_netdev); |
301 | if (vf_netdev) { | 326 | if (vf_netdev) { |
302 | txq = skb_rx_queue_recorded(skb) ? skb_get_rx_queue(skb) : 0; | 327 | const struct net_device_ops *vf_ops = vf_netdev->netdev_ops; |
303 | qdisc_skb_cb(skb)->slave_dev_queue_mapping = skb->queue_mapping; | 328 | |
329 | if (vf_ops->ndo_select_queue) | ||
330 | txq = vf_ops->ndo_select_queue(vf_netdev, skb, | ||
331 | accel_priv, fallback); | ||
332 | else | ||
333 | txq = fallback(vf_netdev, skb); | ||
334 | |||
335 | /* Record the queue selected by VF so that it can be | ||
336 | * used for common case where VF has more queues than | ||
337 | * the synthetic device. | ||
338 | */ | ||
339 | qdisc_skb_cb(skb)->slave_dev_queue_mapping = txq; | ||
304 | } else { | 340 | } else { |
305 | txq = netvsc_pick_tx(ndev, skb); | 341 | txq = netvsc_pick_tx(ndev, skb); |
306 | } | 342 | } |
@@ -1576,7 +1612,8 @@ static const struct net_device_ops device_ops = { | |||
1576 | .ndo_open = netvsc_open, | 1612 | .ndo_open = netvsc_open, |
1577 | .ndo_stop = netvsc_close, | 1613 | .ndo_stop = netvsc_close, |
1578 | .ndo_start_xmit = netvsc_start_xmit, | 1614 | .ndo_start_xmit = netvsc_start_xmit, |
1579 | .ndo_set_rx_mode = netvsc_set_multicast_list, | 1615 | .ndo_change_rx_flags = netvsc_change_rx_flags, |
1616 | .ndo_set_rx_mode = netvsc_set_rx_mode, | ||
1580 | .ndo_change_mtu = netvsc_change_mtu, | 1617 | .ndo_change_mtu = netvsc_change_mtu, |
1581 | .ndo_validate_addr = eth_validate_addr, | 1618 | .ndo_validate_addr = eth_validate_addr, |
1582 | .ndo_set_mac_address = netvsc_set_mac_addr, | 1619 | .ndo_set_mac_address = netvsc_set_mac_addr, |
@@ -1807,6 +1844,11 @@ static void __netvsc_vf_setup(struct net_device *ndev, | |||
1807 | netdev_warn(vf_netdev, | 1844 | netdev_warn(vf_netdev, |
1808 | "unable to change mtu to %u\n", ndev->mtu); | 1845 | "unable to change mtu to %u\n", ndev->mtu); |
1809 | 1846 | ||
1847 | /* set multicast etc flags on VF */ | ||
1848 | dev_change_flags(vf_netdev, ndev->flags | IFF_SLAVE); | ||
1849 | dev_uc_sync(vf_netdev, ndev); | ||
1850 | dev_mc_sync(vf_netdev, ndev); | ||
1851 | |||
1810 | if (netif_running(ndev)) { | 1852 | if (netif_running(ndev)) { |
1811 | ret = dev_open(vf_netdev); | 1853 | ret = dev_open(vf_netdev); |
1812 | if (ret) | 1854 | if (ret) |