Skip to content

Commit d41987e

Browse files
Edward Creekuba-moo
authored andcommitted
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>
1 parent fd118a7 commit d41987e

File tree

3 files changed

+121
-23
lines changed

3 files changed

+121
-23
lines changed

drivers/net/ethernet/sfc/ef10.c

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3501,7 +3501,7 @@ static int efx_ef10_mtd_probe_partition(struct efx_nic *efx,
35013501
MCDI_DECLARE_BUF(inbuf, MC_CMD_NVRAM_METADATA_IN_LEN);
35023502
MCDI_DECLARE_BUF(outbuf, MC_CMD_NVRAM_METADATA_OUT_LENMAX);
35033503
const struct efx_ef10_nvram_type_info *info;
3504-
size_t size, erase_size, outlen;
3504+
size_t size, erase_size, write_size, outlen;
35053505
int type_idx = 0;
35063506
bool protected;
35073507
int rc;
@@ -3516,7 +3516,8 @@ static int efx_ef10_mtd_probe_partition(struct efx_nic *efx,
35163516
if (info->port != efx_port_num(efx))
35173517
return -ENODEV;
35183518

3519-
rc = efx_mcdi_nvram_info(efx, type, &size, &erase_size, &protected);
3519+
rc = efx_mcdi_nvram_info(efx, type, &size, &erase_size, &write_size,
3520+
&protected);
35203521
if (rc)
35213522
return rc;
35223523
if (protected &&
@@ -3561,6 +3562,8 @@ static int efx_ef10_mtd_probe_partition(struct efx_nic *efx,
35613562
if (!erase_size)
35623563
part->common.mtd.flags |= MTD_NO_ERASE;
35633564

3565+
part->common.mtd.writesize = write_size;
3566+
35643567
return 0;
35653568
}
35663569

drivers/net/ethernet/sfc/mcdi.c

Lines changed: 95 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1625,12 +1625,15 @@ static int efx_new_mcdi_nvram_types(struct efx_nic *efx, u32 *number,
16251625
return rc;
16261626
}
16271627

1628+
#define EFX_MCDI_NVRAM_DEFAULT_WRITE_LEN 128
1629+
16281630
int efx_mcdi_nvram_info(struct efx_nic *efx, unsigned int type,
16291631
size_t *size_out, size_t *erase_size_out,
1630-
bool *protected_out)
1632+
size_t *write_size_out, bool *protected_out)
16311633
{
16321634
MCDI_DECLARE_BUF(inbuf, MC_CMD_NVRAM_INFO_IN_LEN);
1633-
MCDI_DECLARE_BUF(outbuf, MC_CMD_NVRAM_INFO_OUT_LEN);
1635+
MCDI_DECLARE_BUF(outbuf, MC_CMD_NVRAM_INFO_V2_OUT_LEN);
1636+
size_t write_size = 0;
16341637
size_t outlen;
16351638
int rc;
16361639

@@ -1645,6 +1648,12 @@ int efx_mcdi_nvram_info(struct efx_nic *efx, unsigned int type,
16451648
goto fail;
16461649
}
16471650

1651+
if (outlen >= MC_CMD_NVRAM_INFO_V2_OUT_LEN)
1652+
write_size = MCDI_DWORD(outbuf, NVRAM_INFO_V2_OUT_WRITESIZE);
1653+
else
1654+
write_size = EFX_MCDI_NVRAM_DEFAULT_WRITE_LEN;
1655+
1656+
*write_size_out = write_size;
16481657
*size_out = MCDI_DWORD(outbuf, NVRAM_INFO_OUT_SIZE);
16491658
*erase_size_out = MCDI_DWORD(outbuf, NVRAM_INFO_OUT_ERASESIZE);
16501659
*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,
21632172
return rc;
21642173
}
21652174

2166-
#ifdef CONFIG_SFC_MTD
2167-
21682175
#define EFX_MCDI_NVRAM_LEN_MAX 128
21692176

2170-
static int efx_mcdi_nvram_update_start(struct efx_nic *efx, unsigned int type)
2177+
int efx_mcdi_nvram_update_start(struct efx_nic *efx, unsigned int type)
21712178
{
21722179
MCDI_DECLARE_BUF(inbuf, MC_CMD_NVRAM_UPDATE_START_V2_IN_LEN);
21732180
int rc;
@@ -2185,6 +2192,8 @@ static int efx_mcdi_nvram_update_start(struct efx_nic *efx, unsigned int type)
21852192
return rc;
21862193
}
21872194

2195+
#ifdef CONFIG_SFC_MTD
2196+
21882197
static int efx_mcdi_nvram_read(struct efx_nic *efx, unsigned int type,
21892198
loff_t offset, u8 *buffer, size_t length)
21902199
{
@@ -2209,28 +2218,35 @@ static int efx_mcdi_nvram_read(struct efx_nic *efx, unsigned int type,
22092218
return 0;
22102219
}
22112220

2212-
static int efx_mcdi_nvram_write(struct efx_nic *efx, unsigned int type,
2213-
loff_t offset, const u8 *buffer, size_t length)
2221+
#endif /* CONFIG_SFC_MTD */
2222+
2223+
int efx_mcdi_nvram_write(struct efx_nic *efx, unsigned int type,
2224+
loff_t offset, const u8 *buffer, size_t length)
22142225
{
2215-
MCDI_DECLARE_BUF(inbuf,
2216-
MC_CMD_NVRAM_WRITE_IN_LEN(EFX_MCDI_NVRAM_LEN_MAX));
2226+
efx_dword_t *inbuf;
2227+
size_t inlen;
22172228
int rc;
22182229

2230+
inlen = ALIGN(MC_CMD_NVRAM_WRITE_IN_LEN(length), 4);
2231+
inbuf = kzalloc(inlen, GFP_KERNEL);
2232+
if (!inbuf)
2233+
return -ENOMEM;
2234+
22192235
MCDI_SET_DWORD(inbuf, NVRAM_WRITE_IN_TYPE, type);
22202236
MCDI_SET_DWORD(inbuf, NVRAM_WRITE_IN_OFFSET, offset);
22212237
MCDI_SET_DWORD(inbuf, NVRAM_WRITE_IN_LENGTH, length);
22222238
memcpy(MCDI_PTR(inbuf, NVRAM_WRITE_IN_WRITE_BUFFER), buffer, length);
22232239

22242240
BUILD_BUG_ON(MC_CMD_NVRAM_WRITE_OUT_LEN != 0);
22252241

2226-
rc = efx_mcdi_rpc(efx, MC_CMD_NVRAM_WRITE, inbuf,
2227-
ALIGN(MC_CMD_NVRAM_WRITE_IN_LEN(length), 4),
2228-
NULL, 0, NULL);
2242+
rc = efx_mcdi_rpc(efx, MC_CMD_NVRAM_WRITE, inbuf, inlen, NULL, 0, NULL);
2243+
kfree(inbuf);
2244+
22292245
return rc;
22302246
}
22312247

2232-
static int efx_mcdi_nvram_erase(struct efx_nic *efx, unsigned int type,
2233-
loff_t offset, size_t length)
2248+
int efx_mcdi_nvram_erase(struct efx_nic *efx, unsigned int type, loff_t offset,
2249+
size_t length)
22342250
{
22352251
MCDI_DECLARE_BUF(inbuf, MC_CMD_NVRAM_ERASE_IN_LEN);
22362252
int rc;
@@ -2246,30 +2262,50 @@ static int efx_mcdi_nvram_erase(struct efx_nic *efx, unsigned int type,
22462262
return rc;
22472263
}
22482264

2249-
static int efx_mcdi_nvram_update_finish(struct efx_nic *efx, unsigned int type)
2265+
int efx_mcdi_nvram_update_finish(struct efx_nic *efx, unsigned int type,
2266+
enum efx_update_finish_mode mode)
22502267
{
22512268
MCDI_DECLARE_BUF(inbuf, MC_CMD_NVRAM_UPDATE_FINISH_V2_IN_LEN);
22522269
MCDI_DECLARE_BUF(outbuf, MC_CMD_NVRAM_UPDATE_FINISH_V2_OUT_LEN);
22532270
size_t outlen;
22542271
int rc, rc2;
22552272

22562273
MCDI_SET_DWORD(inbuf, NVRAM_UPDATE_FINISH_IN_TYPE, type);
2257-
/* Always set this flag. Old firmware ignores it */
2258-
MCDI_POPULATE_DWORD_1(inbuf, NVRAM_UPDATE_FINISH_V2_IN_FLAGS,
2274+
2275+
/* Old firmware doesn't support background update finish and abort
2276+
* operations. Fallback to waiting if the requested mode is not
2277+
* supported.
2278+
*/
2279+
if (!efx_has_cap(efx, NVRAM_UPDATE_POLL_VERIFY_RESULT) ||
2280+
(!efx_has_cap(efx, NVRAM_UPDATE_ABORT_SUPPORTED) &&
2281+
mode == EFX_UPDATE_FINISH_ABORT))
2282+
mode = EFX_UPDATE_FINISH_WAIT;
2283+
2284+
MCDI_POPULATE_DWORD_4(inbuf, NVRAM_UPDATE_FINISH_V2_IN_FLAGS,
22592285
NVRAM_UPDATE_FINISH_V2_IN_FLAG_REPORT_VERIFY_RESULT,
2260-
1);
2286+
(mode != EFX_UPDATE_FINISH_ABORT),
2287+
NVRAM_UPDATE_FINISH_V2_IN_FLAG_RUN_IN_BACKGROUND,
2288+
(mode == EFX_UPDATE_FINISH_BACKGROUND),
2289+
NVRAM_UPDATE_FINISH_V2_IN_FLAG_POLL_VERIFY_RESULT,
2290+
(mode == EFX_UPDATE_FINISH_POLL),
2291+
NVRAM_UPDATE_FINISH_V2_IN_FLAG_ABORT,
2292+
(mode == EFX_UPDATE_FINISH_ABORT));
22612293

22622294
rc = efx_mcdi_rpc(efx, MC_CMD_NVRAM_UPDATE_FINISH, inbuf, sizeof(inbuf),
22632295
outbuf, sizeof(outbuf), &outlen);
22642296
if (!rc && outlen >= MC_CMD_NVRAM_UPDATE_FINISH_V2_OUT_LEN) {
22652297
rc2 = MCDI_DWORD(outbuf, NVRAM_UPDATE_FINISH_V2_OUT_RESULT_CODE);
2266-
if (rc2 != MC_CMD_NVRAM_VERIFY_RC_SUCCESS)
2298+
if (rc2 != MC_CMD_NVRAM_VERIFY_RC_SUCCESS &&
2299+
rc2 != MC_CMD_NVRAM_VERIFY_RC_PENDING)
22672300
netif_err(efx, drv, efx->net_dev,
22682301
"NVRAM update failed verification with code 0x%x\n",
22692302
rc2);
22702303
switch (rc2) {
22712304
case MC_CMD_NVRAM_VERIFY_RC_SUCCESS:
22722305
break;
2306+
case MC_CMD_NVRAM_VERIFY_RC_PENDING:
2307+
rc = -EAGAIN;
2308+
break;
22732309
case MC_CMD_NVRAM_VERIFY_RC_CMS_CHECK_FAILED:
22742310
case MC_CMD_NVRAM_VERIFY_RC_MESSAGE_DIGEST_CHECK_FAILED:
22752311
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)
22842320
case MC_CMD_NVRAM_VERIFY_RC_NO_VALID_SIGNATURES:
22852321
case MC_CMD_NVRAM_VERIFY_RC_NO_TRUSTED_APPROVERS:
22862322
case MC_CMD_NVRAM_VERIFY_RC_NO_SIGNATURE_MATCH:
2323+
case MC_CMD_NVRAM_VERIFY_RC_REJECT_TEST_SIGNED:
2324+
case MC_CMD_NVRAM_VERIFY_RC_SECURITY_LEVEL_DOWNGRADE:
22872325
rc = -EPERM;
22882326
break;
22892327
default:
@@ -2296,6 +2334,42 @@ static int efx_mcdi_nvram_update_finish(struct efx_nic *efx, unsigned int type)
22962334
return rc;
22972335
}
22982336

2337+
#define EFX_MCDI_NVRAM_UPDATE_FINISH_INITIAL_POLL_DELAY_MS 5
2338+
#define EFX_MCDI_NVRAM_UPDATE_FINISH_MAX_POLL_DELAY_MS 5000
2339+
#define EFX_MCDI_NVRAM_UPDATE_FINISH_RETRIES 185
2340+
2341+
int efx_mcdi_nvram_update_finish_polled(struct efx_nic *efx, unsigned int type)
2342+
{
2343+
unsigned int delay = EFX_MCDI_NVRAM_UPDATE_FINISH_INITIAL_POLL_DELAY_MS;
2344+
unsigned int retry = 0;
2345+
int rc;
2346+
2347+
/* NVRAM updates can take a long time (e.g. up to 1 minute for bundle
2348+
* images). Polling for NVRAM update completion ensures that other MCDI
2349+
* commands can be issued before the background NVRAM update completes.
2350+
*
2351+
* The initial call either completes the update synchronously, or
2352+
* returns -EAGAIN to indicate processing is continuing. In the latter
2353+
* case, we poll for at least 900 seconds, at increasing intervals
2354+
* (5ms, 50ms, 500ms, 5s).
2355+
*/
2356+
rc = efx_mcdi_nvram_update_finish(efx, type, EFX_UPDATE_FINISH_BACKGROUND);
2357+
while (rc == -EAGAIN) {
2358+
if (retry > EFX_MCDI_NVRAM_UPDATE_FINISH_RETRIES)
2359+
return -ETIMEDOUT;
2360+
retry++;
2361+
2362+
msleep(delay);
2363+
if (delay < EFX_MCDI_NVRAM_UPDATE_FINISH_MAX_POLL_DELAY_MS)
2364+
delay *= 10;
2365+
2366+
rc = efx_mcdi_nvram_update_finish(efx, type, EFX_UPDATE_FINISH_POLL);
2367+
}
2368+
return rc;
2369+
}
2370+
2371+
#ifdef CONFIG_SFC_MTD
2372+
22992373
int efx_mcdi_mtd_read(struct mtd_info *mtd, loff_t start,
23002374
size_t len, size_t *retlen, u8 *buffer)
23012375
{
@@ -2389,7 +2463,8 @@ int efx_mcdi_mtd_sync(struct mtd_info *mtd)
23892463

23902464
if (part->updating) {
23912465
part->updating = false;
2392-
rc = efx_mcdi_nvram_update_finish(efx, part->nvram_type);
2466+
rc = efx_mcdi_nvram_update_finish(efx, part->nvram_type,
2467+
EFX_UPDATE_FINISH_WAIT);
23932468
}
23942469

23952470
return rc;

drivers/net/ethernet/sfc/mcdi.h

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -392,7 +392,7 @@ int efx_mcdi_log_ctrl(struct efx_nic *efx, bool evq, bool uart, u32 dest_evq);
392392
int efx_mcdi_nvram_types(struct efx_nic *efx, u32 *nvram_types_out);
393393
int efx_mcdi_nvram_info(struct efx_nic *efx, unsigned int type,
394394
size_t *size_out, size_t *erase_size_out,
395-
bool *protected_out);
395+
size_t *write_size_out, bool *protected_out);
396396
int efx_new_mcdi_nvram_test_all(struct efx_nic *efx);
397397
int efx_mcdi_nvram_metadata(struct efx_nic *efx, unsigned int type,
398398
u32 *subtype, u16 version[4], char *desc,
@@ -424,6 +424,26 @@ static inline int efx_mcdi_mon_probe(struct efx_nic *efx) { return 0; }
424424
static inline void efx_mcdi_mon_remove(struct efx_nic *efx) {}
425425
#endif
426426

427+
int efx_mcdi_nvram_update_start(struct efx_nic *efx, unsigned int type);
428+
int efx_mcdi_nvram_write(struct efx_nic *efx, unsigned int type,
429+
loff_t offset, const u8 *buffer, size_t length);
430+
int efx_mcdi_nvram_erase(struct efx_nic *efx, unsigned int type,
431+
loff_t offset, size_t length);
432+
int efx_mcdi_nvram_metadata(struct efx_nic *efx, unsigned int type,
433+
u32 *subtype, u16 version[4], char *desc,
434+
size_t descsize);
435+
436+
enum efx_update_finish_mode {
437+
EFX_UPDATE_FINISH_WAIT,
438+
EFX_UPDATE_FINISH_BACKGROUND,
439+
EFX_UPDATE_FINISH_POLL,
440+
EFX_UPDATE_FINISH_ABORT,
441+
};
442+
443+
int efx_mcdi_nvram_update_finish(struct efx_nic *efx, unsigned int type,
444+
enum efx_update_finish_mode mode);
445+
int efx_mcdi_nvram_update_finish_polled(struct efx_nic *efx, unsigned int type);
446+
427447
#ifdef CONFIG_SFC_MTD
428448
int efx_mcdi_mtd_read(struct mtd_info *mtd, loff_t start, size_t len,
429449
size_t *retlen, u8 *buffer);

0 commit comments

Comments
 (0)