diff options
Diffstat (limited to 'drivers/net/hyperv/netvsc_drv.c')
-rw-r--r-- | drivers/net/hyperv/netvsc_drv.c | 53 |
1 files changed, 38 insertions, 15 deletions
diff --git a/drivers/net/hyperv/netvsc_drv.c b/drivers/net/hyperv/netvsc_drv.c index 7756118c2f0a..7141a1937360 100644 --- a/drivers/net/hyperv/netvsc_drv.c +++ b/drivers/net/hyperv/netvsc_drv.c | |||
@@ -88,8 +88,12 @@ static int netvsc_open(struct net_device *net) | |||
88 | { | 88 | { |
89 | struct net_device_context *net_device_ctx = netdev_priv(net); | 89 | struct net_device_context *net_device_ctx = netdev_priv(net); |
90 | struct hv_device *device_obj = net_device_ctx->device_ctx; | 90 | struct hv_device *device_obj = net_device_ctx->device_ctx; |
91 | struct netvsc_device *nvdev; | ||
92 | struct rndis_device *rdev; | ||
91 | int ret = 0; | 93 | int ret = 0; |
92 | 94 | ||
95 | netif_carrier_off(net); | ||
96 | |||
93 | /* Open up the device */ | 97 | /* Open up the device */ |
94 | ret = rndis_filter_open(device_obj); | 98 | ret = rndis_filter_open(device_obj); |
95 | if (ret != 0) { | 99 | if (ret != 0) { |
@@ -99,6 +103,11 @@ static int netvsc_open(struct net_device *net) | |||
99 | 103 | ||
100 | netif_start_queue(net); | 104 | netif_start_queue(net); |
101 | 105 | ||
106 | nvdev = hv_get_drvdata(device_obj); | ||
107 | rdev = nvdev->extension; | ||
108 | if (!rdev->link_state) | ||
109 | netif_carrier_on(net); | ||
110 | |||
102 | return ret; | 111 | return ret; |
103 | } | 112 | } |
104 | 113 | ||
@@ -229,23 +238,24 @@ void netvsc_linkstatus_callback(struct hv_device *device_obj, | |||
229 | struct net_device *net; | 238 | struct net_device *net; |
230 | struct net_device_context *ndev_ctx; | 239 | struct net_device_context *ndev_ctx; |
231 | struct netvsc_device *net_device; | 240 | struct netvsc_device *net_device; |
241 | struct rndis_device *rdev; | ||
232 | 242 | ||
233 | net_device = hv_get_drvdata(device_obj); | 243 | net_device = hv_get_drvdata(device_obj); |
244 | rdev = net_device->extension; | ||
245 | |||
246 | rdev->link_state = status != 1; | ||
247 | |||
234 | net = net_device->ndev; | 248 | net = net_device->ndev; |
235 | 249 | ||
236 | if (!net) { | 250 | if (!net || net->reg_state != NETREG_REGISTERED) |
237 | netdev_err(net, "got link status but net device " | ||
238 | "not initialized yet\n"); | ||
239 | return; | 251 | return; |
240 | } | ||
241 | 252 | ||
253 | ndev_ctx = netdev_priv(net); | ||
242 | if (status == 1) { | 254 | if (status == 1) { |
243 | netif_carrier_on(net); | ||
244 | ndev_ctx = netdev_priv(net); | ||
245 | schedule_delayed_work(&ndev_ctx->dwork, 0); | 255 | schedule_delayed_work(&ndev_ctx->dwork, 0); |
246 | schedule_delayed_work(&ndev_ctx->dwork, msecs_to_jiffies(20)); | 256 | schedule_delayed_work(&ndev_ctx->dwork, msecs_to_jiffies(20)); |
247 | } else { | 257 | } else { |
248 | netif_carrier_off(net); | 258 | schedule_delayed_work(&ndev_ctx->dwork, 0); |
249 | } | 259 | } |
250 | } | 260 | } |
251 | 261 | ||
@@ -388,17 +398,35 @@ static const struct net_device_ops device_ops = { | |||
388 | * current context when receiving RNDIS_STATUS_MEDIA_CONNECT event. So, add | 398 | * current context when receiving RNDIS_STATUS_MEDIA_CONNECT event. So, add |
389 | * another netif_notify_peers() into a delayed work, otherwise GARP packet | 399 | * another netif_notify_peers() into a delayed work, otherwise GARP packet |
390 | * will not be sent after quick migration, and cause network disconnection. | 400 | * will not be sent after quick migration, and cause network disconnection. |
401 | * Also, we update the carrier status here. | ||
391 | */ | 402 | */ |
392 | static void netvsc_send_garp(struct work_struct *w) | 403 | static void netvsc_link_change(struct work_struct *w) |
393 | { | 404 | { |
394 | struct net_device_context *ndev_ctx; | 405 | struct net_device_context *ndev_ctx; |
395 | struct net_device *net; | 406 | struct net_device *net; |
396 | struct netvsc_device *net_device; | 407 | struct netvsc_device *net_device; |
408 | struct rndis_device *rdev; | ||
409 | bool notify; | ||
410 | |||
411 | rtnl_lock(); | ||
397 | 412 | ||
398 | ndev_ctx = container_of(w, struct net_device_context, dwork.work); | 413 | ndev_ctx = container_of(w, struct net_device_context, dwork.work); |
399 | net_device = hv_get_drvdata(ndev_ctx->device_ctx); | 414 | net_device = hv_get_drvdata(ndev_ctx->device_ctx); |
415 | rdev = net_device->extension; | ||
400 | net = net_device->ndev; | 416 | net = net_device->ndev; |
401 | netdev_notify_peers(net); | 417 | |
418 | if (rdev->link_state) { | ||
419 | netif_carrier_off(net); | ||
420 | notify = false; | ||
421 | } else { | ||
422 | netif_carrier_on(net); | ||
423 | notify = true; | ||
424 | } | ||
425 | |||
426 | rtnl_unlock(); | ||
427 | |||
428 | if (notify) | ||
429 | netdev_notify_peers(net); | ||
402 | } | 430 | } |
403 | 431 | ||
404 | 432 | ||
@@ -414,13 +442,10 @@ static int netvsc_probe(struct hv_device *dev, | |||
414 | if (!net) | 442 | if (!net) |
415 | return -ENOMEM; | 443 | return -ENOMEM; |
416 | 444 | ||
417 | /* Set initial state */ | ||
418 | netif_carrier_off(net); | ||
419 | |||
420 | net_device_ctx = netdev_priv(net); | 445 | net_device_ctx = netdev_priv(net); |
421 | net_device_ctx->device_ctx = dev; | 446 | net_device_ctx->device_ctx = dev; |
422 | hv_set_drvdata(dev, net); | 447 | hv_set_drvdata(dev, net); |
423 | INIT_DELAYED_WORK(&net_device_ctx->dwork, netvsc_send_garp); | 448 | INIT_DELAYED_WORK(&net_device_ctx->dwork, netvsc_link_change); |
424 | INIT_WORK(&net_device_ctx->work, do_set_multicast); | 449 | INIT_WORK(&net_device_ctx->work, do_set_multicast); |
425 | 450 | ||
426 | net->netdev_ops = &device_ops; | 451 | net->netdev_ops = &device_ops; |
@@ -443,8 +468,6 @@ static int netvsc_probe(struct hv_device *dev, | |||
443 | } | 468 | } |
444 | memcpy(net->dev_addr, device_info.mac_adr, ETH_ALEN); | 469 | memcpy(net->dev_addr, device_info.mac_adr, ETH_ALEN); |
445 | 470 | ||
446 | netif_carrier_on(net); | ||
447 | |||
448 | ret = register_netdev(net); | 471 | ret = register_netdev(net); |
449 | if (ret != 0) { | 472 | if (ret != 0) { |
450 | pr_err("Unable to register netdev.\n"); | 473 | pr_err("Unable to register netdev.\n"); |