Skip to content

Commit 0efeea5

Browse files
dcuiSasha Levin
authored andcommitted
hv_netvsc: Add the support of hibernation
The existing netvsc_detach() and netvsc_attach() APIs make it easy to implement the suspend/resume callbacks. Signed-off-by: Dexuan Cui <[email protected]> Reviewed-by: Haiyang Zhang <[email protected]> Signed-off-by: Sasha Levin <[email protected]>
1 parent 2194c2e commit 0efeea5

File tree

2 files changed

+60
-0
lines changed

2 files changed

+60
-0
lines changed

drivers/net/hyperv/hyperv_net.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -952,6 +952,9 @@ struct net_device_context {
952952
u32 vf_alloc;
953953
/* Serial number of the VF to team with */
954954
u32 vf_serial;
955+
956+
/* Used to temporarily save the config info across hibernation */
957+
struct netvsc_device_info *saved_netvsc_dev_info;
955958
};
956959

957960
/* Per channel data */

drivers/net/hyperv/netvsc_drv.c

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2421,6 +2421,61 @@ static int netvsc_remove(struct hv_device *dev)
24212421
return 0;
24222422
}
24232423

2424+
static int netvsc_suspend(struct hv_device *dev)
2425+
{
2426+
struct net_device_context *ndev_ctx;
2427+
struct net_device *vf_netdev, *net;
2428+
struct netvsc_device *nvdev;
2429+
int ret;
2430+
2431+
net = hv_get_drvdata(dev);
2432+
2433+
ndev_ctx = netdev_priv(net);
2434+
cancel_delayed_work_sync(&ndev_ctx->dwork);
2435+
2436+
rtnl_lock();
2437+
2438+
nvdev = rtnl_dereference(ndev_ctx->nvdev);
2439+
if (nvdev == NULL) {
2440+
ret = -ENODEV;
2441+
goto out;
2442+
}
2443+
2444+
vf_netdev = rtnl_dereference(ndev_ctx->vf_netdev);
2445+
if (vf_netdev)
2446+
netvsc_unregister_vf(vf_netdev);
2447+
2448+
/* Save the current config info */
2449+
ndev_ctx->saved_netvsc_dev_info = netvsc_devinfo_get(nvdev);
2450+
2451+
ret = netvsc_detach(net, nvdev);
2452+
out:
2453+
rtnl_unlock();
2454+
2455+
return ret;
2456+
}
2457+
2458+
static int netvsc_resume(struct hv_device *dev)
2459+
{
2460+
struct net_device *net = hv_get_drvdata(dev);
2461+
struct net_device_context *net_device_ctx;
2462+
struct netvsc_device_info *device_info;
2463+
int ret;
2464+
2465+
rtnl_lock();
2466+
2467+
net_device_ctx = netdev_priv(net);
2468+
device_info = net_device_ctx->saved_netvsc_dev_info;
2469+
2470+
ret = netvsc_attach(net, device_info);
2471+
2472+
rtnl_unlock();
2473+
2474+
kfree(device_info);
2475+
net_device_ctx->saved_netvsc_dev_info = NULL;
2476+
2477+
return ret;
2478+
}
24242479
static const struct hv_vmbus_device_id id_table[] = {
24252480
/* Network guid */
24262481
{ HV_NIC_GUID, },
@@ -2435,6 +2490,8 @@ static struct hv_driver netvsc_drv = {
24352490
.id_table = id_table,
24362491
.probe = netvsc_probe,
24372492
.remove = netvsc_remove,
2493+
.suspend = netvsc_suspend,
2494+
.resume = netvsc_resume,
24382495
.driver = {
24392496
.probe_type = PROBE_FORCE_SYNCHRONOUS,
24402497
},

0 commit comments

Comments
 (0)