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

Commit 57aab75a authored by Tomas Winkler's avatar Tomas Winkler Committed by John W. Linville
Browse files

iwlwifi: generalize iwlwifi init flow



This patch creates handlers to support
iwlwifi init flow for multiple HWs

Signed-off-by: default avatarTomas Winkler <tomas.winkler@intel.com>
Signed-off-by: default avatarRon Rindjunsky <ron.rindjunsky@intel.com>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent b454048c
Loading
Loading
Loading
Loading
+149 −0
Original line number Original line Diff line number Diff line
@@ -114,6 +114,151 @@ static const u16 default_tid_to_tx_fifo[] = {


#endif	/*CONFIG_IWL4965_HT */
#endif	/*CONFIG_IWL4965_HT */


/* check contents of special bootstrap uCode SRAM */
static int iwl4965_verify_bsm(struct iwl_priv *priv)
{
	__le32 *image = priv->ucode_boot.v_addr;
	u32 len = priv->ucode_boot.len;
	u32 reg;
	u32 val;

	IWL_DEBUG_INFO("Begin verify bsm\n");

	/* verify BSM SRAM contents */
	val = iwl_read_prph(priv, BSM_WR_DWCOUNT_REG);
	for (reg = BSM_SRAM_LOWER_BOUND;
	     reg < BSM_SRAM_LOWER_BOUND + len;
	     reg += sizeof(u32), image++) {
		val = iwl_read_prph(priv, reg);
		if (val != le32_to_cpu(*image)) {
			IWL_ERROR("BSM uCode verification failed at "
				  "addr 0x%08X+%u (of %u), is 0x%x, s/b 0x%x\n",
				  BSM_SRAM_LOWER_BOUND,
				  reg - BSM_SRAM_LOWER_BOUND, len,
				  val, le32_to_cpu(*image));
			return -EIO;
		}
	}

	IWL_DEBUG_INFO("BSM bootstrap uCode image OK\n");

	return 0;
}

/**
 * iwl4965_load_bsm - Load bootstrap instructions
 *
 * BSM operation:
 *
 * The Bootstrap State Machine (BSM) stores a short bootstrap uCode program
 * in special SRAM that does not power down during RFKILL.  When powering back
 * up after power-saving sleeps (or during initial uCode load), the BSM loads
 * the bootstrap program into the on-board processor, and starts it.
 *
 * The bootstrap program loads (via DMA) instructions and data for a new
 * program from host DRAM locations indicated by the host driver in the
 * BSM_DRAM_* registers.  Once the new program is loaded, it starts
 * automatically.
 *
 * When initializing the NIC, the host driver points the BSM to the
 * "initialize" uCode image.  This uCode sets up some internal data, then
 * notifies host via "initialize alive" that it is complete.
 *
 * The host then replaces the BSM_DRAM_* pointer values to point to the
 * normal runtime uCode instructions and a backup uCode data cache buffer
 * (filled initially with starting data values for the on-board processor),
 * then triggers the "initialize" uCode to load and launch the runtime uCode,
 * which begins normal operation.
 *
 * When doing a power-save shutdown, runtime uCode saves data SRAM into
 * the backup data cache in DRAM before SRAM is powered down.
 *
 * When powering back up, the BSM loads the bootstrap program.  This reloads
 * the runtime uCode instructions and the backup data cache into SRAM,
 * and re-launches the runtime uCode from where it left off.
 */
static int iwl4965_load_bsm(struct iwl_priv *priv)
{
	__le32 *image = priv->ucode_boot.v_addr;
	u32 len = priv->ucode_boot.len;
	dma_addr_t pinst;
	dma_addr_t pdata;
	u32 inst_len;
	u32 data_len;
	int i;
	u32 done;
	u32 reg_offset;
	int ret;

	IWL_DEBUG_INFO("Begin load bsm\n");

	/* make sure bootstrap program is no larger than BSM's SRAM size */
	if (len > IWL_MAX_BSM_SIZE)
		return -EINVAL;

	/* Tell bootstrap uCode where to find the "Initialize" uCode
	 *   in host DRAM ... host DRAM physical address bits 35:4 for 4965.
	 * NOTE:  iwl4965_initialize_alive_start() will replace these values,
	 *        after the "initialize" uCode has run, to point to
	 *        runtime/protocol instructions and backup data cache. */
	pinst = priv->ucode_init.p_addr >> 4;
	pdata = priv->ucode_init_data.p_addr >> 4;
	inst_len = priv->ucode_init.len;
	data_len = priv->ucode_init_data.len;

	ret = iwl_grab_nic_access(priv);
	if (ret)
		return ret;

	iwl_write_prph(priv, BSM_DRAM_INST_PTR_REG, pinst);
	iwl_write_prph(priv, BSM_DRAM_DATA_PTR_REG, pdata);
	iwl_write_prph(priv, BSM_DRAM_INST_BYTECOUNT_REG, inst_len);
	iwl_write_prph(priv, BSM_DRAM_DATA_BYTECOUNT_REG, data_len);

	/* Fill BSM memory with bootstrap instructions */
	for (reg_offset = BSM_SRAM_LOWER_BOUND;
	     reg_offset < BSM_SRAM_LOWER_BOUND + len;
	     reg_offset += sizeof(u32), image++)
		_iwl_write_prph(priv, reg_offset, le32_to_cpu(*image));

	ret = iwl4965_verify_bsm(priv);
	if (ret) {
		iwl_release_nic_access(priv);
		return ret;
	}

	/* Tell BSM to copy from BSM SRAM into instruction SRAM, when asked */
	iwl_write_prph(priv, BSM_WR_MEM_SRC_REG, 0x0);
	iwl_write_prph(priv, BSM_WR_MEM_DST_REG, RTC_INST_LOWER_BOUND);
	iwl_write_prph(priv, BSM_WR_DWCOUNT_REG, len / sizeof(u32));

	/* Load bootstrap code into instruction SRAM now,
	 *   to prepare to load "initialize" uCode */
	iwl_write_prph(priv, BSM_WR_CTRL_REG, BSM_WR_CTRL_REG_BIT_START);

	/* Wait for load of bootstrap uCode to finish */
	for (i = 0; i < 100; i++) {
		done = iwl_read_prph(priv, BSM_WR_CTRL_REG);
		if (!(done & BSM_WR_CTRL_REG_BIT_START))
			break;
		udelay(10);
	}
	if (i < 100)
		IWL_DEBUG_INFO("BSM write complete, poll %d iterations\n", i);
	else {
		IWL_ERROR("BSM write did not complete!\n");
		return -EIO;
	}

	/* Enable future boot loads whenever power management unit triggers it
	 *   (e.g. when powering back up after power-save shutdown) */
	iwl_write_prph(priv, BSM_WR_CTRL_REG, BSM_WR_CTRL_REG_BIT_START_EN);

	iwl_release_nic_access(priv);

	return 0;
}

static int iwl4965_init_drv(struct iwl_priv *priv)
static int iwl4965_init_drv(struct iwl_priv *priv)
{
{
	int ret;
	int ret;
@@ -4789,6 +4934,10 @@ static struct iwl_hcmd_utils_ops iwl4965_hcmd_utils = {


static struct iwl_lib_ops iwl4965_lib = {
static struct iwl_lib_ops iwl4965_lib = {
	.init_drv = iwl4965_init_drv,
	.init_drv = iwl4965_init_drv,
	.hw_nic_init = iwl4965_hw_nic_init,
	.is_valid_rtc_data_addr = iwl4965_hw_valid_rtc_data_addr,
	.alive_notify = iwl4965_alive_notify,
	.load_ucode = iwl4965_load_bsm,
	.eeprom_ops = {
	.eeprom_ops = {
		.verify_signature  = iwlcore_eeprom_verify_signature,
		.verify_signature  = iwlcore_eeprom_verify_signature,
		.acquire_semaphore = iwlcore_eeprom_acquire_semaphore,
		.acquire_semaphore = iwlcore_eeprom_acquire_semaphore,
+10 −1
Original line number Original line Diff line number Diff line
@@ -89,9 +89,18 @@ struct iwl_hcmd_utils_ops {
struct iwl_lib_ops {
struct iwl_lib_ops {
	/* iwlwifi driver (priv) init */
	/* iwlwifi driver (priv) init */
	int (*init_drv)(struct iwl_priv *priv);
	int (*init_drv)(struct iwl_priv *priv);
	/* nic init */
	int (*hw_nic_init)(struct iwl_priv *priv);
	/* alive notification */
	int (*alive_notify)(struct iwl_priv *priv);
	/* check validity of rtc data address */
	int (*is_valid_rtc_data_addr)(u32 addr);
	/* 1st ucode load */
	int (*load_ucode)(struct iwl_priv *priv);
	/* rfkill */
	void (*radio_kill_sw)(struct iwl_priv *priv, int disable_radio);
	/* eeprom operations (as defined in iwl-eeprom.h) */
	/* eeprom operations (as defined in iwl-eeprom.h) */
	struct iwl_eeprom_ops eeprom_ops;
	struct iwl_eeprom_ops eeprom_ops;
	void (*radio_kill_sw)(struct iwl_priv *priv, int disable_radio);
};
};


struct iwl_ops {
struct iwl_ops {
+15 −164
Original line number Original line Diff line number Diff line
@@ -4305,7 +4305,7 @@ static void iwl4965_dump_nic_error_log(struct iwl_priv *priv)


	base = le32_to_cpu(priv->card_alive.error_event_table_ptr);
	base = le32_to_cpu(priv->card_alive.error_event_table_ptr);


	if (!iwl4965_hw_valid_rtc_data_addr(base)) {
	if (!priv->cfg->ops->lib->is_valid_rtc_data_addr(base)) {
		IWL_ERROR("Not valid error log pointer 0x%08X\n", base);
		IWL_ERROR("Not valid error log pointer 0x%08X\n", base);
		return;
		return;
	}
	}
@@ -4400,7 +4400,7 @@ static void iwl4965_dump_nic_event_log(struct iwl_priv *priv)
	u32 size;       /* # entries that we'll print */
	u32 size;       /* # entries that we'll print */


	base = le32_to_cpu(priv->card_alive.log_event_table_ptr);
	base = le32_to_cpu(priv->card_alive.log_event_table_ptr);
	if (!iwl4965_hw_valid_rtc_data_addr(base)) {
	if (!priv->cfg->ops->lib->is_valid_rtc_data_addr(base)) {
		IWL_ERROR("Invalid event log pointer 0x%08X\n", base);
		IWL_ERROR("Invalid event log pointer 0x%08X\n", base);
		return;
		return;
	}
	}
@@ -5175,156 +5175,6 @@ static int iwl4965_verify_ucode(struct iwl_priv *priv)
	return rc;
	return rc;
}
}



/* check contents of special bootstrap uCode SRAM */
static int iwl4965_verify_bsm(struct iwl_priv *priv)
{
	__le32 *image = priv->ucode_boot.v_addr;
	u32 len = priv->ucode_boot.len;
	u32 reg;
	u32 val;

	IWL_DEBUG_INFO("Begin verify bsm\n");

	/* verify BSM SRAM contents */
	val = iwl_read_prph(priv, BSM_WR_DWCOUNT_REG);
	for (reg = BSM_SRAM_LOWER_BOUND;
	     reg < BSM_SRAM_LOWER_BOUND + len;
	     reg += sizeof(u32), image ++) {
		val = iwl_read_prph(priv, reg);
		if (val != le32_to_cpu(*image)) {
			IWL_ERROR("BSM uCode verification failed at "
				  "addr 0x%08X+%u (of %u), is 0x%x, s/b 0x%x\n",
				  BSM_SRAM_LOWER_BOUND,
				  reg - BSM_SRAM_LOWER_BOUND, len,
				  val, le32_to_cpu(*image));
			return -EIO;
		}
	}

	IWL_DEBUG_INFO("BSM bootstrap uCode image OK\n");

	return 0;
}

/**
 * iwl4965_load_bsm - Load bootstrap instructions
 *
 * BSM operation:
 *
 * The Bootstrap State Machine (BSM) stores a short bootstrap uCode program
 * in special SRAM that does not power down during RFKILL.  When powering back
 * up after power-saving sleeps (or during initial uCode load), the BSM loads
 * the bootstrap program into the on-board processor, and starts it.
 *
 * The bootstrap program loads (via DMA) instructions and data for a new
 * program from host DRAM locations indicated by the host driver in the
 * BSM_DRAM_* registers.  Once the new program is loaded, it starts
 * automatically.
 *
 * When initializing the NIC, the host driver points the BSM to the
 * "initialize" uCode image.  This uCode sets up some internal data, then
 * notifies host via "initialize alive" that it is complete.
 *
 * The host then replaces the BSM_DRAM_* pointer values to point to the
 * normal runtime uCode instructions and a backup uCode data cache buffer
 * (filled initially with starting data values for the on-board processor),
 * then triggers the "initialize" uCode to load and launch the runtime uCode,
 * which begins normal operation.
 *
 * When doing a power-save shutdown, runtime uCode saves data SRAM into
 * the backup data cache in DRAM before SRAM is powered down.
 *
 * When powering back up, the BSM loads the bootstrap program.  This reloads
 * the runtime uCode instructions and the backup data cache into SRAM,
 * and re-launches the runtime uCode from where it left off.
 */
static int iwl4965_load_bsm(struct iwl_priv *priv)
{
	__le32 *image = priv->ucode_boot.v_addr;
	u32 len = priv->ucode_boot.len;
	dma_addr_t pinst;
	dma_addr_t pdata;
	u32 inst_len;
	u32 data_len;
	int rc;
	int i;
	u32 done;
	u32 reg_offset;

	IWL_DEBUG_INFO("Begin load bsm\n");

	/* make sure bootstrap program is no larger than BSM's SRAM size */
	if (len > IWL_MAX_BSM_SIZE)
		return -EINVAL;

	/* Tell bootstrap uCode where to find the "Initialize" uCode
	 *   in host DRAM ... host DRAM physical address bits 35:4 for 4965.
	 * NOTE:  iwl4965_initialize_alive_start() will replace these values,
	 *        after the "initialize" uCode has run, to point to
	 *        runtime/protocol instructions and backup data cache. */
	pinst = priv->ucode_init.p_addr >> 4;
	pdata = priv->ucode_init_data.p_addr >> 4;
	inst_len = priv->ucode_init.len;
	data_len = priv->ucode_init_data.len;

	rc = iwl_grab_nic_access(priv);
	if (rc)
		return rc;

	iwl_write_prph(priv, BSM_DRAM_INST_PTR_REG, pinst);
	iwl_write_prph(priv, BSM_DRAM_DATA_PTR_REG, pdata);
	iwl_write_prph(priv, BSM_DRAM_INST_BYTECOUNT_REG, inst_len);
	iwl_write_prph(priv, BSM_DRAM_DATA_BYTECOUNT_REG, data_len);

	/* Fill BSM memory with bootstrap instructions */
	for (reg_offset = BSM_SRAM_LOWER_BOUND;
	     reg_offset < BSM_SRAM_LOWER_BOUND + len;
	     reg_offset += sizeof(u32), image++)
		_iwl_write_prph(priv, reg_offset,
					  le32_to_cpu(*image));

	rc = iwl4965_verify_bsm(priv);
	if (rc) {
		iwl_release_nic_access(priv);
		return rc;
	}

	/* Tell BSM to copy from BSM SRAM into instruction SRAM, when asked */
	iwl_write_prph(priv, BSM_WR_MEM_SRC_REG, 0x0);
	iwl_write_prph(priv, BSM_WR_MEM_DST_REG,
				 RTC_INST_LOWER_BOUND);
	iwl_write_prph(priv, BSM_WR_DWCOUNT_REG, len / sizeof(u32));

	/* Load bootstrap code into instruction SRAM now,
	 *   to prepare to load "initialize" uCode */
	iwl_write_prph(priv, BSM_WR_CTRL_REG,
		BSM_WR_CTRL_REG_BIT_START);

	/* Wait for load of bootstrap uCode to finish */
	for (i = 0; i < 100; i++) {
		done = iwl_read_prph(priv, BSM_WR_CTRL_REG);
		if (!(done & BSM_WR_CTRL_REG_BIT_START))
			break;
		udelay(10);
	}
	if (i < 100)
		IWL_DEBUG_INFO("BSM write complete, poll %d iterations\n", i);
	else {
		IWL_ERROR("BSM write did not complete!\n");
		return -EIO;
	}

	/* Enable future boot loads whenever power management unit triggers it
	 *   (e.g. when powering back up after power-save shutdown) */
	iwl_write_prph(priv, BSM_WR_CTRL_REG,
		BSM_WR_CTRL_REG_BIT_START_EN);

	iwl_release_nic_access(priv);

	return 0;
}

static void iwl4965_nic_start(struct iwl_priv *priv)
static void iwl4965_nic_start(struct iwl_priv *priv)
{
{
	/* Remove all resets to allow NIC to operate */
	/* Remove all resets to allow NIC to operate */
@@ -5634,7 +5484,7 @@ static void iwl4965_init_alive_start(struct iwl_priv *priv)
 */
 */
static void iwl4965_alive_start(struct iwl_priv *priv)
static void iwl4965_alive_start(struct iwl_priv *priv)
{
{
	int rc = 0;
	int ret = 0;


	IWL_DEBUG_INFO("Runtime Alive received.\n");
	IWL_DEBUG_INFO("Runtime Alive received.\n");


@@ -5657,10 +5507,10 @@ static void iwl4965_alive_start(struct iwl_priv *priv)


	iwlcore_clear_stations_table(priv);
	iwlcore_clear_stations_table(priv);


	rc = iwl4965_alive_notify(priv);
	ret = priv->cfg->ops->lib->alive_notify(priv);
	if (rc) {
	if (ret) {
		IWL_WARNING("Could not complete ALIVE transition [ntf]: %d\n",
		IWL_WARNING("Could not complete ALIVE transition [ntf]: %d\n",
			    rc);
			    ret);
		goto restart;
		goto restart;
	}
	}


@@ -5835,7 +5685,8 @@ static void iwl4965_down(struct iwl_priv *priv)


static int __iwl4965_up(struct iwl_priv *priv)
static int __iwl4965_up(struct iwl_priv *priv)
{
{
	int rc, i;
	int i;
	int ret;


	if (test_bit(STATUS_EXIT_PENDING, &priv->status)) {
	if (test_bit(STATUS_EXIT_PENDING, &priv->status)) {
		IWL_WARNING("Exit pending; will not bring the NIC up\n");
		IWL_WARNING("Exit pending; will not bring the NIC up\n");
@@ -5870,10 +5721,10 @@ static int __iwl4965_up(struct iwl_priv *priv)
	iwl_rfkill_set_hw_state(priv);
	iwl_rfkill_set_hw_state(priv);
	iwl_write32(priv, CSR_INT, 0xFFFFFFFF);
	iwl_write32(priv, CSR_INT, 0xFFFFFFFF);


	rc = iwl4965_hw_nic_init(priv);
	ret = priv->cfg->ops->lib->hw_nic_init(priv);
	if (rc) {
	if (ret) {
		IWL_ERROR("Unable to int nic\n");
		IWL_ERROR("Unable to init nic\n");
		return rc;
		return ret;
	}
	}


	/* make sure rfkill handshake bits are cleared */
	/* make sure rfkill handshake bits are cleared */
@@ -5906,10 +5757,10 @@ static int __iwl4965_up(struct iwl_priv *priv)
		/* load bootstrap state machine,
		/* load bootstrap state machine,
		 * load bootstrap program into processor's memory,
		 * load bootstrap program into processor's memory,
		 * prepare to load the "initialize" uCode */
		 * prepare to load the "initialize" uCode */
		rc = iwl4965_load_bsm(priv);
		ret = priv->cfg->ops->lib->load_ucode(priv);


		if (rc) {
		if (ret) {
			IWL_ERROR("Unable to set up bootstrap uCode: %d\n", rc);
			IWL_ERROR("Unable to set up bootstrap uCode: %d\n", ret);
			continue;
			continue;
		}
		}