aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorJohannes Berg <johannes@sipsolutions.net>2009-03-23 12:28:42 -0400
committerJohn W. Linville <linville@tuxdriver.com>2009-03-27 20:13:23 -0400
commite4e72fb4de93e3d4047a4ee3f08778422e17ed0d (patch)
treedd133a749e6fa6960c9aa708041d996110f6440e /net
parentcd8ffc800ce18e558335c4946b2217864fc16045 (diff)
mac80211/iwlwifi: move virtual A-MDPU queue bookkeeping to iwlwifi
This patch removes all the virtual A-MPDU-queue bookkeeping from mac80211. Curiously, iwlwifi already does its own bookkeeping, so it doesn't require much changes except where it needs to handle starting and stopping the queues in mac80211. To handle the queue stop/wake properly, we rewrite the software queue number for aggregation frames and internally to iwlwifi keep track of the queues that map into the same AC queue, and only talk to mac80211 about the AC queue. The implementation requires calling two new functions, iwl_stop_queue and iwl_wake_queue instead of the mac80211 counterparts. Signed-off-by: Johannes Berg <johannes@sipsolutions.net> Cc: Reinette Chattre <reinette.chatre@intel.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'net')
-rw-r--r--net/mac80211/agg-tx.c44
-rw-r--r--net/mac80211/ieee80211_i.h7
-rw-r--r--net/mac80211/main.c9
-rw-r--r--net/mac80211/sta_info.c12
-rw-r--r--net/mac80211/sta_info.h2
-rw-r--r--net/mac80211/tx.c19
-rw-r--r--net/mac80211/util.c58
7 files changed, 11 insertions, 140 deletions
diff --git a/net/mac80211/agg-tx.c b/net/mac80211/agg-tx.c
index 64b839bfbf17..947aaaad35d2 100644
--- a/net/mac80211/agg-tx.c
+++ b/net/mac80211/agg-tx.c
@@ -131,14 +131,6 @@ static int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid,
131 131
132 state = &sta->ampdu_mlme.tid_state_tx[tid]; 132 state = &sta->ampdu_mlme.tid_state_tx[tid];
133 133
134 if (local->hw.ampdu_queues) {
135 /*
136 * Pretend the driver woke the queue, just in case
137 * it disabled it before the session was stopped.
138 */
139 ieee80211_wake_queue(
140 &local->hw, local->hw.queues + sta->tid_to_tx_q[tid]);
141 }
142 *state = HT_AGG_STATE_REQ_STOP_BA_MSK | 134 *state = HT_AGG_STATE_REQ_STOP_BA_MSK |
143 (initiator << HT_AGG_STATE_INITIATOR_SHIFT); 135 (initiator << HT_AGG_STATE_INITIATOR_SHIFT);
144 136
@@ -206,7 +198,7 @@ int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid)
206 struct sta_info *sta; 198 struct sta_info *sta;
207 struct ieee80211_sub_if_data *sdata; 199 struct ieee80211_sub_if_data *sdata;
208 u8 *state; 200 u8 *state;
209 int i, qn = -1, ret = 0; 201 int ret = 0;
210 u16 start_seq_num; 202 u16 start_seq_num;
211 203
212 if (WARN_ON(!local->ops->ampdu_action)) 204 if (WARN_ON(!local->ops->ampdu_action))
@@ -275,29 +267,6 @@ int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid)
275 goto err_unlock_sta; 267 goto err_unlock_sta;
276 } 268 }
277 269
278 if (hw->ampdu_queues) {
279 spin_lock(&local->queue_stop_reason_lock);
280 /* reserve a new queue for this session */
281 for (i = 0; i < local->hw.ampdu_queues; i++) {
282 if (local->ampdu_ac_queue[i] < 0) {
283 qn = i;
284 local->ampdu_ac_queue[qn] =
285 ieee80211_ac_from_tid(tid);
286 break;
287 }
288 }
289 spin_unlock(&local->queue_stop_reason_lock);
290
291 if (qn < 0) {
292#ifdef CONFIG_MAC80211_HT_DEBUG
293 printk(KERN_DEBUG "BA request denied - "
294 "queue unavailable for tid %d\n", tid);
295#endif /* CONFIG_MAC80211_HT_DEBUG */
296 ret = -ENOSPC;
297 goto err_unlock_sta;
298 }
299 }
300
301 /* 270 /*
302 * While we're asking the driver about the aggregation, 271 * While we're asking the driver about the aggregation,
303 * stop the AC queue so that we don't have to worry 272 * stop the AC queue so that we don't have to worry
@@ -319,7 +288,7 @@ int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid)
319 tid); 288 tid);
320#endif 289#endif
321 ret = -ENOMEM; 290 ret = -ENOMEM;
322 goto err_return_queue; 291 goto err_wake_queue;
323 } 292 }
324 293
325 skb_queue_head_init(&sta->ampdu_mlme.tid_tx[tid]->pending); 294 skb_queue_head_init(&sta->ampdu_mlme.tid_tx[tid]->pending);
@@ -348,7 +317,6 @@ int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid)
348 *state = HT_AGG_STATE_IDLE; 317 *state = HT_AGG_STATE_IDLE;
349 goto err_free; 318 goto err_free;
350 } 319 }
351 sta->tid_to_tx_q[tid] = qn;
352 320
353 /* Driver vetoed or OKed, but we can take packets again now */ 321 /* Driver vetoed or OKed, but we can take packets again now */
354 ieee80211_wake_queue_by_reason( 322 ieee80211_wake_queue_by_reason(
@@ -380,13 +348,7 @@ int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid)
380 err_free: 348 err_free:
381 kfree(sta->ampdu_mlme.tid_tx[tid]); 349 kfree(sta->ampdu_mlme.tid_tx[tid]);
382 sta->ampdu_mlme.tid_tx[tid] = NULL; 350 sta->ampdu_mlme.tid_tx[tid] = NULL;
383 err_return_queue: 351 err_wake_queue:
384 if (qn >= 0) {
385 /* give queue back to pool */
386 spin_lock(&local->queue_stop_reason_lock);
387 local->ampdu_ac_queue[qn] = -1;
388 spin_unlock(&local->queue_stop_reason_lock);
389 }
390 ieee80211_wake_queue_by_reason( 352 ieee80211_wake_queue_by_reason(
391 &local->hw, ieee80211_ac_from_tid(tid), 353 &local->hw, ieee80211_ac_from_tid(tid),
392 IEEE80211_QUEUE_STOP_REASON_AGGREGATION); 354 IEEE80211_QUEUE_STOP_REASON_AGGREGATION);
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 32345b479adb..e6ed78cb16b3 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -594,12 +594,7 @@ struct ieee80211_local {
594 594
595 const struct ieee80211_ops *ops; 595 const struct ieee80211_ops *ops;
596 596
597 /* AC queue corresponding to each AMPDU queue */ 597 unsigned long queue_stop_reasons[IEEE80211_MAX_QUEUES];
598 s8 ampdu_ac_queue[IEEE80211_MAX_AMPDU_QUEUES];
599 unsigned int amdpu_ac_stop_refcnt[IEEE80211_MAX_AMPDU_QUEUES];
600
601 unsigned long queue_stop_reasons[IEEE80211_MAX_QUEUES +
602 IEEE80211_MAX_AMPDU_QUEUES];
603 /* also used to protect ampdu_ac_queue and amdpu_ac_stop_refcnt */ 598 /* also used to protect ampdu_ac_queue and amdpu_ac_stop_refcnt */
604 spinlock_t queue_stop_reason_lock; 599 spinlock_t queue_stop_reason_lock;
605 600
diff --git a/net/mac80211/main.c b/net/mac80211/main.c
index 756284e0bbd3..a6f1d8a869bc 100644
--- a/net/mac80211/main.c
+++ b/net/mac80211/main.c
@@ -774,11 +774,6 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
774 setup_timer(&local->dynamic_ps_timer, 774 setup_timer(&local->dynamic_ps_timer,
775 ieee80211_dynamic_ps_timer, (unsigned long) local); 775 ieee80211_dynamic_ps_timer, (unsigned long) local);
776 776
777 for (i = 0; i < IEEE80211_MAX_AMPDU_QUEUES; i++)
778 local->ampdu_ac_queue[i] = -1;
779 /* using an s8 won't work with more than that */
780 BUILD_BUG_ON(IEEE80211_MAX_AMPDU_QUEUES > 127);
781
782 sta_info_init(local); 777 sta_info_init(local);
783 778
784 for (i = 0; i < IEEE80211_MAX_QUEUES; i++) 779 for (i = 0; i < IEEE80211_MAX_QUEUES; i++)
@@ -874,10 +869,6 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
874 */ 869 */
875 if (hw->queues > IEEE80211_MAX_QUEUES) 870 if (hw->queues > IEEE80211_MAX_QUEUES)
876 hw->queues = IEEE80211_MAX_QUEUES; 871 hw->queues = IEEE80211_MAX_QUEUES;
877 if (hw->ampdu_queues > IEEE80211_MAX_AMPDU_QUEUES)
878 hw->ampdu_queues = IEEE80211_MAX_AMPDU_QUEUES;
879 if (hw->queues < 4)
880 hw->ampdu_queues = 0;
881 872
882 mdev = alloc_netdev_mq(sizeof(struct ieee80211_master_priv), 873 mdev = alloc_netdev_mq(sizeof(struct ieee80211_master_priv),
883 "wmaster%d", ieee80211_master_setup, 874 "wmaster%d", ieee80211_master_setup,
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c
index dd3593c1fd23..c5f14e6bbde2 100644
--- a/net/mac80211/sta_info.c
+++ b/net/mac80211/sta_info.c
@@ -203,17 +203,6 @@ void sta_info_destroy(struct sta_info *sta)
203 if (tid_rx) 203 if (tid_rx)
204 tid_rx->shutdown = true; 204 tid_rx->shutdown = true;
205 205
206 /*
207 * The stop callback cannot find this station any more, but
208 * it didn't complete its work -- start the queue if necessary
209 */
210 if (sta->ampdu_mlme.tid_state_tx[i] & HT_AGG_STATE_INITIATOR_MSK &&
211 sta->ampdu_mlme.tid_state_tx[i] & HT_AGG_STATE_REQ_STOP_BA_MSK &&
212 local->hw.ampdu_queues)
213 ieee80211_wake_queue_by_reason(&local->hw,
214 local->hw.queues + sta->tid_to_tx_q[i],
215 IEEE80211_QUEUE_STOP_REASON_AGGREGATION);
216
217 spin_unlock_bh(&sta->lock); 206 spin_unlock_bh(&sta->lock);
218 207
219 /* 208 /*
@@ -292,7 +281,6 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata,
292 * enable session_timer's data differentiation. refer to 281 * enable session_timer's data differentiation. refer to
293 * sta_rx_agg_session_timer_expired for useage */ 282 * sta_rx_agg_session_timer_expired for useage */
294 sta->timer_to_tid[i] = i; 283 sta->timer_to_tid[i] = i;
295 sta->tid_to_tx_q[i] = -1;
296 /* rx */ 284 /* rx */
297 sta->ampdu_mlme.tid_state_rx[i] = HT_AGG_STATE_IDLE; 285 sta->ampdu_mlme.tid_state_rx[i] = HT_AGG_STATE_IDLE;
298 sta->ampdu_mlme.tid_rx[i] = NULL; 286 sta->ampdu_mlme.tid_rx[i] = NULL;
diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h
index 18fd5d1a4422..5534d489f506 100644
--- a/net/mac80211/sta_info.h
+++ b/net/mac80211/sta_info.h
@@ -206,7 +206,6 @@ struct sta_ampdu_mlme {
206 * @tid_seq: per-TID sequence numbers for sending to this STA 206 * @tid_seq: per-TID sequence numbers for sending to this STA
207 * @ampdu_mlme: A-MPDU state machine state 207 * @ampdu_mlme: A-MPDU state machine state
208 * @timer_to_tid: identity mapping to ID timers 208 * @timer_to_tid: identity mapping to ID timers
209 * @tid_to_tx_q: map tid to tx queue (invalid == negative values)
210 * @llid: Local link ID 209 * @llid: Local link ID
211 * @plid: Peer link ID 210 * @plid: Peer link ID
212 * @reason: Cancel reason on PLINK_HOLDING state 211 * @reason: Cancel reason on PLINK_HOLDING state
@@ -281,7 +280,6 @@ struct sta_info {
281 */ 280 */
282 struct sta_ampdu_mlme ampdu_mlme; 281 struct sta_ampdu_mlme ampdu_mlme;
283 u8 timer_to_tid[STA_TID_NUM]; 282 u8 timer_to_tid[STA_TID_NUM];
284 s8 tid_to_tx_q[STA_TID_NUM];
285 283
286#ifdef CONFIG_MAC80211_MESH 284#ifdef CONFIG_MAC80211_MESH
287 /* 285 /*
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index 906ab785db40..3fb04a86444d 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -1145,25 +1145,6 @@ static int __ieee80211_tx(struct ieee80211_local *local,
1145 info->flags &= ~(IEEE80211_TX_CTL_CLEAR_PS_FILT | 1145 info->flags &= ~(IEEE80211_TX_CTL_CLEAR_PS_FILT |
1146 IEEE80211_TX_CTL_FIRST_FRAGMENT); 1146 IEEE80211_TX_CTL_FIRST_FRAGMENT);
1147 1147
1148 /*
1149 * Internally, we need to have the queue mapping point to
1150 * the real AC queue, not the virtual A-MPDU queue. This
1151 * now finally sets the queue to what the driver wants.
1152 * We will later move this down into the only driver that
1153 * needs it, iwlwifi.
1154 */
1155 if (sta && local->hw.ampdu_queues &&
1156 info->flags & IEEE80211_TX_CTL_AMPDU) {
1157 unsigned long flags;
1158 u8 *qc = ieee80211_get_qos_ctl((void *) skb->data);
1159 int tid = *qc & IEEE80211_QOS_CTL_TID_MASK;
1160
1161 spin_lock_irqsave(&sta->lock, flags);
1162 skb_set_queue_mapping(skb, local->hw.queues +
1163 sta->tid_to_tx_q[tid]);
1164 spin_unlock_irqrestore(&sta->lock, flags);
1165 }
1166
1167 next = skb->next; 1148 next = skb->next;
1168 len = skb->len; 1149 len = skb->len;
1169 ret = local->ops->tx(local_to_hw(local), skb); 1150 ret = local->ops->tx(local_to_hw(local), skb);
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index 0247d8022f5f..fdf432f14554 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -339,29 +339,8 @@ static void __ieee80211_wake_queue(struct ieee80211_hw *hw, int queue,
339{ 339{
340 struct ieee80211_local *local = hw_to_local(hw); 340 struct ieee80211_local *local = hw_to_local(hw);
341 341
342 if (queue >= hw->queues) { 342 if (WARN_ON(queue >= hw->queues))
343 if (local->ampdu_ac_queue[queue - hw->queues] < 0) 343 return;
344 return;
345
346 /*
347 * for virtual aggregation queues, we need to refcount the
348 * internal mac80211 disable (multiple times!), keep track of
349 * driver disable _and_ make sure the regular queue is
350 * actually enabled.
351 */
352 if (reason == IEEE80211_QUEUE_STOP_REASON_AGGREGATION)
353 local->amdpu_ac_stop_refcnt[queue - hw->queues]--;
354 else
355 __clear_bit(reason, &local->queue_stop_reasons[queue]);
356
357 if (local->queue_stop_reasons[queue] ||
358 local->amdpu_ac_stop_refcnt[queue - hw->queues])
359 return;
360
361 /* now go on to treat the corresponding regular queue */
362 queue = local->ampdu_ac_queue[queue - hw->queues];
363 reason = IEEE80211_QUEUE_STOP_REASON_AGGREGATION;
364 }
365 344
366 __clear_bit(reason, &local->queue_stop_reasons[queue]); 345 __clear_bit(reason, &local->queue_stop_reasons[queue]);
367 346
@@ -400,25 +379,8 @@ static void __ieee80211_stop_queue(struct ieee80211_hw *hw, int queue,
400{ 379{
401 struct ieee80211_local *local = hw_to_local(hw); 380 struct ieee80211_local *local = hw_to_local(hw);
402 381
403 if (queue >= hw->queues) { 382 if (WARN_ON(queue >= hw->queues))
404 if (local->ampdu_ac_queue[queue - hw->queues] < 0) 383 return;
405 return;
406
407 /*
408 * for virtual aggregation queues, we need to refcount the
409 * internal mac80211 disable (multiple times!), keep track of
410 * driver disable _and_ make sure the regular queue is
411 * actually enabled.
412 */
413 if (reason == IEEE80211_QUEUE_STOP_REASON_AGGREGATION)
414 local->amdpu_ac_stop_refcnt[queue - hw->queues]++;
415 else
416 __set_bit(reason, &local->queue_stop_reasons[queue]);
417
418 /* now go on to treat the corresponding regular queue */
419 queue = local->ampdu_ac_queue[queue - hw->queues];
420 reason = IEEE80211_QUEUE_STOP_REASON_AGGREGATION;
421 }
422 384
423 /* 385 /*
424 * Only stop if it was previously running, this is necessary 386 * Only stop if it was previously running, this is necessary
@@ -474,15 +436,9 @@ EXPORT_SYMBOL(ieee80211_stop_queues);
474int ieee80211_queue_stopped(struct ieee80211_hw *hw, int queue) 436int ieee80211_queue_stopped(struct ieee80211_hw *hw, int queue)
475{ 437{
476 struct ieee80211_local *local = hw_to_local(hw); 438 struct ieee80211_local *local = hw_to_local(hw);
477 unsigned long flags;
478 439
479 if (queue >= hw->queues) { 440 if (WARN_ON(queue >= hw->queues))
480 spin_lock_irqsave(&local->queue_stop_reason_lock, flags); 441 return true;
481 queue = local->ampdu_ac_queue[queue - hw->queues];
482 spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
483 if (queue < 0)
484 return true;
485 }
486 442
487 return __netif_subqueue_stopped(local->mdev, queue); 443 return __netif_subqueue_stopped(local->mdev, queue);
488} 444}
@@ -497,7 +453,7 @@ void ieee80211_wake_queues_by_reason(struct ieee80211_hw *hw,
497 453
498 spin_lock_irqsave(&local->queue_stop_reason_lock, flags); 454 spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
499 455
500 for (i = 0; i < hw->queues + hw->ampdu_queues; i++) 456 for (i = 0; i < hw->queues; i++)
501 __ieee80211_wake_queue(hw, i, reason); 457 __ieee80211_wake_queue(hw, i, reason);
502 458
503 spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); 459 spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);