nfp: implement PCI driver shutdown callback
authorDirk van der Merwe <dirk.vandermerwe@netronome.com>
Thu, 25 Apr 2019 03:18:02 +0000 (20:18 -0700)
committerDavid S. Miller <davem@davemloft.net>
Fri, 26 Apr 2019 16:08:13 +0000 (12:08 -0400)
Device may be shutdown without the hardware being reinitialized, in
which case we want to ensure we cleanup properly.

This is especially important for kexec with traffic flowing.

The shutdown procedures resembles the remove procedures, so we can reuse
those common tasks.

Signed-off-by: Dirk van der Merwe <dirk.vandermerwe@netronome.com>
Reviewed-by: Jakub Kicinski <jakub.kicinski@netronome.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/netronome/nfp/nfp_main.c
drivers/net/ethernet/netronome/nfp/nfp_netvf_main.c

index f4c8776e42b680ab29058f4bf168781b60b32059..948d1a4b46439b61f7d4cd7ba197ce2b14b04d85 100644 (file)
@@ -294,6 +294,9 @@ static int nfp_pcie_sriov_disable(struct pci_dev *pdev)
 
 static int nfp_pcie_sriov_configure(struct pci_dev *pdev, int num_vfs)
 {
+       if (!pci_get_drvdata(pdev))
+               return -ENOENT;
+
        if (num_vfs == 0)
                return nfp_pcie_sriov_disable(pdev);
        else
@@ -720,9 +723,13 @@ err_pci_disable:
        return err;
 }
 
-static void nfp_pci_remove(struct pci_dev *pdev)
+static void __nfp_pci_shutdown(struct pci_dev *pdev, bool unload_fw)
 {
-       struct nfp_pf *pf = pci_get_drvdata(pdev);
+       struct nfp_pf *pf;
+
+       pf = pci_get_drvdata(pdev);
+       if (!pf)
+               return;
 
        nfp_hwmon_unregister(pf);
 
@@ -733,7 +740,7 @@ static void nfp_pci_remove(struct pci_dev *pdev)
        vfree(pf->dumpspec);
        kfree(pf->rtbl);
        nfp_mip_close(pf->mip);
-       if (pf->fw_loaded)
+       if (unload_fw && pf->fw_loaded)
                nfp_fw_unload(pf);
 
        destroy_workqueue(pf->wq);
@@ -749,11 +756,22 @@ static void nfp_pci_remove(struct pci_dev *pdev)
        pci_disable_device(pdev);
 }
 
+static void nfp_pci_remove(struct pci_dev *pdev)
+{
+       __nfp_pci_shutdown(pdev, true);
+}
+
+static void nfp_pci_shutdown(struct pci_dev *pdev)
+{
+       __nfp_pci_shutdown(pdev, false);
+}
+
 static struct pci_driver nfp_pci_driver = {
        .name                   = nfp_driver_name,
        .id_table               = nfp_pci_device_ids,
        .probe                  = nfp_pci_probe,
        .remove                 = nfp_pci_remove,
+       .shutdown               = nfp_pci_shutdown,
        .sriov_configure        = nfp_pcie_sriov_configure,
 };
 
index 1145849ca7bac044195f0778db8d882e37b9b8ba..e4977cdf767899a3a664919aee2f1687893b884a 100644 (file)
@@ -282,8 +282,14 @@ err_free_vf:
 
 static void nfp_netvf_pci_remove(struct pci_dev *pdev)
 {
-       struct nfp_net_vf *vf = pci_get_drvdata(pdev);
-       struct nfp_net *nn = vf->nn;
+       struct nfp_net_vf *vf;
+       struct nfp_net *nn;
+
+       vf = pci_get_drvdata(pdev);
+       if (!vf)
+               return;
+
+       nn = vf->nn;
 
        /* Note, the order is slightly different from above as we need
         * to keep the nn pointer around till we have freed everything.
@@ -317,4 +323,5 @@ struct pci_driver nfp_netvf_pci_driver = {
        .id_table    = nfp_netvf_pci_device_ids,
        .probe       = nfp_netvf_pci_probe,
        .remove      = nfp_netvf_pci_remove,
+       .shutdown    = nfp_netvf_pci_remove,
 };