diff options
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, | |||
582 | queue->rt2x00dev->ops->lib->kick_queue(queue); | 582 | queue->rt2x00dev->ops->lib->kick_queue(queue); |
583 | } | 583 | } |
584 | 584 | ||
585 | static 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 | |||
585 | int rt2x00queue_write_tx_frame(struct data_queue *queue, struct sk_buff *skb, | 627 | int 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); |