aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2017-06-08 11:45:49 -0400
committerDavid S. Miller <davem@davemloft.net>2017-06-08 11:45:49 -0400
commitbcdaa2b8a640d6e3d29d3257434fe741fcba4a9c (patch)
treee0c31bfe883920902c20fe662007cbe52d1e17ef
parent8397ed36b7c585f8d3e06c431f4137309124f78f (diff)
parent4f19c0d8070cd4aa8e85bbf8a19d9ef5bef77c90 (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.h5
-rw-r--r--drivers/net/hyperv/netvsc_drv.c54
-rw-r--r--drivers/net/hyperv/rndis_filter.c30
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);
201int rndis_filter_close(struct netvsc_device *nvdev); 203int rndis_filter_close(struct netvsc_device *nvdev);
202int rndis_filter_device_add(struct hv_device *dev, 204int rndis_filter_device_add(struct hv_device *dev,
203 struct netvsc_device_info *info); 205 struct netvsc_device_info *info);
206void rndis_filter_update(struct netvsc_device *nvdev);
204void rndis_filter_device_remove(struct hv_device *dev, 207void rndis_filter_device_remove(struct hv_device *dev,
205 struct netvsc_device *nvdev); 208 struct netvsc_device *nvdev);
206int rndis_filter_set_rss_param(struct rndis_device *rdev, 209int 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
214int rndis_filter_set_packet_filter(struct rndis_device *dev, u32 new_filter);
215int rndis_filter_set_device_mac(struct net_device *ndev, char *mac); 217int rndis_filter_set_device_mac(struct net_device *ndev, char *mac);
216 218
217void netvsc_switch_datapath(struct net_device *nv_dev, bool vf); 219void 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;
56module_param(debug, int, S_IRUGO); 56module_param(debug, int, S_IRUGO);
57MODULE_PARM_DESC(debug, "Debug level (0=none,...,16=all)"); 57MODULE_PARM_DESC(debug, "Debug level (0=none,...,16=all)");
58 58
59static 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
85static void netvsc_set_multicast_list(struct net_device *net) 59static 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
92static int netvsc_open(struct net_device *net) 67static 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 {
1028static int netvsc_get_sset_count(struct net_device *dev, int string_set) 1001static 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
1161static void netvsc_poll_controller(struct net_device *net) 1134static 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
34static void rndis_set_multicast(struct work_struct *w);
34 35
35#define RNDIS_EXT_LEN PAGE_SIZE 36#define RNDIS_EXT_LEN PAGE_SIZE
36struct rndis_request { 37struct 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
818int rndis_filter_set_packet_filter(struct rndis_device *dev, u32 new_filter) 820static 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
852static 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
867void rndis_filter_update(struct netvsc_device *nvdev)
868{
869 struct rndis_device *rdev = nvdev->extension;
870
871 schedule_work(&rdev->mcast_work);
872}
873
849static int rndis_filter_init_device(struct rndis_device *dev) 874static 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;