u8 rsvd2[12];
 };
 
-/* The result of netlist NVM read comes in a TLV format. The actual data
- * (netlist header) starts from word offset 1 (byte 2). The FW strips
- * out the type field from the TLV header so all the netlist fields
- * should adjust their offset value by 1 word (2 bytes) in order to map
- * their correct location.
- */
-#define ICE_AQC_NVM_LINK_TOPO_NETLIST_MOD_ID           0x11B
-#define ICE_AQC_NVM_LINK_TOPO_NETLIST_LEN_OFFSET       1
-#define ICE_AQC_NVM_LINK_TOPO_NETLIST_LEN              2 /* In bytes */
-#define ICE_AQC_NVM_NETLIST_NODE_COUNT_OFFSET          2
-#define ICE_AQC_NVM_NETLIST_NODE_COUNT_LEN             2 /* In bytes */
-#define ICE_AQC_NVM_NETLIST_NODE_COUNT_M               ICE_M(0x3FF, 0)
-#define ICE_AQC_NVM_NETLIST_ID_BLK_START_OFFSET                5
-#define ICE_AQC_NVM_NETLIST_ID_BLK_LEN                 0x30 /* In words */
-
-/* netlist ID block field offsets (word offsets) */
-#define ICE_AQC_NVM_NETLIST_ID_BLK_MAJOR_VER_LOW       2
-#define ICE_AQC_NVM_NETLIST_ID_BLK_MAJOR_VER_HIGH      3
-#define ICE_AQC_NVM_NETLIST_ID_BLK_MINOR_VER_LOW       4
-#define ICE_AQC_NVM_NETLIST_ID_BLK_MINOR_VER_HIGH      5
-#define ICE_AQC_NVM_NETLIST_ID_BLK_TYPE_LOW            6
-#define ICE_AQC_NVM_NETLIST_ID_BLK_TYPE_HIGH           7
-#define ICE_AQC_NVM_NETLIST_ID_BLK_REV_LOW             8
-#define ICE_AQC_NVM_NETLIST_ID_BLK_REV_HIGH            9
-#define ICE_AQC_NVM_NETLIST_ID_BLK_SHA_HASH            0xA
-#define ICE_AQC_NVM_NETLIST_ID_BLK_CUST_VER            0x2F
-
 /* Used for NVM Set Package Data command - 0x070A */
 struct ice_aqc_nvm_pkg_data {
        u8 reserved[3];
 
 struct ice_info_ctx {
        char buf[128];
        struct ice_nvm_info pending_nvm;
+       struct ice_netlist_info pending_netlist;
        struct ice_hw_dev_caps dev_caps;
 };
 
        return 0;
 }
 
+static int
+ice_info_pending_netlist_ver(struct ice_pf __always_unused *pf, struct ice_info_ctx *ctx)
+{
+       struct ice_netlist_info *netlist = &ctx->pending_netlist;
+
+       /* The netlist version fields are BCD formatted */
+       if (ctx->dev_caps.common_cap.nvm_update_pending_netlist)
+               snprintf(ctx->buf, sizeof(ctx->buf), "%x.%x.%x-%x.%x.%x",
+                        netlist->major, netlist->minor,
+                        netlist->type >> 16, netlist->type & 0xFFFF, netlist->rev,
+                        netlist->cust_ver);
+
+       return 0;
+}
+
+static int
+ice_info_pending_netlist_build(struct ice_pf __always_unused *pf, struct ice_info_ctx *ctx)
+{
+       struct ice_netlist_info *netlist = &ctx->pending_netlist;
+
+       if (ctx->dev_caps.common_cap.nvm_update_pending_netlist)
+               snprintf(ctx->buf, sizeof(ctx->buf), "0x%08x", netlist->hash);
+
+       return 0;
+}
+
 #define fixed(key, getter) { ICE_VERSION_FIXED, key, getter, NULL }
 #define running(key, getter) { ICE_VERSION_RUNNING, key, getter, NULL }
 #define stored(key, getter, fallback) { ICE_VERSION_STORED, key, getter, fallback }
        running("fw.app.name", ice_info_ddp_pkg_name),
        running(DEVLINK_INFO_VERSION_GENERIC_FW_APP, ice_info_ddp_pkg_version),
        running("fw.app.bundle_id", ice_info_ddp_pkg_bundle_id),
-       running("fw.netlist", ice_info_netlist_ver),
-       running("fw.netlist.build", ice_info_netlist_build),
+       combined("fw.netlist", ice_info_netlist_ver, ice_info_pending_netlist_ver),
+       combined("fw.netlist.build", ice_info_netlist_build, ice_info_pending_netlist_build),
 };
 
 /**
                }
        }
 
+       if (ctx->dev_caps.common_cap.nvm_update_pending_netlist) {
+               status = ice_get_inactive_netlist_ver(hw, &ctx->pending_netlist);
+               if (status) {
+                       dev_dbg(dev, "Unable to read inactive Netlist version data, status %s aq_err %s\n",
+                               ice_stat_str(status), ice_aq_str(hw->adminq.sq_last_status));
+
+                       /* disable display of pending Option ROM */
+                       ctx->dev_caps.common_cap.nvm_update_pending_netlist = false;
+               }
+       }
+
        err = devlink_info_driver_name_put(req, KBUILD_MODNAME);
        if (err) {
                NL_SET_ERR_MSG_MOD(extack, "Unable to set driver name");
 
        return ice_read_nvm_module(hw, bank, ICE_NVM_SR_COPY_WORD_OFFSET + offset, data);
 }
 
+/**
+ * ice_read_netlist_module - Read data from the netlist module area
+ * @hw: pointer to the HW structure
+ * @bank: whether to read from the active or inactive module
+ * @offset: offset into the netlist to read from
+ * @data: storage for returned word value
+ *
+ * Read a word from the specified netlist bank.
+ */
+static enum ice_status
+ice_read_netlist_module(struct ice_hw *hw, enum ice_bank_select bank, u32 offset, u16 *data)
+{
+       enum ice_status status;
+       __le16 data_local;
+
+       status = ice_read_flash_module(hw, bank, ICE_SR_NETLIST_BANK_PTR, offset * sizeof(u16),
+                                      (__force u8 *)&data_local, sizeof(u16));
+       if (!status)
+               *data = le16_to_cpu(data_local);
+
+       return status;
+}
+
 /**
  * ice_read_sr_word - Reads Shadow RAM word and acquire NVM if necessary
  * @hw: pointer to the HW structure
 }
 
 /**
- * ice_get_netlist_ver_info
+ * ice_get_netlist_info
  * @hw: pointer to the HW struct
- * @ver: pointer to netlist version info structure
+ * @bank: whether to read from the active or inactive flash bank
+ * @netlist: pointer to netlist version info structure
  *
- * Get the netlist version information
+ * Get the netlist version information from the requested bank. Reads the Link
+ * Topology section to find the Netlist ID block and extract the relevant
+ * information into the netlist version structure.
  */
 static enum ice_status
-ice_get_netlist_ver_info(struct ice_hw *hw, struct ice_netlist_info *ver)
+ice_get_netlist_info(struct ice_hw *hw, enum ice_bank_select bank,
+                    struct ice_netlist_info *netlist)
 {
-       enum ice_status ret;
-       u32 id_blk_start;
-       __le16 raw_data;
-       u16 data, i;
-       u16 *buff;
-
-       ret = ice_acquire_nvm(hw, ICE_RES_READ);
-       if (ret)
-               return ret;
-       buff = kcalloc(ICE_AQC_NVM_NETLIST_ID_BLK_LEN, sizeof(*buff),
-                      GFP_KERNEL);
-       if (!buff) {
-               ret = ICE_ERR_NO_MEMORY;
-               goto exit_no_mem;
+       u16 module_id, length, node_count, i;
+       enum ice_status status;
+       u16 *id_blk;
+
+       status = ice_read_netlist_module(hw, bank, ICE_NETLIST_TYPE_OFFSET, &module_id);
+       if (status)
+               return status;
+
+       if (module_id != ICE_NETLIST_LINK_TOPO_MOD_ID) {
+               ice_debug(hw, ICE_DBG_NVM, "Expected netlist module_id ID of 0x%04x, but got 0x%04x\n",
+                         ICE_NETLIST_LINK_TOPO_MOD_ID, module_id);
+               return ICE_ERR_NVM;
        }
 
-       /* read module length */
-       ret = ice_aq_read_nvm(hw, ICE_AQC_NVM_LINK_TOPO_NETLIST_MOD_ID,
-                             ICE_AQC_NVM_LINK_TOPO_NETLIST_LEN_OFFSET * 2,
-                             ICE_AQC_NVM_LINK_TOPO_NETLIST_LEN, &raw_data,
-                             false, false, NULL);
-       if (ret)
-               goto exit_error;
+       status = ice_read_netlist_module(hw, bank, ICE_LINK_TOPO_MODULE_LEN, &length);
+       if (status)
+               return status;
 
-       data = le16_to_cpu(raw_data);
-       /* exit if length is = 0 */
-       if (!data)
-               goto exit_error;
+       /* sanity check that we have at least enough words to store the netlist ID block */
+       if (length < ICE_NETLIST_ID_BLK_SIZE) {
+               ice_debug(hw, ICE_DBG_NVM, "Netlist Link Topology module too small. Expected at least %u words, but got %u words.\n",
+                         ICE_NETLIST_ID_BLK_SIZE, length);
+               return ICE_ERR_NVM;
+       }
 
-       /* read node count */
-       ret = ice_aq_read_nvm(hw, ICE_AQC_NVM_LINK_TOPO_NETLIST_MOD_ID,
-                             ICE_AQC_NVM_NETLIST_NODE_COUNT_OFFSET * 2,
-                             ICE_AQC_NVM_NETLIST_NODE_COUNT_LEN, &raw_data,
-                             false, false, NULL);
-       if (ret)
-               goto exit_error;
-       data = le16_to_cpu(raw_data) & ICE_AQC_NVM_NETLIST_NODE_COUNT_M;
+       status = ice_read_netlist_module(hw, bank, ICE_LINK_TOPO_NODE_COUNT, &node_count);
+       if (status)
+               return status;
+       node_count &= ICE_LINK_TOPO_NODE_COUNT_M;
 
-       /* netlist ID block starts from offset 4 + node count * 2 */
-       id_blk_start = ICE_AQC_NVM_NETLIST_ID_BLK_START_OFFSET + data * 2;
+       id_blk = kcalloc(ICE_NETLIST_ID_BLK_SIZE, sizeof(*id_blk), GFP_KERNEL);
+       if (!id_blk)
+               return ICE_ERR_NO_MEMORY;
 
-       /* read the entire netlist ID block */
-       ret = ice_aq_read_nvm(hw, ICE_AQC_NVM_LINK_TOPO_NETLIST_MOD_ID,
-                             id_blk_start * 2,
-                             ICE_AQC_NVM_NETLIST_ID_BLK_LEN * 2, buff, false,
-                             false, NULL);
-       if (ret)
+       /* Read out the entire Netlist ID Block at once. */
+       status = ice_read_flash_module(hw, bank, ICE_SR_NETLIST_BANK_PTR,
+                                      ICE_NETLIST_ID_BLK_OFFSET(node_count) * sizeof(u16),
+                                      (u8 *)id_blk, ICE_NETLIST_ID_BLK_SIZE * sizeof(u16));
+       if (status)
                goto exit_error;
 
-       for (i = 0; i < ICE_AQC_NVM_NETLIST_ID_BLK_LEN; i++)
-               buff[i] = le16_to_cpu(((__force __le16 *)buff)[i]);
-
-       ver->major = (buff[ICE_AQC_NVM_NETLIST_ID_BLK_MAJOR_VER_HIGH] << 16) |
-               buff[ICE_AQC_NVM_NETLIST_ID_BLK_MAJOR_VER_LOW];
-       ver->minor = (buff[ICE_AQC_NVM_NETLIST_ID_BLK_MINOR_VER_HIGH] << 16) |
-               buff[ICE_AQC_NVM_NETLIST_ID_BLK_MINOR_VER_LOW];
-       ver->type = (buff[ICE_AQC_NVM_NETLIST_ID_BLK_TYPE_HIGH] << 16) |
-               buff[ICE_AQC_NVM_NETLIST_ID_BLK_TYPE_LOW];
-       ver->rev = (buff[ICE_AQC_NVM_NETLIST_ID_BLK_REV_HIGH] << 16) |
-               buff[ICE_AQC_NVM_NETLIST_ID_BLK_REV_LOW];
-       ver->cust_ver = buff[ICE_AQC_NVM_NETLIST_ID_BLK_CUST_VER];
+       for (i = 0; i < ICE_NETLIST_ID_BLK_SIZE; i++)
+               id_blk[i] = le16_to_cpu(((__force __le16 *)id_blk)[i]);
+
+       netlist->major = id_blk[ICE_NETLIST_ID_BLK_MAJOR_VER_HIGH] << 16 |
+                        id_blk[ICE_NETLIST_ID_BLK_MAJOR_VER_LOW];
+       netlist->minor = id_blk[ICE_NETLIST_ID_BLK_MINOR_VER_HIGH] << 16 |
+                        id_blk[ICE_NETLIST_ID_BLK_MINOR_VER_LOW];
+       netlist->type = id_blk[ICE_NETLIST_ID_BLK_TYPE_HIGH] << 16 |
+                       id_blk[ICE_NETLIST_ID_BLK_TYPE_LOW];
+       netlist->rev = id_blk[ICE_NETLIST_ID_BLK_REV_HIGH] << 16 |
+                      id_blk[ICE_NETLIST_ID_BLK_REV_LOW];
+       netlist->cust_ver = id_blk[ICE_NETLIST_ID_BLK_CUST_VER];
        /* Read the left most 4 bytes of SHA */
-       ver->hash = buff[ICE_AQC_NVM_NETLIST_ID_BLK_SHA_HASH + 15] << 16 |
-               buff[ICE_AQC_NVM_NETLIST_ID_BLK_SHA_HASH + 14];
+       netlist->hash = id_blk[ICE_NETLIST_ID_BLK_SHA_HASH_WORD(15)] << 16 |
+                       id_blk[ICE_NETLIST_ID_BLK_SHA_HASH_WORD(14)];
 
 exit_error:
-       kfree(buff);
-exit_no_mem:
-       ice_release_nvm(hw);
-       return ret;
+       kfree(id_blk);
+
+       return status;
+}
+
+/**
+ * ice_get_inactive_netlist_ver
+ * @hw: pointer to the HW struct
+ * @netlist: pointer to netlist version info structure
+ *
+ * Read the netlist version data from the inactive netlist bank. Used to
+ * extract version data of a pending flash update in order to display the
+ * version data.
+ */
+enum ice_status ice_get_inactive_netlist_ver(struct ice_hw *hw, struct ice_netlist_info *netlist)
+{
+       return ice_get_netlist_info(hw, ICE_INACTIVE_FLASH_BANK, netlist);
 }
 
 /**
        }
 
        /* read the netlist version information */
-       status = ice_get_netlist_ver_info(hw, &flash->netlist);
+       status = ice_get_netlist_info(hw, ICE_ACTIVE_FLASH_BANK, &flash->netlist);
        if (status)
                ice_debug(hw, ICE_DBG_INIT, "Failed to read netlist info.\n");
 
 
 /* Size in bytes of Option ROM trailer */
 #define ICE_NVM_OROM_TRAILER_LENGTH            (2 * ICE_CSS_HEADER_LENGTH)
 
+/* The Link Topology Netlist section is stored as a series of words. It is
+ * stored in the NVM as a TLV, with the first two words containing the type
+ * and length.
+ */
+#define ICE_NETLIST_LINK_TOPO_MOD_ID           0x011B
+#define ICE_NETLIST_TYPE_OFFSET                        0x0000
+#define ICE_NETLIST_LEN_OFFSET                 0x0001
+
+/* The Link Topology section follows the TLV header. When reading the netlist
+ * using ice_read_netlist_module, we need to account for the 2-word TLV
+ * header.
+ */
+#define ICE_NETLIST_LINK_TOPO_OFFSET(n)                ((n) + 2)
+
+#define ICE_LINK_TOPO_MODULE_LEN               ICE_NETLIST_LINK_TOPO_OFFSET(0x0000)
+#define ICE_LINK_TOPO_NODE_COUNT               ICE_NETLIST_LINK_TOPO_OFFSET(0x0001)
+
+#define ICE_LINK_TOPO_NODE_COUNT_M             ICE_M(0x3FF, 0)
+
+/* The Netlist ID Block is located after all of the Link Topology nodes. */
+#define ICE_NETLIST_ID_BLK_SIZE                        0x30
+#define ICE_NETLIST_ID_BLK_OFFSET(n)           ICE_NETLIST_LINK_TOPO_OFFSET(0x0004 + 2 * (n))
+
+/* netlist ID block field offsets (word offsets) */
+#define ICE_NETLIST_ID_BLK_MAJOR_VER_LOW       0x02
+#define ICE_NETLIST_ID_BLK_MAJOR_VER_HIGH      0x03
+#define ICE_NETLIST_ID_BLK_MINOR_VER_LOW       0x04
+#define ICE_NETLIST_ID_BLK_MINOR_VER_HIGH      0x05
+#define ICE_NETLIST_ID_BLK_TYPE_LOW            0x06
+#define ICE_NETLIST_ID_BLK_TYPE_HIGH           0x07
+#define ICE_NETLIST_ID_BLK_REV_LOW             0x08
+#define ICE_NETLIST_ID_BLK_REV_HIGH            0x09
+#define ICE_NETLIST_ID_BLK_SHA_HASH_WORD(n)    (0x0A + (n))
+#define ICE_NETLIST_ID_BLK_CUST_VER            0x2F
+
 /* Auxiliary field, mask, and shift definition for Shadow RAM and NVM Flash */
 #define ICE_SR_CTRL_WORD_1_S           0x06
 #define ICE_SR_CTRL_WORD_1_M           (0x03 << ICE_SR_CTRL_WORD_1_S)