diff options
Diffstat (limited to 'drivers/net')
-rw-r--r-- | drivers/net/hyperv/hyperv_net.h | 3 | ||||
-rw-r--r-- | drivers/net/hyperv/netvsc_drv.c | 57 |
2 files changed, 60 insertions, 0 deletions
diff --git a/drivers/net/hyperv/hyperv_net.h b/drivers/net/hyperv/hyperv_net.h index 250bd90627a5..9caa876ce6e8 100644 --- a/drivers/net/hyperv/hyperv_net.h +++ b/drivers/net/hyperv/hyperv_net.h @@ -955,6 +955,9 @@ struct net_device_context { u32 vf_alloc; /* Serial number of the VF to team with */ u32 vf_serial; + + /* Used to temporarily save the config info across hibernation */ + struct netvsc_device_info *saved_netvsc_dev_info; }; /* Per channel data */ diff --git a/drivers/net/hyperv/netvsc_drv.c b/drivers/net/hyperv/netvsc_drv.c index 868e22e286ca..eff8fef4f775 100644 --- a/drivers/net/hyperv/netvsc_drv.c +++ b/drivers/net/hyperv/netvsc_drv.c @@ -2424,6 +2424,61 @@ static int netvsc_remove(struct hv_device *dev) return 0; } +static int netvsc_suspend(struct hv_device *dev) +{ + struct net_device_context *ndev_ctx; + struct net_device *vf_netdev, *net; + struct netvsc_device *nvdev; + int ret; + + net = hv_get_drvdata(dev); + + ndev_ctx = netdev_priv(net); + cancel_delayed_work_sync(&ndev_ctx->dwork); + + rtnl_lock(); + + nvdev = rtnl_dereference(ndev_ctx->nvdev); + if (nvdev == NULL) { + ret = -ENODEV; + goto out; + } + + vf_netdev = rtnl_dereference(ndev_ctx->vf_netdev); + if (vf_netdev) + netvsc_unregister_vf(vf_netdev); + + /* Save the current config info */ + ndev_ctx->saved_netvsc_dev_info = netvsc_devinfo_get(nvdev); + + ret = netvsc_detach(net, nvdev); +out: + rtnl_unlock(); + + return ret; +} + +static int netvsc_resume(struct hv_device *dev) +{ + struct net_device *net = hv_get_drvdata(dev); + struct net_device_context *net_device_ctx; + struct netvsc_device_info *device_info; + int ret; + + rtnl_lock(); + + net_device_ctx = netdev_priv(net); + device_info = net_device_ctx->saved_netvsc_dev_info; + + ret = netvsc_attach(net, device_info); + + rtnl_unlock(); + + kfree(device_info); + net_device_ctx->saved_netvsc_dev_info = NULL; + + return ret; +} static const struct hv_vmbus_device_id id_table[] = { /* Network guid */ { HV_NIC_GUID, }, @@ -2438,6 +2493,8 @@ static struct hv_driver netvsc_drv = { .id_table = id_table, .probe = netvsc_probe, .remove = netvsc_remove, + .suspend = netvsc_suspend, + .resume = netvsc_resume, .driver = { .probe_type = PROBE_FORCE_SYNCHRONOUS, }, |