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 <[email protected]>
Reviewed-by: Przemek Kitszel <[email protected]>
---
 .../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


Reply via email to