Commit 817e60a7 authored by David S. Miller's avatar David S. Miller

Merge branch 'nfp-add-NFP5000-support'

Jakub Kicinski says:

====================
nfp: add NFP5000 support

This series broadly speaking adds support for NFP5000 and
related products.

First we add support for loading FW from flash.  We need to allow
for the management processor to provide extended log messages when
FW is loaded.  This is needed when FW selection policy is to compare
the FW on the disk and in the flash, and load the newer.  User should
be told what FW was selected.

We use this opportunity to add extended errors for normal FW loading
as well.

Next we add support for requesting HW information from the management
processor.  Up until now the driver read the HWinfo as it appears in
card memory, but there can be cases when management processor has
additional information or generates the entries dynamically so
occasionally we will have to consult it.  We use this to look up MAC
addresses for PCIe netdevs.

Next the actual patch with NFP5000 support and a small dose of
refactoring of PCIe init.

The remaining patches add support for reading RTsymbol types we
didn't need before.  Ones explicitly placed in external memory unit's
cache and absolute ones.

This part begins with a patch moving the logic which figures out
the correct bit offsets to device probe, to avoid redoing the
calculation for each access.  Second patch adds error messages
for easier troubleshooting.  Next patch adds helpers which will
take care of address conversions to reach into EMU cache.
Subsequently users are migrated from the raw CPP API to the new RTsym
helpers.  Finally we add support for reading absolute symbols.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 09990ad1 4152e58c
......@@ -55,30 +55,21 @@
#define NFP_QMSTAT_DROP 16
#define NFP_QMSTAT_ECN 24
static unsigned long long
nfp_abm_q_lvl_thrs(struct nfp_abm_link *alink, unsigned int queue)
{
return alink->abm->q_lvls->addr +
(alink->queue_base + queue) * NFP_QLVL_STRIDE + NFP_QLVL_THRS;
}
static int
nfp_abm_ctrl_stat(struct nfp_abm_link *alink, const struct nfp_rtsym *sym,
unsigned int stride, unsigned int offset, unsigned int i,
bool is_u64, u64 *res)
{
struct nfp_cpp *cpp = alink->abm->app->cpp;
u32 val32, mur;
u64 val, addr;
u64 val, sym_offset;
u32 val32;
int err;
mur = NFP_CPP_ATOMIC_RD(sym->target, sym->domain);
addr = sym->addr + (alink->queue_base + i) * stride + offset;
sym_offset = (alink->queue_base + i) * stride + offset;
if (is_u64)
err = nfp_cpp_readq(cpp, mur, addr, &val);
err = __nfp_rtsym_readq(cpp, sym, 3, 0, sym_offset, &val);
else
err = nfp_cpp_readl(cpp, mur, addr, &val32);
err = __nfp_rtsym_readl(cpp, sym, 3, 0, sym_offset, &val32);
if (err) {
nfp_err(cpp,
"RED offload reading stat failed on vNIC %d queue %d\n",
......@@ -114,13 +105,12 @@ nfp_abm_ctrl_stat_all(struct nfp_abm_link *alink, const struct nfp_rtsym *sym,
int nfp_abm_ctrl_set_q_lvl(struct nfp_abm_link *alink, unsigned int i, u32 val)
{
struct nfp_cpp *cpp = alink->abm->app->cpp;
u32 muw;
u64 sym_offset;
int err;
muw = NFP_CPP_ATOMIC_WR(alink->abm->q_lvls->target,
alink->abm->q_lvls->domain);
err = nfp_cpp_writel(cpp, muw, nfp_abm_q_lvl_thrs(alink, i), val);
sym_offset = (alink->queue_base + i) * NFP_QLVL_STRIDE + NFP_QLVL_THRS;
err = __nfp_rtsym_writel(cpp, alink->abm->q_lvls, 4, 0,
sym_offset, val);
if (err) {
nfp_err(cpp, "RED offload setting level failed on vNIC %d queue %d\n",
alink->id, i);
......@@ -290,10 +280,10 @@ nfp_abm_ctrl_find_rtsym(struct nfp_pf *pf, const char *name, unsigned int size)
nfp_err(pf->cpp, "Symbol '%s' not found\n", name);
return ERR_PTR(-ENOENT);
}
if (sym->size != size) {
if (nfp_rtsym_size(sym) != size) {
nfp_err(pf->cpp,
"Symbol '%s' wrong size: expected %u got %llu\n",
name, size, sym->size);
name, size, nfp_rtsym_size(sym));
return ERR_PTR(-EINVAL);
}
......
......@@ -540,8 +540,9 @@ nfp_abm_vnic_set_mac(struct nfp_pf *pf, struct nfp_abm *abm, struct nfp_net *nn,
{
struct nfp_eth_table_port *eth_port = &pf->eth_tbl->ports[id];
u8 mac_addr[ETH_ALEN];
const char *mac_str;
char name[32];
struct nfp_nsp *nsp;
char hwinfo[32];
int err;
if (id > pf->eth_tbl->count) {
nfp_warn(pf->cpp, "No entry for persistent MAC address\n");
......@@ -549,22 +550,37 @@ nfp_abm_vnic_set_mac(struct nfp_pf *pf, struct nfp_abm *abm, struct nfp_net *nn,
return;
}
snprintf(name, sizeof(name), "eth%u.mac.pf%u",
snprintf(hwinfo, sizeof(hwinfo), "eth%u.mac.pf%u",
eth_port->eth_index, abm->pf_id);
mac_str = nfp_hwinfo_lookup(pf->hwinfo, name);
if (!mac_str) {
nfp_warn(pf->cpp, "Can't lookup persistent MAC address (%s)\n",
name);
nsp = nfp_nsp_open(pf->cpp);
if (IS_ERR(nsp)) {
nfp_warn(pf->cpp, "Failed to access the NSP for persistent MAC address: %ld\n",
PTR_ERR(nsp));
eth_hw_addr_random(nn->dp.netdev);
return;
}
if (!nfp_nsp_has_hwinfo_lookup(nsp)) {
nfp_warn(pf->cpp, "NSP doesn't support PF MAC generation\n");
eth_hw_addr_random(nn->dp.netdev);
return;
}
err = nfp_nsp_hwinfo_lookup(nsp, hwinfo, sizeof(hwinfo));
nfp_nsp_close(nsp);
if (err) {
nfp_warn(pf->cpp, "Reading persistent MAC address failed: %d\n",
err);
eth_hw_addr_random(nn->dp.netdev);
return;
}
if (sscanf(mac_str, "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx",
if (sscanf(hwinfo, "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx",
&mac_addr[0], &mac_addr[1], &mac_addr[2],
&mac_addr[3], &mac_addr[4], &mac_addr[5]) != 6) {
nfp_warn(pf->cpp, "Can't parse persistent MAC address (%s)\n",
mac_str);
hwinfo);
eth_hw_addr_random(nn->dp.netdev);
return;
}
......
......@@ -68,6 +68,10 @@ static const struct pci_device_id nfp_pci_device_ids[] = {
PCI_VENDOR_ID_NETRONOME, PCI_ANY_ID,
PCI_ANY_ID, 0,
},
{ PCI_VENDOR_ID_NETRONOME, PCI_DEVICE_ID_NETRONOME_NFP5000,
PCI_VENDOR_ID_NETRONOME, PCI_ANY_ID,
PCI_ANY_ID, 0,
},
{ PCI_VENDOR_ID_NETRONOME, PCI_DEVICE_ID_NETRONOME_NFP4000,
PCI_VENDOR_ID_NETRONOME, PCI_ANY_ID,
PCI_ANY_ID, 0,
......@@ -112,23 +116,18 @@ nfp_pf_map_rtsym(struct nfp_pf *pf, const char *name, const char *sym_fmt,
int nfp_mbox_cmd(struct nfp_pf *pf, u32 cmd, void *in_data, u64 in_length,
void *out_data, u64 out_length)
{
unsigned long long addr;
unsigned long err_at;
u64 max_data_sz;
u32 val = 0;
u32 cpp_id;
int n, err;
if (!pf->mbox)
return -EOPNOTSUPP;
cpp_id = NFP_CPP_ISLAND_ID(pf->mbox->target, NFP_CPP_ACTION_RW, 0,
pf->mbox->domain);
addr = pf->mbox->addr;
max_data_sz = pf->mbox->size - NFP_MBOX_SYM_MIN_SIZE;
max_data_sz = nfp_rtsym_size(pf->mbox) - NFP_MBOX_SYM_MIN_SIZE;
/* Check if cmd field is clear */
err = nfp_cpp_readl(pf->cpp, cpp_id, addr + NFP_MBOX_CMD, &val);
err = nfp_rtsym_readl(pf->cpp, pf->mbox, NFP_MBOX_CMD, &val);
if (err || val) {
nfp_warn(pf->cpp, "failed to issue command (%u): %u, err: %d\n",
cmd, val, err);
......@@ -136,30 +135,29 @@ int nfp_mbox_cmd(struct nfp_pf *pf, u32 cmd, void *in_data, u64 in_length,
}
in_length = min(in_length, max_data_sz);
n = nfp_cpp_write(pf->cpp, cpp_id, addr + NFP_MBOX_DATA,
in_data, in_length);
n = nfp_rtsym_write(pf->cpp, pf->mbox, NFP_MBOX_DATA, in_data,
in_length);
if (n != in_length)
return -EIO;
/* Write data_len and wipe reserved */
err = nfp_cpp_writeq(pf->cpp, cpp_id, addr + NFP_MBOX_DATA_LEN,
in_length);
err = nfp_rtsym_writeq(pf->cpp, pf->mbox, NFP_MBOX_DATA_LEN, in_length);
if (err)
return err;
/* Read back for ordering */
err = nfp_cpp_readl(pf->cpp, cpp_id, addr + NFP_MBOX_DATA_LEN, &val);
err = nfp_rtsym_readl(pf->cpp, pf->mbox, NFP_MBOX_DATA_LEN, &val);
if (err)
return err;
/* Write cmd and wipe return value */
err = nfp_cpp_writeq(pf->cpp, cpp_id, addr + NFP_MBOX_CMD, cmd);
err = nfp_rtsym_writeq(pf->cpp, pf->mbox, NFP_MBOX_CMD, cmd);
if (err)
return err;
err_at = jiffies + 5 * HZ;
while (true) {
/* Wait for command to go to 0 (NFP_MBOX_NO_CMD) */
err = nfp_cpp_readl(pf->cpp, cpp_id, addr + NFP_MBOX_CMD, &val);
err = nfp_rtsym_readl(pf->cpp, pf->mbox, NFP_MBOX_CMD, &val);
if (err)
return err;
if (!val)
......@@ -172,18 +170,18 @@ int nfp_mbox_cmd(struct nfp_pf *pf, u32 cmd, void *in_data, u64 in_length,
}
/* Copy output if any (could be error info, do it before reading ret) */
err = nfp_cpp_readl(pf->cpp, cpp_id, addr + NFP_MBOX_DATA_LEN, &val);
err = nfp_rtsym_readl(pf->cpp, pf->mbox, NFP_MBOX_DATA_LEN, &val);
if (err)
return err;
out_length = min_t(u32, val, min(out_length, max_data_sz));
n = nfp_cpp_read(pf->cpp, cpp_id, addr + NFP_MBOX_DATA,
n = nfp_rtsym_read(pf->cpp, pf->mbox, NFP_MBOX_DATA,
out_data, out_length);
if (n != out_length)
return -EIO;
/* Check if there is an error */
err = nfp_cpp_readl(pf->cpp, cpp_id, addr + NFP_MBOX_RET, &val);
err = nfp_rtsym_readl(pf->cpp, pf->mbox, NFP_MBOX_RET, &val);
if (err)
return err;
if (val)
......@@ -441,8 +439,11 @@ nfp_fw_load(struct pci_dev *pdev, struct nfp_pf *pf, struct nfp_nsp *nsp)
}
fw = nfp_net_fw_find(pdev, pf);
if (!fw)
if (!fw) {
if (nfp_nsp_has_stored_fw_load(nsp))
nfp_nsp_load_stored_fw(nsp);
return 0;
}
dev_info(&pdev->dev, "Soft-reset, loading FW image\n");
err = nfp_nsp_device_soft_reset(nsp);
......@@ -453,7 +454,6 @@ nfp_fw_load(struct pci_dev *pdev, struct nfp_pf *pf, struct nfp_nsp *nsp)
}
err = nfp_nsp_load_fw(nsp, fw);
if (err < 0) {
dev_err(&pdev->dev, "FW loading failed: %d\n", err);
goto exit_release_fw;
......@@ -566,9 +566,9 @@ static int nfp_pf_find_rtsyms(struct nfp_pf *pf)
/* Optional per-PCI PF mailbox */
snprintf(pf_symbol, sizeof(pf_symbol), NFP_MBOX_SYM_NAME, pf_id);
pf->mbox = nfp_rtsym_lookup(pf->rtbl, pf_symbol);
if (pf->mbox && pf->mbox->size < NFP_MBOX_SYM_MIN_SIZE) {
if (pf->mbox && nfp_rtsym_size(pf->mbox) < NFP_MBOX_SYM_MIN_SIZE) {
nfp_err(pf->cpp, "PF mailbox symbol too small: %llu < %d\n",
pf->mbox->size, NFP_MBOX_SYM_MIN_SIZE);
nfp_rtsym_size(pf->mbox), NFP_MBOX_SYM_MIN_SIZE);
return -EINVAL;
}
......
......@@ -188,25 +188,21 @@ nfp_net_dump_load_dumpspec(struct nfp_cpp *cpp, struct nfp_rtsym_table *rtbl)
const struct nfp_rtsym *specsym;
struct nfp_dumpspec *dumpspec;
int bytes_read;
u32 cpp_id;
u64 sym_size;
specsym = nfp_rtsym_lookup(rtbl, NFP_DUMP_SPEC_RTSYM);
if (!specsym)
return NULL;
sym_size = nfp_rtsym_size(specsym);
/* expected size of this buffer is in the order of tens of kilobytes */
dumpspec = vmalloc(sizeof(*dumpspec) + specsym->size);
dumpspec = vmalloc(sizeof(*dumpspec) + sym_size);
if (!dumpspec)
return NULL;
dumpspec->size = sym_size;
dumpspec->size = specsym->size;
cpp_id = NFP_CPP_ISLAND_ID(specsym->target, NFP_CPP_ACTION_RW, 0,
specsym->domain);
bytes_read = nfp_cpp_read(cpp, cpp_id, specsym->addr, dumpspec->data,
specsym->size);
if (bytes_read != specsym->size) {
bytes_read = nfp_rtsym_read(cpp, specsym, 0, dumpspec->data, sym_size);
if (bytes_read != sym_size) {
vfree(dumpspec);
nfp_warn(cpp, "Debug dump specification read failed.\n");
return NULL;
......@@ -266,7 +262,6 @@ nfp_calc_rtsym_dump_sz(struct nfp_pf *pf, struct nfp_dump_tl *spec)
struct nfp_dumpspec_rtsym *spec_rtsym;
const struct nfp_rtsym *sym;
u32 tl_len, key_len;
u32 size;
spec_rtsym = (struct nfp_dumpspec_rtsym *)spec;
tl_len = be32_to_cpu(spec->length);
......@@ -278,13 +273,8 @@ nfp_calc_rtsym_dump_sz(struct nfp_pf *pf, struct nfp_dump_tl *spec)
if (!sym)
return nfp_dump_error_tlv_size(spec);
if (sym->type == NFP_RTSYM_TYPE_ABS)
size = sizeof(sym->addr);
else
size = sym->size;
return ALIGN8(offsetof(struct nfp_dump_rtsym, rtsym) + key_len + 1) +
ALIGN8(size);
ALIGN8(nfp_rtsym_size(sym));
}
static int
......@@ -644,7 +634,6 @@ nfp_dump_single_rtsym(struct nfp_pf *pf, struct nfp_dumpspec_rtsym *spec,
const struct nfp_rtsym *sym;
u32 tl_len, key_len;
int bytes_read;
u32 cpp_id;
void *dest;
int err;
......@@ -657,11 +646,7 @@ nfp_dump_single_rtsym(struct nfp_pf *pf, struct nfp_dumpspec_rtsym *spec,
if (!sym)
return nfp_dump_error_tlv(&spec->tl, -ENOENT, dump);
if (sym->type == NFP_RTSYM_TYPE_ABS)
sym_size = sizeof(sym->addr);
else
sym_size = sym->size;
sym_size = nfp_rtsym_size(sym);
header_size =
ALIGN8(offsetof(struct nfp_dump_rtsym, rtsym) + key_len + 1);
total_size = header_size + ALIGN8(sym_size);
......@@ -676,24 +661,21 @@ nfp_dump_single_rtsym(struct nfp_pf *pf, struct nfp_dumpspec_rtsym *spec,
memcpy(dump_header->rtsym, spec->rtsym, key_len + 1);
dump_header->cpp.dump_length = cpu_to_be32(sym_size);
if (sym->type == NFP_RTSYM_TYPE_ABS) {
*(u64 *)dest = sym->addr;
} else {
if (sym->type != NFP_RTSYM_TYPE_ABS) {
cpp_params.target = sym->target;
cpp_params.action = NFP_CPP_ACTION_RW;
cpp_params.token = 0;
cpp_params.island = sym->domain;
cpp_id = nfp_get_numeric_cpp_id(&cpp_params);
dump_header->cpp.cpp_id = cpp_params;
dump_header->cpp.offset = cpu_to_be32(sym->addr);
bytes_read = nfp_cpp_read(pf->cpp, cpp_id, sym->addr, dest,
sym_size);
}
bytes_read = nfp_rtsym_read(pf->cpp, sym, 0, dest, sym_size);
if (bytes_read != sym_size) {
if (bytes_read >= 0)
bytes_read = -EIO;
dump_header->error = cpu_to_be32(bytes_read);
}
}
return 0;
}
......
......@@ -470,8 +470,8 @@ static void nfp_net_pci_unmap_mem(struct nfp_pf *pf)
static int nfp_net_pci_map_mem(struct nfp_pf *pf)
{
u32 min_size, cpp_id;
u8 __iomem *mem;
u32 min_size;
int err;
min_size = pf->max_data_vnics * NFP_PF_CSR_SLICE_SIZE;
......@@ -519,9 +519,9 @@ static int nfp_net_pci_map_mem(struct nfp_pf *pf)
pf->vfcfg_tbl2 = NULL;
}
mem = nfp_cpp_map_area(pf->cpp, "net.qc", 0, 0,
NFP_PCIE_QUEUE(0), NFP_QCP_QUEUE_AREA_SZ,
&pf->qc_area);
cpp_id = NFP_CPP_ISLAND_ID(0, NFP_CPP_ACTION_RW, 0, 0);
mem = nfp_cpp_map_area(pf->cpp, "net.qc", cpp_id, NFP_PCIE_QUEUE(0),
NFP_QCP_QUEUE_AREA_SZ, &pf->qc_area);
if (IS_ERR(mem)) {
nfp_err(pf->cpp, "Failed to map Queue Controller area.\n");
err = PTR_ERR(mem);
......
......@@ -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);
......
......@@ -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;
......
......@@ -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));
......
......@@ -294,8 +294,7 @@ int nfp_cpp_explicit_write(struct nfp_cpp *cpp, u32 cpp_id, u64 addr,
* 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 @@ int nfp_cpp_explicit_write(struct nfp_cpp *cpp, u32 cpp_id, u64 addr,
* 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;
......
......@@ -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;
......
......@@ -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,
......
......@@ -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,7 +408,10 @@ __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);
-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;
}
......@@ -380,18 +419,17 @@ __nfp_nsp_command(struct nfp_nsp *state, u16 code, u32 option, u32 buff_cpp,
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.
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.
*/
u32 timeout_sec = 2.5 * 70;
.timeout_sec = 2.5 * 70,
},
.in_buf = fw->data,
.in_size = fw->size,
};
return __nfp_nsp_command_buf(state, SPCODE_NSP_WRITE_FLASH, fw->size,
fw->data, fw->size, NULL, 0, timeout_sec);
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;
}
......@@ -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,
......
......@@ -233,6 +233,186 @@ 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 type NONE\n");
return 0;
default:
pr_warn("Unknown rtsym type: %d\n", 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, "Direct access attempt to non-object rtsym\n");
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, "Unhandled RTsym target encoding: %d\n",
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)
{
u32 cpp_id;
u64 addr;
int err;
if (sym->type == NFP_RTSYM_TYPE_ABS) {
__le64 tmp = cpu_to_le64(sym->addr);
len = min(len, sizeof(tmp));
memcpy(buf, &tmp, 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;
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 (sym->type == NFP_RTSYM_TYPE_ABS)
return sym->addr;
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)
{
u32 cpp_id;
u64 addr;
int err;
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;
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;
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 +429,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 +439,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);
name, nfp_rtsym_size(sym));
err = -EINVAL;
break;
}
......@@ -303,25 +481,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);
name, nfp_rtsym_size(sym));
err = -EINVAL;
break;
}
......@@ -335,18 +510,27 @@ 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, "Symbol %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);
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",
name, PTR_ERR(mem));
......
......@@ -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),
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment