Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit e8846a56 authored by David S. Miller's avatar David S. Miller
Browse files

Merge branch 'nfp-next'



Jakub Kicinski says:

====================
nfp: expose more firmware and hw debug info

This series is mostly a result of flash firmware team requesting
access to some of the information and data necessary for debugging
firmware problems.  Patch 1 adds a missing error message.  Patch 2
prints manufacturing info to logs in case PCI VPD capability is
not programmed correctly.  Patches 3 and 4 allow reporting NSP ABI
version in ethtool -i.  Patch 5 allows dumping flash application
logs.

Patches 6 and 7 provides a way of application firmwares to declare
limited SR-IOV support.

v2: put some of the code in patch 7 in #ifdef CONFIG_PCI_SRIOV (Yuval).
====================

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents c1ceee5e 0bc3827f
Loading
Loading
Loading
Loading
+66 −21
Original line number Original line Diff line number Diff line
@@ -47,6 +47,7 @@


#include "nfpcore/nfp.h"
#include "nfpcore/nfp.h"
#include "nfpcore/nfp_cpp.h"
#include "nfpcore/nfp_cpp.h"
#include "nfpcore/nfp_nffw.h"
#include "nfpcore/nfp_nsp_eth.h"
#include "nfpcore/nfp_nsp_eth.h"


#include "nfpcore/nfp6000_pcie.h"
#include "nfpcore/nfp6000_pcie.h"
@@ -70,12 +71,34 @@ static const struct pci_device_id nfp_pci_device_ids[] = {
};
};
MODULE_DEVICE_TABLE(pci, nfp_pci_device_ids);
MODULE_DEVICE_TABLE(pci, nfp_pci_device_ids);


static void nfp_pcie_sriov_read_nfd_limit(struct nfp_pf *pf)
{
#ifdef CONFIG_PCI_IOV
	int err;

	pf->limit_vfs = nfp_rtsym_read_le(pf->cpp, "nfd_vf_cfg_max_vfs", &err);
	if (!err)
		return;

	pf->limit_vfs = ~0;
	/* Allow any setting for backwards compatibility if symbol not found */
	if (err != -ENOENT)
		nfp_warn(pf->cpp, "Warning: VF limit read failed: %d\n", err);
#endif
}

static int nfp_pcie_sriov_enable(struct pci_dev *pdev, int num_vfs)
static int nfp_pcie_sriov_enable(struct pci_dev *pdev, int num_vfs)
{
{
#ifdef CONFIG_PCI_IOV
#ifdef CONFIG_PCI_IOV
	struct nfp_pf *pf = pci_get_drvdata(pdev);
	struct nfp_pf *pf = pci_get_drvdata(pdev);
	int err;
	int err;


	if (num_vfs > pf->limit_vfs) {
		nfp_info(pf->cpp, "Firmware limits number of VFs to %u\n",
			 pf->limit_vfs);
		return -EINVAL;
	}

	err = pci_enable_sriov(pdev, num_vfs);
	err = pci_enable_sriov(pdev, num_vfs);
	if (err) {
	if (err) {
		dev_warn(&pdev->dev, "Failed to enable PCI sriov: %d\n", err);
		dev_warn(&pdev->dev, "Failed to enable PCI sriov: %d\n", err);
@@ -228,6 +251,40 @@ nfp_fw_load(struct pci_dev *pdev, struct nfp_pf *pf, struct nfp_nsp *nsp)
	return err < 0 ? err : 1;
	return err < 0 ? err : 1;
}
}


static int nfp_nsp_init(struct pci_dev *pdev, struct nfp_pf *pf)
{
	struct nfp_nsp *nsp;
	int err;

	nsp = nfp_nsp_open(pf->cpp);
	if (IS_ERR(nsp)) {
		err = PTR_ERR(nsp);
		dev_err(&pdev->dev, "Failed to access the NSP: %d\n", err);
		return err;
	}

	err = nfp_nsp_wait(nsp);
	if (err < 0)
		goto exit_close_nsp;

	pf->eth_tbl = __nfp_eth_read_ports(pf->cpp, nsp);

	err = nfp_fw_load(pdev, pf, nsp);
	if (err < 0) {
		kfree(pf->eth_tbl);
		dev_err(&pdev->dev, "Failed to load FW\n");
		goto exit_close_nsp;
	}

	pf->fw_loaded = !!err;
	err = 0;

exit_close_nsp:
	nfp_nsp_close(nsp);

	return err;
}

static void nfp_fw_unload(struct nfp_pf *pf)
static void nfp_fw_unload(struct nfp_pf *pf)
{
{
	struct nfp_nsp *nsp;
	struct nfp_nsp *nsp;
@@ -251,7 +308,6 @@ static void nfp_fw_unload(struct nfp_pf *pf)
static int nfp_pci_probe(struct pci_dev *pdev,
static int nfp_pci_probe(struct pci_dev *pdev,
			 const struct pci_device_id *pci_id)
			 const struct pci_device_id *pci_id)
{
{
	struct nfp_nsp *nsp;
	struct nfp_pf *pf;
	struct nfp_pf *pf;
	int err;
	int err;


@@ -289,28 +345,18 @@ static int nfp_pci_probe(struct pci_dev *pdev,
		goto err_disable_msix;
		goto err_disable_msix;
	}
	}


	nsp = nfp_nsp_open(pf->cpp);
	dev_info(&pdev->dev, "Assembly: %s%s%s-%s CPLD: %s\n",
	if (IS_ERR(nsp)) {
		 nfp_hwinfo_lookup(pf->cpp, "assembly.vendor"),
		err = PTR_ERR(nsp);
		 nfp_hwinfo_lookup(pf->cpp, "assembly.partno"),
		goto err_cpp_free;
		 nfp_hwinfo_lookup(pf->cpp, "assembly.serial"),
	}
		 nfp_hwinfo_lookup(pf->cpp, "assembly.revision"),
		 nfp_hwinfo_lookup(pf->cpp, "cpld.version"));


	err = nfp_nsp_wait(nsp);
	err = nfp_nsp_init(pdev, pf);
	if (err < 0) {
	if (err)
		nfp_nsp_close(nsp);
		goto err_cpp_free;
		goto err_cpp_free;
	}

	pf->eth_tbl = __nfp_eth_read_ports(pf->cpp, nsp);


	err = nfp_fw_load(pdev, pf, nsp);
	nfp_pcie_sriov_read_nfd_limit(pf);
	nfp_nsp_close(nsp);
	if (err < 0) {
		dev_err(&pdev->dev, "Failed to load FW\n");
		goto err_eth_tbl_free;
	}

	pf->fw_loaded = !!err;


	err = nfp_net_pci_probe(pf);
	err = nfp_net_pci_probe(pf);
	if (err)
	if (err)
@@ -321,7 +367,6 @@ static int nfp_pci_probe(struct pci_dev *pdev,
err_fw_unload:
err_fw_unload:
	if (pf->fw_loaded)
	if (pf->fw_loaded)
		nfp_fw_unload(pf);
		nfp_fw_unload(pf);
err_eth_tbl_free:
	kfree(pf->eth_tbl);
	kfree(pf->eth_tbl);
err_cpp_free:
err_cpp_free:
	nfp_cpp_free(pf->cpp);
	nfp_cpp_free(pf->cpp);
+2 −0
Original line number Original line Diff line number Diff line
@@ -59,6 +59,7 @@ struct nfp_eth_table;
 * @tx_area:		Pointer to the CPP area for the TX queues
 * @tx_area:		Pointer to the CPP area for the TX queues
 * @rx_area:		Pointer to the CPP area for the FL/RX queues
 * @rx_area:		Pointer to the CPP area for the FL/RX queues
 * @irq_entries:	Array of MSI-X entries for all ports
 * @irq_entries:	Array of MSI-X entries for all ports
 * @limit_vfs:		Number of VFs supported by firmware (~0 for PCI limit)
 * @num_vfs:		Number of SR-IOV VFs enabled
 * @num_vfs:		Number of SR-IOV VFs enabled
 * @fw_loaded:		Is the firmware loaded?
 * @fw_loaded:		Is the firmware loaded?
 * @eth_tbl:		NSP ETH table
 * @eth_tbl:		NSP ETH table
@@ -77,6 +78,7 @@ struct nfp_pf {


	struct msix_entry *irq_entries;
	struct msix_entry *irq_entries;


	unsigned int limit_vfs;
	unsigned int num_vfs;
	unsigned int num_vfs;


	bool fw_loaded;
	bool fw_loaded;
+6 −0
Original line number Original line Diff line number Diff line
@@ -111,6 +111,7 @@
				 SKB_DATA_ALIGN(sizeof(struct skb_shared_info)))
				 SKB_DATA_ALIGN(sizeof(struct skb_shared_info)))


/* Forward declarations */
/* Forward declarations */
struct nfp_cpp;
struct nfp_net;
struct nfp_net;
struct nfp_net_r_vector;
struct nfp_net_r_vector;


@@ -491,7 +492,9 @@ struct nfp_stat_pair {
 * @tx_bar:             Pointer to mapped TX queues
 * @tx_bar:             Pointer to mapped TX queues
 * @rx_bar:             Pointer to mapped FL/RX queues
 * @rx_bar:             Pointer to mapped FL/RX queues
 * @debugfs_dir:	Device directory in debugfs
 * @debugfs_dir:	Device directory in debugfs
 * @ethtool_dump_flag:	Ethtool dump flag
 * @port_list:		Entry on device port list
 * @port_list:		Entry on device port list
 * @cpp:		CPP device handle if available
 */
 */
struct nfp_net {
struct nfp_net {
	struct pci_dev *pdev;
	struct pci_dev *pdev;
@@ -577,8 +580,11 @@ struct nfp_net {
	u8 __iomem *rx_bar;
	u8 __iomem *rx_bar;


	struct dentry *debugfs_dir;
	struct dentry *debugfs_dir;
	u32 ethtool_dump_flag;


	struct list_head port_list;
	struct list_head port_list;

	struct nfp_cpp *cpp;
};
};


struct nfp_net_ring_set {
struct nfp_net_ring_set {
+99 −2
Original line number Original line Diff line number Diff line
@@ -47,9 +47,14 @@
#include <linux/pci.h>
#include <linux/pci.h>
#include <linux/ethtool.h>
#include <linux/ethtool.h>


#include "nfpcore/nfp.h"
#include "nfp_net_ctrl.h"
#include "nfp_net_ctrl.h"
#include "nfp_net.h"
#include "nfp_net.h"


enum nfp_dump_diag {
	NFP_DUMP_NSP_DIAG = 0,
};

/* Support for stats. Returns netdev, driver, and device stats */
/* Support for stats. Returns netdev, driver, and device stats */
enum { NETDEV_ET_STATS, NFP_NET_DRV_ET_STATS, NFP_NET_DEV_ET_STATS };
enum { NETDEV_ET_STATS, NFP_NET_DRV_ET_STATS, NFP_NET_DEV_ET_STATS };
struct _nfp_net_et_stats {
struct _nfp_net_et_stats {
@@ -127,19 +132,39 @@ static const struct _nfp_net_et_stats nfp_net_et_stats[] = {
#define NN_ET_STATS_LEN (NN_ET_GLOBAL_STATS_LEN + NN_ET_RVEC_GATHER_STATS + \
#define NN_ET_STATS_LEN (NN_ET_GLOBAL_STATS_LEN + NN_ET_RVEC_GATHER_STATS + \
			 NN_ET_RVEC_STATS_LEN + NN_ET_QUEUE_STATS_LEN)
			 NN_ET_RVEC_STATS_LEN + NN_ET_QUEUE_STATS_LEN)


static void nfp_net_get_nspinfo(struct nfp_net *nn, char *version)
{
	struct nfp_nsp *nsp;

	if (!nn->cpp)
		return;

	nsp = nfp_nsp_open(nn->cpp);
	if (IS_ERR(nsp))
		return;

	snprintf(version, ETHTOOL_FWVERS_LEN, "sp:%hu.%hu",
		 nfp_nsp_get_abi_ver_major(nsp),
		 nfp_nsp_get_abi_ver_minor(nsp));

	nfp_nsp_close(nsp);
}

static void nfp_net_get_drvinfo(struct net_device *netdev,
static void nfp_net_get_drvinfo(struct net_device *netdev,
				struct ethtool_drvinfo *drvinfo)
				struct ethtool_drvinfo *drvinfo)
{
{
	char nsp_version[ETHTOOL_FWVERS_LEN] = {};
	struct nfp_net *nn = netdev_priv(netdev);
	struct nfp_net *nn = netdev_priv(netdev);


	strlcpy(drvinfo->driver, nn->pdev->driver->name,
	strlcpy(drvinfo->driver, nn->pdev->driver->name,
		sizeof(drvinfo->driver));
		sizeof(drvinfo->driver));
	strlcpy(drvinfo->version, nfp_driver_version, sizeof(drvinfo->version));
	strlcpy(drvinfo->version, nfp_driver_version, sizeof(drvinfo->version));


	nfp_net_get_nspinfo(nn, nsp_version);
	snprintf(drvinfo->fw_version, sizeof(drvinfo->fw_version),
	snprintf(drvinfo->fw_version, sizeof(drvinfo->fw_version),
		 "%d.%d.%d.%d",
		 "%d.%d.%d.%d %s",
		 nn->fw_ver.resv, nn->fw_ver.class,
		 nn->fw_ver.resv, nn->fw_ver.class,
		 nn->fw_ver.major, nn->fw_ver.minor);
		 nn->fw_ver.major, nn->fw_ver.minor, nsp_version);
	strlcpy(drvinfo->bus_info, pci_name(nn->pdev),
	strlcpy(drvinfo->bus_info, pci_name(nn->pdev),
		sizeof(drvinfo->bus_info));
		sizeof(drvinfo->bus_info));


@@ -558,6 +583,75 @@ static int nfp_net_get_coalesce(struct net_device *netdev,
	return 0;
	return 0;
}
}


/* Other debug dumps
 */
static int
nfp_dump_nsp_diag(struct nfp_net *nn, struct ethtool_dump *dump, void *buffer)
{
	struct nfp_resource *res;
	int ret;

	if (!nn->cpp)
		return -EOPNOTSUPP;

	dump->version = 1;
	dump->flag = NFP_DUMP_NSP_DIAG;

	res = nfp_resource_acquire(nn->cpp, NFP_RESOURCE_NSP_DIAG);
	if (IS_ERR(res))
		return PTR_ERR(res);

	if (buffer) {
		if (dump->len != nfp_resource_size(res)) {
			ret = -EINVAL;
			goto exit_release;
		}

		ret = nfp_cpp_read(nn->cpp, nfp_resource_cpp_id(res),
				   nfp_resource_address(res),
				   buffer, dump->len);
		if (ret != dump->len)
			ret = ret < 0 ? ret : -EIO;
		else
			ret = 0;
	} else {
		dump->len = nfp_resource_size(res);
		ret = 0;
	}
exit_release:
	nfp_resource_release(res);

	return ret;
}

static int nfp_net_set_dump(struct net_device *netdev, struct ethtool_dump *val)
{
	struct nfp_net *nn = netdev_priv(netdev);

	if (!nn->cpp)
		return -EOPNOTSUPP;

	if (val->flag != NFP_DUMP_NSP_DIAG)
		return -EINVAL;

	nn->ethtool_dump_flag = val->flag;

	return 0;
}

static int
nfp_net_get_dump_flag(struct net_device *netdev, struct ethtool_dump *dump)
{
	return nfp_dump_nsp_diag(netdev_priv(netdev), dump, NULL);
}

static int
nfp_net_get_dump_data(struct net_device *netdev, struct ethtool_dump *dump,
		      void *buffer)
{
	return nfp_dump_nsp_diag(netdev_priv(netdev), dump, buffer);
}

static int nfp_net_set_coalesce(struct net_device *netdev,
static int nfp_net_set_coalesce(struct net_device *netdev,
				struct ethtool_coalesce *ec)
				struct ethtool_coalesce *ec)
{
{
@@ -722,6 +816,9 @@ static const struct ethtool_ops nfp_net_ethtool_ops = {
	.set_rxfh		= nfp_net_set_rxfh,
	.set_rxfh		= nfp_net_set_rxfh,
	.get_regs_len		= nfp_net_get_regs_len,
	.get_regs_len		= nfp_net_get_regs_len,
	.get_regs		= nfp_net_get_regs,
	.get_regs		= nfp_net_get_regs,
	.set_dump		= nfp_net_set_dump,
	.get_dump_flag		= nfp_net_get_dump_flag,
	.get_dump_data		= nfp_net_get_dump_data,
	.get_coalesce           = nfp_net_get_coalesce,
	.get_coalesce           = nfp_net_get_coalesce,
	.set_coalesce           = nfp_net_set_coalesce,
	.set_coalesce           = nfp_net_set_coalesce,
	.get_channels		= nfp_net_get_channels,
	.get_channels		= nfp_net_get_channels,
+1 −0
Original line number Original line Diff line number Diff line
@@ -303,6 +303,7 @@ nfp_net_pf_alloc_port_netdev(struct nfp_pf *pf, void __iomem *ctrl_bar,
	if (IS_ERR(nn))
	if (IS_ERR(nn))
		return nn;
		return nn;


	nn->cpp = pf->cpp;
	nn->fw_ver = *fw_ver;
	nn->fw_ver = *fw_ver;
	nn->ctrl_bar = ctrl_bar;
	nn->ctrl_bar = ctrl_bar;
	nn->tx_bar = tx_bar;
	nn->tx_bar = tx_bar;
Loading