Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wirel...
[pandora-kernel.git] / drivers / net / wireless / iwlwifi / iwl-rx.c
index 0f718f6..0d09f57 100644 (file)
@@ -123,12 +123,11 @@ EXPORT_SYMBOL(iwl_rx_queue_space);
 /**
  * iwl_rx_queue_update_write_ptr - Update the write pointer for the RX queue
  */
-int iwl_rx_queue_update_write_ptr(struct iwl_priv *priv, struct iwl_rx_queue *q)
+void iwl_rx_queue_update_write_ptr(struct iwl_priv *priv, struct iwl_rx_queue *q)
 {
        unsigned long flags;
        u32 rx_wrt_ptr_reg = priv->hw_params.rx_wrt_ptr_reg;
        u32 reg;
-       int ret = 0;
 
        spin_lock_irqsave(&q->lock, flags);
 
@@ -161,7 +160,6 @@ int iwl_rx_queue_update_write_ptr(struct iwl_priv *priv, struct iwl_rx_queue *q)
 
  exit_unlock:
        spin_unlock_irqrestore(&q->lock, flags);
-       return ret;
 }
 EXPORT_SYMBOL(iwl_rx_queue_update_write_ptr);
 /**
@@ -184,14 +182,13 @@ static inline __le32 iwl_dma_addr2rbd_ptr(struct iwl_priv *priv,
  * also updates the memory address in the firmware to reference the new
  * target buffer.
  */
-int iwl_rx_queue_restock(struct iwl_priv *priv)
+void iwl_rx_queue_restock(struct iwl_priv *priv)
 {
        struct iwl_rx_queue *rxq = &priv->rxq;
        struct list_head *element;
        struct iwl_rx_mem_buffer *rxb;
        unsigned long flags;
        int write;
-       int ret = 0;
 
        spin_lock_irqsave(&rxq->lock, flags);
        write = rxq->write & ~0x7;
@@ -220,10 +217,8 @@ int iwl_rx_queue_restock(struct iwl_priv *priv)
                spin_lock_irqsave(&rxq->lock, flags);
                rxq->need_update = 1;
                spin_unlock_irqrestore(&rxq->lock, flags);
-               ret = iwl_rx_queue_update_write_ptr(priv, rxq);
+               iwl_rx_queue_update_write_ptr(priv, rxq);
        }
-
-       return ret;
 }
 EXPORT_SYMBOL(iwl_rx_queue_restock);
 
@@ -350,10 +345,10 @@ void iwl_rx_queue_free(struct iwl_priv *priv, struct iwl_rx_queue *rxq)
                }
        }
 
-       pci_free_consistent(priv->pci_dev, 4 * RX_QUEUE_SIZE, rxq->bd,
-                           rxq->dma_addr);
-       pci_free_consistent(priv->pci_dev, sizeof(struct iwl_rb_status),
-                           rxq->rb_stts, rxq->rb_stts_dma);
+       dma_free_coherent(&priv->pci_dev->dev, 4 * RX_QUEUE_SIZE, rxq->bd,
+                         rxq->dma_addr);
+       dma_free_coherent(&priv->pci_dev->dev, sizeof(struct iwl_rb_status),
+                         rxq->rb_stts, rxq->rb_stts_dma);
        rxq->bd = NULL;
        rxq->rb_stts  = NULL;
 }
@@ -362,7 +357,7 @@ EXPORT_SYMBOL(iwl_rx_queue_free);
 int iwl_rx_queue_alloc(struct iwl_priv *priv)
 {
        struct iwl_rx_queue *rxq = &priv->rxq;
-       struct pci_dev *dev = priv->pci_dev;
+       struct device *dev = &priv->pci_dev->dev;
        int i;
 
        spin_lock_init(&rxq->lock);
@@ -370,12 +365,13 @@ int iwl_rx_queue_alloc(struct iwl_priv *priv)
        INIT_LIST_HEAD(&rxq->rx_used);
 
        /* Alloc the circular buffer of Read Buffer Descriptors (RBDs) */
-       rxq->bd = pci_alloc_consistent(dev, 4 * RX_QUEUE_SIZE, &rxq->dma_addr);
+       rxq->bd = dma_alloc_coherent(dev, 4 * RX_QUEUE_SIZE, &rxq->dma_addr,
+                                    GFP_KERNEL);
        if (!rxq->bd)
                goto err_bd;
 
-       rxq->rb_stts = pci_alloc_consistent(dev, sizeof(struct iwl_rb_status),
-                                       &rxq->rb_stts_dma);
+       rxq->rb_stts = dma_alloc_coherent(dev, sizeof(struct iwl_rb_status),
+                                         &rxq->rb_stts_dma, GFP_KERNEL);
        if (!rxq->rb_stts)
                goto err_rb;
 
@@ -392,8 +388,8 @@ int iwl_rx_queue_alloc(struct iwl_priv *priv)
        return 0;
 
 err_rb:
-       pci_free_consistent(priv->pci_dev, 4 * RX_QUEUE_SIZE, rxq->bd,
-                           rxq->dma_addr);
+       dma_free_coherent(&priv->pci_dev->dev, 4 * RX_QUEUE_SIZE, rxq->bd,
+                         rxq->dma_addr);
 err_bd:
        return -ENOMEM;
 }
@@ -620,6 +616,11 @@ static void iwl_accumulative_statistics(struct iwl_priv *priv,
 
 #define REG_RECALIB_PERIOD (60)
 
+/* the threshold ratio of actual_ack_cnt to expected_ack_cnt in percent */
+#define ACK_CNT_RATIO (50)
+#define BA_TIMEOUT_CNT (5)
+#define BA_TIMEOUT_MAX (16)
+
 #define PLCP_MSG "plcp_err exceeded %u, %u, %u, %u, %u, %d, %u mSecs\n"
 void iwl_rx_statistics(struct iwl_priv *priv,
                              struct iwl_rx_mem_buffer *rxb)
@@ -629,6 +630,9 @@ void iwl_rx_statistics(struct iwl_priv *priv,
        int combined_plcp_delta;
        unsigned int plcp_msec;
        unsigned long plcp_received_jiffies;
+       int actual_ack_cnt_delta;
+       int expected_ack_cnt_delta;
+       int ba_timeout_delta;
 
        IWL_DEBUG_RX(priv, "Statistics notification received (%d vs %d).\n",
                     (int)sizeof(priv->statistics),
@@ -643,6 +647,44 @@ void iwl_rx_statistics(struct iwl_priv *priv,
 #ifdef CONFIG_IWLWIFI_DEBUG
        iwl_accumulative_statistics(priv, (__le32 *)&pkt->u.stats);
 #endif
+       actual_ack_cnt_delta = le32_to_cpu(pkt->u.stats.tx.actual_ack_cnt) -
+               le32_to_cpu(priv->statistics.tx.actual_ack_cnt);
+       expected_ack_cnt_delta = le32_to_cpu(
+                       pkt->u.stats.tx.expected_ack_cnt) -
+               le32_to_cpu(priv->statistics.tx.expected_ack_cnt);
+       ba_timeout_delta = le32_to_cpu(
+                       pkt->u.stats.tx.agg.ba_timeout) -
+               le32_to_cpu(priv->statistics.tx.agg.ba_timeout);
+       if ((priv->agg_tids_count > 0) &&
+               (expected_ack_cnt_delta > 0) &&
+               (((actual_ack_cnt_delta * 100) / expected_ack_cnt_delta) <
+                       ACK_CNT_RATIO) &&
+               (ba_timeout_delta > BA_TIMEOUT_CNT)) {
+               IWL_DEBUG_RADIO(priv,
+                       "actual_ack_cnt delta = %d, expected_ack_cnt = %d\n",
+                       actual_ack_cnt_delta, expected_ack_cnt_delta);
+
+#ifdef CONFIG_IWLWIFI_DEBUG
+               IWL_DEBUG_RADIO(priv, "rx_detected_cnt delta = %d\n",
+                       priv->delta_statistics.tx.rx_detected_cnt);
+               IWL_DEBUG_RADIO(priv,
+                       "ack_or_ba_timeout_collision delta = %d\n",
+                       priv->delta_statistics.tx.ack_or_ba_timeout_collision);
+#endif
+               IWL_DEBUG_RADIO(priv, "agg ba_timeout delta = %d\n",
+                       ba_timeout_delta);
+               if ((actual_ack_cnt_delta == 0) &&
+                       (ba_timeout_delta >=
+                               BA_TIMEOUT_MAX)) {
+                       IWL_DEBUG_RADIO(priv,
+                               "call iwl_force_reset(IWL_FW_RESET)\n");
+                       iwl_force_reset(priv, IWL_FW_RESET);
+               } else {
+                       IWL_DEBUG_RADIO(priv,
+                               "call iwl_force_reset(IWL_RF_RESET)\n");
+                       iwl_force_reset(priv, IWL_RF_RESET);
+               }
+       }
        /*
         * check for plcp_err and trigger radio reset if it exceeds
         * the plcp error threshold plcp_delta.
@@ -689,7 +731,7 @@ void iwl_rx_statistics(struct iwl_priv *priv,
                         * Reset the RF radio due to the high plcp
                         * error rate
                         */
-                       iwl_force_rf_reset(priv);
+                       iwl_force_reset(priv, IWL_RF_RESET);
                }
        }