196de2506SJakub Kicinski // SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
296de2506SJakub Kicinski /* Copyright (C) 2015-2018 Netronome Systems, Inc. */
32633beb9SJakub Kicinski 
42633beb9SJakub Kicinski /*
52633beb9SJakub Kicinski  * nfp_main.c
62633beb9SJakub Kicinski  * Authors: Jakub Kicinski <jakub.kicinski@netronome.com>
72633beb9SJakub Kicinski  *          Alejandro Lucero <alejandro.lucero@netronome.com>
82633beb9SJakub Kicinski  *          Jason McMullan <jason.mcmullan@netronome.com>
92633beb9SJakub Kicinski  *          Rolf Neugebauer <rolf.neugebauer@netronome.com>
102633beb9SJakub Kicinski  */
112633beb9SJakub Kicinski 
122633beb9SJakub Kicinski #include <linux/kernel.h>
132633beb9SJakub Kicinski #include <linux/module.h>
14346cfe84SJakub Kicinski #include <linux/mutex.h>
152633beb9SJakub Kicinski #include <linux/pci.h>
162633beb9SJakub Kicinski #include <linux/firmware.h>
17d79e19f5SCarl Heymann #include <linux/vmalloc.h>
181851f93fSSimon Horman #include <net/devlink.h>
192633beb9SJakub Kicinski 
2063461a02SJakub Kicinski #include "nfpcore/nfp.h"
2163461a02SJakub Kicinski #include "nfpcore/nfp_cpp.h"
220bc3827fSJakub Kicinski #include "nfpcore/nfp_nffw.h"
23ce22f5a2SJakub Kicinski #include "nfpcore/nfp_nsp.h"
2463461a02SJakub Kicinski 
2563461a02SJakub Kicinski #include "nfpcore/nfp6000_pcie.h"
2663461a02SJakub Kicinski 
270c693323SJakub Kicinski #include "nfp_abi.h"
28758238f2SSimon Horman #include "nfp_app.h"
292633beb9SJakub Kicinski #include "nfp_main.h"
302633beb9SJakub Kicinski #include "nfp_net.h"
312633beb9SJakub Kicinski 
322633beb9SJakub Kicinski static const char nfp_driver_name[] = "nfp";
332633beb9SJakub Kicinski 
3463461a02SJakub Kicinski static const struct pci_device_id nfp_pci_device_ids[] = {
353b473528SSimon Horman 	{ PCI_VENDOR_ID_NETRONOME, PCI_DEVICE_ID_NETRONOME_NFP6000,
3663461a02SJakub Kicinski 	  PCI_VENDOR_ID_NETRONOME, PCI_ANY_ID,
3763461a02SJakub Kicinski 	  PCI_ANY_ID, 0,
3863461a02SJakub Kicinski 	},
390377505cSJakub Kicinski 	{ PCI_VENDOR_ID_NETRONOME, PCI_DEVICE_ID_NETRONOME_NFP5000,
400377505cSJakub Kicinski 	  PCI_VENDOR_ID_NETRONOME, PCI_ANY_ID,
410377505cSJakub Kicinski 	  PCI_ANY_ID, 0,
420377505cSJakub Kicinski 	},
433b473528SSimon Horman 	{ PCI_VENDOR_ID_NETRONOME, PCI_DEVICE_ID_NETRONOME_NFP4000,
4463461a02SJakub Kicinski 	  PCI_VENDOR_ID_NETRONOME, PCI_ANY_ID,
4563461a02SJakub Kicinski 	  PCI_ANY_ID, 0,
4663461a02SJakub Kicinski 	},
4763461a02SJakub Kicinski 	{ 0, } /* Required last entry. */
4863461a02SJakub Kicinski };
4963461a02SJakub Kicinski MODULE_DEVICE_TABLE(pci, nfp_pci_device_ids);
5063461a02SJakub Kicinski 
518f6196f6SJakub Kicinski int nfp_pf_rtsym_read_optional(struct nfp_pf *pf, const char *format,
528f6196f6SJakub Kicinski 			       unsigned int default_val)
538f6196f6SJakub Kicinski {
548f6196f6SJakub Kicinski 	char name[256];
558f6196f6SJakub Kicinski 	int err = 0;
568f6196f6SJakub Kicinski 	u64 val;
578f6196f6SJakub Kicinski 
588f6196f6SJakub Kicinski 	snprintf(name, sizeof(name), format, nfp_cppcore_pcie_unit(pf->cpp));
598f6196f6SJakub Kicinski 
608f6196f6SJakub Kicinski 	val = nfp_rtsym_read_le(pf->rtbl, name, &err);
618f6196f6SJakub Kicinski 	if (err) {
628f6196f6SJakub Kicinski 		if (err == -ENOENT)
638f6196f6SJakub Kicinski 			return default_val;
648f6196f6SJakub Kicinski 		nfp_err(pf->cpp, "Unable to read symbol %s\n", name);
658f6196f6SJakub Kicinski 		return err;
668f6196f6SJakub Kicinski 	}
678f6196f6SJakub Kicinski 
688f6196f6SJakub Kicinski 	return val;
698f6196f6SJakub Kicinski }
708f6196f6SJakub Kicinski 
718f6196f6SJakub Kicinski u8 __iomem *
728f6196f6SJakub Kicinski nfp_pf_map_rtsym(struct nfp_pf *pf, const char *name, const char *sym_fmt,
738f6196f6SJakub Kicinski 		 unsigned int min_size, struct nfp_cpp_area **area)
748f6196f6SJakub Kicinski {
758f6196f6SJakub Kicinski 	char pf_symbol[256];
768f6196f6SJakub Kicinski 
778f6196f6SJakub Kicinski 	snprintf(pf_symbol, sizeof(pf_symbol), sym_fmt,
788f6196f6SJakub Kicinski 		 nfp_cppcore_pcie_unit(pf->cpp));
798f6196f6SJakub Kicinski 
808f6196f6SJakub Kicinski 	return nfp_rtsym_map(pf->rtbl, pf_symbol, name, min_size, area);
818f6196f6SJakub Kicinski }
828f6196f6SJakub Kicinski 
830c693323SJakub Kicinski /* Callers should hold the devlink instance lock */
840c693323SJakub Kicinski int nfp_mbox_cmd(struct nfp_pf *pf, u32 cmd, void *in_data, u64 in_length,
850c693323SJakub Kicinski 		 void *out_data, u64 out_length)
860c693323SJakub Kicinski {
870c693323SJakub Kicinski 	unsigned long err_at;
880c693323SJakub Kicinski 	u64 max_data_sz;
890c693323SJakub Kicinski 	u32 val = 0;
900c693323SJakub Kicinski 	int n, err;
910c693323SJakub Kicinski 
920c693323SJakub Kicinski 	if (!pf->mbox)
930c693323SJakub Kicinski 		return -EOPNOTSUPP;
940c693323SJakub Kicinski 
954152e58cSJakub Kicinski 	max_data_sz = nfp_rtsym_size(pf->mbox) - NFP_MBOX_SYM_MIN_SIZE;
960c693323SJakub Kicinski 
970c693323SJakub Kicinski 	/* Check if cmd field is clear */
981240989cSJakub Kicinski 	err = nfp_rtsym_readl(pf->cpp, pf->mbox, NFP_MBOX_CMD, &val);
990c693323SJakub Kicinski 	if (err || val) {
1000c693323SJakub Kicinski 		nfp_warn(pf->cpp, "failed to issue command (%u): %u, err: %d\n",
1010c693323SJakub Kicinski 			 cmd, val, err);
1020c693323SJakub Kicinski 		return err ?: -EBUSY;
1030c693323SJakub Kicinski 	}
1040c693323SJakub Kicinski 
1050c693323SJakub Kicinski 	in_length = min(in_length, max_data_sz);
1061240989cSJakub Kicinski 	n = nfp_rtsym_write(pf->cpp, pf->mbox, NFP_MBOX_DATA, in_data,
1071240989cSJakub Kicinski 			    in_length);
1080c693323SJakub Kicinski 	if (n != in_length)
1090c693323SJakub Kicinski 		return -EIO;
1100c693323SJakub Kicinski 	/* Write data_len and wipe reserved */
1111240989cSJakub Kicinski 	err = nfp_rtsym_writeq(pf->cpp, pf->mbox, NFP_MBOX_DATA_LEN, in_length);
1120c693323SJakub Kicinski 	if (err)
1130c693323SJakub Kicinski 		return err;
1140c693323SJakub Kicinski 
1150c693323SJakub Kicinski 	/* Read back for ordering */
1161240989cSJakub Kicinski 	err = nfp_rtsym_readl(pf->cpp, pf->mbox, NFP_MBOX_DATA_LEN, &val);
1170c693323SJakub Kicinski 	if (err)
1180c693323SJakub Kicinski 		return err;
1190c693323SJakub Kicinski 
1200c693323SJakub Kicinski 	/* Write cmd and wipe return value */
1211240989cSJakub Kicinski 	err = nfp_rtsym_writeq(pf->cpp, pf->mbox, NFP_MBOX_CMD, cmd);
1220c693323SJakub Kicinski 	if (err)
1230c693323SJakub Kicinski 		return err;
1240c693323SJakub Kicinski 
1250c693323SJakub Kicinski 	err_at = jiffies + 5 * HZ;
1260c693323SJakub Kicinski 	while (true) {
1270c693323SJakub Kicinski 		/* Wait for command to go to 0 (NFP_MBOX_NO_CMD) */
1281240989cSJakub Kicinski 		err = nfp_rtsym_readl(pf->cpp, pf->mbox, NFP_MBOX_CMD, &val);
1290c693323SJakub Kicinski 		if (err)
1300c693323SJakub Kicinski 			return err;
1310c693323SJakub Kicinski 		if (!val)
1320c693323SJakub Kicinski 			break;
1330c693323SJakub Kicinski 
1340c693323SJakub Kicinski 		if (time_is_before_eq_jiffies(err_at))
1350c693323SJakub Kicinski 			return -ETIMEDOUT;
1360c693323SJakub Kicinski 
1370c693323SJakub Kicinski 		msleep(5);
1380c693323SJakub Kicinski 	}
1390c693323SJakub Kicinski 
1400c693323SJakub Kicinski 	/* Copy output if any (could be error info, do it before reading ret) */
1411240989cSJakub Kicinski 	err = nfp_rtsym_readl(pf->cpp, pf->mbox, NFP_MBOX_DATA_LEN, &val);
1420c693323SJakub Kicinski 	if (err)
1430c693323SJakub Kicinski 		return err;
1440c693323SJakub Kicinski 
1450c693323SJakub Kicinski 	out_length = min_t(u32, val, min(out_length, max_data_sz));
1461240989cSJakub Kicinski 	n = nfp_rtsym_read(pf->cpp, pf->mbox, NFP_MBOX_DATA,
1470c693323SJakub Kicinski 			   out_data, out_length);
1480c693323SJakub Kicinski 	if (n != out_length)
1490c693323SJakub Kicinski 		return -EIO;
1500c693323SJakub Kicinski 
1510c693323SJakub Kicinski 	/* Check if there is an error */
1521240989cSJakub Kicinski 	err = nfp_rtsym_readl(pf->cpp, pf->mbox, NFP_MBOX_RET, &val);
1530c693323SJakub Kicinski 	if (err)
1540c693323SJakub Kicinski 		return err;
1550c693323SJakub Kicinski 	if (val)
1560c693323SJakub Kicinski 		return -val;
1570c693323SJakub Kicinski 
1580c693323SJakub Kicinski 	return out_length;
1590c693323SJakub Kicinski }
1600c693323SJakub Kicinski 
1614cbe94f2SJakub Kicinski static bool nfp_board_ready(struct nfp_pf *pf)
1624cbe94f2SJakub Kicinski {
1634cbe94f2SJakub Kicinski 	const char *cp;
1644cbe94f2SJakub Kicinski 	long state;
1654cbe94f2SJakub Kicinski 	int err;
1664cbe94f2SJakub Kicinski 
1674cbe94f2SJakub Kicinski 	cp = nfp_hwinfo_lookup(pf->hwinfo, "board.state");
1684cbe94f2SJakub Kicinski 	if (!cp)
1694cbe94f2SJakub Kicinski 		return false;
1704cbe94f2SJakub Kicinski 
1714cbe94f2SJakub Kicinski 	err = kstrtol(cp, 0, &state);
1724cbe94f2SJakub Kicinski 	if (err < 0)
1734cbe94f2SJakub Kicinski 		return false;
1744cbe94f2SJakub Kicinski 
1754cbe94f2SJakub Kicinski 	return state == 15;
1764cbe94f2SJakub Kicinski }
1774cbe94f2SJakub Kicinski 
1784cbe94f2SJakub Kicinski static int nfp_pf_board_state_wait(struct nfp_pf *pf)
1794cbe94f2SJakub Kicinski {
1804cbe94f2SJakub Kicinski 	const unsigned long wait_until = jiffies + 10 * HZ;
1814cbe94f2SJakub Kicinski 
1824cbe94f2SJakub Kicinski 	while (!nfp_board_ready(pf)) {
1834cbe94f2SJakub Kicinski 		if (time_is_before_eq_jiffies(wait_until)) {
1844cbe94f2SJakub Kicinski 			nfp_err(pf->cpp, "NFP board initialization timeout\n");
1854cbe94f2SJakub Kicinski 			return -EINVAL;
1864cbe94f2SJakub Kicinski 		}
1874cbe94f2SJakub Kicinski 
1884cbe94f2SJakub Kicinski 		nfp_info(pf->cpp, "waiting for board initialization\n");
1894cbe94f2SJakub Kicinski 		if (msleep_interruptible(500))
1904cbe94f2SJakub Kicinski 			return -ERESTARTSYS;
1914cbe94f2SJakub Kicinski 
1924cbe94f2SJakub Kicinski 		/* Refresh cached information */
1934cbe94f2SJakub Kicinski 		kfree(pf->hwinfo);
1944cbe94f2SJakub Kicinski 		pf->hwinfo = nfp_hwinfo_read(pf->cpp);
1954cbe94f2SJakub Kicinski 	}
1964cbe94f2SJakub Kicinski 
1974cbe94f2SJakub Kicinski 	return 0;
1984cbe94f2SJakub Kicinski }
1994cbe94f2SJakub Kicinski 
200651e1f2fSJakub Kicinski static int nfp_pcie_sriov_read_nfd_limit(struct nfp_pf *pf)
2010bc3827fSJakub Kicinski {
2020bc3827fSJakub Kicinski 	int err;
2030bc3827fSJakub Kicinski 
204af4fa7eaSJakub Kicinski 	pf->limit_vfs = nfp_rtsym_read_le(pf->rtbl, "nfd_vf_cfg_max_vfs", &err);
2055b0ced17SJakub Kicinski 	if (err) {
2065b0ced17SJakub Kicinski 		/* For backwards compatibility if symbol not found allow all */
2070bc3827fSJakub Kicinski 		pf->limit_vfs = ~0;
208651e1f2fSJakub Kicinski 		if (err == -ENOENT)
209651e1f2fSJakub Kicinski 			return 0;
210651e1f2fSJakub Kicinski 
2110bc3827fSJakub Kicinski 		nfp_warn(pf->cpp, "Warning: VF limit read failed: %d\n", err);
212651e1f2fSJakub Kicinski 		return err;
2130bc3827fSJakub Kicinski 	}
2140bc3827fSJakub Kicinski 
2155b0ced17SJakub Kicinski 	err = pci_sriov_set_totalvfs(pf->pdev, pf->limit_vfs);
2165b0ced17SJakub Kicinski 	if (err)
2175b0ced17SJakub Kicinski 		nfp_warn(pf->cpp, "Failed to set VF count in sysfs: %d\n", err);
2185b0ced17SJakub Kicinski 	return 0;
2195b0ced17SJakub Kicinski }
2205b0ced17SJakub Kicinski 
22163461a02SJakub Kicinski static int nfp_pcie_sriov_enable(struct pci_dev *pdev, int num_vfs)
22263461a02SJakub Kicinski {
22363461a02SJakub Kicinski #ifdef CONFIG_PCI_IOV
22463461a02SJakub Kicinski 	struct nfp_pf *pf = pci_get_drvdata(pdev);
22563461a02SJakub Kicinski 	int err;
22663461a02SJakub Kicinski 
2270bc3827fSJakub Kicinski 	if (num_vfs > pf->limit_vfs) {
2280bc3827fSJakub Kicinski 		nfp_info(pf->cpp, "Firmware limits number of VFs to %u\n",
2290bc3827fSJakub Kicinski 			 pf->limit_vfs);
230d6e1ab9eSJakub Kicinski 		return -EINVAL;
231758238f2SSimon Horman 	}
232758238f2SSimon Horman 
233e3f28473SJakub Kicinski 	err = pci_enable_sriov(pdev, num_vfs);
234758238f2SSimon Horman 	if (err) {
235e3f28473SJakub Kicinski 		dev_warn(&pdev->dev, "Failed to enable PCI SR-IOV: %d\n", err);
236d6e1ab9eSJakub Kicinski 		return err;
2370bc3827fSJakub Kicinski 	}
2380bc3827fSJakub Kicinski 
239d6e1ab9eSJakub Kicinski 	mutex_lock(&pf->lock);
240d6e1ab9eSJakub Kicinski 
241e3f28473SJakub Kicinski 	err = nfp_app_sriov_enable(pf->app, num_vfs);
24263461a02SJakub Kicinski 	if (err) {
243e3f28473SJakub Kicinski 		dev_warn(&pdev->dev,
244e3f28473SJakub Kicinski 			 "App specific PCI SR-IOV configuration failed: %d\n",
245e3f28473SJakub Kicinski 			 err);
246e3f28473SJakub Kicinski 		goto err_sriov_disable;
24763461a02SJakub Kicinski 	}
24863461a02SJakub Kicinski 
24963461a02SJakub Kicinski 	pf->num_vfs = num_vfs;
25063461a02SJakub Kicinski 
25163461a02SJakub Kicinski 	dev_dbg(&pdev->dev, "Created %d VFs.\n", pf->num_vfs);
25263461a02SJakub Kicinski 
253758238f2SSimon Horman 	mutex_unlock(&pf->lock);
25463461a02SJakub Kicinski 	return num_vfs;
255758238f2SSimon Horman 
256e3f28473SJakub Kicinski err_sriov_disable:
257758238f2SSimon Horman 	mutex_unlock(&pf->lock);
258d6e1ab9eSJakub Kicinski 	pci_disable_sriov(pdev);
259758238f2SSimon Horman 	return err;
26063461a02SJakub Kicinski #endif
26163461a02SJakub Kicinski 	return 0;
26263461a02SJakub Kicinski }
26363461a02SJakub Kicinski 
264e3f28473SJakub Kicinski static int nfp_pcie_sriov_disable(struct pci_dev *pdev)
26563461a02SJakub Kicinski {
26663461a02SJakub Kicinski #ifdef CONFIG_PCI_IOV
26763461a02SJakub Kicinski 	struct nfp_pf *pf = pci_get_drvdata(pdev);
26863461a02SJakub Kicinski 
269e3f28473SJakub Kicinski 	mutex_lock(&pf->lock);
270e3f28473SJakub Kicinski 
27163461a02SJakub Kicinski 	/* If the VFs are assigned we cannot shut down SR-IOV without
27263461a02SJakub Kicinski 	 * causing issues, so just leave the hardware available but
27363461a02SJakub Kicinski 	 * disabled
27463461a02SJakub Kicinski 	 */
27563461a02SJakub Kicinski 	if (pci_vfs_assigned(pdev)) {
27663461a02SJakub Kicinski 		dev_warn(&pdev->dev, "Disabling while VFs assigned - VFs will not be deallocated\n");
277e3f28473SJakub Kicinski 		mutex_unlock(&pf->lock);
27863461a02SJakub Kicinski 		return -EPERM;
27963461a02SJakub Kicinski 	}
28063461a02SJakub Kicinski 
281758238f2SSimon Horman 	nfp_app_sriov_disable(pf->app);
282758238f2SSimon Horman 
28363461a02SJakub Kicinski 	pf->num_vfs = 0;
28463461a02SJakub Kicinski 
285d6e1ab9eSJakub Kicinski 	mutex_unlock(&pf->lock);
286d6e1ab9eSJakub Kicinski 
28763461a02SJakub Kicinski 	pci_disable_sriov(pdev);
28863461a02SJakub Kicinski 	dev_dbg(&pdev->dev, "Removed VFs.\n");
28963461a02SJakub Kicinski #endif
29063461a02SJakub Kicinski 	return 0;
29163461a02SJakub Kicinski }
29263461a02SJakub Kicinski 
29363461a02SJakub Kicinski static int nfp_pcie_sriov_configure(struct pci_dev *pdev, int num_vfs)
29463461a02SJakub Kicinski {
295790d23e7SDirk van der Merwe 	if (!pci_get_drvdata(pdev))
296790d23e7SDirk van der Merwe 		return -ENOENT;
297790d23e7SDirk van der Merwe 
29863461a02SJakub Kicinski 	if (num_vfs == 0)
29963461a02SJakub Kicinski 		return nfp_pcie_sriov_disable(pdev);
30063461a02SJakub Kicinski 	else
30163461a02SJakub Kicinski 		return nfp_pcie_sriov_enable(pdev, num_vfs);
30263461a02SJakub Kicinski }
30363461a02SJakub Kicinski 
3045c5696f3SJakub Kicinski int nfp_flash_update_common(struct nfp_pf *pf, const char *path,
3055c5696f3SJakub Kicinski 			    struct netlink_ext_ack *extack)
3065c5696f3SJakub Kicinski {
3075c5696f3SJakub Kicinski 	struct device *dev = &pf->pdev->dev;
3085c5696f3SJakub Kicinski 	const struct firmware *fw;
3095c5696f3SJakub Kicinski 	struct nfp_nsp *nsp;
3105c5696f3SJakub Kicinski 	int err;
3115c5696f3SJakub Kicinski 
3125c5696f3SJakub Kicinski 	nsp = nfp_nsp_open(pf->cpp);
3135c5696f3SJakub Kicinski 	if (IS_ERR(nsp)) {
3145c5696f3SJakub Kicinski 		err = PTR_ERR(nsp);
3155c5696f3SJakub Kicinski 		if (extack)
3165c5696f3SJakub Kicinski 			NL_SET_ERR_MSG_MOD(extack, "can't access NSP");
3175c5696f3SJakub Kicinski 		else
3185c5696f3SJakub Kicinski 			dev_err(dev, "Failed to access the NSP: %d\n", err);
3195c5696f3SJakub Kicinski 		return err;
3205c5696f3SJakub Kicinski 	}
3215c5696f3SJakub Kicinski 
3225c5696f3SJakub Kicinski 	err = request_firmware_direct(&fw, path, dev);
3235c5696f3SJakub Kicinski 	if (err) {
3245c5696f3SJakub Kicinski 		NL_SET_ERR_MSG_MOD(extack,
3255c5696f3SJakub Kicinski 				   "unable to read flash file from disk");
3265c5696f3SJakub Kicinski 		goto exit_close_nsp;
3275c5696f3SJakub Kicinski 	}
3285c5696f3SJakub Kicinski 
3295c5696f3SJakub Kicinski 	dev_info(dev, "Please be patient while writing flash image: %s\n",
3305c5696f3SJakub Kicinski 		 path);
3315c5696f3SJakub Kicinski 
3325c5696f3SJakub Kicinski 	err = nfp_nsp_write_flash(nsp, fw);
3335c5696f3SJakub Kicinski 	if (err < 0)
3345c5696f3SJakub Kicinski 		goto exit_release_fw;
3355c5696f3SJakub Kicinski 	dev_info(dev, "Finished writing flash image\n");
3365c5696f3SJakub Kicinski 	err = 0;
3375c5696f3SJakub Kicinski 
3385c5696f3SJakub Kicinski exit_release_fw:
3395c5696f3SJakub Kicinski 	release_firmware(fw);
3405c5696f3SJakub Kicinski exit_close_nsp:
3415c5696f3SJakub Kicinski 	nfp_nsp_close(nsp);
3425c5696f3SJakub Kicinski 	return err;
3435c5696f3SJakub Kicinski }
3445c5696f3SJakub Kicinski 
3451680a370SJakub Kicinski static const struct firmware *
3461680a370SJakub Kicinski nfp_net_fw_request(struct pci_dev *pdev, struct nfp_pf *pf, const char *name)
3471680a370SJakub Kicinski {
3481680a370SJakub Kicinski 	const struct firmware *fw = NULL;
3491680a370SJakub Kicinski 	int err;
3501680a370SJakub Kicinski 
3511680a370SJakub Kicinski 	err = request_firmware_direct(&fw, name, &pdev->dev);
3521680a370SJakub Kicinski 	nfp_info(pf->cpp, "  %s: %s\n",
353f8921d73SDirk van der Merwe 		 name, err ? "not found" : "found");
3541680a370SJakub Kicinski 	if (err)
3551680a370SJakub Kicinski 		return NULL;
3561680a370SJakub Kicinski 
3571680a370SJakub Kicinski 	return fw;
3581680a370SJakub Kicinski }
3591680a370SJakub Kicinski 
36063461a02SJakub Kicinski /**
36163461a02SJakub Kicinski  * nfp_net_fw_find() - Find the correct firmware image for netdev mode
36263461a02SJakub Kicinski  * @pdev:	PCI Device structure
36363461a02SJakub Kicinski  * @pf:		NFP PF Device structure
36463461a02SJakub Kicinski  *
36563461a02SJakub Kicinski  * Return: firmware if found and requested successfully.
36663461a02SJakub Kicinski  */
36763461a02SJakub Kicinski static const struct firmware *
36863461a02SJakub Kicinski nfp_net_fw_find(struct pci_dev *pdev, struct nfp_pf *pf)
36963461a02SJakub Kicinski {
37063461a02SJakub Kicinski 	struct nfp_eth_table_port *port;
3711680a370SJakub Kicinski 	const struct firmware *fw;
37263461a02SJakub Kicinski 	const char *fw_model;
37363461a02SJakub Kicinski 	char fw_name[256];
3749511f298SJakub Kicinski 	const u8 *serial;
3759511f298SJakub Kicinski 	u16 interface;
3761680a370SJakub Kicinski 	int spc, i, j;
3771680a370SJakub Kicinski 
3781680a370SJakub Kicinski 	nfp_info(pf->cpp, "Looking for firmware file in order of priority:\n");
37963461a02SJakub Kicinski 
3809511f298SJakub Kicinski 	/* First try to find a firmware image specific for this device */
3819511f298SJakub Kicinski 	interface = nfp_cpp_interface(pf->cpp);
3829511f298SJakub Kicinski 	nfp_cpp_serial(pf->cpp, &serial);
3839511f298SJakub Kicinski 	sprintf(fw_name, "netronome/serial-%pMF-%02hhx-%02hhx.nffw",
3849511f298SJakub Kicinski 		serial, interface >> 8, interface & 0xff);
3851680a370SJakub Kicinski 	fw = nfp_net_fw_request(pdev, pf, fw_name);
3861680a370SJakub Kicinski 	if (fw)
3871680a370SJakub Kicinski 		return fw;
3889511f298SJakub Kicinski 
3899511f298SJakub Kicinski 	/* Then try the PCI name */
3909511f298SJakub Kicinski 	sprintf(fw_name, "netronome/pci-%s.nffw", pci_name(pdev));
3911680a370SJakub Kicinski 	fw = nfp_net_fw_request(pdev, pf, fw_name);
3921680a370SJakub Kicinski 	if (fw)
3931680a370SJakub Kicinski 		return fw;
3949511f298SJakub Kicinski 
3959511f298SJakub Kicinski 	/* Finally try the card type and media */
39663461a02SJakub Kicinski 	if (!pf->eth_tbl) {
39763461a02SJakub Kicinski 		dev_err(&pdev->dev, "Error: can't identify media config\n");
39863461a02SJakub Kicinski 		return NULL;
39963461a02SJakub Kicinski 	}
40063461a02SJakub Kicinski 
4019baa4885SJakub Kicinski 	fw_model = nfp_hwinfo_lookup(pf->hwinfo, "assembly.partno");
40263461a02SJakub Kicinski 	if (!fw_model) {
40363461a02SJakub Kicinski 		dev_err(&pdev->dev, "Error: can't read part number\n");
40463461a02SJakub Kicinski 		return NULL;
40563461a02SJakub Kicinski 	}
40663461a02SJakub Kicinski 
40763461a02SJakub Kicinski 	spc = ARRAY_SIZE(fw_name);
40863461a02SJakub Kicinski 	spc -= snprintf(fw_name, spc, "netronome/nic_%s", fw_model);
40963461a02SJakub Kicinski 
41063461a02SJakub Kicinski 	for (i = 0; spc > 0 && i < pf->eth_tbl->count; i += j) {
41163461a02SJakub Kicinski 		port = &pf->eth_tbl->ports[i];
41263461a02SJakub Kicinski 		j = 1;
41363461a02SJakub Kicinski 		while (i + j < pf->eth_tbl->count &&
41463461a02SJakub Kicinski 		       port->speed == port[j].speed)
41563461a02SJakub Kicinski 			j++;
41663461a02SJakub Kicinski 
41763461a02SJakub Kicinski 		spc -= snprintf(&fw_name[ARRAY_SIZE(fw_name) - spc], spc,
41863461a02SJakub Kicinski 				"_%dx%d", j, port->speed / 1000);
41963461a02SJakub Kicinski 	}
42063461a02SJakub Kicinski 
42163461a02SJakub Kicinski 	if (spc <= 0)
42263461a02SJakub Kicinski 		return NULL;
42363461a02SJakub Kicinski 
42463461a02SJakub Kicinski 	spc -= snprintf(&fw_name[ARRAY_SIZE(fw_name) - spc], spc, ".nffw");
42563461a02SJakub Kicinski 	if (spc <= 0)
42663461a02SJakub Kicinski 		return NULL;
42763461a02SJakub Kicinski 
4281680a370SJakub Kicinski 	return nfp_net_fw_request(pdev, pf, fw_name);
42963461a02SJakub Kicinski }
43063461a02SJakub Kicinski 
431f8921d73SDirk van der Merwe static int
432f8921d73SDirk van der Merwe nfp_get_fw_policy_value(struct pci_dev *pdev, struct nfp_nsp *nsp,
433f8921d73SDirk van der Merwe 			const char *key, const char *default_val, int max_val,
434f8921d73SDirk van der Merwe 			int *value)
435f8921d73SDirk van der Merwe {
436f8921d73SDirk van der Merwe 	char hwinfo[64];
437f8921d73SDirk van der Merwe 	long hi_val;
438f8921d73SDirk van der Merwe 	int err;
439f8921d73SDirk van der Merwe 
440f8921d73SDirk van der Merwe 	snprintf(hwinfo, sizeof(hwinfo), key);
441f8921d73SDirk van der Merwe 	err = nfp_nsp_hwinfo_lookup_optional(nsp, hwinfo, sizeof(hwinfo),
442f8921d73SDirk van der Merwe 					     default_val);
443f8921d73SDirk van der Merwe 	if (err)
444f8921d73SDirk van der Merwe 		return err;
445f8921d73SDirk van der Merwe 
446f8921d73SDirk van der Merwe 	err = kstrtol(hwinfo, 0, &hi_val);
447f8921d73SDirk van der Merwe 	if (err || hi_val < 0 || hi_val > max_val) {
448f8921d73SDirk van der Merwe 		dev_warn(&pdev->dev,
449f8921d73SDirk van der Merwe 			 "Invalid value '%s' from '%s', ignoring\n",
450f8921d73SDirk van der Merwe 			 hwinfo, key);
451f8921d73SDirk van der Merwe 		err = kstrtol(default_val, 0, &hi_val);
452f8921d73SDirk van der Merwe 	}
453f8921d73SDirk van der Merwe 
454f8921d73SDirk van der Merwe 	*value = hi_val;
455f8921d73SDirk van der Merwe 	return err;
456f8921d73SDirk van der Merwe }
457f8921d73SDirk van der Merwe 
45863461a02SJakub Kicinski /**
4598fb822ceSDirk van der Merwe  * nfp_fw_load() - Load the firmware image
46063461a02SJakub Kicinski  * @pdev:       PCI Device structure
46163461a02SJakub Kicinski  * @pf:		NFP PF Device structure
46263461a02SJakub Kicinski  * @nsp:	NFP SP handle
46363461a02SJakub Kicinski  *
46463461a02SJakub Kicinski  * Return: -ERRNO, 0 for no firmware loaded, 1 for firmware loaded
46563461a02SJakub Kicinski  */
46663461a02SJakub Kicinski static int
46763461a02SJakub Kicinski nfp_fw_load(struct pci_dev *pdev, struct nfp_pf *pf, struct nfp_nsp *nsp)
46863461a02SJakub Kicinski {
469f8921d73SDirk van der Merwe 	bool do_reset, fw_loaded = false;
470f8921d73SDirk van der Merwe 	const struct firmware *fw = NULL;
471f8921d73SDirk van der Merwe 	int err, reset, policy, ifcs = 0;
472f8921d73SDirk van der Merwe 	char *token, *ptr;
473f8921d73SDirk van der Merwe 	char hwinfo[64];
47463461a02SJakub Kicinski 	u16 interface;
475f8921d73SDirk van der Merwe 
476f8921d73SDirk van der Merwe 	snprintf(hwinfo, sizeof(hwinfo), "abi_drv_load_ifc");
477f8921d73SDirk van der Merwe 	err = nfp_nsp_hwinfo_lookup_optional(nsp, hwinfo, sizeof(hwinfo),
478f8921d73SDirk van der Merwe 					     NFP_NSP_DRV_LOAD_IFC_DEFAULT);
479f8921d73SDirk van der Merwe 	if (err)
480f8921d73SDirk van der Merwe 		return err;
48163461a02SJakub Kicinski 
48263461a02SJakub Kicinski 	interface = nfp_cpp_interface(pf->cpp);
483f8921d73SDirk van der Merwe 	ptr = hwinfo;
484f8921d73SDirk van der Merwe 	while ((token = strsep(&ptr, ","))) {
485f8921d73SDirk van der Merwe 		unsigned long interface_hi;
486f8921d73SDirk van der Merwe 
487f8921d73SDirk van der Merwe 		err = kstrtoul(token, 0, &interface_hi);
488f8921d73SDirk van der Merwe 		if (err) {
489f8921d73SDirk van der Merwe 			dev_err(&pdev->dev,
490f8921d73SDirk van der Merwe 				"Failed to parse interface '%s': %d\n",
491f8921d73SDirk van der Merwe 				token, err);
492f8921d73SDirk van der Merwe 			return err;
493f8921d73SDirk van der Merwe 		}
494f8921d73SDirk van der Merwe 
495f8921d73SDirk van der Merwe 		ifcs++;
496f8921d73SDirk van der Merwe 		if (interface == interface_hi)
497f8921d73SDirk van der Merwe 			break;
498f8921d73SDirk van der Merwe 	}
499f8921d73SDirk van der Merwe 
500f8921d73SDirk van der Merwe 	if (!token) {
50163461a02SJakub Kicinski 		dev_info(&pdev->dev, "Firmware will be loaded by partner\n");
50263461a02SJakub Kicinski 		return 0;
50363461a02SJakub Kicinski 	}
50463461a02SJakub Kicinski 
505f8921d73SDirk van der Merwe 	err = nfp_get_fw_policy_value(pdev, nsp, "abi_drv_reset",
506f8921d73SDirk van der Merwe 				      NFP_NSP_DRV_RESET_DEFAULT,
507f8921d73SDirk van der Merwe 				      NFP_NSP_DRV_RESET_NEVER, &reset);
508f8921d73SDirk van der Merwe 	if (err)
509f8921d73SDirk van der Merwe 		return err;
51063461a02SJakub Kicinski 
511f8921d73SDirk van der Merwe 	err = nfp_get_fw_policy_value(pdev, nsp, "app_fw_from_flash",
512f8921d73SDirk van der Merwe 				      NFP_NSP_APP_FW_LOAD_DEFAULT,
513f8921d73SDirk van der Merwe 				      NFP_NSP_APP_FW_LOAD_PREF, &policy);
514f8921d73SDirk van der Merwe 	if (err)
515f8921d73SDirk van der Merwe 		return err;
516f8921d73SDirk van der Merwe 
517f8921d73SDirk van der Merwe 	fw = nfp_net_fw_find(pdev, pf);
518f8921d73SDirk van der Merwe 	do_reset = reset == NFP_NSP_DRV_RESET_ALWAYS ||
519f8921d73SDirk van der Merwe 		   (fw && reset == NFP_NSP_DRV_RESET_DISK);
520f8921d73SDirk van der Merwe 
521f8921d73SDirk van der Merwe 	if (do_reset) {
522f8921d73SDirk van der Merwe 		dev_info(&pdev->dev, "Soft-resetting the NFP\n");
52363461a02SJakub Kicinski 		err = nfp_nsp_device_soft_reset(nsp);
52463461a02SJakub Kicinski 		if (err < 0) {
525f8921d73SDirk van der Merwe 			dev_err(&pdev->dev,
526f8921d73SDirk van der Merwe 				"Failed to soft reset the NFP: %d\n", err);
52763461a02SJakub Kicinski 			goto exit_release_fw;
52863461a02SJakub Kicinski 		}
529f8921d73SDirk van der Merwe 	}
530f8921d73SDirk van der Merwe 
531f8921d73SDirk van der Merwe 	if (fw && policy != NFP_NSP_APP_FW_LOAD_FLASH) {
532f8921d73SDirk van der Merwe 		if (nfp_nsp_has_fw_loaded(nsp) && nfp_nsp_fw_loaded(nsp))
533f8921d73SDirk van der Merwe 			goto exit_release_fw;
53463461a02SJakub Kicinski 
53563461a02SJakub Kicinski 		err = nfp_nsp_load_fw(nsp, fw);
53663461a02SJakub Kicinski 		if (err < 0) {
537f8921d73SDirk van der Merwe 			dev_err(&pdev->dev, "FW loading failed: %d\n",
538f8921d73SDirk van der Merwe 				err);
53963461a02SJakub Kicinski 			goto exit_release_fw;
54063461a02SJakub Kicinski 		}
54163461a02SJakub Kicinski 		dev_info(&pdev->dev, "Finished loading FW image\n");
542f8921d73SDirk van der Merwe 		fw_loaded = true;
543f8921d73SDirk van der Merwe 	} else if (policy != NFP_NSP_APP_FW_LOAD_DISK &&
544f8921d73SDirk van der Merwe 		   nfp_nsp_has_stored_fw_load(nsp)) {
545f8921d73SDirk van der Merwe 
546f8921d73SDirk van der Merwe 		/* Don't propagate this error to stick with legacy driver
547f8921d73SDirk van der Merwe 		 * behavior, failure will be detected later during init.
548f8921d73SDirk van der Merwe 		 */
549f8921d73SDirk van der Merwe 		if (!nfp_nsp_load_stored_fw(nsp))
550f8921d73SDirk van der Merwe 			dev_info(&pdev->dev, "Finished loading stored FW image\n");
551f8921d73SDirk van der Merwe 
552f8921d73SDirk van der Merwe 		/* Don't flag the fw_loaded in this case since other devices
553f8921d73SDirk van der Merwe 		 * may reuse the firmware when configured this way
554f8921d73SDirk van der Merwe 		 */
555f8921d73SDirk van der Merwe 	} else {
556f8921d73SDirk van der Merwe 		dev_warn(&pdev->dev, "Didn't load firmware, please update flash or reconfigure card\n");
557f8921d73SDirk van der Merwe 	}
55863461a02SJakub Kicinski 
55963461a02SJakub Kicinski exit_release_fw:
56063461a02SJakub Kicinski 	release_firmware(fw);
56163461a02SJakub Kicinski 
562f8921d73SDirk van der Merwe 	/* We don't want to unload firmware when other devices may still be
563f8921d73SDirk van der Merwe 	 * dependent on it, which could be the case if there are multiple
564f8921d73SDirk van der Merwe 	 * devices that could load firmware.
565f8921d73SDirk van der Merwe 	 */
566f8921d73SDirk van der Merwe 	if (fw_loaded && ifcs == 1)
567f8921d73SDirk van der Merwe 		pf->unload_fw_on_remove = true;
568f8921d73SDirk van der Merwe 
569f8921d73SDirk van der Merwe 	return err < 0 ? err : fw_loaded;
57063461a02SJakub Kicinski }
57163461a02SJakub Kicinski 
5727717c319SJakub Kicinski static void
5737717c319SJakub Kicinski nfp_nsp_init_ports(struct pci_dev *pdev, struct nfp_pf *pf,
5747717c319SJakub Kicinski 		   struct nfp_nsp *nsp)
5757717c319SJakub Kicinski {
5767717c319SJakub Kicinski 	bool needs_reinit = false;
5777717c319SJakub Kicinski 	int i;
5787717c319SJakub Kicinski 
5797717c319SJakub Kicinski 	pf->eth_tbl = __nfp_eth_read_ports(pf->cpp, nsp);
5807717c319SJakub Kicinski 	if (!pf->eth_tbl)
5817717c319SJakub Kicinski 		return;
5827717c319SJakub Kicinski 
5837717c319SJakub Kicinski 	if (!nfp_nsp_has_mac_reinit(nsp))
5847717c319SJakub Kicinski 		return;
5857717c319SJakub Kicinski 
5867717c319SJakub Kicinski 	for (i = 0; i < pf->eth_tbl->count; i++)
5877717c319SJakub Kicinski 		needs_reinit |= pf->eth_tbl->ports[i].override_changed;
5887717c319SJakub Kicinski 	if (!needs_reinit)
5897717c319SJakub Kicinski 		return;
5907717c319SJakub Kicinski 
5917717c319SJakub Kicinski 	kfree(pf->eth_tbl);
5927717c319SJakub Kicinski 	if (nfp_nsp_mac_reinit(nsp))
5937717c319SJakub Kicinski 		dev_warn(&pdev->dev, "MAC reinit failed\n");
5947717c319SJakub Kicinski 
5957717c319SJakub Kicinski 	pf->eth_tbl = __nfp_eth_read_ports(pf->cpp, nsp);
5967717c319SJakub Kicinski }
5977717c319SJakub Kicinski 
598a9c83f7bSJakub Kicinski static int nfp_nsp_init(struct pci_dev *pdev, struct nfp_pf *pf)
599a9c83f7bSJakub Kicinski {
600a9c83f7bSJakub Kicinski 	struct nfp_nsp *nsp;
601a9c83f7bSJakub Kicinski 	int err;
602a9c83f7bSJakub Kicinski 
6037dbd5b75SJakub Kicinski 	err = nfp_resource_wait(pf->cpp, NFP_RESOURCE_NSP, 30);
6047dbd5b75SJakub Kicinski 	if (err)
6057dbd5b75SJakub Kicinski 		return err;
6067dbd5b75SJakub Kicinski 
607a9c83f7bSJakub Kicinski 	nsp = nfp_nsp_open(pf->cpp);
608a9c83f7bSJakub Kicinski 	if (IS_ERR(nsp)) {
609a9c83f7bSJakub Kicinski 		err = PTR_ERR(nsp);
610a9c83f7bSJakub Kicinski 		dev_err(&pdev->dev, "Failed to access the NSP: %d\n", err);
611a9c83f7bSJakub Kicinski 		return err;
612a9c83f7bSJakub Kicinski 	}
613a9c83f7bSJakub Kicinski 
614a9c83f7bSJakub Kicinski 	err = nfp_nsp_wait(nsp);
615a9c83f7bSJakub Kicinski 	if (err < 0)
616a9c83f7bSJakub Kicinski 		goto exit_close_nsp;
617a9c83f7bSJakub Kicinski 
6187717c319SJakub Kicinski 	nfp_nsp_init_ports(pdev, pf, nsp);
619a9c83f7bSJakub Kicinski 
620eefbde7eSDavid Brunecz 	pf->nspi = __nfp_nsp_identify(nsp);
621eefbde7eSDavid Brunecz 	if (pf->nspi)
622eefbde7eSDavid Brunecz 		dev_info(&pdev->dev, "BSP: %s\n", pf->nspi->version);
623010e2f9cSDavid Brunecz 
624a9c83f7bSJakub Kicinski 	err = nfp_fw_load(pdev, pf, nsp);
625a9c83f7bSJakub Kicinski 	if (err < 0) {
62647eaa23bSJakub Kicinski 		kfree(pf->nspi);
627a9c83f7bSJakub Kicinski 		kfree(pf->eth_tbl);
628a9c83f7bSJakub Kicinski 		dev_err(&pdev->dev, "Failed to load FW\n");
629a9c83f7bSJakub Kicinski 		goto exit_close_nsp;
630a9c83f7bSJakub Kicinski 	}
631a9c83f7bSJakub Kicinski 
632a9c83f7bSJakub Kicinski 	pf->fw_loaded = !!err;
633a9c83f7bSJakub Kicinski 	err = 0;
634a9c83f7bSJakub Kicinski 
635a9c83f7bSJakub Kicinski exit_close_nsp:
636a9c83f7bSJakub Kicinski 	nfp_nsp_close(nsp);
637a9c83f7bSJakub Kicinski 
638a9c83f7bSJakub Kicinski 	return err;
639a9c83f7bSJakub Kicinski }
640a9c83f7bSJakub Kicinski 
64163461a02SJakub Kicinski static void nfp_fw_unload(struct nfp_pf *pf)
64263461a02SJakub Kicinski {
64363461a02SJakub Kicinski 	struct nfp_nsp *nsp;
64463461a02SJakub Kicinski 	int err;
64563461a02SJakub Kicinski 
64663461a02SJakub Kicinski 	nsp = nfp_nsp_open(pf->cpp);
64763461a02SJakub Kicinski 	if (IS_ERR(nsp)) {
64863461a02SJakub Kicinski 		nfp_err(pf->cpp, "Reset failed, can't open NSP\n");
64963461a02SJakub Kicinski 		return;
65063461a02SJakub Kicinski 	}
65163461a02SJakub Kicinski 
65263461a02SJakub Kicinski 	err = nfp_nsp_device_soft_reset(nsp);
65363461a02SJakub Kicinski 	if (err < 0)
65463461a02SJakub Kicinski 		dev_warn(&pf->pdev->dev, "Couldn't unload firmware: %d\n", err);
65563461a02SJakub Kicinski 	else
65663461a02SJakub Kicinski 		dev_info(&pf->pdev->dev, "Firmware safely unloaded\n");
65763461a02SJakub Kicinski 
65863461a02SJakub Kicinski 	nfp_nsp_close(nsp);
65963461a02SJakub Kicinski }
66063461a02SJakub Kicinski 
6610c693323SJakub Kicinski static int nfp_pf_find_rtsyms(struct nfp_pf *pf)
6620c693323SJakub Kicinski {
6630c693323SJakub Kicinski 	char pf_symbol[256];
6640c693323SJakub Kicinski 	unsigned int pf_id;
6650c693323SJakub Kicinski 
6660c693323SJakub Kicinski 	pf_id = nfp_cppcore_pcie_unit(pf->cpp);
6670c693323SJakub Kicinski 
6680c693323SJakub Kicinski 	/* Optional per-PCI PF mailbox */
6690c693323SJakub Kicinski 	snprintf(pf_symbol, sizeof(pf_symbol), NFP_MBOX_SYM_NAME, pf_id);
6700c693323SJakub Kicinski 	pf->mbox = nfp_rtsym_lookup(pf->rtbl, pf_symbol);
6714152e58cSJakub Kicinski 	if (pf->mbox && nfp_rtsym_size(pf->mbox) < NFP_MBOX_SYM_MIN_SIZE) {
6720c693323SJakub Kicinski 		nfp_err(pf->cpp, "PF mailbox symbol too small: %llu < %d\n",
6734152e58cSJakub Kicinski 			nfp_rtsym_size(pf->mbox), NFP_MBOX_SYM_MIN_SIZE);
6740c693323SJakub Kicinski 		return -EINVAL;
6750c693323SJakub Kicinski 	}
6760c693323SJakub Kicinski 
6770c693323SJakub Kicinski 	return 0;
6780c693323SJakub Kicinski }
6790c693323SJakub Kicinski 
68063461a02SJakub Kicinski static int nfp_pci_probe(struct pci_dev *pdev,
68163461a02SJakub Kicinski 			 const struct pci_device_id *pci_id)
68263461a02SJakub Kicinski {
6831851f93fSSimon Horman 	struct devlink *devlink;
68463461a02SJakub Kicinski 	struct nfp_pf *pf;
68563461a02SJakub Kicinski 	int err;
68663461a02SJakub Kicinski 
687f767fc66SJakub Kicinski 	if (pdev->vendor == PCI_VENDOR_ID_NETRONOME &&
688f767fc66SJakub Kicinski 	    pdev->device == PCI_DEVICE_ID_NETRONOME_NFP6000_VF)
689f767fc66SJakub Kicinski 		dev_warn(&pdev->dev, "Binding NFP VF device to the NFP PF driver, the VF driver is called 'nfp_netvf'\n");
690f767fc66SJakub Kicinski 
69163461a02SJakub Kicinski 	err = pci_enable_device(pdev);
69263461a02SJakub Kicinski 	if (err < 0)
69363461a02SJakub Kicinski 		return err;
69463461a02SJakub Kicinski 
69563461a02SJakub Kicinski 	pci_set_master(pdev);
69663461a02SJakub Kicinski 
69763461a02SJakub Kicinski 	err = dma_set_mask_and_coherent(&pdev->dev,
69863461a02SJakub Kicinski 					DMA_BIT_MASK(NFP_NET_MAX_DMA_BITS));
69963461a02SJakub Kicinski 	if (err)
70063461a02SJakub Kicinski 		goto err_pci_disable;
70163461a02SJakub Kicinski 
70263461a02SJakub Kicinski 	err = pci_request_regions(pdev, nfp_driver_name);
70363461a02SJakub Kicinski 	if (err < 0) {
70463461a02SJakub Kicinski 		dev_err(&pdev->dev, "Unable to reserve pci resources.\n");
70563461a02SJakub Kicinski 		goto err_pci_disable;
70663461a02SJakub Kicinski 	}
70763461a02SJakub Kicinski 
7081851f93fSSimon Horman 	devlink = devlink_alloc(&nfp_devlink_ops, sizeof(*pf));
7091851f93fSSimon Horman 	if (!devlink) {
71063461a02SJakub Kicinski 		err = -ENOMEM;
71163461a02SJakub Kicinski 		goto err_rel_regions;
71263461a02SJakub Kicinski 	}
7131851f93fSSimon Horman 	pf = devlink_priv(devlink);
714d4e7f092SJakub Kicinski 	INIT_LIST_HEAD(&pf->vnics);
7153eb3b74aSJakub Kicinski 	INIT_LIST_HEAD(&pf->ports);
716346cfe84SJakub Kicinski 	mutex_init(&pf->lock);
71763461a02SJakub Kicinski 	pci_set_drvdata(pdev, pf);
71863461a02SJakub Kicinski 	pf->pdev = pdev;
71963461a02SJakub Kicinski 
7206d48ceb2SJakub Kicinski 	pf->wq = alloc_workqueue("nfp-%s", 0, 2, pci_name(pdev));
7216d48ceb2SJakub Kicinski 	if (!pf->wq) {
7226d48ceb2SJakub Kicinski 		err = -ENOMEM;
7236d48ceb2SJakub Kicinski 		goto err_pci_priv_unset;
7246d48ceb2SJakub Kicinski 	}
7256d48ceb2SJakub Kicinski 
72663461a02SJakub Kicinski 	pf->cpp = nfp_cpp_from_nfp6000_pcie(pdev);
727*95530a59SYueHaibing 	if (IS_ERR(pf->cpp)) {
72863461a02SJakub Kicinski 		err = PTR_ERR(pf->cpp);
72963461a02SJakub Kicinski 		goto err_disable_msix;
73063461a02SJakub Kicinski 	}
73163461a02SJakub Kicinski 
7323e3e9fd8SJakub Kicinski 	err = nfp_resource_table_init(pf->cpp);
7333e3e9fd8SJakub Kicinski 	if (err)
7343e3e9fd8SJakub Kicinski 		goto err_cpp_free;
7353e3e9fd8SJakub Kicinski 
7369baa4885SJakub Kicinski 	pf->hwinfo = nfp_hwinfo_read(pf->cpp);
7379baa4885SJakub Kicinski 
73864db09edSJakub Kicinski 	dev_info(&pdev->dev, "Assembly: %s%s%s-%s CPLD: %s\n",
7399baa4885SJakub Kicinski 		 nfp_hwinfo_lookup(pf->hwinfo, "assembly.vendor"),
7409baa4885SJakub Kicinski 		 nfp_hwinfo_lookup(pf->hwinfo, "assembly.partno"),
7419baa4885SJakub Kicinski 		 nfp_hwinfo_lookup(pf->hwinfo, "assembly.serial"),
7429baa4885SJakub Kicinski 		 nfp_hwinfo_lookup(pf->hwinfo, "assembly.revision"),
7439baa4885SJakub Kicinski 		 nfp_hwinfo_lookup(pf->hwinfo, "cpld.version"));
74464db09edSJakub Kicinski 
7454cbe94f2SJakub Kicinski 	err = nfp_pf_board_state_wait(pf);
7464cbe94f2SJakub Kicinski 	if (err)
7474cbe94f2SJakub Kicinski 		goto err_hwinfo_free;
7484cbe94f2SJakub Kicinski 
7491851f93fSSimon Horman 	err = nfp_nsp_init(pdev, pf);
7501851f93fSSimon Horman 	if (err)
751bcc93a23SJakub Kicinski 		goto err_hwinfo_free;
7521851f93fSSimon Horman 
7530be40e66SJakub Kicinski 	pf->mip = nfp_mip_open(pf->cpp);
7540be40e66SJakub Kicinski 	pf->rtbl = __nfp_rtsym_table_read(pf->cpp, pf->mip);
755af4fa7eaSJakub Kicinski 
7560c693323SJakub Kicinski 	err = nfp_pf_find_rtsyms(pf);
7570c693323SJakub Kicinski 	if (err)
7580c693323SJakub Kicinski 		goto err_fw_unload;
7590c693323SJakub Kicinski 
760d79e19f5SCarl Heymann 	pf->dump_flag = NFP_DUMP_NSP_DIAG;
761d79e19f5SCarl Heymann 	pf->dumpspec = nfp_net_dump_load_dumpspec(pf->cpp, pf->rtbl);
762d79e19f5SCarl Heymann 
763651e1f2fSJakub Kicinski 	err = nfp_pcie_sriov_read_nfd_limit(pf);
76463461a02SJakub Kicinski 	if (err)
76563461a02SJakub Kicinski 		goto err_fw_unload;
76663461a02SJakub Kicinski 
7670dc78621SJakub Kicinski 	pf->num_vfs = pci_num_vf(pdev);
7680dc78621SJakub Kicinski 	if (pf->num_vfs > pf->limit_vfs) {
7690dc78621SJakub Kicinski 		dev_err(&pdev->dev,
7700dc78621SJakub Kicinski 			"Error: %d VFs already enabled, but loaded FW can only support %d\n",
7710dc78621SJakub Kicinski 			pf->num_vfs, pf->limit_vfs);
772e58decc9SWei Yongjun 		err = -EINVAL;
7730dc78621SJakub Kicinski 		goto err_fw_unload;
7740dc78621SJakub Kicinski 	}
7750dc78621SJakub Kicinski 
776651e1f2fSJakub Kicinski 	err = nfp_net_pci_probe(pf);
777651e1f2fSJakub Kicinski 	if (err)
77883235822SJakub Kicinski 		goto err_fw_unload;
779651e1f2fSJakub Kicinski 
780eefbde7eSDavid Brunecz 	err = nfp_hwmon_register(pf);
781eefbde7eSDavid Brunecz 	if (err) {
782eefbde7eSDavid Brunecz 		dev_err(&pdev->dev, "Failed to register hwmon info\n");
783eefbde7eSDavid Brunecz 		goto err_net_remove;
784eefbde7eSDavid Brunecz 	}
785eefbde7eSDavid Brunecz 
78663461a02SJakub Kicinski 	return 0;
78763461a02SJakub Kicinski 
788eefbde7eSDavid Brunecz err_net_remove:
789eefbde7eSDavid Brunecz 	nfp_net_pci_remove(pf);
79063461a02SJakub Kicinski err_fw_unload:
791af4fa7eaSJakub Kicinski 	kfree(pf->rtbl);
7920be40e66SJakub Kicinski 	nfp_mip_close(pf->mip);
793f8921d73SDirk van der Merwe 	if (pf->unload_fw_on_remove)
79463461a02SJakub Kicinski 		nfp_fw_unload(pf);
79563461a02SJakub Kicinski 	kfree(pf->eth_tbl);
796eefbde7eSDavid Brunecz 	kfree(pf->nspi);
797d79e19f5SCarl Heymann 	vfree(pf->dumpspec);
7989baa4885SJakub Kicinski err_hwinfo_free:
7999baa4885SJakub Kicinski 	kfree(pf->hwinfo);
8003e3e9fd8SJakub Kicinski err_cpp_free:
80163461a02SJakub Kicinski 	nfp_cpp_free(pf->cpp);
80263461a02SJakub Kicinski err_disable_msix:
8036d48ceb2SJakub Kicinski 	destroy_workqueue(pf->wq);
8046d48ceb2SJakub Kicinski err_pci_priv_unset:
80563461a02SJakub Kicinski 	pci_set_drvdata(pdev, NULL);
806346cfe84SJakub Kicinski 	mutex_destroy(&pf->lock);
8071851f93fSSimon Horman 	devlink_free(devlink);
80863461a02SJakub Kicinski err_rel_regions:
80963461a02SJakub Kicinski 	pci_release_regions(pdev);
81063461a02SJakub Kicinski err_pci_disable:
81163461a02SJakub Kicinski 	pci_disable_device(pdev);
81263461a02SJakub Kicinski 
81363461a02SJakub Kicinski 	return err;
81463461a02SJakub Kicinski }
81563461a02SJakub Kicinski 
816790d23e7SDirk van der Merwe static void __nfp_pci_shutdown(struct pci_dev *pdev, bool unload_fw)
81763461a02SJakub Kicinski {
818790d23e7SDirk van der Merwe 	struct nfp_pf *pf;
819790d23e7SDirk van der Merwe 
820790d23e7SDirk van der Merwe 	pf = pci_get_drvdata(pdev);
821790d23e7SDirk van der Merwe 	if (!pf)
822790d23e7SDirk van der Merwe 		return;
8231851f93fSSimon Horman 
824eefbde7eSDavid Brunecz 	nfp_hwmon_unregister(pf);
825eefbde7eSDavid Brunecz 
82663461a02SJakub Kicinski 	nfp_pcie_sriov_disable(pdev);
82763461a02SJakub Kicinski 
828bcc93a23SJakub Kicinski 	nfp_net_pci_remove(pf);
8291851f93fSSimon Horman 
830d79e19f5SCarl Heymann 	vfree(pf->dumpspec);
831af4fa7eaSJakub Kicinski 	kfree(pf->rtbl);
8320be40e66SJakub Kicinski 	nfp_mip_close(pf->mip);
833f8921d73SDirk van der Merwe 	if (unload_fw && pf->unload_fw_on_remove)
83463461a02SJakub Kicinski 		nfp_fw_unload(pf);
83563461a02SJakub Kicinski 
8366d48ceb2SJakub Kicinski 	destroy_workqueue(pf->wq);
83763461a02SJakub Kicinski 	pci_set_drvdata(pdev, NULL);
8389baa4885SJakub Kicinski 	kfree(pf->hwinfo);
83963461a02SJakub Kicinski 	nfp_cpp_free(pf->cpp);
84063461a02SJakub Kicinski 
84163461a02SJakub Kicinski 	kfree(pf->eth_tbl);
842eefbde7eSDavid Brunecz 	kfree(pf->nspi);
843346cfe84SJakub Kicinski 	mutex_destroy(&pf->lock);
844bcc93a23SJakub Kicinski 	devlink_free(priv_to_devlink(pf));
84563461a02SJakub Kicinski 	pci_release_regions(pdev);
84663461a02SJakub Kicinski 	pci_disable_device(pdev);
84763461a02SJakub Kicinski }
84863461a02SJakub Kicinski 
849790d23e7SDirk van der Merwe static void nfp_pci_remove(struct pci_dev *pdev)
850790d23e7SDirk van der Merwe {
851790d23e7SDirk van der Merwe 	__nfp_pci_shutdown(pdev, true);
852790d23e7SDirk van der Merwe }
853790d23e7SDirk van der Merwe 
854790d23e7SDirk van der Merwe static void nfp_pci_shutdown(struct pci_dev *pdev)
855790d23e7SDirk van der Merwe {
856790d23e7SDirk van der Merwe 	__nfp_pci_shutdown(pdev, false);
857790d23e7SDirk van der Merwe }
858790d23e7SDirk van der Merwe 
85963461a02SJakub Kicinski static struct pci_driver nfp_pci_driver = {
86063461a02SJakub Kicinski 	.name			= nfp_driver_name,
86163461a02SJakub Kicinski 	.id_table		= nfp_pci_device_ids,
86263461a02SJakub Kicinski 	.probe			= nfp_pci_probe,
86363461a02SJakub Kicinski 	.remove			= nfp_pci_remove,
864790d23e7SDirk van der Merwe 	.shutdown		= nfp_pci_shutdown,
86563461a02SJakub Kicinski 	.sriov_configure	= nfp_pcie_sriov_configure,
86663461a02SJakub Kicinski };
86763461a02SJakub Kicinski 
8682633beb9SJakub Kicinski static int __init nfp_main_init(void)
8692633beb9SJakub Kicinski {
8702633beb9SJakub Kicinski 	int err;
8712633beb9SJakub Kicinski 
8722633beb9SJakub Kicinski 	pr_info("%s: NFP PCIe Driver, Copyright (C) 2014-2017 Netronome Systems\n",
8732633beb9SJakub Kicinski 		nfp_driver_name);
8742633beb9SJakub Kicinski 
8752633beb9SJakub Kicinski 	nfp_net_debugfs_create();
8762633beb9SJakub Kicinski 
87763461a02SJakub Kicinski 	err = pci_register_driver(&nfp_pci_driver);
87863461a02SJakub Kicinski 	if (err < 0)
87963461a02SJakub Kicinski 		goto err_destroy_debugfs;
88063461a02SJakub Kicinski 
8812633beb9SJakub Kicinski 	err = pci_register_driver(&nfp_netvf_pci_driver);
8822633beb9SJakub Kicinski 	if (err)
88363461a02SJakub Kicinski 		goto err_unreg_pf;
8842633beb9SJakub Kicinski 
8852633beb9SJakub Kicinski 	return err;
8862633beb9SJakub Kicinski 
88763461a02SJakub Kicinski err_unreg_pf:
88863461a02SJakub Kicinski 	pci_unregister_driver(&nfp_pci_driver);
8892633beb9SJakub Kicinski err_destroy_debugfs:
8902633beb9SJakub Kicinski 	nfp_net_debugfs_destroy();
8912633beb9SJakub Kicinski 	return err;
8922633beb9SJakub Kicinski }
8932633beb9SJakub Kicinski 
8942633beb9SJakub Kicinski static void __exit nfp_main_exit(void)
8952633beb9SJakub Kicinski {
8962633beb9SJakub Kicinski 	pci_unregister_driver(&nfp_netvf_pci_driver);
89763461a02SJakub Kicinski 	pci_unregister_driver(&nfp_pci_driver);
8982633beb9SJakub Kicinski 	nfp_net_debugfs_destroy();
8992633beb9SJakub Kicinski }
9002633beb9SJakub Kicinski 
9012633beb9SJakub Kicinski module_init(nfp_main_init);
9022633beb9SJakub Kicinski module_exit(nfp_main_exit);
9032633beb9SJakub Kicinski 
904d00ee466SJakub Kicinski MODULE_FIRMWARE("netronome/nic_AMDA0058-0011_2x40.nffw");
905d00ee466SJakub Kicinski MODULE_FIRMWARE("netronome/nic_AMDA0058-0012_2x40.nffw");
90663461a02SJakub Kicinski MODULE_FIRMWARE("netronome/nic_AMDA0081-0001_1x40.nffw");
90763461a02SJakub Kicinski MODULE_FIRMWARE("netronome/nic_AMDA0081-0001_4x10.nffw");
90863461a02SJakub Kicinski MODULE_FIRMWARE("netronome/nic_AMDA0096-0001_2x10.nffw");
90963461a02SJakub Kicinski MODULE_FIRMWARE("netronome/nic_AMDA0097-0001_2x40.nffw");
91063461a02SJakub Kicinski MODULE_FIRMWARE("netronome/nic_AMDA0097-0001_4x10_1x40.nffw");
91163461a02SJakub Kicinski MODULE_FIRMWARE("netronome/nic_AMDA0097-0001_8x10.nffw");
91263461a02SJakub Kicinski MODULE_FIRMWARE("netronome/nic_AMDA0099-0001_2x10.nffw");
91363461a02SJakub Kicinski MODULE_FIRMWARE("netronome/nic_AMDA0099-0001_2x25.nffw");
91470271dadSDirk van der Merwe MODULE_FIRMWARE("netronome/nic_AMDA0099-0001_1x10_1x25.nffw");
91563461a02SJakub Kicinski 
9162633beb9SJakub Kicinski MODULE_AUTHOR("Netronome Systems <oss-drivers@netronome.com>");
9172633beb9SJakub Kicinski MODULE_LICENSE("GPL");
9182633beb9SJakub Kicinski MODULE_DESCRIPTION("The Netronome Flow Processor (NFP) driver.");
919