Commit bcdaa2b8 authored by David S. Miller's avatar David S. Miller

Merge branch 'netvsc-bug-fixes'

Stephen Hemminger says:

====================
netvsc: bug fixes

These are bugfixes for netvsc driver in 4.12.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 8397ed36 4f19c0d8
...@@ -171,6 +171,8 @@ struct rndis_device { ...@@ -171,6 +171,8 @@ struct rndis_device {
spinlock_t request_lock; spinlock_t request_lock;
struct list_head req_list; struct list_head req_list;
struct work_struct mcast_work;
u8 hw_mac_adr[ETH_ALEN]; u8 hw_mac_adr[ETH_ALEN];
u8 rss_key[NETVSC_HASH_KEYLEN]; u8 rss_key[NETVSC_HASH_KEYLEN];
u16 ind_table[ITAB_NUM]; u16 ind_table[ITAB_NUM];
...@@ -201,6 +203,7 @@ int rndis_filter_open(struct netvsc_device *nvdev); ...@@ -201,6 +203,7 @@ int rndis_filter_open(struct netvsc_device *nvdev);
int rndis_filter_close(struct netvsc_device *nvdev); int rndis_filter_close(struct netvsc_device *nvdev);
int rndis_filter_device_add(struct hv_device *dev, int rndis_filter_device_add(struct hv_device *dev,
struct netvsc_device_info *info); struct netvsc_device_info *info);
void rndis_filter_update(struct netvsc_device *nvdev);
void rndis_filter_device_remove(struct hv_device *dev, void rndis_filter_device_remove(struct hv_device *dev,
struct netvsc_device *nvdev); struct netvsc_device *nvdev);
int rndis_filter_set_rss_param(struct rndis_device *rdev, int rndis_filter_set_rss_param(struct rndis_device *rdev,
...@@ -211,7 +214,6 @@ int rndis_filter_receive(struct net_device *ndev, ...@@ -211,7 +214,6 @@ int rndis_filter_receive(struct net_device *ndev,
struct vmbus_channel *channel, struct vmbus_channel *channel,
void *data, u32 buflen); void *data, u32 buflen);
int rndis_filter_set_packet_filter(struct rndis_device *dev, u32 new_filter);
int rndis_filter_set_device_mac(struct net_device *ndev, char *mac); int rndis_filter_set_device_mac(struct net_device *ndev, char *mac);
void netvsc_switch_datapath(struct net_device *nv_dev, bool vf); void netvsc_switch_datapath(struct net_device *nv_dev, bool vf);
...@@ -696,7 +698,6 @@ struct net_device_context { ...@@ -696,7 +698,6 @@ struct net_device_context {
/* list protection */ /* list protection */
spinlock_t lock; spinlock_t lock;
struct work_struct work;
u32 msg_enable; /* debug level */ u32 msg_enable; /* debug level */
u32 tx_checksum_mask; u32 tx_checksum_mask;
......
...@@ -56,37 +56,12 @@ static int debug = -1; ...@@ -56,37 +56,12 @@ static int debug = -1;
module_param(debug, int, S_IRUGO); module_param(debug, int, S_IRUGO);
MODULE_PARM_DESC(debug, "Debug level (0=none,...,16=all)"); MODULE_PARM_DESC(debug, "Debug level (0=none,...,16=all)");
static void do_set_multicast(struct work_struct *w)
{
struct net_device_context *ndevctx =
container_of(w, struct net_device_context, work);
struct hv_device *device_obj = ndevctx->device_ctx;
struct net_device *ndev = hv_get_drvdata(device_obj);
struct netvsc_device *nvdev = rcu_dereference(ndevctx->nvdev);
struct rndis_device *rdev;
if (!nvdev)
return;
rdev = nvdev->extension;
if (rdev == NULL)
return;
if (ndev->flags & IFF_PROMISC)
rndis_filter_set_packet_filter(rdev,
NDIS_PACKET_TYPE_PROMISCUOUS);
else
rndis_filter_set_packet_filter(rdev,
NDIS_PACKET_TYPE_BROADCAST |
NDIS_PACKET_TYPE_ALL_MULTICAST |
NDIS_PACKET_TYPE_DIRECTED);
}
static void netvsc_set_multicast_list(struct net_device *net) static void netvsc_set_multicast_list(struct net_device *net)
{ {
struct net_device_context *net_device_ctx = netdev_priv(net); struct net_device_context *net_device_ctx = netdev_priv(net);
struct netvsc_device *nvdev = rtnl_dereference(net_device_ctx->nvdev);
schedule_work(&net_device_ctx->work); rndis_filter_update(nvdev);
} }
static int netvsc_open(struct net_device *net) static int netvsc_open(struct net_device *net)
...@@ -123,8 +98,6 @@ static int netvsc_close(struct net_device *net) ...@@ -123,8 +98,6 @@ static int netvsc_close(struct net_device *net)
netif_tx_disable(net); netif_tx_disable(net);
/* Make sure netvsc_set_multicast_list doesn't re-enable filter! */
cancel_work_sync(&net_device_ctx->work);
ret = rndis_filter_close(nvdev); ret = rndis_filter_close(nvdev);
if (ret != 0) { if (ret != 0) {
netdev_err(net, "unable to close device (ret %d).\n", ret); netdev_err(net, "unable to close device (ret %d).\n", ret);
...@@ -1028,7 +1001,7 @@ static const struct { ...@@ -1028,7 +1001,7 @@ static const struct {
static int netvsc_get_sset_count(struct net_device *dev, int string_set) static int netvsc_get_sset_count(struct net_device *dev, int string_set)
{ {
struct net_device_context *ndc = netdev_priv(dev); struct net_device_context *ndc = netdev_priv(dev);
struct netvsc_device *nvdev = rcu_dereference(ndc->nvdev); struct netvsc_device *nvdev = rtnl_dereference(ndc->nvdev);
if (!nvdev) if (!nvdev)
return -ENODEV; return -ENODEV;
...@@ -1158,11 +1131,22 @@ netvsc_get_rxnfc(struct net_device *dev, struct ethtool_rxnfc *info, ...@@ -1158,11 +1131,22 @@ netvsc_get_rxnfc(struct net_device *dev, struct ethtool_rxnfc *info,
} }
#ifdef CONFIG_NET_POLL_CONTROLLER #ifdef CONFIG_NET_POLL_CONTROLLER
static void netvsc_poll_controller(struct net_device *net) static void netvsc_poll_controller(struct net_device *dev)
{ {
/* As netvsc_start_xmit() works synchronous we don't have to struct net_device_context *ndc = netdev_priv(dev);
* trigger anything here. struct netvsc_device *ndev;
*/ int i;
rcu_read_lock();
ndev = rcu_dereference(ndc->nvdev);
if (ndev) {
for (i = 0; i < ndev->num_chn; i++) {
struct netvsc_channel *nvchan = &ndev->chan_table[i];
napi_schedule(&nvchan->napi);
}
}
rcu_read_unlock();
} }
#endif #endif
...@@ -1552,7 +1536,6 @@ static int netvsc_probe(struct hv_device *dev, ...@@ -1552,7 +1536,6 @@ static int netvsc_probe(struct hv_device *dev,
hv_set_drvdata(dev, net); hv_set_drvdata(dev, net);
INIT_DELAYED_WORK(&net_device_ctx->dwork, netvsc_link_change); INIT_DELAYED_WORK(&net_device_ctx->dwork, netvsc_link_change);
INIT_WORK(&net_device_ctx->work, do_set_multicast);
spin_lock_init(&net_device_ctx->lock); spin_lock_init(&net_device_ctx->lock);
INIT_LIST_HEAD(&net_device_ctx->reconfig_events); INIT_LIST_HEAD(&net_device_ctx->reconfig_events);
...@@ -1622,7 +1605,6 @@ static int netvsc_remove(struct hv_device *dev) ...@@ -1622,7 +1605,6 @@ static int netvsc_remove(struct hv_device *dev)
netif_device_detach(net); netif_device_detach(net);
cancel_delayed_work_sync(&ndev_ctx->dwork); cancel_delayed_work_sync(&ndev_ctx->dwork);
cancel_work_sync(&ndev_ctx->work);
/* /*
* Call to the vsc driver to let it know that the device is being * Call to the vsc driver to let it know that the device is being
......
...@@ -31,6 +31,7 @@ ...@@ -31,6 +31,7 @@
#include "hyperv_net.h" #include "hyperv_net.h"
static void rndis_set_multicast(struct work_struct *w);
#define RNDIS_EXT_LEN PAGE_SIZE #define RNDIS_EXT_LEN PAGE_SIZE
struct rndis_request { struct rndis_request {
...@@ -76,6 +77,7 @@ static struct rndis_device *get_rndis_device(void) ...@@ -76,6 +77,7 @@ static struct rndis_device *get_rndis_device(void)
spin_lock_init(&device->request_lock); spin_lock_init(&device->request_lock);
INIT_LIST_HEAD(&device->req_list); INIT_LIST_HEAD(&device->req_list);
INIT_WORK(&device->mcast_work, rndis_set_multicast);
device->state = RNDIS_DEV_UNINITIALIZED; device->state = RNDIS_DEV_UNINITIALIZED;
...@@ -815,7 +817,8 @@ static int rndis_filter_query_link_speed(struct rndis_device *dev) ...@@ -815,7 +817,8 @@ static int rndis_filter_query_link_speed(struct rndis_device *dev)
return ret; return ret;
} }
int rndis_filter_set_packet_filter(struct rndis_device *dev, u32 new_filter) static int rndis_filter_set_packet_filter(struct rndis_device *dev,
u32 new_filter)
{ {
struct rndis_request *request; struct rndis_request *request;
struct rndis_set_request *set; struct rndis_set_request *set;
...@@ -846,6 +849,28 @@ int rndis_filter_set_packet_filter(struct rndis_device *dev, u32 new_filter) ...@@ -846,6 +849,28 @@ int rndis_filter_set_packet_filter(struct rndis_device *dev, u32 new_filter)
return ret; return ret;
} }
static void rndis_set_multicast(struct work_struct *w)
{
struct rndis_device *rdev
= container_of(w, struct rndis_device, mcast_work);
if (rdev->ndev->flags & IFF_PROMISC)
rndis_filter_set_packet_filter(rdev,
NDIS_PACKET_TYPE_PROMISCUOUS);
else
rndis_filter_set_packet_filter(rdev,
NDIS_PACKET_TYPE_BROADCAST |
NDIS_PACKET_TYPE_ALL_MULTICAST |
NDIS_PACKET_TYPE_DIRECTED);
}
void rndis_filter_update(struct netvsc_device *nvdev)
{
struct rndis_device *rdev = nvdev->extension;
schedule_work(&rdev->mcast_work);
}
static int rndis_filter_init_device(struct rndis_device *dev) static int rndis_filter_init_device(struct rndis_device *dev)
{ {
struct rndis_request *request; struct rndis_request *request;
...@@ -973,6 +998,9 @@ static int rndis_filter_close_device(struct rndis_device *dev) ...@@ -973,6 +998,9 @@ static int rndis_filter_close_device(struct rndis_device *dev)
if (dev->state != RNDIS_DEV_DATAINITIALIZED) if (dev->state != RNDIS_DEV_DATAINITIALIZED)
return 0; return 0;
/* Make sure rndis_set_multicast doesn't re-enable filter! */
cancel_work_sync(&dev->mcast_work);
ret = rndis_filter_set_packet_filter(dev, 0); ret = rndis_filter_set_packet_filter(dev, 0);
if (ret == -ENODEV) if (ret == -ENODEV)
ret = 0; ret = 0;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment