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

Commit 891de74d authored by Haiyang Zhang's avatar Haiyang Zhang Committed by David S. Miller
Browse files

hyperv: Fix the carrier status setting



Without this patch, the "cat /sys/class/net/ethN/operstate" shows
"unknown", and "ethtool ethN" shows "Link detected: yes", when VM
boots up with or without vNIC connected.

This patch fixed the problem.

Signed-off-by: default avatarHaiyang Zhang <haiyangz@microsoft.com>
Reviewed-by: default avatarK. Y. Srinivasan <kys@microsoft.com>
Acked-by: default avatarJason Wang <jasowang@redhat.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 09db3080
Loading
Loading
Loading
Loading
+38 −15
Original line number Original line Diff line number Diff line
@@ -88,8 +88,12 @@ static int netvsc_open(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 hv_device *device_obj = net_device_ctx->device_ctx;
	struct hv_device *device_obj = net_device_ctx->device_ctx;
	struct netvsc_device *nvdev;
	struct rndis_device *rdev;
	int ret = 0;
	int ret = 0;


	netif_carrier_off(net);

	/* Open up the device */
	/* Open up the device */
	ret = rndis_filter_open(device_obj);
	ret = rndis_filter_open(device_obj);
	if (ret != 0) {
	if (ret != 0) {
@@ -99,6 +103,11 @@ static int netvsc_open(struct net_device *net)


	netif_start_queue(net);
	netif_start_queue(net);


	nvdev = hv_get_drvdata(device_obj);
	rdev = nvdev->extension;
	if (!rdev->link_state)
		netif_carrier_on(net);

	return ret;
	return ret;
}
}


@@ -229,23 +238,24 @@ void netvsc_linkstatus_callback(struct hv_device *device_obj,
	struct net_device *net;
	struct net_device *net;
	struct net_device_context *ndev_ctx;
	struct net_device_context *ndev_ctx;
	struct netvsc_device *net_device;
	struct netvsc_device *net_device;
	struct rndis_device *rdev;


	net_device = hv_get_drvdata(device_obj);
	net_device = hv_get_drvdata(device_obj);
	rdev = net_device->extension;

	rdev->link_state = status != 1;

	net = net_device->ndev;
	net = net_device->ndev;


	if (!net) {
	if (!net || net->reg_state != NETREG_REGISTERED)
		netdev_err(net, "got link status but net device "
				"not initialized yet\n");
		return;
		return;
	}


	if (status == 1) {
		netif_carrier_on(net);
	ndev_ctx = netdev_priv(net);
	ndev_ctx = netdev_priv(net);
	if (status == 1) {
		schedule_delayed_work(&ndev_ctx->dwork, 0);
		schedule_delayed_work(&ndev_ctx->dwork, 0);
		schedule_delayed_work(&ndev_ctx->dwork, msecs_to_jiffies(20));
		schedule_delayed_work(&ndev_ctx->dwork, msecs_to_jiffies(20));
	} else {
	} else {
		netif_carrier_off(net);
		schedule_delayed_work(&ndev_ctx->dwork, 0);
	}
	}
}
}


@@ -388,16 +398,34 @@ static const struct net_device_ops device_ops = {
 * current context when receiving RNDIS_STATUS_MEDIA_CONNECT event. So, add
 * current context when receiving RNDIS_STATUS_MEDIA_CONNECT event. So, add
 * another netif_notify_peers() into a delayed work, otherwise GARP packet
 * another netif_notify_peers() into a delayed work, otherwise GARP packet
 * will not be sent after quick migration, and cause network disconnection.
 * will not be sent after quick migration, and cause network disconnection.
 * Also, we update the carrier status here.
 */
 */
static void netvsc_send_garp(struct work_struct *w)
static void netvsc_link_change(struct work_struct *w)
{
{
	struct net_device_context *ndev_ctx;
	struct net_device_context *ndev_ctx;
	struct net_device *net;
	struct net_device *net;
	struct netvsc_device *net_device;
	struct netvsc_device *net_device;
	struct rndis_device *rdev;
	bool notify;

	rtnl_lock();


	ndev_ctx = container_of(w, struct net_device_context, dwork.work);
	ndev_ctx = container_of(w, struct net_device_context, dwork.work);
	net_device = hv_get_drvdata(ndev_ctx->device_ctx);
	net_device = hv_get_drvdata(ndev_ctx->device_ctx);
	rdev = net_device->extension;
	net = net_device->ndev;
	net = net_device->ndev;

	if (rdev->link_state) {
		netif_carrier_off(net);
		notify = false;
	} else {
		netif_carrier_on(net);
		notify = true;
	}

	rtnl_unlock();

	if (notify)
		netdev_notify_peers(net);
		netdev_notify_peers(net);
}
}


@@ -414,13 +442,10 @@ static int netvsc_probe(struct hv_device *dev,
	if (!net)
	if (!net)
		return -ENOMEM;
		return -ENOMEM;


	/* Set initial state */
	netif_carrier_off(net);

	net_device_ctx = netdev_priv(net);
	net_device_ctx = netdev_priv(net);
	net_device_ctx->device_ctx = dev;
	net_device_ctx->device_ctx = dev;
	hv_set_drvdata(dev, net);
	hv_set_drvdata(dev, net);
	INIT_DELAYED_WORK(&net_device_ctx->dwork, netvsc_send_garp);
	INIT_DELAYED_WORK(&net_device_ctx->dwork, netvsc_link_change);
	INIT_WORK(&net_device_ctx->work, do_set_multicast);
	INIT_WORK(&net_device_ctx->work, do_set_multicast);


	net->netdev_ops = &device_ops;
	net->netdev_ops = &device_ops;
@@ -443,8 +468,6 @@ static int netvsc_probe(struct hv_device *dev,
	}
	}
	memcpy(net->dev_addr, device_info.mac_adr, ETH_ALEN);
	memcpy(net->dev_addr, device_info.mac_adr, ETH_ALEN);


	netif_carrier_on(net);

	ret = register_netdev(net);
	ret = register_netdev(net);
	if (ret != 0) {
	if (ret != 0) {
		pr_err("Unable to register netdev.\n");
		pr_err("Unable to register netdev.\n");