/** * nfp_reset_soft() - Perform a soft reset of the NFP * @nfp: NFP Device handle * * Return: 0, or -ERRNO */ int nfp_reset_soft(struct nfp_device *nfp) { struct nfp_cpp *cpp = nfp_device_cpp(nfp); struct nfp_cpp_area *area; struct nfp_resource *res; u32 model; int i, err; model = nfp_cpp_model(cpp); /* Claim the nfp.nffw resource page */ res = nfp_resource_acquire(nfp, NFP_RESOURCE_NFP_NFFW); if (IS_ERR(res)) { nfp_err(nfp, "Can't aquire %s resource\n", NFP_RESOURCE_NFP_NFFW); return -EBUSY; } if (NFP_CPP_MODEL_IS_3200(model)) err = nfp3200_reset_soft(nfp); else if (NFP_CPP_MODEL_IS_6000(model)) err = nfp6000_reset_soft(nfp); else err = -EINVAL; if (err < 0) goto exit; /* Clear all NFP NFFW page */ area = nfp_cpp_area_alloc_acquire(cpp, nfp_resource_cpp_id(res), nfp_resource_address(res), nfp_resource_size(res)); if (!area) { nfp_err(nfp, "Can't acquire area for %s resource\n", NFP_RESOURCE_NFP_NFFW); err = -ENOMEM; goto exit; } for (i = 0; i < nfp_resource_size(res); i += 8) { err = nfp_cpp_area_writeq(area, i, 0); if (err < 0) break; } nfp_cpp_area_release_free(area); if (err < 0) { nfp_err(nfp, "Can't erase area of %s resource\n", NFP_RESOURCE_NFP_NFFW); goto exit; } err = 0; exit: nfp_resource_release(res); return err; }
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; }
/* 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; }
/** * nfp_nsp_command() - Execute a command on the NFP Service Processor * @nfp: NFP Device handle * @code: NSP Command Code * * Return: 0 for success with no result * * 1..255 for NSP completion with a result code * * -EAGAIN if the NSP is not yet present * * -ENODEV if the NSP is not a supported model * * -EBUSY if the NSP is stuck * * -EINTR if interrupted while waiting for completion * * -ETIMEDOUT if the NSP took longer than 30 seconds to complete */ int nfp_nsp_command(struct nfp_device *nfp, uint16_t code, u32 option, u32 buff_cpp, u64 buff_addr) { struct nfp_cpp *cpp = nfp_device_cpp(nfp); struct nfp_nsp *nsp; u32 nsp_cpp; u64 nsp_base; u64 nsp_status; u64 nsp_command; u64 nsp_buffer; int err, ok; u64 tmp; int timeout = 30 * 10; /* 30 seconds total */ nsp = nfp_device_private(nfp, nfp_nsp_con); if (!nsp) return -EAGAIN; nsp_cpp = nfp_resource_cpp_id(nsp->res); nsp_base = nfp_resource_address(nsp->res); nsp_status = nsp_base + NSP_STATUS; nsp_command = nsp_base + NSP_COMMAND; nsp_buffer = nsp_base + NSP_BUFFER; err = nfp_cpp_readq(cpp, nsp_cpp, nsp_status, &tmp); if (err < 0) return err; if (NSP_MAGIC != NSP_STATUS_MAGIC_of(tmp)) { nfp_err(nfp, "NSP: Cannot detect NFP Service Processor\n"); return -ENODEV; } ok = NSP_STATUS_MAJOR_of(tmp) == NSP_CODE_MAJOR_of(code) && NSP_STATUS_MINOR_of(tmp) >= NSP_CODE_MINOR_of(code); if (!ok) { nfp_err(nfp, "NSP: Code 0x%04x not supported (ABI %d.%d)\n", code, (int)NSP_STATUS_MAJOR_of(tmp), (int)NSP_STATUS_MINOR_of(tmp)); return -EINVAL; } if (tmp & NSP_STATUS_BUSY) { nfp_err(nfp, "NSP: Service processor busy!\n"); return -EBUSY; } err = nfp_cpp_writeq(cpp, nsp_cpp, nsp_buffer, NSP_BUFFER_CPP(buff_cpp) | NSP_BUFFER_ADDRESS(buff_addr)); if (err < 0) return err; err = nfp_cpp_writeq(cpp, nsp_cpp, nsp_command, NSP_COMMAND_OPTION(option) | NSP_COMMAND_CODE(code) | NSP_COMMAND_START); if (err < 0) return err; /* Wait for NSP_COMMAND_START to go to 0 */ for (; timeout > 0; timeout--) { err = nfp_cpp_readq(cpp, nsp_cpp, nsp_command, &tmp); if (err < 0) return err; if (!(tmp & NSP_COMMAND_START)) break; if (msleep_interruptible(100) > 0) { nfp_warn(nfp, "NSP: Interrupt waiting for code 0x%04x to start\n", code); return -EINTR; } } if (timeout < 0) { nfp_warn(nfp, "NSP: Timeout waiting for code 0x%04x to start\n", code); return -ETIMEDOUT; } /* Wait for NSP_STATUS_BUSY to go to 0 */ for (; timeout > 0; timeout--) { err = nfp_cpp_readq(cpp, nsp_cpp, nsp_status, &tmp); if (err < 0) return err; if (!(tmp & NSP_STATUS_BUSY)) break; if (msleep_interruptible(100) > 0) { nfp_warn(nfp, "NSP: Interrupt waiting for code 0x%04x to complete\n", code); return -EINTR; } } if (timeout < 0) { nfp_warn(nfp, "NSP: Timeout waiting for code 0x%04x to complete\n", code); return -ETIMEDOUT; } err = NSP_STATUS_RESULT_of(tmp); if (err > 0) return -err; err = nfp_cpp_readq(cpp, nsp_cpp, nsp_command, &tmp); if (err < 0) return err; return NSP_COMMAND_OPTION_of(tmp); }