diff options
author | Helmut Schaa <helmut.schaa@googlemail.com> | 2013-01-17 20:34:32 +0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2013-01-23 01:01:29 +0400 |
commit | 84e9e8ebd369679a958200a8baca96aafb2393bb (patch) | |
tree | 7523f89f2477138e11cadeb330521a35804af969 /drivers/net/wireless/rt2x00/rt2x00queue.c | |
parent | f49aabf816afa5913e5001bd1db1c3efb4c6e19e (diff) |
rt2x00: Improve TX status handling for BlockAckReq frames
Since rt2800 hardware isn't capable of reporting the TX status of
BlockAckReq frames implement the TX status handling of BARs in
rt2x00lib. We keep track of all BARs that are send out and try to
match incoming BAs to the appropriate BARs. This allows us to report a
more or less accurate TX status for BAR frames which in turn improves
BA session stability.
This is loosley based on Christian Lamparter's patch for carl9170
"carl9170: fix HT peer BA session corruption".
We have to walk the list of pending BARs for every rx'red BA even
though most BAs don't belong to any of these BARs as they are just
acknowledging an AMPDU. To keep that overhead low use RCU which allows
us to walk the list of pending BARs without the need to acquire a lock.
This however requires us to _copy_ relevant information from the BAR
(RA, TA, control field, start sequence number) into our BAR list entry.
Signed-off-by: Helmut Schaa <helmut.schaa@googlemail.com>
Tested-by: Andreas Hartmann <andihartmann@01019freenet.de>
Acked-by: Gertjan van Wingerde <gwingerde@gmail.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/rt2x00/rt2x00queue.c')
-rw-r--r-- | drivers/net/wireless/rt2x00/rt2x00queue.c | 47 |
1 files changed, 47 insertions, 0 deletions
diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.c b/drivers/net/wireless/rt2x00/rt2x00queue.c index e488b944a034..f35d85a71bbc 100644 --- a/drivers/net/wireless/rt2x00/rt2x00queue.c +++ b/drivers/net/wireless/rt2x00/rt2x00queue.c @@ -582,6 +582,48 @@ static void rt2x00queue_kick_tx_queue(struct data_queue *queue, queue->rt2x00dev->ops->lib->kick_queue(queue); } +static void rt2x00queue_bar_check(struct queue_entry *entry) +{ + struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev; + struct ieee80211_bar *bar = (void *) (entry->skb->data + + rt2x00dev->ops->extra_tx_headroom); + struct rt2x00_bar_list_entry *bar_entry; + + if (likely(!ieee80211_is_back_req(bar->frame_control))) + return; + + bar_entry = kmalloc(sizeof(*bar_entry), GFP_ATOMIC); + + /* + * If the alloc fails we still send the BAR out but just don't track + * it in our bar list. And as a result we will report it to mac80211 + * back as failed. + */ + if (!bar_entry) + return; + + bar_entry->entry = entry; + bar_entry->block_acked = 0; + + /* + * Copy the relevant parts of the 802.11 BAR into out check list + * such that we can use RCU for less-overhead in the RX path since + * sending BARs and processing the according BlockAck should be + * the exception. + */ + memcpy(bar_entry->ra, bar->ra, sizeof(bar->ra)); + memcpy(bar_entry->ta, bar->ta, sizeof(bar->ta)); + bar_entry->control = bar->control; + bar_entry->start_seq_num = bar->start_seq_num; + + /* + * Insert BAR into our BAR check list. + */ + spin_lock_bh(&rt2x00dev->bar_list_lock); + list_add_tail_rcu(&bar_entry->list, &rt2x00dev->bar_list); + spin_unlock_bh(&rt2x00dev->bar_list_lock); +} + int rt2x00queue_write_tx_frame(struct data_queue *queue, struct sk_buff *skb, bool local) { @@ -680,6 +722,11 @@ int rt2x00queue_write_tx_frame(struct data_queue *queue, struct sk_buff *skb, goto out; } + /* + * Put BlockAckReqs into our check list for driver BA processing. + */ + rt2x00queue_bar_check(entry); + set_bit(ENTRY_DATA_PENDING, &entry->flags); rt2x00queue_index_inc(entry, Q_INDEX); |