1
0

Merge branch '100GbE' of git://git.kernel.org/pub/scm/linux/kernel/git/tnguy/next-queue

Tony Nguyen says:

====================
ice: support FW Recovery Mode

Konrad Knitter says:

Enable update of card in FW Recovery Mode

* '100GbE' of git://git.kernel.org/pub/scm/linux/kernel/git/tnguy/next-queue:
  ice: support FW Recovery Mode
  devlink: add devl guard
  pldmfw: enable selected component update
====================

Link: https://patch.msgid.link/20250116212059.1254349-1-anthony.l.nguyen@intel.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
Jakub Kicinski
2025-01-17 19:45:34 -08:00
9 changed files with 97 additions and 3 deletions

View File

@@ -368,14 +368,18 @@ static int ice_devlink_info_get(struct devlink *devlink,
}
break;
case ICE_VERSION_RUNNING:
err = devlink_info_version_running_put(req, key, ctx->buf);
err = devlink_info_version_running_put_ext(req, key,
ctx->buf,
DEVLINK_INFO_VERSION_TYPE_COMPONENT);
if (err) {
NL_SET_ERR_MSG_MOD(extack, "Unable to set running version");
goto out_free_ctx;
}
break;
case ICE_VERSION_STORED:
err = devlink_info_version_stored_put(req, key, ctx->buf);
err = devlink_info_version_stored_put_ext(req, key,
ctx->buf,
DEVLINK_INFO_VERSION_TYPE_COMPONENT);
if (err) {
NL_SET_ERR_MSG_MOD(extack, "Unable to set stored version");
goto out_free_ctx;

View File

@@ -1815,6 +1815,7 @@ struct ice_aqc_nvm_pass_comp_tbl {
#define ICE_AQ_NVM_PASS_COMP_CAN_BE_UPDATED 0x0
#define ICE_AQ_NVM_PASS_COMP_CAN_MAY_BE_UPDATEABLE 0x1
#define ICE_AQ_NVM_PASS_COMP_CAN_NOT_BE_UPDATED 0x2
#define ICE_AQ_NVM_PASS_COMP_PARTIAL_CHECK 0x3
u8 component_response_code; /* Response only */
#define ICE_AQ_NVM_PASS_COMP_CAN_BE_UPDATED_CODE 0x0
#define ICE_AQ_NVM_PASS_COMP_STAMP_IDENTICAL_CODE 0x1

View File

@@ -6,6 +6,7 @@
#include <linux/crc32.h>
#include <linux/pldmfw.h>
#include "ice.h"
#include "ice_lib.h"
#include "ice_fw_update.h"
struct ice_fwu_priv {
@@ -125,6 +126,10 @@ ice_check_component_response(struct ice_pf *pf, u16 id, u8 response, u8 code,
case ICE_AQ_NVM_PASS_COMP_CAN_NOT_BE_UPDATED:
dev_info(dev, "firmware has rejected updating %s\n", component);
break;
case ICE_AQ_NVM_PASS_COMP_PARTIAL_CHECK:
if (ice_is_recovery_mode(&pf->hw))
return 0;
break;
}
switch (code) {
@@ -1004,13 +1009,20 @@ int ice_devlink_flash_update(struct devlink *devlink,
return -EOPNOTSUPP;
}
if (!hw->dev_caps.common_cap.nvm_unified_update) {
if (!hw->dev_caps.common_cap.nvm_unified_update && !ice_is_recovery_mode(hw)) {
NL_SET_ERR_MSG_MOD(extack, "Current firmware does not support unified update");
return -EOPNOTSUPP;
}
memset(&priv, 0, sizeof(priv));
if (params->component && strcmp(params->component, "fw.mgmt") == 0) {
priv.context.mode = PLDMFW_UPDATE_MODE_SINGLE_COMPONENT;
priv.context.component_identifier = NVM_COMP_ID_NVM;
} else if (params->component) {
return -EOPNOTSUPP;
}
/* the E822 device needs a slightly different ops */
if (hw->mac_type == ICE_MAC_GENERIC)
priv.context.ops = &ice_fwu_ops_e822;

View File

@@ -1700,6 +1700,12 @@ bool ice_pf_state_is_nominal(struct ice_pf *pf)
return true;
}
#define ICE_FW_MODE_REC_M BIT(1)
bool ice_is_recovery_mode(struct ice_hw *hw)
{
return rd32(hw, GL_MNG_FWSM) & ICE_FW_MODE_REC_M;
}
/**
* ice_update_eth_stats - Update VSI-specific ethernet statistics counters
* @vsi: the VSI to be updated

View File

@@ -90,6 +90,7 @@ void ice_set_q_vector_intrl(struct ice_q_vector *q_vector);
bool ice_is_safe_mode(struct ice_pf *pf);
bool ice_is_rdma_ena(struct ice_pf *pf);
bool ice_is_recovery_mode(struct ice_hw *hw);
bool ice_is_dflt_vsi_in_use(struct ice_port_info *pi);
bool ice_is_vsi_dflt_vsi(struct ice_vsi *vsi);
int ice_set_dflt_vsi(struct ice_vsi *vsi);

View File

@@ -2364,6 +2364,18 @@ static void ice_check_media_subtask(struct ice_pf *pf)
}
}
static void ice_service_task_recovery_mode(struct work_struct *work)
{
struct ice_pf *pf = container_of(work, struct ice_pf, serv_task);
set_bit(ICE_ADMINQ_EVENT_PENDING, pf->state);
ice_clean_adminq_subtask(pf);
ice_service_task_complete(pf);
mod_timer(&pf->serv_tmr, jiffies + msecs_to_jiffies(100));
}
/**
* ice_service_task - manage and run subtasks
* @work: pointer to work_struct contained by the PF struct
@@ -5217,6 +5229,36 @@ void ice_unload(struct ice_pf *pf)
ice_decfg_netdev(vsi);
}
static int ice_probe_recovery_mode(struct ice_pf *pf)
{
struct device *dev = ice_pf_to_dev(pf);
int err;
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");
INIT_HLIST_HEAD(&pf->aq_wait_list);
spin_lock_init(&pf->aq_wait_lock);
init_waitqueue_head(&pf->aq_wait_queue);
timer_setup(&pf->serv_tmr, ice_service_timer, 0);
pf->serv_tmr_period = HZ;
INIT_WORK(&pf->serv_task, ice_service_task_recovery_mode);
clear_bit(ICE_SERVICE_SCHED, pf->state);
err = ice_create_all_ctrlq(&pf->hw);
if (err)
return err;
scoped_guard(devl, priv_to_devlink(pf)) {
err = ice_init_devlink(pf);
if (err)
return err;
}
ice_service_task_restart(pf);
return 0;
}
/**
* ice_probe - Device initialization routine
* @pdev: PCI device information struct
@@ -5308,6 +5350,9 @@ ice_probe(struct pci_dev *pdev, const struct pci_device_id __always_unused *ent)
hw->debug_mask = debug;
#endif
if (ice_is_recovery_mode(hw))
return ice_probe_recovery_mode(pf);
err = ice_init_hw(hw);
if (err) {
dev_err(dev, "ice_init_hw failed: %d\n", err);
@@ -5425,6 +5470,14 @@ static void ice_remove(struct pci_dev *pdev)
msleep(100);
}
if (ice_is_recovery_mode(&pf->hw)) {
ice_service_task_stop(pf);
scoped_guard(devl, priv_to_devlink(pf)) {
ice_deinit_devlink(pf);
}
return;
}
if (test_bit(ICE_FLAG_SRIOV_ENA, pf->flags)) {
set_bit(ICE_VF_RESETS_DISABLED, pf->state);
ice_free_vfs(pf);

View File

@@ -125,9 +125,17 @@ struct pldmfw_ops;
* a pointer to their own data, used to implement the device specific
* operations.
*/
enum pldmfw_update_mode {
PLDMFW_UPDATE_MODE_FULL,
PLDMFW_UPDATE_MODE_SINGLE_COMPONENT,
};
struct pldmfw {
const struct pldmfw_ops *ops;
struct device *dev;
u16 component_identifier;
enum pldmfw_update_mode mode;
};
bool pldmfw_op_pci_match_record(struct pldmfw *context, struct pldmfw_record *record);

View File

@@ -1535,6 +1535,7 @@ int devl_trylock(struct devlink *devlink);
void devl_unlock(struct devlink *devlink);
void devl_assert_locked(struct devlink *devlink);
bool devl_lock_is_held(struct devlink *devlink);
DEFINE_GUARD(devl, struct devlink *, devl_lock(_T), devl_unlock(_T));
struct ib_device;

View File

@@ -481,9 +481,17 @@ static int pldm_parse_components(struct pldmfw_priv *data)
component->component_data = data->fw->data + offset;
component->component_size = size;
if (data->context->mode == PLDMFW_UPDATE_MODE_SINGLE_COMPONENT &&
data->context->component_identifier != component->identifier)
continue;
list_add_tail(&component->entry, &data->components);
}
if (data->context->mode == PLDMFW_UPDATE_MODE_SINGLE_COMPONENT &&
list_empty(&data->components))
return -ENOENT;
header_crc_ptr = data->fw->data + data->offset;
err = pldm_move_fw_offset(data, sizeof(data->header_crc));