diff options
author | David S. Miller <davem@davemloft.net> | 2017-06-08 11:45:49 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2017-06-08 11:45:49 -0400 |
commit | bcdaa2b8a640d6e3d29d3257434fe741fcba4a9c (patch) | |
tree | e0c31bfe883920902c20fe662007cbe52d1e17ef | |
parent | 8397ed36b7c585f8d3e06c431f4137309124f78f (diff) | |
parent | 4f19c0d8070cd4aa8e85bbf8a19d9ef5bef77c90 (diff) |
Merge branch 'netvsc-bug-fixes'
Stephen Hemminger says:
====================
netvsc: bug fixes
These are bugfixes for netvsc driver in 4.12.
====================
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | drivers/net/hyperv/hyperv_net.h | 5 | ||||
-rw-r--r-- | drivers/net/hyperv/netvsc_drv.c | 54 | ||||
-rw-r--r-- | drivers/net/hyperv/rndis_filter.c | 30 |
3 files changed, 50 insertions, 39 deletions
diff --git a/drivers/net/hyperv/hyperv_net.h b/drivers/net/hyperv/hyperv_net.h index 262b2ea576a3..6066f1bcaf2d 100644 --- a/drivers/net/hyperv/hyperv_net.h +++ b/drivers/net/hyperv/hyperv_net.h | |||
@@ -171,6 +171,8 @@ struct rndis_device { | |||
171 | spinlock_t request_lock; | 171 | spinlock_t request_lock; |
172 | struct list_head req_list; | 172 | struct list_head req_list; |
173 | 173 | ||
174 | struct work_struct mcast_work; | ||
175 | |||
174 | u8 hw_mac_adr[ETH_ALEN]; | 176 | u8 hw_mac_adr[ETH_ALEN]; |
175 | u8 rss_key[NETVSC_HASH_KEYLEN]; | 177 | u8 rss_key[NETVSC_HASH_KEYLEN]; |
176 | u16 ind_table[ITAB_NUM]; | 178 | u16 ind_table[ITAB_NUM]; |
@@ -201,6 +203,7 @@ int rndis_filter_open(struct netvsc_device *nvdev); | |||
201 | int rndis_filter_close(struct netvsc_device *nvdev); | 203 | int rndis_filter_close(struct netvsc_device *nvdev); |
202 | int rndis_filter_device_add(struct hv_device *dev, | 204 | int rndis_filter_device_add(struct hv_device *dev, |
203 | struct netvsc_device_info *info); | 205 | struct netvsc_device_info *info); |
206 | void rndis_filter_update(struct netvsc_device *nvdev); | ||
204 | void rndis_filter_device_remove(struct hv_device *dev, | 207 | void rndis_filter_device_remove(struct hv_device *dev, |
205 | struct netvsc_device *nvdev); | 208 | struct netvsc_device *nvdev); |
206 | int rndis_filter_set_rss_param(struct rndis_device *rdev, | 209 | int rndis_filter_set_rss_param(struct rndis_device *rdev, |
@@ -211,7 +214,6 @@ int rndis_filter_receive(struct net_device *ndev, | |||
211 | struct vmbus_channel *channel, | 214 | struct vmbus_channel *channel, |
212 | void *data, u32 buflen); | 215 | void *data, u32 buflen); |
213 | 216 | ||
214 | int rndis_filter_set_packet_filter(struct rndis_device *dev, u32 new_filter); | ||
215 | int rndis_filter_set_device_mac(struct net_device *ndev, char *mac); | 217 | int rndis_filter_set_device_mac(struct net_device *ndev, char *mac); |
216 | 218 | ||
217 | void netvsc_switch_datapath(struct net_device *nv_dev, bool vf); | 219 | void netvsc_switch_datapath(struct net_device *nv_dev, bool vf); |
@@ -696,7 +698,6 @@ struct net_device_context { | |||
696 | /* list protection */ | 698 | /* list protection */ |
697 | spinlock_t lock; | 699 | spinlock_t lock; |
698 | 700 | ||
699 | struct work_struct work; | ||
700 | u32 msg_enable; /* debug level */ | 701 | u32 msg_enable; /* debug level */ |
701 | 702 | ||
702 | u32 tx_checksum_mask; | 703 | u32 tx_checksum_mask; |
diff --git a/drivers/net/hyperv/netvsc_drv.c b/drivers/net/hyperv/netvsc_drv.c index 4421a6d00375..82d6c022ca85 100644 --- a/drivers/net/hyperv/netvsc_drv.c +++ b/drivers/net/hyperv/netvsc_drv.c | |||
@@ -56,37 +56,12 @@ static int debug = -1; | |||
56 | module_param(debug, int, S_IRUGO); | 56 | module_param(debug, int, S_IRUGO); |
57 | MODULE_PARM_DESC(debug, "Debug level (0=none,...,16=all)"); | 57 | MODULE_PARM_DESC(debug, "Debug level (0=none,...,16=all)"); |
58 | 58 | ||
59 | static void do_set_multicast(struct work_struct *w) | ||
60 | { | ||
61 | struct net_device_context *ndevctx = | ||
62 | container_of(w, struct net_device_context, work); | ||
63 | struct hv_device *device_obj = ndevctx->device_ctx; | ||
64 | struct net_device *ndev = hv_get_drvdata(device_obj); | ||
65 | struct netvsc_device *nvdev = rcu_dereference(ndevctx->nvdev); | ||
66 | struct rndis_device *rdev; | ||
67 | |||
68 | if (!nvdev) | ||
69 | return; | ||
70 | |||
71 | rdev = nvdev->extension; | ||
72 | if (rdev == NULL) | ||
73 | return; | ||
74 | |||
75 | if (ndev->flags & IFF_PROMISC) | ||
76 | rndis_filter_set_packet_filter(rdev, | ||
77 | NDIS_PACKET_TYPE_PROMISCUOUS); | ||
78 | else | ||
79 | rndis_filter_set_packet_filter(rdev, | ||
80 | NDIS_PACKET_TYPE_BROADCAST | | ||
81 | NDIS_PACKET_TYPE_ALL_MULTICAST | | ||
82 | NDIS_PACKET_TYPE_DIRECTED); | ||
83 | } | ||
84 | |||
85 | static void netvsc_set_multicast_list(struct net_device *net) | 59 | static void netvsc_set_multicast_list(struct net_device *net) |
86 | { | 60 | { |
87 | struct net_device_context *net_device_ctx = netdev_priv(net); | 61 | struct net_device_context *net_device_ctx = netdev_priv(net); |
62 | struct netvsc_device *nvdev = rtnl_dereference(net_device_ctx->nvdev); | ||
88 | 63 | ||
89 | schedule_work(&net_device_ctx->work); | 64 | rndis_filter_update(nvdev); |
90 | } | 65 | } |
91 | 66 | ||
92 | static int netvsc_open(struct net_device *net) | 67 | static int netvsc_open(struct net_device *net) |
@@ -123,8 +98,6 @@ static int netvsc_close(struct net_device *net) | |||
123 | 98 | ||
124 | netif_tx_disable(net); | 99 | netif_tx_disable(net); |
125 | 100 | ||
126 | /* Make sure netvsc_set_multicast_list doesn't re-enable filter! */ | ||
127 | cancel_work_sync(&net_device_ctx->work); | ||
128 | ret = rndis_filter_close(nvdev); | 101 | ret = rndis_filter_close(nvdev); |
129 | if (ret != 0) { | 102 | if (ret != 0) { |
130 | netdev_err(net, "unable to close device (ret %d).\n", ret); | 103 | netdev_err(net, "unable to close device (ret %d).\n", ret); |
@@ -1028,7 +1001,7 @@ static const struct { | |||
1028 | static int netvsc_get_sset_count(struct net_device *dev, int string_set) | 1001 | static int netvsc_get_sset_count(struct net_device *dev, int string_set) |
1029 | { | 1002 | { |
1030 | struct net_device_context *ndc = netdev_priv(dev); | 1003 | struct net_device_context *ndc = netdev_priv(dev); |
1031 | struct netvsc_device *nvdev = rcu_dereference(ndc->nvdev); | 1004 | struct netvsc_device *nvdev = rtnl_dereference(ndc->nvdev); |
1032 | 1005 | ||
1033 | if (!nvdev) | 1006 | if (!nvdev) |
1034 | return -ENODEV; | 1007 | return -ENODEV; |
@@ -1158,11 +1131,22 @@ netvsc_get_rxnfc(struct net_device *dev, struct ethtool_rxnfc *info, | |||
1158 | } | 1131 | } |
1159 | 1132 | ||
1160 | #ifdef CONFIG_NET_POLL_CONTROLLER | 1133 | #ifdef CONFIG_NET_POLL_CONTROLLER |
1161 | static void netvsc_poll_controller(struct net_device *net) | 1134 | static void netvsc_poll_controller(struct net_device *dev) |
1162 | { | 1135 | { |
1163 | /* As netvsc_start_xmit() works synchronous we don't have to | 1136 | struct net_device_context *ndc = netdev_priv(dev); |
1164 | * trigger anything here. | 1137 | struct netvsc_device *ndev; |
1165 | */ | 1138 | int i; |
1139 | |||
1140 | rcu_read_lock(); | ||
1141 | ndev = rcu_dereference(ndc->nvdev); | ||
1142 | if (ndev) { | ||
1143 | for (i = 0; i < ndev->num_chn; i++) { | ||
1144 | struct netvsc_channel *nvchan = &ndev->chan_table[i]; | ||
1145 | |||
1146 | napi_schedule(&nvchan->napi); | ||
1147 | } | ||
1148 | } | ||
1149 | rcu_read_unlock(); | ||
1166 | } | 1150 | } |
1167 | #endif | 1151 | #endif |
1168 | 1152 | ||
@@ -1552,7 +1536,6 @@ static int netvsc_probe(struct hv_device *dev, | |||
1552 | hv_set_drvdata(dev, net); | 1536 | hv_set_drvdata(dev, net); |
1553 | 1537 | ||
1554 | INIT_DELAYED_WORK(&net_device_ctx->dwork, netvsc_link_change); | 1538 | INIT_DELAYED_WORK(&net_device_ctx->dwork, netvsc_link_change); |
1555 | INIT_WORK(&net_device_ctx->work, do_set_multicast); | ||
1556 | 1539 | ||
1557 | spin_lock_init(&net_device_ctx->lock); | 1540 | spin_lock_init(&net_device_ctx->lock); |
1558 | INIT_LIST_HEAD(&net_device_ctx->reconfig_events); | 1541 | INIT_LIST_HEAD(&net_device_ctx->reconfig_events); |
@@ -1622,7 +1605,6 @@ static int netvsc_remove(struct hv_device *dev) | |||
1622 | netif_device_detach(net); | 1605 | netif_device_detach(net); |
1623 | 1606 | ||
1624 | cancel_delayed_work_sync(&ndev_ctx->dwork); | 1607 | cancel_delayed_work_sync(&ndev_ctx->dwork); |
1625 | cancel_work_sync(&ndev_ctx->work); | ||
1626 | 1608 | ||
1627 | /* | 1609 | /* |
1628 | * Call to the vsc driver to let it know that the device is being | 1610 | * Call to the vsc driver to let it know that the device is being |
diff --git a/drivers/net/hyperv/rndis_filter.c b/drivers/net/hyperv/rndis_filter.c index f9d5b0b8209a..cb79cd081f42 100644 --- a/drivers/net/hyperv/rndis_filter.c +++ b/drivers/net/hyperv/rndis_filter.c | |||
@@ -31,6 +31,7 @@ | |||
31 | 31 | ||
32 | #include "hyperv_net.h" | 32 | #include "hyperv_net.h" |
33 | 33 | ||
34 | static void rndis_set_multicast(struct work_struct *w); | ||
34 | 35 | ||
35 | #define RNDIS_EXT_LEN PAGE_SIZE | 36 | #define RNDIS_EXT_LEN PAGE_SIZE |
36 | struct rndis_request { | 37 | struct rndis_request { |
@@ -76,6 +77,7 @@ static struct rndis_device *get_rndis_device(void) | |||
76 | spin_lock_init(&device->request_lock); | 77 | spin_lock_init(&device->request_lock); |
77 | 78 | ||
78 | INIT_LIST_HEAD(&device->req_list); | 79 | INIT_LIST_HEAD(&device->req_list); |
80 | INIT_WORK(&device->mcast_work, rndis_set_multicast); | ||
79 | 81 | ||
80 | device->state = RNDIS_DEV_UNINITIALIZED; | 82 | device->state = RNDIS_DEV_UNINITIALIZED; |
81 | 83 | ||
@@ -815,7 +817,8 @@ static int rndis_filter_query_link_speed(struct rndis_device *dev) | |||
815 | return ret; | 817 | return ret; |
816 | } | 818 | } |
817 | 819 | ||
818 | int rndis_filter_set_packet_filter(struct rndis_device *dev, u32 new_filter) | 820 | static int rndis_filter_set_packet_filter(struct rndis_device *dev, |
821 | u32 new_filter) | ||
819 | { | 822 | { |
820 | struct rndis_request *request; | 823 | struct rndis_request *request; |
821 | struct rndis_set_request *set; | 824 | struct rndis_set_request *set; |
@@ -846,6 +849,28 @@ int rndis_filter_set_packet_filter(struct rndis_device *dev, u32 new_filter) | |||
846 | return ret; | 849 | return ret; |
847 | } | 850 | } |
848 | 851 | ||
852 | static void rndis_set_multicast(struct work_struct *w) | ||
853 | { | ||
854 | struct rndis_device *rdev | ||
855 | = container_of(w, struct rndis_device, mcast_work); | ||
856 | |||
857 | if (rdev->ndev->flags & IFF_PROMISC) | ||
858 | rndis_filter_set_packet_filter(rdev, | ||
859 | NDIS_PACKET_TYPE_PROMISCUOUS); | ||
860 | else | ||
861 | rndis_filter_set_packet_filter(rdev, | ||
862 | NDIS_PACKET_TYPE_BROADCAST | | ||
863 | NDIS_PACKET_TYPE_ALL_MULTICAST | | ||
864 | NDIS_PACKET_TYPE_DIRECTED); | ||
865 | } | ||
866 | |||
867 | void rndis_filter_update(struct netvsc_device *nvdev) | ||
868 | { | ||
869 | struct rndis_device *rdev = nvdev->extension; | ||
870 | |||
871 | schedule_work(&rdev->mcast_work); | ||
872 | } | ||
873 | |||
849 | static int rndis_filter_init_device(struct rndis_device *dev) | 874 | static int rndis_filter_init_device(struct rndis_device *dev) |
850 | { | 875 | { |
851 | struct rndis_request *request; | 876 | struct rndis_request *request; |
@@ -973,6 +998,9 @@ static int rndis_filter_close_device(struct rndis_device *dev) | |||
973 | if (dev->state != RNDIS_DEV_DATAINITIALIZED) | 998 | if (dev->state != RNDIS_DEV_DATAINITIALIZED) |
974 | return 0; | 999 | return 0; |
975 | 1000 | ||
1001 | /* Make sure rndis_set_multicast doesn't re-enable filter! */ | ||
1002 | cancel_work_sync(&dev->mcast_work); | ||
1003 | |||
976 | ret = rndis_filter_set_packet_filter(dev, 0); | 1004 | ret = rndis_filter_set_packet_filter(dev, 0); |
977 | if (ret == -ENODEV) | 1005 | if (ret == -ENODEV) |
978 | ret = 0; | 1006 | ret = 0; |