Commit 7c9f335a authored by Haiyang Zhang's avatar Haiyang Zhang Committed by Sasha Levin

hv_netvsc: Refactor assignments of struct netvsc_device_info

These assignments occur in multiple places. The patch refactor them
to a function for simplicity. It also puts the struct to heap area
for future expension.
Signed-off-by: default avatarHaiyang Zhang <haiyangz@microsoft.com>
Reviewed-by: default avatarMichael Kelley <mikelley@microsoft.com>
[sl: fix up subject line]
Signed-off-by: default avatarSasha Levin <sashal@kernel.org>
parent b4a10c75
...@@ -858,6 +858,36 @@ static void netvsc_get_channels(struct net_device *net, ...@@ -858,6 +858,36 @@ static void netvsc_get_channels(struct net_device *net,
} }
} }
/* Alloc struct netvsc_device_info, and initialize it from either existing
* struct netvsc_device, or from default values.
*/
static struct netvsc_device_info *netvsc_devinfo_get
(struct netvsc_device *nvdev)
{
struct netvsc_device_info *dev_info;
dev_info = kzalloc(sizeof(*dev_info), GFP_ATOMIC);
if (!dev_info)
return NULL;
if (nvdev) {
dev_info->num_chn = nvdev->num_chn;
dev_info->send_sections = nvdev->send_section_cnt;
dev_info->send_section_size = nvdev->send_section_size;
dev_info->recv_sections = nvdev->recv_section_cnt;
dev_info->recv_section_size = nvdev->recv_section_size;
} else {
dev_info->num_chn = VRSS_CHANNEL_DEFAULT;
dev_info->send_sections = NETVSC_DEFAULT_TX;
dev_info->send_section_size = NETVSC_SEND_SECTION_SIZE;
dev_info->recv_sections = NETVSC_DEFAULT_RX;
dev_info->recv_section_size = NETVSC_RECV_SECTION_SIZE;
}
return dev_info;
}
static int netvsc_detach(struct net_device *ndev, static int netvsc_detach(struct net_device *ndev,
struct netvsc_device *nvdev) struct netvsc_device *nvdev)
{ {
...@@ -943,7 +973,7 @@ static int netvsc_set_channels(struct net_device *net, ...@@ -943,7 +973,7 @@ static int netvsc_set_channels(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); struct netvsc_device *nvdev = rtnl_dereference(net_device_ctx->nvdev);
unsigned int orig, count = channels->combined_count; unsigned int orig, count = channels->combined_count;
struct netvsc_device_info device_info; struct netvsc_device_info *device_info;
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 */
...@@ -962,24 +992,26 @@ static int netvsc_set_channels(struct net_device *net, ...@@ -962,24 +992,26 @@ static int netvsc_set_channels(struct net_device *net,
orig = nvdev->num_chn; orig = nvdev->num_chn;
memset(&device_info, 0, sizeof(device_info)); device_info = netvsc_devinfo_get(nvdev);
device_info.num_chn = count;
device_info.send_sections = nvdev->send_section_cnt; if (!device_info)
device_info.send_section_size = nvdev->send_section_size; return -ENOMEM;
device_info.recv_sections = nvdev->recv_section_cnt;
device_info.recv_section_size = nvdev->recv_section_size; device_info->num_chn = count;
ret = netvsc_detach(net, nvdev); ret = netvsc_detach(net, nvdev);
if (ret) if (ret)
return ret; goto out;
ret = netvsc_attach(net, &device_info); ret = netvsc_attach(net, device_info);
if (ret) { if (ret) {
device_info.num_chn = orig; device_info->num_chn = orig;
if (netvsc_attach(net, &device_info)) if (netvsc_attach(net, device_info))
netdev_err(net, "restoring channel setting failed\n"); netdev_err(net, "restoring channel setting failed\n");
} }
out:
kfree(device_info);
return ret; return ret;
} }
...@@ -1048,48 +1080,45 @@ static int netvsc_change_mtu(struct net_device *ndev, int mtu) ...@@ -1048,48 +1080,45 @@ static int netvsc_change_mtu(struct net_device *ndev, int mtu)
struct net_device *vf_netdev = rtnl_dereference(ndevctx->vf_netdev); struct net_device *vf_netdev = rtnl_dereference(ndevctx->vf_netdev);
struct netvsc_device *nvdev = rtnl_dereference(ndevctx->nvdev); struct netvsc_device *nvdev = rtnl_dereference(ndevctx->nvdev);
int orig_mtu = ndev->mtu; int orig_mtu = ndev->mtu;
struct netvsc_device_info device_info; struct netvsc_device_info *device_info;
int ret = 0; int ret = 0;
if (!nvdev || nvdev->destroy) if (!nvdev || nvdev->destroy)
return -ENODEV; return -ENODEV;
device_info = netvsc_devinfo_get(nvdev);
if (!device_info)
return -ENOMEM;
/* Change MTU of underlying VF netdev first. */ /* Change MTU of underlying VF netdev first. */
if (vf_netdev) { if (vf_netdev) {
ret = dev_set_mtu(vf_netdev, mtu); ret = dev_set_mtu(vf_netdev, mtu);
if (ret) if (ret)
return ret; goto out;
} }
memset(&device_info, 0, sizeof(device_info));
device_info.num_chn = nvdev->num_chn;
device_info.send_sections = nvdev->send_section_cnt;
device_info.send_section_size = nvdev->send_section_size;
device_info.recv_sections = nvdev->recv_section_cnt;
device_info.recv_section_size = nvdev->recv_section_size;
ret = netvsc_detach(ndev, nvdev); ret = netvsc_detach(ndev, nvdev);
if (ret) if (ret)
goto rollback_vf; goto rollback_vf;
ndev->mtu = mtu; ndev->mtu = mtu;
ret = netvsc_attach(ndev, &device_info); ret = netvsc_attach(ndev, device_info);
if (ret) if (!ret)
goto rollback; goto out;
return 0;
rollback:
/* Attempt rollback to original MTU */ /* Attempt rollback to original MTU */
ndev->mtu = orig_mtu; ndev->mtu = orig_mtu;
if (netvsc_attach(ndev, &device_info)) if (netvsc_attach(ndev, device_info))
netdev_err(ndev, "restoring mtu failed\n"); netdev_err(ndev, "restoring mtu failed\n");
rollback_vf: rollback_vf:
if (vf_netdev) if (vf_netdev)
dev_set_mtu(vf_netdev, orig_mtu); dev_set_mtu(vf_netdev, orig_mtu);
out:
kfree(device_info);
return ret; return ret;
} }
...@@ -1674,7 +1703,7 @@ static int netvsc_set_ringparam(struct net_device *ndev, ...@@ -1674,7 +1703,7 @@ static int netvsc_set_ringparam(struct net_device *ndev,
{ {
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 netvsc_device_info device_info; struct netvsc_device_info *device_info;
struct ethtool_ringparam orig; struct ethtool_ringparam orig;
u32 new_tx, new_rx; u32 new_tx, new_rx;
int ret = 0; int ret = 0;
...@@ -1694,26 +1723,29 @@ static int netvsc_set_ringparam(struct net_device *ndev, ...@@ -1694,26 +1723,29 @@ static int netvsc_set_ringparam(struct net_device *ndev,
new_rx == orig.rx_pending) new_rx == orig.rx_pending)
return 0; /* no change */ return 0; /* no change */
memset(&device_info, 0, sizeof(device_info)); device_info = netvsc_devinfo_get(nvdev);
device_info.num_chn = nvdev->num_chn;
device_info.send_sections = new_tx; if (!device_info)
device_info.send_section_size = nvdev->send_section_size; return -ENOMEM;
device_info.recv_sections = new_rx;
device_info.recv_section_size = nvdev->recv_section_size; device_info->send_sections = new_tx;
device_info->recv_sections = new_rx;
ret = netvsc_detach(ndev, nvdev); ret = netvsc_detach(ndev, nvdev);
if (ret) if (ret)
return ret; goto out;
ret = netvsc_attach(ndev, &device_info); ret = netvsc_attach(ndev, device_info);
if (ret) { if (ret) {
device_info.send_sections = orig.tx_pending; device_info->send_sections = orig.tx_pending;
device_info.recv_sections = orig.rx_pending; device_info->recv_sections = orig.rx_pending;
if (netvsc_attach(ndev, &device_info)) if (netvsc_attach(ndev, device_info))
netdev_err(ndev, "restoring ringparam failed"); netdev_err(ndev, "restoring ringparam failed");
} }
out:
kfree(device_info);
return ret; return ret;
} }
...@@ -2167,7 +2199,7 @@ static int netvsc_probe(struct hv_device *dev, ...@@ -2167,7 +2199,7 @@ static int netvsc_probe(struct hv_device *dev,
{ {
struct net_device *net = NULL; struct net_device *net = NULL;
struct net_device_context *net_device_ctx; struct net_device_context *net_device_ctx;
struct netvsc_device_info device_info; struct netvsc_device_info *device_info = NULL;
struct netvsc_device *nvdev; struct netvsc_device *nvdev;
int ret = -ENOMEM; int ret = -ENOMEM;
...@@ -2214,21 +2246,21 @@ static int netvsc_probe(struct hv_device *dev, ...@@ -2214,21 +2246,21 @@ static int netvsc_probe(struct hv_device *dev,
netif_set_real_num_rx_queues(net, 1); netif_set_real_num_rx_queues(net, 1);
/* Notify the netvsc driver of the new device */ /* Notify the netvsc driver of the new device */
memset(&device_info, 0, sizeof(device_info)); device_info = netvsc_devinfo_get(NULL);
device_info.num_chn = VRSS_CHANNEL_DEFAULT;
device_info.send_sections = NETVSC_DEFAULT_TX; if (!device_info) {
device_info.send_section_size = NETVSC_SEND_SECTION_SIZE; ret = -ENOMEM;
device_info.recv_sections = NETVSC_DEFAULT_RX; goto devinfo_failed;
device_info.recv_section_size = NETVSC_RECV_SECTION_SIZE; }
nvdev = rndis_filter_device_add(dev, &device_info); nvdev = rndis_filter_device_add(dev, device_info);
if (IS_ERR(nvdev)) { if (IS_ERR(nvdev)) {
ret = PTR_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);
goto rndis_failed; goto rndis_failed;
} }
memcpy(net->dev_addr, device_info.mac_adr, ETH_ALEN); memcpy(net->dev_addr, device_info->mac_adr, ETH_ALEN);
/* We must get rtnl lock before scheduling nvdev->subchan_work, /* We must get rtnl lock before scheduling nvdev->subchan_work,
* otherwise netvsc_subchan_work() can get rtnl lock first and wait * otherwise netvsc_subchan_work() can get rtnl lock first and wait
...@@ -2266,12 +2298,16 @@ static int netvsc_probe(struct hv_device *dev, ...@@ -2266,12 +2298,16 @@ static int netvsc_probe(struct hv_device *dev,
list_add(&net_device_ctx->list, &netvsc_dev_list); list_add(&net_device_ctx->list, &netvsc_dev_list);
rtnl_unlock(); rtnl_unlock();
kfree(device_info);
return 0; return 0;
register_failed: register_failed:
rtnl_unlock(); rtnl_unlock();
rndis_filter_device_remove(dev, nvdev); rndis_filter_device_remove(dev, nvdev);
rndis_failed: rndis_failed:
kfree(device_info);
devinfo_failed:
free_percpu(net_device_ctx->vf_stats); free_percpu(net_device_ctx->vf_stats);
no_stats: no_stats:
hv_set_drvdata(dev, NULL); hv_set_drvdata(dev, NULL);
......
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