Skip to content

Commit 1de25c6

Browse files
konradknitteranguy11
authored andcommitted
ice: support FW Recovery Mode
Recovery Mode is intended to recover from a fatal failure scenario in which the device is not accessible to the host, meaning the firmware is non-responsive. The purpose of the Firmware Recovery Mode is to enable software tools to update firmware and/or device configuration so the fatal error can be resolved. Recovery Mode Firmware supports a limited set of admin commands required for NVM update. Recovery Firmware does not support hardware interrupts so a polling mode is used. The driver will expose only the minimum set of devlink commands required for the recovery of the adapter. Using an appropriate NVM image, the user can recover the adapter using the devlink flash API. Prior to 4.20 E810 Adapter Recovery Firmware supports only the update and erase of the "fw.mgmt" component. E810 Adapter Recovery Firmware doesn't support selected preservation of cards settings or identifiers. The following command can be used to recover the adapter: $ devlink dev flash <pci-address> <update-image.bin> component fw.mgmt overwrite settings overwrite identifier Newer FW versions (4.20 or newer) supports update of "fw.undi" and "fw.netlist" components. $ devlink dev flash <pci-address> <update-image.bin> Tested on Intel Corporation Ethernet Controller E810-C for SFP FW revision 3.20 and 4.30. Reviewed-by: Przemek Kitszel <przemyslaw.kitszel@intel.com> Signed-off-by: Konrad Knitter <konrad.knitter@intel.com> Tested-by: Pucha Himasekhar Reddy <himasekharx.reddy.pucha@intel.com> (A Contingent worker at Intel) Signed-off-by: Tony Nguyen <anthony.l.nguyen@intel.com>
1 parent 0502bd2 commit 1de25c6

File tree

6 files changed

+80
-3
lines changed

6 files changed

+80
-3
lines changed

drivers/net/ethernet/intel/ice/devlink/devlink.c

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -368,14 +368,18 @@ static int ice_devlink_info_get(struct devlink *devlink,
368368
}
369369
break;
370370
case ICE_VERSION_RUNNING:
371-
err = devlink_info_version_running_put(req, key, ctx->buf);
371+
err = devlink_info_version_running_put_ext(req, key,
372+
ctx->buf,
373+
DEVLINK_INFO_VERSION_TYPE_COMPONENT);
372374
if (err) {
373375
NL_SET_ERR_MSG_MOD(extack, "Unable to set running version");
374376
goto out_free_ctx;
375377
}
376378
break;
377379
case ICE_VERSION_STORED:
378-
err = devlink_info_version_stored_put(req, key, ctx->buf);
380+
err = devlink_info_version_stored_put_ext(req, key,
381+
ctx->buf,
382+
DEVLINK_INFO_VERSION_TYPE_COMPONENT);
379383
if (err) {
380384
NL_SET_ERR_MSG_MOD(extack, "Unable to set stored version");
381385
goto out_free_ctx;

drivers/net/ethernet/intel/ice/ice_adminq_cmd.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1814,6 +1814,7 @@ struct ice_aqc_nvm_pass_comp_tbl {
18141814
#define ICE_AQ_NVM_PASS_COMP_CAN_BE_UPDATED 0x0
18151815
#define ICE_AQ_NVM_PASS_COMP_CAN_MAY_BE_UPDATEABLE 0x1
18161816
#define ICE_AQ_NVM_PASS_COMP_CAN_NOT_BE_UPDATED 0x2
1817+
#define ICE_AQ_NVM_PASS_COMP_PARTIAL_CHECK 0x3
18171818
u8 component_response_code; /* Response only */
18181819
#define ICE_AQ_NVM_PASS_COMP_CAN_BE_UPDATED_CODE 0x0
18191820
#define ICE_AQ_NVM_PASS_COMP_STAMP_IDENTICAL_CODE 0x1

drivers/net/ethernet/intel/ice/ice_fw_update.c

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
#include <linux/crc32.h>
77
#include <linux/pldmfw.h>
88
#include "ice.h"
9+
#include "ice_lib.h"
910
#include "ice_fw_update.h"
1011

1112
struct ice_fwu_priv {
@@ -125,6 +126,10 @@ ice_check_component_response(struct ice_pf *pf, u16 id, u8 response, u8 code,
125126
case ICE_AQ_NVM_PASS_COMP_CAN_NOT_BE_UPDATED:
126127
dev_info(dev, "firmware has rejected updating %s\n", component);
127128
break;
129+
case ICE_AQ_NVM_PASS_COMP_PARTIAL_CHECK:
130+
if (ice_is_recovery_mode(&pf->hw))
131+
return 0;
132+
break;
128133
}
129134

130135
switch (code) {
@@ -1004,13 +1009,20 @@ int ice_devlink_flash_update(struct devlink *devlink,
10041009
return -EOPNOTSUPP;
10051010
}
10061011

1007-
if (!hw->dev_caps.common_cap.nvm_unified_update) {
1012+
if (!hw->dev_caps.common_cap.nvm_unified_update && !ice_is_recovery_mode(hw)) {
10081013
NL_SET_ERR_MSG_MOD(extack, "Current firmware does not support unified update");
10091014
return -EOPNOTSUPP;
10101015
}
10111016

10121017
memset(&priv, 0, sizeof(priv));
10131018

1019+
if (params->component && strcmp(params->component, "fw.mgmt") == 0) {
1020+
priv.context.mode = PLDMFW_UPDATE_MODE_SINGLE_COMPONENT;
1021+
priv.context.component_identifier = NVM_COMP_ID_NVM;
1022+
} else if (params->component) {
1023+
return -EOPNOTSUPP;
1024+
}
1025+
10141026
/* the E822 device needs a slightly different ops */
10151027
if (hw->mac_type == ICE_MAC_GENERIC)
10161028
priv.context.ops = &ice_fwu_ops_e822;

drivers/net/ethernet/intel/ice/ice_lib.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1700,6 +1700,12 @@ bool ice_pf_state_is_nominal(struct ice_pf *pf)
17001700
return true;
17011701
}
17021702

1703+
#define ICE_FW_MODE_REC_M BIT(1)
1704+
bool ice_is_recovery_mode(struct ice_hw *hw)
1705+
{
1706+
return rd32(hw, GL_MNG_FWSM) & ICE_FW_MODE_REC_M;
1707+
}
1708+
17031709
/**
17041710
* ice_update_eth_stats - Update VSI-specific ethernet statistics counters
17051711
* @vsi: the VSI to be updated

drivers/net/ethernet/intel/ice/ice_lib.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@ void ice_set_q_vector_intrl(struct ice_q_vector *q_vector);
9090

9191
bool ice_is_safe_mode(struct ice_pf *pf);
9292
bool ice_is_rdma_ena(struct ice_pf *pf);
93+
bool ice_is_recovery_mode(struct ice_hw *hw);
9394
bool ice_is_dflt_vsi_in_use(struct ice_port_info *pi);
9495
bool ice_is_vsi_dflt_vsi(struct ice_vsi *vsi);
9596
int ice_set_dflt_vsi(struct ice_vsi *vsi);

drivers/net/ethernet/intel/ice/ice_main.c

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2364,6 +2364,18 @@ static void ice_check_media_subtask(struct ice_pf *pf)
23642364
}
23652365
}
23662366

2367+
static void ice_service_task_recovery_mode(struct work_struct *work)
2368+
{
2369+
struct ice_pf *pf = container_of(work, struct ice_pf, serv_task);
2370+
2371+
set_bit(ICE_ADMINQ_EVENT_PENDING, pf->state);
2372+
ice_clean_adminq_subtask(pf);
2373+
2374+
ice_service_task_complete(pf);
2375+
2376+
mod_timer(&pf->serv_tmr, jiffies + msecs_to_jiffies(100));
2377+
}
2378+
23672379
/**
23682380
* ice_service_task - manage and run subtasks
23692381
* @work: pointer to work_struct contained by the PF struct
@@ -5217,6 +5229,36 @@ void ice_unload(struct ice_pf *pf)
52175229
ice_decfg_netdev(vsi);
52185230
}
52195231

5232+
static int ice_probe_recovery_mode(struct ice_pf *pf)
5233+
{
5234+
struct device *dev = ice_pf_to_dev(pf);
5235+
int err;
5236+
5237+
dev_err(dev, "Firmware recovery mode detected. Limiting functionality. Refer to the Intel(R) Ethernet Adapters and Devices User Guide for details on firmware recovery mode\n");
5238+
5239+
INIT_HLIST_HEAD(&pf->aq_wait_list);
5240+
spin_lock_init(&pf->aq_wait_lock);
5241+
init_waitqueue_head(&pf->aq_wait_queue);
5242+
5243+
timer_setup(&pf->serv_tmr, ice_service_timer, 0);
5244+
pf->serv_tmr_period = HZ;
5245+
INIT_WORK(&pf->serv_task, ice_service_task_recovery_mode);
5246+
clear_bit(ICE_SERVICE_SCHED, pf->state);
5247+
err = ice_create_all_ctrlq(&pf->hw);
5248+
if (err)
5249+
return err;
5250+
5251+
scoped_guard(devl, priv_to_devlink(pf)) {
5252+
err = ice_init_devlink(pf);
5253+
if (err)
5254+
return err;
5255+
}
5256+
5257+
ice_service_task_restart(pf);
5258+
5259+
return 0;
5260+
}
5261+
52205262
/**
52215263
* ice_probe - Device initialization routine
52225264
* @pdev: PCI device information struct
@@ -5308,6 +5350,9 @@ ice_probe(struct pci_dev *pdev, const struct pci_device_id __always_unused *ent)
53085350
hw->debug_mask = debug;
53095351
#endif
53105352

5353+
if (ice_is_recovery_mode(hw))
5354+
return ice_probe_recovery_mode(pf);
5355+
53115356
err = ice_init_hw(hw);
53125357
if (err) {
53135358
dev_err(dev, "ice_init_hw failed: %d\n", err);
@@ -5425,6 +5470,14 @@ static void ice_remove(struct pci_dev *pdev)
54255470
msleep(100);
54265471
}
54275472

5473+
if (ice_is_recovery_mode(&pf->hw)) {
5474+
ice_service_task_stop(pf);
5475+
scoped_guard(devl, priv_to_devlink(pf)) {
5476+
ice_deinit_devlink(pf);
5477+
}
5478+
return;
5479+
}
5480+
54285481
if (test_bit(ICE_FLAG_SRIOV_ENA, pf->flags)) {
54295482
set_bit(ICE_VF_RESETS_DISABLED, pf->state);
54305483
ice_free_vfs(pf);

0 commit comments

Comments
 (0)