Merge branch 'x86-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel...
[pandora-kernel.git] / drivers / net / wireless / iwlwifi / iwl-agn-lib.c
index 08ccb94..8e79653 100644 (file)
@@ -2,7 +2,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved.
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of version 2 of the GNU General Public License as
@@ -172,6 +172,7 @@ static void iwlagn_count_agg_tx_err_status(struct iwl_priv *priv, u16 status)
 
 static void iwlagn_set_tx_status(struct iwl_priv *priv,
                                 struct ieee80211_tx_info *info,
+                                struct iwl_rxon_context *ctx,
                                 struct iwlagn_tx_resp *tx_resp,
                                 int txq_id, bool is_agg)
 {
@@ -186,6 +187,13 @@ static void iwlagn_set_tx_status(struct iwl_priv *priv,
        if (!iwl_is_tx_success(status))
                iwlagn_count_tx_err_status(priv, status);
 
+       if (status == TX_STATUS_FAIL_PASSIVE_NO_RX &&
+           iwl_is_associated_ctx(ctx) && ctx->vif &&
+           ctx->vif->type == NL80211_IFTYPE_STATION) {
+               ctx->last_tx_rejected = true;
+               iwl_stop_queue(priv, &priv->txq[txq_id]);
+       }
+
        IWL_DEBUG_TX_REPLY(priv, "TXQ %d status %s (0x%08x) rate_n_flags "
                           "0x%x retries %d\n",
                           txq_id,
@@ -242,15 +250,16 @@ static int iwlagn_tx_status_reply_tx(struct iwl_priv *priv,
 
        /* # frames attempted by Tx command */
        if (agg->frame_count == 1) {
+               struct iwl_tx_info *txb;
+
                /* Only one frame was attempted; no block-ack will arrive */
                idx = start_idx;
 
                IWL_DEBUG_TX_REPLY(priv, "FrameCnt = %d, StartIdx=%d idx=%d\n",
                                   agg->frame_count, agg->start_idx, idx);
-               iwlagn_set_tx_status(priv,
-                                    IEEE80211_SKB_CB(
-                                       priv->txq[txq_id].txb[idx].skb),
-                                    tx_resp, txq_id, true);
+               txb = &priv->txq[txq_id].txb[idx];
+               iwlagn_set_tx_status(priv, IEEE80211_SKB_CB(txb->skb),
+                                    txb->ctx, tx_resp, txq_id, true);
                agg->wait_for_ba = 0;
        } else {
                /* Two or more frames were attempted; expect block-ack */
@@ -391,7 +400,8 @@ static void iwlagn_rx_reply_tx(struct iwl_priv *priv,
        struct iwl_tx_queue *txq = &priv->txq[txq_id];
        struct ieee80211_tx_info *info;
        struct iwlagn_tx_resp *tx_resp = (void *)&pkt->u.raw[0];
-       u32  status = le16_to_cpu(tx_resp->status.status);
+       struct iwl_tx_info *txb;
+       u32 status = le16_to_cpu(tx_resp->status.status);
        int tid;
        int sta_id;
        int freed;
@@ -406,7 +416,8 @@ static void iwlagn_rx_reply_tx(struct iwl_priv *priv,
        }
 
        txq->time_stamp = jiffies;
-       info = IEEE80211_SKB_CB(txq->txb[txq->q.read_ptr].skb);
+       txb = &txq->txb[txq->q.read_ptr];
+       info = IEEE80211_SKB_CB(txb->skb);
        memset(&info->status, 0, sizeof(info->status));
 
        tid = (tx_resp->ra_tid & IWLAGN_TX_RES_TID_MSK) >>
@@ -450,12 +461,14 @@ static void iwlagn_rx_reply_tx(struct iwl_priv *priv,
                                iwl_wake_queue(priv, txq);
                }
        } else {
-               iwlagn_set_tx_status(priv, info, tx_resp, txq_id, false);
+               iwlagn_set_tx_status(priv, info, txb->ctx, tx_resp,
+                                    txq_id, false);
                freed = iwlagn_tx_queue_reclaim(priv, txq_id, index);
                iwl_free_tfds_in_queue(priv, sta_id, tid, freed);
 
                if (priv->mac80211_registered &&
-                   (iwl_queue_space(&txq->q) > txq->q.low_mark))
+                   iwl_queue_space(&txq->q) > txq->q.low_mark &&
+                   status != TX_STATUS_FAIL_PASSIVE_NO_RX)
                        iwl_wake_queue(priv, txq);
        }
 
@@ -470,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 */
@@ -482,8 +493,10 @@ void iwlagn_rx_handler_setup(struct iwl_priv *priv)
 
 void iwlagn_setup_deferred_work(struct iwl_priv *priv)
 {
-       /* in agn, the tx power calibration is done in uCode */
-       priv->disable_tx_power_cal = 1;
+       /*
+        * nothing need to be done here anymore
+        * still keep for future use if needed
+        */
 }
 
 int iwlagn_hw_valid_rtc_data_addr(u32 addr)
@@ -534,9 +547,7 @@ int iwlagn_send_tx_power(struct iwl_priv *priv)
 void iwlagn_temperature(struct iwl_priv *priv)
 {
        /* store temperature from correct statistics (in Celsius) */
-       priv->temperature = le32_to_cpu((iwl_bt_statistics(priv)) ?
-               priv->_agn.statistics_bt.general.common.temperature :
-               priv->_agn.statistics.general.common.temperature);
+       priv->temperature = le32_to_cpu(priv->statistics.common.temperature);
        iwl_tt_handler(priv);
 }
 
@@ -652,10 +663,9 @@ int iwlagn_rx_init(struct iwl_priv *priv, struct iwl_rx_queue *rxq)
        const u32 rfdnlog = RX_QUEUE_SIZE_LOG; /* 256 RBDs */
        u32 rb_timeout = 0; /* FIXME: RX_RB_TIMEOUT for all devices? */
 
-       if (!priv->cfg->base_params->use_isr_legacy)
-               rb_timeout = RX_RB_TIMEOUT;
+       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;
@@ -913,7 +923,6 @@ void iwlagn_rx_allocate(struct iwl_priv *priv, gfp_t priority)
 
                list_add_tail(&rxb->list, &rxq->rx_free);
                rxq->free_count++;
-               priv->alloc_rxb_page++;
 
                spin_unlock_irqrestore(&rxq->lock, flags);
        }
@@ -1285,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;
 
@@ -2245,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,
@@ -2282,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);
+}