diff options
| -rw-r--r-- | drivers/net/hyperv/netvsc.c | 33 | ||||
| -rw-r--r-- | drivers/net/hyperv/netvsc_drv.c | 62 | ||||
| -rw-r--r-- | drivers/net/hyperv/rndis_filter.c | 23 |
3 files changed, 79 insertions, 39 deletions
diff --git a/drivers/net/hyperv/netvsc.c b/drivers/net/hyperv/netvsc.c index 17e529af79dc..0265d703eb03 100644 --- a/drivers/net/hyperv/netvsc.c +++ b/drivers/net/hyperv/netvsc.c | |||
| @@ -852,13 +852,6 @@ int netvsc_send(struct net_device *ndev, | |||
| 852 | if (unlikely(!net_device || net_device->destroy)) | 852 | if (unlikely(!net_device || net_device->destroy)) |
| 853 | return -ENODEV; | 853 | return -ENODEV; |
| 854 | 854 | ||
| 855 | /* We may race with netvsc_connect_vsp()/netvsc_init_buf() and get | ||
| 856 | * here before the negotiation with the host is finished and | ||
| 857 | * send_section_map may not be allocated yet. | ||
| 858 | */ | ||
| 859 | if (unlikely(!net_device->send_section_map)) | ||
| 860 | return -EAGAIN; | ||
| 861 | |||
| 862 | nvchan = &net_device->chan_table[packet->q_idx]; | 855 | nvchan = &net_device->chan_table[packet->q_idx]; |
| 863 | packet->send_buf_index = NETVSC_INVALID_INDEX; | 856 | packet->send_buf_index = NETVSC_INVALID_INDEX; |
| 864 | packet->cp_partial = false; | 857 | packet->cp_partial = false; |
| @@ -866,10 +859,8 @@ int netvsc_send(struct net_device *ndev, | |||
| 866 | /* Send control message directly without accessing msd (Multi-Send | 859 | /* Send control message directly without accessing msd (Multi-Send |
| 867 | * Data) field which may be changed during data packet processing. | 860 | * Data) field which may be changed during data packet processing. |
| 868 | */ | 861 | */ |
| 869 | if (!skb) { | 862 | if (!skb) |
| 870 | cur_send = packet; | 863 | return netvsc_send_pkt(device, packet, net_device, pb, skb); |
| 871 | goto send_now; | ||
| 872 | } | ||
| 873 | 864 | ||
| 874 | /* batch packets in send buffer if possible */ | 865 | /* batch packets in send buffer if possible */ |
| 875 | msdp = &nvchan->msd; | 866 | msdp = &nvchan->msd; |
| @@ -953,7 +944,6 @@ int netvsc_send(struct net_device *ndev, | |||
| 953 | } | 944 | } |
| 954 | } | 945 | } |
| 955 | 946 | ||
| 956 | send_now: | ||
| 957 | if (cur_send) | 947 | if (cur_send) |
| 958 | ret = netvsc_send_pkt(device, cur_send, net_device, pb, skb); | 948 | ret = netvsc_send_pkt(device, cur_send, net_device, pb, skb); |
| 959 | 949 | ||
| @@ -1217,9 +1207,10 @@ int netvsc_poll(struct napi_struct *napi, int budget) | |||
| 1217 | if (send_recv_completions(ndev, net_device, nvchan) == 0 && | 1207 | if (send_recv_completions(ndev, net_device, nvchan) == 0 && |
| 1218 | work_done < budget && | 1208 | work_done < budget && |
| 1219 | napi_complete_done(napi, work_done) && | 1209 | napi_complete_done(napi, work_done) && |
| 1220 | hv_end_read(&channel->inbound)) { | 1210 | hv_end_read(&channel->inbound) && |
| 1211 | napi_schedule_prep(napi)) { | ||
| 1221 | hv_begin_read(&channel->inbound); | 1212 | hv_begin_read(&channel->inbound); |
| 1222 | napi_reschedule(napi); | 1213 | __napi_schedule(napi); |
| 1223 | } | 1214 | } |
| 1224 | 1215 | ||
| 1225 | /* Driver may overshoot since multiple packets per descriptor */ | 1216 | /* Driver may overshoot since multiple packets per descriptor */ |
| @@ -1242,7 +1233,7 @@ void netvsc_channel_cb(void *context) | |||
| 1242 | /* disable interupts from host */ | 1233 | /* disable interupts from host */ |
| 1243 | hv_begin_read(rbi); | 1234 | hv_begin_read(rbi); |
| 1244 | 1235 | ||
| 1245 | __napi_schedule(&nvchan->napi); | 1236 | __napi_schedule_irqoff(&nvchan->napi); |
| 1246 | } | 1237 | } |
| 1247 | } | 1238 | } |
| 1248 | 1239 | ||
| @@ -1296,7 +1287,6 @@ struct netvsc_device *netvsc_device_add(struct hv_device *device, | |||
| 1296 | netvsc_channel_cb, net_device->chan_table); | 1287 | netvsc_channel_cb, net_device->chan_table); |
| 1297 | 1288 | ||
| 1298 | if (ret != 0) { | 1289 | if (ret != 0) { |
| 1299 | netif_napi_del(&net_device->chan_table[0].napi); | ||
| 1300 | netdev_err(ndev, "unable to open channel: %d\n", ret); | 1290 | netdev_err(ndev, "unable to open channel: %d\n", ret); |
| 1301 | goto cleanup; | 1291 | goto cleanup; |
| 1302 | } | 1292 | } |
| @@ -1306,11 +1296,6 @@ struct netvsc_device *netvsc_device_add(struct hv_device *device, | |||
| 1306 | 1296 | ||
| 1307 | napi_enable(&net_device->chan_table[0].napi); | 1297 | napi_enable(&net_device->chan_table[0].napi); |
| 1308 | 1298 | ||
| 1309 | /* Writing nvdev pointer unlocks netvsc_send(), make sure chn_table is | ||
| 1310 | * populated. | ||
| 1311 | */ | ||
| 1312 | rcu_assign_pointer(net_device_ctx->nvdev, net_device); | ||
| 1313 | |||
| 1314 | /* Connect with the NetVsp */ | 1299 | /* Connect with the NetVsp */ |
| 1315 | ret = netvsc_connect_vsp(device, net_device, device_info); | 1300 | ret = netvsc_connect_vsp(device, net_device, device_info); |
| 1316 | if (ret != 0) { | 1301 | if (ret != 0) { |
| @@ -1319,6 +1304,11 @@ struct netvsc_device *netvsc_device_add(struct hv_device *device, | |||
| 1319 | goto close; | 1304 | goto close; |
| 1320 | } | 1305 | } |
| 1321 | 1306 | ||
| 1307 | /* Writing nvdev pointer unlocks netvsc_send(), make sure chn_table is | ||
| 1308 | * populated. | ||
| 1309 | */ | ||
| 1310 | rcu_assign_pointer(net_device_ctx->nvdev, net_device); | ||
| 1311 | |||
| 1322 | return net_device; | 1312 | return net_device; |
| 1323 | 1313 | ||
| 1324 | close: | 1314 | close: |
| @@ -1329,6 +1319,7 @@ close: | |||
| 1329 | vmbus_close(device->channel); | 1319 | vmbus_close(device->channel); |
| 1330 | 1320 | ||
| 1331 | cleanup: | 1321 | cleanup: |
| 1322 | netif_napi_del(&net_device->chan_table[0].napi); | ||
| 1332 | free_netvsc_device(&net_device->rcu); | 1323 | free_netvsc_device(&net_device->rcu); |
| 1333 | 1324 | ||
| 1334 | return ERR_PTR(ret); | 1325 | return ERR_PTR(ret); |
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) |
diff --git a/drivers/net/hyperv/rndis_filter.c b/drivers/net/hyperv/rndis_filter.c index c3ca191fea7f..8927c483c217 100644 --- a/drivers/net/hyperv/rndis_filter.c +++ b/drivers/net/hyperv/rndis_filter.c | |||
| @@ -854,15 +854,19 @@ static void rndis_set_multicast(struct work_struct *w) | |||
| 854 | { | 854 | { |
| 855 | struct rndis_device *rdev | 855 | struct rndis_device *rdev |
| 856 | = container_of(w, struct rndis_device, mcast_work); | 856 | = container_of(w, struct rndis_device, mcast_work); |
| 857 | u32 filter = NDIS_PACKET_TYPE_DIRECTED; | ||
| 858 | unsigned int flags = rdev->ndev->flags; | ||
| 857 | 859 | ||
| 858 | if (rdev->ndev->flags & IFF_PROMISC) | 860 | if (flags & IFF_PROMISC) { |
| 859 | rndis_filter_set_packet_filter(rdev, | 861 | filter = NDIS_PACKET_TYPE_PROMISCUOUS; |
| 860 | NDIS_PACKET_TYPE_PROMISCUOUS); | 862 | } else { |
| 861 | else | 863 | if (flags & IFF_ALLMULTI) |
| 862 | rndis_filter_set_packet_filter(rdev, | 864 | flags |= NDIS_PACKET_TYPE_ALL_MULTICAST; |
| 863 | NDIS_PACKET_TYPE_BROADCAST | | 865 | if (flags & IFF_BROADCAST) |
| 864 | NDIS_PACKET_TYPE_ALL_MULTICAST | | 866 | flags |= NDIS_PACKET_TYPE_BROADCAST; |
| 865 | NDIS_PACKET_TYPE_DIRECTED); | 867 | } |
| 868 | |||
| 869 | rndis_filter_set_packet_filter(rdev, filter); | ||
| 866 | } | 870 | } |
| 867 | 871 | ||
| 868 | void rndis_filter_update(struct netvsc_device *nvdev) | 872 | void rndis_filter_update(struct netvsc_device *nvdev) |
| @@ -1340,6 +1344,9 @@ void rndis_filter_device_remove(struct hv_device *dev, | |||
| 1340 | { | 1344 | { |
| 1341 | struct rndis_device *rndis_dev = net_dev->extension; | 1345 | struct rndis_device *rndis_dev = net_dev->extension; |
| 1342 | 1346 | ||
| 1347 | /* Don't try and setup sub channels if about to halt */ | ||
| 1348 | cancel_work_sync(&net_dev->subchan_work); | ||
| 1349 | |||
| 1343 | /* Halt and release the rndis device */ | 1350 | /* Halt and release the rndis device */ |
| 1344 | rndis_filter_halt_device(rndis_dev); | 1351 | rndis_filter_halt_device(rndis_dev); |
| 1345 | 1352 | ||
