Commit 88f34810 authored by David S. Miller's avatar David S. Miller

Merge branch 'netvsc-lockdep-and-related-fixes'

Stephen Hemminger says:

====================
netvsc: lockdep and related fixes

These fix sparse and lockdep warnings from netvsc driver.
Targeting these at net-next since no actual related failures
have been observed in non-debug kernels.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 9492f426 3962981f
...@@ -183,10 +183,12 @@ struct rndis_device { ...@@ -183,10 +183,12 @@ struct rndis_device {
/* Interface */ /* Interface */
struct rndis_message; struct rndis_message;
struct netvsc_device; struct netvsc_device;
int netvsc_device_add(struct hv_device *device, struct net_device_context;
const struct netvsc_device_info *info);
struct netvsc_device *netvsc_device_add(struct hv_device *device,
const struct netvsc_device_info *info);
void netvsc_device_remove(struct hv_device *device); void netvsc_device_remove(struct hv_device *device);
int netvsc_send(struct hv_device *device, int netvsc_send(struct net_device_context *ndc,
struct hv_netvsc_packet *packet, struct hv_netvsc_packet *packet,
struct rndis_message *rndis_msg, struct rndis_message *rndis_msg,
struct hv_page_buffer **page_buffer, struct hv_page_buffer **page_buffer,
...@@ -200,10 +202,11 @@ int netvsc_recv_callback(struct net_device *net, ...@@ -200,10 +202,11 @@ int netvsc_recv_callback(struct net_device *net,
const struct ndis_pkt_8021q_info *vlan); const struct ndis_pkt_8021q_info *vlan);
void netvsc_channel_cb(void *context); void netvsc_channel_cb(void *context);
int netvsc_poll(struct napi_struct *napi, int budget); int netvsc_poll(struct napi_struct *napi, int budget);
bool rndis_filter_opened(const struct netvsc_device *nvdev);
int rndis_filter_open(struct netvsc_device *nvdev); 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, struct netvsc_device *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_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);
...@@ -724,6 +727,7 @@ struct net_device_context { ...@@ -724,6 +727,7 @@ struct net_device_context {
/* Per channel data */ /* Per channel data */
struct netvsc_channel { struct netvsc_channel {
struct vmbus_channel *channel; struct vmbus_channel *channel;
struct netvsc_device *net_device;
const struct vmpacket_descriptor *desc; const struct vmpacket_descriptor *desc;
struct napi_struct napi; struct napi_struct napi;
struct multi_send_data msd; struct multi_send_data msd;
...@@ -783,18 +787,6 @@ struct netvsc_device { ...@@ -783,18 +787,6 @@ struct netvsc_device {
struct rcu_head rcu; struct rcu_head rcu;
}; };
static inline struct netvsc_device *
net_device_to_netvsc_device(struct net_device *ndev)
{
return ((struct net_device_context *)netdev_priv(ndev))->nvdev;
}
static inline struct netvsc_device *
hv_device_to_netvsc_device(struct hv_device *device)
{
return net_device_to_netvsc_device(hv_get_drvdata(device));
}
/* NdisInitialize message */ /* NdisInitialize message */
struct rndis_initialize_request { struct rndis_initialize_request {
u32 req_id; u32 req_id;
......
...@@ -29,6 +29,8 @@ ...@@ -29,6 +29,8 @@
#include <linux/netdevice.h> #include <linux/netdevice.h>
#include <linux/if_ether.h> #include <linux/if_ether.h>
#include <linux/vmalloc.h> #include <linux/vmalloc.h>
#include <linux/rtnetlink.h>
#include <asm/sync_bitops.h> #include <asm/sync_bitops.h>
#include "hyperv_net.h" #include "hyperv_net.h"
...@@ -41,7 +43,7 @@ void netvsc_switch_datapath(struct net_device *ndev, bool vf) ...@@ -41,7 +43,7 @@ void netvsc_switch_datapath(struct net_device *ndev, bool vf)
{ {
struct net_device_context *net_device_ctx = netdev_priv(ndev); struct net_device_context *net_device_ctx = netdev_priv(ndev);
struct hv_device *dev = net_device_ctx->device_ctx; struct hv_device *dev = net_device_ctx->device_ctx;
struct netvsc_device *nv_dev = net_device_ctx->nvdev; struct netvsc_device *nv_dev = rtnl_dereference(net_device_ctx->nvdev);
struct nvsp_message *init_pkt = &nv_dev->channel_init_pkt; struct nvsp_message *init_pkt = &nv_dev->channel_init_pkt;
memset(init_pkt, 0, sizeof(struct nvsp_message)); memset(init_pkt, 0, sizeof(struct nvsp_message));
...@@ -103,7 +105,8 @@ static void netvsc_destroy_buf(struct hv_device *device) ...@@ -103,7 +105,8 @@ static void netvsc_destroy_buf(struct hv_device *device)
{ {
struct nvsp_message *revoke_packet; struct nvsp_message *revoke_packet;
struct net_device *ndev = hv_get_drvdata(device); struct net_device *ndev = hv_get_drvdata(device);
struct netvsc_device *net_device = net_device_to_netvsc_device(ndev); struct net_device_context *ndc = netdev_priv(ndev);
struct netvsc_device *net_device = rtnl_dereference(ndc->nvdev);
int ret; int ret;
/* /*
...@@ -549,7 +552,8 @@ void netvsc_device_remove(struct hv_device *device) ...@@ -549,7 +552,8 @@ void netvsc_device_remove(struct hv_device *device)
{ {
struct net_device *ndev = hv_get_drvdata(device); struct net_device *ndev = hv_get_drvdata(device);
struct net_device_context *net_device_ctx = netdev_priv(ndev); struct net_device_context *net_device_ctx = netdev_priv(ndev);
struct netvsc_device *net_device = net_device_ctx->nvdev; struct netvsc_device *net_device
= rtnl_dereference(net_device_ctx->nvdev);
int i; int i;
netvsc_disconnect_vsp(device); netvsc_disconnect_vsp(device);
...@@ -819,13 +823,16 @@ static inline void move_pkt_msd(struct hv_netvsc_packet **msd_send, ...@@ -819,13 +823,16 @@ static inline void move_pkt_msd(struct hv_netvsc_packet **msd_send,
msdp->count = 0; msdp->count = 0;
} }
int netvsc_send(struct hv_device *device, /* RCU already held by caller */
int netvsc_send(struct net_device_context *ndev_ctx,
struct hv_netvsc_packet *packet, struct hv_netvsc_packet *packet,
struct rndis_message *rndis_msg, struct rndis_message *rndis_msg,
struct hv_page_buffer **pb, struct hv_page_buffer **pb,
struct sk_buff *skb) struct sk_buff *skb)
{ {
struct netvsc_device *net_device = hv_device_to_netvsc_device(device); struct netvsc_device *net_device
= rcu_dereference_rtnl(ndev_ctx->nvdev);
struct hv_device *device = ndev_ctx->device_ctx;
int ret = 0; int ret = 0;
struct netvsc_channel *nvchan; struct netvsc_channel *nvchan;
u32 pktlen = packet->total_data_buflen, msd_len = 0; u32 pktlen = packet->total_data_buflen, msd_len = 0;
...@@ -837,7 +844,7 @@ int netvsc_send(struct hv_device *device, ...@@ -837,7 +844,7 @@ int netvsc_send(struct hv_device *device,
bool xmit_more = (skb != NULL) ? skb->xmit_more : false; bool xmit_more = (skb != NULL) ? skb->xmit_more : false;
/* If device is rescinded, return error and packet will get dropped. */ /* If device is rescinded, return error and packet will get dropped. */
if (unlikely(net_device->destroy)) if (unlikely(!net_device || net_device->destroy))
return -ENODEV; return -ENODEV;
/* We may race with netvsc_connect_vsp()/netvsc_init_buf() and get /* We may race with netvsc_connect_vsp()/netvsc_init_buf() and get
...@@ -1219,11 +1226,11 @@ int netvsc_poll(struct napi_struct *napi, int budget) ...@@ -1219,11 +1226,11 @@ int netvsc_poll(struct napi_struct *napi, int budget)
{ {
struct netvsc_channel *nvchan struct netvsc_channel *nvchan
= container_of(napi, struct netvsc_channel, napi); = container_of(napi, struct netvsc_channel, napi);
struct netvsc_device *net_device = nvchan->net_device;
struct vmbus_channel *channel = nvchan->channel; struct vmbus_channel *channel = nvchan->channel;
struct hv_device *device = netvsc_channel_to_device(channel); struct hv_device *device = netvsc_channel_to_device(channel);
u16 q_idx = channel->offermsg.offer.sub_channel_index; u16 q_idx = channel->offermsg.offer.sub_channel_index;
struct net_device *ndev = hv_get_drvdata(device); struct net_device *ndev = hv_get_drvdata(device);
struct netvsc_device *net_device = net_device_to_netvsc_device(ndev);
int work_done = 0; int work_done = 0;
/* If starting a new interval */ /* If starting a new interval */
...@@ -1271,8 +1278,8 @@ void netvsc_channel_cb(void *context) ...@@ -1271,8 +1278,8 @@ void netvsc_channel_cb(void *context)
* netvsc_device_add - Callback when the device belonging to this * netvsc_device_add - Callback when the device belonging to this
* driver is added * driver is added
*/ */
int netvsc_device_add(struct hv_device *device, struct netvsc_device *netvsc_device_add(struct hv_device *device,
const struct netvsc_device_info *device_info) const struct netvsc_device_info *device_info)
{ {
int i, ret = 0; int i, ret = 0;
int ring_size = device_info->ring_size; int ring_size = device_info->ring_size;
...@@ -1282,7 +1289,7 @@ int netvsc_device_add(struct hv_device *device, ...@@ -1282,7 +1289,7 @@ int netvsc_device_add(struct hv_device *device,
net_device = alloc_net_device(); net_device = alloc_net_device();
if (!net_device) if (!net_device)
return -ENOMEM; return ERR_PTR(-ENOMEM);
net_device->ring_size = ring_size; net_device->ring_size = ring_size;
...@@ -1302,6 +1309,7 @@ int netvsc_device_add(struct hv_device *device, ...@@ -1302,6 +1309,7 @@ int netvsc_device_add(struct hv_device *device,
struct netvsc_channel *nvchan = &net_device->chan_table[i]; struct netvsc_channel *nvchan = &net_device->chan_table[i];
nvchan->channel = device->channel; nvchan->channel = device->channel;
nvchan->net_device = net_device;
} }
/* Enable NAPI handler before init callbacks */ /* Enable NAPI handler before init callbacks */
...@@ -1338,7 +1346,7 @@ int netvsc_device_add(struct hv_device *device, ...@@ -1338,7 +1346,7 @@ int netvsc_device_add(struct hv_device *device,
goto close; goto close;
} }
return ret; return net_device;
close: close:
netif_napi_del(&net_device->chan_table[0].napi); netif_napi_del(&net_device->chan_table[0].napi);
...@@ -1349,6 +1357,5 @@ int netvsc_device_add(struct hv_device *device, ...@@ -1349,6 +1357,5 @@ int netvsc_device_add(struct hv_device *device,
cleanup: cleanup:
free_netvsc_device(&net_device->rcu); free_netvsc_device(&net_device->rcu);
return ret; return ERR_PTR(ret);
} }
...@@ -69,7 +69,7 @@ static void netvsc_set_multicast_list(struct net_device *net) ...@@ -69,7 +69,7 @@ static void netvsc_set_multicast_list(struct net_device *net)
static int netvsc_open(struct net_device *net) static int netvsc_open(struct net_device *net)
{ {
struct net_device_context *ndev_ctx = netdev_priv(net); struct net_device_context *ndev_ctx = netdev_priv(net);
struct netvsc_device *nvdev = ndev_ctx->nvdev; struct netvsc_device *nvdev = rtnl_dereference(ndev_ctx->nvdev);
struct rndis_device *rdev; struct rndis_device *rdev;
int ret = 0; int ret = 0;
...@@ -505,8 +505,8 @@ static int netvsc_start_xmit(struct sk_buff *skb, struct net_device *net) ...@@ -505,8 +505,8 @@ static int netvsc_start_xmit(struct sk_buff *skb, struct net_device *net)
/* timestamp packet in software */ /* timestamp packet in software */
skb_tx_timestamp(skb); skb_tx_timestamp(skb);
ret = netvsc_send(net_device_ctx->device_ctx, packet,
rndis_msg, &pb, skb); ret = netvsc_send(net_device_ctx, packet, rndis_msg, &pb, skb);
if (likely(ret == 0)) if (likely(ret == 0))
return NETDEV_TX_OK; return NETDEV_TX_OK;
...@@ -717,6 +717,7 @@ static int netvsc_set_queues(struct net_device *net, struct hv_device *dev, ...@@ -717,6 +717,7 @@ static int netvsc_set_queues(struct net_device *net, struct hv_device *dev,
u32 num_chn) u32 num_chn)
{ {
struct netvsc_device_info device_info; struct netvsc_device_info device_info;
struct netvsc_device *net_device;
int ret; int ret;
memset(&device_info, 0, sizeof(device_info)); memset(&device_info, 0, sizeof(device_info));
...@@ -724,17 +725,16 @@ static int netvsc_set_queues(struct net_device *net, struct hv_device *dev, ...@@ -724,17 +725,16 @@ static int netvsc_set_queues(struct net_device *net, struct hv_device *dev,
device_info.ring_size = ring_size; device_info.ring_size = ring_size;
device_info.max_num_vrss_chns = num_chn; device_info.max_num_vrss_chns = num_chn;
ret = rndis_filter_device_add(dev, &device_info);
if (ret)
return ret;
ret = netif_set_real_num_tx_queues(net, num_chn); ret = netif_set_real_num_tx_queues(net, num_chn);
if (ret) if (ret)
return ret; return ret;
ret = netif_set_real_num_rx_queues(net, num_chn); ret = netif_set_real_num_rx_queues(net, num_chn);
if (ret)
return ret;
return ret; net_device = rndis_filter_device_add(dev, &device_info);
return IS_ERR(net_device) ? PTR_ERR(net_device) : 0;
} }
static int netvsc_set_channels(struct net_device *net, static int netvsc_set_channels(struct net_device *net,
...@@ -744,7 +744,7 @@ static int netvsc_set_channels(struct net_device *net, ...@@ -744,7 +744,7 @@ static int netvsc_set_channels(struct net_device *net,
struct hv_device *dev = net_device_ctx->device_ctx; struct hv_device *dev = net_device_ctx->device_ctx;
struct netvsc_device *nvdev = rtnl_dereference(net_device_ctx->nvdev); struct netvsc_device *nvdev = rtnl_dereference(net_device_ctx->nvdev);
unsigned int count = channels->combined_count; unsigned int count = channels->combined_count;
bool was_running; bool was_opened;
int ret; int ret;
/* We do not support separate count for rx, tx, or other */ /* We do not support separate count for rx, tx, or other */
...@@ -764,12 +764,9 @@ static int netvsc_set_channels(struct net_device *net, ...@@ -764,12 +764,9 @@ static int netvsc_set_channels(struct net_device *net,
if (count > nvdev->max_chn) if (count > nvdev->max_chn)
return -EINVAL; return -EINVAL;
was_running = netif_running(net); was_opened = rndis_filter_opened(nvdev);
if (was_running) { if (was_opened)
ret = netvsc_close(net); rndis_filter_close(nvdev);
if (ret)
return ret;
}
rndis_filter_device_remove(dev, nvdev); rndis_filter_device_remove(dev, nvdev);
...@@ -779,10 +776,12 @@ static int netvsc_set_channels(struct net_device *net, ...@@ -779,10 +776,12 @@ static int netvsc_set_channels(struct net_device *net,
else else
netvsc_set_queues(net, dev, nvdev->num_chn); netvsc_set_queues(net, dev, nvdev->num_chn);
if (was_running) nvdev = rtnl_dereference(net_device_ctx->nvdev);
ret = netvsc_open(net); if (was_opened)
rndis_filter_open(nvdev);
/* We may have missed link change notifications */ /* We may have missed link change notifications */
net_device_ctx->last_reconfig = 0;
schedule_delayed_work(&net_device_ctx->dwork, 0); schedule_delayed_work(&net_device_ctx->dwork, 0);
return ret; return ret;
...@@ -848,19 +847,18 @@ static int netvsc_change_mtu(struct net_device *ndev, int mtu) ...@@ -848,19 +847,18 @@ static int netvsc_change_mtu(struct net_device *ndev, int mtu)
struct net_device_context *ndevctx = netdev_priv(ndev); struct net_device_context *ndevctx = netdev_priv(ndev);
struct netvsc_device *nvdev = rtnl_dereference(ndevctx->nvdev); struct netvsc_device *nvdev = rtnl_dereference(ndevctx->nvdev);
struct hv_device *hdev = ndevctx->device_ctx; struct hv_device *hdev = ndevctx->device_ctx;
int orig_mtu = ndev->mtu;
struct netvsc_device_info device_info; struct netvsc_device_info device_info;
bool was_running; bool was_opened;
int ret = 0; int ret = 0;
if (!nvdev || nvdev->destroy) if (!nvdev || nvdev->destroy)
return -ENODEV; return -ENODEV;
was_running = netif_running(ndev); netif_device_detach(ndev);
if (was_running) { was_opened = rndis_filter_opened(nvdev);
ret = netvsc_close(ndev); if (was_opened)
if (ret) rndis_filter_close(nvdev);
return ret;
}
memset(&device_info, 0, sizeof(device_info)); memset(&device_info, 0, sizeof(device_info));
device_info.ring_size = ring_size; device_info.ring_size = ring_size;
...@@ -869,18 +867,21 @@ static int netvsc_change_mtu(struct net_device *ndev, int mtu) ...@@ -869,18 +867,21 @@ static int netvsc_change_mtu(struct net_device *ndev, int mtu)
rndis_filter_device_remove(hdev, nvdev); rndis_filter_device_remove(hdev, nvdev);
/* 'nvdev' has been freed in rndis_filter_device_remove() ->
* netvsc_device_remove () -> free_netvsc_device().
* We mustn't access it before it's re-created in
* rndis_filter_device_add() -> netvsc_device_add().
*/
ndev->mtu = mtu; ndev->mtu = mtu;
rndis_filter_device_add(hdev, &device_info); nvdev = rndis_filter_device_add(hdev, &device_info);
if (IS_ERR(nvdev)) {
ret = PTR_ERR(nvdev);
/* Attempt rollback to original MTU */
ndev->mtu = orig_mtu;
rndis_filter_device_add(hdev, &device_info);
}
if (was_opened)
rndis_filter_open(nvdev);
if (was_running) netif_device_attach(ndev);
ret = netvsc_open(ndev);
/* We may have missed link change notifications */ /* We may have missed link change notifications */
schedule_delayed_work(&ndevctx->dwork, 0); schedule_delayed_work(&ndevctx->dwork, 0);
...@@ -1363,7 +1364,7 @@ static struct net_device *get_netvsc_byref(struct net_device *vf_netdev) ...@@ -1363,7 +1364,7 @@ static struct net_device *get_netvsc_byref(struct net_device *vf_netdev)
continue; /* not a netvsc device */ continue; /* not a netvsc device */
net_device_ctx = netdev_priv(dev); net_device_ctx = netdev_priv(dev);
if (net_device_ctx->nvdev == NULL) if (!rtnl_dereference(net_device_ctx->nvdev))
continue; /* device is removed */ continue; /* device is removed */
if (rtnl_dereference(net_device_ctx->vf_netdev) == vf_netdev) if (rtnl_dereference(net_device_ctx->vf_netdev) == vf_netdev)
...@@ -1528,8 +1529,10 @@ static int netvsc_probe(struct hv_device *dev, ...@@ -1528,8 +1529,10 @@ static int netvsc_probe(struct hv_device *dev,
memset(&device_info, 0, sizeof(device_info)); memset(&device_info, 0, sizeof(device_info));
device_info.ring_size = ring_size; device_info.ring_size = ring_size;
device_info.num_chn = VRSS_CHANNEL_DEFAULT; device_info.num_chn = VRSS_CHANNEL_DEFAULT;
ret = rndis_filter_device_add(dev, &device_info);
if (ret != 0) { nvdev = rndis_filter_device_add(dev, &device_info);
if (IS_ERR(nvdev)) {
ret = PTR_ERR(nvdev);
netdev_err(net, "unable to add netvsc device (ret %d)\n", ret); netdev_err(net, "unable to add netvsc device (ret %d)\n", ret);
free_netdev(net); free_netdev(net);
hv_set_drvdata(dev, NULL); hv_set_drvdata(dev, NULL);
...@@ -1543,10 +1546,11 @@ static int netvsc_probe(struct hv_device *dev, ...@@ -1543,10 +1546,11 @@ static int netvsc_probe(struct hv_device *dev,
NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_HW_VLAN_CTAG_RX; NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_HW_VLAN_CTAG_RX;
net->vlan_features = net->features; net->vlan_features = net->features;
/* RCU not necessary here, device not registered */
nvdev = net_device_ctx->nvdev;
netif_set_real_num_tx_queues(net, nvdev->num_chn); netif_set_real_num_tx_queues(net, nvdev->num_chn);
netif_set_real_num_rx_queues(net, nvdev->num_chn); netif_set_real_num_rx_queues(net, nvdev->num_chn);
rtnl_unlock();
netdev_lockdep_set_classes(net);
/* MTU range: 68 - 1500 or 65521 */ /* MTU range: 68 - 1500 or 65521 */
net->min_mtu = NETVSC_MTU_MIN; net->min_mtu = NETVSC_MTU_MIN;
...@@ -1588,7 +1592,8 @@ static int netvsc_remove(struct hv_device *dev) ...@@ -1588,7 +1592,8 @@ static int netvsc_remove(struct hv_device *dev)
* removed. Also blocks mtu and channel changes. * removed. Also blocks mtu and channel changes.
*/ */
rtnl_lock(); rtnl_lock();
rndis_filter_device_remove(dev, ndev_ctx->nvdev); rndis_filter_device_remove(dev,
rtnl_dereference(ndev_ctx->nvdev));
rtnl_unlock(); rtnl_unlock();
unregister_netdev(net); unregister_netdev(net);
......
...@@ -84,6 +84,14 @@ static struct rndis_device *get_rndis_device(void) ...@@ -84,6 +84,14 @@ static struct rndis_device *get_rndis_device(void)
return device; return device;
} }
static struct netvsc_device *
net_device_to_netvsc_device(struct net_device *ndev)
{
struct net_device_context *net_device_ctx = netdev_priv(ndev);
return rtnl_dereference(net_device_ctx->nvdev);
}
static struct rndis_request *get_rndis_request(struct rndis_device *dev, static struct rndis_request *get_rndis_request(struct rndis_device *dev,
u32 msg_type, u32 msg_type,
u32 msg_len) u32 msg_len)
...@@ -243,7 +251,7 @@ static int rndis_filter_send_request(struct rndis_device *dev, ...@@ -243,7 +251,7 @@ static int rndis_filter_send_request(struct rndis_device *dev,
pb[0].len; pb[0].len;
} }
ret = netvsc_send(net_device_ctx->device_ctx, packet, NULL, &pb, NULL); ret = netvsc_send(net_device_ctx, packet, NULL, &pb, NULL);
return ret; return ret;
} }
...@@ -472,7 +480,7 @@ static int rndis_filter_query_device(struct rndis_device *dev, u32 oid, ...@@ -472,7 +480,7 @@ static int rndis_filter_query_device(struct rndis_device *dev, u32 oid,
if (oid == OID_TCP_OFFLOAD_HARDWARE_CAPABILITIES) { if (oid == OID_TCP_OFFLOAD_HARDWARE_CAPABILITIES) {
struct net_device_context *ndevctx = netdev_priv(dev->ndev); struct net_device_context *ndevctx = netdev_priv(dev->ndev);
struct netvsc_device *nvdev = ndevctx->nvdev; struct netvsc_device *nvdev = rtnl_dereference(ndevctx->nvdev);
struct ndis_offload *hwcaps; struct ndis_offload *hwcaps;
u32 nvsp_version = nvdev->nvsp_version; u32 nvsp_version = nvdev->nvsp_version;
u8 ndis_rev; u8 ndis_rev;
...@@ -658,9 +666,9 @@ int rndis_filter_set_device_mac(struct net_device *ndev, char *mac) ...@@ -658,9 +666,9 @@ int rndis_filter_set_device_mac(struct net_device *ndev, char *mac)
static int static int
rndis_filter_set_offload_params(struct net_device *ndev, rndis_filter_set_offload_params(struct net_device *ndev,
struct netvsc_device *nvdev,
struct ndis_offload_params *req_offloads) struct ndis_offload_params *req_offloads)
{ {
struct netvsc_device *nvdev = net_device_to_netvsc_device(ndev);
struct rndis_device *rdev = nvdev->extension; struct rndis_device *rdev = nvdev->extension;
struct rndis_request *request; struct rndis_request *request;
struct rndis_set_request *set; struct rndis_set_request *set;
...@@ -944,7 +952,7 @@ static void rndis_filter_halt_device(struct rndis_device *dev) ...@@ -944,7 +952,7 @@ static void rndis_filter_halt_device(struct rndis_device *dev)
struct rndis_request *request; struct rndis_request *request;
struct rndis_halt_request *halt; struct rndis_halt_request *halt;
struct net_device_context *net_device_ctx = netdev_priv(dev->ndev); struct net_device_context *net_device_ctx = netdev_priv(dev->ndev);
struct netvsc_device *nvdev = net_device_ctx->nvdev; struct netvsc_device *nvdev = rtnl_dereference(net_device_ctx->nvdev);
/* Attempt to do a rndis device halt */ /* Attempt to do a rndis device halt */
request = get_rndis_request(dev, RNDIS_MSG_HALT, request = get_rndis_request(dev, RNDIS_MSG_HALT,
...@@ -1052,8 +1060,8 @@ static void netvsc_sc_open(struct vmbus_channel *new_sc) ...@@ -1052,8 +1060,8 @@ static void netvsc_sc_open(struct vmbus_channel *new_sc)
complete(&nvscdev->channel_init_wait); complete(&nvscdev->channel_init_wait);
} }
int rndis_filter_device_add(struct hv_device *dev, struct netvsc_device *rndis_filter_device_add(struct hv_device *dev,
struct netvsc_device_info *device_info) struct netvsc_device_info *device_info)
{ {
struct net_device *net = hv_get_drvdata(dev); struct net_device *net = hv_get_drvdata(dev);
struct net_device_context *net_device_ctx = netdev_priv(net); struct net_device_context *net_device_ctx = netdev_priv(net);
...@@ -1072,21 +1080,20 @@ int rndis_filter_device_add(struct hv_device *dev, ...@@ -1072,21 +1080,20 @@ int rndis_filter_device_add(struct hv_device *dev,
rndis_device = get_rndis_device(); rndis_device = get_rndis_device();
if (!rndis_device) if (!rndis_device)
return -ENODEV; return ERR_PTR(-ENODEV);
/* /*
* Let the inner driver handle this first to create the netvsc channel * Let the inner driver handle this first to create the netvsc channel
* NOTE! Once the channel is created, we may get a receive callback * NOTE! Once the channel is created, we may get a receive callback
* (RndisFilterOnReceive()) before this call is completed * (RndisFilterOnReceive()) before this call is completed
*/ */
ret = netvsc_device_add(dev, device_info); net_device = netvsc_device_add(dev, device_info);
if (ret != 0) { if (IS_ERR(net_device)) {
kfree(rndis_device); kfree(rndis_device);
return ret; return net_device;
} }
/* Initialize the rndis device */ /* Initialize the rndis device */
net_device = net_device_ctx->nvdev;
net_device->max_chn = 1; net_device->max_chn = 1;
net_device->num_chn = 1; net_device->num_chn = 1;
...@@ -1097,10 +1104,8 @@ int rndis_filter_device_add(struct hv_device *dev, ...@@ -1097,10 +1104,8 @@ int rndis_filter_device_add(struct hv_device *dev,
/* Send the rndis initialization message */ /* Send the rndis initialization message */
ret = rndis_filter_init_device(rndis_device); ret = rndis_filter_init_device(rndis_device);
if (ret != 0) { if (ret != 0)
rndis_filter_device_remove(dev, net_device); goto err_dev_remv;
return ret;
}
/* Get the MTU from the host */ /* Get the MTU from the host */
size = sizeof(u32); size = sizeof(u32);
...@@ -1112,19 +1117,15 @@ int rndis_filter_device_add(struct hv_device *dev, ...@@ -1112,19 +1117,15 @@ int rndis_filter_device_add(struct hv_device *dev,
/* Get the mac address */ /* Get the mac address */
ret = rndis_filter_query_device_mac(rndis_device); ret = rndis_filter_query_device_mac(rndis_device);
if (ret != 0) { if (ret != 0)
rndis_filter_device_remove(dev, net_device); goto err_dev_remv;
return ret;
}
memcpy(device_info->mac_adr, rndis_device->hw_mac_adr, ETH_ALEN); memcpy(device_info->mac_adr, rndis_device->hw_mac_adr, ETH_ALEN);
/* Find HW offload capabilities */ /* Find HW offload capabilities */
ret = rndis_query_hwcaps(rndis_device, &hwcaps); ret = rndis_query_hwcaps(rndis_device, &hwcaps);
if (ret != 0) { if (ret != 0)
rndis_filter_device_remove(dev, net_device); goto err_dev_remv;
return ret;
}
/* A value of zero means "no change"; now turn on what we want. */ /* A value of zero means "no change"; now turn on what we want. */
memset(&offloads, 0, sizeof(struct ndis_offload_params)); memset(&offloads, 0, sizeof(struct ndis_offload_params));
...@@ -1179,7 +1180,7 @@ int rndis_filter_device_add(struct hv_device *dev, ...@@ -1179,7 +1180,7 @@ int rndis_filter_device_add(struct hv_device *dev,
netif_set_gso_max_size(net, gso_max_size); netif_set_gso_max_size(net, gso_max_size);
ret = rndis_filter_set_offload_params(net, &offloads); ret = rndis_filter_set_offload_params(net, net_device, &offloads);
if (ret) if (ret)
goto err_dev_remv; goto err_dev_remv;
...@@ -1190,7 +1191,7 @@ int rndis_filter_device_add(struct hv_device *dev, ...@@ -1190,7 +1191,7 @@ int rndis_filter_device_add(struct hv_device *dev,
rndis_device->link_state ? "down" : "up"); rndis_device->link_state ? "down" : "up");
if (net_device->nvsp_version < NVSP_PROTOCOL_VERSION_5) if (net_device->nvsp_version < NVSP_PROTOCOL_VERSION_5)
return 0; return net_device;
rndis_filter_query_link_speed(rndis_device); rndis_filter_query_link_speed(rndis_device);
...@@ -1223,7 +1224,7 @@ int rndis_filter_device_add(struct hv_device *dev, ...@@ -1223,7 +1224,7 @@ int rndis_filter_device_add(struct hv_device *dev,
num_rss_qs = net_device->num_chn - 1; num_rss_qs = net_device->num_chn - 1;
if (num_rss_qs == 0) if (num_rss_qs == 0)
return 0; return net_device;
refcount_set(&net_device->sc_offered, num_rss_qs); refcount_set(&net_device->sc_offered, num_rss_qs);
vmbus_set_sc_create_callback(dev->channel, netvsc_sc_open); vmbus_set_sc_create_callback(dev->channel, netvsc_sc_open);
...@@ -1260,11 +1261,11 @@ int rndis_filter_device_add(struct hv_device *dev, ...@@ -1260,11 +1261,11 @@ int rndis_filter_device_add(struct hv_device *dev,
net_device->num_chn = 1; net_device->num_chn = 1;
} }
return 0; /* return 0 because primary channel can be used alone */ return net_device;
err_dev_remv: err_dev_remv:
rndis_filter_device_remove(dev, net_device); rndis_filter_device_remove(dev, net_device);
return ret; return ERR_PTR(ret);
} }
void rndis_filter_device_remove(struct hv_device *dev, void rndis_filter_device_remove(struct hv_device *dev,
...@@ -1302,3 +1303,8 @@ int rndis_filter_close(struct netvsc_device *nvdev) ...@@ -1302,3 +1303,8 @@ int rndis_filter_close(struct netvsc_device *nvdev)
return rndis_filter_close_device(nvdev->extension); return rndis_filter_close_device(nvdev->extension);
} }
bool rndis_filter_opened(const struct netvsc_device *nvdev)
{
return atomic_read(&nvdev->open_cnt) > 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