Search Linux Wireless

[PATCH 21/47] iwlagn: prepare for new firmware file format

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



From: Johannes Berg <johannes.berg@xxxxxxxxx>

Currently the first four bytes in a firmware file
indicate the major, minor and api versions as well
as the serial number. These combined can never be
zero, so we can use that special case for a new,
future, file format.

This patch simply shuffles the code and prepares
for that new format.

Signed-off-by: Johannes Berg <johannes.berg@xxxxxxxxx>
Signed-off-by: Reinette Chatre <reinette.chatre@xxxxxxxxx>
---
 drivers/net/wireless/iwlwifi/iwl-agn.c |  291 ++++++++++++++++++--------------
 1 files changed, 168 insertions(+), 123 deletions(-)

diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c
index 70094bb..65ae636 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn.c
@@ -1534,6 +1534,91 @@ static int __must_check iwl_request_firmware(struct iwl_priv *priv, bool first)
 				       iwl_ucode_callback);
 }
 
+struct iwlagn_firmware_pieces {
+	const void *inst, *data, *init, *init_data, *boot;
+	size_t inst_size, data_size, init_size, init_data_size, boot_size;
+
+	u32 build;
+};
+
+static int iwlagn_load_legacy_firmware(struct iwl_priv *priv,
+				       const struct firmware *ucode_raw,
+				       struct iwlagn_firmware_pieces *pieces)
+{
+	struct iwl_ucode_header *ucode = (void *)ucode_raw->data;
+	u32 api_ver, hdr_size;
+	const u8 *src;
+
+	priv->ucode_ver = le32_to_cpu(ucode->ver);
+	api_ver = IWL_UCODE_API(priv->ucode_ver);
+
+	switch (api_ver) {
+	default:
+		/*
+		 * 4965 doesn't revision the firmware file format
+		 * along with the API version, it always uses v1
+		 * file format.
+		 */
+		if ((priv->hw_rev & CSR_HW_REV_TYPE_MSK) !=
+				CSR_HW_REV_TYPE_4965) {
+			hdr_size = 28;
+			if (ucode_raw->size < hdr_size) {
+				IWL_ERR(priv, "File size too small!\n");
+				return -EINVAL;
+			}
+			pieces->build = le32_to_cpu(ucode->u.v2.build);
+			pieces->inst_size = le32_to_cpu(ucode->u.v2.inst_size);
+			pieces->data_size = le32_to_cpu(ucode->u.v2.data_size);
+			pieces->init_size = le32_to_cpu(ucode->u.v2.init_size);
+			pieces->init_data_size = le32_to_cpu(ucode->u.v2.init_data_size);
+			pieces->boot_size = le32_to_cpu(ucode->u.v2.boot_size);
+			src = ucode->u.v2.data;
+			break;
+		}
+		/* fall through for 4965 */
+	case 0:
+	case 1:
+	case 2:
+		hdr_size = 24;
+		if (ucode_raw->size < hdr_size) {
+			IWL_ERR(priv, "File size too small!\n");
+			return -EINVAL;
+		}
+		pieces->build = 0;
+		pieces->inst_size = le32_to_cpu(ucode->u.v1.inst_size);
+		pieces->data_size = le32_to_cpu(ucode->u.v1.data_size);
+		pieces->init_size = le32_to_cpu(ucode->u.v1.init_size);
+		pieces->init_data_size = le32_to_cpu(ucode->u.v1.init_data_size);
+		pieces->boot_size = le32_to_cpu(ucode->u.v1.boot_size);
+		src = ucode->u.v1.data;
+		break;
+	}
+
+	/* Verify size of file vs. image size info in file's header */
+	if (ucode_raw->size != hdr_size + pieces->inst_size +
+				pieces->data_size + pieces->init_size +
+				pieces->init_data_size + pieces->boot_size) {
+
+		IWL_ERR(priv,
+			"uCode file size %d does not match expected size\n",
+			(int)ucode_raw->size);
+		return -EINVAL;
+	}
+
+	pieces->inst = src;
+	src += pieces->inst_size;
+	pieces->data = src;
+	src += pieces->data_size;
+	pieces->init = src;
+	src += pieces->init_size;
+	pieces->init_data = src;
+	src += pieces->init_data_size;
+	pieces->boot = src;
+	src += pieces->boot_size;
+
+	return 0;
+}
+
 /**
  * iwl_ucode_callback - callback when firmware was loaded
  *
@@ -1544,14 +1629,15 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context)
 {
 	struct iwl_priv *priv = context;
 	struct iwl_ucode_header *ucode;
+	int err;
+	struct iwlagn_firmware_pieces pieces;
 	const unsigned int api_max = priv->cfg->ucode_api_max;
 	const unsigned int api_min = priv->cfg->ucode_api_min;
-	u8 *src;
-	size_t len;
-	u32 api_ver, build;
-	u32 inst_size, data_size, init_size, init_data_size, boot_size;
-	int err, hdr_size;
+	u32 api_ver;
 	char buildstr[25];
+	u32 build;
+
+	memset(&pieces, 0, sizeof(pieces));
 
 	if (!ucode_raw) {
 		IWL_ERR(priv, "request for firmware file '%s' failed.\n",
@@ -1571,54 +1657,22 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context)
 	/* Data from ucode file:  header followed by uCode images */
 	ucode = (struct iwl_ucode_header *)ucode_raw->data;
 
-	priv->ucode_ver = le32_to_cpu(ucode->ver);
-	api_ver = IWL_UCODE_API(priv->ucode_ver);
+	if (ucode->ver)
+		err = iwlagn_load_legacy_firmware(priv, ucode_raw, &pieces);
+	else
+		err = -EINVAL;
 
-	switch (api_ver) {
-	default:
-		/*
-		 * 4965 doesn't revision the firmware file format
-		 * along with the API version, it always uses v1
-		 * file format.
-		 */
-		if (priv->cfg != &iwl4965_agn_cfg) {
-			hdr_size = 28;
-			if (ucode_raw->size < hdr_size) {
-				IWL_ERR(priv, "File size too small!\n");
-				goto try_again;
-			}
-			build = ucode->u.v2.build;
-			inst_size = ucode->u.v2.inst_size;
-			data_size = ucode->u.v2.data_size;
-			init_size = ucode->u.v2.init_size;
-			init_data_size = ucode->u.v2.init_data_size;
-			boot_size = ucode->u.v2.boot_size;
-			src = ucode->u.v2.data;
-			break;
-		}
-		/* fall through for 4965 */
-	case 0:
-	case 1:
-	case 2:
-		hdr_size = 24;
-		if (ucode_raw->size < hdr_size) {
-			IWL_ERR(priv, "File size too small!\n");
-			goto try_again;
-		}
-		build = 0;
-		inst_size = ucode->u.v1.inst_size;
-		data_size = ucode->u.v1.data_size;
-		init_size = ucode->u.v1.init_size;
-		init_data_size = ucode->u.v1.init_data_size;
-		boot_size = ucode->u.v1.boot_size;
-		src = ucode->u.v1.data;
-		break;
-	}
+	if (err)
+		goto try_again;
 
-	/* api_ver should match the api version forming part of the
-	 * firmware filename ... but we don't check for that and only rely
-	 * on the API version read from firmware header from here on forward */
+	api_ver = IWL_UCODE_API(priv->ucode_ver);
+	build = pieces.build;
 
+	/*
+	 * api_ver should match the api version forming part of the
+	 * firmware filename ... but we don't check for that and only rely
+	 * on the API version read from firmware header from here on forward
+	 */
 	if (api_ver < api_min || api_ver > api_max) {
 		IWL_ERR(priv, "Driver unable to support your firmware API. "
 			  "Driver supports v%u, firmware is v%u.\n",
@@ -1653,75 +1707,69 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context)
 		 IWL_UCODE_SERIAL(priv->ucode_ver),
 		 buildstr);
 
-	IWL_DEBUG_INFO(priv, "f/w package hdr ucode version raw = 0x%x\n",
-		       priv->ucode_ver);
-	IWL_DEBUG_INFO(priv, "f/w package hdr runtime inst size = %u\n",
-		       inst_size);
-	IWL_DEBUG_INFO(priv, "f/w package hdr runtime data size = %u\n",
-		       data_size);
-	IWL_DEBUG_INFO(priv, "f/w package hdr init inst size = %u\n",
-		       init_size);
-	IWL_DEBUG_INFO(priv, "f/w package hdr init data size = %u\n",
-		       init_data_size);
-	IWL_DEBUG_INFO(priv, "f/w package hdr boot inst size = %u\n",
-		       boot_size);
-
 	/*
 	 * For any of the failures below (before allocating pci memory)
 	 * we will try to load a version with a smaller API -- maybe the
 	 * user just got a corrupted version of the latest API.
 	 */
 
-	/* Verify size of file vs. image size info in file's header */
-	if (ucode_raw->size != hdr_size + inst_size + data_size + init_size +
-				init_data_size + boot_size) {
-
-		IWL_DEBUG_INFO(priv,
-			"uCode file size %d does not match expected size\n",
-			(int)ucode_raw->size);
-		goto try_again;
-	}
+	IWL_DEBUG_INFO(priv, "f/w package hdr ucode version raw = 0x%x\n",
+		       priv->ucode_ver);
+	IWL_DEBUG_INFO(priv, "f/w package hdr runtime inst size = %Zd\n",
+		       pieces.inst_size);
+	IWL_DEBUG_INFO(priv, "f/w package hdr runtime data size = %Zd\n",
+		       pieces.data_size);
+	IWL_DEBUG_INFO(priv, "f/w package hdr init inst size = %Zd\n",
+		       pieces.init_size);
+	IWL_DEBUG_INFO(priv, "f/w package hdr init data size = %Zd\n",
+		       pieces.init_data_size);
+	IWL_DEBUG_INFO(priv, "f/w package hdr boot inst size = %Zd\n",
+		       pieces.boot_size);
 
 	/* Verify that uCode images will fit in card's SRAM */
-	if (inst_size > priv->hw_params.max_inst_size) {
-		IWL_DEBUG_INFO(priv, "uCode instr len %d too large to fit in\n",
-			       inst_size);
+	if (pieces.inst_size > priv->hw_params.max_inst_size) {
+		IWL_ERR(priv, "uCode instr len %Zd too large to fit in\n",
+			pieces.inst_size);
 		goto try_again;
 	}
 
-	if (data_size > priv->hw_params.max_data_size) {
-		IWL_DEBUG_INFO(priv, "uCode data len %d too large to fit in\n",
-				data_size);
+	if (pieces.data_size > priv->hw_params.max_data_size) {
+		IWL_ERR(priv, "uCode data len %Zd too large to fit in\n",
+			pieces.data_size);
 		goto try_again;
 	}
-	if (init_size > priv->hw_params.max_inst_size) {
-		IWL_INFO(priv, "uCode init instr len %d too large to fit in\n",
-			init_size);
+
+	if (pieces.init_size > priv->hw_params.max_inst_size) {
+		IWL_ERR(priv, "uCode init instr len %Zd too large to fit in\n",
+			pieces.init_size);
 		goto try_again;
 	}
-	if (init_data_size > priv->hw_params.max_data_size) {
-		IWL_INFO(priv, "uCode init data len %d too large to fit in\n",
-		      init_data_size);
+
+	if (pieces.init_data_size > priv->hw_params.max_data_size) {
+		IWL_ERR(priv, "uCode init data len %Zd too large to fit in\n",
+			pieces.init_data_size);
 		goto try_again;
 	}
-	if (boot_size > priv->hw_params.max_bsm_size) {
-		IWL_INFO(priv, "uCode boot instr len %d too large to fit in\n",
-			boot_size);
+
+	if (pieces.boot_size > priv->hw_params.max_bsm_size) {
+		IWL_ERR(priv, "uCode boot instr len %Zd too large to fit in\n",
+			pieces.boot_size);
 		goto try_again;
 	}
 
+
 	/* Allocate ucode buffers for card's bus-master loading ... */
 
 	/* Runtime instructions and 2 copies of data:
 	 * 1) unmodified from disk
 	 * 2) backup cache for save/restore during power-downs */
-	priv->ucode_code.len = inst_size;
+	priv->ucode_code.len = pieces.inst_size;
 	iwl_alloc_fw_desc(priv->pci_dev, &priv->ucode_code);
 
-	priv->ucode_data.len = data_size;
+	priv->ucode_data.len = pieces.data_size;
 	iwl_alloc_fw_desc(priv->pci_dev, &priv->ucode_data);
 
-	priv->ucode_data_backup.len = data_size;
+	priv->ucode_data_backup.len = pieces.data_size;
 	iwl_alloc_fw_desc(priv->pci_dev, &priv->ucode_data_backup);
 
 	if (!priv->ucode_code.v_addr || !priv->ucode_data.v_addr ||
@@ -1729,11 +1777,11 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context)
 		goto err_pci_alloc;
 
 	/* Initialization instructions and data */
-	if (init_size && init_data_size) {
-		priv->ucode_init.len = init_size;
+	if (pieces.init_size && pieces.init_data_size) {
+		priv->ucode_init.len = pieces.init_size;
 		iwl_alloc_fw_desc(priv->pci_dev, &priv->ucode_init);
 
-		priv->ucode_init_data.len = init_data_size;
+		priv->ucode_init_data.len = pieces.init_data_size;
 		iwl_alloc_fw_desc(priv->pci_dev, &priv->ucode_init_data);
 
 		if (!priv->ucode_init.v_addr || !priv->ucode_init_data.v_addr)
@@ -1741,8 +1789,8 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context)
 	}
 
 	/* Bootstrap (instructions only, no data) */
-	if (boot_size) {
-		priv->ucode_boot.len = boot_size;
+	if (pieces.boot_size) {
+		priv->ucode_boot.len = pieces.boot_size;
 		iwl_alloc_fw_desc(priv->pci_dev, &priv->ucode_boot);
 
 		if (!priv->ucode_boot.v_addr)
@@ -1752,44 +1800,41 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context)
 	/* Copy images into buffers for card's bus-master reads ... */
 
 	/* Runtime instructions (first block of data in file) */
-	len = inst_size;
-	IWL_DEBUG_INFO(priv, "Copying (but not loading) uCode instr len %Zd\n", len);
-	memcpy(priv->ucode_code.v_addr, src, len);
-	src += len;
+	IWL_DEBUG_INFO(priv, "Copying (but not loading) uCode instr len %Zd\n",
+			pieces.inst_size);
+	memcpy(priv->ucode_code.v_addr, pieces.inst, pieces.inst_size);
 
 	IWL_DEBUG_INFO(priv, "uCode instr buf vaddr = 0x%p, paddr = 0x%08x\n",
 		priv->ucode_code.v_addr, (u32)priv->ucode_code.p_addr);
 
-	/* Runtime data (2nd block)
-	 * NOTE:  Copy into backup buffer will be done in iwl_up()  */
-	len = data_size;
-	IWL_DEBUG_INFO(priv, "Copying (but not loading) uCode data len %Zd\n", len);
-	memcpy(priv->ucode_data.v_addr, src, len);
-	memcpy(priv->ucode_data_backup.v_addr, src, len);
-	src += len;
-
-	/* Initialization instructions (3rd block) */
-	if (init_size) {
-		len = init_size;
+	/*
+	 * Runtime data
+	 * NOTE:  Copy into backup buffer will be done in iwl_up()
+	 */
+	IWL_DEBUG_INFO(priv, "Copying (but not loading) uCode data len %Zd\n",
+			pieces.data_size);
+	memcpy(priv->ucode_data.v_addr, pieces.data, pieces.data_size);
+	memcpy(priv->ucode_data_backup.v_addr, pieces.data, pieces.data_size);
+
+	/* Initialization instructions */
+	if (pieces.init_size) {
 		IWL_DEBUG_INFO(priv, "Copying (but not loading) init instr len %Zd\n",
-				len);
-		memcpy(priv->ucode_init.v_addr, src, len);
-		src += len;
+				pieces.init_size);
+		memcpy(priv->ucode_init.v_addr, pieces.init, pieces.init_size);
 	}
 
-	/* Initialization data (4th block) */
-	if (init_data_size) {
-		len = init_data_size;
+	/* Initialization data */
+	if (pieces.init_data_size) {
 		IWL_DEBUG_INFO(priv, "Copying (but not loading) init data len %Zd\n",
-			       len);
-		memcpy(priv->ucode_init_data.v_addr, src, len);
-		src += len;
+			       pieces.init_data_size);
+		memcpy(priv->ucode_init_data.v_addr, pieces.init_data,
+		       pieces.init_data_size);
 	}
 
-	/* Bootstrap instructions (5th block) */
-	len = boot_size;
-	IWL_DEBUG_INFO(priv, "Copying (but not loading) boot instr len %Zd\n", len);
-	memcpy(priv->ucode_boot.v_addr, src, len);
+	/* Bootstrap instructions */
+	IWL_DEBUG_INFO(priv, "Copying (but not loading) boot instr len %Zd\n",
+			pieces.boot_size);
+	memcpy(priv->ucode_boot.v_addr, pieces.boot, pieces.boot_size);
 
 	/**************************************************
 	 * This is still part of probe() in a sense...
-- 
1.6.3.3

--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [Linux Host AP]     [ATH6KL]     [Linux Bluetooth]     [Linux Netdev]     [Kernel Newbies]     [Linux Kernel]     [IDE]     [Security]     [Git]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux ATA RAID]     [Samba]     [Device Mapper]
  Powered by Linux