--- b7e196e3c8d37e1671171e2cacecf86a99306dcc +++ d21c06ea0ec3a85a00b800a7acb34f9b38a82dc9 @@ -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(stru 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)); } @@ -119,6 +120,20 @@ int iwl_txq_update_write_ptr(struct iwl_ 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_DEBUG_TX(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. @@ -131,7 +146,7 @@ void iwl_tx_queue_free(struct iwl_priv * { 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, len; if (q->n_bd == 0) @@ -150,8 +165,8 @@ void iwl_tx_queue_free(struct iwl_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); /* De-alloc array of per-TFD driver data */ kfree(txq->txb); @@ -180,7 +195,7 @@ void iwl_cmd_queue_free(struct iwl_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, len; if (q->n_bd == 0) @@ -195,8 +210,8 @@ void iwl_cmd_queue_free(struct iwl_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); @@ -287,7 +302,7 @@ static int iwl_queue_init(struct iwl_pri 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, @@ -306,8 +321,8 @@ static int iwl_tx_queue_alloc(struct iwl /* 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; @@ -776,8 +791,10 @@ int iwl_tx_skb(struct iwl_priv *priv, st hdr->seq_ctrl |= cpu_to_le16(seq_number); seq_number += 0x10; /* aggregation is on for this */ - if (info->flags & IEEE80211_TX_CTL_AMPDU) + if (info->flags & IEEE80211_TX_CTL_AMPDU && + priv->stations[sta_id].tid[tid].agg.state == IWL_AGG_ON) { txq_id = priv->stations[sta_id].tid[tid].agg.txq_id; + } } txq = &priv->txq[txq_id]; @@ -1057,6 +1074,7 @@ int iwl_tx_queue_reclaim(struct iwl_priv 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, " @@ -1071,13 +1089,16 @@ int iwl_tx_queue_reclaim(struct iwl_priv tx_info = &txq->txb[txq->q.read_ptr]; ieee80211_tx_status_irqsafe(priv->hw, 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; } @@ -1254,7 +1275,7 @@ int iwl_tx_agg_stop(struct iwl_priv *pri { int tx_fifo_id, txq_id, sta_id, ssn = -1; struct iwl_tid_data *tid_data; - int ret, write_ptr, read_ptr; + int write_ptr, read_ptr; unsigned long flags; if (!ra) { @@ -1306,13 +1327,17 @@ int iwl_tx_agg_stop(struct iwl_priv *pri priv->stations[sta_id].tid[tid].agg.state = IWL_AGG_OFF; spin_lock_irqsave(&priv->lock, flags); - ret = priv->cfg->ops->lib->txq_agg_disable(priv, txq_id, ssn, + /* + * the only reason this call can fail is queue number out of range, + * which can happen if uCode is reloaded and all the station + * information are lost. if it is outside the range, there is no need + * to deactivate the uCode queue, just return "success" to allow + * mac80211 to clean up it own data. + */ + priv->cfg->ops->lib->txq_agg_disable(priv, txq_id, ssn, tx_fifo_id); spin_unlock_irqrestore(&priv->lock, flags); - if (ret) - return ret; - ieee80211_stop_tx_ba_cb_irqsafe(priv->hw, ra, tid); return 0; @@ -1454,6 +1479,11 @@ void iwl_rx_reply_compressed_ba(struct i sta_id = ba_resp->sta_id; tid = ba_resp->tid; agg = &priv->stations[sta_id].tid[tid].agg; + if (unlikely(agg->txq_id != scd_flow)) { + IWL_ERR(priv, "BA scd_flow %d does not match txq_id %d\n", + scd_flow, agg->txq_id); + return; + } /* Find index just before block-ack window */ index = iwl_queue_dec_wrap(ba_resp_scd_ssn & 0xff, txq->q.n_bd); @@ -1485,7 +1515,7 @@ void iwl_rx_reply_compressed_ba(struct i 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 &&