nfp: add mutex protection for the port list
authorJakub Kicinski <jakub.kicinski@netronome.com>
Tue, 4 Apr 2017 23:12:24 +0000 (16:12 -0700)
committerDavid S. Miller <davem@davemloft.net>
Wed, 5 Apr 2017 17:49:12 +0000 (10:49 -0700)
We will want to unregister netdevs after their port got reconfigured.
For that we need to make sure manipulations of port list from the
port reconfiguration flow will not race with driver's .remove()
callback.

Signed-off-by: Jakub Kicinski <jakub.kicinski@netronome.com>
Reviewed-by: Simon Horman <simon.horman@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_main.h
drivers/net/ethernet/netronome/nfp/nfp_net_main.c

index dedac720fb292c289edc8a7db50169852945bb5c..96266796fd094ee0caae5fefac74c1f91269a9d7 100644 (file)
@@ -385,8 +385,7 @@ static void nfp_pci_remove(struct pci_dev *pdev)
 {
        struct nfp_pf *pf = pci_get_drvdata(pdev);
 
-       if (!list_empty(&pf->ports))
-               nfp_net_pci_remove(pf);
+       nfp_net_pci_remove(pf);
 
        nfp_pcie_sriov_disable(pdev);
 
index bb15a5724bf742f118f3421ab3d4a2f0d7fe09fb..b7ceec9a5783d94073d9596b4a8dce03842a2937 100644 (file)
@@ -42,6 +42,7 @@
 #include <linux/list.h>
 #include <linux/types.h>
 #include <linux/msi.h>
+#include <linux/mutex.h>
 #include <linux/pci.h>
 
 struct dentry;
@@ -67,6 +68,7 @@ struct nfp_eth_table;
  * @num_ports:         Number of adapter ports app firmware supports
  * @num_netdevs:       Number of netdevs spawned
  * @ports:             Linked list of port structures (struct nfp_net)
+ * @port_lock:         Protects @ports, @num_ports, @num_netdevs
  */
 struct nfp_pf {
        struct pci_dev *pdev;
@@ -92,6 +94,7 @@ struct nfp_pf {
        unsigned int num_netdevs;
 
        struct list_head ports;
+       struct mutex port_lock;
 };
 
 extern struct pci_driver nfp_netvf_pci_driver;
index 1644954f52cda42dd3d60cf926a0f0af29bb1454..4d602b1ddc90ea31f433b013cd22bfff3d86f9ac 100644 (file)
@@ -481,17 +481,22 @@ int nfp_net_pci_probe(struct nfp_pf *pf)
        int stride;
        int err;
 
+       mutex_init(&pf->port_lock);
+
        /* Verify that the board has completed initialization */
        if (!nfp_is_ready(pf->cpp)) {
                nfp_err(pf->cpp, "NFP is not ready for NIC operation.\n");
                return -EINVAL;
        }
 
+       mutex_lock(&pf->port_lock);
        pf->num_ports = nfp_net_pf_get_num_ports(pf);
 
        ctrl_bar = nfp_net_pf_map_ctrl_bar(pf);
-       if (!ctrl_bar)
-               return pf->fw_loaded ? -EINVAL : -EPROBE_DEFER;
+       if (!ctrl_bar) {
+               err = pf->fw_loaded ? -EINVAL : -EPROBE_DEFER;
+               goto err_unlock;
+       }
 
        nfp_net_get_fw_version(&fw_ver, ctrl_bar);
        if (fw_ver.resv || fw_ver.class != NFP_NET_CFG_VERSION_CLASS_GENERIC) {
@@ -565,6 +570,8 @@ int nfp_net_pci_probe(struct nfp_pf *pf)
        if (err)
                goto err_clean_ddir;
 
+       mutex_unlock(&pf->port_lock);
+
        return 0;
 
 err_clean_ddir:
@@ -574,6 +581,8 @@ err_unmap_tx:
        nfp_cpp_area_release_free(pf->tx_area);
 err_ctrl_unmap:
        nfp_cpp_area_release_free(pf->ctrl_area);
+err_unlock:
+       mutex_unlock(&pf->port_lock);
        return err;
 }
 
@@ -581,6 +590,10 @@ void nfp_net_pci_remove(struct nfp_pf *pf)
 {
        struct nfp_net *nn;
 
+       mutex_lock(&pf->port_lock);
+       if (list_empty(&pf->ports))
+               goto out;
+
        list_for_each_entry(nn, &pf->ports, port_list) {
                nfp_net_debugfs_dir_clean(&nn->debugfs_dir);
 
@@ -597,4 +610,6 @@ void nfp_net_pci_remove(struct nfp_pf *pf)
        nfp_cpp_area_release_free(pf->rx_area);
        nfp_cpp_area_release_free(pf->tx_area);
        nfp_cpp_area_release_free(pf->ctrl_area);
+out:
+       mutex_unlock(&pf->port_lock);
 }