nfp: register devlink after app is created

Devlink used to have two global locks: devlink lock and port lock,
our lock ordering looked like this:

  devlink lock -> driver's pf->lock -> devlink port lock

After recent changes port lock was replaced with per-instance
lock.  Unfortunately, new per-instance lock is taken on most
operations now.  This means we can only grab the pf->lock from
the port split/unsplit ops.  Lock ordering looks like this:

  devlink lock -> driver's pf->lock -> devlink instance lock

Since we can't take pf->lock from most devlink ops, make sure
nfp_apps are prepared to service them as soon as devlink is
registered.  Locking the pf must be pushed down after
nfp_app_init() callback.

The init order looks like this:
 nfp_app_init
 devlink_register
 nfp_app_start
 netdev/port_register

As soon as app_init is done nfp_apps must be ready to service
devlink-related callbacks.  apps can only register their own
devlink objects from nfp_app_start.

Fixes: 2406e7e546 ("devlink: Add per devlink instance lock")
Signed-off-by: Jakub Kicinski <jakub.kicinski@netronome.com>
Reviewed-by: Dirk van der Merwe <dirk.vandermerwe@netronome.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Jakub Kicinski 2018-01-17 18:50:57 -08:00 committed by David S. Miller
parent e1a2599db5
commit bcc93a23ca
3 changed files with 29 additions and 36 deletions

View File

@ -152,18 +152,8 @@ nfp_devlink_port_unsplit(struct devlink *devlink, unsigned int port_index)
static int nfp_devlink_eswitch_mode_get(struct devlink *devlink, u16 *mode)
{
struct nfp_pf *pf = devlink_priv(devlink);
int ret;
mutex_lock(&pf->lock);
if (!pf->app) {
ret = -EBUSY;
goto out;
}
ret = nfp_app_eswitch_mode_get(pf->app, mode);
out:
mutex_unlock(&pf->lock);
return ret;
return nfp_app_eswitch_mode_get(pf->app, mode);
}
const struct devlink_ops nfp_devlink_ops = {

View File

@ -499,13 +499,9 @@ static int nfp_pci_probe(struct pci_dev *pdev,
if (err)
goto err_hwinfo_free;
err = devlink_register(devlink, &pdev->dev);
if (err)
goto err_hwinfo_free;
err = nfp_nsp_init(pdev, pf);
if (err)
goto err_devlink_unreg;
goto err_hwinfo_free;
pf->mip = nfp_mip_open(pf->cpp);
pf->rtbl = __nfp_rtsym_table_read(pf->cpp, pf->mip);
@ -549,8 +545,6 @@ static int nfp_pci_probe(struct pci_dev *pdev,
kfree(pf->eth_tbl);
kfree(pf->nspi);
vfree(pf->dumpspec);
err_devlink_unreg:
devlink_unregister(devlink);
err_hwinfo_free:
kfree(pf->hwinfo);
nfp_cpp_free(pf->cpp);
@ -571,18 +565,13 @@ static int nfp_pci_probe(struct pci_dev *pdev,
static void nfp_pci_remove(struct pci_dev *pdev)
{
struct nfp_pf *pf = pci_get_drvdata(pdev);
struct devlink *devlink;
nfp_hwmon_unregister(pf);
devlink = priv_to_devlink(pf);
nfp_net_pci_remove(pf);
nfp_pcie_sriov_disable(pdev);
pci_sriov_set_totalvfs(pf->pdev, 0);
devlink_unregister(devlink);
nfp_net_pci_remove(pf);
vfree(pf->dumpspec);
kfree(pf->rtbl);
@ -598,7 +587,7 @@ static void nfp_pci_remove(struct pci_dev *pdev)
kfree(pf->eth_tbl);
kfree(pf->nspi);
mutex_destroy(&pf->lock);
devlink_free(devlink);
devlink_free(priv_to_devlink(pf));
pci_release_regions(pdev);
pci_disable_device(pdev);
}

View File

@ -373,7 +373,9 @@ nfp_net_pf_app_init(struct nfp_pf *pf, u8 __iomem *qc_bar, unsigned int stride)
if (IS_ERR(pf->app))
return PTR_ERR(pf->app);
mutex_lock(&pf->lock);
err = nfp_app_init(pf->app);
mutex_unlock(&pf->lock);
if (err)
goto err_free;
@ -401,7 +403,9 @@ nfp_net_pf_app_init(struct nfp_pf *pf, u8 __iomem *qc_bar, unsigned int stride)
err_unmap:
nfp_cpp_area_release_free(pf->ctrl_vnic_bar);
err_app_clean:
mutex_lock(&pf->lock);
nfp_app_clean(pf->app);
mutex_unlock(&pf->lock);
err_free:
nfp_app_free(pf->app);
pf->app = NULL;
@ -414,7 +418,11 @@ static void nfp_net_pf_app_clean(struct nfp_pf *pf)
nfp_net_pf_free_vnic(pf, pf->ctrl_vnic);
nfp_cpp_area_release_free(pf->ctrl_vnic_bar);
}
mutex_lock(&pf->lock);
nfp_app_clean(pf->app);
mutex_unlock(&pf->lock);
nfp_app_free(pf->app);
pf->app = NULL;
}
@ -693,6 +701,7 @@ int nfp_net_refresh_eth_port(struct nfp_port *port)
*/
int nfp_net_pci_probe(struct nfp_pf *pf)
{
struct devlink *devlink = priv_to_devlink(pf);
struct nfp_net_fw_version fw_ver;
u8 __iomem *ctrl_bar, *qc_bar;
int stride;
@ -706,16 +715,13 @@ int nfp_net_pci_probe(struct nfp_pf *pf)
return -EINVAL;
}
mutex_lock(&pf->lock);
pf->max_data_vnics = nfp_net_pf_get_num_ports(pf);
if ((int)pf->max_data_vnics < 0) {
err = pf->max_data_vnics;
goto err_unlock;
}
if ((int)pf->max_data_vnics < 0)
return pf->max_data_vnics;
err = nfp_net_pci_map_mem(pf);
if (err)
goto err_unlock;
return err;
ctrl_bar = nfp_cpp_area_iomem(pf->data_vnic_bar);
qc_bar = nfp_cpp_area_iomem(pf->qc_area);
@ -754,6 +760,11 @@ int nfp_net_pci_probe(struct nfp_pf *pf)
if (err)
goto err_unmap;
err = devlink_register(devlink, &pf->pdev->dev);
if (err)
goto err_app_clean;
mutex_lock(&pf->lock);
pf->ddir = nfp_net_debugfs_device_add(pf->pdev);
/* Allocate the vnics and do basic init */
@ -785,12 +796,13 @@ int nfp_net_pci_probe(struct nfp_pf *pf)
nfp_net_pf_free_vnics(pf);
err_clean_ddir:
nfp_net_debugfs_dir_clean(&pf->ddir);
mutex_unlock(&pf->lock);
cancel_work_sync(&pf->port_refresh_work);
devlink_unregister(devlink);
err_app_clean:
nfp_net_pf_app_clean(pf);
err_unmap:
nfp_net_pci_unmap_mem(pf);
err_unlock:
mutex_unlock(&pf->lock);
cancel_work_sync(&pf->port_refresh_work);
return err;
}
@ -810,11 +822,13 @@ void nfp_net_pci_remove(struct nfp_pf *pf)
/* stop app first, to avoid double free of ctrl vNIC's ddir */
nfp_net_debugfs_dir_clean(&pf->ddir);
mutex_unlock(&pf->lock);
devlink_unregister(priv_to_devlink(pf));
nfp_net_pf_free_irqs(pf);
nfp_net_pf_app_clean(pf);
nfp_net_pci_unmap_mem(pf);
mutex_unlock(&pf->lock);
cancel_work_sync(&pf->port_refresh_work);
}