aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJohannes Berg <johannes.berg@intel.com>2011-03-15 14:33:03 -0400
committerWey-Yi Guy <wey-yi.w.guy@intel.com>2011-03-25 09:57:40 -0400
commitc8823ec1337017e23b99fb0814e2f3d62537f811 (patch)
tree50d8e265a5e4fccb02f4d02c8599b67c9a828bb1
parent7ffef13d7a24654292c4641450f2794224b9eb5d (diff)
iwlagn: fix aggregation queue scheduler setup
iwlagn's hardware scheduler needs to be set up with the right aggregation frame limit and buffer sizes. To achieve this, we need to move the hardware queue setup to when the session becomes operational. Tested-by: Daniel Halperin <dhalperi@cs.washington.edu> Signed-off-by: Johannes Berg <johannes.berg@intel.com> Signed-off-by: Wey-Yi Guy <wey-yi.w.guy@intel.com>
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn-tx.c47
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn.c4
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn.h3
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-dev.h1
4 files changed, 39 insertions, 16 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-tx.c b/drivers/net/wireless/iwlwifi/iwl-agn-tx.c
index 23e5667108e2..fb63a03a395e 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-tx.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-tx.c
@@ -222,13 +222,8 @@ void iwlagn_tx_queue_set_status(struct iwl_priv *priv,
222 scd_retry ? "BA" : "AC/CMD", txq_id, tx_fifo_id); 222 scd_retry ? "BA" : "AC/CMD", txq_id, tx_fifo_id);
223} 223}
224 224
225static int iwlagn_txq_agg_enable(struct iwl_priv *priv, int txq_id, 225static int iwlagn_txq_agg_enable(struct iwl_priv *priv, int txq_id, int sta_id, int tid)
226 int tx_fifo, int sta_id, int tid, u16 ssn_idx)
227{ 226{
228 unsigned long flags;
229 u16 ra_tid;
230 int ret;
231
232 if ((IWLAGN_FIRST_AMPDU_QUEUE > txq_id) || 227 if ((IWLAGN_FIRST_AMPDU_QUEUE > txq_id) ||
233 (IWLAGN_FIRST_AMPDU_QUEUE + 228 (IWLAGN_FIRST_AMPDU_QUEUE +
234 priv->cfg->base_params->num_of_ampdu_queues <= txq_id)) { 229 priv->cfg->base_params->num_of_ampdu_queues <= txq_id)) {
@@ -240,12 +235,33 @@ static int iwlagn_txq_agg_enable(struct iwl_priv *priv, int txq_id,
240 return -EINVAL; 235 return -EINVAL;
241 } 236 }
242 237
243 ra_tid = BUILD_RAxTID(sta_id, tid);
244
245 /* Modify device's station table to Tx this TID */ 238 /* Modify device's station table to Tx this TID */
246 ret = iwl_sta_tx_modify_enable_tid(priv, sta_id, tid); 239 return iwl_sta_tx_modify_enable_tid(priv, sta_id, tid);
247 if (ret) 240}
248 return ret; 241
242void iwlagn_txq_agg_queue_setup(struct iwl_priv *priv,
243 struct ieee80211_sta *sta,
244 int tid, int frame_limit)
245{
246 int sta_id, tx_fifo, txq_id, ssn_idx;
247 u16 ra_tid;
248 unsigned long flags;
249 struct iwl_tid_data *tid_data;
250
251 sta_id = iwl_sta_id(sta);
252 if (WARN_ON(sta_id == IWL_INVALID_STATION))
253 return;
254 if (WARN_ON(tid >= MAX_TID_COUNT))
255 return;
256
257 spin_lock_irqsave(&priv->sta_lock, flags);
258 tid_data = &priv->stations[sta_id].tid[tid];
259 ssn_idx = SEQ_TO_SN(tid_data->seq_number);
260 txq_id = tid_data->agg.txq_id;
261 tx_fifo = tid_data->agg.tx_fifo;
262 spin_unlock_irqrestore(&priv->sta_lock, flags);
263
264 ra_tid = BUILD_RAxTID(sta_id, tid);
249 265
250 spin_lock_irqsave(&priv->lock, flags); 266 spin_lock_irqsave(&priv->lock, flags);
251 267
@@ -271,10 +287,10 @@ static int iwlagn_txq_agg_enable(struct iwl_priv *priv, int txq_id,
271 iwl_write_targ_mem(priv, priv->scd_base_addr + 287 iwl_write_targ_mem(priv, priv->scd_base_addr +
272 IWLAGN_SCD_CONTEXT_QUEUE_OFFSET(txq_id) + 288 IWLAGN_SCD_CONTEXT_QUEUE_OFFSET(txq_id) +
273 sizeof(u32), 289 sizeof(u32),
274 ((SCD_WIN_SIZE << 290 ((frame_limit <<
275 IWLAGN_SCD_QUEUE_CTX_REG2_WIN_SIZE_POS) & 291 IWLAGN_SCD_QUEUE_CTX_REG2_WIN_SIZE_POS) &
276 IWLAGN_SCD_QUEUE_CTX_REG2_WIN_SIZE_MSK) | 292 IWLAGN_SCD_QUEUE_CTX_REG2_WIN_SIZE_MSK) |
277 ((SCD_FRAME_LIMIT << 293 ((frame_limit <<
278 IWLAGN_SCD_QUEUE_CTX_REG2_FRAME_LIMIT_POS) & 294 IWLAGN_SCD_QUEUE_CTX_REG2_FRAME_LIMIT_POS) &
279 IWLAGN_SCD_QUEUE_CTX_REG2_FRAME_LIMIT_MSK)); 295 IWLAGN_SCD_QUEUE_CTX_REG2_FRAME_LIMIT_MSK));
280 296
@@ -284,8 +300,6 @@ static int iwlagn_txq_agg_enable(struct iwl_priv *priv, int txq_id,
284 iwlagn_tx_queue_set_status(priv, &priv->txq[txq_id], tx_fifo, 1); 300 iwlagn_tx_queue_set_status(priv, &priv->txq[txq_id], tx_fifo, 1);
285 301
286 spin_unlock_irqrestore(&priv->lock, flags); 302 spin_unlock_irqrestore(&priv->lock, flags);
287
288 return 0;
289} 303}
290 304
291static int iwlagn_txq_agg_disable(struct iwl_priv *priv, u16 txq_id, 305static int iwlagn_txq_agg_disable(struct iwl_priv *priv, u16 txq_id,
@@ -1034,10 +1048,11 @@ int iwlagn_tx_agg_start(struct iwl_priv *priv, struct ieee80211_vif *vif,
1034 tid_data = &priv->stations[sta_id].tid[tid]; 1048 tid_data = &priv->stations[sta_id].tid[tid];
1035 *ssn = SEQ_TO_SN(tid_data->seq_number); 1049 *ssn = SEQ_TO_SN(tid_data->seq_number);
1036 tid_data->agg.txq_id = txq_id; 1050 tid_data->agg.txq_id = txq_id;
1051 tid_data->agg.tx_fifo = tx_fifo;
1037 iwl_set_swq_id(&priv->txq[txq_id], get_ac_from_tid(tid), txq_id); 1052 iwl_set_swq_id(&priv->txq[txq_id], get_ac_from_tid(tid), txq_id);
1038 spin_unlock_irqrestore(&priv->sta_lock, flags); 1053 spin_unlock_irqrestore(&priv->sta_lock, flags);
1039 1054
1040 ret = iwlagn_txq_agg_enable(priv, txq_id, tx_fifo, sta_id, tid, *ssn); 1055 ret = iwlagn_txq_agg_enable(priv, txq_id, sta_id, tid);
1041 if (ret) 1056 if (ret)
1042 return ret; 1057 return ret;
1043 1058
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c
index b57fbbf3fb64..8fdd1746c102 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn.c
@@ -3345,6 +3345,10 @@ int iwlagn_mac_ampdu_action(struct ieee80211_hw *hw,
3345 } 3345 }
3346 break; 3346 break;
3347 case IEEE80211_AMPDU_TX_OPERATIONAL: 3347 case IEEE80211_AMPDU_TX_OPERATIONAL:
3348 buf_size = min_t(int, buf_size, LINK_QUAL_AGG_FRAME_LIMIT_DEF);
3349
3350 iwlagn_txq_agg_queue_setup(priv, sta, tid, buf_size);
3351
3348 /* 3352 /*
3349 * If the limit is 0, then it wasn't initialised yet, 3353 * If the limit is 0, then it wasn't initialised yet,
3350 * use the default. We can do that since we take the 3354 * use the default. We can do that since we take the
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.h b/drivers/net/wireless/iwlwifi/iwl-agn.h
index 8d918ea36c61..4f7c9ce9d8bd 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn.h
+++ b/drivers/net/wireless/iwlwifi/iwl-agn.h
@@ -202,6 +202,9 @@ int iwlagn_tx_agg_start(struct iwl_priv *priv, struct ieee80211_vif *vif,
202 struct ieee80211_sta *sta, u16 tid, u16 *ssn); 202 struct ieee80211_sta *sta, u16 tid, u16 *ssn);
203int iwlagn_tx_agg_stop(struct iwl_priv *priv, struct ieee80211_vif *vif, 203int iwlagn_tx_agg_stop(struct iwl_priv *priv, struct ieee80211_vif *vif,
204 struct ieee80211_sta *sta, u16 tid); 204 struct ieee80211_sta *sta, u16 tid);
205void iwlagn_txq_agg_queue_setup(struct iwl_priv *priv,
206 struct ieee80211_sta *sta,
207 int tid, int frame_limit);
205int iwlagn_txq_check_empty(struct iwl_priv *priv, 208int iwlagn_txq_check_empty(struct iwl_priv *priv,
206 int sta_id, u8 tid, int txq_id); 209 int sta_id, u8 tid, int txq_id);
207void iwlagn_rx_reply_compressed_ba(struct iwl_priv *priv, 210void iwlagn_rx_reply_compressed_ba(struct iwl_priv *priv,
diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h
index 68b953f2bdc7..a5d438d91821 100644
--- a/drivers/net/wireless/iwlwifi/iwl-dev.h
+++ b/drivers/net/wireless/iwlwifi/iwl-dev.h
@@ -416,6 +416,7 @@ struct iwl_ht_agg {
416#define IWL_EMPTYING_HW_QUEUE_ADDBA 2 416#define IWL_EMPTYING_HW_QUEUE_ADDBA 2
417#define IWL_EMPTYING_HW_QUEUE_DELBA 3 417#define IWL_EMPTYING_HW_QUEUE_DELBA 3
418 u8 state; 418 u8 state;
419 u8 tx_fifo;
419}; 420};
420 421
421 422