Commit 867047c4 authored by stephen hemminger's avatar stephen hemminger Committed by David S. Miller

netvsc: fix warnings reported by lockdep

This includes a bunch of fixups for issues reported by
lockdep.
   * ethtool routines can assume RTNL
   * send is done with RCU lock (and BH disable)
   * avoid refetching internal device struct (netvsc)
     instead pass it as a parameter.
Signed-off-by: default avatarStephen Hemminger <sthemmin@microsoft.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent d6aac1f2
...@@ -217,7 +217,8 @@ int rndis_filter_receive(struct net_device *ndev, ...@@ -217,7 +217,8 @@ 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_device_mac(struct net_device *ndev, char *mac); int rndis_filter_set_device_mac(struct netvsc_device *ndev,
const char *mac);
void netvsc_switch_datapath(struct net_device *nv_dev, bool vf); void netvsc_switch_datapath(struct net_device *nv_dev, bool vf);
......
...@@ -832,7 +832,7 @@ int netvsc_send(struct net_device_context *ndev_ctx, ...@@ -832,7 +832,7 @@ int netvsc_send(struct net_device_context *ndev_ctx,
struct sk_buff *skb) struct sk_buff *skb)
{ {
struct netvsc_device *net_device struct netvsc_device *net_device
= rcu_dereference_rtnl(ndev_ctx->nvdev); = rcu_dereference_bh(ndev_ctx->nvdev);
struct hv_device *device = ndev_ctx->device_ctx; struct hv_device *device = ndev_ctx->device_ctx;
int ret = 0; int ret = 0;
struct netvsc_channel *nvchan; struct netvsc_channel *nvchan;
......
...@@ -923,6 +923,8 @@ static void netvsc_get_stats64(struct net_device *net, ...@@ -923,6 +923,8 @@ static void netvsc_get_stats64(struct net_device *net,
static int netvsc_set_mac_addr(struct net_device *ndev, void *p) static int netvsc_set_mac_addr(struct net_device *ndev, void *p)
{ {
struct net_device_context *ndc = netdev_priv(ndev);
struct netvsc_device *nvdev = rtnl_dereference(ndc->nvdev);
struct sockaddr *addr = p; struct sockaddr *addr = p;
char save_adr[ETH_ALEN]; char save_adr[ETH_ALEN];
unsigned char save_aatype; unsigned char save_aatype;
...@@ -935,7 +937,10 @@ static int netvsc_set_mac_addr(struct net_device *ndev, void *p) ...@@ -935,7 +937,10 @@ static int netvsc_set_mac_addr(struct net_device *ndev, void *p)
if (err != 0) if (err != 0)
return err; return err;
err = rndis_filter_set_device_mac(ndev, addr->sa_data); if (!nvdev)
return -ENODEV;
err = rndis_filter_set_device_mac(nvdev, addr->sa_data);
if (err != 0) { if (err != 0) {
/* roll back to saved MAC */ /* roll back to saved MAC */
memcpy(ndev->dev_addr, save_adr, ETH_ALEN); memcpy(ndev->dev_addr, save_adr, ETH_ALEN);
...@@ -981,7 +986,7 @@ static void netvsc_get_ethtool_stats(struct net_device *dev, ...@@ -981,7 +986,7 @@ static void netvsc_get_ethtool_stats(struct net_device *dev,
struct ethtool_stats *stats, u64 *data) struct ethtool_stats *stats, u64 *data)
{ {
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);
const void *nds = &ndc->eth_stats; const void *nds = &ndc->eth_stats;
const struct netvsc_stats *qstats; const struct netvsc_stats *qstats;
unsigned int start; unsigned int start;
...@@ -1019,7 +1024,7 @@ static void netvsc_get_ethtool_stats(struct net_device *dev, ...@@ -1019,7 +1024,7 @@ static void netvsc_get_ethtool_stats(struct net_device *dev,
static void netvsc_get_strings(struct net_device *dev, u32 stringset, u8 *data) static void netvsc_get_strings(struct net_device *dev, u32 stringset, u8 *data)
{ {
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);
u8 *p = data; u8 *p = data;
int i; int i;
...@@ -1077,7 +1082,7 @@ netvsc_get_rxnfc(struct net_device *dev, struct ethtool_rxnfc *info, ...@@ -1077,7 +1082,7 @@ netvsc_get_rxnfc(struct net_device *dev, struct ethtool_rxnfc *info,
u32 *rules) u32 *rules)
{ {
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;
...@@ -1127,7 +1132,7 @@ static int netvsc_get_rxfh(struct net_device *dev, u32 *indir, u8 *key, ...@@ -1127,7 +1132,7 @@ static int netvsc_get_rxfh(struct net_device *dev, u32 *indir, u8 *key,
u8 *hfunc) u8 *hfunc)
{ {
struct net_device_context *ndc = netdev_priv(dev); struct net_device_context *ndc = netdev_priv(dev);
struct netvsc_device *ndev = rcu_dereference(ndc->nvdev); struct netvsc_device *ndev = rtnl_dereference(ndc->nvdev);
struct rndis_device *rndis_dev; struct rndis_device *rndis_dev;
int i; int i;
......
...@@ -85,14 +85,6 @@ static struct rndis_device *get_rndis_device(void) ...@@ -85,14 +85,6 @@ 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)
...@@ -252,7 +244,10 @@ static int rndis_filter_send_request(struct rndis_device *dev, ...@@ -252,7 +244,10 @@ static int rndis_filter_send_request(struct rndis_device *dev,
pb[0].len; pb[0].len;
} }
rcu_read_lock_bh();
ret = netvsc_send(net_device_ctx, packet, NULL, &pb, NULL); ret = netvsc_send(net_device_ctx, packet, NULL, &pb, NULL);
rcu_read_unlock_bh();
return ret; return ret;
} }
...@@ -452,8 +447,9 @@ int rndis_filter_receive(struct net_device *ndev, ...@@ -452,8 +447,9 @@ int rndis_filter_receive(struct net_device *ndev,
return 0; return 0;
} }
static int rndis_filter_query_device(struct rndis_device *dev, u32 oid, static int rndis_filter_query_device(struct rndis_device *dev,
void *result, u32 *result_size) struct netvsc_device *nvdev,
u32 oid, void *result, u32 *result_size)
{ {
struct rndis_request *request; struct rndis_request *request;
u32 inresult_size = *result_size; u32 inresult_size = *result_size;
...@@ -480,8 +476,6 @@ static int rndis_filter_query_device(struct rndis_device *dev, u32 oid, ...@@ -480,8 +476,6 @@ static int rndis_filter_query_device(struct rndis_device *dev, u32 oid,
query->dev_vc_handle = 0; query->dev_vc_handle = 0;
if (oid == OID_TCP_OFFLOAD_HARDWARE_CAPABILITIES) { if (oid == OID_TCP_OFFLOAD_HARDWARE_CAPABILITIES) {
struct net_device_context *ndevctx = netdev_priv(dev->ndev);
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;
...@@ -550,14 +544,15 @@ static int rndis_filter_query_device(struct rndis_device *dev, u32 oid, ...@@ -550,14 +544,15 @@ static int rndis_filter_query_device(struct rndis_device *dev, u32 oid,
/* Get the hardware offload capabilities */ /* Get the hardware offload capabilities */
static int static int
rndis_query_hwcaps(struct rndis_device *dev, struct ndis_offload *caps) rndis_query_hwcaps(struct rndis_device *dev, struct netvsc_device *net_device,
struct ndis_offload *caps)
{ {
u32 caps_len = sizeof(*caps); u32 caps_len = sizeof(*caps);
int ret; int ret;
memset(caps, 0, sizeof(*caps)); memset(caps, 0, sizeof(*caps));
ret = rndis_filter_query_device(dev, ret = rndis_filter_query_device(dev, net_device,
OID_TCP_OFFLOAD_HARDWARE_CAPABILITIES, OID_TCP_OFFLOAD_HARDWARE_CAPABILITIES,
caps, &caps_len); caps, &caps_len);
if (ret) if (ret)
...@@ -586,11 +581,12 @@ rndis_query_hwcaps(struct rndis_device *dev, struct ndis_offload *caps) ...@@ -586,11 +581,12 @@ rndis_query_hwcaps(struct rndis_device *dev, struct ndis_offload *caps)
return 0; return 0;
} }
static int rndis_filter_query_device_mac(struct rndis_device *dev) static int rndis_filter_query_device_mac(struct rndis_device *dev,
struct netvsc_device *net_device)
{ {
u32 size = ETH_ALEN; u32 size = ETH_ALEN;
return rndis_filter_query_device(dev, return rndis_filter_query_device(dev, net_device,
RNDIS_OID_802_3_PERMANENT_ADDRESS, RNDIS_OID_802_3_PERMANENT_ADDRESS,
dev->hw_mac_adr, &size); dev->hw_mac_adr, &size);
} }
...@@ -598,9 +594,9 @@ static int rndis_filter_query_device_mac(struct rndis_device *dev) ...@@ -598,9 +594,9 @@ static int rndis_filter_query_device_mac(struct rndis_device *dev)
#define NWADR_STR "NetworkAddress" #define NWADR_STR "NetworkAddress"
#define NWADR_STRLEN 14 #define NWADR_STRLEN 14
int rndis_filter_set_device_mac(struct net_device *ndev, char *mac) int rndis_filter_set_device_mac(struct netvsc_device *nvdev,
const char *mac)
{ {
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;
...@@ -654,11 +650,8 @@ int rndis_filter_set_device_mac(struct net_device *ndev, char *mac) ...@@ -654,11 +650,8 @@ int rndis_filter_set_device_mac(struct net_device *ndev, char *mac)
wait_for_completion(&request->wait_event); wait_for_completion(&request->wait_event);
set_complete = &request->response_msg.msg.set_complete; set_complete = &request->response_msg.msg.set_complete;
if (set_complete->status != RNDIS_STATUS_SUCCESS) { if (set_complete->status != RNDIS_STATUS_SUCCESS)
netdev_err(ndev, "Fail to set MAC on host side:0x%x\n", ret = -EIO;
set_complete->status);
ret = -EINVAL;
}
cleanup: cleanup:
put_rndis_request(rdev, request); put_rndis_request(rdev, request);
...@@ -791,27 +784,27 @@ int rndis_filter_set_rss_param(struct rndis_device *rdev, ...@@ -791,27 +784,27 @@ int rndis_filter_set_rss_param(struct rndis_device *rdev,
return ret; return ret;
} }
static int rndis_filter_query_device_link_status(struct rndis_device *dev) static int rndis_filter_query_device_link_status(struct rndis_device *dev,
struct netvsc_device *net_device)
{ {
u32 size = sizeof(u32); u32 size = sizeof(u32);
u32 link_status; u32 link_status;
int ret;
ret = rndis_filter_query_device(dev, return rndis_filter_query_device(dev, net_device,
RNDIS_OID_GEN_MEDIA_CONNECT_STATUS, RNDIS_OID_GEN_MEDIA_CONNECT_STATUS,
&link_status, &size); &link_status, &size);
return ret;
} }
static int rndis_filter_query_link_speed(struct rndis_device *dev) static int rndis_filter_query_link_speed(struct rndis_device *dev,
struct netvsc_device *net_device)
{ {
u32 size = sizeof(u32); u32 size = sizeof(u32);
u32 link_speed; u32 link_speed;
struct net_device_context *ndc; struct net_device_context *ndc;
int ret; int ret;
ret = rndis_filter_query_device(dev, RNDIS_OID_GEN_LINK_SPEED, ret = rndis_filter_query_device(dev, net_device,
RNDIS_OID_GEN_LINK_SPEED,
&link_speed, &size); &link_speed, &size);
if (!ret) { if (!ret) {
...@@ -880,14 +873,14 @@ void rndis_filter_update(struct netvsc_device *nvdev) ...@@ -880,14 +873,14 @@ void rndis_filter_update(struct netvsc_device *nvdev)
schedule_work(&rdev->mcast_work); 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 netvsc_device *nvdev)
{ {
struct rndis_request *request; struct rndis_request *request;
struct rndis_initialize_request *init; struct rndis_initialize_request *init;
struct rndis_initialize_complete *init_complete; struct rndis_initialize_complete *init_complete;
u32 status; u32 status;
int ret; int ret;
struct netvsc_device *nvdev = net_device_to_netvsc_device(dev->ndev);
request = get_rndis_request(dev, RNDIS_MSG_INIT, request = get_rndis_request(dev, RNDIS_MSG_INIT,
RNDIS_MESSAGE_SIZE(struct rndis_initialize_request)); RNDIS_MESSAGE_SIZE(struct rndis_initialize_request));
...@@ -1024,12 +1017,17 @@ static void netvsc_sc_open(struct vmbus_channel *new_sc) ...@@ -1024,12 +1017,17 @@ static void netvsc_sc_open(struct vmbus_channel *new_sc)
{ {
struct net_device *ndev = struct net_device *ndev =
hv_get_drvdata(new_sc->primary_channel->device_obj); hv_get_drvdata(new_sc->primary_channel->device_obj);
struct netvsc_device *nvscdev = net_device_to_netvsc_device(ndev); struct net_device_context *ndev_ctx = netdev_priv(ndev);
struct netvsc_device *nvscdev;
u16 chn_index = new_sc->offermsg.offer.sub_channel_index; u16 chn_index = new_sc->offermsg.offer.sub_channel_index;
struct netvsc_channel *nvchan; struct netvsc_channel *nvchan;
int ret; int ret;
if (chn_index >= nvscdev->num_chn) /* This is safe because this callback only happens when
* new device is being setup and waiting on the channel_init_wait.
*/
nvscdev = rcu_dereference_raw(ndev_ctx->nvdev);
if (!nvscdev || chn_index >= nvscdev->num_chn)
return; return;
nvchan = nvscdev->chan_table + chn_index; nvchan = nvscdev->chan_table + chn_index;
...@@ -1104,27 +1102,27 @@ struct netvsc_device *rndis_filter_device_add(struct hv_device *dev, ...@@ -1104,27 +1102,27 @@ struct netvsc_device *rndis_filter_device_add(struct hv_device *dev,
rndis_device->ndev = net; rndis_device->ndev = net;
/* Send the rndis initialization message */ /* Send the rndis initialization message */
ret = rndis_filter_init_device(rndis_device); ret = rndis_filter_init_device(rndis_device, net_device);
if (ret != 0) if (ret != 0)
goto err_dev_remv; goto err_dev_remv;
/* Get the MTU from the host */ /* Get the MTU from the host */
size = sizeof(u32); size = sizeof(u32);
ret = rndis_filter_query_device(rndis_device, ret = rndis_filter_query_device(rndis_device, net_device,
RNDIS_OID_GEN_MAXIMUM_FRAME_SIZE, RNDIS_OID_GEN_MAXIMUM_FRAME_SIZE,
&mtu, &size); &mtu, &size);
if (ret == 0 && size == sizeof(u32) && mtu < net->mtu) if (ret == 0 && size == sizeof(u32) && mtu < net->mtu)
net->mtu = mtu; net->mtu = mtu;
/* Get the mac address */ /* Get the mac address */
ret = rndis_filter_query_device_mac(rndis_device); ret = rndis_filter_query_device_mac(rndis_device, net_device);
if (ret != 0) if (ret != 0)
goto err_dev_remv; goto err_dev_remv;
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, net_device, &hwcaps);
if (ret != 0) if (ret != 0)
goto err_dev_remv; goto err_dev_remv;
...@@ -1185,7 +1183,7 @@ struct netvsc_device *rndis_filter_device_add(struct hv_device *dev, ...@@ -1185,7 +1183,7 @@ struct netvsc_device *rndis_filter_device_add(struct hv_device *dev,
if (ret) if (ret)
goto err_dev_remv; goto err_dev_remv;
rndis_filter_query_device_link_status(rndis_device); rndis_filter_query_device_link_status(rndis_device, net_device);
netdev_dbg(net, "Device MAC %pM link state %s\n", netdev_dbg(net, "Device MAC %pM link state %s\n",
rndis_device->hw_mac_adr, rndis_device->hw_mac_adr,
...@@ -1194,11 +1192,11 @@ struct netvsc_device *rndis_filter_device_add(struct hv_device *dev, ...@@ -1194,11 +1192,11 @@ struct netvsc_device *rndis_filter_device_add(struct hv_device *dev,
if (net_device->nvsp_version < NVSP_PROTOCOL_VERSION_5) if (net_device->nvsp_version < NVSP_PROTOCOL_VERSION_5)
return net_device; return net_device;
rndis_filter_query_link_speed(rndis_device); rndis_filter_query_link_speed(rndis_device, net_device);
/* vRSS setup */ /* vRSS setup */
memset(&rsscap, 0, rsscap_size); memset(&rsscap, 0, rsscap_size);
ret = rndis_filter_query_device(rndis_device, ret = rndis_filter_query_device(rndis_device, net_device,
OID_GEN_RECEIVE_SCALE_CAPABILITIES, OID_GEN_RECEIVE_SCALE_CAPABILITIES,
&rsscap, &rsscap_size); &rsscap, &rsscap_size);
if (ret || rsscap.num_recv_que < 2) if (ret || rsscap.num_recv_que < 2)
......
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