diff options
Diffstat (limited to 'drivers/net/wireless/rt2x00/rt2x00dev.c')
-rw-r--r-- | drivers/net/wireless/rt2x00/rt2x00dev.c | 101 |
1 files changed, 100 insertions, 1 deletions
diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c index 44f8b3f3cbed..b40a53857498 100644 --- a/drivers/net/wireless/rt2x00/rt2x00dev.c +++ b/drivers/net/wireless/rt2x00/rt2x00dev.c | |||
@@ -271,6 +271,50 @@ void rt2x00lib_dmadone(struct queue_entry *entry) | |||
271 | } | 271 | } |
272 | EXPORT_SYMBOL_GPL(rt2x00lib_dmadone); | 272 | EXPORT_SYMBOL_GPL(rt2x00lib_dmadone); |
273 | 273 | ||
274 | static inline int rt2x00lib_txdone_bar_status(struct queue_entry *entry) | ||
275 | { | ||
276 | struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev; | ||
277 | struct ieee80211_bar *bar = (void *) entry->skb->data; | ||
278 | struct rt2x00_bar_list_entry *bar_entry; | ||
279 | int ret; | ||
280 | |||
281 | if (likely(!ieee80211_is_back_req(bar->frame_control))) | ||
282 | return 0; | ||
283 | |||
284 | /* | ||
285 | * Unlike all other frames, the status report for BARs does | ||
286 | * not directly come from the hardware as it is incapable of | ||
287 | * matching a BA to a previously send BAR. The hardware will | ||
288 | * report all BARs as if they weren't acked at all. | ||
289 | * | ||
290 | * Instead the RX-path will scan for incoming BAs and set the | ||
291 | * block_acked flag if it sees one that was likely caused by | ||
292 | * a BAR from us. | ||
293 | * | ||
294 | * Remove remaining BARs here and return their status for | ||
295 | * TX done processing. | ||
296 | */ | ||
297 | ret = 0; | ||
298 | rcu_read_lock(); | ||
299 | list_for_each_entry_rcu(bar_entry, &rt2x00dev->bar_list, list) { | ||
300 | if (bar_entry->entry != entry) | ||
301 | continue; | ||
302 | |||
303 | spin_lock_bh(&rt2x00dev->bar_list_lock); | ||
304 | /* Return whether this BAR was blockacked or not */ | ||
305 | ret = bar_entry->block_acked; | ||
306 | /* Remove the BAR from our checklist */ | ||
307 | list_del_rcu(&bar_entry->list); | ||
308 | spin_unlock_bh(&rt2x00dev->bar_list_lock); | ||
309 | kfree_rcu(bar_entry, head); | ||
310 | |||
311 | break; | ||
312 | } | ||
313 | rcu_read_unlock(); | ||
314 | |||
315 | return ret; | ||
316 | } | ||
317 | |||
274 | void rt2x00lib_txdone(struct queue_entry *entry, | 318 | void rt2x00lib_txdone(struct queue_entry *entry, |
275 | struct txdone_entry_desc *txdesc) | 319 | struct txdone_entry_desc *txdesc) |
276 | { | 320 | { |
@@ -324,9 +368,12 @@ void rt2x00lib_txdone(struct queue_entry *entry, | |||
324 | rt2x00debug_dump_frame(rt2x00dev, DUMP_FRAME_TXDONE, entry->skb); | 368 | rt2x00debug_dump_frame(rt2x00dev, DUMP_FRAME_TXDONE, entry->skb); |
325 | 369 | ||
326 | /* | 370 | /* |
327 | * Determine if the frame has been successfully transmitted. | 371 | * Determine if the frame has been successfully transmitted and |
372 | * remove BARs from our check list while checking for their | ||
373 | * TX status. | ||
328 | */ | 374 | */ |
329 | success = | 375 | success = |
376 | rt2x00lib_txdone_bar_status(entry) || | ||
330 | test_bit(TXDONE_SUCCESS, &txdesc->flags) || | 377 | test_bit(TXDONE_SUCCESS, &txdesc->flags) || |
331 | test_bit(TXDONE_UNKNOWN, &txdesc->flags); | 378 | test_bit(TXDONE_UNKNOWN, &txdesc->flags); |
332 | 379 | ||
@@ -491,6 +538,50 @@ static void rt2x00lib_sleep(struct work_struct *work) | |||
491 | IEEE80211_CONF_CHANGE_PS); | 538 | IEEE80211_CONF_CHANGE_PS); |
492 | } | 539 | } |
493 | 540 | ||
541 | static void rt2x00lib_rxdone_check_ba(struct rt2x00_dev *rt2x00dev, | ||
542 | struct sk_buff *skb, | ||
543 | struct rxdone_entry_desc *rxdesc) | ||
544 | { | ||
545 | struct rt2x00_bar_list_entry *entry; | ||
546 | struct ieee80211_bar *ba = (void *)skb->data; | ||
547 | |||
548 | if (likely(!ieee80211_is_back(ba->frame_control))) | ||
549 | return; | ||
550 | |||
551 | if (rxdesc->size < sizeof(*ba) + FCS_LEN) | ||
552 | return; | ||
553 | |||
554 | rcu_read_lock(); | ||
555 | list_for_each_entry_rcu(entry, &rt2x00dev->bar_list, list) { | ||
556 | |||
557 | if (ba->start_seq_num != entry->start_seq_num) | ||
558 | continue; | ||
559 | |||
560 | #define TID_CHECK(a, b) ( \ | ||
561 | ((a) & cpu_to_le16(IEEE80211_BAR_CTRL_TID_INFO_MASK)) == \ | ||
562 | ((b) & cpu_to_le16(IEEE80211_BAR_CTRL_TID_INFO_MASK))) \ | ||
563 | |||
564 | if (!TID_CHECK(ba->control, entry->control)) | ||
565 | continue; | ||
566 | |||
567 | #undef TID_CHECK | ||
568 | |||
569 | if (compare_ether_addr(ba->ra, entry->ta)) | ||
570 | continue; | ||
571 | |||
572 | if (compare_ether_addr(ba->ta, entry->ra)) | ||
573 | continue; | ||
574 | |||
575 | /* Mark BAR since we received the according BA */ | ||
576 | spin_lock_bh(&rt2x00dev->bar_list_lock); | ||
577 | entry->block_acked = 1; | ||
578 | spin_unlock_bh(&rt2x00dev->bar_list_lock); | ||
579 | break; | ||
580 | } | ||
581 | rcu_read_unlock(); | ||
582 | |||
583 | } | ||
584 | |||
494 | static void rt2x00lib_rxdone_check_ps(struct rt2x00_dev *rt2x00dev, | 585 | static void rt2x00lib_rxdone_check_ps(struct rt2x00_dev *rt2x00dev, |
495 | struct sk_buff *skb, | 586 | struct sk_buff *skb, |
496 | struct rxdone_entry_desc *rxdesc) | 587 | struct rxdone_entry_desc *rxdesc) |
@@ -674,6 +765,12 @@ void rt2x00lib_rxdone(struct queue_entry *entry, gfp_t gfp) | |||
674 | rt2x00lib_rxdone_check_ps(rt2x00dev, entry->skb, &rxdesc); | 765 | rt2x00lib_rxdone_check_ps(rt2x00dev, entry->skb, &rxdesc); |
675 | 766 | ||
676 | /* | 767 | /* |
768 | * Check for incoming BlockAcks to match to the BlockAckReqs | ||
769 | * we've send out. | ||
770 | */ | ||
771 | rt2x00lib_rxdone_check_ba(rt2x00dev, entry->skb, &rxdesc); | ||
772 | |||
773 | /* | ||
677 | * Update extra components | 774 | * Update extra components |
678 | */ | 775 | */ |
679 | rt2x00link_update_stats(rt2x00dev, entry->skb, &rxdesc); | 776 | rt2x00link_update_stats(rt2x00dev, entry->skb, &rxdesc); |
@@ -1183,6 +1280,8 @@ int rt2x00lib_probe_dev(struct rt2x00_dev *rt2x00dev) | |||
1183 | 1280 | ||
1184 | spin_lock_init(&rt2x00dev->irqmask_lock); | 1281 | spin_lock_init(&rt2x00dev->irqmask_lock); |
1185 | mutex_init(&rt2x00dev->csr_mutex); | 1282 | mutex_init(&rt2x00dev->csr_mutex); |
1283 | INIT_LIST_HEAD(&rt2x00dev->bar_list); | ||
1284 | spin_lock_init(&rt2x00dev->bar_list_lock); | ||
1186 | 1285 | ||
1187 | set_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags); | 1286 | set_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags); |
1188 | 1287 | ||