Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wirel...
[linux-2.6.git] / drivers / net / wireless / iwlwifi / iwl-tx.c
index 2199b1b..10701b8 100644 (file)
@@ -60,7 +60,8 @@ static const u16 default_tid_to_tx_fifo[] = {
 static inline int iwl_alloc_dma_ptr(struct iwl_priv *priv,
                                    struct iwl_dma_ptr *ptr, size_t size)
 {
-       ptr->addr = pci_alloc_consistent(priv->pci_dev, size, &ptr->dma);
+       ptr->addr = dma_alloc_coherent(&priv->pci_dev->dev, size, &ptr->dma,
+                                      GFP_KERNEL);
        if (!ptr->addr)
                return -ENOMEM;
        ptr->size = size;
@@ -73,7 +74,7 @@ static inline void iwl_free_dma_ptr(struct iwl_priv *priv,
        if (unlikely(!ptr->addr))
                return;
 
-       pci_free_consistent(priv->pci_dev, ptr->size, ptr->addr, ptr->dma);
+       dma_free_coherent(&priv->pci_dev->dev, ptr->size, ptr->addr, ptr->dma);
        memset(ptr, 0, sizeof(*ptr));
 }
 
@@ -117,6 +118,20 @@ void iwl_txq_update_write_ptr(struct iwl_priv *priv, struct iwl_tx_queue *txq)
 EXPORT_SYMBOL(iwl_txq_update_write_ptr);
 
 
+void iwl_free_tfds_in_queue(struct iwl_priv *priv,
+                           int sta_id, int tid, int freed)
+{
+       if (priv->stations[sta_id].tid[tid].tfds_in_queue >= freed)
+               priv->stations[sta_id].tid[tid].tfds_in_queue -= freed;
+       else {
+               IWL_ERR(priv, "free more than tfds_in_queue (%u:%d)\n",
+                       priv->stations[sta_id].tid[tid].tfds_in_queue,
+                       freed);
+               priv->stations[sta_id].tid[tid].tfds_in_queue = 0;
+       }
+}
+EXPORT_SYMBOL(iwl_free_tfds_in_queue);
+
 /**
  * iwl_tx_queue_free - Deallocate DMA queue.
  * @txq: Transmit queue to deallocate.
@@ -129,7 +144,7 @@ void iwl_tx_queue_free(struct iwl_priv *priv, int txq_id)
 {
        struct iwl_tx_queue *txq = &priv->txq[txq_id];
        struct iwl_queue *q = &txq->q;
-       struct pci_dev *dev = priv->pci_dev;
+       struct device *dev = &priv->pci_dev->dev;
        int i;
 
        if (q->n_bd == 0)
@@ -146,8 +161,8 @@ void iwl_tx_queue_free(struct iwl_priv *priv, int txq_id)
 
        /* De-alloc circular buffer of TFDs */
        if (txq->q.n_bd)
-               pci_free_consistent(dev, priv->hw_params.tfd_size *
-                                   txq->q.n_bd, txq->tfds, txq->q.dma_addr);
+               dma_free_coherent(dev, priv->hw_params.tfd_size *
+                                 txq->q.n_bd, txq->tfds, txq->q.dma_addr);
 
        /* De-alloc array of per-TFD driver data */
        kfree(txq->txb);
@@ -176,7 +191,7 @@ void iwl_cmd_queue_free(struct iwl_priv *priv)
 {
        struct iwl_tx_queue *txq = &priv->txq[IWL_CMD_QUEUE_NUM];
        struct iwl_queue *q = &txq->q;
-       struct pci_dev *dev = priv->pci_dev;
+       struct device *dev = &priv->pci_dev->dev;
        int i;
 
        if (q->n_bd == 0)
@@ -188,8 +203,8 @@ void iwl_cmd_queue_free(struct iwl_priv *priv)
 
        /* De-alloc circular buffer of TFDs */
        if (txq->q.n_bd)
-               pci_free_consistent(dev, priv->hw_params.tfd_size *
-                                   txq->q.n_bd, txq->tfds, txq->q.dma_addr);
+               dma_free_coherent(dev, priv->hw_params.tfd_size * txq->q.n_bd,
+                                 txq->tfds, txq->q.dma_addr);
 
        /* deallocate arrays */
        kfree(txq->cmd);
@@ -280,7 +295,7 @@ static int iwl_queue_init(struct iwl_priv *priv, struct iwl_queue *q,
 static int iwl_tx_queue_alloc(struct iwl_priv *priv,
                              struct iwl_tx_queue *txq, u32 id)
 {
-       struct pci_dev *dev = priv->pci_dev;
+       struct device *dev = &priv->pci_dev->dev;
        size_t tfd_sz = priv->hw_params.tfd_size * TFD_QUEUE_SIZE_MAX;
 
        /* Driver private data, only for Tx (not command) queues,
@@ -299,8 +314,8 @@ static int iwl_tx_queue_alloc(struct iwl_priv *priv,
 
        /* Circular buffer of transmit frame descriptors (TFDs),
         * shared with device */
-       txq->tfds = pci_alloc_consistent(dev, tfd_sz, &txq->q.dma_addr);
-
+       txq->tfds = dma_alloc_coherent(dev, tfd_sz, &txq->q.dma_addr,
+                                      GFP_KERNEL);
        if (!txq->tfds) {
                IWL_ERR(priv, "pci_alloc_consistent(%zd) failed\n", tfd_sz);
                goto error;
@@ -1126,6 +1141,7 @@ int iwl_tx_queue_reclaim(struct iwl_priv *priv, int txq_id, int index)
        struct iwl_queue *q = &txq->q;
        struct iwl_tx_info *tx_info;
        int nfreed = 0;
+       struct ieee80211_hdr *hdr;
 
        if ((index >= q->n_bd) || (iwl_queue_used(q, index) == 0)) {
                IWL_ERR(priv, "Read index for DMA queue txq id (%d), index %d, "
@@ -1140,13 +1156,16 @@ int iwl_tx_queue_reclaim(struct iwl_priv *priv, int txq_id, int index)
 
                tx_info = &txq->txb[txq->q.read_ptr];
                iwl_tx_status(priv, tx_info->skb[0]);
+
+               hdr = (struct ieee80211_hdr *)tx_info->skb[0]->data;
+               if (hdr && ieee80211_is_data_qos(hdr->frame_control))
+                       nfreed++;
                tx_info->skb[0] = NULL;
 
                if (priv->cfg->ops->lib->txq_inval_byte_cnt_tbl)
                        priv->cfg->ops->lib->txq_inval_byte_cnt_tbl(priv, txq);
 
                priv->cfg->ops->lib->txq_free_tfd(priv, txq);
-               nfreed++;
        }
        return nfreed;
 }
@@ -1237,6 +1256,8 @@ void iwl_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb)
 
        if (!(meta->flags & CMD_ASYNC)) {
                clear_bit(STATUS_HCMD_ACTIVE, &priv->status);
+               IWL_DEBUG_INFO(priv, "Clearing HCMD_ACTIVE for command %s \n",
+                              get_cmd_string(cmd->hdr.cmd));
                wake_up_interruptible(&priv->wait_command_queue);
        }
 }
@@ -1558,7 +1579,7 @@ void iwl_rx_reply_compressed_ba(struct iwl_priv *priv,
        if (txq->q.read_ptr != (ba_resp_scd_ssn & 0xff)) {
                /* calculate mac80211 ampdu sw queue to wake */
                int freed = iwl_tx_queue_reclaim(priv, scd_flow, index);
-               priv->stations[sta_id].tid[tid].tfds_in_queue -= freed;
+               iwl_free_tfds_in_queue(priv, sta_id, tid, freed);
 
                if ((iwl_queue_space(&txq->q) > txq->q.low_mark) &&
                    priv->mac80211_registered &&