aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/ethernet/netronome/nfp/nfpcore
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/ethernet/netronome/nfp/nfpcore')
-rw-r--r--drivers/net/ethernet/netronome/nfp/nfpcore/nfp6000_pcie.c50
-rw-r--r--drivers/net/ethernet/netronome/nfp/nfpcore/nfp_cpp.h12
-rw-r--r--drivers/net/ethernet/netronome/nfp/nfpcore/nfp_cppcore.c36
-rw-r--r--drivers/net/ethernet/netronome/nfp/nfpcore/nfp_cpplib.c12
-rw-r--r--drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nffw.c32
-rw-r--r--drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nffw.h38
-rw-r--r--drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp.c330
-rw-r--r--drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp.h12
-rw-r--r--drivers/net/ethernet/netronome/nfp/nfpcore/nfp_rtsym.c269
-rw-r--r--drivers/net/ethernet/netronome/nfp/nfpcore/nfp_target.c12
10 files changed, 653 insertions, 150 deletions
diff --git a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp6000_pcie.c b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp6000_pcie.c
index c8d0b1016a64..fd63d83bdea5 100644
--- a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp6000_pcie.c
+++ b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp6000_pcie.c
@@ -138,6 +138,7 @@
/* The number of explicit BARs to reserve.
* Minimum is 0, maximum is 4 on the NFP6000.
+ * The NFP3800 can have only one per PF.
*/
#define NFP_PCIE_EXPLICIT_BARS 2
@@ -589,8 +590,8 @@ static int enable_bars(struct nfp6000_pcie *nfp, u16 interface)
NFP_PCIE_BAR_PCIE2CPP_MapType_EXPLICIT3),
};
char status_msg[196] = {};
+ int i, err, bars_free;
struct nfp_bar *bar;
- int i, bars_free;
int expl_groups;
char *msg, *end;
@@ -643,6 +644,8 @@ static int enable_bars(struct nfp6000_pcie *nfp, u16 interface)
bar->iomem = ioremap_nocache(nfp_bar_resource_start(bar),
nfp_bar_resource_len(bar));
if (bar->iomem) {
+ int pf;
+
msg += snprintf(msg, end - msg, "0.0: General/MSI-X SRAM, ");
atomic_inc(&bar->refcnt);
bars_free--;
@@ -651,22 +654,40 @@ static int enable_bars(struct nfp6000_pcie *nfp, u16 interface)
nfp->expl.data = bar->iomem + NFP_PCIE_SRAM + 0x1000;
- if (nfp->pdev->device == PCI_DEVICE_ID_NETRONOME_NFP4000 ||
- nfp->pdev->device == PCI_DEVICE_ID_NETRONOME_NFP6000) {
- nfp->iomem.csr = bar->iomem + NFP_PCIE_BAR(0);
- } else {
- int pf = nfp->pdev->devfn & 7;
-
+ switch (nfp->pdev->device) {
+ case PCI_DEVICE_ID_NETRONOME_NFP3800:
+ pf = nfp->pdev->devfn & 7;
nfp->iomem.csr = bar->iomem + NFP_PCIE_BAR(pf);
+ break;
+ case PCI_DEVICE_ID_NETRONOME_NFP4000:
+ case PCI_DEVICE_ID_NETRONOME_NFP5000:
+ case PCI_DEVICE_ID_NETRONOME_NFP6000:
+ nfp->iomem.csr = bar->iomem + NFP_PCIE_BAR(0);
+ break;
+ default:
+ dev_err(nfp->dev, "Unsupported device ID: %04hx!\n",
+ nfp->pdev->device);
+ err = -EINVAL;
+ goto err_unmap_bar0;
}
nfp->iomem.em = bar->iomem + NFP_PCIE_EM;
}
- if (nfp->pdev->device == PCI_DEVICE_ID_NETRONOME_NFP4000 ||
- nfp->pdev->device == PCI_DEVICE_ID_NETRONOME_NFP6000)
- expl_groups = 4;
- else
+ switch (nfp->pdev->device) {
+ case PCI_DEVICE_ID_NETRONOME_NFP3800:
expl_groups = 1;
+ break;
+ case PCI_DEVICE_ID_NETRONOME_NFP4000:
+ case PCI_DEVICE_ID_NETRONOME_NFP5000:
+ case PCI_DEVICE_ID_NETRONOME_NFP6000:
+ expl_groups = 4;
+ break;
+ default:
+ dev_err(nfp->dev, "Unsupported device ID: %04hx!\n",
+ nfp->pdev->device);
+ err = -EINVAL;
+ goto err_unmap_bar0;
+ }
/* Configure, and lock, BAR0.1 for PCIe XPB (MSI-X PBA) */
bar = &nfp->bar[1];
@@ -711,6 +732,11 @@ static int enable_bars(struct nfp6000_pcie *nfp, u16 interface)
dev_info(nfp->dev, "%sfree: %d/%d\n", status_msg, bars_free, nfp->bars);
return 0;
+
+err_unmap_bar0:
+ if (nfp->bar[0].iomem)
+ iounmap(nfp->bar[0].iomem);
+ return err;
}
static void disable_bars(struct nfp6000_pcie *nfp)
@@ -1327,7 +1353,7 @@ struct nfp_cpp *nfp_cpp_from_nfp6000_pcie(struct pci_dev *pdev)
/* Finished with card initialization. */
dev_info(&pdev->dev,
- "Netronome Flow Processor NFP4000/NFP6000 PCIe Card Probe\n");
+ "Netronome Flow Processor NFP4000/NFP5000/NFP6000 PCIe Card Probe\n");
pcie_print_link_status(pdev);
nfp = kzalloc(sizeof(*nfp), GFP_KERNEL);
diff --git a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_cpp.h b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_cpp.h
index c338d539fa96..123e29cba6d1 100644
--- a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_cpp.h
+++ b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_cpp.h
@@ -56,9 +56,16 @@
dev_info(nfp_cpp_device(cpp)->parent, NFP_SUBSYS ": " fmt, ## args)
#define nfp_dbg(cpp, fmt, args...) \
dev_dbg(nfp_cpp_device(cpp)->parent, NFP_SUBSYS ": " fmt, ## args)
+#define nfp_printk(level, cpp, fmt, args...) \
+ dev_printk(level, nfp_cpp_device(cpp)->parent, \
+ NFP_SUBSYS ": " fmt, ## args)
#define PCI_64BIT_BAR_COUNT 3
+/* NFP hardware vendor/device ids.
+ */
+#define PCI_DEVICE_ID_NETRONOME_NFP3800 0x3800
+
#define NFP_CPP_NUM_TARGETS 16
/* Max size of area it should be safe to request */
#define NFP_CPP_SAFE_AREA_SIZE SZ_2M
@@ -226,6 +233,7 @@ void nfp_cpp_free(struct nfp_cpp *cpp);
u32 nfp_cpp_model(struct nfp_cpp *cpp);
u16 nfp_cpp_interface(struct nfp_cpp *cpp);
int nfp_cpp_serial(struct nfp_cpp *cpp, const u8 **serial);
+unsigned int nfp_cpp_mu_locality_lsb(struct nfp_cpp *cpp);
struct nfp_cpp_area *nfp_cpp_area_alloc_with_name(struct nfp_cpp *cpp,
u32 cpp_id,
@@ -286,8 +294,8 @@ int nfp_cpp_writeq(struct nfp_cpp *cpp, u32 cpp_id,
unsigned long long address, u64 value);
u8 __iomem *
-nfp_cpp_map_area(struct nfp_cpp *cpp, const char *name, int domain, int target,
- u64 addr, unsigned long size, struct nfp_cpp_area **area);
+nfp_cpp_map_area(struct nfp_cpp *cpp, const char *name, u32 cpp_id, u64 addr,
+ unsigned long size, struct nfp_cpp_area **area);
struct nfp_cpp_mutex;
diff --git a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_cppcore.c b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_cppcore.c
index 73de57a09800..f7e1d79e735f 100644
--- a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_cppcore.c
+++ b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_cppcore.c
@@ -75,6 +75,7 @@ struct nfp_cpp_resource {
* @interface: chip interface id we are using to reach it
* @serial: chip serial number
* @imb_cat_table: CPP Mapping Table
+ * @mu_locality_lsb: MU access type bit offset
*
* Following fields use explicit locking:
* @resource_list: NFP CPP resource list
@@ -100,6 +101,7 @@ struct nfp_cpp {
wait_queue_head_t waitq;
u32 imb_cat_table[16];
+ unsigned int mu_locality_lsb;
struct mutex area_cache_mutex;
struct list_head area_cache_list;
@@ -266,6 +268,34 @@ int nfp_cpp_serial(struct nfp_cpp *cpp, const u8 **serial)
return sizeof(cpp->serial);
}
+#define NFP_IMB_TGTADDRESSMODECFG_MODE_of(_x) (((_x) >> 13) & 0x7)
+#define NFP_IMB_TGTADDRESSMODECFG_ADDRMODE BIT(12)
+#define NFP_IMB_TGTADDRESSMODECFG_ADDRMODE_32_BIT 0
+#define NFP_IMB_TGTADDRESSMODECFG_ADDRMODE_40_BIT BIT(12)
+
+static int nfp_cpp_set_mu_locality_lsb(struct nfp_cpp *cpp)
+{
+ unsigned int mode, addr40;
+ u32 imbcppat;
+ int res;
+
+ imbcppat = cpp->imb_cat_table[NFP_CPP_TARGET_MU];
+ mode = NFP_IMB_TGTADDRESSMODECFG_MODE_of(imbcppat);
+ addr40 = !!(imbcppat & NFP_IMB_TGTADDRESSMODECFG_ADDRMODE);
+
+ res = nfp_cppat_mu_locality_lsb(mode, addr40);
+ if (res < 0)
+ return res;
+ cpp->mu_locality_lsb = res;
+
+ return 0;
+}
+
+unsigned int nfp_cpp_mu_locality_lsb(struct nfp_cpp *cpp)
+{
+ return cpp->mu_locality_lsb;
+}
+
/**
* nfp_cpp_area_alloc_with_name() - allocate a new CPP area
* @cpp: CPP device handle
@@ -1241,6 +1271,12 @@ nfp_cpp_from_operations(const struct nfp_cpp_operations *ops,
nfp_cpp_readl(cpp, arm, NFP_ARM_GCSR + NFP_ARM_GCSR_SOFTMODEL3,
&mask[1]);
+ err = nfp_cpp_set_mu_locality_lsb(cpp);
+ if (err < 0) {
+ dev_err(parent, "Can't calculate MU locality bit offset\n");
+ goto err_out;
+ }
+
dev_info(cpp->dev.parent, "Model: 0x%08x, SN: %pM, Ifc: 0x%04x\n",
nfp_cpp_model(cpp), cpp->serial, nfp_cpp_interface(cpp));
diff --git a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_cpplib.c b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_cpplib.c
index 20bad05e2e92..03fcde5fa137 100644
--- a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_cpplib.c
+++ b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_cpplib.c
@@ -294,8 +294,7 @@ exit_release:
* nfp_cpp_map_area() - Helper function to map an area
* @cpp: NFP CPP handler
* @name: Name for the area
- * @domain: CPP domain
- * @target: CPP target
+ * @cpp_id: CPP ID for operation
* @addr: CPP address
* @size: Size of the area
* @area: Area handle (output)
@@ -306,15 +305,12 @@ exit_release:
* Return: Pointer to memory mapped area or ERR_PTR
*/
u8 __iomem *
-nfp_cpp_map_area(struct nfp_cpp *cpp, const char *name, int domain, int target,
- u64 addr, unsigned long size, struct nfp_cpp_area **area)
+nfp_cpp_map_area(struct nfp_cpp *cpp, const char *name, u32 cpp_id, u64 addr,
+ unsigned long size, struct nfp_cpp_area **area)
{
u8 __iomem *res;
- u32 dest;
- dest = NFP_CPP_ISLAND_ID(target, NFP_CPP_ACTION_RW, 0, domain);
-
- *area = nfp_cpp_area_alloc_acquire(cpp, name, dest, addr, size);
+ *area = nfp_cpp_area_alloc_acquire(cpp, name, cpp_id, addr, size);
if (!*area)
goto err_eio;
diff --git a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nffw.c b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nffw.c
index 40510860341b..a164fbc85cd3 100644
--- a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nffw.c
+++ b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nffw.c
@@ -156,29 +156,6 @@ static u64 nffw_fwinfo_mip_offset_get(const struct nffw_fwinfo *fi)
return (mip_off_hi & 0xFF) << 32 | le32_to_cpu(fi->mip_offset_lo);
}
-#define NFP_IMB_TGTADDRESSMODECFG_MODE_of(_x) (((_x) >> 13) & 0x7)
-#define NFP_IMB_TGTADDRESSMODECFG_ADDRMODE BIT(12)
-#define NFP_IMB_TGTADDRESSMODECFG_ADDRMODE_32_BIT 0
-#define NFP_IMB_TGTADDRESSMODECFG_ADDRMODE_40_BIT BIT(12)
-
-static int nfp_mip_mu_locality_lsb(struct nfp_cpp *cpp)
-{
- unsigned int mode, addr40;
- u32 xpbaddr, imbcppat;
- int err;
-
- /* Hardcoded XPB IMB Base, island 0 */
- xpbaddr = 0x000a0000 + NFP_CPP_TARGET_MU * 4;
- err = nfp_xpb_readl(cpp, xpbaddr, &imbcppat);
- if (err < 0)
- return err;
-
- mode = NFP_IMB_TGTADDRESSMODECFG_MODE_of(imbcppat);
- addr40 = !!(imbcppat & NFP_IMB_TGTADDRESSMODECFG_ADDRMODE);
-
- return nfp_cppat_mu_locality_lsb(mode, addr40);
-}
-
static unsigned int
nffw_res_fwinfos(struct nfp_nffw_info_data *fwinf, struct nffw_fwinfo **arr)
{
@@ -304,14 +281,7 @@ int nfp_nffw_info_mip_first(struct nfp_nffw_info *state, u32 *cpp_id, u64 *off)
*off = nffw_fwinfo_mip_offset_get(fwinfo);
if (nffw_fwinfo_mip_mu_da_get(fwinfo)) {
- int locality_off;
-
- if (NFP_CPP_ID_TARGET_of(*cpp_id) != NFP_CPP_TARGET_MU)
- return 0;
-
- locality_off = nfp_mip_mu_locality_lsb(state->cpp);
- if (locality_off < 0)
- return locality_off;
+ int locality_off = nfp_cpp_mu_locality_lsb(state->cpp);
*off &= ~(NFP_MU_ADDR_ACCESS_TYPE_MASK << locality_off);
*off |= NFP_MU_ADDR_ACCESS_TYPE_DIRECT << locality_off;
diff --git a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nffw.h b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nffw.h
index df599d5b6bb3..8d2cbdf4d517 100644
--- a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nffw.h
+++ b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nffw.h
@@ -61,10 +61,12 @@ void nfp_mip_strtab(const struct nfp_mip *mip, u32 *addr, u32 *size);
/* Implemented in nfp_rtsym.c */
-#define NFP_RTSYM_TYPE_NONE 0
-#define NFP_RTSYM_TYPE_OBJECT 1
-#define NFP_RTSYM_TYPE_FUNCTION 2
-#define NFP_RTSYM_TYPE_ABS 3
+enum nfp_rtsym_type {
+ NFP_RTSYM_TYPE_NONE = 0,
+ NFP_RTSYM_TYPE_OBJECT = 1,
+ NFP_RTSYM_TYPE_FUNCTION = 2,
+ NFP_RTSYM_TYPE_ABS = 3,
+};
#define NFP_RTSYM_TARGET_NONE 0
#define NFP_RTSYM_TARGET_LMEM -1
@@ -83,7 +85,7 @@ struct nfp_rtsym {
const char *name;
u64 addr;
u64 size;
- int type;
+ enum nfp_rtsym_type type;
int target;
int domain;
};
@@ -98,6 +100,32 @@ const struct nfp_rtsym *nfp_rtsym_get(struct nfp_rtsym_table *rtbl, int idx);
const struct nfp_rtsym *
nfp_rtsym_lookup(struct nfp_rtsym_table *rtbl, const char *name);
+u64 nfp_rtsym_size(const struct nfp_rtsym *rtsym);
+int __nfp_rtsym_read(struct nfp_cpp *cpp, const struct nfp_rtsym *sym,
+ u8 action, u8 token, u64 off, void *buf, size_t len);
+int nfp_rtsym_read(struct nfp_cpp *cpp, const struct nfp_rtsym *sym, u64 off,
+ void *buf, size_t len);
+int __nfp_rtsym_readl(struct nfp_cpp *cpp, const struct nfp_rtsym *sym,
+ u8 action, u8 token, u64 off, u32 *value);
+int nfp_rtsym_readl(struct nfp_cpp *cpp, const struct nfp_rtsym *sym, u64 off,
+ u32 *value);
+int __nfp_rtsym_readq(struct nfp_cpp *cpp, const struct nfp_rtsym *sym,
+ u8 action, u8 token, u64 off, u64 *value);
+int nfp_rtsym_readq(struct nfp_cpp *cpp, const struct nfp_rtsym *sym, u64 off,
+ u64 *value);
+int __nfp_rtsym_write(struct nfp_cpp *cpp, const struct nfp_rtsym *sym,
+ u8 action, u8 token, u64 off, void *buf, size_t len);
+int nfp_rtsym_write(struct nfp_cpp *cpp, const struct nfp_rtsym *sym, u64 off,
+ void *buf, size_t len);
+int __nfp_rtsym_writel(struct nfp_cpp *cpp, const struct nfp_rtsym *sym,
+ u8 action, u8 token, u64 off, u32 value);
+int nfp_rtsym_writel(struct nfp_cpp *cpp, const struct nfp_rtsym *sym, u64 off,
+ u32 value);
+int __nfp_rtsym_writeq(struct nfp_cpp *cpp, const struct nfp_rtsym *sym,
+ u8 action, u8 token, u64 off, u64 value);
+int nfp_rtsym_writeq(struct nfp_cpp *cpp, const struct nfp_rtsym *sym, u64 off,
+ u64 value);
+
u64 nfp_rtsym_read_le(struct nfp_rtsym_table *rtbl, const char *name,
int *error);
int nfp_rtsym_write_le(struct nfp_rtsym_table *rtbl, const char *name,
diff --git a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp.c b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp.c
index 2abee0fe3a7c..bf593a6b26a1 100644
--- a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp.c
+++ b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp.c
@@ -87,6 +87,11 @@
#define NSP_CODE_MAJOR GENMASK(15, 12)
#define NSP_CODE_MINOR GENMASK(11, 0)
+#define NFP_FW_LOAD_RET_MAJOR GENMASK(15, 8)
+#define NFP_FW_LOAD_RET_MINOR GENMASK(23, 16)
+
+#define NFP_HWINFO_LOOKUP_SIZE GENMASK(11, 0)
+
enum nfp_nsp_cmd {
SPCODE_NOOP = 0, /* No operation */
SPCODE_SOFT_RESET = 1, /* Soft reset the NFP */
@@ -100,6 +105,8 @@ enum nfp_nsp_cmd {
SPCODE_NSP_WRITE_FLASH = 11, /* Load and flash image from buffer */
SPCODE_NSP_SENSORS = 12, /* Read NSP sensor(s) */
SPCODE_NSP_IDENTIFY = 13, /* Read NSP version */
+ SPCODE_FW_STORED = 16, /* If no FW loaded, load flash app FW */
+ SPCODE_HWINFO_LOOKUP = 17, /* Lookup HWinfo with overwrites etc. */
};
static const struct {
@@ -127,6 +134,40 @@ struct nfp_nsp {
void *entries;
};
+/**
+ * struct nfp_nsp_command_arg - NFP command argument structure
+ * @code: NFP SP Command Code
+ * @timeout_sec:Timeout value to wait for completion in seconds
+ * @option: NFP SP Command Argument
+ * @buff_cpp: NFP SP Buffer CPP Address info
+ * @buff_addr: NFP SP Buffer Host address
+ * @error_cb: Callback for interpreting option if error occurred
+ */
+struct nfp_nsp_command_arg {
+ u16 code;
+ unsigned int timeout_sec;
+ u32 option;
+ u32 buff_cpp;
+ u64 buff_addr;
+ void (*error_cb)(struct nfp_nsp *state, u32 ret_val);
+};
+
+/**
+ * struct nfp_nsp_command_buf_arg - NFP command with buffer argument structure
+ * @arg: NFP command argument structure
+ * @in_buf: Buffer with data for input
+ * @in_size: Size of @in_buf
+ * @out_buf: Buffer for output data
+ * @out_size: Size of @out_buf
+ */
+struct nfp_nsp_command_buf_arg {
+ struct nfp_nsp_command_arg arg;
+ const void *in_buf;
+ unsigned int in_size;
+ void *out_buf;
+ unsigned int out_size;
+};
+
struct nfp_cpp *nfp_nsp_cpp(struct nfp_nsp *state)
{
return state->cpp;
@@ -291,11 +332,7 @@ nfp_nsp_wait_reg(struct nfp_cpp *cpp, u64 *reg, u32 nsp_cpp, u64 addr,
/**
* __nfp_nsp_command() - Execute a command on the NFP Service Processor
* @state: NFP SP state
- * @code: NFP SP Command Code
- * @option: NFP SP Command Argument
- * @buff_cpp: NFP SP Buffer CPP Address info
- * @buff_addr: NFP SP Buffer Host address
- * @timeout_sec:Timeout value to wait for completion in seconds
+ * @arg: NFP command argument structure
*
* Return: 0 for success with no result
*
@@ -308,8 +345,7 @@ nfp_nsp_wait_reg(struct nfp_cpp *cpp, u64 *reg, u32 nsp_cpp, u64 addr,
* -ETIMEDOUT if the NSP took longer than @timeout_sec seconds to complete
*/
static int
-__nfp_nsp_command(struct nfp_nsp *state, u16 code, u32 option, u32 buff_cpp,
- u64 buff_addr, u32 timeout_sec)
+__nfp_nsp_command(struct nfp_nsp *state, const struct nfp_nsp_command_arg *arg)
{
u64 reg, ret_val, nsp_base, nsp_buffer, nsp_status, nsp_command;
struct nfp_cpp *cpp = state->cpp;
@@ -326,22 +362,22 @@ __nfp_nsp_command(struct nfp_nsp *state, u16 code, u32 option, u32 buff_cpp,
if (err)
return err;
- if (!FIELD_FIT(NSP_BUFFER_CPP, buff_cpp >> 8) ||
- !FIELD_FIT(NSP_BUFFER_ADDRESS, buff_addr)) {
+ if (!FIELD_FIT(NSP_BUFFER_CPP, arg->buff_cpp >> 8) ||
+ !FIELD_FIT(NSP_BUFFER_ADDRESS, arg->buff_addr)) {
nfp_err(cpp, "Host buffer out of reach %08x %016llx\n",
- buff_cpp, buff_addr);
+ arg->buff_cpp, arg->buff_addr);
return -EINVAL;
}
err = nfp_cpp_writeq(cpp, nsp_cpp, nsp_buffer,
- FIELD_PREP(NSP_BUFFER_CPP, buff_cpp >> 8) |
- FIELD_PREP(NSP_BUFFER_ADDRESS, buff_addr));
+ FIELD_PREP(NSP_BUFFER_CPP, arg->buff_cpp >> 8) |
+ FIELD_PREP(NSP_BUFFER_ADDRESS, arg->buff_addr));
if (err < 0)
return err;
err = nfp_cpp_writeq(cpp, nsp_cpp, nsp_command,
- FIELD_PREP(NSP_COMMAND_OPTION, option) |
- FIELD_PREP(NSP_COMMAND_CODE, code) |
+ FIELD_PREP(NSP_COMMAND_OPTION, arg->option) |
+ FIELD_PREP(NSP_COMMAND_CODE, arg->code) |
FIELD_PREP(NSP_COMMAND_START, 1));
if (err < 0)
return err;
@@ -351,16 +387,16 @@ __nfp_nsp_command(struct nfp_nsp *state, u16 code, u32 option, u32 buff_cpp,
NSP_COMMAND_START, 0, NFP_NSP_TIMEOUT_DEFAULT);
if (err) {
nfp_err(cpp, "Error %d waiting for code 0x%04x to start\n",
- err, code);
+ err, arg->code);
return err;
}
/* Wait for NSP_STATUS_BUSY to go to 0 */
err = nfp_nsp_wait_reg(cpp, &reg, nsp_cpp, nsp_status, NSP_STATUS_BUSY,
- 0, timeout_sec);
+ 0, arg->timeout_sec ?: NFP_NSP_TIMEOUT_DEFAULT);
if (err) {
nfp_err(cpp, "Error %d waiting for code 0x%04x to complete\n",
- err, code);
+ err, arg->code);
return err;
}
@@ -372,26 +408,28 @@ __nfp_nsp_command(struct nfp_nsp *state, u16 code, u32 option, u32 buff_cpp,
err = FIELD_GET(NSP_STATUS_RESULT, reg);
if (err) {
nfp_warn(cpp, "Result (error) code set: %d (%d) command: %d\n",
- -err, (int)ret_val, code);
- nfp_nsp_print_extended_error(state, ret_val);
+ -err, (int)ret_val, arg->code);
+ if (arg->error_cb)
+ arg->error_cb(state, ret_val);
+ else
+ nfp_nsp_print_extended_error(state, ret_val);
return -err;
}
return ret_val;
}
-static int
-nfp_nsp_command(struct nfp_nsp *state, u16 code, u32 option, u32 buff_cpp,
- u64 buff_addr)
+static int nfp_nsp_command(struct nfp_nsp *state, u16 code)
{
- return __nfp_nsp_command(state, code, option, buff_cpp, buff_addr,
- NFP_NSP_TIMEOUT_DEFAULT);
+ const struct nfp_nsp_command_arg arg = {
+ .code = code,
+ };
+
+ return __nfp_nsp_command(state, &arg);
}
static int
-__nfp_nsp_command_buf(struct nfp_nsp *nsp, u16 code, u32 option,
- const void *in_buf, unsigned int in_size, void *out_buf,
- unsigned int out_size, u32 timeout_sec)
+nfp_nsp_command_buf(struct nfp_nsp *nsp, struct nfp_nsp_command_buf_arg *arg)
{
struct nfp_cpp *cpp = nsp->cpp;
unsigned int max_size;
@@ -401,7 +439,7 @@ __nfp_nsp_command_buf(struct nfp_nsp *nsp, u16 code, u32 option,
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);
+ arg->arg.code, nsp->ver.major, nsp->ver.minor);
return -EOPNOTSUPP;
}
@@ -412,10 +450,11 @@ __nfp_nsp_command_buf(struct nfp_nsp *nsp, u16 code, u32 option,
if (err < 0)
return err;
- max_size = max(in_size, out_size);
+ max_size = max(arg->in_size, arg->out_size);
if (FIELD_GET(NSP_DFLT_BUFFER_SIZE_MB, reg) * SZ_1M < max_size) {
nfp_err(cpp, "NSP: default buffer too small for command 0x%04x (%llu < %u)\n",
- code, FIELD_GET(NSP_DFLT_BUFFER_SIZE_MB, reg) * SZ_1M,
+ arg->arg.code,
+ FIELD_GET(NSP_DFLT_BUFFER_SIZE_MB, reg) * SZ_1M,
max_size);
return -EINVAL;
}
@@ -430,27 +469,30 @@ __nfp_nsp_command_buf(struct nfp_nsp *nsp, u16 code, u32 option,
cpp_id = FIELD_GET(NSP_DFLT_BUFFER_CPP, reg) << 8;
cpp_buf = FIELD_GET(NSP_DFLT_BUFFER_ADDRESS, reg);
- if (in_buf && in_size) {
- err = nfp_cpp_write(cpp, cpp_id, cpp_buf, in_buf, in_size);
+ if (arg->in_buf && arg->in_size) {
+ err = nfp_cpp_write(cpp, cpp_id, cpp_buf,
+ arg->in_buf, arg->in_size);
if (err < 0)
return err;
}
/* Zero out remaining part of the buffer */
- if (out_buf && out_size && out_size > in_size) {
- memset(out_buf, 0, out_size - in_size);
- err = nfp_cpp_write(cpp, cpp_id, cpp_buf + in_size,
- out_buf, out_size - in_size);
+ if (arg->out_buf && arg->out_size && arg->out_size > arg->in_size) {
+ memset(arg->out_buf, 0, arg->out_size - arg->in_size);
+ err = nfp_cpp_write(cpp, cpp_id, cpp_buf + arg->in_size,
+ arg->out_buf, arg->out_size - arg->in_size);
if (err < 0)
return err;
}
- ret = __nfp_nsp_command(nsp, code, option, cpp_id, cpp_buf,
- timeout_sec);
+ arg->arg.buff_cpp = cpp_id;
+ arg->arg.buff_addr = cpp_buf;
+ ret = __nfp_nsp_command(nsp, &arg->arg);
if (ret < 0)
return ret;
- if (out_buf && out_size) {
- err = nfp_cpp_read(cpp, cpp_id, cpp_buf, out_buf, out_size);
+ if (arg->out_buf && arg->out_size) {
+ err = nfp_cpp_read(cpp, cpp_id, cpp_buf,
+ arg->out_buf, arg->out_size);
if (err < 0)
return err;
}
@@ -458,16 +500,6 @@ __nfp_nsp_command_buf(struct nfp_nsp *nsp, u16 code, u32 option,
return ret;
}
-static int
-nfp_nsp_command_buf(struct nfp_nsp *nsp, u16 code, u32 option,
- const void *in_buf, unsigned int in_size, void *out_buf,
- unsigned int out_size)
-{
- return __nfp_nsp_command_buf(nsp, code, option, in_buf, in_size,
- out_buf, out_size,
- NFP_NSP_TIMEOUT_DEFAULT);
-}
-
int nfp_nsp_wait(struct nfp_nsp *state)
{
const unsigned long wait_until = jiffies + NFP_NSP_TIMEOUT_BOOT * HZ;
@@ -479,7 +511,7 @@ int nfp_nsp_wait(struct nfp_nsp *state)
for (;;) {
const unsigned long start_time = jiffies;
- err = nfp_nsp_command(state, SPCODE_NOOP, 0, 0, 0);
+ err = nfp_nsp_command(state, SPCODE_NOOP);
if (err != -EAGAIN)
break;
@@ -501,53 +533,211 @@ int nfp_nsp_wait(struct nfp_nsp *state)
int nfp_nsp_device_soft_reset(struct nfp_nsp *state)
{
- return nfp_nsp_command(state, SPCODE_SOFT_RESET, 0, 0, 0);
+ return nfp_nsp_command(state, SPCODE_SOFT_RESET);
}
int nfp_nsp_mac_reinit(struct nfp_nsp *state)
{
- return nfp_nsp_command(state, SPCODE_MAC_INIT, 0, 0, 0);
+ return nfp_nsp_command(state, SPCODE_MAC_INIT);
+}
+
+static void nfp_nsp_load_fw_extended_msg(struct nfp_nsp *state, u32 ret_val)
+{
+ static const char * const major_msg[] = {
+ /* 0 */ "Firmware from driver loaded",
+ /* 1 */ "Firmware from flash loaded",
+ /* 2 */ "Firmware loading failure",
+ };
+ static const char * const minor_msg[] = {
+ /* 0 */ "",
+ /* 1 */ "no named partition on flash",
+ /* 2 */ "error reading from flash",
+ /* 3 */ "can not deflate",
+ /* 4 */ "not a trusted file",
+ /* 5 */ "can not parse FW file",
+ /* 6 */ "MIP not found in FW file",
+ /* 7 */ "null firmware name in MIP",
+ /* 8 */ "FW version none",
+ /* 9 */ "FW build number none",
+ /* 10 */ "no FW selection policy HWInfo key found",
+ /* 11 */ "static FW selection policy",
+ /* 12 */ "FW version has precedence",
+ /* 13 */ "different FW application load requested",
+ /* 14 */ "development build",
+ };
+ unsigned int major, minor;
+ const char *level;
+
+ major = FIELD_GET(NFP_FW_LOAD_RET_MAJOR, ret_val);
+ minor = FIELD_GET(NFP_FW_LOAD_RET_MINOR, ret_val);
+
+ if (!nfp_nsp_has_stored_fw_load(state))
+ return;
+
+ /* Lower the message level in legacy case */
+ if (major == 0 && (minor == 0 || minor == 10))
+ level = KERN_DEBUG;
+ else if (major == 2)
+ level = KERN_ERR;
+ else
+ level = KERN_INFO;
+
+ if (major >= ARRAY_SIZE(major_msg))
+ nfp_printk(level, state->cpp, "FW loading status: %x\n",
+ ret_val);
+ else if (minor >= ARRAY_SIZE(minor_msg))
+ nfp_printk(level, state->cpp, "%s, reason code: %d\n",
+ major_msg[major], minor);
+ else
+ nfp_printk(level, state->cpp, "%s%c %s\n",
+ major_msg[major], minor ? ',' : '.',
+ minor_msg[minor]);
}
int nfp_nsp_load_fw(struct nfp_nsp *state, const struct firmware *fw)
{
- return nfp_nsp_command_buf(state, SPCODE_FW_LOAD, fw->size, fw->data,
- fw->size, NULL, 0);
+ struct nfp_nsp_command_buf_arg load_fw = {
+ {
+ .code = SPCODE_FW_LOAD,
+ .option = fw->size,
+ .error_cb = nfp_nsp_load_fw_extended_msg,
+ },
+ .in_buf = fw->data,
+ .in_size = fw->size,
+ };
+ int ret;
+
+ ret = nfp_nsp_command_buf(state, &load_fw);
+ if (ret < 0)
+ return ret;
+
+ nfp_nsp_load_fw_extended_msg(state, ret);
+ return 0;
}
int nfp_nsp_write_flash(struct nfp_nsp *state, const struct firmware *fw)
{
- /* The flash time is specified to take a maximum of 70s so we add an
- * additional factor to this spec time.
- */
- u32 timeout_sec = 2.5 * 70;
-
- return __nfp_nsp_command_buf(state, SPCODE_NSP_WRITE_FLASH, fw->size,
- fw->data, fw->size, NULL, 0, timeout_sec);
+ struct nfp_nsp_command_buf_arg write_flash = {
+ {
+ .code = SPCODE_NSP_WRITE_FLASH,
+ .option = fw->size,
+ /* The flash time is specified to take a maximum of 70s
+ * so we add an additional factor to this spec time.
+ */
+ .timeout_sec = 2.5 * 70,
+ },
+ .in_buf = fw->data,
+ .in_size = fw->size,
+ };
+
+ return nfp_nsp_command_buf(state, &write_flash);
}
int nfp_nsp_read_eth_table(struct nfp_nsp *state, void *buf, unsigned int size)
{
- return nfp_nsp_command_buf(state, SPCODE_ETH_RESCAN, size, NULL, 0,
- buf, size);
+ struct nfp_nsp_command_buf_arg eth_rescan = {
+ {
+ .code = SPCODE_ETH_RESCAN,
+ .option = size,
+ },
+ .out_buf = buf,
+ .out_size = size,
+ };
+
+ return nfp_nsp_command_buf(state, &eth_rescan);
}
int nfp_nsp_write_eth_table(struct nfp_nsp *state,
const void *buf, unsigned int size)
{
- return nfp_nsp_command_buf(state, SPCODE_ETH_CONTROL, size, buf, size,
- NULL, 0);
+ struct nfp_nsp_command_buf_arg eth_ctrl = {
+ {
+ .code = SPCODE_ETH_CONTROL,
+ .option = size,
+ },
+ .in_buf = buf,
+ .in_size = size,
+ };
+
+ return nfp_nsp_command_buf(state, &eth_ctrl);
}
int nfp_nsp_read_identify(struct nfp_nsp *state, void *buf, unsigned int size)
{
- return nfp_nsp_command_buf(state, SPCODE_NSP_IDENTIFY, size, NULL, 0,
- buf, size);
+ struct nfp_nsp_command_buf_arg identify = {
+ {
+ .code = SPCODE_NSP_IDENTIFY,
+ .option = size,
+ },
+ .out_buf = buf,
+ .out_size = size,
+ };
+
+ return nfp_nsp_command_buf(state, &identify);
}
int nfp_nsp_read_sensors(struct nfp_nsp *state, unsigned int sensor_mask,
void *buf, unsigned int size)
{
- return nfp_nsp_command_buf(state, SPCODE_NSP_SENSORS, sensor_mask,
- NULL, 0, buf, size);
+ struct nfp_nsp_command_buf_arg sensors = {
+ {
+ .code = SPCODE_NSP_SENSORS,
+ .option = sensor_mask,
+ },
+ .out_buf = buf,
+ .out_size = size,
+ };
+
+ return nfp_nsp_command_buf(state, &sensors);
+}
+
+int nfp_nsp_load_stored_fw(struct nfp_nsp *state)
+{
+ const struct nfp_nsp_command_arg arg = {
+ .code = SPCODE_FW_STORED,
+ .error_cb = nfp_nsp_load_fw_extended_msg,
+ };
+ int ret;
+
+ ret = __nfp_nsp_command(state, &arg);
+ if (ret < 0)
+ return ret;
+
+ nfp_nsp_load_fw_extended_msg(state, ret);
+ return 0;
+}
+
+static int
+__nfp_nsp_hwinfo_lookup(struct nfp_nsp *state, void *buf, unsigned int size)
+{
+ struct nfp_nsp_command_buf_arg hwinfo_lookup = {
+ {
+ .code = SPCODE_HWINFO_LOOKUP,
+ .option = size,
+ },
+ .in_buf = buf,
+ .in_size = size,
+ .out_buf = buf,
+ .out_size = size,
+ };
+
+ return nfp_nsp_command_buf(state, &hwinfo_lookup);
+}
+
+int nfp_nsp_hwinfo_lookup(struct nfp_nsp *state, void *buf, unsigned int size)
+{
+ int err;
+
+ size = min_t(u32, size, NFP_HWINFO_LOOKUP_SIZE);
+
+ err = __nfp_nsp_hwinfo_lookup(state, buf, size);
+ if (err)
+ return err;
+
+ if (strnlen(buf, size) == size) {
+ nfp_err(state->cpp, "NSP HWinfo value not NULL-terminated\n");
+ return -EINVAL;
+ }
+
+ return 0;
}
diff --git a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp.h b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp.h
index f23d9e06f097..bd6c9071c8e9 100644
--- a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp.h
+++ b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp.h
@@ -50,12 +50,24 @@ int nfp_nsp_device_soft_reset(struct nfp_nsp *state);
int nfp_nsp_load_fw(struct nfp_nsp *state, const struct firmware *fw);
int nfp_nsp_write_flash(struct nfp_nsp *state, const struct firmware *fw);
int nfp_nsp_mac_reinit(struct nfp_nsp *state);
+int nfp_nsp_load_stored_fw(struct nfp_nsp *state);
+int nfp_nsp_hwinfo_lookup(struct nfp_nsp *state, void *buf, unsigned int size);
static inline bool nfp_nsp_has_mac_reinit(struct nfp_nsp *state)
{
return nfp_nsp_get_abi_ver_minor(state) > 20;
}
+static inline bool nfp_nsp_has_stored_fw_load(struct nfp_nsp *state)
+{
+ return nfp_nsp_get_abi_ver_minor(state) > 23;
+}
+
+static inline bool nfp_nsp_has_hwinfo_lookup(struct nfp_nsp *state)
+{
+ return nfp_nsp_get_abi_ver_minor(state) > 24;
+}
+
enum nfp_eth_interface {
NFP_INTERFACE_NONE = 0,
NFP_INTERFACE_SFP = 1,
diff --git a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_rtsym.c b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_rtsym.c
index 9e34216578da..1ad0a015572e 100644
--- a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_rtsym.c
+++ b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_rtsym.c
@@ -39,6 +39,8 @@
* Espen Skoglund <espen.skoglund@netronome.com>
* Francois H. Theron <francois.theron@netronome.com>
*/
+
+#include <asm/unaligned.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
@@ -233,6 +235,229 @@ nfp_rtsym_lookup(struct nfp_rtsym_table *rtbl, const char *name)
return NULL;
}
+u64 nfp_rtsym_size(const struct nfp_rtsym *sym)
+{
+ switch (sym->type) {
+ case NFP_RTSYM_TYPE_NONE:
+ pr_err("rtsym '%s': type NONE\n", sym->name);
+ return 0;
+ default:
+ pr_warn("rtsym '%s': unknown type: %d\n", sym->name, sym->type);
+ /* fall through */
+ case NFP_RTSYM_TYPE_OBJECT:
+ case NFP_RTSYM_TYPE_FUNCTION:
+ return sym->size;
+ case NFP_RTSYM_TYPE_ABS:
+ return sizeof(u64);
+ }
+}
+
+static int
+nfp_rtsym_to_dest(struct nfp_cpp *cpp, const struct nfp_rtsym *sym,
+ u8 action, u8 token, u64 off, u32 *cpp_id, u64 *addr)
+{
+ if (sym->type != NFP_RTSYM_TYPE_OBJECT) {
+ nfp_err(cpp, "rtsym '%s': direct access to non-object rtsym\n",
+ sym->name);
+ return -EINVAL;
+ }
+
+ *addr = sym->addr + off;
+
+ if (sym->target == NFP_RTSYM_TARGET_EMU_CACHE) {
+ int locality_off = nfp_cpp_mu_locality_lsb(cpp);
+
+ *addr &= ~(NFP_MU_ADDR_ACCESS_TYPE_MASK << locality_off);
+ *addr |= NFP_MU_ADDR_ACCESS_TYPE_DIRECT << locality_off;
+
+ *cpp_id = NFP_CPP_ISLAND_ID(NFP_CPP_TARGET_MU, action, token,
+ sym->domain);
+ } else if (sym->target < 0) {
+ nfp_err(cpp, "rtsym '%s': unhandled target encoding: %d\n",
+ sym->name, sym->target);
+ return -EINVAL;
+ } else {
+ *cpp_id = NFP_CPP_ISLAND_ID(sym->target, action, token,
+ sym->domain);
+ }
+
+ return 0;
+}
+
+int __nfp_rtsym_read(struct nfp_cpp *cpp, const struct nfp_rtsym *sym,
+ u8 action, u8 token, u64 off, void *buf, size_t len)
+{
+ u64 sym_size = nfp_rtsym_size(sym);
+ u32 cpp_id;
+ u64 addr;
+ int err;
+
+ if (off > sym_size) {
+ nfp_err(cpp, "rtsym '%s': read out of bounds: off: %lld + len: %zd > size: %lld\n",
+ sym->name, off, len, sym_size);
+ return -ENXIO;
+ }
+ len = min_t(size_t, len, sym_size - off);
+
+ if (sym->type == NFP_RTSYM_TYPE_ABS) {
+ u8 tmp[8];
+
+ put_unaligned_le64(sym->addr, tmp);
+ memcpy(buf, &tmp[off], len);
+
+ return len;
+ }
+
+ err = nfp_rtsym_to_dest(cpp, sym, action, token, off, &cpp_id, &addr);
+ if (err)
+ return err;
+
+ return nfp_cpp_read(cpp, cpp_id, addr, buf, len);
+}
+
+int nfp_rtsym_read(struct nfp_cpp *cpp, const struct nfp_rtsym *sym, u64 off,
+ void *buf, size_t len)
+{
+ return __nfp_rtsym_read(cpp, sym, NFP_CPP_ACTION_RW, 0, off, buf, len);
+}
+
+int __nfp_rtsym_readl(struct nfp_cpp *cpp, const struct nfp_rtsym *sym,
+ u8 action, u8 token, u64 off, u32 *value)
+{
+ u32 cpp_id;
+ u64 addr;
+ int err;
+
+ if (off + 4 > nfp_rtsym_size(sym)) {
+ nfp_err(cpp, "rtsym '%s': readl out of bounds: off: %lld + 4 > size: %lld\n",
+ sym->name, off, nfp_rtsym_size(sym));
+ return -ENXIO;
+ }
+
+ err = nfp_rtsym_to_dest(cpp, sym, action, token, off, &cpp_id, &addr);
+ if (err)
+ return err;
+
+ return nfp_cpp_readl(cpp, cpp_id, addr, value);
+}
+
+int nfp_rtsym_readl(struct nfp_cpp *cpp, const struct nfp_rtsym *sym, u64 off,
+ u32 *value)
+{
+ return __nfp_rtsym_readl(cpp, sym, NFP_CPP_ACTION_RW, 0, off, value);
+}
+
+int __nfp_rtsym_readq(struct nfp_cpp *cpp, const struct nfp_rtsym *sym,
+ u8 action, u8 token, u64 off, u64 *value)
+{
+ u32 cpp_id;
+ u64 addr;
+ int err;
+
+ if (off + 8 > nfp_rtsym_size(sym)) {
+ nfp_err(cpp, "rtsym '%s': readq out of bounds: off: %lld + 8 > size: %lld\n",
+ sym->name, off, nfp_rtsym_size(sym));
+ return -ENXIO;
+ }
+
+ if (sym->type == NFP_RTSYM_TYPE_ABS) {
+ *value = sym->addr;
+ return 0;
+ }
+
+ err = nfp_rtsym_to_dest(cpp, sym, action, token, off, &cpp_id, &addr);
+ if (err)
+ return err;
+
+ return nfp_cpp_readq(cpp, cpp_id, addr, value);
+}
+
+int nfp_rtsym_readq(struct nfp_cpp *cpp, const struct nfp_rtsym *sym, u64 off,
+ u64 *value)
+{
+ return __nfp_rtsym_readq(cpp, sym, NFP_CPP_ACTION_RW, 0, off, value);
+}
+
+int __nfp_rtsym_write(struct nfp_cpp *cpp, const struct nfp_rtsym *sym,
+ u8 action, u8 token, u64 off, void *buf, size_t len)
+{
+ u64 sym_size = nfp_rtsym_size(sym);
+ u32 cpp_id;
+ u64 addr;
+ int err;
+
+ if (off > sym_size) {
+ nfp_err(cpp, "rtsym '%s': write out of bounds: off: %lld + len: %zd > size: %lld\n",
+ sym->name, off, len, sym_size);
+ return -ENXIO;
+ }
+ len = min_t(size_t, len, sym_size - off);
+
+ err = nfp_rtsym_to_dest(cpp, sym, action, token, off, &cpp_id, &addr);
+ if (err)
+ return err;
+
+ return nfp_cpp_write(cpp, cpp_id, addr, buf, len);
+}
+
+int nfp_rtsym_write(struct nfp_cpp *cpp, const struct nfp_rtsym *sym, u64 off,
+ void *buf, size_t len)
+{
+ return __nfp_rtsym_write(cpp, sym, NFP_CPP_ACTION_RW, 0, off, buf, len);
+}
+
+int __nfp_rtsym_writel(struct nfp_cpp *cpp, const struct nfp_rtsym *sym,
+ u8 action, u8 token, u64 off, u32 value)
+{
+ u32 cpp_id;
+ u64 addr;
+ int err;
+
+ if (off + 4 > nfp_rtsym_size(sym)) {
+ nfp_err(cpp, "rtsym '%s': writel out of bounds: off: %lld + 4 > size: %lld\n",
+ sym->name, off, nfp_rtsym_size(sym));
+ return -ENXIO;
+ }
+
+ err = nfp_rtsym_to_dest(cpp, sym, action, token, off, &cpp_id, &addr);
+ if (err)
+ return err;
+
+ return nfp_cpp_writel(cpp, cpp_id, addr, value);
+}
+
+int nfp_rtsym_writel(struct nfp_cpp *cpp, const struct nfp_rtsym *sym, u64 off,
+ u32 value)
+{
+ return __nfp_rtsym_writel(cpp, sym, NFP_CPP_ACTION_RW, 0, off, value);
+}
+
+int __nfp_rtsym_writeq(struct nfp_cpp *cpp, const struct nfp_rtsym *sym,
+ u8 action, u8 token, u64 off, u64 value)
+{
+ u32 cpp_id;
+ u64 addr;
+ int err;
+
+ if (off + 8 > nfp_rtsym_size(sym)) {
+ nfp_err(cpp, "rtsym '%s': writeq out of bounds: off: %lld + 8 > size: %lld\n",
+ sym->name, off, nfp_rtsym_size(sym));
+ return -ENXIO;
+ }
+
+ err = nfp_rtsym_to_dest(cpp, sym, action, token, off, &cpp_id, &addr);
+ if (err)
+ return err;
+
+ return nfp_cpp_writeq(cpp, cpp_id, addr, value);
+}
+
+int nfp_rtsym_writeq(struct nfp_cpp *cpp, const struct nfp_rtsym *sym, u64 off,
+ u64 value)
+{
+ return __nfp_rtsym_writeq(cpp, sym, NFP_CPP_ACTION_RW, 0, off, value);
+}
+
/**
* nfp_rtsym_read_le() - Read a simple unsigned scalar value from symbol
* @rtbl: NFP RTsym table
@@ -249,7 +474,7 @@ u64 nfp_rtsym_read_le(struct nfp_rtsym_table *rtbl, const char *name,
int *error)
{
const struct nfp_rtsym *sym;
- u32 val32, id;
+ u32 val32;
u64 val;
int err;
@@ -259,20 +484,18 @@ u64 nfp_rtsym_read_le(struct nfp_rtsym_table *rtbl, const char *name,
goto exit;
}
- id = NFP_CPP_ISLAND_ID(sym->target, NFP_CPP_ACTION_RW, 0, sym->domain);
-
- switch (sym->size) {
+ switch (nfp_rtsym_size(sym)) {
case 4:
- err = nfp_cpp_readl(rtbl->cpp, id, sym->addr, &val32);
+ err = nfp_rtsym_readl(rtbl->cpp, sym, 0, &val32);
val = val32;
break;
case 8:
- err = nfp_cpp_readq(rtbl->cpp, id, sym->addr, &val);
+ err = nfp_rtsym_readq(rtbl->cpp, sym, 0, &val);
break;
default:
nfp_err(rtbl->cpp,
- "rtsym '%s' unsupported or non-scalar size: %lld\n",
- name, sym->size);
+ "rtsym '%s': unsupported or non-scalar size: %lld\n",
+ name, nfp_rtsym_size(sym));
err = -EINVAL;
break;
}
@@ -303,25 +526,22 @@ int nfp_rtsym_write_le(struct nfp_rtsym_table *rtbl, const char *name,
{
const struct nfp_rtsym *sym;
int err;
- u32 id;
sym = nfp_rtsym_lookup(rtbl, name);
if (!sym)
return -ENOENT;
- id = NFP_CPP_ISLAND_ID(sym->target, NFP_CPP_ACTION_RW, 0, sym->domain);
-
- switch (sym->size) {
+ switch (nfp_rtsym_size(sym)) {
case 4:
- err = nfp_cpp_writel(rtbl->cpp, id, sym->addr, value);
+ err = nfp_rtsym_writel(rtbl->cpp, sym, 0, value);
break;
case 8:
- err = nfp_cpp_writeq(rtbl->cpp, id, sym->addr, value);
+ err = nfp_rtsym_writeq(rtbl->cpp, sym, 0, value);
break;
default:
nfp_err(rtbl->cpp,
- "rtsym '%s' unsupported or non-scalar size: %lld\n",
- name, sym->size);
+ "rtsym '%s': unsupported or non-scalar size: %lld\n",
+ name, nfp_rtsym_size(sym));
err = -EINVAL;
break;
}
@@ -335,20 +555,29 @@ nfp_rtsym_map(struct nfp_rtsym_table *rtbl, const char *name, const char *id,
{
const struct nfp_rtsym *sym;
u8 __iomem *mem;
+ u32 cpp_id;
+ u64 addr;
+ int err;
sym = nfp_rtsym_lookup(rtbl, name);
if (!sym)
return (u8 __iomem *)ERR_PTR(-ENOENT);
+ err = nfp_rtsym_to_dest(rtbl->cpp, sym, NFP_CPP_ACTION_RW, 0, 0,
+ &cpp_id, &addr);
+ if (err) {
+ nfp_err(rtbl->cpp, "rtsym '%s': mapping failed\n", name);
+ return (u8 __iomem *)ERR_PTR(err);
+ }
+
if (sym->size < min_size) {
- nfp_err(rtbl->cpp, "Symbol %s too small\n", name);
+ nfp_err(rtbl->cpp, "rtsym '%s': too small\n", name);
return (u8 __iomem *)ERR_PTR(-EINVAL);
}
- mem = nfp_cpp_map_area(rtbl->cpp, id, sym->domain, sym->target,
- sym->addr, sym->size, area);
+ mem = nfp_cpp_map_area(rtbl->cpp, id, cpp_id, addr, sym->size, area);
if (IS_ERR(mem)) {
- nfp_err(rtbl->cpp, "Failed to map symbol %s: %ld\n",
+ nfp_err(rtbl->cpp, "rtysm '%s': failed to map: %ld\n",
name, PTR_ERR(mem));
return mem;
}
diff --git a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_target.c b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_target.c
index 4ea1e585d945..f691c6587c76 100644
--- a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_target.c
+++ b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_target.c
@@ -39,7 +39,11 @@
* Francois H. Theron <francois.theron@netronome.com>
*/
+#define pr_fmt(fmt) "NFP target: " fmt
+
#include <linux/bitops.h>
+#include <linux/kernel.h>
+#include <linux/printk.h>
#include "nfp_cpp.h"
@@ -733,8 +737,10 @@ int nfp_target_cpp(u32 cpp_island_id, u64 cpp_island_address,
u32 imb;
int err;
- if (target < 0 || target >= 16)
+ if (target < 0 || target >= 16) {
+ pr_err("Invalid CPP target: %d\n", target);
return -EINVAL;
+ }
if (island == 0) {
/* Already translated */
@@ -753,8 +759,10 @@ int nfp_target_cpp(u32 cpp_island_id, u64 cpp_island_address,
err = nfp_cppat_addr_encode(cpp_target_address, island, target,
((imb >> 13) & 7), ((imb >> 12) & 1),
((imb >> 6) & 0x3f), ((imb >> 0) & 0x3f));
- if (err)
+ if (err) {
+ pr_err("Can't encode CPP address: %d\n", err);
return err;
+ }
*cpp_target_id = NFP_CPP_ID(target,
NFP_CPP_ID_ACTION_of(cpp_island_id),