Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 351955
b: refs/heads/master
c: 84e9e8e
h: refs/heads/master
i:
  351953: 2c73260
  351951: a197e81
v: v3
  • Loading branch information
Helmut Schaa authored and John W. Linville committed Jan 22, 2013
1 parent 4a090aa commit 408d2b1
Show file tree
Hide file tree
Showing 5 changed files with 170 additions and 6 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: f49aabf816afa5913e5001bd1db1c3efb4c6e19e
refs/heads/master: 84e9e8ebd369679a958200a8baca96aafb2393bb
6 changes: 2 additions & 4 deletions trunk/drivers/net/wireless/rt2x00/rt2800lib.c
Original file line number Diff line number Diff line change
Expand Up @@ -1296,8 +1296,7 @@ void rt2800_config_filter(struct rt2x00_dev *rt2x00dev,
!(filter_flags & FIF_CONTROL));
rt2x00_set_field32(&reg, RX_FILTER_CFG_DROP_PSPOLL,
!(filter_flags & FIF_PSPOLL));
rt2x00_set_field32(&reg, RX_FILTER_CFG_DROP_BA,
!(filter_flags & FIF_CONTROL));
rt2x00_set_field32(&reg, RX_FILTER_CFG_DROP_BA, 0);
rt2x00_set_field32(&reg, RX_FILTER_CFG_DROP_BAR,
!(filter_flags & FIF_CONTROL));
rt2x00_set_field32(&reg, RX_FILTER_CFG_DROP_CNTL,
Expand Down Expand Up @@ -5146,8 +5145,7 @@ static int rt2800_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
IEEE80211_HW_SUPPORTS_PS |
IEEE80211_HW_PS_NULLFUNC_STACK |
IEEE80211_HW_AMPDU_AGGREGATION |
IEEE80211_HW_REPORTS_TX_ACK_STATUS |
IEEE80211_HW_TEARDOWN_AGGR_ON_BAR_FAIL;
IEEE80211_HW_REPORTS_TX_ACK_STATUS;

/*
* Don't set IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING for USB devices
Expand Down
20 changes: 20 additions & 0 deletions trunk/drivers/net/wireless/rt2x00/rt2x00.h
Original file line number Diff line number Diff line change
Expand Up @@ -1016,6 +1016,26 @@ struct rt2x00_dev {
* Protect the interrupt mask register.
*/
spinlock_t irqmask_lock;

/*
* List of BlockAckReq TX entries that need driver BlockAck processing.
*/
struct list_head bar_list;
spinlock_t bar_list_lock;
};

struct rt2x00_bar_list_entry {
struct list_head list;
struct rcu_head head;

struct queue_entry *entry;
int block_acked;

/* Relevant parts of the IEEE80211 BAR header */
__u8 ra[6];
__u8 ta[6];
__le16 control;
__le16 start_seq_num;
};

/*
Expand Down
101 changes: 100 additions & 1 deletion trunk/drivers/net/wireless/rt2x00/rt2x00dev.c
Original file line number Diff line number Diff line change
Expand Up @@ -271,6 +271,50 @@ void rt2x00lib_dmadone(struct queue_entry *entry)
}
EXPORT_SYMBOL_GPL(rt2x00lib_dmadone);

static inline int rt2x00lib_txdone_bar_status(struct queue_entry *entry)
{
struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
struct ieee80211_bar *bar = (void *) entry->skb->data;
struct rt2x00_bar_list_entry *bar_entry;
int ret;

if (likely(!ieee80211_is_back_req(bar->frame_control)))
return 0;

/*
* Unlike all other frames, the status report for BARs does
* not directly come from the hardware as it is incapable of
* matching a BA to a previously send BAR. The hardware will
* report all BARs as if they weren't acked at all.
*
* Instead the RX-path will scan for incoming BAs and set the
* block_acked flag if it sees one that was likely caused by
* a BAR from us.
*
* Remove remaining BARs here and return their status for
* TX done processing.
*/
ret = 0;
rcu_read_lock();
list_for_each_entry_rcu(bar_entry, &rt2x00dev->bar_list, list) {
if (bar_entry->entry != entry)
continue;

spin_lock_bh(&rt2x00dev->bar_list_lock);
/* Return whether this BAR was blockacked or not */
ret = bar_entry->block_acked;
/* Remove the BAR from our checklist */
list_del_rcu(&bar_entry->list);
spin_unlock_bh(&rt2x00dev->bar_list_lock);
kfree_rcu(bar_entry, head);

break;
}
rcu_read_unlock();

return ret;
}

void rt2x00lib_txdone(struct queue_entry *entry,
struct txdone_entry_desc *txdesc)
{
Expand Down Expand Up @@ -324,9 +368,12 @@ void rt2x00lib_txdone(struct queue_entry *entry,
rt2x00debug_dump_frame(rt2x00dev, DUMP_FRAME_TXDONE, entry->skb);

/*
* Determine if the frame has been successfully transmitted.
* Determine if the frame has been successfully transmitted and
* remove BARs from our check list while checking for their
* TX status.
*/
success =
rt2x00lib_txdone_bar_status(entry) ||
test_bit(TXDONE_SUCCESS, &txdesc->flags) ||
test_bit(TXDONE_UNKNOWN, &txdesc->flags);

Expand Down Expand Up @@ -491,6 +538,50 @@ static void rt2x00lib_sleep(struct work_struct *work)
IEEE80211_CONF_CHANGE_PS);
}

static void rt2x00lib_rxdone_check_ba(struct rt2x00_dev *rt2x00dev,
struct sk_buff *skb,
struct rxdone_entry_desc *rxdesc)
{
struct rt2x00_bar_list_entry *entry;
struct ieee80211_bar *ba = (void *)skb->data;

if (likely(!ieee80211_is_back(ba->frame_control)))
return;

if (rxdesc->size < sizeof(*ba) + FCS_LEN)
return;

rcu_read_lock();
list_for_each_entry_rcu(entry, &rt2x00dev->bar_list, list) {

if (ba->start_seq_num != entry->start_seq_num)
continue;

#define TID_CHECK(a, b) ( \
((a) & cpu_to_le16(IEEE80211_BAR_CTRL_TID_INFO_MASK)) == \
((b) & cpu_to_le16(IEEE80211_BAR_CTRL_TID_INFO_MASK))) \

if (!TID_CHECK(ba->control, entry->control))
continue;

#undef TID_CHECK

if (compare_ether_addr(ba->ra, entry->ta))
continue;

if (compare_ether_addr(ba->ta, entry->ra))
continue;

/* Mark BAR since we received the according BA */
spin_lock_bh(&rt2x00dev->bar_list_lock);
entry->block_acked = 1;
spin_unlock_bh(&rt2x00dev->bar_list_lock);
break;
}
rcu_read_unlock();

}

static void rt2x00lib_rxdone_check_ps(struct rt2x00_dev *rt2x00dev,
struct sk_buff *skb,
struct rxdone_entry_desc *rxdesc)
Expand Down Expand Up @@ -673,6 +764,12 @@ void rt2x00lib_rxdone(struct queue_entry *entry, gfp_t gfp)
*/
rt2x00lib_rxdone_check_ps(rt2x00dev, entry->skb, &rxdesc);

/*
* Check for incoming BlockAcks to match to the BlockAckReqs
* we've send out.
*/
rt2x00lib_rxdone_check_ba(rt2x00dev, entry->skb, &rxdesc);

/*
* Update extra components
*/
Expand Down Expand Up @@ -1183,6 +1280,8 @@ int rt2x00lib_probe_dev(struct rt2x00_dev *rt2x00dev)

spin_lock_init(&rt2x00dev->irqmask_lock);
mutex_init(&rt2x00dev->csr_mutex);
INIT_LIST_HEAD(&rt2x00dev->bar_list);
spin_lock_init(&rt2x00dev->bar_list_lock);

set_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags);

Expand Down
47 changes: 47 additions & 0 deletions trunk/drivers/net/wireless/rt2x00/rt2x00queue.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand Down Expand Up @@ -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);
Expand Down

0 comments on commit 408d2b1

Please sign in to comment.