diff options
Diffstat (limited to 'drivers/net/wireless/iwlwifi/iwl-agn-lib.c')
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-agn-lib.c | 124 |
1 files changed, 112 insertions, 12 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-lib.c b/drivers/net/wireless/iwlwifi/iwl-agn-lib.c index e741128842b..8e79653aed9 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-lib.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-lib.c @@ -483,8 +483,6 @@ void iwlagn_rx_handler_setup(struct iwl_priv *priv) /* init calibration handlers */ priv->rx_handlers[CALIBRATION_RES_NOTIFICATION] = iwlagn_rx_calib_result; - priv->rx_handlers[CALIBRATION_COMPLETE_NOTIFICATION] = - iwlagn_rx_calib_complete; priv->rx_handlers[REPLY_TX] = iwlagn_rx_reply_tx; /* set up notification wait support */ @@ -667,7 +665,7 @@ int iwlagn_rx_init(struct iwl_priv *priv, struct iwl_rx_queue *rxq) rb_timeout = RX_RB_TIMEOUT; - if (priv->cfg->mod_params->amsdu_size_8K) + if (iwlagn_mod_params.amsdu_size_8K) rb_size = FH_RCSR_RX_CONFIG_REG_VAL_RB_SIZE_8K; else rb_size = FH_RCSR_RX_CONFIG_REG_VAL_RB_SIZE_4K; @@ -1296,9 +1294,17 @@ int iwlagn_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif) * mean we never reach it, but at the same time work around * the aforementioned issue. Thus use IWL_GOOD_CRC_TH_NEVER * here instead of IWL_GOOD_CRC_TH_DISABLED. + * + * This was fixed in later versions along with some other + * scan changes, and the threshold behaves as a flag in those + * versions. */ - scan->good_CRC_th = is_active ? IWL_GOOD_CRC_TH_DEFAULT : - IWL_GOOD_CRC_TH_NEVER; + if (priv->new_scan_threshold_behaviour) + scan->good_CRC_th = is_active ? IWL_GOOD_CRC_TH_DEFAULT : + IWL_GOOD_CRC_TH_DISABLED; + else + scan->good_CRC_th = is_active ? IWL_GOOD_CRC_TH_DEFAULT : + IWL_GOOD_CRC_TH_NEVER; band = priv->scan_band; @@ -2256,34 +2262,44 @@ int iwl_dump_fh(struct iwl_priv *priv, char **buf, bool display) /* notification wait support */ void iwlagn_init_notification_wait(struct iwl_priv *priv, struct iwl_notification_wait *wait_entry, + u8 cmd, void (*fn)(struct iwl_priv *priv, - struct iwl_rx_packet *pkt), - u8 cmd) + struct iwl_rx_packet *pkt, + void *data), + void *fn_data) { wait_entry->fn = fn; + wait_entry->fn_data = fn_data; wait_entry->cmd = cmd; wait_entry->triggered = false; + wait_entry->aborted = false; spin_lock_bh(&priv->_agn.notif_wait_lock); list_add(&wait_entry->list, &priv->_agn.notif_waits); spin_unlock_bh(&priv->_agn.notif_wait_lock); } -signed long iwlagn_wait_notification(struct iwl_priv *priv, - struct iwl_notification_wait *wait_entry, - unsigned long timeout) +int iwlagn_wait_notification(struct iwl_priv *priv, + struct iwl_notification_wait *wait_entry, + unsigned long timeout) { int ret; ret = wait_event_timeout(priv->_agn.notif_waitq, - wait_entry->triggered, + wait_entry->triggered || wait_entry->aborted, timeout); spin_lock_bh(&priv->_agn.notif_wait_lock); list_del(&wait_entry->list); spin_unlock_bh(&priv->_agn.notif_wait_lock); - return ret; + if (wait_entry->aborted) + return -EIO; + + /* return value is always >= 0 */ + if (ret <= 0) + return -ETIMEDOUT; + return 0; } void iwlagn_remove_notification(struct iwl_priv *priv, @@ -2293,3 +2309,87 @@ void iwlagn_remove_notification(struct iwl_priv *priv, list_del(&wait_entry->list); spin_unlock_bh(&priv->_agn.notif_wait_lock); } + +int iwlagn_start_device(struct iwl_priv *priv) +{ + int ret; + + if (iwl_prepare_card_hw(priv)) { + 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); + return -ERFKILL; + } + + iwl_write32(priv, CSR_INT, 0xFFFFFFFF); + + ret = iwlagn_hw_nic_init(priv); + if (ret) { + IWL_ERR(priv, "Unable to init nic\n"); + return ret; + } + + /* 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); + + return 0; +} + +void iwlagn_stop_device(struct iwl_priv *priv) +{ + unsigned long flags; + + /* 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); + + /* device going down, Stop using ICT table */ + iwl_disable_ict(priv); + + /* + * If a HW restart happens during firmware loading, + * then the firmware loading might call this function + * and later it might be called again due to the + * restart. So don't process again if the device is + * already dead. + */ + if (test_bit(STATUS_DEVICE_ENABLED, &priv->status)) { + 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); + + /* Stop the device, and put it in low power state */ + iwl_apm_stop(priv); +} |