diff options
author | Christian Lamparter <chunkeey@googlemail.com> | 2011-04-24 11:44:19 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2011-04-26 15:50:30 -0400 |
commit | caf1eae206688210f61f3b48627ce4ca3c709784 (patch) | |
tree | 81afc8accccdf900e01fa9c3cd3697a1724fc8c3 /drivers/net/wireless/ath/carl9170/main.c | |
parent | be8d98eab81d1f6445461a1631513f7091805e53 (diff) |
carl9170: improve unicast PS buffering
Using the ieee80211_sta_block allows the PS code
to handle awake->doze->awake transitions of our
clients in a race-free manner.
Signed-off-by: Christian Lamparter <chunkeey@googlemail.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/ath/carl9170/main.c')
-rw-r--r-- | drivers/net/wireless/ath/carl9170/main.c | 92 |
1 files changed, 6 insertions, 86 deletions
diff --git a/drivers/net/wireless/ath/carl9170/main.c b/drivers/net/wireless/ath/carl9170/main.c index 89fe60accf8..1638468be5a 100644 --- a/drivers/net/wireless/ath/carl9170/main.c +++ b/drivers/net/wireless/ath/carl9170/main.c | |||
@@ -1193,6 +1193,8 @@ static int carl9170_op_sta_add(struct ieee80211_hw *hw, | |||
1193 | struct carl9170_sta_info *sta_info = (void *) sta->drv_priv; | 1193 | struct carl9170_sta_info *sta_info = (void *) sta->drv_priv; |
1194 | unsigned int i; | 1194 | unsigned int i; |
1195 | 1195 | ||
1196 | atomic_set(&sta_info->pending_frames, 0); | ||
1197 | |||
1196 | if (sta->ht_cap.ht_supported) { | 1198 | if (sta->ht_cap.ht_supported) { |
1197 | if (sta->ht_cap.ampdu_density > 6) { | 1199 | if (sta->ht_cap.ampdu_density > 6) { |
1198 | /* | 1200 | /* |
@@ -1467,99 +1469,17 @@ static void carl9170_op_sta_notify(struct ieee80211_hw *hw, | |||
1467 | enum sta_notify_cmd cmd, | 1469 | enum sta_notify_cmd cmd, |
1468 | struct ieee80211_sta *sta) | 1470 | struct ieee80211_sta *sta) |
1469 | { | 1471 | { |
1470 | struct ar9170 *ar = hw->priv; | ||
1471 | struct carl9170_sta_info *sta_info = (void *) sta->drv_priv; | 1472 | struct carl9170_sta_info *sta_info = (void *) sta->drv_priv; |
1472 | struct sk_buff *skb, *tmp; | ||
1473 | struct sk_buff_head free; | ||
1474 | int i; | ||
1475 | 1473 | ||
1476 | switch (cmd) { | 1474 | switch (cmd) { |
1477 | case STA_NOTIFY_SLEEP: | 1475 | case STA_NOTIFY_SLEEP: |
1478 | /* | 1476 | sta_info->sleeping = true; |
1479 | * Since the peer is no longer listening, we have to return | 1477 | if (atomic_read(&sta_info->pending_frames)) |
1480 | * as many SKBs as possible back to the mac80211 stack. | 1478 | ieee80211_sta_block_awake(hw, sta, true); |
1481 | * It will deal with the retry procedure, once the peer | ||
1482 | * has become available again. | ||
1483 | * | ||
1484 | * NB: Ideally, the driver should return the all frames in | ||
1485 | * the correct, ascending order. However, I think that this | ||
1486 | * functionality should be implemented in the stack and not | ||
1487 | * here... | ||
1488 | */ | ||
1489 | |||
1490 | __skb_queue_head_init(&free); | ||
1491 | |||
1492 | if (sta->ht_cap.ht_supported) { | ||
1493 | rcu_read_lock(); | ||
1494 | for (i = 0; i < CARL9170_NUM_TID; i++) { | ||
1495 | struct carl9170_sta_tid *tid_info; | ||
1496 | |||
1497 | tid_info = rcu_dereference(sta_info->agg[i]); | ||
1498 | |||
1499 | if (!tid_info) | ||
1500 | continue; | ||
1501 | |||
1502 | spin_lock_bh(&ar->tx_ampdu_list_lock); | ||
1503 | if (tid_info->state > | ||
1504 | CARL9170_TID_STATE_SUSPEND) | ||
1505 | tid_info->state = | ||
1506 | CARL9170_TID_STATE_SUSPEND; | ||
1507 | spin_unlock_bh(&ar->tx_ampdu_list_lock); | ||
1508 | |||
1509 | spin_lock_bh(&tid_info->lock); | ||
1510 | while ((skb = __skb_dequeue(&tid_info->queue))) | ||
1511 | __skb_queue_tail(&free, skb); | ||
1512 | spin_unlock_bh(&tid_info->lock); | ||
1513 | } | ||
1514 | rcu_read_unlock(); | ||
1515 | } | ||
1516 | |||
1517 | for (i = 0; i < ar->hw->queues; i++) { | ||
1518 | spin_lock_bh(&ar->tx_pending[i].lock); | ||
1519 | skb_queue_walk_safe(&ar->tx_pending[i], skb, tmp) { | ||
1520 | struct _carl9170_tx_superframe *super; | ||
1521 | struct ieee80211_hdr *hdr; | ||
1522 | struct ieee80211_tx_info *info; | ||
1523 | |||
1524 | super = (void *) skb->data; | ||
1525 | hdr = (void *) super->frame_data; | ||
1526 | |||
1527 | if (compare_ether_addr(hdr->addr1, sta->addr)) | ||
1528 | continue; | ||
1529 | |||
1530 | __skb_unlink(skb, &ar->tx_pending[i]); | ||
1531 | |||
1532 | info = IEEE80211_SKB_CB(skb); | ||
1533 | if (info->flags & IEEE80211_TX_CTL_AMPDU) | ||
1534 | atomic_dec(&ar->tx_ampdu_upload); | ||
1535 | |||
1536 | carl9170_tx_status(ar, skb, false); | ||
1537 | } | ||
1538 | spin_unlock_bh(&ar->tx_pending[i].lock); | ||
1539 | } | ||
1540 | |||
1541 | while ((skb = __skb_dequeue(&free))) | ||
1542 | carl9170_tx_status(ar, skb, false); | ||
1543 | |||
1544 | break; | 1479 | break; |
1545 | 1480 | ||
1546 | case STA_NOTIFY_AWAKE: | 1481 | case STA_NOTIFY_AWAKE: |
1547 | if (!sta->ht_cap.ht_supported) | 1482 | sta_info->sleeping = false; |
1548 | return; | ||
1549 | |||
1550 | rcu_read_lock(); | ||
1551 | for (i = 0; i < CARL9170_NUM_TID; i++) { | ||
1552 | struct carl9170_sta_tid *tid_info; | ||
1553 | |||
1554 | tid_info = rcu_dereference(sta_info->agg[i]); | ||
1555 | |||
1556 | if (!tid_info) | ||
1557 | continue; | ||
1558 | |||
1559 | if ((tid_info->state == CARL9170_TID_STATE_SUSPEND)) | ||
1560 | tid_info->state = CARL9170_TID_STATE_IDLE; | ||
1561 | } | ||
1562 | rcu_read_unlock(); | ||
1563 | break; | 1483 | break; |
1564 | } | 1484 | } |
1565 | } | 1485 | } |