mirror of
https://github.com/torvalds/linux.git
synced 2026-05-31 18:43:33 +02:00
sfc: extend NVRAM MCDI handlers
Support variable write-alignment, and background updates. The latter allows other MCDI to continue while the device is processing an MC_CMD_NVRAM_UPDATE_FINISH, since this can take a long time owing to e.g. cryptographic signature verification. Expose these handlers in mcdi.h, and build them even when CONFIG_SFC_MTD=n, so they can be used for devlink flash in a subsequent patch. Signed-off-by: Edward Cree <ecree.xilinx@gmail.com> Link: https://patch.msgid.link/de3d9e14fee69e15d95b46258401a93b75659f78.1739186253.git.ecree.xilinx@gmail.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
parent
fd118a77ed
commit
d41987e906
|
|
@ -3501,7 +3501,7 @@ static int efx_ef10_mtd_probe_partition(struct efx_nic *efx,
|
|||
MCDI_DECLARE_BUF(inbuf, MC_CMD_NVRAM_METADATA_IN_LEN);
|
||||
MCDI_DECLARE_BUF(outbuf, MC_CMD_NVRAM_METADATA_OUT_LENMAX);
|
||||
const struct efx_ef10_nvram_type_info *info;
|
||||
size_t size, erase_size, outlen;
|
||||
size_t size, erase_size, write_size, outlen;
|
||||
int type_idx = 0;
|
||||
bool protected;
|
||||
int rc;
|
||||
|
|
@ -3516,7 +3516,8 @@ static int efx_ef10_mtd_probe_partition(struct efx_nic *efx,
|
|||
if (info->port != efx_port_num(efx))
|
||||
return -ENODEV;
|
||||
|
||||
rc = efx_mcdi_nvram_info(efx, type, &size, &erase_size, &protected);
|
||||
rc = efx_mcdi_nvram_info(efx, type, &size, &erase_size, &write_size,
|
||||
&protected);
|
||||
if (rc)
|
||||
return rc;
|
||||
if (protected &&
|
||||
|
|
@ -3561,6 +3562,8 @@ static int efx_ef10_mtd_probe_partition(struct efx_nic *efx,
|
|||
if (!erase_size)
|
||||
part->common.mtd.flags |= MTD_NO_ERASE;
|
||||
|
||||
part->common.mtd.writesize = write_size;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1625,12 +1625,15 @@ static int efx_new_mcdi_nvram_types(struct efx_nic *efx, u32 *number,
|
|||
return rc;
|
||||
}
|
||||
|
||||
#define EFX_MCDI_NVRAM_DEFAULT_WRITE_LEN 128
|
||||
|
||||
int efx_mcdi_nvram_info(struct efx_nic *efx, unsigned int type,
|
||||
size_t *size_out, size_t *erase_size_out,
|
||||
bool *protected_out)
|
||||
size_t *write_size_out, bool *protected_out)
|
||||
{
|
||||
MCDI_DECLARE_BUF(inbuf, MC_CMD_NVRAM_INFO_IN_LEN);
|
||||
MCDI_DECLARE_BUF(outbuf, MC_CMD_NVRAM_INFO_OUT_LEN);
|
||||
MCDI_DECLARE_BUF(outbuf, MC_CMD_NVRAM_INFO_V2_OUT_LEN);
|
||||
size_t write_size = 0;
|
||||
size_t outlen;
|
||||
int rc;
|
||||
|
||||
|
|
@ -1645,6 +1648,12 @@ int efx_mcdi_nvram_info(struct efx_nic *efx, unsigned int type,
|
|||
goto fail;
|
||||
}
|
||||
|
||||
if (outlen >= MC_CMD_NVRAM_INFO_V2_OUT_LEN)
|
||||
write_size = MCDI_DWORD(outbuf, NVRAM_INFO_V2_OUT_WRITESIZE);
|
||||
else
|
||||
write_size = EFX_MCDI_NVRAM_DEFAULT_WRITE_LEN;
|
||||
|
||||
*write_size_out = write_size;
|
||||
*size_out = MCDI_DWORD(outbuf, NVRAM_INFO_OUT_SIZE);
|
||||
*erase_size_out = MCDI_DWORD(outbuf, NVRAM_INFO_OUT_ERASESIZE);
|
||||
*protected_out = !!(MCDI_DWORD(outbuf, NVRAM_INFO_OUT_FLAGS) &
|
||||
|
|
@ -2163,11 +2172,9 @@ int efx_mcdi_nvram_metadata(struct efx_nic *efx, unsigned int type,
|
|||
return rc;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SFC_MTD
|
||||
|
||||
#define EFX_MCDI_NVRAM_LEN_MAX 128
|
||||
|
||||
static int efx_mcdi_nvram_update_start(struct efx_nic *efx, unsigned int type)
|
||||
int efx_mcdi_nvram_update_start(struct efx_nic *efx, unsigned int type)
|
||||
{
|
||||
MCDI_DECLARE_BUF(inbuf, MC_CMD_NVRAM_UPDATE_START_V2_IN_LEN);
|
||||
int rc;
|
||||
|
|
@ -2185,6 +2192,8 @@ static int efx_mcdi_nvram_update_start(struct efx_nic *efx, unsigned int type)
|
|||
return rc;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SFC_MTD
|
||||
|
||||
static int efx_mcdi_nvram_read(struct efx_nic *efx, unsigned int type,
|
||||
loff_t offset, u8 *buffer, size_t length)
|
||||
{
|
||||
|
|
@ -2209,13 +2218,20 @@ static int efx_mcdi_nvram_read(struct efx_nic *efx, unsigned int type,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int efx_mcdi_nvram_write(struct efx_nic *efx, unsigned int type,
|
||||
loff_t offset, const u8 *buffer, size_t length)
|
||||
#endif /* CONFIG_SFC_MTD */
|
||||
|
||||
int efx_mcdi_nvram_write(struct efx_nic *efx, unsigned int type,
|
||||
loff_t offset, const u8 *buffer, size_t length)
|
||||
{
|
||||
MCDI_DECLARE_BUF(inbuf,
|
||||
MC_CMD_NVRAM_WRITE_IN_LEN(EFX_MCDI_NVRAM_LEN_MAX));
|
||||
efx_dword_t *inbuf;
|
||||
size_t inlen;
|
||||
int rc;
|
||||
|
||||
inlen = ALIGN(MC_CMD_NVRAM_WRITE_IN_LEN(length), 4);
|
||||
inbuf = kzalloc(inlen, GFP_KERNEL);
|
||||
if (!inbuf)
|
||||
return -ENOMEM;
|
||||
|
||||
MCDI_SET_DWORD(inbuf, NVRAM_WRITE_IN_TYPE, type);
|
||||
MCDI_SET_DWORD(inbuf, NVRAM_WRITE_IN_OFFSET, offset);
|
||||
MCDI_SET_DWORD(inbuf, NVRAM_WRITE_IN_LENGTH, length);
|
||||
|
|
@ -2223,14 +2239,14 @@ static int efx_mcdi_nvram_write(struct efx_nic *efx, unsigned int type,
|
|||
|
||||
BUILD_BUG_ON(MC_CMD_NVRAM_WRITE_OUT_LEN != 0);
|
||||
|
||||
rc = efx_mcdi_rpc(efx, MC_CMD_NVRAM_WRITE, inbuf,
|
||||
ALIGN(MC_CMD_NVRAM_WRITE_IN_LEN(length), 4),
|
||||
NULL, 0, NULL);
|
||||
rc = efx_mcdi_rpc(efx, MC_CMD_NVRAM_WRITE, inbuf, inlen, NULL, 0, NULL);
|
||||
kfree(inbuf);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int efx_mcdi_nvram_erase(struct efx_nic *efx, unsigned int type,
|
||||
loff_t offset, size_t length)
|
||||
int efx_mcdi_nvram_erase(struct efx_nic *efx, unsigned int type, loff_t offset,
|
||||
size_t length)
|
||||
{
|
||||
MCDI_DECLARE_BUF(inbuf, MC_CMD_NVRAM_ERASE_IN_LEN);
|
||||
int rc;
|
||||
|
|
@ -2246,7 +2262,8 @@ static int efx_mcdi_nvram_erase(struct efx_nic *efx, unsigned int type,
|
|||
return rc;
|
||||
}
|
||||
|
||||
static int efx_mcdi_nvram_update_finish(struct efx_nic *efx, unsigned int type)
|
||||
int efx_mcdi_nvram_update_finish(struct efx_nic *efx, unsigned int type,
|
||||
enum efx_update_finish_mode mode)
|
||||
{
|
||||
MCDI_DECLARE_BUF(inbuf, MC_CMD_NVRAM_UPDATE_FINISH_V2_IN_LEN);
|
||||
MCDI_DECLARE_BUF(outbuf, MC_CMD_NVRAM_UPDATE_FINISH_V2_OUT_LEN);
|
||||
|
|
@ -2254,22 +2271,41 @@ static int efx_mcdi_nvram_update_finish(struct efx_nic *efx, unsigned int type)
|
|||
int rc, rc2;
|
||||
|
||||
MCDI_SET_DWORD(inbuf, NVRAM_UPDATE_FINISH_IN_TYPE, type);
|
||||
/* Always set this flag. Old firmware ignores it */
|
||||
MCDI_POPULATE_DWORD_1(inbuf, NVRAM_UPDATE_FINISH_V2_IN_FLAGS,
|
||||
|
||||
/* Old firmware doesn't support background update finish and abort
|
||||
* operations. Fallback to waiting if the requested mode is not
|
||||
* supported.
|
||||
*/
|
||||
if (!efx_has_cap(efx, NVRAM_UPDATE_POLL_VERIFY_RESULT) ||
|
||||
(!efx_has_cap(efx, NVRAM_UPDATE_ABORT_SUPPORTED) &&
|
||||
mode == EFX_UPDATE_FINISH_ABORT))
|
||||
mode = EFX_UPDATE_FINISH_WAIT;
|
||||
|
||||
MCDI_POPULATE_DWORD_4(inbuf, NVRAM_UPDATE_FINISH_V2_IN_FLAGS,
|
||||
NVRAM_UPDATE_FINISH_V2_IN_FLAG_REPORT_VERIFY_RESULT,
|
||||
1);
|
||||
(mode != EFX_UPDATE_FINISH_ABORT),
|
||||
NVRAM_UPDATE_FINISH_V2_IN_FLAG_RUN_IN_BACKGROUND,
|
||||
(mode == EFX_UPDATE_FINISH_BACKGROUND),
|
||||
NVRAM_UPDATE_FINISH_V2_IN_FLAG_POLL_VERIFY_RESULT,
|
||||
(mode == EFX_UPDATE_FINISH_POLL),
|
||||
NVRAM_UPDATE_FINISH_V2_IN_FLAG_ABORT,
|
||||
(mode == EFX_UPDATE_FINISH_ABORT));
|
||||
|
||||
rc = efx_mcdi_rpc(efx, MC_CMD_NVRAM_UPDATE_FINISH, inbuf, sizeof(inbuf),
|
||||
outbuf, sizeof(outbuf), &outlen);
|
||||
if (!rc && outlen >= MC_CMD_NVRAM_UPDATE_FINISH_V2_OUT_LEN) {
|
||||
rc2 = MCDI_DWORD(outbuf, NVRAM_UPDATE_FINISH_V2_OUT_RESULT_CODE);
|
||||
if (rc2 != MC_CMD_NVRAM_VERIFY_RC_SUCCESS)
|
||||
if (rc2 != MC_CMD_NVRAM_VERIFY_RC_SUCCESS &&
|
||||
rc2 != MC_CMD_NVRAM_VERIFY_RC_PENDING)
|
||||
netif_err(efx, drv, efx->net_dev,
|
||||
"NVRAM update failed verification with code 0x%x\n",
|
||||
rc2);
|
||||
switch (rc2) {
|
||||
case MC_CMD_NVRAM_VERIFY_RC_SUCCESS:
|
||||
break;
|
||||
case MC_CMD_NVRAM_VERIFY_RC_PENDING:
|
||||
rc = -EAGAIN;
|
||||
break;
|
||||
case MC_CMD_NVRAM_VERIFY_RC_CMS_CHECK_FAILED:
|
||||
case MC_CMD_NVRAM_VERIFY_RC_MESSAGE_DIGEST_CHECK_FAILED:
|
||||
case MC_CMD_NVRAM_VERIFY_RC_SIGNATURE_CHECK_FAILED:
|
||||
|
|
@ -2284,6 +2320,8 @@ static int efx_mcdi_nvram_update_finish(struct efx_nic *efx, unsigned int type)
|
|||
case MC_CMD_NVRAM_VERIFY_RC_NO_VALID_SIGNATURES:
|
||||
case MC_CMD_NVRAM_VERIFY_RC_NO_TRUSTED_APPROVERS:
|
||||
case MC_CMD_NVRAM_VERIFY_RC_NO_SIGNATURE_MATCH:
|
||||
case MC_CMD_NVRAM_VERIFY_RC_REJECT_TEST_SIGNED:
|
||||
case MC_CMD_NVRAM_VERIFY_RC_SECURITY_LEVEL_DOWNGRADE:
|
||||
rc = -EPERM;
|
||||
break;
|
||||
default:
|
||||
|
|
@ -2296,6 +2334,42 @@ static int efx_mcdi_nvram_update_finish(struct efx_nic *efx, unsigned int type)
|
|||
return rc;
|
||||
}
|
||||
|
||||
#define EFX_MCDI_NVRAM_UPDATE_FINISH_INITIAL_POLL_DELAY_MS 5
|
||||
#define EFX_MCDI_NVRAM_UPDATE_FINISH_MAX_POLL_DELAY_MS 5000
|
||||
#define EFX_MCDI_NVRAM_UPDATE_FINISH_RETRIES 185
|
||||
|
||||
int efx_mcdi_nvram_update_finish_polled(struct efx_nic *efx, unsigned int type)
|
||||
{
|
||||
unsigned int delay = EFX_MCDI_NVRAM_UPDATE_FINISH_INITIAL_POLL_DELAY_MS;
|
||||
unsigned int retry = 0;
|
||||
int rc;
|
||||
|
||||
/* NVRAM updates can take a long time (e.g. up to 1 minute for bundle
|
||||
* images). Polling for NVRAM update completion ensures that other MCDI
|
||||
* commands can be issued before the background NVRAM update completes.
|
||||
*
|
||||
* The initial call either completes the update synchronously, or
|
||||
* returns -EAGAIN to indicate processing is continuing. In the latter
|
||||
* case, we poll for at least 900 seconds, at increasing intervals
|
||||
* (5ms, 50ms, 500ms, 5s).
|
||||
*/
|
||||
rc = efx_mcdi_nvram_update_finish(efx, type, EFX_UPDATE_FINISH_BACKGROUND);
|
||||
while (rc == -EAGAIN) {
|
||||
if (retry > EFX_MCDI_NVRAM_UPDATE_FINISH_RETRIES)
|
||||
return -ETIMEDOUT;
|
||||
retry++;
|
||||
|
||||
msleep(delay);
|
||||
if (delay < EFX_MCDI_NVRAM_UPDATE_FINISH_MAX_POLL_DELAY_MS)
|
||||
delay *= 10;
|
||||
|
||||
rc = efx_mcdi_nvram_update_finish(efx, type, EFX_UPDATE_FINISH_POLL);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SFC_MTD
|
||||
|
||||
int efx_mcdi_mtd_read(struct mtd_info *mtd, loff_t start,
|
||||
size_t len, size_t *retlen, u8 *buffer)
|
||||
{
|
||||
|
|
@ -2389,7 +2463,8 @@ int efx_mcdi_mtd_sync(struct mtd_info *mtd)
|
|||
|
||||
if (part->updating) {
|
||||
part->updating = false;
|
||||
rc = efx_mcdi_nvram_update_finish(efx, part->nvram_type);
|
||||
rc = efx_mcdi_nvram_update_finish(efx, part->nvram_type,
|
||||
EFX_UPDATE_FINISH_WAIT);
|
||||
}
|
||||
|
||||
return rc;
|
||||
|
|
|
|||
|
|
@ -392,7 +392,7 @@ int efx_mcdi_log_ctrl(struct efx_nic *efx, bool evq, bool uart, u32 dest_evq);
|
|||
int efx_mcdi_nvram_types(struct efx_nic *efx, u32 *nvram_types_out);
|
||||
int efx_mcdi_nvram_info(struct efx_nic *efx, unsigned int type,
|
||||
size_t *size_out, size_t *erase_size_out,
|
||||
bool *protected_out);
|
||||
size_t *write_size_out, bool *protected_out);
|
||||
int efx_new_mcdi_nvram_test_all(struct efx_nic *efx);
|
||||
int efx_mcdi_nvram_metadata(struct efx_nic *efx, unsigned int type,
|
||||
u32 *subtype, u16 version[4], char *desc,
|
||||
|
|
@ -424,6 +424,26 @@ static inline int efx_mcdi_mon_probe(struct efx_nic *efx) { return 0; }
|
|||
static inline void efx_mcdi_mon_remove(struct efx_nic *efx) {}
|
||||
#endif
|
||||
|
||||
int efx_mcdi_nvram_update_start(struct efx_nic *efx, unsigned int type);
|
||||
int efx_mcdi_nvram_write(struct efx_nic *efx, unsigned int type,
|
||||
loff_t offset, const u8 *buffer, size_t length);
|
||||
int efx_mcdi_nvram_erase(struct efx_nic *efx, unsigned int type,
|
||||
loff_t offset, size_t length);
|
||||
int efx_mcdi_nvram_metadata(struct efx_nic *efx, unsigned int type,
|
||||
u32 *subtype, u16 version[4], char *desc,
|
||||
size_t descsize);
|
||||
|
||||
enum efx_update_finish_mode {
|
||||
EFX_UPDATE_FINISH_WAIT,
|
||||
EFX_UPDATE_FINISH_BACKGROUND,
|
||||
EFX_UPDATE_FINISH_POLL,
|
||||
EFX_UPDATE_FINISH_ABORT,
|
||||
};
|
||||
|
||||
int efx_mcdi_nvram_update_finish(struct efx_nic *efx, unsigned int type,
|
||||
enum efx_update_finish_mode mode);
|
||||
int efx_mcdi_nvram_update_finish_polled(struct efx_nic *efx, unsigned int type);
|
||||
|
||||
#ifdef CONFIG_SFC_MTD
|
||||
int efx_mcdi_mtd_read(struct mtd_info *mtd, loff_t start, size_t len,
|
||||
size_t *retlen, u8 *buffer);
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user