summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2017-02-20 19:18:50 +0300
committerDavid S. Miller <davem@davemloft.net>2017-02-20 19:18:50 +0300
commite8846a56083aa05f4155c627531ecdcc299cc411 (patch)
tree16665e7a0120e7687775e76b1254b371247a2093 /drivers
parentc1ceee5efe80a2f03071a39a7df19b69dee21eae (diff)
parent0bc3827f8c9f74b5335667d70309cefa12ec14ae (diff)
downloadlinux-e8846a56083aa05f4155c627531ecdcc299cc411.tar.xz
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: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/net/ethernet/netronome/nfp/nfp_main.c87
-rw-r--r--drivers/net/ethernet/netronome/nfp/nfp_main.h2
-rw-r--r--drivers/net/ethernet/netronome/nfp/nfp_net.h6
-rw-r--r--drivers/net/ethernet/netronome/nfp/nfp_net_ethtool.c101
-rw-r--r--drivers/net/ethernet/netronome/nfp/nfp_net_main.c1
-rw-r--r--drivers/net/ethernet/netronome/nfp/nfpcore/nfp.h4
-rw-r--r--drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp.c37
-rw-r--r--drivers/net/ethernet/netronome/nfp/nfpcore/nfp_rtsym.c8
8 files changed, 206 insertions, 40 deletions
diff --git a/drivers/net/ethernet/netronome/nfp/nfp_main.c b/drivers/net/ethernet/netronome/nfp/nfp_main.c
index db52b6a53c6f..dedac720fb29 100644
--- a/drivers/net/ethernet/netronome/nfp/nfp_main.c
+++ b/drivers/net/ethernet/netronome/nfp/nfp_main.c
@@ -47,6 +47,7 @@
#include "nfpcore/nfp.h"
#include "nfpcore/nfp_cpp.h"
+#include "nfpcore/nfp_nffw.h"
#include "nfpcore/nfp_nsp_eth.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);
+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)
{
#ifdef CONFIG_PCI_IOV
struct nfp_pf *pf = pci_get_drvdata(pdev);
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);
if (err) {
dev_warn(&pdev->dev, "Failed to enable PCI sriov: %d\n", err);
@@ -228,6 +251,40 @@ exit_release_fw:
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)
{
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,
const struct pci_device_id *pci_id)
{
- struct nfp_nsp *nsp;
struct nfp_pf *pf;
int err;
@@ -289,28 +345,18 @@ static int nfp_pci_probe(struct pci_dev *pdev,
goto err_disable_msix;
}
- nsp = nfp_nsp_open(pf->cpp);
- if (IS_ERR(nsp)) {
- err = PTR_ERR(nsp);
- goto err_cpp_free;
- }
+ dev_info(&pdev->dev, "Assembly: %s%s%s-%s CPLD: %s\n",
+ nfp_hwinfo_lookup(pf->cpp, "assembly.vendor"),
+ nfp_hwinfo_lookup(pf->cpp, "assembly.partno"),
+ 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);
- if (err < 0) {
- nfp_nsp_close(nsp);
+ err = nfp_nsp_init(pdev, pf);
+ if (err)
goto err_cpp_free;
- }
-
- pf->eth_tbl = __nfp_eth_read_ports(pf->cpp, nsp);
- err = nfp_fw_load(pdev, pf, nsp);
- 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;
+ nfp_pcie_sriov_read_nfd_limit(pf);
err = nfp_net_pci_probe(pf);
if (err)
@@ -321,7 +367,6 @@ static int nfp_pci_probe(struct pci_dev *pdev,
err_fw_unload:
if (pf->fw_loaded)
nfp_fw_unload(pf);
-err_eth_tbl_free:
kfree(pf->eth_tbl);
err_cpp_free:
nfp_cpp_free(pf->cpp);
diff --git a/drivers/net/ethernet/netronome/nfp/nfp_main.h b/drivers/net/ethernet/netronome/nfp/nfp_main.h
index 6c40fa322da3..39105d0435e9 100644
--- a/drivers/net/ethernet/netronome/nfp/nfp_main.h
+++ b/drivers/net/ethernet/netronome/nfp/nfp_main.h
@@ -59,6 +59,7 @@ struct nfp_eth_table;
* @tx_area: Pointer to the CPP area for the TX queues
* @rx_area: Pointer to the CPP area for the FL/RX queues
* @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
* @fw_loaded: Is the firmware loaded?
* @eth_tbl: NSP ETH table
@@ -77,6 +78,7 @@ struct nfp_pf {
struct msix_entry *irq_entries;
+ unsigned int limit_vfs;
unsigned int num_vfs;
bool fw_loaded;
diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net.h b/drivers/net/ethernet/netronome/nfp/nfp_net.h
index d37d2391b4fe..e614a376b595 100644
--- a/drivers/net/ethernet/netronome/nfp/nfp_net.h
+++ b/drivers/net/ethernet/netronome/nfp/nfp_net.h
@@ -111,6 +111,7 @@
SKB_DATA_ALIGN(sizeof(struct skb_shared_info)))
/* Forward declarations */
+struct nfp_cpp;
struct nfp_net;
struct nfp_net_r_vector;
@@ -491,7 +492,9 @@ struct nfp_stat_pair {
* @tx_bar: Pointer to mapped TX queues
* @rx_bar: Pointer to mapped FL/RX queues
* @debugfs_dir: Device directory in debugfs
+ * @ethtool_dump_flag: Ethtool dump flag
* @port_list: Entry on device port list
+ * @cpp: CPP device handle if available
*/
struct nfp_net {
struct pci_dev *pdev;
@@ -577,8 +580,11 @@ struct nfp_net {
u8 __iomem *rx_bar;
struct dentry *debugfs_dir;
+ u32 ethtool_dump_flag;
struct list_head port_list;
+
+ struct nfp_cpp *cpp;
};
struct nfp_net_ring_set {
diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_ethtool.c b/drivers/net/ethernet/netronome/nfp/nfp_net_ethtool.c
index 255f30252550..2649f7523c81 100644
--- a/drivers/net/ethernet/netronome/nfp/nfp_net_ethtool.c
+++ b/drivers/net/ethernet/netronome/nfp/nfp_net_ethtool.c
@@ -47,9 +47,14 @@
#include <linux/pci.h>
#include <linux/ethtool.h>
+#include "nfpcore/nfp.h"
#include "nfp_net_ctrl.h"
#include "nfp_net.h"
+enum nfp_dump_diag {
+ NFP_DUMP_NSP_DIAG = 0,
+};
+
/* Support for stats. Returns netdev, driver, and device stats */
enum { NETDEV_ET_STATS, NFP_NET_DRV_ET_STATS, NFP_NET_DEV_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 + \
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,
struct ethtool_drvinfo *drvinfo)
{
+ char nsp_version[ETHTOOL_FWVERS_LEN] = {};
struct nfp_net *nn = netdev_priv(netdev);
strlcpy(drvinfo->driver, nn->pdev->driver->name,
sizeof(drvinfo->driver));
strlcpy(drvinfo->version, nfp_driver_version, sizeof(drvinfo->version));
+ nfp_net_get_nspinfo(nn, nsp_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.major, nn->fw_ver.minor);
+ nn->fw_ver.major, nn->fw_ver.minor, nsp_version);
strlcpy(drvinfo->bus_info, pci_name(nn->pdev),
sizeof(drvinfo->bus_info));
@@ -558,6 +583,75 @@ static int nfp_net_get_coalesce(struct net_device *netdev,
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,
struct ethtool_coalesce *ec)
{
@@ -722,6 +816,9 @@ static const struct ethtool_ops nfp_net_ethtool_ops = {
.set_rxfh = nfp_net_set_rxfh,
.get_regs_len = nfp_net_get_regs_len,
.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,
.set_coalesce = nfp_net_set_coalesce,
.get_channels = nfp_net_get_channels,
diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_main.c b/drivers/net/ethernet/netronome/nfp/nfp_net_main.c
index eccd31003b0d..3afcdc11480c 100644
--- a/drivers/net/ethernet/netronome/nfp/nfp_net_main.c
+++ b/drivers/net/ethernet/netronome/nfp/nfp_net_main.c
@@ -303,6 +303,7 @@ nfp_net_pf_alloc_port_netdev(struct nfp_pf *pf, void __iomem *ctrl_bar,
if (IS_ERR(nn))
return nn;
+ nn->cpp = pf->cpp;
nn->fw_ver = *fw_ver;
nn->ctrl_bar = ctrl_bar;
nn->tx_bar = tx_bar;
diff --git a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp.h b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp.h
index 3d70a8578a98..42cb720b696d 100644
--- a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp.h
+++ b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp.h
@@ -40,6 +40,7 @@
#define __NFP_H__
#include <linux/device.h>
+#include <linux/types.h>
#include "nfp_cpp.h"
@@ -54,6 +55,8 @@ struct firmware;
struct nfp_nsp *nfp_nsp_open(struct nfp_cpp *cpp);
void nfp_nsp_close(struct nfp_nsp *state);
+u16 nfp_nsp_get_abi_ver_major(struct nfp_nsp *state);
+u16 nfp_nsp_get_abi_ver_minor(struct nfp_nsp *state);
int nfp_nsp_wait(struct nfp_nsp *state);
int nfp_nsp_device_soft_reset(struct nfp_nsp *state);
int nfp_nsp_load_fw(struct nfp_nsp *state, const struct firmware *fw);
@@ -83,6 +86,7 @@ int nfp_nsp_write_eth_table(struct nfp_nsp *state,
/* Service Processor */
#define NFP_RESOURCE_NSP "nfp.sp"
+#define NFP_RESOURCE_NSP_DIAG "arm.diag"
/* Netronone Flow Firmware Table */
#define NFP_RESOURCE_NFP_NFFW "nfp.nffw"
diff --git a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp.c b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp.c
index f07f2fc3fba0..34c50987c377 100644
--- a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp.c
+++ b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp.c
@@ -99,6 +99,10 @@ enum nfp_nsp_cmd {
struct nfp_nsp {
struct nfp_cpp *cpp;
struct nfp_resource *res;
+ struct {
+ u16 major;
+ u16 minor;
+ } ver;
};
static int nfp_nsp_check(struct nfp_nsp *state)
@@ -120,11 +124,12 @@ static int nfp_nsp_check(struct nfp_nsp *state)
return -ENODEV;
}
- if (FIELD_GET(NSP_STATUS_MAJOR, reg) != NSP_MAJOR ||
- FIELD_GET(NSP_STATUS_MINOR, reg) < NSP_MINOR) {
- nfp_err(cpp, "Unsupported ABI %lld.%lld\n",
- FIELD_GET(NSP_STATUS_MAJOR, reg),
- FIELD_GET(NSP_STATUS_MINOR, reg));
+ state->ver.major = FIELD_GET(NSP_STATUS_MAJOR, reg);
+ state->ver.minor = FIELD_GET(NSP_STATUS_MINOR, reg);
+
+ if (state->ver.major != NSP_MAJOR || state->ver.minor < NSP_MINOR) {
+ nfp_err(cpp, "Unsupported ABI %hu.%hu\n",
+ state->ver.major, state->ver.minor);
return -EINVAL;
}
@@ -177,6 +182,16 @@ void nfp_nsp_close(struct nfp_nsp *state)
kfree(state);
}
+u16 nfp_nsp_get_abi_ver_major(struct nfp_nsp *state)
+{
+ return state->ver.major;
+}
+
+u16 nfp_nsp_get_abi_ver_minor(struct nfp_nsp *state)
+{
+ return state->ver.minor;
+}
+
static int
nfp_nsp_wait_reg(struct nfp_cpp *cpp, u64 *reg,
u32 nsp_cpp, u64 addr, u64 mask, u64 val)
@@ -301,15 +316,9 @@ static int nfp_nsp_command_buf(struct nfp_nsp *nsp, u16 code, u32 option,
int ret, err;
u32 cpp_id;
- err = nfp_cpp_readq(cpp, nfp_resource_cpp_id(nsp->res),
- nfp_resource_address(nsp->res) + NSP_STATUS, &reg);
- if (err < 0)
- return err;
-
- if (FIELD_GET(NSP_STATUS_MINOR, reg) < 13) {
- nfp_err(cpp, "NSP: Code 0x%04x with buffer not supported (ABI %lld.%lld)\n",
- code, FIELD_GET(NSP_STATUS_MAJOR, reg),
- FIELD_GET(NSP_STATUS_MINOR, reg));
+ if (nsp->ver.minor < 13) {
+ nfp_err(cpp, "NSP: Code 0x%04x with buffer not supported (ABI %hu.%hu)\n",
+ code, nsp->ver.major, nsp->ver.minor);
return -EOPNOTSUPP;
}
diff --git a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_rtsym.c b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_rtsym.c
index c659b1d999be..0e3870ecfb8c 100644
--- a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_rtsym.c
+++ b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_rtsym.c
@@ -269,8 +269,10 @@ u64 nfp_rtsym_read_le(struct nfp_cpp *cpp, const char *name, int *error)
int err;
sym = nfp_rtsym_lookup(cpp, name);
- if (!sym)
- return -ENOENT;
+ if (!sym) {
+ err = -ENOENT;
+ goto exit;
+ }
id = NFP_CPP_ISLAND_ID(sym->target, NFP_CPP_ACTION_RW, 0, sym->domain);
@@ -294,7 +296,7 @@ u64 nfp_rtsym_read_le(struct nfp_cpp *cpp, const char *name, int *error)
err = 0;
else if (err >= 0)
err = -EIO;
-
+exit:
if (error)
*error = err;