Skip to content

Commit 3c41533

Browse files
Edwin Peerdavem330
authored andcommitted
bnxt_en: implement firmware live patching
Live patches are activated by using the 'limit no_reset' option when performing a devlink dev reload fw_activate operation. These packages must first be installed on the device in the usual way. For example, via devlink dev flash or ethtool -f. The devlink device info has also been enhanced to render stored and running live patch versions. Signed-off-by: Edwin Peer <[email protected]> Signed-off-by: Michael Chan <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 21e7077 commit 3c41533

File tree

3 files changed

+174
-2
lines changed

3 files changed

+174
-2
lines changed

drivers/net/ethernet/broadcom/bnxt/bnxt.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7490,6 +7490,8 @@ static int __bnxt_hwrm_func_qcaps(struct bnxt *bp)
74907490
bp->fw_cap |= BNXT_FW_CAP_PTP_PPS;
74917491
if (BNXT_PF(bp) && (flags_ext & FUNC_QCAPS_RESP_FLAGS_EXT_HOT_RESET_IF_SUPPORT))
74927492
bp->fw_cap |= BNXT_FW_CAP_HOT_RESET_IF;
7493+
if (BNXT_PF(bp) && (flags_ext & FUNC_QCAPS_RESP_FLAGS_EXT_FW_LIVEPATCH_SUPPORTED))
7494+
bp->fw_cap |= BNXT_FW_CAP_LIVEPATCH;
74937495

74947496
bp->tx_push_thresh = 0;
74957497
if ((flags & FUNC_QCAPS_RESP_FLAGS_PUSH_MODE_SUPPORTED) &&

drivers/net/ethernet/broadcom/bnxt/bnxt.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1958,6 +1958,7 @@ struct bnxt {
19581958
#define BNXT_FW_CAP_VLAN_RX_STRIP 0x01000000
19591959
#define BNXT_FW_CAP_VLAN_TX_INSERT 0x02000000
19601960
#define BNXT_FW_CAP_EXT_HW_STATS_SUPPORTED 0x04000000
1961+
#define BNXT_FW_CAP_LIVEPATCH 0x08000000
19611962
#define BNXT_FW_CAP_PTP_PPS 0x10000000
19621963
#define BNXT_FW_CAP_HOT_RESET_IF 0x20000000
19631964
#define BNXT_FW_CAP_RING_MONITOR 0x40000000

drivers/net/ethernet/broadcom/bnxt/bnxt_devlink.c

Lines changed: 171 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -326,6 +326,111 @@ void bnxt_dl_health_fw_recovery_done(struct bnxt *bp)
326326
static int bnxt_dl_info_get(struct devlink *dl, struct devlink_info_req *req,
327327
struct netlink_ext_ack *extack);
328328

329+
static void
330+
bnxt_dl_livepatch_report_err(struct bnxt *bp, struct netlink_ext_ack *extack,
331+
struct hwrm_fw_livepatch_output *resp)
332+
{
333+
int err = ((struct hwrm_err_output *)resp)->cmd_err;
334+
335+
switch (err) {
336+
case FW_LIVEPATCH_CMD_ERR_CODE_INVALID_OPCODE:
337+
netdev_err(bp->dev, "Illegal live patch opcode");
338+
NL_SET_ERR_MSG_MOD(extack, "Invalid opcode");
339+
break;
340+
case FW_LIVEPATCH_CMD_ERR_CODE_NOT_SUPPORTED:
341+
NL_SET_ERR_MSG_MOD(extack, "Live patch operation not supported");
342+
break;
343+
case FW_LIVEPATCH_CMD_ERR_CODE_NOT_INSTALLED:
344+
NL_SET_ERR_MSG_MOD(extack, "Live patch not found");
345+
break;
346+
case FW_LIVEPATCH_CMD_ERR_CODE_NOT_PATCHED:
347+
NL_SET_ERR_MSG_MOD(extack,
348+
"Live patch deactivation failed. Firmware not patched.");
349+
break;
350+
case FW_LIVEPATCH_CMD_ERR_CODE_AUTH_FAIL:
351+
NL_SET_ERR_MSG_MOD(extack, "Live patch not authenticated");
352+
break;
353+
case FW_LIVEPATCH_CMD_ERR_CODE_INVALID_HEADER:
354+
NL_SET_ERR_MSG_MOD(extack, "Incompatible live patch");
355+
break;
356+
case FW_LIVEPATCH_CMD_ERR_CODE_INVALID_SIZE:
357+
NL_SET_ERR_MSG_MOD(extack, "Live patch has invalid size");
358+
break;
359+
case FW_LIVEPATCH_CMD_ERR_CODE_ALREADY_PATCHED:
360+
NL_SET_ERR_MSG_MOD(extack, "Live patch already applied");
361+
break;
362+
default:
363+
netdev_err(bp->dev, "Unexpected live patch error: %hhd\n", err);
364+
NL_SET_ERR_MSG_MOD(extack, "Failed to activate live patch");
365+
break;
366+
}
367+
}
368+
369+
static int
370+
bnxt_dl_livepatch_activate(struct bnxt *bp, struct netlink_ext_ack *extack)
371+
{
372+
struct hwrm_fw_livepatch_query_output *query_resp;
373+
struct hwrm_fw_livepatch_query_input *query_req;
374+
struct hwrm_fw_livepatch_output *patch_resp;
375+
struct hwrm_fw_livepatch_input *patch_req;
376+
u32 installed = 0;
377+
u16 flags;
378+
u8 target;
379+
int rc;
380+
381+
if (~bp->fw_cap & BNXT_FW_CAP_LIVEPATCH) {
382+
NL_SET_ERR_MSG_MOD(extack, "Device does not support live patch");
383+
return -EOPNOTSUPP;
384+
}
385+
386+
rc = hwrm_req_init(bp, query_req, HWRM_FW_LIVEPATCH_QUERY);
387+
if (rc)
388+
return rc;
389+
query_resp = hwrm_req_hold(bp, query_req);
390+
391+
rc = hwrm_req_init(bp, patch_req, HWRM_FW_LIVEPATCH);
392+
if (rc) {
393+
hwrm_req_drop(bp, query_req);
394+
return rc;
395+
}
396+
patch_req->opcode = FW_LIVEPATCH_REQ_OPCODE_ACTIVATE;
397+
patch_req->loadtype = FW_LIVEPATCH_REQ_LOADTYPE_NVM_INSTALL;
398+
patch_resp = hwrm_req_hold(bp, patch_req);
399+
400+
for (target = 1; target <= FW_LIVEPATCH_REQ_FW_TARGET_LAST; target++) {
401+
query_req->fw_target = target;
402+
rc = hwrm_req_send(bp, query_req);
403+
if (rc) {
404+
NL_SET_ERR_MSG_MOD(extack, "Failed to query packages");
405+
break;
406+
}
407+
408+
flags = le16_to_cpu(query_resp->status_flags);
409+
if (~flags & FW_LIVEPATCH_QUERY_RESP_STATUS_FLAGS_INSTALL)
410+
continue;
411+
if ((flags & FW_LIVEPATCH_QUERY_RESP_STATUS_FLAGS_ACTIVE) &&
412+
!strncmp(query_resp->active_ver, query_resp->install_ver,
413+
sizeof(query_resp->active_ver)))
414+
continue;
415+
416+
patch_req->fw_target = target;
417+
rc = hwrm_req_send(bp, patch_req);
418+
if (rc) {
419+
bnxt_dl_livepatch_report_err(bp, extack, patch_resp);
420+
break;
421+
}
422+
installed++;
423+
}
424+
425+
if (!rc && !installed) {
426+
NL_SET_ERR_MSG_MOD(extack, "No live patches found");
427+
rc = -ENOENT;
428+
}
429+
hwrm_req_drop(bp, query_req);
430+
hwrm_req_drop(bp, patch_req);
431+
return rc;
432+
}
433+
329434
static int bnxt_dl_reload_down(struct devlink *dl, bool netns_change,
330435
enum devlink_reload_action action,
331436
enum devlink_reload_limit limit,
@@ -372,6 +477,8 @@ static int bnxt_dl_reload_down(struct devlink *dl, bool netns_change,
372477
break;
373478
}
374479
case DEVLINK_RELOAD_ACTION_FW_ACTIVATE: {
480+
if (limit == DEVLINK_RELOAD_LIMIT_NO_RESET)
481+
return bnxt_dl_livepatch_activate(bp, extack);
375482
if (~bp->fw_cap & BNXT_FW_CAP_HOT_RESET) {
376483
NL_SET_ERR_MSG_MOD(extack, "Device not capable, requires reboot");
377484
return -EOPNOTSUPP;
@@ -432,6 +539,8 @@ static int bnxt_dl_reload_up(struct devlink *dl, enum devlink_reload_action acti
432539
unsigned long start = jiffies;
433540
unsigned long timeout = start + BNXT_DFLT_FW_RST_MAX_DSECS * HZ / 10;
434541

542+
if (limit == DEVLINK_RELOAD_LIMIT_NO_RESET)
543+
break;
435544
if (bp->fw_cap & BNXT_FW_CAP_ERROR_RECOVERY)
436545
timeout = start + bp->fw_health->normal_func_wait_dsecs * HZ / 10;
437546
if (!netif_running(bp->dev))
@@ -485,6 +594,7 @@ static const struct devlink_ops bnxt_dl_ops = {
485594
.flash_update = bnxt_dl_flash_update,
486595
.reload_actions = BIT(DEVLINK_RELOAD_ACTION_DRIVER_REINIT) |
487596
BIT(DEVLINK_RELOAD_ACTION_FW_ACTIVATE),
597+
.reload_limits = BIT(DEVLINK_RELOAD_LIMIT_NO_RESET),
488598
.reload_down = bnxt_dl_reload_down,
489599
.reload_up = bnxt_dl_reload_up,
490600
};
@@ -630,6 +740,57 @@ static int bnxt_dl_info_put(struct bnxt *bp, struct devlink_info_req *req,
630740
return 0;
631741
}
632742

743+
#define BNXT_FW_SRT_PATCH "fw.srt.patch"
744+
#define BNXT_FW_CRT_PATCH "fw.crt.patch"
745+
746+
static int bnxt_dl_livepatch_info_put(struct bnxt *bp,
747+
struct devlink_info_req *req,
748+
const char *key)
749+
{
750+
struct hwrm_fw_livepatch_query_input *query;
751+
struct hwrm_fw_livepatch_query_output *resp;
752+
u16 flags;
753+
int rc;
754+
755+
if (~bp->fw_cap & BNXT_FW_CAP_LIVEPATCH)
756+
return 0;
757+
758+
rc = hwrm_req_init(bp, query, HWRM_FW_LIVEPATCH_QUERY);
759+
if (rc)
760+
return rc;
761+
762+
if (!strcmp(key, BNXT_FW_SRT_PATCH))
763+
query->fw_target = FW_LIVEPATCH_QUERY_REQ_FW_TARGET_SECURE_FW;
764+
else if (!strcmp(key, BNXT_FW_CRT_PATCH))
765+
query->fw_target = FW_LIVEPATCH_QUERY_REQ_FW_TARGET_COMMON_FW;
766+
else
767+
goto exit;
768+
769+
resp = hwrm_req_hold(bp, query);
770+
rc = hwrm_req_send(bp, query);
771+
if (rc)
772+
goto exit;
773+
774+
flags = le16_to_cpu(resp->status_flags);
775+
if (flags & FW_LIVEPATCH_QUERY_RESP_STATUS_FLAGS_ACTIVE) {
776+
resp->active_ver[sizeof(resp->active_ver) - 1] = '\0';
777+
rc = devlink_info_version_running_put(req, key, resp->active_ver);
778+
if (rc)
779+
goto exit;
780+
}
781+
782+
if (flags & FW_LIVEPATCH_QUERY_RESP_STATUS_FLAGS_INSTALL) {
783+
resp->install_ver[sizeof(resp->install_ver) - 1] = '\0';
784+
rc = devlink_info_version_stored_put(req, key, resp->install_ver);
785+
if (rc)
786+
goto exit;
787+
}
788+
789+
exit:
790+
hwrm_req_drop(bp, query);
791+
return rc;
792+
}
793+
633794
#define HWRM_FW_VER_STR_LEN 16
634795

635796
static int bnxt_dl_info_get(struct devlink *dl, struct devlink_info_req *req,
@@ -783,8 +944,16 @@ static int bnxt_dl_info_get(struct devlink *dl, struct devlink_info_req *req,
783944
snprintf(roce_ver, FW_VER_STR_LEN, "%d.%d.%d.%d",
784945
nvm_dev_info.roce_fw_major, nvm_dev_info.roce_fw_minor,
785946
nvm_dev_info.roce_fw_build, nvm_dev_info.roce_fw_patch);
786-
return bnxt_dl_info_put(bp, req, BNXT_VERSION_STORED,
787-
DEVLINK_INFO_VERSION_GENERIC_FW_ROCE, roce_ver);
947+
rc = bnxt_dl_info_put(bp, req, BNXT_VERSION_STORED,
948+
DEVLINK_INFO_VERSION_GENERIC_FW_ROCE, roce_ver);
949+
if (rc)
950+
return rc;
951+
952+
rc = bnxt_dl_livepatch_info_put(bp, req, BNXT_FW_SRT_PATCH);
953+
if (rc)
954+
return rc;
955+
return bnxt_dl_livepatch_info_put(bp, req, BNXT_FW_CRT_PATCH);
956+
788957
}
789958

790959
static int bnxt_hwrm_nvm_req(struct bnxt *bp, u32 param_id, void *msg,

0 commit comments

Comments
 (0)