From: Aleksandr Loktionov <aleksandr.loktionov@intel.com>
To: intel-wired-lan@lists.osuosl.org, anthony.l.nguyen@intel.com,
aleksandr.loktionov@intel.com
Cc: netdev@vger.kernel.org, e02905820face5404ac5eb8193ba94f9823c4606,
Mon, Sep, 17, 00:00:00, 2001,
Przemek Kitszel <przemyslaw.kitszel@intel.com>
Subject: From: Aleksandr Loktionov <aleksandr.loktionov@intel.com>
Date: Thu, 17 Sep 2026 11:43:12 +0200 [thread overview]
Message-ID: <20260917094312.1567881-3-aleksandr.loktionov@intel.com> (raw)
In-Reply-To: <20260917094312.1567881-1-aleksandr.loktionov@intel.com>
On eRoT adapters, firmware rejects partial NVM updates mid-session.
Detect this proactively before any flash writes by tracking which PLDM
components have been presented in ice_send_component_table().
All four authentication components must be present for an eRoT update:
NVM Bank, OROM, NetList, and Manifest. If any are absent when
ice_flash_component() is called, reject with -EPERM and a clear
netlink error message before erasing any flash bank.
NVM_COMP_ID_MANIFEST only exists on eRoT adapters; the Shadow RAM
pointer backing it (module 0x4E) is unallocated on other hardware.
Accept it in ice_send_component_table() only when ICE_F_EROT is
supported, so a non-eRoT adapter still rejects it as an unknown
component before any flash write, same as before this patch. Its
activate-select flag is 0, since the ACTIV_SEL bitmask only defines
bits for NVM, OROM, and NetList.
Duplicate component IDs within a single PLDM image are also rejected
in ice_send_component_table() before the component table is sent to
firmware.
Unlike its NVM/OROM/NetList siblings, the manifest bank has no
ICE_SR_PQC_MANIFEST_BANK_SIZE counterpart: nothing reads the manifest
area size back via ice_read_sr_area_size(), so only the bank pointer
is defined.
Signed-off-by: Aleksandr Loktionov <aleksandr.loktionov@intel.com>
Reviewed-by: Przemek Kitszel <przemyslaw.kitszel@intel.com>
---
.../net/ethernet/intel/ice/ice_adminq_cmd.h | 1 +
.../net/ethernet/intel/ice/ice_fw_update.c | 80 +++++++++++++++++++
drivers/net/ethernet/intel/ice/ice_type.h | 1 +
3 files changed, 82 insertions(+)
diff --git a/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h b/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h
index 42878ab..b240f2c 100644
--- a/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h
+++ b/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h
@@ -1747,6 +1747,7 @@ struct ice_aqc_nvm_comp_tbl {
#define NVM_COMP_ID_OROM 0x5
#define NVM_COMP_ID_NVM 0x6
#define NVM_COMP_ID_NETLIST 0x8
+#define NVM_COMP_ID_MANIFEST 0x12
u8 comp_class_idx;
#define FWU_COMP_CLASS_IDX_NOT_USE 0x0
diff --git a/drivers/net/ethernet/intel/ice/ice_fw_update.c b/drivers/net/ethernet/intel/ice/ice_fw_update.c
index 3631461..fe68efa 100644
--- a/drivers/net/ethernet/intel/ice/ice_fw_update.c
+++ b/drivers/net/ethernet/intel/ice/ice_fw_update.c
@@ -9,6 +9,18 @@
#include "ice_lib.h"
#include "ice_fw_update.h"
+/* Bitmask values for ice_fwu_priv::seen_components */
+#define ICE_FWU_COMP_NVM BIT(0)
+#define ICE_FWU_COMP_OROM BIT(1)
+#define ICE_FWU_COMP_NETLIST BIT(2)
+#define ICE_FWU_COMP_MANIFEST BIT(3)
+/* Components required for a complete eRoT-authenticated update.
+ * If firmware adds further authentication components in future
+ * hardware, this mask must be extended to match.
+ */
+#define ICE_FWU_COMP_ALL_EROT (ICE_FWU_COMP_NVM | ICE_FWU_COMP_OROM | \
+ ICE_FWU_COMP_NETLIST | ICE_FWU_COMP_MANIFEST)
+
struct ice_fwu_priv {
struct pldmfw context;
@@ -29,6 +41,9 @@ struct ice_fwu_priv {
/* Track if EMP reset is available */
u8 emp_reset_available;
+
+ /* Bitmask of auth components seen in this image (ICE_FWU_COMP_*) */
+ u8 seen_components;
};
/**
@@ -108,6 +123,9 @@ ice_check_component_response(struct ice_pf *pf, u16 id, u8 response, u8 code,
case NVM_COMP_ID_NETLIST:
component = "fw.netlist";
break;
+ case NVM_COMP_ID_MANIFEST:
+ component = "fw.pqc_manifest";
+ break;
default:
WARN(1, "Unexpected unknown component identifier 0x%02x", id);
return -EINVAL;
@@ -220,12 +238,28 @@ ice_send_component_table(struct pldmfw *context, struct pldmfw_component *compon
struct ice_pf *pf = priv->pf;
struct ice_hw *hw = &pf->hw;
size_t length;
+ u8 comp_bit;
int status;
switch (component->identifier) {
case NVM_COMP_ID_OROM:
+ comp_bit = ICE_FWU_COMP_OROM;
+ break;
case NVM_COMP_ID_NVM:
+ comp_bit = ICE_FWU_COMP_NVM;
+ break;
case NVM_COMP_ID_NETLIST:
+ comp_bit = ICE_FWU_COMP_NETLIST;
+ break;
+ case NVM_COMP_ID_MANIFEST:
+ if (!ice_is_feature_supported(pf, ICE_F_EROT)) {
+ dev_err(dev, "Unable to update due to a firmware component with unknown ID %u\n",
+ component->identifier);
+ NL_SET_ERR_MSG_MOD(extack,
+ "Unable to update due to unknown firmware component");
+ return -EOPNOTSUPP;
+ }
+ comp_bit = ICE_FWU_COMP_MANIFEST;
break;
default:
dev_err(dev, "Unable to update due to a firmware component with unknown ID %u\n",
@@ -234,6 +268,14 @@ ice_send_component_table(struct pldmfw *context, struct pldmfw_component *compon
return -EOPNOTSUPP;
}
+ if (priv->seen_components & comp_bit) {
+ dev_err(dev, "Duplicate component in PLDM image: component ID 0x%02x\n",
+ component->identifier);
+ NL_SET_ERR_MSG_MOD(extack, "Duplicate component in PLDM image");
+ return -EOPNOTSUPP;
+ }
+ priv->seen_components |= comp_bit;
+
length = struct_size(comp_tbl, cvs, component->version_len);
comp_tbl = kzalloc(length, GFP_KERNEL);
if (!comp_tbl)
@@ -623,6 +665,24 @@ ice_switch_flash_banks(struct ice_pf *pf, u8 activate_flags,
return 0;
}
+/**
+ * ice_has_erot_incomplete - check whether an eRoT update is missing a component
+ * @priv: PLDM firmware update private data
+ *
+ * On eRoT adapters all four authentication components must be present.
+ *
+ * Return: true when a required component is absent on an eRoT adapter (the
+ * update must be rejected), false otherwise (including non-eRoT adapters).
+ */
+static bool
+ice_has_erot_incomplete(struct ice_fwu_priv *priv)
+{
+ if (!ice_is_feature_supported(priv->pf, ICE_F_EROT))
+ return false;
+
+ return priv->seen_components != ICE_FWU_COMP_ALL_EROT;
+}
+
/**
* ice_flash_component - Flash a component of the NVM
* @context: PLDM fw update structure
@@ -667,6 +727,16 @@ ice_flash_component(struct pldmfw *context, struct pldmfw_component *component)
reset_level = NULL;
name = "fw.netlist";
break;
+ case NVM_COMP_ID_MANIFEST:
+ module = ICE_SR_PQC_MANIFEST_BANK_PTR;
+ /* Manifest has no ACTIV_SEL bit of its own; ACTIV_SEL only
+ * defines activation bits for NVM, OROM, and NetList, so
+ * there is nothing to add to priv->activate_flags here.
+ */
+ flag = 0;
+ reset_level = NULL;
+ name = "fw.pqc_manifest";
+ break;
default:
/* This should not trigger, since we check the id before
* sending the component table to firmware.
@@ -676,6 +746,16 @@ ice_flash_component(struct pldmfw *context, struct pldmfw_component *component)
return -EINVAL;
}
+ /* ice_send_component_table() is called for every component in the
+ * PLDM image before pldmfw_flash_image() ever calls this function,
+ * so priv->seen_components is already fully populated by the time
+ * the first component reaches ice_flash_component().
+ */
+ if (ice_has_erot_incomplete(priv)) {
+ NL_SET_ERR_MSG_MOD(extack,
+ "eRoT adapter requires all four components (NVM, OROM, NetList, Manifest) in a single update");
+ return -EINVAL;
+ }
/* Mark this component for activating at the end */
priv->activate_flags |= flag;
diff --git a/drivers/net/ethernet/intel/ice/ice_type.h b/drivers/net/ethernet/intel/ice/ice_type.h
index 1375106..847f17e6 100644
--- a/drivers/net/ethernet/intel/ice/ice_type.h
+++ b/drivers/net/ethernet/intel/ice/ice_type.h
@@ -1154,6 +1154,7 @@ struct ice_aq_get_set_rss_lut_params {
#define ICE_SR_OROM_BANK_SIZE 0x45
#define ICE_SR_NETLIST_BANK_PTR 0x46
#define ICE_SR_NETLIST_BANK_SIZE 0x47
+#define ICE_SR_PQC_MANIFEST_BANK_PTR 0x4E
#define ICE_SR_SECTOR_SIZE_IN_WORDS 0x800
/* CSS Header words */
--
2.52.0
next prev parent reply other threads:[~2026-09-17 9:43 UTC|newest]
Thread overview: 5+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-09-17 9:43 [PATCH next-queue v1 0/2] ice: eRoT adapter NVM update guard Aleksandr Loktionov
2026-09-17 9:43 ` From: Aleksandr Loktionov <aleksandr.loktionov@intel.com> Aleksandr Loktionov
2026-09-18 13:11 ` Tomasz Lichwala
2026-09-17 9:43 ` Aleksandr Loktionov [this message]
2026-09-18 13:21 ` Tomasz Lichwala
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260917094312.1567881-3-aleksandr.loktionov@intel.com \
--to=aleksandr.loktionov@intel.com \
--cc=anthony.l.nguyen@intel.com \
--cc=intel-wired-lan@lists.osuosl.org \
--cc=netdev@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox