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"
229423d24bSJakub Kicinski #include "nfpcore/nfp_dev.h"
230bc3827fSJakub Kicinski #include "nfpcore/nfp_nffw.h"
24ce22f5a2SJakub Kicinski #include "nfpcore/nfp_nsp.h"
2563461a02SJakub Kicinski 
2663461a02SJakub Kicinski #include "nfpcore/nfp6000_pcie.h"
2763461a02SJakub Kicinski 
280c693323SJakub Kicinski #include "nfp_abi.h"
29758238f2SSimon Horman #include "nfp_app.h"
302633beb9SJakub Kicinski #include "nfp_main.h"
312633beb9SJakub Kicinski #include "nfp_net.h"
322633beb9SJakub Kicinski 
332633beb9SJakub Kicinski static const char nfp_driver_name[] = "nfp";
342633beb9SJakub Kicinski 
3563461a02SJakub Kicinski static const struct pci_device_id nfp_pci_device_ids[] = {
36299ba7a3SYu Xiao 	{ PCI_VENDOR_ID_NETRONOME, PCI_DEVICE_ID_NFP3800,
37d3826a95SDirk van der Merwe 	  PCI_VENDOR_ID_NETRONOME, PCI_ANY_ID,
38d3826a95SDirk van der Merwe 	  PCI_ANY_ID, 0, NFP_DEV_NFP3800,
39d3826a95SDirk van der Merwe 	},
40299ba7a3SYu Xiao 	{ PCI_VENDOR_ID_NETRONOME, PCI_DEVICE_ID_NFP4000,
4163461a02SJakub Kicinski 	  PCI_VENDOR_ID_NETRONOME, PCI_ANY_ID,
429423d24bSJakub Kicinski 	  PCI_ANY_ID, 0, NFP_DEV_NFP6000,
4363461a02SJakub Kicinski 	},
44299ba7a3SYu Xiao 	{ PCI_VENDOR_ID_NETRONOME, PCI_DEVICE_ID_NFP5000,
450377505cSJakub Kicinski 	  PCI_VENDOR_ID_NETRONOME, PCI_ANY_ID,
469423d24bSJakub Kicinski 	  PCI_ANY_ID, 0, NFP_DEV_NFP6000,
470377505cSJakub Kicinski 	},
48299ba7a3SYu Xiao 	{ PCI_VENDOR_ID_NETRONOME, PCI_DEVICE_ID_NFP6000,
4963461a02SJakub Kicinski 	  PCI_VENDOR_ID_NETRONOME, PCI_ANY_ID,
509423d24bSJakub Kicinski 	  PCI_ANY_ID, 0, NFP_DEV_NFP6000,
5163461a02SJakub Kicinski 	},
52299ba7a3SYu Xiao 	{ PCI_VENDOR_ID_CORIGINE, PCI_DEVICE_ID_NFP3800,
53299ba7a3SYu Xiao 	  PCI_VENDOR_ID_CORIGINE, PCI_ANY_ID,
54299ba7a3SYu Xiao 	  PCI_ANY_ID, 0, NFP_DEV_NFP3800,
55299ba7a3SYu Xiao 	},
56299ba7a3SYu Xiao 	{ PCI_VENDOR_ID_CORIGINE, PCI_DEVICE_ID_NFP4000,
57299ba7a3SYu Xiao 	  PCI_VENDOR_ID_CORIGINE, PCI_ANY_ID,
58299ba7a3SYu Xiao 	  PCI_ANY_ID, 0, NFP_DEV_NFP6000,
59299ba7a3SYu Xiao 	},
60299ba7a3SYu Xiao 	{ PCI_VENDOR_ID_CORIGINE, PCI_DEVICE_ID_NFP5000,
61299ba7a3SYu Xiao 	  PCI_VENDOR_ID_CORIGINE, PCI_ANY_ID,
62299ba7a3SYu Xiao 	  PCI_ANY_ID, 0, NFP_DEV_NFP6000,
63299ba7a3SYu Xiao 	},
64299ba7a3SYu Xiao 	{ PCI_VENDOR_ID_CORIGINE, PCI_DEVICE_ID_NFP6000,
65299ba7a3SYu Xiao 	  PCI_VENDOR_ID_CORIGINE, PCI_ANY_ID,
66299ba7a3SYu Xiao 	  PCI_ANY_ID, 0, NFP_DEV_NFP6000,
67299ba7a3SYu Xiao 	},
6863461a02SJakub Kicinski 	{ 0, } /* Required last entry. */
6963461a02SJakub Kicinski };
7063461a02SJakub Kicinski MODULE_DEVICE_TABLE(pci, nfp_pci_device_ids);
7163461a02SJakub Kicinski 
nfp_pf_rtsym_read_optional(struct nfp_pf * pf,const char * format,unsigned int default_val)728f6196f6SJakub Kicinski int nfp_pf_rtsym_read_optional(struct nfp_pf *pf, const char *format,
738f6196f6SJakub Kicinski 			       unsigned int default_val)
748f6196f6SJakub Kicinski {
758f6196f6SJakub Kicinski 	char name[256];
768f6196f6SJakub Kicinski 	int err = 0;
778f6196f6SJakub Kicinski 	u64 val;
788f6196f6SJakub Kicinski 
798f6196f6SJakub Kicinski 	snprintf(name, sizeof(name), format, nfp_cppcore_pcie_unit(pf->cpp));
808f6196f6SJakub Kicinski 
818f6196f6SJakub Kicinski 	val = nfp_rtsym_read_le(pf->rtbl, name, &err);
828f6196f6SJakub Kicinski 	if (err) {
838f6196f6SJakub Kicinski 		if (err == -ENOENT)
848f6196f6SJakub Kicinski 			return default_val;
858f6196f6SJakub Kicinski 		nfp_err(pf->cpp, "Unable to read symbol %s\n", name);
868f6196f6SJakub Kicinski 		return err;
878f6196f6SJakub Kicinski 	}
888f6196f6SJakub Kicinski 
898f6196f6SJakub Kicinski 	return val;
908f6196f6SJakub Kicinski }
918f6196f6SJakub Kicinski 
928f6196f6SJakub Kicinski u8 __iomem *
nfp_pf_map_rtsym(struct nfp_pf * pf,const char * name,const char * sym_fmt,unsigned int min_size,struct nfp_cpp_area ** area)938f6196f6SJakub Kicinski nfp_pf_map_rtsym(struct nfp_pf *pf, const char *name, const char *sym_fmt,
948f6196f6SJakub Kicinski 		 unsigned int min_size, struct nfp_cpp_area **area)
958f6196f6SJakub Kicinski {
968f6196f6SJakub Kicinski 	char pf_symbol[256];
978f6196f6SJakub Kicinski 
988f6196f6SJakub Kicinski 	snprintf(pf_symbol, sizeof(pf_symbol), sym_fmt,
998f6196f6SJakub Kicinski 		 nfp_cppcore_pcie_unit(pf->cpp));
1008f6196f6SJakub Kicinski 
1018f6196f6SJakub Kicinski 	return nfp_rtsym_map(pf->rtbl, pf_symbol, name, min_size, area);
1028f6196f6SJakub Kicinski }
1038f6196f6SJakub Kicinski 
1040c693323SJakub Kicinski /* Callers should hold the devlink instance lock */
nfp_mbox_cmd(struct nfp_pf * pf,u32 cmd,void * in_data,u64 in_length,void * out_data,u64 out_length)1050c693323SJakub Kicinski int nfp_mbox_cmd(struct nfp_pf *pf, u32 cmd, void *in_data, u64 in_length,
1060c693323SJakub Kicinski 		 void *out_data, u64 out_length)
1070c693323SJakub Kicinski {
1080c693323SJakub Kicinski 	unsigned long err_at;
1090c693323SJakub Kicinski 	u64 max_data_sz;
1100c693323SJakub Kicinski 	u32 val = 0;
1110c693323SJakub Kicinski 	int n, err;
1120c693323SJakub Kicinski 
1130c693323SJakub Kicinski 	if (!pf->mbox)
1140c693323SJakub Kicinski 		return -EOPNOTSUPP;
1150c693323SJakub Kicinski 
1164152e58cSJakub Kicinski 	max_data_sz = nfp_rtsym_size(pf->mbox) - NFP_MBOX_SYM_MIN_SIZE;
1170c693323SJakub Kicinski 
1180c693323SJakub Kicinski 	/* Check if cmd field is clear */
1191240989cSJakub Kicinski 	err = nfp_rtsym_readl(pf->cpp, pf->mbox, NFP_MBOX_CMD, &val);
1200c693323SJakub Kicinski 	if (err || val) {
1210c693323SJakub Kicinski 		nfp_warn(pf->cpp, "failed to issue command (%u): %u, err: %d\n",
1220c693323SJakub Kicinski 			 cmd, val, err);
1230c693323SJakub Kicinski 		return err ?: -EBUSY;
1240c693323SJakub Kicinski 	}
1250c693323SJakub Kicinski 
1260c693323SJakub Kicinski 	in_length = min(in_length, max_data_sz);
1271240989cSJakub Kicinski 	n = nfp_rtsym_write(pf->cpp, pf->mbox, NFP_MBOX_DATA, in_data,
1281240989cSJakub Kicinski 			    in_length);
1290c693323SJakub Kicinski 	if (n != in_length)
1300c693323SJakub Kicinski 		return -EIO;
1310c693323SJakub Kicinski 	/* Write data_len and wipe reserved */
1321240989cSJakub Kicinski 	err = nfp_rtsym_writeq(pf->cpp, pf->mbox, NFP_MBOX_DATA_LEN, in_length);
1330c693323SJakub Kicinski 	if (err)
1340c693323SJakub Kicinski 		return err;
1350c693323SJakub Kicinski 
1360c693323SJakub Kicinski 	/* Read back for ordering */
1371240989cSJakub Kicinski 	err = nfp_rtsym_readl(pf->cpp, pf->mbox, NFP_MBOX_DATA_LEN, &val);
1380c693323SJakub Kicinski 	if (err)
1390c693323SJakub Kicinski 		return err;
1400c693323SJakub Kicinski 
1410c693323SJakub Kicinski 	/* Write cmd and wipe return value */
1421240989cSJakub Kicinski 	err = nfp_rtsym_writeq(pf->cpp, pf->mbox, NFP_MBOX_CMD, cmd);
1430c693323SJakub Kicinski 	if (err)
1440c693323SJakub Kicinski 		return err;
1450c693323SJakub Kicinski 
1460c693323SJakub Kicinski 	err_at = jiffies + 5 * HZ;
1470c693323SJakub Kicinski 	while (true) {
1480c693323SJakub Kicinski 		/* Wait for command to go to 0 (NFP_MBOX_NO_CMD) */
1491240989cSJakub Kicinski 		err = nfp_rtsym_readl(pf->cpp, pf->mbox, NFP_MBOX_CMD, &val);
1500c693323SJakub Kicinski 		if (err)
1510c693323SJakub Kicinski 			return err;
1520c693323SJakub Kicinski 		if (!val)
1530c693323SJakub Kicinski 			break;
1540c693323SJakub Kicinski 
1550c693323SJakub Kicinski 		if (time_is_before_eq_jiffies(err_at))
1560c693323SJakub Kicinski 			return -ETIMEDOUT;
1570c693323SJakub Kicinski 
1580c693323SJakub Kicinski 		msleep(5);
1590c693323SJakub Kicinski 	}
1600c693323SJakub Kicinski 
1610c693323SJakub Kicinski 	/* Copy output if any (could be error info, do it before reading ret) */
1621240989cSJakub Kicinski 	err = nfp_rtsym_readl(pf->cpp, pf->mbox, NFP_MBOX_DATA_LEN, &val);
1630c693323SJakub Kicinski 	if (err)
1640c693323SJakub Kicinski 		return err;
1650c693323SJakub Kicinski 
1660c693323SJakub Kicinski 	out_length = min_t(u32, val, min(out_length, max_data_sz));
1671240989cSJakub Kicinski 	n = nfp_rtsym_read(pf->cpp, pf->mbox, NFP_MBOX_DATA,
1680c693323SJakub Kicinski 			   out_data, out_length);
1690c693323SJakub Kicinski 	if (n != out_length)
1700c693323SJakub Kicinski 		return -EIO;
1710c693323SJakub Kicinski 
1720c693323SJakub Kicinski 	/* Check if there is an error */
1731240989cSJakub Kicinski 	err = nfp_rtsym_readl(pf->cpp, pf->mbox, NFP_MBOX_RET, &val);
1740c693323SJakub Kicinski 	if (err)
1750c693323SJakub Kicinski 		return err;
1760c693323SJakub Kicinski 	if (val)
1770c693323SJakub Kicinski 		return -val;
1780c693323SJakub Kicinski 
1790c693323SJakub Kicinski 	return out_length;
1800c693323SJakub Kicinski }
1810c693323SJakub Kicinski 
nfp_board_ready(struct nfp_pf * pf)1824cbe94f2SJakub Kicinski static bool nfp_board_ready(struct nfp_pf *pf)
1834cbe94f2SJakub Kicinski {
1844cbe94f2SJakub Kicinski 	const char *cp;
1854cbe94f2SJakub Kicinski 	long state;
1864cbe94f2SJakub Kicinski 	int err;
1874cbe94f2SJakub Kicinski 
1884cbe94f2SJakub Kicinski 	cp = nfp_hwinfo_lookup(pf->hwinfo, "board.state");
1894cbe94f2SJakub Kicinski 	if (!cp)
1904cbe94f2SJakub Kicinski 		return false;
1914cbe94f2SJakub Kicinski 
1924cbe94f2SJakub Kicinski 	err = kstrtol(cp, 0, &state);
1934cbe94f2SJakub Kicinski 	if (err < 0)
1944cbe94f2SJakub Kicinski 		return false;
1954cbe94f2SJakub Kicinski 
1964cbe94f2SJakub Kicinski 	return state == 15;
1974cbe94f2SJakub Kicinski }
1984cbe94f2SJakub Kicinski 
nfp_pf_board_state_wait(struct nfp_pf * pf)1994cbe94f2SJakub Kicinski static int nfp_pf_board_state_wait(struct nfp_pf *pf)
2004cbe94f2SJakub Kicinski {
2014cbe94f2SJakub Kicinski 	const unsigned long wait_until = jiffies + 10 * HZ;
2024cbe94f2SJakub Kicinski 
2034cbe94f2SJakub Kicinski 	while (!nfp_board_ready(pf)) {
2044cbe94f2SJakub Kicinski 		if (time_is_before_eq_jiffies(wait_until)) {
2054cbe94f2SJakub Kicinski 			nfp_err(pf->cpp, "NFP board initialization timeout\n");
2064cbe94f2SJakub Kicinski 			return -EINVAL;
2074cbe94f2SJakub Kicinski 		}
2084cbe94f2SJakub Kicinski 
2094cbe94f2SJakub Kicinski 		nfp_info(pf->cpp, "waiting for board initialization\n");
2104cbe94f2SJakub Kicinski 		if (msleep_interruptible(500))
2114cbe94f2SJakub Kicinski 			return -ERESTARTSYS;
2124cbe94f2SJakub Kicinski 
2134cbe94f2SJakub Kicinski 		/* Refresh cached information */
2144cbe94f2SJakub Kicinski 		kfree(pf->hwinfo);
2154cbe94f2SJakub Kicinski 		pf->hwinfo = nfp_hwinfo_read(pf->cpp);
2164cbe94f2SJakub Kicinski 	}
2174cbe94f2SJakub Kicinski 
2184cbe94f2SJakub Kicinski 	return 0;
2194cbe94f2SJakub Kicinski }
2204cbe94f2SJakub Kicinski 
nfp_pcie_sriov_read_nfd_limit(struct nfp_pf * pf)221651e1f2fSJakub Kicinski static int nfp_pcie_sriov_read_nfd_limit(struct nfp_pf *pf)
2220bc3827fSJakub Kicinski {
2230bc3827fSJakub Kicinski 	int err;
2240bc3827fSJakub Kicinski 
225af4fa7eaSJakub Kicinski 	pf->limit_vfs = nfp_rtsym_read_le(pf->rtbl, "nfd_vf_cfg_max_vfs", &err);
2265b0ced17SJakub Kicinski 	if (err) {
2275b0ced17SJakub Kicinski 		/* For backwards compatibility if symbol not found allow all */
2280bc3827fSJakub Kicinski 		pf->limit_vfs = ~0;
229651e1f2fSJakub Kicinski 		if (err == -ENOENT)
230651e1f2fSJakub Kicinski 			return 0;
231651e1f2fSJakub Kicinski 
2320bc3827fSJakub Kicinski 		nfp_warn(pf->cpp, "Warning: VF limit read failed: %d\n", err);
233651e1f2fSJakub Kicinski 		return err;
2340bc3827fSJakub Kicinski 	}
2350bc3827fSJakub Kicinski 
2365b0ced17SJakub Kicinski 	err = pci_sriov_set_totalvfs(pf->pdev, pf->limit_vfs);
2375b0ced17SJakub Kicinski 	if (err)
2385b0ced17SJakub Kicinski 		nfp_warn(pf->cpp, "Failed to set VF count in sysfs: %d\n", err);
2395b0ced17SJakub Kicinski 	return 0;
2405b0ced17SJakub Kicinski }
2415b0ced17SJakub Kicinski 
nfp_pcie_sriov_enable(struct pci_dev * pdev,int num_vfs)24263461a02SJakub Kicinski static int nfp_pcie_sriov_enable(struct pci_dev *pdev, int num_vfs)
24363461a02SJakub Kicinski {
24463461a02SJakub Kicinski #ifdef CONFIG_PCI_IOV
24563461a02SJakub Kicinski 	struct nfp_pf *pf = pci_get_drvdata(pdev);
246162cca42SJakub Kicinski 	struct devlink *devlink;
24763461a02SJakub Kicinski 	int err;
24863461a02SJakub Kicinski 
2490bc3827fSJakub Kicinski 	if (num_vfs > pf->limit_vfs) {
2500bc3827fSJakub Kicinski 		nfp_info(pf->cpp, "Firmware limits number of VFs to %u\n",
2510bc3827fSJakub Kicinski 			 pf->limit_vfs);
252d6e1ab9eSJakub Kicinski 		return -EINVAL;
253758238f2SSimon Horman 	}
254758238f2SSimon Horman 
255e3f28473SJakub Kicinski 	err = pci_enable_sriov(pdev, num_vfs);
256758238f2SSimon Horman 	if (err) {
257e3f28473SJakub Kicinski 		dev_warn(&pdev->dev, "Failed to enable PCI SR-IOV: %d\n", err);
258d6e1ab9eSJakub Kicinski 		return err;
2590bc3827fSJakub Kicinski 	}
2600bc3827fSJakub Kicinski 
261162cca42SJakub Kicinski 	devlink = priv_to_devlink(pf);
262162cca42SJakub Kicinski 	devl_lock(devlink);
263d6e1ab9eSJakub Kicinski 
264e3f28473SJakub Kicinski 	err = nfp_app_sriov_enable(pf->app, num_vfs);
26563461a02SJakub Kicinski 	if (err) {
266e3f28473SJakub Kicinski 		dev_warn(&pdev->dev,
267e3f28473SJakub Kicinski 			 "App specific PCI SR-IOV configuration failed: %d\n",
268e3f28473SJakub Kicinski 			 err);
269e3f28473SJakub Kicinski 		goto err_sriov_disable;
27063461a02SJakub Kicinski 	}
27163461a02SJakub Kicinski 
27263461a02SJakub Kicinski 	pf->num_vfs = num_vfs;
27363461a02SJakub Kicinski 
27463461a02SJakub Kicinski 	dev_dbg(&pdev->dev, "Created %d VFs.\n", pf->num_vfs);
27563461a02SJakub Kicinski 
276162cca42SJakub Kicinski 	devl_unlock(devlink);
27763461a02SJakub Kicinski 	return num_vfs;
278758238f2SSimon Horman 
279e3f28473SJakub Kicinski err_sriov_disable:
280162cca42SJakub Kicinski 	devl_unlock(devlink);
281d6e1ab9eSJakub Kicinski 	pci_disable_sriov(pdev);
282758238f2SSimon Horman 	return err;
28363461a02SJakub Kicinski #endif
28463461a02SJakub Kicinski 	return 0;
28563461a02SJakub Kicinski }
28663461a02SJakub Kicinski 
nfp_pcie_sriov_disable(struct pci_dev * pdev)287e3f28473SJakub Kicinski static int nfp_pcie_sriov_disable(struct pci_dev *pdev)
28863461a02SJakub Kicinski {
28963461a02SJakub Kicinski #ifdef CONFIG_PCI_IOV
29063461a02SJakub Kicinski 	struct nfp_pf *pf = pci_get_drvdata(pdev);
291162cca42SJakub Kicinski 	struct devlink *devlink;
29263461a02SJakub Kicinski 
293162cca42SJakub Kicinski 	devlink = priv_to_devlink(pf);
294162cca42SJakub Kicinski 	devl_lock(devlink);
295e3f28473SJakub Kicinski 
29663461a02SJakub Kicinski 	/* If the VFs are assigned we cannot shut down SR-IOV without
29763461a02SJakub Kicinski 	 * causing issues, so just leave the hardware available but
29863461a02SJakub Kicinski 	 * disabled
29963461a02SJakub Kicinski 	 */
30063461a02SJakub Kicinski 	if (pci_vfs_assigned(pdev)) {
30163461a02SJakub Kicinski 		dev_warn(&pdev->dev, "Disabling while VFs assigned - VFs will not be deallocated\n");
302162cca42SJakub Kicinski 		devl_unlock(devlink);
30363461a02SJakub Kicinski 		return -EPERM;
30463461a02SJakub Kicinski 	}
30563461a02SJakub Kicinski 
306758238f2SSimon Horman 	nfp_app_sriov_disable(pf->app);
307758238f2SSimon Horman 
30863461a02SJakub Kicinski 	pf->num_vfs = 0;
30963461a02SJakub Kicinski 
310162cca42SJakub Kicinski 	devl_unlock(devlink);
311d6e1ab9eSJakub Kicinski 
31263461a02SJakub Kicinski 	pci_disable_sriov(pdev);
31363461a02SJakub Kicinski 	dev_dbg(&pdev->dev, "Removed VFs.\n");
31463461a02SJakub Kicinski #endif
31563461a02SJakub Kicinski 	return 0;
31663461a02SJakub Kicinski }
31763461a02SJakub Kicinski 
nfp_pcie_sriov_configure(struct pci_dev * pdev,int num_vfs)31863461a02SJakub Kicinski static int nfp_pcie_sriov_configure(struct pci_dev *pdev, int num_vfs)
31963461a02SJakub Kicinski {
320790d23e7SDirk van der Merwe 	if (!pci_get_drvdata(pdev))
321790d23e7SDirk van der Merwe 		return -ENOENT;
322790d23e7SDirk van der Merwe 
32363461a02SJakub Kicinski 	if (num_vfs == 0)
32463461a02SJakub Kicinski 		return nfp_pcie_sriov_disable(pdev);
32563461a02SJakub Kicinski 	else
32663461a02SJakub Kicinski 		return nfp_pcie_sriov_enable(pdev, num_vfs);
32763461a02SJakub Kicinski }
32863461a02SJakub Kicinski 
nfp_flash_update_common(struct nfp_pf * pf,const struct firmware * fw,struct netlink_ext_ack * extack)329b44cfd4fSJacob Keller int nfp_flash_update_common(struct nfp_pf *pf, const struct firmware *fw,
3305c5696f3SJakub Kicinski 			    struct netlink_ext_ack *extack)
3315c5696f3SJakub Kicinski {
3325c5696f3SJakub Kicinski 	struct device *dev = &pf->pdev->dev;
3335c5696f3SJakub Kicinski 	struct nfp_nsp *nsp;
3345c5696f3SJakub Kicinski 	int err;
3355c5696f3SJakub Kicinski 
3365c5696f3SJakub Kicinski 	nsp = nfp_nsp_open(pf->cpp);
3375c5696f3SJakub Kicinski 	if (IS_ERR(nsp)) {
3385c5696f3SJakub Kicinski 		err = PTR_ERR(nsp);
3395c5696f3SJakub Kicinski 		if (extack)
3405c5696f3SJakub Kicinski 			NL_SET_ERR_MSG_MOD(extack, "can't access NSP");
3415c5696f3SJakub Kicinski 		else
3425c5696f3SJakub Kicinski 			dev_err(dev, "Failed to access the NSP: %d\n", err);
3435c5696f3SJakub Kicinski 		return err;
3445c5696f3SJakub Kicinski 	}
3455c5696f3SJakub Kicinski 
3465c5696f3SJakub Kicinski 	err = nfp_nsp_write_flash(nsp, fw);
3475c5696f3SJakub Kicinski 	if (err < 0)
348b44cfd4fSJacob Keller 		goto exit_close_nsp;
3495c5696f3SJakub Kicinski 	dev_info(dev, "Finished writing flash image\n");
3505c5696f3SJakub Kicinski 	err = 0;
3515c5696f3SJakub Kicinski 
3525c5696f3SJakub Kicinski exit_close_nsp:
3535c5696f3SJakub Kicinski 	nfp_nsp_close(nsp);
3545c5696f3SJakub Kicinski 	return err;
3555c5696f3SJakub Kicinski }
3565c5696f3SJakub Kicinski 
3571680a370SJakub Kicinski static const struct firmware *
nfp_net_fw_request(struct pci_dev * pdev,struct nfp_pf * pf,const char * name)3581680a370SJakub Kicinski nfp_net_fw_request(struct pci_dev *pdev, struct nfp_pf *pf, const char *name)
3591680a370SJakub Kicinski {
3601680a370SJakub Kicinski 	const struct firmware *fw = NULL;
3611680a370SJakub Kicinski 	int err;
3621680a370SJakub Kicinski 
3631680a370SJakub Kicinski 	err = request_firmware_direct(&fw, name, &pdev->dev);
3641680a370SJakub Kicinski 	nfp_info(pf->cpp, "  %s: %s\n",
365f8921d73SDirk van der Merwe 		 name, err ? "not found" : "found");
3661680a370SJakub Kicinski 	if (err)
3671680a370SJakub Kicinski 		return NULL;
3681680a370SJakub Kicinski 
3691680a370SJakub Kicinski 	return fw;
3701680a370SJakub Kicinski }
3711680a370SJakub Kicinski 
37263461a02SJakub Kicinski /**
37363461a02SJakub Kicinski  * nfp_net_fw_find() - Find the correct firmware image for netdev mode
37463461a02SJakub Kicinski  * @pdev:	PCI Device structure
37563461a02SJakub Kicinski  * @pf:		NFP PF Device structure
37663461a02SJakub Kicinski  *
37763461a02SJakub Kicinski  * Return: firmware if found and requested successfully.
37863461a02SJakub Kicinski  */
37963461a02SJakub Kicinski static const struct firmware *
nfp_net_fw_find(struct pci_dev * pdev,struct nfp_pf * pf)38063461a02SJakub Kicinski nfp_net_fw_find(struct pci_dev *pdev, struct nfp_pf *pf)
38163461a02SJakub Kicinski {
38263461a02SJakub Kicinski 	struct nfp_eth_table_port *port;
3831680a370SJakub Kicinski 	const struct firmware *fw;
38463461a02SJakub Kicinski 	const char *fw_model;
38563461a02SJakub Kicinski 	char fw_name[256];
3869511f298SJakub Kicinski 	const u8 *serial;
3879511f298SJakub Kicinski 	u16 interface;
3881680a370SJakub Kicinski 	int spc, i, j;
3891680a370SJakub Kicinski 
3901680a370SJakub Kicinski 	nfp_info(pf->cpp, "Looking for firmware file in order of priority:\n");
39163461a02SJakub Kicinski 
3929511f298SJakub Kicinski 	/* First try to find a firmware image specific for this device */
3939511f298SJakub Kicinski 	interface = nfp_cpp_interface(pf->cpp);
3949511f298SJakub Kicinski 	nfp_cpp_serial(pf->cpp, &serial);
395ef2a95dbSJustin Stitt 	sprintf(fw_name, "netronome/serial-%pMF-%02x-%02x.nffw",
3969511f298SJakub Kicinski 		serial, interface >> 8, interface & 0xff);
3971680a370SJakub Kicinski 	fw = nfp_net_fw_request(pdev, pf, fw_name);
3981680a370SJakub Kicinski 	if (fw)
3991680a370SJakub Kicinski 		return fw;
4009511f298SJakub Kicinski 
4019511f298SJakub Kicinski 	/* Then try the PCI name */
4029511f298SJakub Kicinski 	sprintf(fw_name, "netronome/pci-%s.nffw", pci_name(pdev));
4031680a370SJakub Kicinski 	fw = nfp_net_fw_request(pdev, pf, fw_name);
4041680a370SJakub Kicinski 	if (fw)
4051680a370SJakub Kicinski 		return fw;
4069511f298SJakub Kicinski 
4079511f298SJakub Kicinski 	/* Finally try the card type and media */
40863461a02SJakub Kicinski 	if (!pf->eth_tbl) {
40963461a02SJakub Kicinski 		dev_err(&pdev->dev, "Error: can't identify media config\n");
41063461a02SJakub Kicinski 		return NULL;
41163461a02SJakub Kicinski 	}
41263461a02SJakub Kicinski 
41300bb2920SYu Xiao 	fw_model = nfp_hwinfo_lookup(pf->hwinfo, "nffw.partno");
41400bb2920SYu Xiao 	if (!fw_model)
4159baa4885SJakub Kicinski 		fw_model = nfp_hwinfo_lookup(pf->hwinfo, "assembly.partno");
41663461a02SJakub Kicinski 	if (!fw_model) {
41763461a02SJakub Kicinski 		dev_err(&pdev->dev, "Error: can't read part number\n");
41863461a02SJakub Kicinski 		return NULL;
41963461a02SJakub Kicinski 	}
42063461a02SJakub Kicinski 
42163461a02SJakub Kicinski 	spc = ARRAY_SIZE(fw_name);
42263461a02SJakub Kicinski 	spc -= snprintf(fw_name, spc, "netronome/nic_%s", fw_model);
42363461a02SJakub Kicinski 
42463461a02SJakub Kicinski 	for (i = 0; spc > 0 && i < pf->eth_tbl->count; i += j) {
42563461a02SJakub Kicinski 		port = &pf->eth_tbl->ports[i];
42663461a02SJakub Kicinski 		j = 1;
42763461a02SJakub Kicinski 		while (i + j < pf->eth_tbl->count &&
42863461a02SJakub Kicinski 		       port->speed == port[j].speed)
42963461a02SJakub Kicinski 			j++;
43063461a02SJakub Kicinski 
43163461a02SJakub Kicinski 		spc -= snprintf(&fw_name[ARRAY_SIZE(fw_name) - spc], spc,
43263461a02SJakub Kicinski 				"_%dx%d", j, port->speed / 1000);
43363461a02SJakub Kicinski 	}
43463461a02SJakub Kicinski 
43563461a02SJakub Kicinski 	if (spc <= 0)
43663461a02SJakub Kicinski 		return NULL;
43763461a02SJakub Kicinski 
43863461a02SJakub Kicinski 	spc -= snprintf(&fw_name[ARRAY_SIZE(fw_name) - spc], spc, ".nffw");
43963461a02SJakub Kicinski 	if (spc <= 0)
44063461a02SJakub Kicinski 		return NULL;
44163461a02SJakub Kicinski 
4421680a370SJakub Kicinski 	return nfp_net_fw_request(pdev, pf, fw_name);
44363461a02SJakub Kicinski }
44463461a02SJakub Kicinski 
445f8921d73SDirk van der Merwe static int
nfp_get_fw_policy_value(struct pci_dev * pdev,struct nfp_nsp * nsp,const char * key,const char * default_val,int max_val,int * value)446f8921d73SDirk van der Merwe nfp_get_fw_policy_value(struct pci_dev *pdev, struct nfp_nsp *nsp,
447f8921d73SDirk van der Merwe 			const char *key, const char *default_val, int max_val,
448f8921d73SDirk van der Merwe 			int *value)
449f8921d73SDirk van der Merwe {
450f8921d73SDirk van der Merwe 	char hwinfo[64];
451f8921d73SDirk van der Merwe 	long hi_val;
452f8921d73SDirk van der Merwe 	int err;
453f8921d73SDirk van der Merwe 
454f8921d73SDirk van der Merwe 	snprintf(hwinfo, sizeof(hwinfo), key);
455f8921d73SDirk van der Merwe 	err = nfp_nsp_hwinfo_lookup_optional(nsp, hwinfo, sizeof(hwinfo),
456f8921d73SDirk van der Merwe 					     default_val);
457f8921d73SDirk van der Merwe 	if (err)
458f8921d73SDirk van der Merwe 		return err;
459f8921d73SDirk van der Merwe 
460f8921d73SDirk van der Merwe 	err = kstrtol(hwinfo, 0, &hi_val);
461f8921d73SDirk van der Merwe 	if (err || hi_val < 0 || hi_val > max_val) {
462f8921d73SDirk van der Merwe 		dev_warn(&pdev->dev,
463f8921d73SDirk van der Merwe 			 "Invalid value '%s' from '%s', ignoring\n",
464f8921d73SDirk van der Merwe 			 hwinfo, key);
465f8921d73SDirk van der Merwe 		err = kstrtol(default_val, 0, &hi_val);
466f8921d73SDirk van der Merwe 	}
467f8921d73SDirk van der Merwe 
468f8921d73SDirk van der Merwe 	*value = hi_val;
469f8921d73SDirk van der Merwe 	return err;
470f8921d73SDirk van der Merwe }
471f8921d73SDirk van der Merwe 
47263461a02SJakub Kicinski /**
4738fb822ceSDirk van der Merwe  * nfp_fw_load() - Load the firmware image
47463461a02SJakub Kicinski  * @pdev:       PCI Device structure
47563461a02SJakub Kicinski  * @pf:		NFP PF Device structure
47663461a02SJakub Kicinski  * @nsp:	NFP SP handle
47763461a02SJakub Kicinski  *
47863461a02SJakub Kicinski  * Return: -ERRNO, 0 for no firmware loaded, 1 for firmware loaded
47963461a02SJakub Kicinski  */
48063461a02SJakub Kicinski static int
nfp_fw_load(struct pci_dev * pdev,struct nfp_pf * pf,struct nfp_nsp * nsp)48163461a02SJakub Kicinski nfp_fw_load(struct pci_dev *pdev, struct nfp_pf *pf, struct nfp_nsp *nsp)
48263461a02SJakub Kicinski {
483f8921d73SDirk van der Merwe 	bool do_reset, fw_loaded = false;
484f8921d73SDirk van der Merwe 	const struct firmware *fw = NULL;
485f8921d73SDirk van der Merwe 	int err, reset, policy, ifcs = 0;
486f8921d73SDirk van der Merwe 	char *token, *ptr;
487f8921d73SDirk van der Merwe 	char hwinfo[64];
48863461a02SJakub Kicinski 	u16 interface;
489f8921d73SDirk van der Merwe 
490f8921d73SDirk van der Merwe 	snprintf(hwinfo, sizeof(hwinfo), "abi_drv_load_ifc");
491f8921d73SDirk van der Merwe 	err = nfp_nsp_hwinfo_lookup_optional(nsp, hwinfo, sizeof(hwinfo),
492f8921d73SDirk van der Merwe 					     NFP_NSP_DRV_LOAD_IFC_DEFAULT);
493f8921d73SDirk van der Merwe 	if (err)
494f8921d73SDirk van der Merwe 		return err;
49563461a02SJakub Kicinski 
49663461a02SJakub Kicinski 	interface = nfp_cpp_interface(pf->cpp);
497f8921d73SDirk van der Merwe 	ptr = hwinfo;
498f8921d73SDirk van der Merwe 	while ((token = strsep(&ptr, ","))) {
499f8921d73SDirk van der Merwe 		unsigned long interface_hi;
500f8921d73SDirk van der Merwe 
501f8921d73SDirk van der Merwe 		err = kstrtoul(token, 0, &interface_hi);
502f8921d73SDirk van der Merwe 		if (err) {
503f8921d73SDirk van der Merwe 			dev_err(&pdev->dev,
504f8921d73SDirk van der Merwe 				"Failed to parse interface '%s': %d\n",
505f8921d73SDirk van der Merwe 				token, err);
506f8921d73SDirk van der Merwe 			return err;
507f8921d73SDirk van der Merwe 		}
508f8921d73SDirk van der Merwe 
509f8921d73SDirk van der Merwe 		ifcs++;
510f8921d73SDirk van der Merwe 		if (interface == interface_hi)
511f8921d73SDirk van der Merwe 			break;
512f8921d73SDirk van der Merwe 	}
513f8921d73SDirk van der Merwe 
514f8921d73SDirk van der Merwe 	if (!token) {
51563461a02SJakub Kicinski 		dev_info(&pdev->dev, "Firmware will be loaded by partner\n");
51663461a02SJakub Kicinski 		return 0;
51763461a02SJakub Kicinski 	}
51863461a02SJakub Kicinski 
519f8921d73SDirk van der Merwe 	err = nfp_get_fw_policy_value(pdev, nsp, "abi_drv_reset",
520f8921d73SDirk van der Merwe 				      NFP_NSP_DRV_RESET_DEFAULT,
521f8921d73SDirk van der Merwe 				      NFP_NSP_DRV_RESET_NEVER, &reset);
522f8921d73SDirk van der Merwe 	if (err)
523f8921d73SDirk van der Merwe 		return err;
52463461a02SJakub Kicinski 
525f8921d73SDirk van der Merwe 	err = nfp_get_fw_policy_value(pdev, nsp, "app_fw_from_flash",
526f8921d73SDirk van der Merwe 				      NFP_NSP_APP_FW_LOAD_DEFAULT,
527f8921d73SDirk van der Merwe 				      NFP_NSP_APP_FW_LOAD_PREF, &policy);
528f8921d73SDirk van der Merwe 	if (err)
529f8921d73SDirk van der Merwe 		return err;
530f8921d73SDirk van der Merwe 
531f8921d73SDirk van der Merwe 	fw = nfp_net_fw_find(pdev, pf);
532f8921d73SDirk van der Merwe 	do_reset = reset == NFP_NSP_DRV_RESET_ALWAYS ||
533f8921d73SDirk van der Merwe 		   (fw && reset == NFP_NSP_DRV_RESET_DISK);
534f8921d73SDirk van der Merwe 
535f8921d73SDirk van der Merwe 	if (do_reset) {
536f8921d73SDirk van der Merwe 		dev_info(&pdev->dev, "Soft-resetting the NFP\n");
53763461a02SJakub Kicinski 		err = nfp_nsp_device_soft_reset(nsp);
53863461a02SJakub Kicinski 		if (err < 0) {
539f8921d73SDirk van der Merwe 			dev_err(&pdev->dev,
540f8921d73SDirk van der Merwe 				"Failed to soft reset the NFP: %d\n", err);
54163461a02SJakub Kicinski 			goto exit_release_fw;
54263461a02SJakub Kicinski 		}
543f8921d73SDirk van der Merwe 	}
544f8921d73SDirk van der Merwe 
545f8921d73SDirk van der Merwe 	if (fw && policy != NFP_NSP_APP_FW_LOAD_FLASH) {
546f8921d73SDirk van der Merwe 		if (nfp_nsp_has_fw_loaded(nsp) && nfp_nsp_fw_loaded(nsp))
547f8921d73SDirk van der Merwe 			goto exit_release_fw;
54863461a02SJakub Kicinski 
54963461a02SJakub Kicinski 		err = nfp_nsp_load_fw(nsp, fw);
55063461a02SJakub Kicinski 		if (err < 0) {
551f8921d73SDirk van der Merwe 			dev_err(&pdev->dev, "FW loading failed: %d\n",
552f8921d73SDirk van der Merwe 				err);
55363461a02SJakub Kicinski 			goto exit_release_fw;
55463461a02SJakub Kicinski 		}
55563461a02SJakub Kicinski 		dev_info(&pdev->dev, "Finished loading FW image\n");
556f8921d73SDirk van der Merwe 		fw_loaded = true;
557f8921d73SDirk van der Merwe 	} else if (policy != NFP_NSP_APP_FW_LOAD_DISK &&
558f8921d73SDirk van der Merwe 		   nfp_nsp_has_stored_fw_load(nsp)) {
559f8921d73SDirk van der Merwe 
560f8921d73SDirk van der Merwe 		/* Don't propagate this error to stick with legacy driver
561f8921d73SDirk van der Merwe 		 * behavior, failure will be detected later during init.
562f8921d73SDirk van der Merwe 		 */
563f8921d73SDirk van der Merwe 		if (!nfp_nsp_load_stored_fw(nsp))
564f8921d73SDirk van der Merwe 			dev_info(&pdev->dev, "Finished loading stored FW image\n");
565f8921d73SDirk van der Merwe 
566f8921d73SDirk van der Merwe 		/* Don't flag the fw_loaded in this case since other devices
567f8921d73SDirk van der Merwe 		 * may reuse the firmware when configured this way
568f8921d73SDirk van der Merwe 		 */
569f8921d73SDirk van der Merwe 	} else {
570f8921d73SDirk van der Merwe 		dev_warn(&pdev->dev, "Didn't load firmware, please update flash or reconfigure card\n");
571f8921d73SDirk van der Merwe 	}
57263461a02SJakub Kicinski 
57363461a02SJakub Kicinski exit_release_fw:
57463461a02SJakub Kicinski 	release_firmware(fw);
57563461a02SJakub Kicinski 
576f8921d73SDirk van der Merwe 	/* We don't want to unload firmware when other devices may still be
577f8921d73SDirk van der Merwe 	 * dependent on it, which could be the case if there are multiple
578f8921d73SDirk van der Merwe 	 * devices that could load firmware.
579f8921d73SDirk van der Merwe 	 */
580f8921d73SDirk van der Merwe 	if (fw_loaded && ifcs == 1)
581f8921d73SDirk van der Merwe 		pf->unload_fw_on_remove = true;
582f8921d73SDirk van der Merwe 
583f8921d73SDirk van der Merwe 	return err < 0 ? err : fw_loaded;
58463461a02SJakub Kicinski }
58563461a02SJakub Kicinski 
5867717c319SJakub Kicinski static void
nfp_nsp_init_ports(struct pci_dev * pdev,struct nfp_pf * pf,struct nfp_nsp * nsp)5877717c319SJakub Kicinski nfp_nsp_init_ports(struct pci_dev *pdev, struct nfp_pf *pf,
5887717c319SJakub Kicinski 		   struct nfp_nsp *nsp)
5897717c319SJakub Kicinski {
5907717c319SJakub Kicinski 	bool needs_reinit = false;
5917717c319SJakub Kicinski 	int i;
5927717c319SJakub Kicinski 
5937717c319SJakub Kicinski 	pf->eth_tbl = __nfp_eth_read_ports(pf->cpp, nsp);
5947717c319SJakub Kicinski 	if (!pf->eth_tbl)
5957717c319SJakub Kicinski 		return;
5967717c319SJakub Kicinski 
5977717c319SJakub Kicinski 	if (!nfp_nsp_has_mac_reinit(nsp))
5987717c319SJakub Kicinski 		return;
5997717c319SJakub Kicinski 
6007717c319SJakub Kicinski 	for (i = 0; i < pf->eth_tbl->count; i++)
6017717c319SJakub Kicinski 		needs_reinit |= pf->eth_tbl->ports[i].override_changed;
6027717c319SJakub Kicinski 	if (!needs_reinit)
6037717c319SJakub Kicinski 		return;
6047717c319SJakub Kicinski 
6057717c319SJakub Kicinski 	kfree(pf->eth_tbl);
6067717c319SJakub Kicinski 	if (nfp_nsp_mac_reinit(nsp))
6077717c319SJakub Kicinski 		dev_warn(&pdev->dev, "MAC reinit failed\n");
6087717c319SJakub Kicinski 
6097717c319SJakub Kicinski 	pf->eth_tbl = __nfp_eth_read_ports(pf->cpp, nsp);
6107717c319SJakub Kicinski }
6117717c319SJakub Kicinski 
nfp_nsp_init(struct pci_dev * pdev,struct nfp_pf * pf)612a9c83f7bSJakub Kicinski static int nfp_nsp_init(struct pci_dev *pdev, struct nfp_pf *pf)
613a9c83f7bSJakub Kicinski {
614a9c83f7bSJakub Kicinski 	struct nfp_nsp *nsp;
615a9c83f7bSJakub Kicinski 	int err;
616a9c83f7bSJakub Kicinski 
6177dbd5b75SJakub Kicinski 	err = nfp_resource_wait(pf->cpp, NFP_RESOURCE_NSP, 30);
6187dbd5b75SJakub Kicinski 	if (err)
6197dbd5b75SJakub Kicinski 		return err;
6207dbd5b75SJakub Kicinski 
621a9c83f7bSJakub Kicinski 	nsp = nfp_nsp_open(pf->cpp);
622a9c83f7bSJakub Kicinski 	if (IS_ERR(nsp)) {
623a9c83f7bSJakub Kicinski 		err = PTR_ERR(nsp);
624a9c83f7bSJakub Kicinski 		dev_err(&pdev->dev, "Failed to access the NSP: %d\n", err);
625a9c83f7bSJakub Kicinski 		return err;
626a9c83f7bSJakub Kicinski 	}
627a9c83f7bSJakub Kicinski 
628a9c83f7bSJakub Kicinski 	err = nfp_nsp_wait(nsp);
629a9c83f7bSJakub Kicinski 	if (err < 0)
630a9c83f7bSJakub Kicinski 		goto exit_close_nsp;
631a9c83f7bSJakub Kicinski 
6327717c319SJakub Kicinski 	nfp_nsp_init_ports(pdev, pf, nsp);
633a9c83f7bSJakub Kicinski 
634eefbde7eSDavid Brunecz 	pf->nspi = __nfp_nsp_identify(nsp);
635eefbde7eSDavid Brunecz 	if (pf->nspi)
636eefbde7eSDavid Brunecz 		dev_info(&pdev->dev, "BSP: %s\n", pf->nspi->version);
637010e2f9cSDavid Brunecz 
638a9c83f7bSJakub Kicinski 	err = nfp_fw_load(pdev, pf, nsp);
639a9c83f7bSJakub Kicinski 	if (err < 0) {
64047eaa23bSJakub Kicinski 		kfree(pf->nspi);
641a9c83f7bSJakub Kicinski 		kfree(pf->eth_tbl);
642a9c83f7bSJakub Kicinski 		dev_err(&pdev->dev, "Failed to load FW\n");
643a9c83f7bSJakub Kicinski 		goto exit_close_nsp;
644a9c83f7bSJakub Kicinski 	}
645a9c83f7bSJakub Kicinski 
646a9c83f7bSJakub Kicinski 	pf->fw_loaded = !!err;
647a9c83f7bSJakub Kicinski 	err = 0;
648a9c83f7bSJakub Kicinski 
649a9c83f7bSJakub Kicinski exit_close_nsp:
650a9c83f7bSJakub Kicinski 	nfp_nsp_close(nsp);
651a9c83f7bSJakub Kicinski 
652a9c83f7bSJakub Kicinski 	return err;
653a9c83f7bSJakub Kicinski }
654a9c83f7bSJakub Kicinski 
nfp_fw_unload(struct nfp_pf * pf)65563461a02SJakub Kicinski static void nfp_fw_unload(struct nfp_pf *pf)
65663461a02SJakub Kicinski {
65763461a02SJakub Kicinski 	struct nfp_nsp *nsp;
65863461a02SJakub Kicinski 	int err;
65963461a02SJakub Kicinski 
66063461a02SJakub Kicinski 	nsp = nfp_nsp_open(pf->cpp);
66163461a02SJakub Kicinski 	if (IS_ERR(nsp)) {
66263461a02SJakub Kicinski 		nfp_err(pf->cpp, "Reset failed, can't open NSP\n");
66363461a02SJakub Kicinski 		return;
66463461a02SJakub Kicinski 	}
66563461a02SJakub Kicinski 
66663461a02SJakub Kicinski 	err = nfp_nsp_device_soft_reset(nsp);
66763461a02SJakub Kicinski 	if (err < 0)
66863461a02SJakub Kicinski 		dev_warn(&pf->pdev->dev, "Couldn't unload firmware: %d\n", err);
66963461a02SJakub Kicinski 	else
67063461a02SJakub Kicinski 		dev_info(&pf->pdev->dev, "Firmware safely unloaded\n");
67163461a02SJakub Kicinski 
67263461a02SJakub Kicinski 	nfp_nsp_close(nsp);
67363461a02SJakub Kicinski }
67463461a02SJakub Kicinski 
nfp_pf_find_rtsyms(struct nfp_pf * pf)6750c693323SJakub Kicinski static int nfp_pf_find_rtsyms(struct nfp_pf *pf)
6760c693323SJakub Kicinski {
6770c693323SJakub Kicinski 	char pf_symbol[256];
6780c693323SJakub Kicinski 	unsigned int pf_id;
6790c693323SJakub Kicinski 
6800c693323SJakub Kicinski 	pf_id = nfp_cppcore_pcie_unit(pf->cpp);
6810c693323SJakub Kicinski 
6820c693323SJakub Kicinski 	/* Optional per-PCI PF mailbox */
6830c693323SJakub Kicinski 	snprintf(pf_symbol, sizeof(pf_symbol), NFP_MBOX_SYM_NAME, pf_id);
6840c693323SJakub Kicinski 	pf->mbox = nfp_rtsym_lookup(pf->rtbl, pf_symbol);
6854152e58cSJakub Kicinski 	if (pf->mbox && nfp_rtsym_size(pf->mbox) < NFP_MBOX_SYM_MIN_SIZE) {
6860c693323SJakub Kicinski 		nfp_err(pf->cpp, "PF mailbox symbol too small: %llu < %d\n",
6874152e58cSJakub Kicinski 			nfp_rtsym_size(pf->mbox), NFP_MBOX_SYM_MIN_SIZE);
6880c693323SJakub Kicinski 		return -EINVAL;
6890c693323SJakub Kicinski 	}
6900c693323SJakub Kicinski 
6910c693323SJakub Kicinski 	return 0;
6920c693323SJakub Kicinski }
6930c693323SJakub Kicinski 
nfp_net_pf_get_app_id(struct nfp_pf * pf)694b1e4f11eSYinjun Zhang int nfp_net_pf_get_app_id(struct nfp_pf *pf)
695b1e4f11eSYinjun Zhang {
696b1e4f11eSYinjun Zhang 	return nfp_pf_rtsym_read_optional(pf, "_pf%u_net_app_id",
697b1e4f11eSYinjun Zhang 					  NFP_APP_CORE_NIC);
698b1e4f11eSYinjun Zhang }
699b1e4f11eSYinjun Zhang 
nfp_net_pf_get_app_cap(struct nfp_pf * pf)700b1e4f11eSYinjun Zhang static u64 nfp_net_pf_get_app_cap(struct nfp_pf *pf)
701b1e4f11eSYinjun Zhang {
702b1e4f11eSYinjun Zhang 	char name[32];
703b1e4f11eSYinjun Zhang 	int err = 0;
704b1e4f11eSYinjun Zhang 	u64 val;
705b1e4f11eSYinjun Zhang 
706b1e4f11eSYinjun Zhang 	snprintf(name, sizeof(name), "_pf%u_net_app_cap", nfp_cppcore_pcie_unit(pf->cpp));
707b1e4f11eSYinjun Zhang 
708b1e4f11eSYinjun Zhang 	val = nfp_rtsym_read_le(pf->rtbl, name, &err);
709b1e4f11eSYinjun Zhang 	if (err) {
710b1e4f11eSYinjun Zhang 		if (err != -ENOENT)
711b1e4f11eSYinjun Zhang 			nfp_err(pf->cpp, "Unable to read symbol %s\n", name);
712b1e4f11eSYinjun Zhang 
713b1e4f11eSYinjun Zhang 		return 0;
714b1e4f11eSYinjun Zhang 	}
715b1e4f11eSYinjun Zhang 
716b1e4f11eSYinjun Zhang 	return val;
717b1e4f11eSYinjun Zhang }
718b1e4f11eSYinjun Zhang 
nfp_pf_cfg_hwinfo(struct nfp_pf * pf)719*0bda0362SYinjun Zhang static void nfp_pf_cfg_hwinfo(struct nfp_pf *pf)
720b1e4f11eSYinjun Zhang {
721b1e4f11eSYinjun Zhang 	struct nfp_nsp *nsp;
722b1e4f11eSYinjun Zhang 	char hwinfo[32];
723*0bda0362SYinjun Zhang 	bool sp_indiff;
724b1e4f11eSYinjun Zhang 	int err;
725b1e4f11eSYinjun Zhang 
726b1e4f11eSYinjun Zhang 	nsp = nfp_nsp_open(pf->cpp);
727b1e4f11eSYinjun Zhang 	if (IS_ERR(nsp))
728*0bda0362SYinjun Zhang 		return;
729b1e4f11eSYinjun Zhang 
730*0bda0362SYinjun Zhang 	if (!nfp_nsp_has_hwinfo_set(nsp))
731*0bda0362SYinjun Zhang 		goto end;
732*0bda0362SYinjun Zhang 
733*0bda0362SYinjun Zhang 	sp_indiff = (nfp_net_pf_get_app_id(pf) == NFP_APP_FLOWER_NIC) ||
734*0bda0362SYinjun Zhang 		    (nfp_net_pf_get_app_cap(pf) & NFP_NET_APP_CAP_SP_INDIFF);
735*0bda0362SYinjun Zhang 
736*0bda0362SYinjun Zhang 	/* No need to clean `sp_indiff` in driver, management firmware
737*0bda0362SYinjun Zhang 	 * will do it when application firmware is unloaded.
738*0bda0362SYinjun Zhang 	 */
739b1e4f11eSYinjun Zhang 	snprintf(hwinfo, sizeof(hwinfo), "sp_indiff=%d", sp_indiff);
740b1e4f11eSYinjun Zhang 	err = nfp_nsp_hwinfo_set(nsp, hwinfo, sizeof(hwinfo));
741b1e4f11eSYinjun Zhang 	/* Not a fatal error, no need to return error to stop driver from loading */
7428d545385SYinjun Zhang 	if (err) {
743b1e4f11eSYinjun Zhang 		nfp_warn(pf->cpp, "HWinfo(sp_indiff=%d) set failed: %d\n", sp_indiff, err);
7448d545385SYinjun Zhang 	} else {
7458d545385SYinjun Zhang 		/* Need reinit eth_tbl since the eth table state may change
7468d545385SYinjun Zhang 		 * after sp_indiff is configured.
7478d545385SYinjun Zhang 		 */
7488d545385SYinjun Zhang 		kfree(pf->eth_tbl);
7498d545385SYinjun Zhang 		pf->eth_tbl = __nfp_eth_read_ports(pf->cpp, nsp);
7508d545385SYinjun Zhang 	}
751b1e4f11eSYinjun Zhang 
752*0bda0362SYinjun Zhang end:
753b1e4f11eSYinjun Zhang 	nfp_nsp_close(nsp);
754b1e4f11eSYinjun Zhang }
755b1e4f11eSYinjun Zhang 
nfp_pci_probe(struct pci_dev * pdev,const struct pci_device_id * pci_id)75663461a02SJakub Kicinski static int nfp_pci_probe(struct pci_dev *pdev,
75763461a02SJakub Kicinski 			 const struct pci_device_id *pci_id)
75863461a02SJakub Kicinski {
7599423d24bSJakub Kicinski 	const struct nfp_dev_info *dev_info;
7601851f93fSSimon Horman 	struct devlink *devlink;
76163461a02SJakub Kicinski 	struct nfp_pf *pf;
76263461a02SJakub Kicinski 	int err;
76363461a02SJakub Kicinski 
764299ba7a3SYu Xiao 	if ((pdev->vendor == PCI_VENDOR_ID_NETRONOME ||
765299ba7a3SYu Xiao 	     pdev->vendor == PCI_VENDOR_ID_CORIGINE) &&
766299ba7a3SYu Xiao 	    (pdev->device == PCI_DEVICE_ID_NFP3800_VF ||
767299ba7a3SYu Xiao 	     pdev->device == PCI_DEVICE_ID_NFP6000_VF))
768f767fc66SJakub Kicinski 		dev_warn(&pdev->dev, "Binding NFP VF device to the NFP PF driver, the VF driver is called 'nfp_netvf'\n");
769f767fc66SJakub Kicinski 
7709423d24bSJakub Kicinski 	dev_info = &nfp_dev_info[pci_id->driver_data];
7719423d24bSJakub Kicinski 
77263461a02SJakub Kicinski 	err = pci_enable_device(pdev);
77363461a02SJakub Kicinski 	if (err < 0)
77463461a02SJakub Kicinski 		return err;
77563461a02SJakub Kicinski 
77663461a02SJakub Kicinski 	pci_set_master(pdev);
77763461a02SJakub Kicinski 
7789ba1dc99SJakub Kicinski 	err = dma_set_mask_and_coherent(&pdev->dev, dev_info->dma_mask);
77963461a02SJakub Kicinski 	if (err)
78063461a02SJakub Kicinski 		goto err_pci_disable;
78163461a02SJakub Kicinski 
78263461a02SJakub Kicinski 	err = pci_request_regions(pdev, nfp_driver_name);
78363461a02SJakub Kicinski 	if (err < 0) {
78463461a02SJakub Kicinski 		dev_err(&pdev->dev, "Unable to reserve pci resources.\n");
78563461a02SJakub Kicinski 		goto err_pci_disable;
78663461a02SJakub Kicinski 	}
78763461a02SJakub Kicinski 
788919d13a7SLeon Romanovsky 	devlink = devlink_alloc(&nfp_devlink_ops, sizeof(*pf), &pdev->dev);
7891851f93fSSimon Horman 	if (!devlink) {
79063461a02SJakub Kicinski 		err = -ENOMEM;
79163461a02SJakub Kicinski 		goto err_rel_regions;
79263461a02SJakub Kicinski 	}
7931851f93fSSimon Horman 	pf = devlink_priv(devlink);
794d4e7f092SJakub Kicinski 	INIT_LIST_HEAD(&pf->vnics);
7953eb3b74aSJakub Kicinski 	INIT_LIST_HEAD(&pf->ports);
79663461a02SJakub Kicinski 	pci_set_drvdata(pdev, pf);
79763461a02SJakub Kicinski 	pf->pdev = pdev;
7989423d24bSJakub Kicinski 	pf->dev_info = dev_info;
79963461a02SJakub Kicinski 
8006d48ceb2SJakub Kicinski 	pf->wq = alloc_workqueue("nfp-%s", 0, 2, pci_name(pdev));
8016d48ceb2SJakub Kicinski 	if (!pf->wq) {
8026d48ceb2SJakub Kicinski 		err = -ENOMEM;
8036d48ceb2SJakub Kicinski 		goto err_pci_priv_unset;
8046d48ceb2SJakub Kicinski 	}
8056d48ceb2SJakub Kicinski 
8069423d24bSJakub Kicinski 	pf->cpp = nfp_cpp_from_nfp6000_pcie(pdev, dev_info);
80795530a59SYueHaibing 	if (IS_ERR(pf->cpp)) {
80863461a02SJakub Kicinski 		err = PTR_ERR(pf->cpp);
80963461a02SJakub Kicinski 		goto err_disable_msix;
81063461a02SJakub Kicinski 	}
81163461a02SJakub Kicinski 
8123e3e9fd8SJakub Kicinski 	err = nfp_resource_table_init(pf->cpp);
8133e3e9fd8SJakub Kicinski 	if (err)
8143e3e9fd8SJakub Kicinski 		goto err_cpp_free;
8153e3e9fd8SJakub Kicinski 
8169baa4885SJakub Kicinski 	pf->hwinfo = nfp_hwinfo_read(pf->cpp);
8179baa4885SJakub Kicinski 
81864db09edSJakub Kicinski 	dev_info(&pdev->dev, "Assembly: %s%s%s-%s CPLD: %s\n",
8199baa4885SJakub Kicinski 		 nfp_hwinfo_lookup(pf->hwinfo, "assembly.vendor"),
8209baa4885SJakub Kicinski 		 nfp_hwinfo_lookup(pf->hwinfo, "assembly.partno"),
8219baa4885SJakub Kicinski 		 nfp_hwinfo_lookup(pf->hwinfo, "assembly.serial"),
8229baa4885SJakub Kicinski 		 nfp_hwinfo_lookup(pf->hwinfo, "assembly.revision"),
8239baa4885SJakub Kicinski 		 nfp_hwinfo_lookup(pf->hwinfo, "cpld.version"));
82464db09edSJakub Kicinski 
8254cbe94f2SJakub Kicinski 	err = nfp_pf_board_state_wait(pf);
8264cbe94f2SJakub Kicinski 	if (err)
8274cbe94f2SJakub Kicinski 		goto err_hwinfo_free;
8284cbe94f2SJakub Kicinski 
8291851f93fSSimon Horman 	err = nfp_nsp_init(pdev, pf);
8301851f93fSSimon Horman 	if (err)
831bcc93a23SJakub Kicinski 		goto err_hwinfo_free;
8321851f93fSSimon Horman 
8330be40e66SJakub Kicinski 	pf->mip = nfp_mip_open(pf->cpp);
8340be40e66SJakub Kicinski 	pf->rtbl = __nfp_rtsym_table_read(pf->cpp, pf->mip);
835af4fa7eaSJakub Kicinski 
8360c693323SJakub Kicinski 	err = nfp_pf_find_rtsyms(pf);
8370c693323SJakub Kicinski 	if (err)
8380c693323SJakub Kicinski 		goto err_fw_unload;
8390c693323SJakub Kicinski 
840d79e19f5SCarl Heymann 	pf->dump_flag = NFP_DUMP_NSP_DIAG;
841d79e19f5SCarl Heymann 	pf->dumpspec = nfp_net_dump_load_dumpspec(pf->cpp, pf->rtbl);
842d79e19f5SCarl Heymann 
843651e1f2fSJakub Kicinski 	err = nfp_pcie_sriov_read_nfd_limit(pf);
84463461a02SJakub Kicinski 	if (err)
84563461a02SJakub Kicinski 		goto err_fw_unload;
84663461a02SJakub Kicinski 
8470dc78621SJakub Kicinski 	pf->num_vfs = pci_num_vf(pdev);
8480dc78621SJakub Kicinski 	if (pf->num_vfs > pf->limit_vfs) {
8490dc78621SJakub Kicinski 		dev_err(&pdev->dev,
8500dc78621SJakub Kicinski 			"Error: %d VFs already enabled, but loaded FW can only support %d\n",
8510dc78621SJakub Kicinski 			pf->num_vfs, pf->limit_vfs);
852e58decc9SWei Yongjun 		err = -EINVAL;
8530dc78621SJakub Kicinski 		goto err_fw_unload;
8540dc78621SJakub Kicinski 	}
8550dc78621SJakub Kicinski 
856*0bda0362SYinjun Zhang 	nfp_pf_cfg_hwinfo(pf);
857651e1f2fSJakub Kicinski 
858b1e4f11eSYinjun Zhang 	err = nfp_net_pci_probe(pf);
859b1e4f11eSYinjun Zhang 	if (err)
860*0bda0362SYinjun Zhang 		goto err_fw_unload;
861b1e4f11eSYinjun Zhang 
862eefbde7eSDavid Brunecz 	err = nfp_hwmon_register(pf);
863eefbde7eSDavid Brunecz 	if (err) {
864eefbde7eSDavid Brunecz 		dev_err(&pdev->dev, "Failed to register hwmon info\n");
865eefbde7eSDavid Brunecz 		goto err_net_remove;
866eefbde7eSDavid Brunecz 	}
867eefbde7eSDavid Brunecz 
86863461a02SJakub Kicinski 	return 0;
86963461a02SJakub Kicinski 
870eefbde7eSDavid Brunecz err_net_remove:
871eefbde7eSDavid Brunecz 	nfp_net_pci_remove(pf);
87263461a02SJakub Kicinski err_fw_unload:
873af4fa7eaSJakub Kicinski 	kfree(pf->rtbl);
8740be40e66SJakub Kicinski 	nfp_mip_close(pf->mip);
875f8921d73SDirk van der Merwe 	if (pf->unload_fw_on_remove)
87663461a02SJakub Kicinski 		nfp_fw_unload(pf);
87763461a02SJakub Kicinski 	kfree(pf->eth_tbl);
878eefbde7eSDavid Brunecz 	kfree(pf->nspi);
879d79e19f5SCarl Heymann 	vfree(pf->dumpspec);
8809baa4885SJakub Kicinski err_hwinfo_free:
8819baa4885SJakub Kicinski 	kfree(pf->hwinfo);
8823e3e9fd8SJakub Kicinski err_cpp_free:
88363461a02SJakub Kicinski 	nfp_cpp_free(pf->cpp);
88463461a02SJakub Kicinski err_disable_msix:
8856d48ceb2SJakub Kicinski 	destroy_workqueue(pf->wq);
8866d48ceb2SJakub Kicinski err_pci_priv_unset:
88763461a02SJakub Kicinski 	pci_set_drvdata(pdev, NULL);
8881851f93fSSimon Horman 	devlink_free(devlink);
88963461a02SJakub Kicinski err_rel_regions:
89063461a02SJakub Kicinski 	pci_release_regions(pdev);
89163461a02SJakub Kicinski err_pci_disable:
89263461a02SJakub Kicinski 	pci_disable_device(pdev);
89363461a02SJakub Kicinski 
89463461a02SJakub Kicinski 	return err;
89563461a02SJakub Kicinski }
89663461a02SJakub Kicinski 
__nfp_pci_shutdown(struct pci_dev * pdev,bool unload_fw)897790d23e7SDirk van der Merwe static void __nfp_pci_shutdown(struct pci_dev *pdev, bool unload_fw)
89863461a02SJakub Kicinski {
899790d23e7SDirk van der Merwe 	struct nfp_pf *pf;
900790d23e7SDirk van der Merwe 
901790d23e7SDirk van der Merwe 	pf = pci_get_drvdata(pdev);
902790d23e7SDirk van der Merwe 	if (!pf)
903790d23e7SDirk van der Merwe 		return;
9041851f93fSSimon Horman 
905eefbde7eSDavid Brunecz 	nfp_hwmon_unregister(pf);
906eefbde7eSDavid Brunecz 
90763461a02SJakub Kicinski 	nfp_pcie_sriov_disable(pdev);
90863461a02SJakub Kicinski 
909bcc93a23SJakub Kicinski 	nfp_net_pci_remove(pf);
9101851f93fSSimon Horman 
911d79e19f5SCarl Heymann 	vfree(pf->dumpspec);
912af4fa7eaSJakub Kicinski 	kfree(pf->rtbl);
9130be40e66SJakub Kicinski 	nfp_mip_close(pf->mip);
914f8921d73SDirk van der Merwe 	if (unload_fw && pf->unload_fw_on_remove)
91563461a02SJakub Kicinski 		nfp_fw_unload(pf);
91663461a02SJakub Kicinski 
9176d48ceb2SJakub Kicinski 	destroy_workqueue(pf->wq);
91863461a02SJakub Kicinski 	pci_set_drvdata(pdev, NULL);
9199baa4885SJakub Kicinski 	kfree(pf->hwinfo);
92063461a02SJakub Kicinski 	nfp_cpp_free(pf->cpp);
92163461a02SJakub Kicinski 
92263461a02SJakub Kicinski 	kfree(pf->eth_tbl);
923eefbde7eSDavid Brunecz 	kfree(pf->nspi);
924bcc93a23SJakub Kicinski 	devlink_free(priv_to_devlink(pf));
92563461a02SJakub Kicinski 	pci_release_regions(pdev);
92663461a02SJakub Kicinski 	pci_disable_device(pdev);
92763461a02SJakub Kicinski }
92863461a02SJakub Kicinski 
nfp_pci_remove(struct pci_dev * pdev)929790d23e7SDirk van der Merwe static void nfp_pci_remove(struct pci_dev *pdev)
930790d23e7SDirk van der Merwe {
931790d23e7SDirk van der Merwe 	__nfp_pci_shutdown(pdev, true);
932790d23e7SDirk van der Merwe }
933790d23e7SDirk van der Merwe 
nfp_pci_shutdown(struct pci_dev * pdev)934790d23e7SDirk van der Merwe static void nfp_pci_shutdown(struct pci_dev *pdev)
935790d23e7SDirk van der Merwe {
936790d23e7SDirk van der Merwe 	__nfp_pci_shutdown(pdev, false);
937790d23e7SDirk van der Merwe }
938790d23e7SDirk van der Merwe 
93963461a02SJakub Kicinski static struct pci_driver nfp_pci_driver = {
94063461a02SJakub Kicinski 	.name			= nfp_driver_name,
94163461a02SJakub Kicinski 	.id_table		= nfp_pci_device_ids,
94263461a02SJakub Kicinski 	.probe			= nfp_pci_probe,
94363461a02SJakub Kicinski 	.remove			= nfp_pci_remove,
944790d23e7SDirk van der Merwe 	.shutdown		= nfp_pci_shutdown,
94563461a02SJakub Kicinski 	.sriov_configure	= nfp_pcie_sriov_configure,
94663461a02SJakub Kicinski };
94763461a02SJakub Kicinski 
nfp_main_init(void)9482633beb9SJakub Kicinski static int __init nfp_main_init(void)
9492633beb9SJakub Kicinski {
9502633beb9SJakub Kicinski 	int err;
9512633beb9SJakub Kicinski 
95234e244eaSYu Xiao 	pr_info("%s: NFP PCIe Driver, Copyright (C) 2014-2020 Netronome Systems\n",
95334e244eaSYu Xiao 		nfp_driver_name);
95434e244eaSYu Xiao 	pr_info("%s: NFP PCIe Driver, Copyright (C) 2021-2022 Corigine Inc.\n",
9552633beb9SJakub Kicinski 		nfp_driver_name);
9562633beb9SJakub Kicinski 
9572633beb9SJakub Kicinski 	nfp_net_debugfs_create();
9582633beb9SJakub Kicinski 
95963461a02SJakub Kicinski 	err = pci_register_driver(&nfp_pci_driver);
96063461a02SJakub Kicinski 	if (err < 0)
96163461a02SJakub Kicinski 		goto err_destroy_debugfs;
96263461a02SJakub Kicinski 
9632633beb9SJakub Kicinski 	err = pci_register_driver(&nfp_netvf_pci_driver);
9642633beb9SJakub Kicinski 	if (err)
96563461a02SJakub Kicinski 		goto err_unreg_pf;
9662633beb9SJakub Kicinski 
9672633beb9SJakub Kicinski 	return err;
9682633beb9SJakub Kicinski 
96963461a02SJakub Kicinski err_unreg_pf:
97063461a02SJakub Kicinski 	pci_unregister_driver(&nfp_pci_driver);
9712633beb9SJakub Kicinski err_destroy_debugfs:
9722633beb9SJakub Kicinski 	nfp_net_debugfs_destroy();
9732633beb9SJakub Kicinski 	return err;
9742633beb9SJakub Kicinski }
9752633beb9SJakub Kicinski 
nfp_main_exit(void)9762633beb9SJakub Kicinski static void __exit nfp_main_exit(void)
9772633beb9SJakub Kicinski {
9782633beb9SJakub Kicinski 	pci_unregister_driver(&nfp_netvf_pci_driver);
97963461a02SJakub Kicinski 	pci_unregister_driver(&nfp_pci_driver);
9802633beb9SJakub Kicinski 	nfp_net_debugfs_destroy();
9812633beb9SJakub Kicinski }
9822633beb9SJakub Kicinski 
9832633beb9SJakub Kicinski module_init(nfp_main_init);
9842633beb9SJakub Kicinski module_exit(nfp_main_exit);
9852633beb9SJakub Kicinski 
986d00ee466SJakub Kicinski MODULE_FIRMWARE("netronome/nic_AMDA0058-0011_2x40.nffw");
987d00ee466SJakub Kicinski MODULE_FIRMWARE("netronome/nic_AMDA0058-0012_2x40.nffw");
98863461a02SJakub Kicinski MODULE_FIRMWARE("netronome/nic_AMDA0081-0001_1x40.nffw");
98963461a02SJakub Kicinski MODULE_FIRMWARE("netronome/nic_AMDA0081-0001_4x10.nffw");
99063461a02SJakub Kicinski MODULE_FIRMWARE("netronome/nic_AMDA0096-0001_2x10.nffw");
99163461a02SJakub Kicinski MODULE_FIRMWARE("netronome/nic_AMDA0097-0001_2x40.nffw");
99263461a02SJakub Kicinski MODULE_FIRMWARE("netronome/nic_AMDA0097-0001_4x10_1x40.nffw");
99363461a02SJakub Kicinski MODULE_FIRMWARE("netronome/nic_AMDA0097-0001_8x10.nffw");
99463461a02SJakub Kicinski MODULE_FIRMWARE("netronome/nic_AMDA0099-0001_2x10.nffw");
99563461a02SJakub Kicinski MODULE_FIRMWARE("netronome/nic_AMDA0099-0001_2x25.nffw");
99670271dadSDirk van der Merwe MODULE_FIRMWARE("netronome/nic_AMDA0099-0001_1x10_1x25.nffw");
99763461a02SJakub Kicinski 
99834e244eaSYu Xiao MODULE_AUTHOR("Corigine, Inc. <oss-drivers@corigine.com>");
9992633beb9SJakub Kicinski MODULE_LICENSE("GPL");
100034e244eaSYu Xiao MODULE_DESCRIPTION("The Network Flow Processor (NFP) driver.");
1001