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: Haiyang Zhang <haiyangz@microsoft.com> Reviewed-by: Michael Kelley <mikelley@microsoft.com> [sl: fix up subject line] Signed-off-by: Sasha Levin <sashal@kernel.org>
This commit is contained in:
parent
b4a10c7504
commit
7c9f335a3f
|
@ -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,
|
||||||
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,
|
||||||
|
|
||||||
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)
|
||||||
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,
|
||||||
{
|
{
|
||||||
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,
|
||||||
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,
|
||||||
{
|
{
|
||||||
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,
|
||||||
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;
|
|
||||||
device_info.send_section_size = NETVSC_SEND_SECTION_SIZE;
|
|
||||||
device_info.recv_sections = NETVSC_DEFAULT_RX;
|
|
||||||
device_info.recv_section_size = NETVSC_RECV_SECTION_SIZE;
|
|
||||||
|
|
||||||
nvdev = rndis_filter_device_add(dev, &device_info);
|
if (!device_info) {
|
||||||
|
ret = -ENOMEM;
|
||||||
|
goto devinfo_failed;
|
||||||
|
}
|
||||||
|
|
||||||
|
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,
|
||||||
|
|
||||||
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);
|
||||||
|
|
Loading…
Reference in New Issue