mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-28 22:54:05 +08:00
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>
This commit is contained in:
commit
e8846a5608
@ -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);
|
||||
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_init(pdev, pf);
|
||||
if (err)
|
||||
goto err_cpp_free;
|
||||
}
|
||||
|
||||
err = nfp_nsp_wait(nsp);
|
||||
if (err < 0) {
|
||||
nfp_nsp_close(nsp);
|
||||
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);
|
||||
|
@ -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;
|
||||
|
@ -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 {
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
|
@ -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"
|
||||
|
@ -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, ®);
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user