/** * nfp_rtsym_read_le() - Read a simple unsigned scalar value from symbol * @cpp: NFP CPP handle * @name: Symbol name * @error: Poniter to error code (optional) * * Lookup a symbol, map, read it and return it's value. Value of the symbol * will be interpreted as a simple little-endian unsigned value. Symbol can * be 4 or 8 bytes in size. * * Return: value read, on error sets the error and returns ~0ULL. */ u64 nfp_rtsym_read_le(struct nfp_cpp *cpp, const char *name, int *error) { const struct nfp_rtsym *sym; u32 val32, id; u64 val; int err; sym = nfp_rtsym_lookup(cpp, name); if (!sym) { err = -ENOENT; goto exit; } id = NFP_CPP_ISLAND_ID(sym->target, NFP_CPP_ACTION_RW, 0, sym->domain); switch (sym->size) { case 4: err = nfp_cpp_readl(cpp, id, sym->addr, &val32); val = val32; break; case 8: err = nfp_cpp_readq(cpp, id, sym->addr, &val); break; default: nfp_err(cpp, "rtsym '%s' unsupported or non-scalar size: %lld\n", name, sym->size); err = -EINVAL; break; } if (err == sym->size) err = 0; else if (err >= 0) err = -EIO; exit: if (error) *error = err; if (err) return ~0ULL; return val; }
/** * 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); }