aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/net/wireless/rt2x00/rt2800lib.c6
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00.h20
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00dev.c101
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00queue.c47
4 files changed, 169 insertions, 5 deletions
diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c
index f139a913c25a..a5c694f23d33 100644
--- a/drivers/net/wireless/rt2x00/rt2800lib.c
+++ b/drivers/net/wireless/rt2x00/rt2800lib.c
@@ -1296,8 +1296,7 @@ void rt2800_config_filter(struct rt2x00_dev *rt2x00dev,
1296 !(filter_flags & FIF_CONTROL)); 1296 !(filter_flags & FIF_CONTROL));
1297 rt2x00_set_field32(&reg, RX_FILTER_CFG_DROP_PSPOLL, 1297 rt2x00_set_field32(&reg, RX_FILTER_CFG_DROP_PSPOLL,
1298 !(filter_flags & FIF_PSPOLL)); 1298 !(filter_flags & FIF_PSPOLL));
1299 rt2x00_set_field32(&reg, RX_FILTER_CFG_DROP_BA, 1299 rt2x00_set_field32(&reg, RX_FILTER_CFG_DROP_BA, 0);
1300 !(filter_flags & FIF_CONTROL));
1301 rt2x00_set_field32(&reg, RX_FILTER_CFG_DROP_BAR, 1300 rt2x00_set_field32(&reg, RX_FILTER_CFG_DROP_BAR,
1302 !(filter_flags & FIF_CONTROL)); 1301 !(filter_flags & FIF_CONTROL));
1303 rt2x00_set_field32(&reg, RX_FILTER_CFG_DROP_CNTL, 1302 rt2x00_set_field32(&reg, RX_FILTER_CFG_DROP_CNTL,
@@ -5146,8 +5145,7 @@ static int rt2800_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
5146 IEEE80211_HW_SUPPORTS_PS | 5145 IEEE80211_HW_SUPPORTS_PS |
5147 IEEE80211_HW_PS_NULLFUNC_STACK | 5146 IEEE80211_HW_PS_NULLFUNC_STACK |
5148 IEEE80211_HW_AMPDU_AGGREGATION | 5147 IEEE80211_HW_AMPDU_AGGREGATION |
5149 IEEE80211_HW_REPORTS_TX_ACK_STATUS | 5148 IEEE80211_HW_REPORTS_TX_ACK_STATUS;
5150 IEEE80211_HW_TEARDOWN_AGGR_ON_BAR_FAIL;
5151 5149
5152 /* 5150 /*
5153 * Don't set IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING for USB devices 5151 * Don't set IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING for USB devices
diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h
index 0751b35ef6dc..b52512b8ac5f 100644
--- a/drivers/net/wireless/rt2x00/rt2x00.h
+++ b/drivers/net/wireless/rt2x00/rt2x00.h
@@ -1016,6 +1016,26 @@ struct rt2x00_dev {
1016 * Protect the interrupt mask register. 1016 * Protect the interrupt mask register.
1017 */ 1017 */
1018 spinlock_t irqmask_lock; 1018 spinlock_t irqmask_lock;
1019
1020 /*
1021 * List of BlockAckReq TX entries that need driver BlockAck processing.
1022 */
1023 struct list_head bar_list;
1024 spinlock_t bar_list_lock;
1025};
1026
1027struct rt2x00_bar_list_entry {
1028 struct list_head list;
1029 struct rcu_head head;
1030
1031 struct queue_entry *entry;
1032 int block_acked;
1033
1034 /* Relevant parts of the IEEE80211 BAR header */
1035 __u8 ra[6];
1036 __u8 ta[6];
1037 __le16 control;
1038 __le16 start_seq_num;
1019}; 1039};
1020 1040
1021/* 1041/*
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}
272EXPORT_SYMBOL_GPL(rt2x00lib_dmadone); 272EXPORT_SYMBOL_GPL(rt2x00lib_dmadone);
273 273
274static 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
274void rt2x00lib_txdone(struct queue_entry *entry, 318void 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
541static 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
494static void rt2x00lib_rxdone_check_ps(struct rt2x00_dev *rt2x00dev, 585static 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
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,
582 queue->rt2x00dev->ops->lib->kick_queue(queue); 582 queue->rt2x00dev->ops->lib->kick_queue(queue);
583} 583}
584 584
585static void rt2x00queue_bar_check(struct queue_entry *entry)
586{
587 struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
588 struct ieee80211_bar *bar = (void *) (entry->skb->data +
589 rt2x00dev->ops->extra_tx_headroom);
590 struct rt2x00_bar_list_entry *bar_entry;
591
592 if (likely(!ieee80211_is_back_req(bar->frame_control)))
593 return;
594
595 bar_entry = kmalloc(sizeof(*bar_entry), GFP_ATOMIC);
596
597 /*
598 * If the alloc fails we still send the BAR out but just don't track
599 * it in our bar list. And as a result we will report it to mac80211
600 * back as failed.
601 */
602 if (!bar_entry)
603 return;
604
605 bar_entry->entry = entry;
606 bar_entry->block_acked = 0;
607
608 /*
609 * Copy the relevant parts of the 802.11 BAR into out check list
610 * such that we can use RCU for less-overhead in the RX path since
611 * sending BARs and processing the according BlockAck should be
612 * the exception.
613 */
614 memcpy(bar_entry->ra, bar->ra, sizeof(bar->ra));
615 memcpy(bar_entry->ta, bar->ta, sizeof(bar->ta));
616 bar_entry->control = bar->control;
617 bar_entry->start_seq_num = bar->start_seq_num;
618
619 /*
620 * Insert BAR into our BAR check list.
621 */
622 spin_lock_bh(&rt2x00dev->bar_list_lock);
623 list_add_tail_rcu(&bar_entry->list, &rt2x00dev->bar_list);
624 spin_unlock_bh(&rt2x00dev->bar_list_lock);
625}
626
585int rt2x00queue_write_tx_frame(struct data_queue *queue, struct sk_buff *skb, 627int rt2x00queue_write_tx_frame(struct data_queue *queue, struct sk_buff *skb,
586 bool local) 628 bool local)
587{ 629{
@@ -680,6 +722,11 @@ int rt2x00queue_write_tx_frame(struct data_queue *queue, struct sk_buff *skb,
680 goto out; 722 goto out;
681 } 723 }
682 724
725 /*
726 * Put BlockAckReqs into our check list for driver BA processing.
727 */
728 rt2x00queue_bar_check(entry);
729
683 set_bit(ENTRY_DATA_PENDING, &entry->flags); 730 set_bit(ENTRY_DATA_PENDING, &entry->flags);
684 731
685 rt2x00queue_index_inc(entry, Q_INDEX); 732 rt2x00queue_index_inc(entry, Q_INDEX);