diff options
author | Kolekar, Abhijeet <abhijeet.kolekar@intel.com> | 2008-12-19 10:37:37 +0800 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2009-01-29 15:59:19 -0500 |
commit | 0164b9b45dbee4a3c4c95f59f9dd538b1e9c2635 (patch) | |
tree | f7557888904652b8a54a85bbf626a285df9b2c88 /drivers/net/wireless/iwlwifi/iwl-3945.c | |
parent | 775a6e27bfca9d19f3ea6006a7e60a4a54aaf69c (diff) |
iwl3945: add load ucode op
The patch adds 3945 iwl_lib_ops->load_ucode to the driver.
Signed-off-by: Abhijeet Kolekar <abhijeet.kolekar@intel.com>
Signed-off-by: Zhu Yi <yi.zhu@intel.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/iwlwifi/iwl-3945.c')
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-3945.c | 159 |
1 files changed, 159 insertions, 0 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c index d5509d58938..1071dac99c5 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945.c @@ -2506,12 +2506,170 @@ void iwl3945_hw_cancel_deferred_work(struct iwl_priv *priv) cancel_delayed_work(&priv->thermal_periodic); } +/* check contents of special bootstrap uCode SRAM */ +static int iwl3945_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_ERR(priv, "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; +} + + /** + * iwl3945_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 iwl3945_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 > IWL39_MAX_BSM_SIZE) + return -EINVAL; + + /* Tell bootstrap uCode where to find the "Initialize" uCode + * in host DRAM ... host DRAM physical address bits 31:0 for 3945. + * NOTE: iwl3945_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; + pdata = priv->ucode_init_data.p_addr; + 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 = iwl3945_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, + IWL39_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_ERR(priv, "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 struct iwl_lib_ops iwl3945_lib = { + .load_ucode = iwl3945_load_bsm, +}; + +static struct iwl_ops iwl3945_ops = { + .lib = &iwl3945_lib, +}; + static struct iwl_cfg iwl3945_bg_cfg = { .name = "3945BG", .fw_name_pre = IWL3945_FW_PRE, .ucode_api_max = IWL3945_UCODE_API_MAX, .ucode_api_min = IWL3945_UCODE_API_MIN, .sku = IWL_SKU_G, + .ops = &iwl3945_ops, .mod_params = &iwl3945_mod_params }; @@ -2521,6 +2679,7 @@ static struct iwl_cfg iwl3945_abg_cfg = { .ucode_api_max = IWL3945_UCODE_API_MAX, .ucode_api_min = IWL3945_UCODE_API_MIN, .sku = IWL_SKU_A|IWL_SKU_G, + .ops = &iwl3945_ops, .mod_params = &iwl3945_mod_params }; |