|
@@ -769,7 +769,7 @@ static void iwl_rx_handle(struct iwl_priv *priv)
|
|
|
if (w->cmd == pkt->hdr.cmd) {
|
|
|
w->triggered = true;
|
|
|
if (w->fn)
|
|
|
- w->fn(priv, pkt);
|
|
|
+ w->fn(priv, pkt, w->fn_data);
|
|
|
}
|
|
|
}
|
|
|
spin_unlock(&priv->_agn.notif_wait_lock);
|
|
@@ -846,14 +846,6 @@ static void iwl_rx_handle(struct iwl_priv *priv)
|
|
|
iwlagn_rx_queue_restock(priv);
|
|
|
}
|
|
|
|
|
|
-/* call this function to flush any scheduled tasklet */
|
|
|
-static inline void iwl_synchronize_irq(struct iwl_priv *priv)
|
|
|
-{
|
|
|
- /* wait to make sure we flush pending tasklet*/
|
|
|
- synchronize_irq(priv->pci_dev->irq);
|
|
|
- tasklet_kill(&priv->irq_tasklet);
|
|
|
-}
|
|
|
-
|
|
|
/* tasklet for iwlagn interrupt */
|
|
|
static void iwl_irq_tasklet(struct iwl_priv *priv)
|
|
|
{
|
|
@@ -1181,18 +1173,42 @@ static struct attribute_group iwl_attribute_group = {
|
|
|
*
|
|
|
******************************************************************************/
|
|
|
|
|
|
-static void iwl_dealloc_ucode_pci(struct iwl_priv *priv)
|
|
|
+static void iwl_free_fw_desc(struct pci_dev *pci_dev, struct fw_desc *desc)
|
|
|
{
|
|
|
- iwl_free_fw_desc(priv->pci_dev, &priv->ucode_code);
|
|
|
- iwl_free_fw_desc(priv->pci_dev, &priv->ucode_data);
|
|
|
- iwl_free_fw_desc(priv->pci_dev, &priv->ucode_init);
|
|
|
- iwl_free_fw_desc(priv->pci_dev, &priv->ucode_init_data);
|
|
|
+ if (desc->v_addr)
|
|
|
+ dma_free_coherent(&pci_dev->dev, desc->len,
|
|
|
+ desc->v_addr, desc->p_addr);
|
|
|
+ desc->v_addr = NULL;
|
|
|
+ desc->len = 0;
|
|
|
+}
|
|
|
+
|
|
|
+static void iwl_free_fw_img(struct pci_dev *pci_dev, struct fw_img *img)
|
|
|
+{
|
|
|
+ iwl_free_fw_desc(pci_dev, &img->code);
|
|
|
+ iwl_free_fw_desc(pci_dev, &img->data);
|
|
|
+}
|
|
|
+
|
|
|
+static int iwl_alloc_fw_desc(struct pci_dev *pci_dev, struct fw_desc *desc,
|
|
|
+ const void *data, size_t len)
|
|
|
+{
|
|
|
+ if (!len) {
|
|
|
+ desc->v_addr = NULL;
|
|
|
+ return -EINVAL;
|
|
|
+ }
|
|
|
+
|
|
|
+ desc->v_addr = dma_alloc_coherent(&pci_dev->dev, len,
|
|
|
+ &desc->p_addr, GFP_KERNEL);
|
|
|
+ if (!desc->v_addr)
|
|
|
+ return -ENOMEM;
|
|
|
+ desc->len = len;
|
|
|
+ memcpy(desc->v_addr, data, len);
|
|
|
+ return 0;
|
|
|
}
|
|
|
|
|
|
-static void iwl_nic_start(struct iwl_priv *priv)
|
|
|
+static void iwl_dealloc_ucode_pci(struct iwl_priv *priv)
|
|
|
{
|
|
|
- /* Remove all resets to allow NIC to operate */
|
|
|
- iwl_write32(priv, CSR_RESET, 0);
|
|
|
+ iwl_free_fw_img(priv->pci_dev, &priv->ucode_rt);
|
|
|
+ iwl_free_fw_img(priv->pci_dev, &priv->ucode_init);
|
|
|
}
|
|
|
|
|
|
struct iwlagn_ucode_capabilities {
|
|
@@ -1661,24 +1677,20 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context)
|
|
|
/* Runtime instructions and 2 copies of data:
|
|
|
* 1) unmodified from disk
|
|
|
* 2) backup cache for save/restore during power-downs */
|
|
|
- priv->ucode_code.len = pieces.inst_size;
|
|
|
- iwl_alloc_fw_desc(priv->pci_dev, &priv->ucode_code);
|
|
|
-
|
|
|
- priv->ucode_data.len = pieces.data_size;
|
|
|
- iwl_alloc_fw_desc(priv->pci_dev, &priv->ucode_data);
|
|
|
-
|
|
|
- if (!priv->ucode_code.v_addr || !priv->ucode_data.v_addr)
|
|
|
+ if (iwl_alloc_fw_desc(priv->pci_dev, &priv->ucode_rt.code,
|
|
|
+ pieces.inst, pieces.inst_size))
|
|
|
+ goto err_pci_alloc;
|
|
|
+ if (iwl_alloc_fw_desc(priv->pci_dev, &priv->ucode_rt.data,
|
|
|
+ pieces.data, pieces.data_size))
|
|
|
goto err_pci_alloc;
|
|
|
|
|
|
/* Initialization instructions and data */
|
|
|
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 = 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)
|
|
|
+ if (iwl_alloc_fw_desc(priv->pci_dev, &priv->ucode_init.code,
|
|
|
+ pieces.init, pieces.init_size))
|
|
|
+ goto err_pci_alloc;
|
|
|
+ if (iwl_alloc_fw_desc(priv->pci_dev, &priv->ucode_init.data,
|
|
|
+ pieces.init_data, pieces.init_data_size))
|
|
|
goto err_pci_alloc;
|
|
|
}
|
|
|
|
|
@@ -1715,39 +1727,6 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context)
|
|
|
else
|
|
|
priv->cmd_queue = IWL_DEFAULT_CMD_QUEUE_NUM;
|
|
|
|
|
|
- /* Copy images into buffers for card's bus-master reads ... */
|
|
|
-
|
|
|
- /* Runtime instructions (first block of data in file) */
|
|
|
- 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
|
|
|
- * 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);
|
|
|
-
|
|
|
- /* Initialization instructions */
|
|
|
- if (pieces.init_size) {
|
|
|
- IWL_DEBUG_INFO(priv, "Copying (but not loading) init instr len %Zd\n",
|
|
|
- pieces.init_size);
|
|
|
- memcpy(priv->ucode_init.v_addr, pieces.init, pieces.init_size);
|
|
|
- }
|
|
|
-
|
|
|
- /* Initialization data */
|
|
|
- if (pieces.init_data_size) {
|
|
|
- IWL_DEBUG_INFO(priv, "Copying (but not loading) init data len %Zd\n",
|
|
|
- pieces.init_data_size);
|
|
|
- memcpy(priv->ucode_init_data.v_addr, pieces.init_data,
|
|
|
- pieces.init_data_size);
|
|
|
- }
|
|
|
-
|
|
|
/*
|
|
|
* figure out the offset of chain noise reset and gain commands
|
|
|
* base on the size of standard phy calibration commands table size
|
|
@@ -1878,9 +1857,10 @@ void iwl_dump_nic_error_log(struct iwl_priv *priv)
|
|
|
u32 desc, time, count, base, data1;
|
|
|
u32 blink1, blink2, ilink1, ilink2;
|
|
|
u32 pc, hcmd;
|
|
|
+ struct iwl_error_event_table table;
|
|
|
|
|
|
base = priv->device_pointers.error_event_table;
|
|
|
- if (priv->ucode_type == UCODE_INIT) {
|
|
|
+ if (priv->ucode_type == UCODE_SUBTYPE_INIT) {
|
|
|
if (!base)
|
|
|
base = priv->_agn.init_errlog_ptr;
|
|
|
} else {
|
|
@@ -1891,11 +1871,15 @@ void iwl_dump_nic_error_log(struct iwl_priv *priv)
|
|
|
if (!priv->cfg->ops->lib->is_valid_rtc_data_addr(base)) {
|
|
|
IWL_ERR(priv,
|
|
|
"Not valid error log pointer 0x%08X for %s uCode\n",
|
|
|
- base, (priv->ucode_type == UCODE_INIT) ? "Init" : "RT");
|
|
|
+ base,
|
|
|
+ (priv->ucode_type == UCODE_SUBTYPE_INIT)
|
|
|
+ ? "Init" : "RT");
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
- count = iwl_read_targ_mem(priv, base);
|
|
|
+ iwl_read_targ_mem_words(priv, base, &table, sizeof(table));
|
|
|
+
|
|
|
+ count = table.valid;
|
|
|
|
|
|
if (ERROR_START_OFFSET <= count * ERROR_ELEM_SIZE) {
|
|
|
IWL_ERR(priv, "Start IWL Error Log Dump:\n");
|
|
@@ -1903,18 +1887,18 @@ void iwl_dump_nic_error_log(struct iwl_priv *priv)
|
|
|
priv->status, count);
|
|
|
}
|
|
|
|
|
|
- desc = iwl_read_targ_mem(priv, base + 1 * sizeof(u32));
|
|
|
+ desc = table.error_id;
|
|
|
priv->isr_stats.err_code = desc;
|
|
|
- pc = iwl_read_targ_mem(priv, base + 2 * sizeof(u32));
|
|
|
- blink1 = iwl_read_targ_mem(priv, base + 3 * sizeof(u32));
|
|
|
- blink2 = iwl_read_targ_mem(priv, base + 4 * sizeof(u32));
|
|
|
- ilink1 = iwl_read_targ_mem(priv, base + 5 * sizeof(u32));
|
|
|
- ilink2 = iwl_read_targ_mem(priv, base + 6 * sizeof(u32));
|
|
|
- data1 = iwl_read_targ_mem(priv, base + 7 * sizeof(u32));
|
|
|
- data2 = iwl_read_targ_mem(priv, base + 8 * sizeof(u32));
|
|
|
- line = iwl_read_targ_mem(priv, base + 9 * sizeof(u32));
|
|
|
- time = iwl_read_targ_mem(priv, base + 11 * sizeof(u32));
|
|
|
- hcmd = iwl_read_targ_mem(priv, base + 22 * sizeof(u32));
|
|
|
+ pc = table.pc;
|
|
|
+ blink1 = table.blink1;
|
|
|
+ blink2 = table.blink2;
|
|
|
+ ilink1 = table.ilink1;
|
|
|
+ ilink2 = table.ilink2;
|
|
|
+ data1 = table.data1;
|
|
|
+ data2 = table.data2;
|
|
|
+ line = table.line;
|
|
|
+ time = table.tsf_low;
|
|
|
+ hcmd = table.hcmd;
|
|
|
|
|
|
trace_iwlwifi_dev_ucode_error(priv, desc, time, data1, data2, line,
|
|
|
blink1, blink2, ilink1, ilink2);
|
|
@@ -1949,7 +1933,7 @@ static int iwl_print_event_log(struct iwl_priv *priv, u32 start_idx,
|
|
|
return pos;
|
|
|
|
|
|
base = priv->device_pointers.log_event_table;
|
|
|
- if (priv->ucode_type == UCODE_INIT) {
|
|
|
+ if (priv->ucode_type == UCODE_SUBTYPE_INIT) {
|
|
|
if (!base)
|
|
|
base = priv->_agn.init_evtlog_ptr;
|
|
|
} else {
|
|
@@ -2062,7 +2046,7 @@ int iwl_dump_nic_event_log(struct iwl_priv *priv, bool full_log,
|
|
|
size_t bufsz = 0;
|
|
|
|
|
|
base = priv->device_pointers.log_event_table;
|
|
|
- if (priv->ucode_type == UCODE_INIT) {
|
|
|
+ if (priv->ucode_type == UCODE_SUBTYPE_INIT) {
|
|
|
logsize = priv->_agn.init_evtlog_size;
|
|
|
if (!base)
|
|
|
base = priv->_agn.init_evtlog_ptr;
|
|
@@ -2075,7 +2059,9 @@ int iwl_dump_nic_event_log(struct iwl_priv *priv, bool full_log,
|
|
|
if (!priv->cfg->ops->lib->is_valid_rtc_data_addr(base)) {
|
|
|
IWL_ERR(priv,
|
|
|
"Invalid event log pointer 0x%08X for %s uCode\n",
|
|
|
- base, (priv->ucode_type == UCODE_INIT) ? "Init" : "RT");
|
|
|
+ base,
|
|
|
+ (priv->ucode_type == UCODE_SUBTYPE_INIT)
|
|
|
+ ? "Init" : "RT");
|
|
|
return -EINVAL;
|
|
|
}
|
|
|
|
|
@@ -2222,30 +2208,14 @@ static int iwlagn_send_calib_cfg_rt(struct iwl_priv *priv, u32 cfg)
|
|
|
* from protocol/runtime uCode (initialization uCode's
|
|
|
* Alive gets handled by iwl_init_alive_start()).
|
|
|
*/
|
|
|
-static void iwl_alive_start(struct iwl_priv *priv)
|
|
|
+static int iwl_alive_start(struct iwl_priv *priv)
|
|
|
{
|
|
|
int ret = 0;
|
|
|
struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
|
|
|
|
|
|
- IWL_DEBUG_INFO(priv, "Runtime Alive received.\n");
|
|
|
-
|
|
|
- /* Initialize uCode has loaded Runtime uCode ... verify inst image.
|
|
|
- * This is a paranoid check, because we would not have gotten the
|
|
|
- * "runtime" alive if code weren't properly loaded. */
|
|
|
- if (iwl_verify_ucode(priv, &priv->ucode_code)) {
|
|
|
- /* Runtime instruction load was bad;
|
|
|
- * take it all the way back down so we can try again */
|
|
|
- IWL_DEBUG_INFO(priv, "Bad runtime uCode load.\n");
|
|
|
- goto restart;
|
|
|
- }
|
|
|
-
|
|
|
- ret = iwlagn_alive_notify(priv);
|
|
|
- if (ret) {
|
|
|
- IWL_WARN(priv,
|
|
|
- "Could not complete ALIVE transition [ntf]: %d\n", ret);
|
|
|
- goto restart;
|
|
|
- }
|
|
|
+ iwl_reset_ict(priv);
|
|
|
|
|
|
+ IWL_DEBUG_INFO(priv, "Runtime Alive received.\n");
|
|
|
|
|
|
/* After the ALIVE response, we can send host commands to the uCode */
|
|
|
set_bit(STATUS_ALIVE, &priv->status);
|
|
@@ -2254,7 +2224,7 @@ static void iwl_alive_start(struct iwl_priv *priv)
|
|
|
iwl_setup_watchdog(priv);
|
|
|
|
|
|
if (iwl_is_rfkill(priv))
|
|
|
- return;
|
|
|
+ return -ERFKILL;
|
|
|
|
|
|
/* download priority table before any calibration request */
|
|
|
if (priv->cfg->bt_params &&
|
|
@@ -2268,10 +2238,14 @@ static void iwl_alive_start(struct iwl_priv *priv)
|
|
|
iwlagn_send_prio_tbl(priv);
|
|
|
|
|
|
/* FIXME: w/a to force change uCode BT state machine */
|
|
|
- iwlagn_send_bt_env(priv, IWL_BT_COEX_ENV_OPEN,
|
|
|
- BT_COEX_PRIO_TBL_EVT_INIT_CALIB2);
|
|
|
- iwlagn_send_bt_env(priv, IWL_BT_COEX_ENV_CLOSE,
|
|
|
- BT_COEX_PRIO_TBL_EVT_INIT_CALIB2);
|
|
|
+ ret = iwlagn_send_bt_env(priv, IWL_BT_COEX_ENV_OPEN,
|
|
|
+ BT_COEX_PRIO_TBL_EVT_INIT_CALIB2);
|
|
|
+ if (ret)
|
|
|
+ return ret;
|
|
|
+ ret = iwlagn_send_bt_env(priv, IWL_BT_COEX_ENV_CLOSE,
|
|
|
+ BT_COEX_PRIO_TBL_EVT_INIT_CALIB2);
|
|
|
+ if (ret)
|
|
|
+ return ret;
|
|
|
}
|
|
|
if (priv->hw_params.calib_rt_cfg)
|
|
|
iwlagn_send_calib_cfg_rt(priv, priv->hw_params.calib_rt_cfg);
|
|
@@ -2313,29 +2287,22 @@ static void iwl_alive_start(struct iwl_priv *priv)
|
|
|
set_bit(STATUS_READY, &priv->status);
|
|
|
|
|
|
/* Configure the adapter for unassociated operation */
|
|
|
- iwlcore_commit_rxon(priv, ctx);
|
|
|
+ ret = iwlcore_commit_rxon(priv, ctx);
|
|
|
+ if (ret)
|
|
|
+ return ret;
|
|
|
|
|
|
/* At this point, the NIC is initialized and operational */
|
|
|
iwl_rf_kill_ct_config(priv);
|
|
|
|
|
|
IWL_DEBUG_INFO(priv, "ALIVE processing complete.\n");
|
|
|
- wake_up_interruptible(&priv->wait_command_queue);
|
|
|
-
|
|
|
- iwl_power_update_mode(priv, true);
|
|
|
- IWL_DEBUG_INFO(priv, "Updated power mode\n");
|
|
|
|
|
|
-
|
|
|
- return;
|
|
|
-
|
|
|
- restart:
|
|
|
- queue_work(priv->workqueue, &priv->restart);
|
|
|
+ return iwl_power_update_mode(priv, true);
|
|
|
}
|
|
|
|
|
|
static void iwl_cancel_deferred_work(struct iwl_priv *priv);
|
|
|
|
|
|
static void __iwl_down(struct iwl_priv *priv)
|
|
|
{
|
|
|
- unsigned long flags;
|
|
|
int exit_pending;
|
|
|
|
|
|
IWL_DEBUG_INFO(priv, DRV_NAME " is going down\n");
|
|
@@ -2367,32 +2334,10 @@ static void __iwl_down(struct iwl_priv *priv)
|
|
|
if (!exit_pending)
|
|
|
clear_bit(STATUS_EXIT_PENDING, &priv->status);
|
|
|
|
|
|
- /* stop and reset the on-board processor */
|
|
|
- iwl_write32(priv, CSR_RESET, CSR_RESET_REG_FLAG_NEVO_RESET);
|
|
|
-
|
|
|
- /* tell the device to stop sending interrupts */
|
|
|
- spin_lock_irqsave(&priv->lock, flags);
|
|
|
- iwl_disable_interrupts(priv);
|
|
|
- spin_unlock_irqrestore(&priv->lock, flags);
|
|
|
- iwl_synchronize_irq(priv);
|
|
|
-
|
|
|
if (priv->mac80211_registered)
|
|
|
ieee80211_stop_queues(priv->hw);
|
|
|
|
|
|
- /* If we have not previously called iwl_init() then
|
|
|
- * clear all bits but the RF Kill bit and return */
|
|
|
- if (!iwl_is_init(priv)) {
|
|
|
- priv->status = test_bit(STATUS_RF_KILL_HW, &priv->status) <<
|
|
|
- STATUS_RF_KILL_HW |
|
|
|
- test_bit(STATUS_GEO_CONFIGURED, &priv->status) <<
|
|
|
- STATUS_GEO_CONFIGURED |
|
|
|
- test_bit(STATUS_EXIT_PENDING, &priv->status) <<
|
|
|
- STATUS_EXIT_PENDING;
|
|
|
- goto exit;
|
|
|
- }
|
|
|
-
|
|
|
- /* ...otherwise clear out all the status bits but the RF Kill
|
|
|
- * bit and continue taking the NIC down. */
|
|
|
+ /* Clear out all status bits but a few that are stable across reset */
|
|
|
priv->status &= test_bit(STATUS_RF_KILL_HW, &priv->status) <<
|
|
|
STATUS_RF_KILL_HW |
|
|
|
test_bit(STATUS_GEO_CONFIGURED, &priv->status) <<
|
|
@@ -2402,23 +2347,8 @@ static void __iwl_down(struct iwl_priv *priv)
|
|
|
test_bit(STATUS_EXIT_PENDING, &priv->status) <<
|
|
|
STATUS_EXIT_PENDING;
|
|
|
|
|
|
- /* device going down, Stop using ICT table */
|
|
|
- iwl_disable_ict(priv);
|
|
|
-
|
|
|
- iwlagn_txq_ctx_stop(priv);
|
|
|
- iwlagn_rxq_stop(priv);
|
|
|
-
|
|
|
- /* Power-down device's busmaster DMA clocks */
|
|
|
- iwl_write_prph(priv, APMG_CLK_DIS_REG, APMG_CLK_VAL_DMA_CLK_RQT);
|
|
|
- udelay(5);
|
|
|
-
|
|
|
- /* Make sure (redundant) we've released our request to stay awake */
|
|
|
- iwl_clear_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
|
|
|
+ iwlagn_stop_device(priv);
|
|
|
|
|
|
- /* Stop the device, and put it in low power state */
|
|
|
- iwl_apm_stop(priv);
|
|
|
-
|
|
|
- exit:
|
|
|
dev_kfree_skb(priv->beacon_skb);
|
|
|
priv->beacon_skb = NULL;
|
|
|
|
|
@@ -2437,9 +2367,10 @@ static void iwl_down(struct iwl_priv *priv)
|
|
|
|
|
|
#define HW_READY_TIMEOUT (50)
|
|
|
|
|
|
+/* Note: returns poll_bit return value, which is >= 0 if success */
|
|
|
static int iwl_set_hw_ready(struct iwl_priv *priv)
|
|
|
{
|
|
|
- int ret = 0;
|
|
|
+ int ret;
|
|
|
|
|
|
iwl_set_bit(priv, CSR_HW_IF_CONFIG_REG,
|
|
|
CSR_HW_IF_CONFIG_REG_BIT_NIC_READY);
|
|
@@ -2449,25 +2380,21 @@ static int iwl_set_hw_ready(struct iwl_priv *priv)
|
|
|
CSR_HW_IF_CONFIG_REG_BIT_NIC_READY,
|
|
|
CSR_HW_IF_CONFIG_REG_BIT_NIC_READY,
|
|
|
HW_READY_TIMEOUT);
|
|
|
- if (ret != -ETIMEDOUT)
|
|
|
- priv->hw_ready = true;
|
|
|
- else
|
|
|
- priv->hw_ready = false;
|
|
|
|
|
|
- IWL_DEBUG_INFO(priv, "hardware %s\n",
|
|
|
- (priv->hw_ready == 1) ? "ready" : "not ready");
|
|
|
+ IWL_DEBUG_INFO(priv, "hardware%s ready\n", ret < 0 ? " not" : "");
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
|
-static int iwl_prepare_card_hw(struct iwl_priv *priv)
|
|
|
+/* Note: returns standard 0/-ERROR code */
|
|
|
+int iwl_prepare_card_hw(struct iwl_priv *priv)
|
|
|
{
|
|
|
- int ret = 0;
|
|
|
+ int ret;
|
|
|
|
|
|
IWL_DEBUG_INFO(priv, "iwl_prepare_card_hw enter\n");
|
|
|
|
|
|
ret = iwl_set_hw_ready(priv);
|
|
|
- if (priv->hw_ready)
|
|
|
- return ret;
|
|
|
+ if (ret >= 0)
|
|
|
+ return 0;
|
|
|
|
|
|
/* If HW is not ready, prepare the conditions to check again */
|
|
|
iwl_set_bit(priv, CSR_HW_IF_CONFIG_REG,
|
|
@@ -2477,10 +2404,13 @@ static int iwl_prepare_card_hw(struct iwl_priv *priv)
|
|
|
~CSR_HW_IF_CONFIG_REG_BIT_NIC_PREPARE_DONE,
|
|
|
CSR_HW_IF_CONFIG_REG_BIT_NIC_PREPARE_DONE, 150000);
|
|
|
|
|
|
- /* HW should be ready by now, check again. */
|
|
|
- if (ret != -ETIMEDOUT)
|
|
|
- iwl_set_hw_ready(priv);
|
|
|
+ if (ret < 0)
|
|
|
+ return ret;
|
|
|
|
|
|
+ /* HW should be ready by now, check again. */
|
|
|
+ ret = iwl_set_hw_ready(priv);
|
|
|
+ if (ret >= 0)
|
|
|
+ return 0;
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
@@ -2489,9 +2419,10 @@ static int iwl_prepare_card_hw(struct iwl_priv *priv)
|
|
|
static int __iwl_up(struct iwl_priv *priv)
|
|
|
{
|
|
|
struct iwl_rxon_context *ctx;
|
|
|
- int i;
|
|
|
int ret;
|
|
|
|
|
|
+ lockdep_assert_held(&priv->mutex);
|
|
|
+
|
|
|
if (test_bit(STATUS_EXIT_PENDING, &priv->status)) {
|
|
|
IWL_WARN(priv, "Exit pending; will not bring the NIC up\n");
|
|
|
return -EIO;
|
|
@@ -2505,77 +2436,33 @@ static int __iwl_up(struct iwl_priv *priv)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- iwl_prepare_card_hw(priv);
|
|
|
-
|
|
|
- if (!priv->hw_ready) {
|
|
|
- IWL_WARN(priv, "Exit HW not ready\n");
|
|
|
- return -EIO;
|
|
|
- }
|
|
|
-
|
|
|
- /* If platform's RF_KILL switch is NOT set to KILL */
|
|
|
- if (iwl_read32(priv, CSR_GP_CNTRL) & CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW)
|
|
|
- clear_bit(STATUS_RF_KILL_HW, &priv->status);
|
|
|
- else
|
|
|
- set_bit(STATUS_RF_KILL_HW, &priv->status);
|
|
|
-
|
|
|
- if (iwl_is_rfkill(priv)) {
|
|
|
- wiphy_rfkill_set_hw_state(priv->hw->wiphy, true);
|
|
|
-
|
|
|
- iwl_enable_interrupts(priv);
|
|
|
- IWL_WARN(priv, "Radio disabled by HW RF Kill switch\n");
|
|
|
- return 0;
|
|
|
+ ret = iwlagn_run_init_ucode(priv);
|
|
|
+ if (ret) {
|
|
|
+ IWL_ERR(priv, "Failed to run INIT ucode: %d\n", ret);
|
|
|
+ goto error;
|
|
|
}
|
|
|
|
|
|
- iwl_write32(priv, CSR_INT, 0xFFFFFFFF);
|
|
|
-
|
|
|
- ret = iwlagn_hw_nic_init(priv);
|
|
|
+ ret = iwlagn_load_ucode_wait_alive(priv,
|
|
|
+ &priv->ucode_rt,
|
|
|
+ UCODE_SUBTYPE_REGULAR,
|
|
|
+ UCODE_SUBTYPE_REGULAR_NEW);
|
|
|
if (ret) {
|
|
|
- IWL_ERR(priv, "Unable to init nic\n");
|
|
|
- return ret;
|
|
|
+ IWL_ERR(priv, "Failed to start RT ucode: %d\n", ret);
|
|
|
+ goto error;
|
|
|
}
|
|
|
|
|
|
- /* make sure rfkill handshake bits are cleared */
|
|
|
- iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL);
|
|
|
- iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR,
|
|
|
- CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED);
|
|
|
-
|
|
|
- /* clear (again), then enable host interrupts */
|
|
|
- iwl_write32(priv, CSR_INT, 0xFFFFFFFF);
|
|
|
- iwl_enable_interrupts(priv);
|
|
|
-
|
|
|
- /* really make sure rfkill handshake bits are cleared */
|
|
|
- iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL);
|
|
|
- iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL);
|
|
|
-
|
|
|
- for (i = 0; i < MAX_HW_RESTARTS; i++) {
|
|
|
-
|
|
|
- /* load bootstrap state machine,
|
|
|
- * load bootstrap program into processor's memory,
|
|
|
- * prepare to load the "initialize" uCode */
|
|
|
- ret = iwlagn_load_ucode(priv);
|
|
|
-
|
|
|
- if (ret) {
|
|
|
- IWL_ERR(priv, "Unable to set up bootstrap uCode: %d\n",
|
|
|
- ret);
|
|
|
- continue;
|
|
|
- }
|
|
|
-
|
|
|
- /* start card; "initialize" will load runtime ucode */
|
|
|
- iwl_nic_start(priv);
|
|
|
-
|
|
|
- IWL_DEBUG_INFO(priv, DRV_NAME " is coming up\n");
|
|
|
-
|
|
|
- return 0;
|
|
|
- }
|
|
|
+ ret = iwl_alive_start(priv);
|
|
|
+ if (ret)
|
|
|
+ goto error;
|
|
|
+ return 0;
|
|
|
|
|
|
+ error:
|
|
|
set_bit(STATUS_EXIT_PENDING, &priv->status);
|
|
|
__iwl_down(priv);
|
|
|
clear_bit(STATUS_EXIT_PENDING, &priv->status);
|
|
|
|
|
|
- /* tried to restart and config the device for as long as our
|
|
|
- * patience could withstand */
|
|
|
- IWL_ERR(priv, "Unable to initialize device after %d attempts.\n", i);
|
|
|
- return -EIO;
|
|
|
+ IWL_ERR(priv, "Unable to initialize device.\n");
|
|
|
+ return ret;
|
|
|
}
|
|
|
|
|
|
|
|
@@ -2585,39 +2472,6 @@ static int __iwl_up(struct iwl_priv *priv)
|
|
|
*
|
|
|
*****************************************************************************/
|
|
|
|
|
|
-static void iwl_bg_init_alive_start(struct work_struct *data)
|
|
|
-{
|
|
|
- struct iwl_priv *priv =
|
|
|
- container_of(data, struct iwl_priv, init_alive_start.work);
|
|
|
-
|
|
|
- mutex_lock(&priv->mutex);
|
|
|
-
|
|
|
- if (test_bit(STATUS_EXIT_PENDING, &priv->status)) {
|
|
|
- mutex_unlock(&priv->mutex);
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- iwlagn_init_alive_start(priv);
|
|
|
- mutex_unlock(&priv->mutex);
|
|
|
-}
|
|
|
-
|
|
|
-static void iwl_bg_alive_start(struct work_struct *data)
|
|
|
-{
|
|
|
- struct iwl_priv *priv =
|
|
|
- container_of(data, struct iwl_priv, alive_start.work);
|
|
|
-
|
|
|
- mutex_lock(&priv->mutex);
|
|
|
- if (test_bit(STATUS_EXIT_PENDING, &priv->status))
|
|
|
- goto unlock;
|
|
|
-
|
|
|
- /* enable dram interrupt */
|
|
|
- iwl_reset_ict(priv);
|
|
|
-
|
|
|
- iwl_alive_start(priv);
|
|
|
-unlock:
|
|
|
- mutex_unlock(&priv->mutex);
|
|
|
-}
|
|
|
-
|
|
|
static void iwl_bg_run_time_calib_work(struct work_struct *work)
|
|
|
{
|
|
|
struct iwl_priv *priv = container_of(work, struct iwl_priv,
|
|
@@ -2683,14 +2537,7 @@ static void iwl_bg_restart(struct work_struct *data)
|
|
|
iwl_cancel_deferred_work(priv);
|
|
|
ieee80211_restart_hw(priv->hw);
|
|
|
} else {
|
|
|
- iwl_down(priv);
|
|
|
-
|
|
|
- if (test_bit(STATUS_EXIT_PENDING, &priv->status))
|
|
|
- return;
|
|
|
-
|
|
|
- mutex_lock(&priv->mutex);
|
|
|
- __iwl_up(priv);
|
|
|
- mutex_unlock(&priv->mutex);
|
|
|
+ WARN_ON(1);
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -2801,8 +2648,6 @@ unlock:
|
|
|
*
|
|
|
*****************************************************************************/
|
|
|
|
|
|
-#define UCODE_READY_TIMEOUT (4 * HZ)
|
|
|
-
|
|
|
/*
|
|
|
* Not a mac80211 entry point function, but it fits in with all the
|
|
|
* other mac80211 functions grouped here.
|
|
@@ -2895,31 +2740,17 @@ static int iwlagn_mac_start(struct ieee80211_hw *hw)
|
|
|
mutex_lock(&priv->mutex);
|
|
|
ret = __iwl_up(priv);
|
|
|
mutex_unlock(&priv->mutex);
|
|
|
-
|
|
|
if (ret)
|
|
|
return ret;
|
|
|
|
|
|
- if (iwl_is_rfkill(priv))
|
|
|
- goto out;
|
|
|
-
|
|
|
IWL_DEBUG_INFO(priv, "Start UP work done.\n");
|
|
|
|
|
|
- /* Wait for START_ALIVE from Run Time ucode. Otherwise callbacks from
|
|
|
- * mac80211 will not be run successfully. */
|
|
|
- ret = wait_event_interruptible_timeout(priv->wait_command_queue,
|
|
|
- test_bit(STATUS_READY, &priv->status),
|
|
|
- UCODE_READY_TIMEOUT);
|
|
|
- if (!ret) {
|
|
|
- if (!test_bit(STATUS_READY, &priv->status)) {
|
|
|
- IWL_ERR(priv, "START_ALIVE timeout after %dms.\n",
|
|
|
- jiffies_to_msecs(UCODE_READY_TIMEOUT));
|
|
|
- return -ETIMEDOUT;
|
|
|
- }
|
|
|
- }
|
|
|
+ /* Now we should be done, and the READY bit should be set. */
|
|
|
+ if (WARN_ON(!test_bit(STATUS_READY, &priv->status)))
|
|
|
+ ret = -EIO;
|
|
|
|
|
|
iwlagn_led_enable(priv);
|
|
|
|
|
|
-out:
|
|
|
priv->is_open = 1;
|
|
|
IWL_DEBUG_MAC80211(priv, "leave\n");
|
|
|
return 0;
|
|
@@ -3506,8 +3337,6 @@ static void iwl_setup_deferred_work(struct iwl_priv *priv)
|
|
|
INIT_WORK(&priv->tx_flush, iwl_bg_tx_flush);
|
|
|
INIT_WORK(&priv->bt_full_concurrency, iwl_bg_bt_full_concurrency);
|
|
|
INIT_WORK(&priv->bt_runtime_config, iwl_bg_bt_runtime_config);
|
|
|
- INIT_DELAYED_WORK(&priv->init_alive_start, iwl_bg_init_alive_start);
|
|
|
- INIT_DELAYED_WORK(&priv->alive_start, iwl_bg_alive_start);
|
|
|
INIT_DELAYED_WORK(&priv->_agn.hw_roc_work, iwlagn_bg_roc_done);
|
|
|
|
|
|
iwl_setup_scan_deferred_work(priv);
|
|
@@ -3536,8 +3365,6 @@ static void iwl_cancel_deferred_work(struct iwl_priv *priv)
|
|
|
if (priv->cfg->ops->lib->cancel_deferred_work)
|
|
|
priv->cfg->ops->lib->cancel_deferred_work(priv);
|
|
|
|
|
|
- cancel_delayed_work_sync(&priv->init_alive_start);
|
|
|
- cancel_delayed_work(&priv->alive_start);
|
|
|
cancel_work_sync(&priv->run_time_calib_work);
|
|
|
cancel_work_sync(&priv->beacon_update);
|
|
|
|
|
@@ -3772,6 +3599,8 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
|
|
|
priv = hw->priv;
|
|
|
/* At this point both hw and priv are allocated. */
|
|
|
|
|
|
+ priv->ucode_type = UCODE_SUBTYPE_NONE_LOADED;
|
|
|
+
|
|
|
/*
|
|
|
* The default context is always valid,
|
|
|
* more may be discovered when firmware
|
|
@@ -3912,8 +3741,7 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
|
|
|
* PCI Tx retries from interfering with C3 CPU state */
|
|
|
pci_write_config_byte(pdev, PCI_CFG_RETRY_TIMEOUT, 0x00);
|
|
|
|
|
|
- iwl_prepare_card_hw(priv);
|
|
|
- if (!priv->hw_ready) {
|
|
|
+ if (iwl_prepare_card_hw(priv)) {
|
|
|
IWL_WARN(priv, "Failed, HW not ready\n");
|
|
|
goto out_iounmap;
|
|
|
}
|
|
@@ -4069,17 +3897,9 @@ static void __devexit iwl_pci_remove(struct pci_dev *pdev)
|
|
|
if (priv->mac80211_registered) {
|
|
|
ieee80211_unregister_hw(priv->hw);
|
|
|
priv->mac80211_registered = 0;
|
|
|
- } else {
|
|
|
- iwl_down(priv);
|
|
|
}
|
|
|
|
|
|
- /*
|
|
|
- * Make sure device is reset to low power before unloading driver.
|
|
|
- * This may be redundant with iwl_down(), but there are paths to
|
|
|
- * run iwl_down() without calling apm_ops.stop(), and there are
|
|
|
- * paths to avoid running iwl_down() at all before leaving driver.
|
|
|
- * This (inexpensive) call *makes sure* device is reset.
|
|
|
- */
|
|
|
+ /* Reset to low power before unloading driver. */
|
|
|
iwl_apm_stop(priv);
|
|
|
|
|
|
iwl_tt_exit(priv);
|