diff options
author | Jakub Kicinski <jakub.kicinski@netronome.com> | 2017-08-23 02:22:42 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2017-08-23 23:39:44 -0400 |
commit | d6e1ab9ea3514840e4f32957c457b094646c2e9d (patch) | |
tree | 1cd1a376d6902098d629ba0d83bcad2408064b76 | |
parent | 2f19f50e0f55a8fa067d3705e3f812a4f709567f (diff) |
nfp: don't hold PF lock while enabling SR-IOV
Enabling SR-IOV VFs will cause the PCI subsystem to schedule a
work and flush its workqueue. Since the nfp driver schedules its
own work we can't enable VFs while holding driver load. Commit
6d48ceb27af1 ("nfp: allocate a private workqueue for driver work")
tried to avoid this deadlock by creating a separate workqueue.
Unfortunately, due to the architecture of workqueue subsystem this
does not guarantee a separate thread of execution. Luckily
we can simply take pci_enable_sriov() from under the driver lock.
Take pci_disable_sriov() from under the lock too for symmetry.
Fixes: 6d48ceb27af1 ("nfp: allocate a private workqueue for driver work")
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>
-rw-r--r-- | drivers/net/ethernet/netronome/nfp/nfp_main.c | 16 |
1 files changed, 7 insertions, 9 deletions
diff --git a/drivers/net/ethernet/netronome/nfp/nfp_main.c b/drivers/net/ethernet/netronome/nfp/nfp_main.c index d67969d3e484..3f199db2002e 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_main.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_main.c | |||
@@ -98,21 +98,20 @@ static int nfp_pcie_sriov_enable(struct pci_dev *pdev, int num_vfs) | |||
98 | struct nfp_pf *pf = pci_get_drvdata(pdev); | 98 | struct nfp_pf *pf = pci_get_drvdata(pdev); |
99 | int err; | 99 | int err; |
100 | 100 | ||
101 | mutex_lock(&pf->lock); | ||
102 | |||
103 | if (num_vfs > pf->limit_vfs) { | 101 | if (num_vfs > pf->limit_vfs) { |
104 | nfp_info(pf->cpp, "Firmware limits number of VFs to %u\n", | 102 | nfp_info(pf->cpp, "Firmware limits number of VFs to %u\n", |
105 | pf->limit_vfs); | 103 | pf->limit_vfs); |
106 | err = -EINVAL; | 104 | return -EINVAL; |
107 | goto err_unlock; | ||
108 | } | 105 | } |
109 | 106 | ||
110 | err = pci_enable_sriov(pdev, num_vfs); | 107 | err = pci_enable_sriov(pdev, num_vfs); |
111 | if (err) { | 108 | if (err) { |
112 | dev_warn(&pdev->dev, "Failed to enable PCI SR-IOV: %d\n", err); | 109 | dev_warn(&pdev->dev, "Failed to enable PCI SR-IOV: %d\n", err); |
113 | goto err_unlock; | 110 | return err; |
114 | } | 111 | } |
115 | 112 | ||
113 | mutex_lock(&pf->lock); | ||
114 | |||
116 | err = nfp_app_sriov_enable(pf->app, num_vfs); | 115 | err = nfp_app_sriov_enable(pf->app, num_vfs); |
117 | if (err) { | 116 | if (err) { |
118 | dev_warn(&pdev->dev, | 117 | dev_warn(&pdev->dev, |
@@ -129,9 +128,8 @@ static int nfp_pcie_sriov_enable(struct pci_dev *pdev, int num_vfs) | |||
129 | return num_vfs; | 128 | return num_vfs; |
130 | 129 | ||
131 | err_sriov_disable: | 130 | err_sriov_disable: |
132 | pci_disable_sriov(pdev); | ||
133 | err_unlock: | ||
134 | mutex_unlock(&pf->lock); | 131 | mutex_unlock(&pf->lock); |
132 | pci_disable_sriov(pdev); | ||
135 | return err; | 133 | return err; |
136 | #endif | 134 | #endif |
137 | return 0; | 135 | return 0; |
@@ -158,10 +156,10 @@ static int nfp_pcie_sriov_disable(struct pci_dev *pdev) | |||
158 | 156 | ||
159 | pf->num_vfs = 0; | 157 | pf->num_vfs = 0; |
160 | 158 | ||
159 | mutex_unlock(&pf->lock); | ||
160 | |||
161 | pci_disable_sriov(pdev); | 161 | pci_disable_sriov(pdev); |
162 | dev_dbg(&pdev->dev, "Removed VFs.\n"); | 162 | dev_dbg(&pdev->dev, "Removed VFs.\n"); |
163 | |||
164 | mutex_unlock(&pf->lock); | ||
165 | #endif | 163 | #endif |
166 | return 0; | 164 | return 0; |
167 | } | 165 | } |