+/* 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(priv, "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(priv, "BSM bootstrap uCode image OK\n");
+
+ return 0;
+}
+
+
+/******************************************************************************
+ *
+ * EEPROM related functions
+ *
+ ******************************************************************************/
+
+/*
+ * Clear the OWNER_MSK, to establish driver (instead of uCode running on
+ * embedded controller) as EEPROM reader; each read is a series of pulses
+ * to/from the EEPROM chip, not a single event, so even reads could conflict
+ * if they weren't arbitrated by some ownership mechanism. Here, the driver
+ * simply claims ownership, which should be safe when this function is called
+ * (i.e. before loading uCode!).
+ */
+static int iwl3945_eeprom_acquire_semaphore(struct iwl_priv *priv)
+{
+ _iwl_clear_bit(priv, CSR_EEPROM_GP, CSR_EEPROM_GP_IF_OWNER_MSK);
+ return 0;
+}
+
+
+static void iwl3945_eeprom_release_semaphore(struct iwl_priv *priv)
+{
+ return;
+}
+
+ /**
+ * 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(priv, "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;
+
+ 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)
+ 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(priv, "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);
+
+ return 0;
+}
+
+#define IWL3945_UCODE_GET(item) \
+static u32 iwl3945_ucode_get_##item(const struct iwl_ucode_header *ucode,\
+ u32 api_ver) \
+{ \
+ return le32_to_cpu(ucode->u.v1.item); \
+}
+
+static u32 iwl3945_ucode_get_header_size(u32 api_ver)
+{
+ return UCODE_HEADER_SIZE(1);
+}
+static u32 iwl3945_ucode_get_build(const struct iwl_ucode_header *ucode,
+ u32 api_ver)
+{
+ return 0;
+}
+static u8 *iwl3945_ucode_get_data(const struct iwl_ucode_header *ucode,
+ u32 api_ver)
+{
+ return (u8 *) ucode->u.v1.data;
+}
+
+IWL3945_UCODE_GET(inst_size);
+IWL3945_UCODE_GET(data_size);
+IWL3945_UCODE_GET(init_size);
+IWL3945_UCODE_GET(init_data_size);
+IWL3945_UCODE_GET(boot_size);
+
+static struct iwl_hcmd_ops iwl3945_hcmd = {
+ .rxon_assoc = iwl3945_send_rxon_assoc,
+ .commit_rxon = iwl3945_commit_rxon,
+};
+
+static struct iwl_ucode_ops iwl3945_ucode = {
+ .get_header_size = iwl3945_ucode_get_header_size,
+ .get_build = iwl3945_ucode_get_build,
+ .get_inst_size = iwl3945_ucode_get_inst_size,
+ .get_data_size = iwl3945_ucode_get_data_size,
+ .get_init_size = iwl3945_ucode_get_init_size,
+ .get_init_data_size = iwl3945_ucode_get_init_data_size,
+ .get_boot_size = iwl3945_ucode_get_boot_size,
+ .get_data = iwl3945_ucode_get_data,
+};
+
+static struct iwl_lib_ops iwl3945_lib = {
+ .txq_attach_buf_to_tfd = iwl3945_hw_txq_attach_buf_to_tfd,
+ .txq_free_tfd = iwl3945_hw_txq_free_tfd,
+ .txq_init = iwl3945_hw_tx_queue_init,
+ .load_ucode = iwl3945_load_bsm,
+ .dump_nic_event_log = iwl3945_dump_nic_event_log,
+ .dump_nic_error_log = iwl3945_dump_nic_error_log,
+ .apm_ops = {
+ .init = iwl3945_apm_init,
+ .stop = iwl_apm_stop,
+ .config = iwl3945_nic_config,
+ .set_pwr_src = iwl3945_set_pwr_src,
+ },
+ .eeprom_ops = {
+ .regulatory_bands = {
+ EEPROM_REGULATORY_BAND_1_CHANNELS,
+ EEPROM_REGULATORY_BAND_2_CHANNELS,
+ EEPROM_REGULATORY_BAND_3_CHANNELS,
+ EEPROM_REGULATORY_BAND_4_CHANNELS,
+ EEPROM_REGULATORY_BAND_5_CHANNELS,
+ EEPROM_REGULATORY_BAND_NO_HT40,
+ EEPROM_REGULATORY_BAND_NO_HT40,
+ },
+ .verify_signature = iwlcore_eeprom_verify_signature,
+ .acquire_semaphore = iwl3945_eeprom_acquire_semaphore,
+ .release_semaphore = iwl3945_eeprom_release_semaphore,
+ .query_addr = iwlcore_eeprom_query_addr,
+ },
+ .send_tx_power = iwl3945_send_tx_power,
+ .is_valid_rtc_data_addr = iwl3945_hw_valid_rtc_data_addr,
+ .post_associate = iwl3945_post_associate,
+ .isr = iwl_isr_legacy,
+ .config_ap = iwl3945_config_ap,
+};
+
+static struct iwl_hcmd_utils_ops iwl3945_hcmd_utils = {
+ .get_hcmd_size = iwl3945_get_hcmd_size,
+ .build_addsta_hcmd = iwl3945_build_addsta_hcmd,
+ .rts_tx_cmd_flag = iwlcore_rts_tx_cmd_flag,
+};
+
+static struct iwl_ops iwl3945_ops = {
+ .ucode = &iwl3945_ucode,
+ .lib = &iwl3945_lib,
+ .hcmd = &iwl3945_hcmd,
+ .utils = &iwl3945_hcmd_utils,
+ .led = &iwl3945_led_ops,
+};
+