summaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/iwlwifi/iwl-trans-pcie.c
diff options
context:
space:
mode:
authorEmmanuel Grumbach <emmanuel.grumbach@intel.com>2011-11-21 11:07:18 +0200
committerWey-Yi Guy <wey-yi.w.guy@intel.com>2011-12-16 07:22:33 -0800
commiteb9a372a73ea3e2b7e795a7ea03a5b8d92815672 (patch)
tree396d90022f3b304ef10f900a3306b8b616a376af /drivers/net/wireless/iwlwifi/iwl-trans-pcie.c
parentaca15f81fffb71e5df8fd72e76ef5f1a3128bd11 (diff)
iwlwifi: don't count the tfds in HW queue any more
Since packets sent to an RA / TID in AGG are sent from a separate HW Tx queue, we may get into a race: the regular queue isn't empty while we already begin to send packets from the AGG queue. This would result in sending packets out of order. In order to cope with this, mac80211 waits until the driver reports that the legacy queue is drained before it can send packets to the AGG queue. During that time, mac80211 buffers packets for the driver. These packets will be sent in order after the driver reports it is ready. The way this was implemented in the driver is as follows: We held a counter that monitors the number of packets for an RA / TID in the HW queues. When this counter reached 0, we knew that the HW queues were drained and we reported to mac80211 that were ready to proceed. This patch changes the implementation described above. We now remember what is the wifi sequence number of the first packet that will be sent in the AGG queue (lets' call it ssn). When we reclaim the packet before ssn, we know that the queue is drained, and we are ready to proceed. This will allow us to move this logic in the upper layer and eventually remove the tid_data from the shared area. Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com> Signed-off-by: Wey-Yi Guy <wey-yi.w.guy@intel.com>
Diffstat (limited to 'drivers/net/wireless/iwlwifi/iwl-trans-pcie.c')
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-trans-pcie.c31
1 files changed, 7 insertions, 24 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-trans-pcie.c b/drivers/net/wireless/iwlwifi/iwl-trans-pcie.c
index 66e1b9fa0b8..4d318431270 100644
--- a/drivers/net/wireless/iwlwifi/iwl-trans-pcie.c
+++ b/drivers/net/wireless/iwlwifi/iwl-trans-pcie.c
@@ -1109,7 +1109,7 @@ static int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb,
IWL_ERR(trans, "sta_id = %d, tid = %d "
"txq_id = %d, seq_num = %d", sta_id,
tid, tid_data->agg.txq_id,
- seq_number >> 4);
+ SEQ_TO_SN(seq_number));
}
txq_id = tid_data->agg.txq_id;
is_agg = true;
@@ -1222,12 +1222,10 @@ static int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb,
q->write_ptr = iwl_queue_inc_wrap(q->write_ptr, q->n_bd);
iwl_txq_update_write_ptr(trans, txq);
- if (ieee80211_is_data_qos(fc) && !ieee80211_is_qos_nullfunc(fc)) {
- trans->shrd->tid_data[sta_id][tid].tfds_in_queue++;
- if (!ieee80211_has_morefrags(fc))
+ if (ieee80211_is_data_qos(fc) && !ieee80211_is_qos_nullfunc(fc) &&
+ !ieee80211_has_morefrags(fc))
trans->shrd->tid_data[sta_id][tid].seq_number =
seq_number;
- }
/*
* At this point the frame is "transmitted" successfully
@@ -1304,10 +1302,11 @@ static int iwlagn_txq_check_empty(struct iwl_trans *trans,
}
break;
case IWL_EMPTYING_HW_QUEUE_ADDBA:
- /* We are reclaiming the last packet of the queue */
- if (tid_data->tfds_in_queue == 0) {
+ /* There are no packets for this RA / TID in the HW any more */
+ if (tid_data->agg.ssn == tid_data->next_reclaimed) {
IWL_DEBUG_TX_QUEUES(trans,
- "HW queue empty: continue ADDBA flow\n");
+ "Can continue ADDBA flow ssn = next_recl ="
+ " %d", tid_data->next_reclaimed);
tid_data->agg.state = IWL_AGG_ON;
iwl_start_tx_ba_trans_ready(priv(trans),
NUM_IWL_RXON_CTX,
@@ -1321,21 +1320,6 @@ static int iwlagn_txq_check_empty(struct iwl_trans *trans,
return 0;
}
-static void iwl_free_tfds_in_queue(struct iwl_trans *trans,
- int sta_id, int tid, int freed)
-{
- lockdep_assert_held(&trans->shrd->sta_lock);
-
- if (trans->shrd->tid_data[sta_id][tid].tfds_in_queue >= freed)
- trans->shrd->tid_data[sta_id][tid].tfds_in_queue -= freed;
- else {
- IWL_DEBUG_TX(trans, "free more than tfds_in_queue (%u:%d)\n",
- trans->shrd->tid_data[sta_id][tid].tfds_in_queue,
- freed);
- trans->shrd->tid_data[sta_id][tid].tfds_in_queue = 0;
- }
-}
-
static void iwl_trans_pcie_reclaim(struct iwl_trans *trans, int sta_id, int tid,
int txq_id, int ssn, u32 status,
struct sk_buff_head *skbs)
@@ -1367,7 +1351,6 @@ static void iwl_trans_pcie_reclaim(struct iwl_trans *trans, int sta_id, int tid,
iwl_wake_queue(trans, txq, "Packets reclaimed");
}
- iwl_free_tfds_in_queue(trans, sta_id, tid, freed);
iwlagn_txq_check_empty(trans, sta_id, tid, txq_id);
}