Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 6dfa8d01 authored by David Spinadel's avatar David Spinadel Committed by John W. Linville
Browse files

iwlwifi: change struct iwl_fw



Change iwl_fw struct to hold an array of fw_img instead of
three separated instances.

Change fw_img to hold an array of fw_desc instead of two
separate descriptors for instructions and data.

Change load_given_ucode, load_section, verification functions
etc. to support this structure.

Signed-off-by: default avatarDavid Spinadel <david.spinadel@intel.com>
Signed-off-by: default avatarWey-Yi Guy <wey-yi.w.guy@intel.com>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent ed8c8365
Loading
Loading
Loading
Loading
+5 −12
Original line number Original line Diff line number Diff line
@@ -230,6 +230,7 @@ static ssize_t iwl_dbgfs_sram_read(struct file *file,
	int pos = 0;
	int pos = 0;
	int sram;
	int sram;
	struct iwl_priv *priv = file->private_data;
	struct iwl_priv *priv = file->private_data;
	const struct fw_img *img;
	size_t bufsz;
	size_t bufsz;


	/* default is to dump the entire data segment */
	/* default is to dump the entire data segment */
@@ -239,17 +240,8 @@ static ssize_t iwl_dbgfs_sram_read(struct file *file,
			IWL_ERR(priv, "No uCode has been loadded.\n");
			IWL_ERR(priv, "No uCode has been loadded.\n");
			return -EINVAL;
			return -EINVAL;
		}
		}
		if (priv->shrd->ucode_type == IWL_UCODE_INIT) {
		img = &priv->fw->img[priv->shrd->ucode_type];
			priv->dbgfs_sram_len = priv->fw->ucode_init.data.len;
		priv->dbgfs_sram_len = img->sec[IWL_UCODE_SECTION_DATA].len;
		} else if (priv->shrd->ucode_type == IWL_UCODE_REGULAR) {
			priv->dbgfs_sram_len = priv->fw->ucode_rt.data.len;
		} else if (priv->shrd->ucode_type == IWL_UCODE_WOWLAN) {
			priv->dbgfs_sram_len = priv->fw->ucode_wowlan.data.len;
		} else {
			IWL_ERR(priv, "Unsupported type of uCode loaded?"
					" that shouldn't happen.\n");
			return -EINVAL;
		}
	}
	}
	len = priv->dbgfs_sram_len;
	len = priv->dbgfs_sram_len;


@@ -346,13 +338,14 @@ static ssize_t iwl_dbgfs_wowlan_sram_read(struct file *file,
					  size_t count, loff_t *ppos)
					  size_t count, loff_t *ppos)
{
{
	struct iwl_priv *priv = file->private_data;
	struct iwl_priv *priv = file->private_data;
	const struct fw_img *img = &priv->fw->img[IWL_UCODE_WOWLAN];


	if (!priv->wowlan_sram)
	if (!priv->wowlan_sram)
		return -ENODATA;
		return -ENODATA;


	return simple_read_from_buffer(user_buf, count, ppos,
	return simple_read_from_buffer(user_buf, count, ppos,
				       priv->wowlan_sram,
				       priv->wowlan_sram,
				       priv->fw->ucode_wowlan.data.len);
				       img->sec[IWL_UCODE_SECTION_DATA].len);
}
}
static ssize_t iwl_dbgfs_stations_read(struct file *file, char __user *user_buf,
static ssize_t iwl_dbgfs_stations_read(struct file *file, char __user *user_buf,
					size_t count, loff_t *ppos)
					size_t count, loff_t *ppos)
+76 −65
Original line number Original line Diff line number Diff line
@@ -118,15 +118,16 @@ static void iwl_free_fw_desc(struct iwl_drv *drv, struct fw_desc *desc)


static void iwl_free_fw_img(struct iwl_drv *drv, struct fw_img *img)
static void iwl_free_fw_img(struct iwl_drv *drv, struct fw_img *img)
{
{
	iwl_free_fw_desc(drv, &img->code);
	int i;
	iwl_free_fw_desc(drv, &img->data);
	for (i = 0; i < IWL_UCODE_SECTION_MAX; i++)
		iwl_free_fw_desc(drv, &img->sec[i]);
}
}


static void iwl_dealloc_ucode(struct iwl_drv *drv)
static void iwl_dealloc_ucode(struct iwl_drv *drv)
{
{
	iwl_free_fw_img(drv, &drv->fw.ucode_rt);
	int i;
	iwl_free_fw_img(drv, &drv->fw.ucode_init);
	for (i = 0; i < IWL_UCODE_TYPE_MAX; i++)
	iwl_free_fw_img(drv, &drv->fw.ucode_wowlan);
		iwl_free_fw_img(drv, drv->fw.img + i);
}
}


static int iwl_alloc_fw_desc(struct iwl_drv *drv, struct fw_desc *desc,
static int iwl_alloc_fw_desc(struct iwl_drv *drv, struct fw_desc *desc,
@@ -189,22 +190,8 @@ static int iwl_request_firmware(struct iwl_drv *drv, bool first)
				       GFP_KERNEL, drv, iwl_ucode_callback);
				       GFP_KERNEL, drv, iwl_ucode_callback);
}
}


/*
 * enumeration of ucode section.
 * This enumeration is used for legacy tlv style (before 16.0 uCode).
 */
enum iwl_ucode_sec {
	IWL_UCODE_SECTION_INST,
	IWL_UCODE_SECTION_DATA,
};
/*
 * For 16.0 uCode and above, there is no differentiation between section,
 * just an offset to the HW address.
 */
#define UCODE_SECTION_MAX 4

struct fw_img_parsing {
struct fw_img_parsing {
	struct fw_sec sec[UCODE_SECTION_MAX];
	struct fw_sec sec[IWL_UCODE_SECTION_MAX];
	int sec_counter;
	int sec_counter;
};
};


@@ -691,6 +678,71 @@ static int iwl_parse_tlv_firmware(struct iwl_drv *drv,
	return -EINVAL;
	return -EINVAL;
}
}


static int alloc_pci_desc(struct iwl_drv *drv,
			  struct iwl_firmware_pieces *pieces,
			  enum iwl_ucode_type type)
{
	int i;
	for (i = 0;
	     i < IWL_UCODE_SECTION_MAX && get_sec_size(pieces, type, i);
	     i++)
		if (iwl_alloc_fw_desc(drv, &(drv->fw.img[type].sec[i]),
						get_sec(pieces, type, i)))
			return -1;
	return 0;
}

static int validate_sec_sizes(struct iwl_drv *drv,
			      struct iwl_firmware_pieces *pieces,
			      const struct iwl_cfg *cfg)
{
	IWL_DEBUG_INFO(drv, "f/w package hdr runtime inst size = %Zd\n",
		get_sec_size(pieces, IWL_UCODE_REGULAR,
			     IWL_UCODE_SECTION_INST));
	IWL_DEBUG_INFO(drv, "f/w package hdr runtime data size = %Zd\n",
		get_sec_size(pieces, IWL_UCODE_REGULAR,
			     IWL_UCODE_SECTION_DATA));
	IWL_DEBUG_INFO(drv, "f/w package hdr init inst size = %Zd\n",
		get_sec_size(pieces, IWL_UCODE_INIT, IWL_UCODE_SECTION_INST));
	IWL_DEBUG_INFO(drv, "f/w package hdr init data size = %Zd\n",
		get_sec_size(pieces, IWL_UCODE_INIT, IWL_UCODE_SECTION_DATA));

	/* Verify that uCode images will fit in card's SRAM. */
	if (get_sec_size(pieces, IWL_UCODE_REGULAR, IWL_UCODE_SECTION_INST) >
							cfg->max_inst_size) {
		IWL_ERR(drv, "uCode instr len %Zd too large to fit in\n",
			get_sec_size(pieces, IWL_UCODE_REGULAR,
						IWL_UCODE_SECTION_INST));
		return -1;
	}

	if (get_sec_size(pieces, IWL_UCODE_REGULAR, IWL_UCODE_SECTION_DATA) >
							cfg->max_data_size) {
		IWL_ERR(drv, "uCode data len %Zd too large to fit in\n",
			get_sec_size(pieces, IWL_UCODE_REGULAR,
						IWL_UCODE_SECTION_DATA));
		return -1;
	}

	 if (get_sec_size(pieces, IWL_UCODE_INIT, IWL_UCODE_SECTION_INST) >
							cfg->max_inst_size) {
		IWL_ERR(drv, "uCode init instr len %Zd too large to fit in\n",
			get_sec_size(pieces, IWL_UCODE_INIT,
						IWL_UCODE_SECTION_INST));
		return -1;
	}

	if (get_sec_size(pieces, IWL_UCODE_INIT, IWL_UCODE_SECTION_DATA) >
							cfg->max_data_size) {
		IWL_ERR(drv, "uCode init data len %Zd too large to fit in\n",
			get_sec_size(pieces, IWL_UCODE_REGULAR,
						IWL_UCODE_SECTION_DATA));
		return -1;
	}
	return 0;
}


/**
/**
 * iwl_ucode_callback - callback when firmware was loaded
 * iwl_ucode_callback - callback when firmware was loaded
 *
 *
@@ -709,6 +761,7 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context)
	unsigned int api_ok = cfg->ucode_api_ok;
	unsigned int api_ok = cfg->ucode_api_ok;
	const unsigned int api_min = cfg->ucode_api_min;
	const unsigned int api_min = cfg->ucode_api_min;
	u32 api_ver;
	u32 api_ver;
	int i;


	fw->ucode_capa.max_probe_length = 200;
	fw->ucode_capa.max_probe_length = 200;
	fw->ucode_capa.standard_phy_calibration_size =
	fw->ucode_capa.standard_phy_calibration_size =
@@ -817,60 +870,18 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context)
		goto try_again;
		goto try_again;
	}
	}


	 if (get_sec_size(&pieces, IWL_UCODE_INIT, IWL_UCODE_SECTION_INST) >
	if (validate_sec_sizes(drv, &pieces, cfg))
							cfg->max_inst_size) {
		IWL_ERR(drv, "uCode init instr len %Zd too large to fit in\n",
			get_sec_size(&pieces, IWL_UCODE_INIT,
				     IWL_UCODE_SECTION_INST));
		goto try_again;
		goto try_again;
	}

	if (get_sec_size(&pieces, IWL_UCODE_INIT, IWL_UCODE_SECTION_DATA) >
							cfg->max_data_size) {
		IWL_ERR(drv, "uCode init data len %Zd too large to fit in\n",
			get_sec_size(&pieces, IWL_UCODE_REGULAR,
				     IWL_UCODE_SECTION_DATA));
		goto try_again;
	}


	/* Allocate ucode buffers for card's bus-master loading ... */
	/* Allocate ucode buffers for card's bus-master loading ... */


	/* Runtime instructions and 2 copies of data:
	/* Runtime instructions and 2 copies of data:
	 * 1) unmodified from disk
	 * 1) unmodified from disk
	 * 2) backup cache for save/restore during power-downs */
	 * 2) backup cache for save/restore during power-downs */
	if (iwl_alloc_fw_desc(drv, &drv->fw.ucode_rt.code,
	for (i = 0; i < IWL_UCODE_TYPE_MAX; i++)
		get_sec(&pieces, IWL_UCODE_REGULAR, IWL_UCODE_SECTION_INST)))
		if (alloc_pci_desc(drv, &pieces, i))
		goto err_pci_alloc;
	if (iwl_alloc_fw_desc(drv, &drv->fw.ucode_rt.data,
		get_sec(&pieces, IWL_UCODE_REGULAR, IWL_UCODE_SECTION_DATA)))
			goto err_pci_alloc;
			goto err_pci_alloc;


	/* Initialization instructions and data */
	if (get_sec_size(&pieces, IWL_UCODE_INIT, IWL_UCODE_SECTION_INST) &&
	    get_sec_size(&pieces, IWL_UCODE_INIT, IWL_UCODE_SECTION_DATA)) {
		if (iwl_alloc_fw_desc(drv, &drv->fw.ucode_init.code,
			get_sec(&pieces, IWL_UCODE_INIT,
						IWL_UCODE_SECTION_INST)))
			goto err_pci_alloc;
		if (iwl_alloc_fw_desc(drv, &drv->fw.ucode_init.data,
			get_sec(&pieces, IWL_UCODE_INIT,
						IWL_UCODE_SECTION_DATA)))
			goto err_pci_alloc;
	}

	/* WoWLAN instructions and data */
	if (get_sec_size(&pieces, IWL_UCODE_WOWLAN, IWL_UCODE_SECTION_INST) &&
	    get_sec_size(&pieces, IWL_UCODE_WOWLAN, IWL_UCODE_SECTION_DATA)) {
		if (iwl_alloc_fw_desc(drv, &drv->fw.ucode_wowlan.code,
			get_sec(&pieces, IWL_UCODE_WOWLAN,
						IWL_UCODE_SECTION_INST)))
			goto err_pci_alloc;
		if (iwl_alloc_fw_desc(drv, &drv->fw.ucode_wowlan.data,
			get_sec(&pieces, IWL_UCODE_WOWLAN,
						IWL_UCODE_SECTION_DATA)))
			goto err_pci_alloc;
	}

	/* Now that we can no longer fail, copy information */
	/* Now that we can no longer fail, copy information */


	/*
	/*
+17 −8
Original line number Original line Diff line number Diff line
@@ -101,6 +101,20 @@ enum iwl_ucode_type {
	IWL_UCODE_TYPE_MAX,
	IWL_UCODE_TYPE_MAX,
};
};


/*
 * enumeration of ucode section.
 * This enumeration is used for legacy tlv style (before 16.0 uCode).
 */
enum iwl_ucode_sec {
	IWL_UCODE_SECTION_INST,
	IWL_UCODE_SECTION_DATA,
};
/*
 * For 16.0 uCode and above, there is no differentiation between sections,
 * just an offset to the HW address.
 */
#define IWL_UCODE_SECTION_MAX 4

struct iwl_ucode_capabilities {
struct iwl_ucode_capabilities {
	u32 max_probe_length;
	u32 max_probe_length;
	u32 standard_phy_calibration_size;
	u32 standard_phy_calibration_size;
@@ -116,8 +130,7 @@ struct fw_desc {
};
};


struct fw_img {
struct fw_img {
	struct fw_desc code;	/* firmware code image */
	struct fw_desc sec[IWL_UCODE_SECTION_MAX];
	struct fw_desc data;	/* firmware data image */
};
};


/* uCode version contains 4 values: Major/Minor/API/Serial */
/* uCode version contains 4 values: Major/Minor/API/Serial */
@@ -131,9 +144,7 @@ struct fw_img {
 *
 *
 * @ucode_ver: ucode version from the ucode file
 * @ucode_ver: ucode version from the ucode file
 * @fw_version: firmware version string
 * @fw_version: firmware version string
 * @ucode_rt: run time ucode image
 * @img: ucode image like ucode_rt, ucode_init, ucode_wowlan.
 * @ucode_init: init ucode image
 * @ucode_wowlan: wake on wireless ucode image (optional)
 * @ucode_capa: capabilities parsed from the ucode file.
 * @ucode_capa: capabilities parsed from the ucode file.
 * @enhance_sensitivity_table: device can do enhanced sensitivity.
 * @enhance_sensitivity_table: device can do enhanced sensitivity.
 * @init_evtlog_ptr: event log offset for init ucode.
 * @init_evtlog_ptr: event log offset for init ucode.
@@ -149,9 +160,7 @@ struct iwl_fw {
	char fw_version[ETHTOOL_BUSINFO_LEN];
	char fw_version[ETHTOOL_BUSINFO_LEN];


	/* ucode images */
	/* ucode images */
	struct fw_img ucode_rt;
	struct fw_img img[IWL_UCODE_TYPE_MAX];
	struct fw_img ucode_init;
	struct fw_img ucode_wowlan;


	struct iwl_ucode_capabilities ucode_capa;
	struct iwl_ucode_capabilities ucode_capa;
	bool enhance_sensitivity_table;
	bool enhance_sensitivity_table;
+9 −6
Original line number Original line Diff line number Diff line
@@ -196,7 +196,7 @@ int iwlagn_mac_setup_register(struct iwl_priv *priv,
			    WIPHY_FLAG_DISABLE_BEACON_HINTS |
			    WIPHY_FLAG_DISABLE_BEACON_HINTS |
			    WIPHY_FLAG_IBSS_RSN;
			    WIPHY_FLAG_IBSS_RSN;


	if (priv->fw->ucode_wowlan.code.len &&
	if (priv->fw->img[IWL_UCODE_WOWLAN].sec[0].len &&
	    trans(priv)->ops->wowlan_suspend &&
	    trans(priv)->ops->wowlan_suspend &&
	    device_can_wakeup(trans(priv)->dev)) {
	    device_can_wakeup(trans(priv)->dev)) {
		hw->wiphy->wowlan.flags = WIPHY_WOWLAN_MAGIC_PKT |
		hw->wiphy->wowlan.flags = WIPHY_WOWLAN_MAGIC_PKT |
@@ -437,6 +437,7 @@ static int iwlagn_mac_resume(struct ieee80211_hw *hw)
	unsigned long flags;
	unsigned long flags;
	u32 base, status = 0xffffffff;
	u32 base, status = 0xffffffff;
	int ret = -EIO;
	int ret = -EIO;
	const struct fw_img *img;


	IWL_DEBUG_MAC80211(priv, "enter\n");
	IWL_DEBUG_MAC80211(priv, "enter\n");
	mutex_lock(&priv->mutex);
	mutex_lock(&priv->mutex);
@@ -457,16 +458,18 @@ static int iwlagn_mac_resume(struct ieee80211_hw *hw)


#ifdef CONFIG_IWLWIFI_DEBUGFS
#ifdef CONFIG_IWLWIFI_DEBUGFS
		if (ret == 0) {
		if (ret == 0) {
			if (!priv->wowlan_sram)
			img = &(priv->fw->img[IWL_UCODE_WOWLAN]);
			if (!priv->wowlan_sram) {
				priv->wowlan_sram =
				priv->wowlan_sram =
					kzalloc(priv->fw->ucode_wowlan.data.len,
				   kzalloc(img->sec[IWL_UCODE_SECTION_DATA].len,
						GFP_KERNEL);
						GFP_KERNEL);
			}


			if (priv->wowlan_sram)
			if (priv->wowlan_sram)
				_iwl_read_targ_mem_words(
				_iwl_read_targ_mem_words(
				      trans(priv), 0x800000,
				      trans(priv), 0x800000,
				      priv->wowlan_sram,
				      priv->wowlan_sram,
					priv->fw->ucode_wowlan.data.len / 4);
				      img->sec[IWL_UCODE_SECTION_DATA].len / 4);
		}
		}
#endif
#endif
	}
	}
+4 −17
Original line number Original line Diff line number Diff line
@@ -466,6 +466,7 @@ static int iwl_testmode_driver(struct ieee80211_hw *hw, struct nlattr **tb)
	unsigned char *rsp_data_ptr = NULL;
	unsigned char *rsp_data_ptr = NULL;
	int status = 0, rsp_data_len = 0;
	int status = 0, rsp_data_len = 0;
	u32 devid, inst_size = 0, data_size = 0;
	u32 devid, inst_size = 0, data_size = 0;
	const struct fw_img *img;


	switch (nla_get_u32(tb[IWL_TM_ATTR_COMMAND])) {
	switch (nla_get_u32(tb[IWL_TM_ATTR_COMMAND])) {
	case IWL_TM_CMD_APP2DEV_GET_DEVICENAME:
	case IWL_TM_CMD_APP2DEV_GET_DEVICENAME:
@@ -597,23 +598,9 @@ static int iwl_testmode_driver(struct ieee80211_hw *hw, struct nlattr **tb)
			IWL_ERR(priv, "No uCode has not been loaded\n");
			IWL_ERR(priv, "No uCode has not been loaded\n");
			return -EINVAL;
			return -EINVAL;
		} else {
		} else {
			switch (priv->shrd->ucode_type) {
			img = &priv->fw->img[priv->shrd->ucode_type];
			case IWL_UCODE_REGULAR:
			inst_size = img->sec[IWL_UCODE_SECTION_INST].len;
				inst_size = priv->fw->ucode_rt.code.len;
			data_size = img->sec[IWL_UCODE_SECTION_DATA].len;
				data_size = priv->fw->ucode_rt.data.len;
				break;
			case IWL_UCODE_INIT:
				inst_size = priv->fw->ucode_init.code.len;
				data_size = priv->fw->ucode_init.data.len;
				break;
			case IWL_UCODE_WOWLAN:
				inst_size = priv->fw->ucode_wowlan.code.len;
				data_size = priv->fw->ucode_wowlan.data.len;
				break;
			default:
				IWL_ERR(priv, "Unsupported uCode type\n");
				break;
			}
		}
		}
		NLA_PUT_U32(skb, IWL_TM_ATTR_FW_TYPE, priv->shrd->ucode_type);
		NLA_PUT_U32(skb, IWL_TM_ATTR_FW_TYPE, priv->shrd->ucode_type);
		NLA_PUT_U32(skb, IWL_TM_ATTR_FW_INST_SIZE, inst_size);
		NLA_PUT_U32(skb, IWL_TM_ATTR_FW_INST_SIZE, inst_size);
Loading