diff options
author | Christian Lamparter <chunkeey@web.de> | 2009-03-23 07:15:43 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2009-03-27 20:13:14 -0400 |
commit | 4a48e2a484e5cf99da4795cf2d6916e057d533ad (patch) | |
tree | e4c123fcd3193eb32f8fa5464d9279bd1a07d5fd | |
parent | 04de83815993714a7ba2618f637fa1092a5f664b (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>
-rw-r--r-- | drivers/net/wireless/ar9170/ar9170.h | 2 | ||||
-rw-r--r-- | drivers/net/wireless/ar9170/hw.h | 11 | ||||
-rw-r--r-- | drivers/net/wireless/ar9170/main.c | 139 |
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 | ||
161 | struct ar9170_sta_info { | 161 | struct 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 */ |
401 | static const u8 ar9170_qos_hwmap[4] = { 3, 2, 0, 1 }; | 403 | static 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 */ |
404 | static const u8 ar9170_qos_mac80211map[4] = { 2, 3, 1, 0 }; | 406 | static const u8 ar9170_qos_mac80211map[4] = { 2, 3, 1, 0 }; |
405 | 407 | ||
408 | enum 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 | ||
280 | static 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 | |||
303 | static 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 | |||
328 | static struct sk_buff *ar9170_find_queued_skb(struct ar9170 *ar, const u8 *mac, | 280 | static 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, | |||
381 | static void ar9170_tx_status_janitor(struct work_struct *work) | 332 | static 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 | ||
416 | static void ar9170_handle_command_response(struct ar9170 *ar, | 371 | static 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 | ||