aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorChristian Lamparter <chunkeey@web.de>2009-03-23 07:15:43 -0400
committerJohn W. Linville <linville@tuxdriver.com>2009-03-27 20:13:14 -0400
commit4a48e2a484e5cf99da4795cf2d6916e057d533ad (patch)
treee4c123fcd3193eb32f8fa5464d9279bd1a07d5fd /drivers
parent04de83815993714a7ba2618f637fa1092a5f664b (diff)
ar9170: simplify & deBUG tx_status queueing and reporting
This patch simplifies the tx_status report code by using four tx_queues per station instead of only one. (the skb lookup should be in O(1) now :-p ). Also, it fixes a really obvious copy&paste bug in the janitor work code and adds back a few spilled bits to the hardware definition header about QoS. Signed-off-by: Christian Lamparter <chunkeey@web.de> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/net/wireless/ar9170/ar9170.h2
-rw-r--r--drivers/net/wireless/ar9170/hw.h11
-rw-r--r--drivers/net/wireless/ar9170/main.c139
3 files changed, 49 insertions, 103 deletions
diff --git a/drivers/net/wireless/ar9170/ar9170.h b/drivers/net/wireless/ar9170/ar9170.h
index c49d7138d574..f4fb2e94aea0 100644
--- a/drivers/net/wireless/ar9170/ar9170.h
+++ b/drivers/net/wireless/ar9170/ar9170.h
@@ -159,7 +159,7 @@ struct ar9170 {
159}; 159};
160 160
161struct ar9170_sta_info { 161struct ar9170_sta_info {
162 struct sk_buff_head tx_status; 162 struct sk_buff_head tx_status[__AR9170_NUM_TXQ];
163}; 163};
164 164
165#define IS_STARTED(a) (a->state >= AR9170_STARTED) 165#define IS_STARTED(a) (a->state >= AR9170_STARTED)
diff --git a/drivers/net/wireless/ar9170/hw.h b/drivers/net/wireless/ar9170/hw.h
index ad205f82f60a..13091bd9d815 100644
--- a/drivers/net/wireless/ar9170/hw.h
+++ b/drivers/net/wireless/ar9170/hw.h
@@ -397,10 +397,21 @@ struct ar9170_cmd_response {
397 }; 397 };
398} __packed; 398} __packed;
399 399
400/* QoS */
401
400/* mac80211 queue to HW/FW map */ 402/* mac80211 queue to HW/FW map */
401static const u8 ar9170_qos_hwmap[4] = { 3, 2, 0, 1 }; 403static const u8 ar9170_qos_hwmap[4] = { 3, 2, 0, 1 };
402 404
403/* HW/FW queue to mac80211 map */ 405/* HW/FW queue to mac80211 map */
404static const u8 ar9170_qos_mac80211map[4] = { 2, 3, 1, 0 }; 406static const u8 ar9170_qos_mac80211map[4] = { 2, 3, 1, 0 };
405 407
408enum ar9170_txq {
409 AR9170_TXQ_BE,
410 AR9170_TXQ_BK,
411 AR9170_TXQ_VI,
412 AR9170_TXQ_VO,
413
414 __AR9170_NUM_TXQ,
415};
416
406#endif /* __AR9170_HW_H */ 417#endif /* __AR9170_HW_H */
diff --git a/drivers/net/wireless/ar9170/main.c b/drivers/net/wireless/ar9170/main.c
index a3b5323743c7..f8c2357a1738 100644
--- a/drivers/net/wireless/ar9170/main.c
+++ b/drivers/net/wireless/ar9170/main.c
@@ -277,54 +277,6 @@ static struct sk_buff *ar9170_find_skb_in_queue(struct ar9170 *ar,
277 return NULL; 277 return NULL;
278} 278}
279 279
280static struct sk_buff *ar9170_find_skb_in_queue_by_mac(struct ar9170 *ar,
281 const u8 *mac,
282 struct sk_buff_head *q)
283{
284 unsigned long flags;
285 struct sk_buff *skb;
286
287 spin_lock_irqsave(&q->lock, flags);
288 skb_queue_walk(q, skb) {
289 struct ar9170_tx_control *txc = (void *) skb->data;
290 struct ieee80211_hdr *hdr = (void *) txc->frame_data;
291
292 if (compare_ether_addr(ieee80211_get_DA(hdr), mac))
293 continue;
294
295 __skb_unlink(skb, q);
296 spin_unlock_irqrestore(&q->lock, flags);
297 return skb;
298 }
299 spin_unlock_irqrestore(&q->lock, flags);
300 return NULL;
301}
302
303static struct sk_buff *ar9170_find_skb_in_queue_by_txcq(struct ar9170 *ar,
304 const u32 queue,
305 struct sk_buff_head *q)
306{
307 unsigned long flags;
308 struct sk_buff *skb;
309
310 spin_lock_irqsave(&q->lock, flags);
311 skb_queue_walk(q, skb) {
312 struct ar9170_tx_control *txc = (void *) skb->data;
313 u32 txc_queue = (le32_to_cpu(txc->phy_control) &
314 AR9170_TX_PHY_QOS_MASK) >>
315 AR9170_TX_PHY_QOS_SHIFT;
316
317 if (queue != txc_queue)
318 continue;
319
320 __skb_unlink(skb, q);
321 spin_unlock_irqrestore(&q->lock, flags);
322 return skb;
323 }
324 spin_unlock_irqrestore(&q->lock, flags);
325 return NULL;
326}
327
328static struct sk_buff *ar9170_find_queued_skb(struct ar9170 *ar, const u8 *mac, 280static struct sk_buff *ar9170_find_queued_skb(struct ar9170 *ar, const u8 *mac,
329 const u32 queue) 281 const u32 queue)
330{ 282{
@@ -344,21 +296,21 @@ static struct sk_buff *ar9170_find_queued_skb(struct ar9170 *ar, const u8 *mac,
344 296
345 if (likely(sta)) { 297 if (likely(sta)) {
346 struct ar9170_sta_info *sta_priv = (void *) sta->drv_priv; 298 struct ar9170_sta_info *sta_priv = (void *) sta->drv_priv;
347 skb = ar9170_find_skb_in_queue_by_txcq(ar, queue, 299 skb = skb_dequeue(&sta_priv->tx_status[queue]);
348 &sta_priv->tx_status); 300 rcu_read_unlock();
349 } else { 301 if (likely(skb))
350 /* STA is not in database (yet/anymore). */ 302 return skb;
303 } else
304 rcu_read_unlock();
351 305
352 /* scan the waste bin for likely candidates */ 306 /* scan the waste queue for candidates */
307 skb = ar9170_find_skb_in_queue(ar, mac, queue,
308 &ar->global_tx_status_waste);
309 if (!skb) {
310 /* so it still _must_ be in the global list. */
353 skb = ar9170_find_skb_in_queue(ar, mac, queue, 311 skb = ar9170_find_skb_in_queue(ar, mac, queue,
354 &ar->global_tx_status_waste); 312 &ar->global_tx_status);
355 if (!skb) {
356 /* so it still _must_ be in the global list. */
357 skb = ar9170_find_skb_in_queue(ar, mac, queue,
358 &ar->global_tx_status);
359 }
360 } 313 }
361 rcu_read_unlock();
362 314
363#ifdef AR9170_QUEUE_DEBUG 315#ifdef AR9170_QUEUE_DEBUG
364 if (unlikely((!skb) && net_ratelimit())) { 316 if (unlikely((!skb) && net_ratelimit())) {
@@ -367,7 +319,6 @@ static struct sk_buff *ar9170_find_queued_skb(struct ar9170 *ar, const u8 *mac,
367 wiphy_name(ar->hw->wiphy), mac, queue); 319 wiphy_name(ar->hw->wiphy), mac, queue);
368 } 320 }
369#endif /* AR9170_QUEUE_DEBUG */ 321#endif /* AR9170_QUEUE_DEBUG */
370
371 return skb; 322 return skb;
372} 323}
373 324
@@ -381,9 +332,13 @@ static struct sk_buff *ar9170_find_queued_skb(struct ar9170 *ar, const u8 *mac,
381static void ar9170_tx_status_janitor(struct work_struct *work) 332static void ar9170_tx_status_janitor(struct work_struct *work)
382{ 333{
383 struct ar9170 *ar = container_of(work, struct ar9170, 334 struct ar9170 *ar = container_of(work, struct ar9170,
384 filter_config_work); 335 tx_status_janitor.work);
385 struct sk_buff *skb; 336 struct sk_buff *skb;
386 337
338 if (unlikely(!IS_STARTED(ar)))
339 return ;
340
341 mutex_lock(&ar->mutex);
387 /* recycle the garbage back to mac80211... one by one. */ 342 /* recycle the garbage back to mac80211... one by one. */
388 while ((skb = skb_dequeue(&ar->global_tx_status_waste))) { 343 while ((skb = skb_dequeue(&ar->global_tx_status_waste))) {
389#ifdef AR9170_QUEUE_DEBUG 344#ifdef AR9170_QUEUE_DEBUG
@@ -395,8 +350,6 @@ static void ar9170_tx_status_janitor(struct work_struct *work)
395 AR9170_TX_STATUS_FAILED); 350 AR9170_TX_STATUS_FAILED);
396 } 351 }
397 352
398
399
400 while ((skb = skb_dequeue(&ar->global_tx_status))) { 353 while ((skb = skb_dequeue(&ar->global_tx_status))) {
401#ifdef AR9170_QUEUE_DEBUG 354#ifdef AR9170_QUEUE_DEBUG
402 printk(KERN_DEBUG "%s: moving frame into waste queue =>\n", 355 printk(KERN_DEBUG "%s: moving frame into waste queue =>\n",
@@ -411,6 +364,8 @@ static void ar9170_tx_status_janitor(struct work_struct *work)
411 if (skb_queue_len(&ar->global_tx_status_waste) > 0) 364 if (skb_queue_len(&ar->global_tx_status_waste) > 0)
412 queue_delayed_work(ar->hw->workqueue, &ar->tx_status_janitor, 365 queue_delayed_work(ar->hw->workqueue, &ar->tx_status_janitor,
413 msecs_to_jiffies(100)); 366 msecs_to_jiffies(100));
367
368 mutex_unlock(&ar->mutex);
414} 369}
415 370
416static void ar9170_handle_command_response(struct ar9170 *ar, 371static void ar9170_handle_command_response(struct ar9170 *ar,
@@ -1012,7 +967,7 @@ int ar9170_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
1012 967
1013 if (info->control.sta) { 968 if (info->control.sta) {
1014 sta_info = (void *) info->control.sta->drv_priv; 969 sta_info = (void *) info->control.sta->drv_priv;
1015 skb_queue_tail(&sta_info->tx_status, skb); 970 skb_queue_tail(&sta_info->tx_status[queue], skb);
1016 } else { 971 } else {
1017 skb_queue_tail(&ar->global_tx_status, skb); 972 skb_queue_tail(&ar->global_tx_status, skb);
1018 973
@@ -1025,7 +980,7 @@ int ar9170_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
1025 err = ar->tx(ar, skb, tx_status, 0); 980 err = ar->tx(ar, skb, tx_status, 0);
1026 if (unlikely(tx_status && err)) { 981 if (unlikely(tx_status && err)) {
1027 if (info->control.sta) 982 if (info->control.sta)
1028 skb_unlink(skb, &sta_info->tx_status); 983 skb_unlink(skb, &sta_info->tx_status[queue]);
1029 else 984 else
1030 skb_unlink(skb, &ar->global_tx_status); 985 skb_unlink(skb, &ar->global_tx_status);
1031 } 986 }
@@ -1479,55 +1434,35 @@ static void ar9170_sta_notify(struct ieee80211_hw *hw,
1479 struct ar9170 *ar = hw->priv; 1434 struct ar9170 *ar = hw->priv;
1480 struct ar9170_sta_info *info = (void *) sta->drv_priv; 1435 struct ar9170_sta_info *info = (void *) sta->drv_priv;
1481 struct sk_buff *skb; 1436 struct sk_buff *skb;
1437 unsigned int i;
1482 1438
1483 switch (cmd) { 1439 switch (cmd) {
1484 case STA_NOTIFY_ADD: 1440 case STA_NOTIFY_ADD:
1485 skb_queue_head_init(&info->tx_status); 1441 for (i = 0; i < ar->hw->queues; i++)
1486 1442 skb_queue_head_init(&info->tx_status[i]);
1487 /*
1488 * do we already have a frame that needs tx_status
1489 * from this station in our queue?
1490 * If so then transfer them to the new station queue.
1491 */
1492
1493 /* preserve the correct order - check the waste bin first */
1494 while ((skb = ar9170_find_skb_in_queue_by_mac(ar, sta->addr,
1495 &ar->global_tx_status_waste)))
1496 skb_queue_tail(&info->tx_status, skb);
1497
1498 /* now the still pending frames */
1499 while ((skb = ar9170_find_skb_in_queue_by_mac(ar, sta->addr,
1500 &ar->global_tx_status)))
1501 skb_queue_tail(&info->tx_status, skb);
1502
1503#ifdef AR9170_QUEUE_DEBUG
1504 printk(KERN_DEBUG "%s: STA[%pM] has %d queued frames =>\n",
1505 wiphy_name(ar->hw->wiphy), sta->addr,
1506 skb_queue_len(&info->tx_status));
1507
1508 ar9170_dump_station_tx_status_queue(ar, &info->tx_status);
1509#endif /* AR9170_QUEUE_DEBUG */
1510
1511
1512 break; 1443 break;
1513 1444
1514 case STA_NOTIFY_REMOVE: 1445 case STA_NOTIFY_REMOVE:
1515 1446
1516 /* 1447 /*
1517 * transfer all outstanding frames that need a tx_status 1448 * transfer all outstanding frames that need a tx_status
1518 * reports to the fallback queue 1449 * reports to the global tx_status queue
1519 */ 1450 */
1520 1451
1521 while ((skb = skb_dequeue(&ar->global_tx_status))) { 1452 for (i = 0; i < ar->hw->queues; i++) {
1453 while ((skb = skb_dequeue(&info->tx_status[i]))) {
1522#ifdef AR9170_QUEUE_DEBUG 1454#ifdef AR9170_QUEUE_DEBUG
1523 printk(KERN_DEBUG "%s: queueing frame in global " 1455 printk(KERN_DEBUG "%s: queueing frame in "
1524 "tx_status queue =>\n", 1456 "global tx_status queue =>\n",
1525 wiphy_name(ar->hw->wiphy)); 1457 wiphy_name(ar->hw->wiphy));
1526 1458
1527 ar9170_print_txheader(ar, skb); 1459 ar9170_print_txheader(ar, skb);
1528#endif /* AR9170_QUEUE_DEBUG */ 1460#endif /* AR9170_QUEUE_DEBUG */
1529 skb_queue_tail(&ar->global_tx_status_waste, skb); 1461 skb_queue_tail(&ar->global_tx_status, skb);
1462 }
1530 } 1463 }
1464 queue_delayed_work(ar->hw->workqueue, &ar->tx_status_janitor,
1465 msecs_to_jiffies(100));
1531 break; 1466 break;
1532 1467
1533 default: 1468 default:
@@ -1571,7 +1506,7 @@ static int ar9170_conf_tx(struct ieee80211_hw *hw, u16 queue,
1571 int ret; 1506 int ret;
1572 1507
1573 mutex_lock(&ar->mutex); 1508 mutex_lock(&ar->mutex);
1574 if ((param) && !(queue > 4)) { 1509 if ((param) && !(queue > ar->hw->queues)) {
1575 memcpy(&ar->edcf[ar9170_qos_hwmap[queue]], 1510 memcpy(&ar->edcf[ar9170_qos_hwmap[queue]],
1576 param, sizeof(*param)); 1511 param, sizeof(*param));
1577 1512
@@ -1635,7 +1570,7 @@ void *ar9170_alloc(size_t priv_size)
1635 IEEE80211_HW_SIGNAL_DBM | 1570 IEEE80211_HW_SIGNAL_DBM |
1636 IEEE80211_HW_NOISE_DBM; 1571 IEEE80211_HW_NOISE_DBM;
1637 1572
1638 ar->hw->queues = 4; 1573 ar->hw->queues = __AR9170_NUM_TXQ;
1639 ar->hw->extra_tx_headroom = 8; 1574 ar->hw->extra_tx_headroom = 8;
1640 ar->hw->sta_data_size = sizeof(struct ar9170_sta_info); 1575 ar->hw->sta_data_size = sizeof(struct ar9170_sta_info);
1641 1576