Index | Thread | Search

From:
Stefan Sperling <stsp@stsp.name>
Subject:
iwx: support pnvm data in firmware image
To:
tech@openbsd.org
Date:
Tue, 3 Mar 2026 15:25:49 +0100

Download raw body.

Thread
  • Stefan Sperling:

    iwx: support pnvm data in firmware image

Newer firmware images for BZ devices have a segment which contains
data that was previously distributed in separate .pnvm files.

If the firmware image contains pnvm data we must use it instead of
the external file. The external file might be incompatible.

ok?

diff /usr/src
path + /usr/src
commit - c58e64aeb4e092373382ec4900136445f091367c
blob - da9e3d2d42cdbb343313ea89ddfa6a89e1d39a31
file + sys/dev/pci/if_iwx.c
--- sys/dev/pci/if_iwx.c
+++ sys/dev/pci/if_iwx.c
@@ -1183,6 +1183,9 @@ iwx_fw_info_free(struct iwx_fw_info *fw)
 	free(fw->iml, M_DEVBUF, fw->iml_len);
 	fw->iml = NULL;
 	fw->iml_len = 0;
+	free(fw->pnvm, M_DEVBUF, fw->pnvm_len);
+	fw->pnvm = NULL;
+	fw->pnvm_len = 0;
 }
 
 #define IWX_FW_ADDR_CACHE_CONTROL 0xC0000000
@@ -1550,6 +1553,19 @@ iwx_read_firmware(struct iwx_softc *sc)
 		case IWX_UCODE_TLV_FW_RECOVERY_INFO:
 			break;
 
+		case IWX_UCODE_TLV_PNVM_DATA:
+			if (fw->pnvm != NULL)
+				break;
+			fw->pnvm = malloc(tlv_len, M_DEVBUF,
+			    M_WAITOK | M_CANFAIL);
+			if (fw->pnvm == NULL) {
+				err = ENOMEM;
+				goto parse_out;
+			}
+			memcpy(fw->pnvm, tlv_data, tlv_len);
+			fw->pnvm_len = tlv_len;
+			break;
+
 		case IWX_UCODE_TLV_FW_FSEQ_VERSION:
 		case IWX_UCODE_TLV_PHY_INTEGRATION_VERSION:
 		case IWX_UCODE_TLV_FW_NUM_STATIONS:
@@ -4294,6 +4310,7 @@ iwx_load_pnvm(struct iwx_softc *sc)
 	int s, err = 0;
 	u_char *pnvm_data = NULL;
 	size_t pnvm_size = 0;
+	struct iwx_fw_info *fw = &sc->sc_fw;
 
 	if (sc->sc_sku_id[0] == 0 &&
 	    sc->sc_sku_id[1] == 0 &&
@@ -4302,18 +4319,28 @@ iwx_load_pnvm(struct iwx_softc *sc)
 
 	if (sc->sc_pnvm_name) {
 		if (sc->pnvm_dma.vaddr == NULL) {
-			err = loadfirmware(sc->sc_pnvm_name,
-			    &pnvm_data, &pnvm_size);
-			if (err) {
-				printf("%s: could not read %s (error %d)\n",
-				    DEVNAME(sc), sc->sc_pnvm_name, err);
-				return err;
-			}
+			/* Prefer PNVM data embedded in firmware image. */
+			if (fw->pnvm) {
+				err = iwx_pnvm_parse(sc, fw->pnvm,
+				    fw->pnvm_len);
+				if (err && err != ENOENT)
+					return err;
+			} else {
+				err = loadfirmware(sc->sc_pnvm_name,
+				    &pnvm_data, &pnvm_size);
+				if (err) {
+					printf("%s: could not read %s "
+					    "(error %d)\n",
+					    DEVNAME(sc), sc->sc_pnvm_name,
+					    err);
+					return err;
+				}
 
-			err = iwx_pnvm_parse(sc, pnvm_data, pnvm_size);
-			if (err && err != ENOENT) {
-				free(pnvm_data, M_DEVBUF, pnvm_size);
-				return err;
+				err = iwx_pnvm_parse(sc, pnvm_data, pnvm_size);
+				if (err && err != ENOENT) {
+					free(pnvm_data, M_DEVBUF, pnvm_size);
+					return err;
+				}
 			}
 		} else
 			iwx_ctxt_info_gen3_set_pnvm(sc);
commit - c58e64aeb4e092373382ec4900136445f091367c
blob - 1af2759f445d0b05c35efd4ec8ff9ddab3ca419c
file + sys/dev/pci/if_iwxreg.h
--- sys/dev/pci/if_iwxreg.h
+++ sys/dev/pci/if_iwxreg.h
@@ -1584,6 +1584,7 @@ struct iwx_ucode_header {
 #define IWX_UCODE_TLV_SEC_TABLE_ADDR		66
 #define IWX_UCODE_TLV_D3_KEK_KCK_ADDR		67
 #define IWX_UCODE_TLV_CURRENT_PC		68
+#define IWX_UCODE_TLV_PNVM_DATA			74
 
 #define IWX_UCODE_TLV_CONST_BASE		0x100
 #define IWX_UCODE_TLV_FW_NUM_STATIONS		(IWX_UCODE_TLV_CONST_BASE + 0)
commit - c58e64aeb4e092373382ec4900136445f091367c
blob - 7be82818bc54423e510492e7b7e8974a0f63000d
file + sys/dev/pci/if_iwxvar.h
--- sys/dev/pci/if_iwxvar.h
+++ sys/dev/pci/if_iwxvar.h
@@ -173,6 +173,13 @@ struct iwx_fw_info {
 	/* Copy of firmware image loader found in file. */
 	uint8_t *iml;
 	size_t iml_len;
+
+	/*
+	 * Copy of PNVM image found in file.
+	 * Used in preference to external .pnvm file if present.
+	 */
+	uint8_t *pnvm;
+	size_t pnvm_len;
 };
 
 struct iwx_nvm_data {