static struct nfp_hwinfo * hwinfo_try_fetch(struct nfp_cpp *cpp, size_t *cpp_size) { struct nfp_hwinfo *header; struct nfp_resource *res; u64 cpp_addr; u32 cpp_id; int err; u8 *db; res = nfp_resource_acquire(cpp, NFP_RESOURCE_NFP_HWINFO); if (!IS_ERR(res)) { cpp_id = nfp_resource_cpp_id(res); cpp_addr = nfp_resource_address(res); *cpp_size = nfp_resource_size(res); nfp_resource_release(res); if (*cpp_size < HWINFO_SIZE_MIN) return NULL; } else if (PTR_ERR(res) == -ENOENT) { /* Try getting the HWInfo table from the 'classic' location */ cpp_id = NFP_CPP_ISLAND_ID(NFP_CPP_TARGET_MU, NFP_CPP_ACTION_RW, 0, 1); cpp_addr = 0x30000; *cpp_size = 0x0e000; } else { return NULL; } db = kmalloc(*cpp_size + 1, GFP_KERNEL); if (!db) return NULL; err = nfp_cpp_read(cpp, cpp_id, cpp_addr, db, *cpp_size); if (err != *cpp_size) goto exit_free; header = (void *)db; if (nfp_hwinfo_is_updating(header)) goto exit_free; if (le32_to_cpu(header->version) != NFP_HWINFO_VERSION_2) { nfp_err(cpp, "Unknown HWInfo version: 0x%08x\n", le32_to_cpu(header->version)); goto exit_free; } /* NULL-terminate for safety */ db[*cpp_size] = '\0'; return (void *)db; exit_free: kfree(db); return NULL; }
/* * nfp_nffw_info_open() - Acquire the lock on the NFFW table * @cpp: NFP CPP handle * * Return: 0, or -ERRNO */ struct nfp_nffw_info * nfp_nffw_info_open(struct nfp_cpp *cpp) { struct nfp_nffw_info_data *fwinf; struct nfp_nffw_info *state; uint32_t info_ver; int err; state = malloc(sizeof(*state)); if (!state) return NULL; memset(state, 0, sizeof(*state)); state->res = nfp_resource_acquire(cpp, NFP_RESOURCE_NFP_NFFW); if (!state->res) goto err_free; fwinf = &state->fwinf; if (sizeof(*fwinf) > nfp_resource_size(state->res)) goto err_release; err = nfp_cpp_read(cpp, nfp_resource_cpp_id(state->res), nfp_resource_address(state->res), fwinf, sizeof(*fwinf)); if (err < (int)sizeof(*fwinf)) goto err_release; if (!nffw_res_flg_init_get(fwinf)) goto err_release; info_ver = nffw_res_info_version_get(fwinf); if (info_ver > NFFW_INFO_VERSION_CURRENT) goto err_release; state->cpp = cpp; return state; err_release: nfp_resource_release(state->res); err_free: free(state); return NULL; }
static int nfp_cpp_resource_find(struct nfp_cpp *cpp, struct nfp_resource *res) { char name_pad[NFP_RESOURCE_ENTRY_NAME_SZ] = {}; struct nfp_resource_entry entry; u32 cpp_id, key; int ret, i; cpp_id = NFP_CPP_ID(NFP_RESOURCE_TBL_TARGET, 3, 0); /* Atomic read */ strncpy(name_pad, res->name, sizeof(name_pad)); /* Search for a matching entry */ key = NFP_RESOURCE_TBL_KEY; if (memcmp(name_pad, NFP_RESOURCE_TBL_NAME "\0\0\0\0\0\0\0\0", 8)) key = crc32_posix(name_pad, sizeof(name_pad)); for (i = 0; i < NFP_RESOURCE_TBL_ENTRIES; i++) { u64 addr = NFP_RESOURCE_TBL_BASE + sizeof(struct nfp_resource_entry) * i; ret = nfp_cpp_read(cpp, cpp_id, addr, &entry, sizeof(entry)); if (ret != sizeof(entry)) return -EIO; if (entry.mutex.key != key) continue; /* Found key! */ res->mutex = nfp_cpp_mutex_alloc(cpp, NFP_RESOURCE_TBL_TARGET, addr, key); res->cpp_id = NFP_CPP_ID(entry.region.cpp_target, entry.region.cpp_action, entry.region.cpp_token); res->addr = (u64)entry.region.page_offset << 8; res->size = (u64)entry.region.page_size << 8; return 0; } return -ENOENT; }
/* 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; }
/* Read memory and check if it could be a valid MIP */ static int nfp_mip_try_read(struct nfp_cpp *cpp, u32 cpp_id, u64 addr, struct nfp_mip *mip) { int ret; ret = nfp_cpp_read(cpp, cpp_id, addr, mip, sizeof(*mip)); if (ret != sizeof(*mip)) { nfp_err(cpp, "Failed to read MIP data (%d, %zu)\n", ret, sizeof(*mip)); return -EIO; } if (mip->signature != NFP_MIP_SIGNATURE) { nfp_warn(cpp, "Incorrect MIP signature (0x%08x)\n", le32_to_cpu(mip->signature)); return -EINVAL; } if (mip->mip_version != NFP_MIP_VERSION) { nfp_warn(cpp, "Unsupported MIP version (%d)\n", le32_to_cpu(mip->mip_version)); return -EINVAL; } return 0; }
static int nfp_rtsymtab_probe(struct nfp_cpp *cpp) { const u32 dram = NFP_CPP_ID(NFP_CPP_TARGET_MU, NFP_CPP_ACTION_RW, 0) | NFP_ISL_EMEM0; u32 strtab_addr, symtab_addr, strtab_size, symtab_size; struct nfp_rtsym_entry *rtsymtab; struct nfp_rtsym_cache *cache; const struct nfp_mip *mip; int err, n, size; mip = nfp_mip_open(cpp); if (!mip) return -EIO; nfp_mip_strtab(mip, &strtab_addr, &strtab_size); nfp_mip_symtab(mip, &symtab_addr, &symtab_size); nfp_mip_close(mip); if (!symtab_size || !strtab_size || symtab_size % sizeof(*rtsymtab)) return -ENXIO; /* Align to 64 bits */ symtab_size = round_up(symtab_size, 8); strtab_size = round_up(strtab_size, 8); rtsymtab = kmalloc(symtab_size, GFP_KERNEL); if (!rtsymtab) return -ENOMEM; size = sizeof(*cache); size += symtab_size / sizeof(*rtsymtab) * sizeof(struct nfp_rtsym); size += strtab_size + 1; cache = kmalloc(size, GFP_KERNEL); if (!cache) { err = -ENOMEM; goto err_free_rtsym_raw; } cache->num = symtab_size / sizeof(*rtsymtab); cache->strtab = (void *)&cache->symtab[cache->num]; err = nfp_cpp_read(cpp, dram, symtab_addr, rtsymtab, symtab_size); if (err != symtab_size) goto err_free_cache; err = nfp_cpp_read(cpp, dram, strtab_addr, cache->strtab, strtab_size); if (err != strtab_size) goto err_free_cache; cache->strtab[strtab_size] = '\0'; for (n = 0; n < cache->num; n++) nfp_rtsym_sw_entry_init(cache, strtab_size, &cache->symtab[n], &rtsymtab[n]); kfree(rtsymtab); nfp_rtsym_cache_set(cpp, cache); return 0; err_free_cache: kfree(cache); err_free_rtsym_raw: kfree(rtsymtab); return err; }
static int nfp_cpp_resource_acquire(struct nfp_cpp *cpp, const char *name, u32 *r_cpp, u64 *r_addr, u64 *r_size, struct nfp_cpp_mutex **resource_mutex) { struct nfp_resource_entry_region region; struct nfp_resource_entry tmp; struct nfp_cpp_mutex *mutex; int target, err, i, entries; u64 base; u32 key; u32 cpp_id; for (i = 0; i < sizeof(region.name); i++) { if (*name != 0) region.name[i] = *(name++); else region.name[i] = 0; } entries = nfp_cpp_resource_table(cpp, &target, &base, NULL); if (entries < 0) return entries; cpp_id = NFP_CPP_ID(target, 3, 0); /* Atomic read */ key = NFP_RESOURCE_TABLE_KEY; mutex = nfp_cpp_mutex_alloc(cpp, target, base, key); if (!mutex) return -ENOMEM; /* Wait for the lock.. */ err = nfp_cpp_mutex_lock(mutex); if (err < 0) { nfp_cpp_mutex_free(mutex); return err; } /* Search for a matching entry */ if (memcmp(region.name, NFP_RESOURCE_TABLE_NAME "\0\0\0\0\0\0\0\0", 8) != 0) key = crc32_posix(®ion.name[0], sizeof(region.name)); for (i = 0; i < entries; i++) { u64 addr = base + sizeof(struct nfp_resource_entry) * i; err = nfp_cpp_read(cpp, cpp_id, addr, &tmp, sizeof(tmp)); if (err < 0) { /* Unlikely to work if the read failed, * but we should at least try... */ nfp_cpp_mutex_unlock(mutex); nfp_cpp_mutex_free(mutex); return err; } if (tmp.mutex.key == key) { /* Found key! */ if (resource_mutex) *resource_mutex = nfp_cpp_mutex_alloc(cpp, target, addr, key); if (r_cpp) *r_cpp = NFP_CPP_ID(tmp.region.cpp_target, tmp.region.cpp_action, tmp.region.cpp_token); if (r_addr) *r_addr = (u64)tmp.region.page_offset << 8; if (r_size) *r_size = (u64)tmp.region.page_size << 8; nfp_cpp_mutex_unlock(mutex); nfp_cpp_mutex_free(mutex); return 0; } } nfp_cpp_mutex_unlock(mutex); nfp_cpp_mutex_free(mutex); return -ENOENT; }