Merge branch 'nfp-fixes'

Jakub Kicinski says:

====================
nfp: fix SR-IOV deadlock and representor bugs

This series tackles the bug I've already tried to fix in commit
6d48ceb27a ("nfp: allocate a private workqueue for driver work").
I created a separate workqueue to avoid possible deadlock, and
the lockdep error disappeared, coincidentally.  The way workqueues
are operating, separate workqueue doesn't necessarily mean separate
thread of execution.  Luckily we can safely forego the lock.

Second fix changes the order in which vNIC netdevs and representors
are created/destroyed.  The fix is kept small and should be sufficient
for net because of how flower uses representors, a more thorough fix
will be targeted at net-next.

Third fix avoids leaking mapped frame buffers if FW sent a frame with
unknown portid.
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
David S. Miller 2017-08-23 20:39:44 -07:00
commit 40e607cbee
3 changed files with 26 additions and 22 deletions

View File

@ -98,21 +98,20 @@ static int nfp_pcie_sriov_enable(struct pci_dev *pdev, int num_vfs)
struct nfp_pf *pf = pci_get_drvdata(pdev); struct nfp_pf *pf = pci_get_drvdata(pdev);
int err; int err;
mutex_lock(&pf->lock);
if (num_vfs > pf->limit_vfs) { if (num_vfs > pf->limit_vfs) {
nfp_info(pf->cpp, "Firmware limits number of VFs to %u\n", nfp_info(pf->cpp, "Firmware limits number of VFs to %u\n",
pf->limit_vfs); pf->limit_vfs);
err = -EINVAL; return -EINVAL;
goto err_unlock;
} }
err = pci_enable_sriov(pdev, num_vfs); err = pci_enable_sriov(pdev, num_vfs);
if (err) { if (err) {
dev_warn(&pdev->dev, "Failed to enable PCI SR-IOV: %d\n", err); dev_warn(&pdev->dev, "Failed to enable PCI SR-IOV: %d\n", err);
goto err_unlock; return err;
} }
mutex_lock(&pf->lock);
err = nfp_app_sriov_enable(pf->app, num_vfs); err = nfp_app_sriov_enable(pf->app, num_vfs);
if (err) { if (err) {
dev_warn(&pdev->dev, dev_warn(&pdev->dev,
@ -129,9 +128,8 @@ static int nfp_pcie_sriov_enable(struct pci_dev *pdev, int num_vfs)
return num_vfs; return num_vfs;
err_sriov_disable: err_sriov_disable:
pci_disable_sriov(pdev);
err_unlock:
mutex_unlock(&pf->lock); mutex_unlock(&pf->lock);
pci_disable_sriov(pdev);
return err; return err;
#endif #endif
return 0; return 0;
@ -158,10 +156,10 @@ static int nfp_pcie_sriov_disable(struct pci_dev *pdev)
pf->num_vfs = 0; pf->num_vfs = 0;
mutex_unlock(&pf->lock);
pci_disable_sriov(pdev); pci_disable_sriov(pdev);
dev_dbg(&pdev->dev, "Removed VFs.\n"); dev_dbg(&pdev->dev, "Removed VFs.\n");
mutex_unlock(&pf->lock);
#endif #endif
return 0; return 0;
} }

View File

@ -1751,6 +1751,10 @@ static int nfp_net_rx(struct nfp_net_rx_ring *rx_ring, int budget)
continue; continue;
} }
nfp_net_dma_unmap_rx(dp, rxbuf->dma_addr);
nfp_net_rx_give_one(dp, rx_ring, new_frag, new_dma_addr);
if (likely(!meta.portid)) { if (likely(!meta.portid)) {
netdev = dp->netdev; netdev = dp->netdev;
} else { } else {
@ -1759,16 +1763,12 @@ static int nfp_net_rx(struct nfp_net_rx_ring *rx_ring, int budget)
nn = netdev_priv(dp->netdev); nn = netdev_priv(dp->netdev);
netdev = nfp_app_repr_get(nn->app, meta.portid); netdev = nfp_app_repr_get(nn->app, meta.portid);
if (unlikely(!netdev)) { if (unlikely(!netdev)) {
nfp_net_rx_drop(dp, r_vec, rx_ring, rxbuf, skb); nfp_net_rx_drop(dp, r_vec, rx_ring, NULL, skb);
continue; continue;
} }
nfp_repr_inc_rx_stats(netdev, pkt_len); nfp_repr_inc_rx_stats(netdev, pkt_len);
} }
nfp_net_dma_unmap_rx(dp, rxbuf->dma_addr);
nfp_net_rx_give_one(dp, rx_ring, new_frag, new_dma_addr);
skb_reserve(skb, pkt_off); skb_reserve(skb, pkt_off);
skb_put(skb, pkt_len); skb_put(skb, pkt_len);

View File

@ -456,10 +456,6 @@ static int nfp_net_pf_app_start(struct nfp_pf *pf)
{ {
int err; int err;
err = nfp_net_pf_app_start_ctrl(pf);
if (err)
return err;
err = nfp_app_start(pf->app, pf->ctrl_vnic); err = nfp_app_start(pf->app, pf->ctrl_vnic);
if (err) if (err)
goto err_ctrl_stop; goto err_ctrl_stop;
@ -484,7 +480,6 @@ static void nfp_net_pf_app_stop(struct nfp_pf *pf)
if (pf->num_vfs) if (pf->num_vfs)
nfp_app_sriov_disable(pf->app); nfp_app_sriov_disable(pf->app);
nfp_app_stop(pf->app); nfp_app_stop(pf->app);
nfp_net_pf_app_stop_ctrl(pf);
} }
static void nfp_net_pci_unmap_mem(struct nfp_pf *pf) static void nfp_net_pci_unmap_mem(struct nfp_pf *pf)
@ -559,7 +554,7 @@ err_unmap_ctrl:
static void nfp_net_pci_remove_finish(struct nfp_pf *pf) static void nfp_net_pci_remove_finish(struct nfp_pf *pf)
{ {
nfp_net_pf_app_stop(pf); nfp_net_pf_app_stop_ctrl(pf);
/* stop app first, to avoid double free of ctrl vNIC's ddir */ /* stop app first, to avoid double free of ctrl vNIC's ddir */
nfp_net_debugfs_dir_clean(&pf->ddir); nfp_net_debugfs_dir_clean(&pf->ddir);
@ -690,6 +685,7 @@ int nfp_net_pci_probe(struct nfp_pf *pf)
{ {
struct nfp_net_fw_version fw_ver; struct nfp_net_fw_version fw_ver;
u8 __iomem *ctrl_bar, *qc_bar; u8 __iomem *ctrl_bar, *qc_bar;
struct nfp_net *nn;
int stride; int stride;
int err; int err;
@ -766,7 +762,7 @@ int nfp_net_pci_probe(struct nfp_pf *pf)
if (err) if (err)
goto err_free_vnics; goto err_free_vnics;
err = nfp_net_pf_app_start(pf); err = nfp_net_pf_app_start_ctrl(pf);
if (err) if (err)
goto err_free_irqs; goto err_free_irqs;
@ -774,12 +770,20 @@ int nfp_net_pci_probe(struct nfp_pf *pf)
if (err) if (err)
goto err_stop_app; goto err_stop_app;
err = nfp_net_pf_app_start(pf);
if (err)
goto err_clean_vnics;
mutex_unlock(&pf->lock); mutex_unlock(&pf->lock);
return 0; return 0;
err_clean_vnics:
list_for_each_entry(nn, &pf->vnics, vnic_list)
if (nfp_net_is_data_vnic(nn))
nfp_net_pf_clean_vnic(pf, nn);
err_stop_app: err_stop_app:
nfp_net_pf_app_stop(pf); nfp_net_pf_app_stop_ctrl(pf);
err_free_irqs: err_free_irqs:
nfp_net_pf_free_irqs(pf); nfp_net_pf_free_irqs(pf);
err_free_vnics: err_free_vnics:
@ -803,6 +807,8 @@ void nfp_net_pci_remove(struct nfp_pf *pf)
if (list_empty(&pf->vnics)) if (list_empty(&pf->vnics))
goto out; goto out;
nfp_net_pf_app_stop(pf);
list_for_each_entry(nn, &pf->vnics, vnic_list) list_for_each_entry(nn, &pf->vnics, vnic_list)
if (nfp_net_is_data_vnic(nn)) if (nfp_net_is_data_vnic(nn))
nfp_net_pf_clean_vnic(pf, nn); nfp_net_pf_clean_vnic(pf, nn);