Skip to content

Commit 635096a

Browse files
dcuidavem330
authored andcommitted
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 <[email protected]> Reviewed-by: Haiyang Zhang <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 62ea8b7 commit 635096a

File tree

3 files changed

+164
-52
lines changed

3 files changed

+164
-52
lines changed

drivers/net/ethernet/microsoft/mana/gdma_main.c

Lines changed: 106 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1258,6 +1258,52 @@ static void mana_gd_remove_irqs(struct pci_dev *pdev)
12581258
gc->irq_contexts = NULL;
12591259
}
12601260

1261+
static int mana_gd_setup(struct pci_dev *pdev)
1262+
{
1263+
struct gdma_context *gc = pci_get_drvdata(pdev);
1264+
int err;
1265+
1266+
mana_gd_init_registers(pdev);
1267+
mana_smc_init(&gc->shm_channel, gc->dev, gc->shm_base);
1268+
1269+
err = mana_gd_setup_irqs(pdev);
1270+
if (err)
1271+
return err;
1272+
1273+
err = mana_hwc_create_channel(gc);
1274+
if (err)
1275+
goto remove_irq;
1276+
1277+
err = mana_gd_verify_vf_version(pdev);
1278+
if (err)
1279+
goto destroy_hwc;
1280+
1281+
err = mana_gd_query_max_resources(pdev);
1282+
if (err)
1283+
goto destroy_hwc;
1284+
1285+
err = mana_gd_detect_devices(pdev);
1286+
if (err)
1287+
goto destroy_hwc;
1288+
1289+
return 0;
1290+
1291+
destroy_hwc:
1292+
mana_hwc_destroy_channel(gc);
1293+
remove_irq:
1294+
mana_gd_remove_irqs(pdev);
1295+
return err;
1296+
}
1297+
1298+
static void mana_gd_cleanup(struct pci_dev *pdev)
1299+
{
1300+
struct gdma_context *gc = pci_get_drvdata(pdev);
1301+
1302+
mana_hwc_destroy_channel(gc);
1303+
1304+
mana_gd_remove_irqs(pdev);
1305+
}
1306+
12611307
static int mana_gd_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
12621308
{
12631309
struct gdma_context *gc;
@@ -1287,54 +1333,33 @@ static int mana_gd_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
12871333
if (!gc)
12881334
goto release_region;
12891335

1336+
mutex_init(&gc->eq_test_event_mutex);
1337+
pci_set_drvdata(pdev, gc);
1338+
12901339
bar0_va = pci_iomap(pdev, bar, 0);
12911340
if (!bar0_va)
12921341
goto free_gc;
12931342

12941343
gc->bar0_va = bar0_va;
12951344
gc->dev = &pdev->dev;
12961345

1297-
pci_set_drvdata(pdev, gc);
1298-
1299-
mana_gd_init_registers(pdev);
13001346

1301-
mana_smc_init(&gc->shm_channel, gc->dev, gc->shm_base);
1302-
1303-
err = mana_gd_setup_irqs(pdev);
1347+
err = mana_gd_setup(pdev);
13041348
if (err)
13051349
goto unmap_bar;
13061350

1307-
mutex_init(&gc->eq_test_event_mutex);
1308-
1309-
err = mana_hwc_create_channel(gc);
1351+
err = mana_probe(&gc->mana, false);
13101352
if (err)
1311-
goto remove_irq;
1312-
1313-
err = mana_gd_verify_vf_version(pdev);
1314-
if (err)
1315-
goto remove_irq;
1316-
1317-
err = mana_gd_query_max_resources(pdev);
1318-
if (err)
1319-
goto remove_irq;
1320-
1321-
err = mana_gd_detect_devices(pdev);
1322-
if (err)
1323-
goto remove_irq;
1324-
1325-
err = mana_probe(&gc->mana);
1326-
if (err)
1327-
goto clean_up_gdma;
1353+
goto cleanup_gd;
13281354

13291355
return 0;
13301356

1331-
clean_up_gdma:
1332-
mana_hwc_destroy_channel(gc);
1333-
remove_irq:
1334-
mana_gd_remove_irqs(pdev);
1357+
cleanup_gd:
1358+
mana_gd_cleanup(pdev);
13351359
unmap_bar:
13361360
pci_iounmap(pdev, bar0_va);
13371361
free_gc:
1362+
pci_set_drvdata(pdev, NULL);
13381363
vfree(gc);
13391364
release_region:
13401365
pci_release_regions(pdev);
@@ -1349,11 +1374,9 @@ static void mana_gd_remove(struct pci_dev *pdev)
13491374
{
13501375
struct gdma_context *gc = pci_get_drvdata(pdev);
13511376

1352-
mana_remove(&gc->mana);
1377+
mana_remove(&gc->mana, false);
13531378

1354-
mana_hwc_destroy_channel(gc);
1355-
1356-
mana_gd_remove_irqs(pdev);
1379+
mana_gd_cleanup(pdev);
13571380

13581381
pci_iounmap(pdev, gc->bar0_va);
13591382

@@ -1364,6 +1387,52 @@ static void mana_gd_remove(struct pci_dev *pdev)
13641387
pci_disable_device(pdev);
13651388
}
13661389

1390+
/* The 'state' parameter is not used. */
1391+
static int mana_gd_suspend(struct pci_dev *pdev, pm_message_t state)
1392+
{
1393+
struct gdma_context *gc = pci_get_drvdata(pdev);
1394+
1395+
mana_remove(&gc->mana, true);
1396+
1397+
mana_gd_cleanup(pdev);
1398+
1399+
return 0;
1400+
}
1401+
1402+
/* In case the NIC hardware stops working, the suspend and resume callbacks will
1403+
* fail -- if this happens, it's safer to just report an error than try to undo
1404+
* what has been done.
1405+
*/
1406+
static int mana_gd_resume(struct pci_dev *pdev)
1407+
{
1408+
struct gdma_context *gc = pci_get_drvdata(pdev);
1409+
int err;
1410+
1411+
err = mana_gd_setup(pdev);
1412+
if (err)
1413+
return err;
1414+
1415+
err = mana_probe(&gc->mana, true);
1416+
if (err)
1417+
return err;
1418+
1419+
return 0;
1420+
}
1421+
1422+
/* Quiesce the device for kexec. This is also called upon reboot/shutdown. */
1423+
static void mana_gd_shutdown(struct pci_dev *pdev)
1424+
{
1425+
struct gdma_context *gc = pci_get_drvdata(pdev);
1426+
1427+
dev_info(&pdev->dev, "Shutdown was calledd\n");
1428+
1429+
mana_remove(&gc->mana, true);
1430+
1431+
mana_gd_cleanup(pdev);
1432+
1433+
pci_disable_device(pdev);
1434+
}
1435+
13671436
#ifndef PCI_VENDOR_ID_MICROSOFT
13681437
#define PCI_VENDOR_ID_MICROSOFT 0x1414
13691438
#endif
@@ -1378,6 +1447,9 @@ static struct pci_driver mana_driver = {
13781447
.id_table = mana_id_table,
13791448
.probe = mana_gd_probe,
13801449
.remove = mana_gd_remove,
1450+
.suspend = mana_gd_suspend,
1451+
.resume = mana_gd_resume,
1452+
.shutdown = mana_gd_shutdown,
13811453
};
13821454

13831455
module_pci_driver(mana_driver);

drivers/net/ethernet/microsoft/mana/mana.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -374,8 +374,8 @@ int mana_alloc_queues(struct net_device *ndev);
374374
int mana_attach(struct net_device *ndev);
375375
int mana_detach(struct net_device *ndev, bool from_close);
376376

377-
int mana_probe(struct gdma_dev *gd);
378-
void mana_remove(struct gdma_dev *gd);
377+
int mana_probe(struct gdma_dev *gd, bool resuming);
378+
void mana_remove(struct gdma_dev *gd, bool suspending);
379379

380380
extern const struct ethtool_ops mana_ethtool_ops;
381381

drivers/net/ethernet/microsoft/mana/mana_en.c

Lines changed: 56 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1828,11 +1828,12 @@ static int mana_probe_port(struct mana_context *ac, int port_idx,
18281828
return err;
18291829
}
18301830

1831-
int mana_probe(struct gdma_dev *gd)
1831+
int mana_probe(struct gdma_dev *gd, bool resuming)
18321832
{
18331833
struct gdma_context *gc = gd->gdma_context;
1834+
struct mana_context *ac = gd->driver_data;
18341835
struct device *dev = gc->dev;
1835-
struct mana_context *ac;
1836+
u16 num_ports = 0;
18361837
int err;
18371838
int i;
18381839

@@ -1844,44 +1845,70 @@ int mana_probe(struct gdma_dev *gd)
18441845
if (err)
18451846
return err;
18461847

1847-
ac = kzalloc(sizeof(*ac), GFP_KERNEL);
1848-
if (!ac)
1849-
return -ENOMEM;
1848+
if (!resuming) {
1849+
ac = kzalloc(sizeof(*ac), GFP_KERNEL);
1850+
if (!ac)
1851+
return -ENOMEM;
18501852

1851-
ac->gdma_dev = gd;
1852-
ac->num_ports = 1;
1853-
gd->driver_data = ac;
1853+
ac->gdma_dev = gd;
1854+
gd->driver_data = ac;
1855+
}
18541856

18551857
err = mana_create_eq(ac);
18561858
if (err)
18571859
goto out;
18581860

18591861
err = mana_query_device_cfg(ac, MANA_MAJOR_VERSION, MANA_MINOR_VERSION,
1860-
MANA_MICRO_VERSION, &ac->num_ports);
1862+
MANA_MICRO_VERSION, &num_ports);
18611863
if (err)
18621864
goto out;
18631865

1866+
if (!resuming) {
1867+
ac->num_ports = num_ports;
1868+
} else {
1869+
if (ac->num_ports != num_ports) {
1870+
dev_err(dev, "The number of vPorts changed: %d->%d\n",
1871+
ac->num_ports, num_ports);
1872+
err = -EPROTO;
1873+
goto out;
1874+
}
1875+
}
1876+
1877+
if (ac->num_ports == 0)
1878+
dev_err(dev, "Failed to detect any vPort\n");
1879+
18641880
if (ac->num_ports > MAX_PORTS_IN_MANA_DEV)
18651881
ac->num_ports = MAX_PORTS_IN_MANA_DEV;
18661882

1867-
for (i = 0; i < ac->num_ports; i++) {
1868-
err = mana_probe_port(ac, i, &ac->ports[i]);
1869-
if (err)
1870-
break;
1883+
if (!resuming) {
1884+
for (i = 0; i < ac->num_ports; i++) {
1885+
err = mana_probe_port(ac, i, &ac->ports[i]);
1886+
if (err)
1887+
break;
1888+
}
1889+
} else {
1890+
for (i = 0; i < ac->num_ports; i++) {
1891+
rtnl_lock();
1892+
err = mana_attach(ac->ports[i]);
1893+
rtnl_unlock();
1894+
if (err)
1895+
break;
1896+
}
18711897
}
18721898
out:
18731899
if (err)
1874-
mana_remove(gd);
1900+
mana_remove(gd, false);
18751901

18761902
return err;
18771903
}
18781904

1879-
void mana_remove(struct gdma_dev *gd)
1905+
void mana_remove(struct gdma_dev *gd, bool suspending)
18801906
{
18811907
struct gdma_context *gc = gd->gdma_context;
18821908
struct mana_context *ac = gd->driver_data;
18831909
struct device *dev = gc->dev;
18841910
struct net_device *ndev;
1911+
int err;
18851912
int i;
18861913

18871914
for (i = 0; i < ac->num_ports; i++) {
@@ -1897,7 +1924,16 @@ void mana_remove(struct gdma_dev *gd)
18971924
*/
18981925
rtnl_lock();
18991926

1900-
mana_detach(ndev, false);
1927+
err = mana_detach(ndev, false);
1928+
if (err)
1929+
netdev_err(ndev, "Failed to detach vPort %d: %d\n",
1930+
i, err);
1931+
1932+
if (suspending) {
1933+
/* No need to unregister the ndev. */
1934+
rtnl_unlock();
1935+
continue;
1936+
}
19011937

19021938
unregister_netdevice(ndev);
19031939

@@ -1910,6 +1946,10 @@ void mana_remove(struct gdma_dev *gd)
19101946

19111947
out:
19121948
mana_gd_deregister_device(gd);
1949+
1950+
if (suspending)
1951+
return;
1952+
19131953
gd->driver_data = NULL;
19141954
gd->gdma_context = NULL;
19151955
kfree(ac);

0 commit comments

Comments
 (0)