Skip to content

Commit 3ed6398

Browse files
Edward Creekuba-moo
authored andcommitted
sfc: deploy devlink flash images to NIC over MCDI
Use MC_CMD_NVRAM_* wrappers to write the firmware to the partition identified from the image header. Signed-off-by: Edward Cree <ecree.xilinx@gmail.com> Link: https://patch.msgid.link/a746335876b621b3e54cf4e49948148e349a1745.1739186253.git.ecree.xilinx@gmail.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
1 parent d41987e commit 3ed6398

File tree

3 files changed

+231
-3
lines changed

3 files changed

+231
-3
lines changed

drivers/net/ethernet/sfc/efx_common.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1003,6 +1003,7 @@ int efx_init_struct(struct efx_nic *efx, struct pci_dev *pci_dev)
10031003
INIT_LIST_HEAD(&efx->vf_reps);
10041004
INIT_WORK(&efx->mac_work, efx_mac_work);
10051005
init_waitqueue_head(&efx->flush_wq);
1006+
mutex_init(&efx->reflash_mutex);
10061007

10071008
efx->tx_queues_per_channel = 1;
10081009
efx->rxq_entries = EFX_DEFAULT_DMAQ_SIZE;

drivers/net/ethernet/sfc/efx_reflash.c

Lines changed: 228 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -255,13 +255,151 @@ static int efx_reflash_parse_firmware_data(const struct firmware *fw,
255255
return -EINVAL;
256256
}
257257

258+
/* Limit the number of status updates during the erase or write phases */
259+
#define EFX_DEVLINK_STATUS_UPDATE_COUNT 50
260+
261+
/* Expected timeout for the efx_mcdi_nvram_update_finish_polled() */
262+
#define EFX_DEVLINK_UPDATE_FINISH_TIMEOUT 900
263+
264+
/* Ideal erase chunk size. This is a balance between minimising the number of
265+
* MCDI requests to erase an entire partition whilst avoiding tripping the MCDI
266+
* RPC timeout.
267+
*/
268+
#define EFX_NVRAM_ERASE_IDEAL_CHUNK_SIZE (64 * 1024)
269+
270+
static int efx_reflash_erase_partition(struct efx_nic *efx,
271+
struct netlink_ext_ack *extack,
272+
struct devlink *devlink, u32 type,
273+
size_t partition_size,
274+
size_t align)
275+
{
276+
size_t chunk, offset, next_update;
277+
int rc;
278+
279+
/* Partitions that cannot be erased or do not require erase before
280+
* write are advertised with a erase alignment/sector size of zero.
281+
*/
282+
if (align == 0)
283+
/* Nothing to do */
284+
return 0;
285+
286+
if (partition_size % align)
287+
return -EINVAL;
288+
289+
/* Erase the entire NVRAM partition a chunk at a time to avoid
290+
* potentially tripping the MCDI RPC timeout.
291+
*/
292+
if (align >= EFX_NVRAM_ERASE_IDEAL_CHUNK_SIZE)
293+
chunk = align;
294+
else
295+
chunk = rounddown(EFX_NVRAM_ERASE_IDEAL_CHUNK_SIZE, align);
296+
297+
for (offset = 0, next_update = 0; offset < partition_size; offset += chunk) {
298+
if (offset >= next_update) {
299+
devlink_flash_update_status_notify(devlink, "Erasing",
300+
NULL, offset,
301+
partition_size);
302+
next_update += partition_size / EFX_DEVLINK_STATUS_UPDATE_COUNT;
303+
}
304+
305+
chunk = min_t(size_t, partition_size - offset, chunk);
306+
rc = efx_mcdi_nvram_erase(efx, type, offset, chunk);
307+
if (rc) {
308+
NL_SET_ERR_MSG_FMT_MOD(extack,
309+
"Erase failed for NVRAM partition %#x at %#zx-%#zx",
310+
type, offset, offset + chunk - 1);
311+
return rc;
312+
}
313+
}
314+
315+
devlink_flash_update_status_notify(devlink, "Erasing", NULL,
316+
partition_size, partition_size);
317+
318+
return 0;
319+
}
320+
321+
static int efx_reflash_write_partition(struct efx_nic *efx,
322+
struct netlink_ext_ack *extack,
323+
struct devlink *devlink, u32 type,
324+
const u8 *data, size_t data_size,
325+
size_t align)
326+
{
327+
size_t write_max, chunk, offset, next_update;
328+
int rc;
329+
330+
if (align == 0)
331+
return -EINVAL;
332+
333+
/* Write the NVRAM partition in chunks that are the largest multiple
334+
* of the partition's required write alignment that will fit into the
335+
* MCDI NVRAM_WRITE RPC payload.
336+
*/
337+
if (efx->type->mcdi_max_ver < 2)
338+
write_max = MC_CMD_NVRAM_WRITE_IN_WRITE_BUFFER_LEN *
339+
MC_CMD_NVRAM_WRITE_IN_WRITE_BUFFER_MAXNUM;
340+
else
341+
write_max = MC_CMD_NVRAM_WRITE_IN_WRITE_BUFFER_LEN *
342+
MC_CMD_NVRAM_WRITE_IN_WRITE_BUFFER_MAXNUM_MCDI2;
343+
chunk = rounddown(write_max, align);
344+
345+
for (offset = 0, next_update = 0; offset + chunk <= data_size; offset += chunk) {
346+
if (offset >= next_update) {
347+
devlink_flash_update_status_notify(devlink, "Writing",
348+
NULL, offset,
349+
data_size);
350+
next_update += data_size / EFX_DEVLINK_STATUS_UPDATE_COUNT;
351+
}
352+
353+
rc = efx_mcdi_nvram_write(efx, type, offset, data + offset, chunk);
354+
if (rc) {
355+
NL_SET_ERR_MSG_FMT_MOD(extack,
356+
"Write failed for NVRAM partition %#x at %#zx-%#zx",
357+
type, offset, offset + chunk - 1);
358+
return rc;
359+
}
360+
}
361+
362+
/* Round up left over data to satisfy write alignment */
363+
if (offset < data_size) {
364+
size_t remaining = data_size - offset;
365+
u8 *buf;
366+
367+
if (offset >= next_update)
368+
devlink_flash_update_status_notify(devlink, "Writing",
369+
NULL, offset,
370+
data_size);
371+
372+
chunk = roundup(remaining, align);
373+
buf = kmalloc(chunk, GFP_KERNEL);
374+
if (!buf)
375+
return -ENOMEM;
376+
377+
memcpy(buf, data + offset, remaining);
378+
memset(buf + remaining, 0xFF, chunk - remaining);
379+
rc = efx_mcdi_nvram_write(efx, type, offset, buf, chunk);
380+
kfree(buf);
381+
if (rc) {
382+
NL_SET_ERR_MSG_FMT_MOD(extack,
383+
"Write failed for NVRAM partition %#x at %#zx-%#zx",
384+
type, offset, offset + chunk - 1);
385+
return rc;
386+
}
387+
}
388+
389+
devlink_flash_update_status_notify(devlink, "Writing", NULL, data_size,
390+
data_size);
391+
392+
return 0;
393+
}
394+
258395
int efx_reflash_flash_firmware(struct efx_nic *efx, const struct firmware *fw,
259396
struct netlink_ext_ack *extack)
260397
{
398+
size_t data_size, size, erase_align, write_align;
261399
struct devlink *devlink = efx->devlink;
262-
u32 type, data_subtype;
263-
size_t data_size;
400+
u32 type, data_subtype, subtype;
264401
const u8 *data;
402+
bool protected;
265403
int rc;
266404

267405
if (!efx_has_cap(efx, BUNDLE_UPDATE)) {
@@ -279,8 +417,95 @@ int efx_reflash_flash_firmware(struct efx_nic *efx, const struct firmware *fw,
279417
goto out;
280418
}
281419

282-
rc = -EOPNOTSUPP;
420+
mutex_lock(&efx->reflash_mutex);
421+
422+
rc = efx_mcdi_nvram_metadata(efx, type, &subtype, NULL, NULL, 0);
423+
if (rc) {
424+
NL_SET_ERR_MSG_FMT_MOD(extack,
425+
"Metadata query for NVRAM partition %#x failed",
426+
type);
427+
goto out_unlock;
428+
}
429+
430+
if (subtype != data_subtype) {
431+
NL_SET_ERR_MSG_MOD(extack,
432+
"Firmware image is not appropriate for this adapter");
433+
rc = -EINVAL;
434+
goto out_unlock;
435+
}
436+
437+
rc = efx_mcdi_nvram_info(efx, type, &size, &erase_align, &write_align,
438+
&protected);
439+
if (rc) {
440+
NL_SET_ERR_MSG_FMT_MOD(extack,
441+
"Info query for NVRAM partition %#x failed",
442+
type);
443+
goto out_unlock;
444+
}
445+
446+
if (protected) {
447+
NL_SET_ERR_MSG_FMT_MOD(extack,
448+
"NVRAM partition %#x is protected",
449+
type);
450+
rc = -EPERM;
451+
goto out_unlock;
452+
}
453+
454+
if (write_align == 0) {
455+
NL_SET_ERR_MSG_FMT_MOD(extack,
456+
"NVRAM partition %#x is not writable",
457+
type);
458+
rc = -EACCES;
459+
goto out_unlock;
460+
}
461+
462+
if (erase_align != 0 && size % erase_align) {
463+
NL_SET_ERR_MSG_FMT_MOD(extack,
464+
"NVRAM partition %#x has a bad partition table entry, can't erase it",
465+
type);
466+
rc = -EACCES;
467+
goto out_unlock;
468+
}
469+
470+
if (data_size > size) {
471+
NL_SET_ERR_MSG_FMT_MOD(extack,
472+
"Firmware image is too big for NVRAM partition %#x",
473+
type);
474+
rc = -EFBIG;
475+
goto out_unlock;
476+
}
477+
478+
devlink_flash_update_status_notify(devlink, "Starting update", NULL, 0, 0);
479+
480+
rc = efx_mcdi_nvram_update_start(efx, type);
481+
if (rc) {
482+
NL_SET_ERR_MSG_FMT_MOD(extack,
483+
"Update start request for NVRAM partition %#x failed",
484+
type);
485+
goto out_unlock;
486+
}
283487

488+
rc = efx_reflash_erase_partition(efx, extack, devlink, type, size,
489+
erase_align);
490+
if (rc)
491+
goto out_update_finish;
492+
493+
rc = efx_reflash_write_partition(efx, extack, devlink, type, data,
494+
data_size, write_align);
495+
if (rc)
496+
goto out_update_finish;
497+
498+
devlink_flash_update_timeout_notify(devlink, "Finishing update", NULL,
499+
EFX_DEVLINK_UPDATE_FINISH_TIMEOUT);
500+
501+
out_update_finish:
502+
if (rc)
503+
/* Don't obscure the return code from an earlier failure */
504+
efx_mcdi_nvram_update_finish(efx, type, EFX_UPDATE_FINISH_ABORT);
505+
else
506+
rc = efx_mcdi_nvram_update_finish_polled(efx, type);
507+
out_unlock:
508+
mutex_unlock(&efx->reflash_mutex);
284509
out:
285510
devlink_flash_update_status_notify(devlink, rc ? "Update failed" :
286511
"Update complete",

drivers/net/ethernet/sfc/net_driver.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1006,6 +1006,7 @@ struct efx_mae;
10061006
* @dl_port: devlink port associated with the PF
10071007
* @mem_bar: The BAR that is mapped into membase.
10081008
* @reg_base: Offset from the start of the bar to the function control window.
1009+
* @reflash_mutex: Mutex for serialising firmware reflash operations.
10091010
* @monitor_work: Hardware monitor workitem
10101011
* @biu_lock: BIU (bus interface unit) lock
10111012
* @last_irq_cpu: Last CPU to handle a possible test interrupt. This
@@ -1191,6 +1192,7 @@ struct efx_nic {
11911192
struct devlink_port *dl_port;
11921193
unsigned int mem_bar;
11931194
u32 reg_base;
1195+
struct mutex reflash_mutex;
11941196

11951197
/* The following fields may be written more often */
11961198

0 commit comments

Comments
 (0)