diff options
author | Dexuan Cui <decui@microsoft.com> | 2021-10-29 17:54:08 -0700 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2021-11-01 13:21:49 +0000 |
commit | 635096a86edb067d55a1e04b4a918f5c6dac0c51 (patch) | |
tree | d739b2dcd39b03b1a7db755215e76a1816166f8c /drivers/net/ethernet/microsoft/mana/mana_en.c | |
parent | 62ea8b77ed3b7086561765df0226ebc7bb442020 (diff) |
net: mana: Support hibernation and kexec
Implement the suspend/resume/shutdown callbacks for hibernation/kexec.
Add mana_gd_setup() and mana_gd_cleanup() for some common code, and
use them in the mand_gd_* callbacks.
Reuse mana_probe/remove() for the hibernation path.
Signed-off-by: Dexuan Cui <decui@microsoft.com>
Reviewed-by: Haiyang Zhang <haiyangz@microsoft.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/ethernet/microsoft/mana/mana_en.c')
-rw-r--r-- | drivers/net/ethernet/microsoft/mana/mana_en.c | 72 |
1 files changed, 56 insertions, 16 deletions
diff --git a/drivers/net/ethernet/microsoft/mana/mana_en.c b/drivers/net/ethernet/microsoft/mana/mana_en.c index 46ef9f47d9c5..72cbf45c42d8 100644 --- a/drivers/net/ethernet/microsoft/mana/mana_en.c +++ b/drivers/net/ethernet/microsoft/mana/mana_en.c @@ -1828,11 +1828,12 @@ free_net: return err; } -int mana_probe(struct gdma_dev *gd) +int mana_probe(struct gdma_dev *gd, bool resuming) { struct gdma_context *gc = gd->gdma_context; + struct mana_context *ac = gd->driver_data; struct device *dev = gc->dev; - struct mana_context *ac; + u16 num_ports = 0; int err; int i; @@ -1844,44 +1845,70 @@ int mana_probe(struct gdma_dev *gd) if (err) return err; - ac = kzalloc(sizeof(*ac), GFP_KERNEL); - if (!ac) - return -ENOMEM; + if (!resuming) { + ac = kzalloc(sizeof(*ac), GFP_KERNEL); + if (!ac) + return -ENOMEM; - ac->gdma_dev = gd; - ac->num_ports = 1; - gd->driver_data = ac; + ac->gdma_dev = gd; + gd->driver_data = ac; + } err = mana_create_eq(ac); if (err) goto out; err = mana_query_device_cfg(ac, MANA_MAJOR_VERSION, MANA_MINOR_VERSION, - MANA_MICRO_VERSION, &ac->num_ports); + MANA_MICRO_VERSION, &num_ports); if (err) goto out; + if (!resuming) { + ac->num_ports = num_ports; + } else { + if (ac->num_ports != num_ports) { + dev_err(dev, "The number of vPorts changed: %d->%d\n", + ac->num_ports, num_ports); + err = -EPROTO; + goto out; + } + } + + if (ac->num_ports == 0) + dev_err(dev, "Failed to detect any vPort\n"); + if (ac->num_ports > MAX_PORTS_IN_MANA_DEV) ac->num_ports = MAX_PORTS_IN_MANA_DEV; - for (i = 0; i < ac->num_ports; i++) { - err = mana_probe_port(ac, i, &ac->ports[i]); - if (err) - break; + if (!resuming) { + for (i = 0; i < ac->num_ports; i++) { + err = mana_probe_port(ac, i, &ac->ports[i]); + if (err) + break; + } + } else { + for (i = 0; i < ac->num_ports; i++) { + rtnl_lock(); + err = mana_attach(ac->ports[i]); + rtnl_unlock(); + if (err) + break; + } } out: if (err) - mana_remove(gd); + mana_remove(gd, false); return err; } -void mana_remove(struct gdma_dev *gd) +void mana_remove(struct gdma_dev *gd, bool suspending) { struct gdma_context *gc = gd->gdma_context; struct mana_context *ac = gd->driver_data; struct device *dev = gc->dev; struct net_device *ndev; + int err; int i; for (i = 0; i < ac->num_ports; i++) { @@ -1897,7 +1924,16 @@ void mana_remove(struct gdma_dev *gd) */ rtnl_lock(); - mana_detach(ndev, false); + err = mana_detach(ndev, false); + if (err) + netdev_err(ndev, "Failed to detach vPort %d: %d\n", + i, err); + + if (suspending) { + /* No need to unregister the ndev. */ + rtnl_unlock(); + continue; + } unregister_netdevice(ndev); @@ -1910,6 +1946,10 @@ void mana_remove(struct gdma_dev *gd) out: mana_gd_deregister_device(gd); + + if (suspending) + return; + gd->driver_data = NULL; gd->gdma_context = NULL; kfree(ac); |