Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit d2ce8e1b authored by Haiyang Zhang's avatar Haiyang Zhang Committed by Greg Kroah-Hartman
Browse files

hv_netvsc: Refactor assignments of struct netvsc_device_info



[ Upstream commit 7c9f335a3ff20557a92584199f3d35c7e992bbe5 ]

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 51b547f2
Loading
Loading
Loading
Loading
+85 −49
Original line number Original line Diff line number Diff line
@@ -856,6 +856,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)
{
{
@@ -941,7 +971,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 */
@@ -960,24 +990,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;
}
}


@@ -1044,48 +1076,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;
}
}


@@ -1690,7 +1719,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;
@@ -1710,26 +1739,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;
}
}


@@ -2158,7 +2190,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;


@@ -2205,21 +2237,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
@@ -2257,12 +2289,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);