diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_ethtool.c b/drivers/net/ethernet/netronome/nfp/nfp_net_ethtool.c index 2cde0eb00ee3..00b8c642e672 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net_ethtool.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_net_ethtool.c @@ -47,6 +47,7 @@ #include #include #include +#include #include "nfpcore/nfp.h" #include "nfpcore/nfp_nsp.h" @@ -1269,6 +1270,57 @@ static int nfp_net_set_channels(struct net_device *netdev, return nfp_net_set_num_rings(nn, total_rx, total_tx); } +static int +nfp_net_flash_device(struct net_device *netdev, struct ethtool_flash *flash) +{ + const struct firmware *fw; + struct nfp_app *app; + struct nfp_nsp *nsp; + struct device *dev; + int err; + + if (flash->region != ETHTOOL_FLASH_ALL_REGIONS) + return -EOPNOTSUPP; + + app = nfp_app_from_netdev(netdev); + if (!app) + return -EOPNOTSUPP; + + dev = &app->pdev->dev; + + nsp = nfp_nsp_open(app->cpp); + if (IS_ERR(nsp)) { + err = PTR_ERR(nsp); + dev_err(dev, "Failed to access the NSP: %d\n", err); + return err; + } + + err = request_firmware_direct(&fw, flash->data, dev); + if (err) + goto exit_close_nsp; + + dev_info(dev, "Please be patient while writing flash image: %s\n", + flash->data); + dev_hold(netdev); + rtnl_unlock(); + + err = nfp_nsp_write_flash(nsp, fw); + if (err < 0) { + dev_err(dev, "Flash write failed: %d\n", err); + goto exit_rtnl_lock; + } + dev_info(dev, "Finished writing flash image\n"); + +exit_rtnl_lock: + rtnl_lock(); + dev_put(netdev); + release_firmware(fw); + +exit_close_nsp: + nfp_nsp_close(nsp); + return err; +} + static const struct ethtool_ops nfp_net_ethtool_ops = { .get_drvinfo = nfp_net_get_drvinfo, .get_link = ethtool_op_get_link, @@ -1279,6 +1331,7 @@ static const struct ethtool_ops nfp_net_ethtool_ops = { .get_sset_count = nfp_net_get_sset_count, .get_rxnfc = nfp_net_get_rxnfc, .set_rxnfc = nfp_net_set_rxnfc, + .flash_device = nfp_net_flash_device, .get_rxfh_indir_size = nfp_net_get_rxfh_indir_size, .get_rxfh_key_size = nfp_net_get_rxfh_key_size, .get_rxfh = nfp_net_get_rxfh, @@ -1304,6 +1357,7 @@ const struct ethtool_ops nfp_port_ethtool_ops = { .get_strings = nfp_port_get_strings, .get_ethtool_stats = nfp_port_get_stats, .get_sset_count = nfp_port_get_sset_count, + .flash_device = nfp_net_flash_device, .set_dump = nfp_app_set_dump, .get_dump_flag = nfp_app_get_dump_flag, .get_dump_data = nfp_app_get_dump_data, diff --git a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp.c b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp.c index 14a6d1ba51a9..39abac678b71 100644 --- a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp.c +++ b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp.c @@ -51,6 +51,9 @@ #include "nfp_cpp.h" #include "nfp_nsp.h" +#define NFP_NSP_TIMEOUT_DEFAULT 30 +#define NFP_NSP_TIMEOUT_BOOT 30 + /* Offsets relative to the CSR base */ #define NSP_STATUS 0x00 #define NSP_STATUS_MAGIC GENMASK_ULL(63, 48) @@ -93,6 +96,7 @@ enum nfp_nsp_cmd { SPCODE_FW_LOAD = 6, /* Load fw from buffer, len in option */ SPCODE_ETH_RESCAN = 7, /* Rescan ETHs, write ETH_TABLE to buf */ SPCODE_ETH_CONTROL = 8, /* Update media config from buffer */ + 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 */ }; @@ -260,10 +264,10 @@ u16 nfp_nsp_get_abi_ver_minor(struct nfp_nsp *state) } static int -nfp_nsp_wait_reg(struct nfp_cpp *cpp, u64 *reg, - u32 nsp_cpp, u64 addr, u64 mask, u64 val) +nfp_nsp_wait_reg(struct nfp_cpp *cpp, u64 *reg, u32 nsp_cpp, u64 addr, + u64 mask, u64 val, u32 timeout_sec) { - const unsigned long wait_until = jiffies + 30 * HZ; + const unsigned long wait_until = jiffies + timeout_sec * HZ; int err; for (;;) { @@ -285,12 +289,13 @@ nfp_nsp_wait_reg(struct nfp_cpp *cpp, u64 *reg, } /** - * nfp_nsp_command() - Execute a command on the NFP Service Processor + * __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 * * Return: 0 for success with no result * @@ -300,10 +305,11 @@ nfp_nsp_wait_reg(struct nfp_cpp *cpp, u64 *reg, * -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 + * -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) +static int +__nfp_nsp_command(struct nfp_nsp *state, u16 code, u32 option, u32 buff_cpp, + u64 buff_addr, u32 timeout_sec) { u64 reg, ret_val, nsp_base, nsp_buffer, nsp_status, nsp_command; struct nfp_cpp *cpp = state->cpp; @@ -341,8 +347,8 @@ static int nfp_nsp_command(struct nfp_nsp *state, u16 code, u32 option, return err; /* Wait for NSP_COMMAND_START to go to 0 */ - err = nfp_nsp_wait_reg(cpp, ®, - nsp_cpp, nsp_command, NSP_COMMAND_START, 0); + err = nfp_nsp_wait_reg(cpp, ®, nsp_cpp, nsp_command, + 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); @@ -350,8 +356,8 @@ static int nfp_nsp_command(struct nfp_nsp *state, u16 code, u32 option, } /* Wait for NSP_STATUS_BUSY to go to 0 */ - err = nfp_nsp_wait_reg(cpp, ®, - nsp_cpp, nsp_status, NSP_STATUS_BUSY, 0); + err = nfp_nsp_wait_reg(cpp, ®, nsp_cpp, nsp_status, NSP_STATUS_BUSY, + 0, timeout_sec); if (err) { nfp_err(cpp, "Error %d waiting for code 0x%04x to complete\n", err, code); @@ -374,9 +380,18 @@ static int nfp_nsp_command(struct nfp_nsp *state, u16 code, u32 option, return ret_val; } -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) +static int +nfp_nsp_command(struct nfp_nsp *state, u16 code, u32 option, u32 buff_cpp, + u64 buff_addr) +{ + return __nfp_nsp_command(state, code, option, buff_cpp, buff_addr, + NFP_NSP_TIMEOUT_DEFAULT); +} + +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) { struct nfp_cpp *cpp = nsp->cpp; unsigned int max_size; @@ -429,7 +444,8 @@ static int nfp_nsp_command_buf(struct nfp_nsp *nsp, u16 code, u32 option, return err; } - ret = nfp_nsp_command(nsp, code, option, cpp_id, cpp_buf); + ret = __nfp_nsp_command(nsp, code, option, cpp_id, cpp_buf, + timeout_sec); if (ret < 0) return ret; @@ -442,12 +458,23 @@ static int 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 + 30 * HZ; + const unsigned long wait_until = jiffies + NFP_NSP_TIMEOUT_BOOT * HZ; int err; - nfp_dbg(state->cpp, "Waiting for NSP to respond (30 sec max).\n"); + nfp_dbg(state->cpp, "Waiting for NSP to respond (%u sec max).\n", + NFP_NSP_TIMEOUT_BOOT); for (;;) { const unsigned long start_time = jiffies; @@ -488,6 +515,17 @@ int nfp_nsp_load_fw(struct nfp_nsp *state, const struct firmware *fw) fw->size, NULL, 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); +} + 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, diff --git a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp.h b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp.h index 650ca1a5bd21..e983c9d7f86c 100644 --- a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp.h +++ b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp.h @@ -48,6 +48,7 @@ u16 nfp_nsp_get_abi_ver_minor(struct nfp_nsp *state); int nfp_nsp_wait(struct nfp_nsp *state); 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); static inline bool nfp_nsp_has_mac_reinit(struct nfp_nsp *state)