提交 ba08910e 编写于 作者: S Stanislaw Gruszka 提交者: John W. Linville

rt2x00: change beaconing setup on RT2800

As reported by Matthias, on 5572 chip, even if we clear up TXWI
of corresponding beacon, hardware still try to send it or do other
action that increase power consumption peak up to 1A.

To avoid the issue, setup beaconing dynamically by configuring offsets
of currently active beacons and MAC_BSSID_DW1_BSS_BCN_NUM variable,
which limit number of beacons that hardware will try to send.
Reported-by: NMatthias Fend <Matthias.Fend@wolfvision.net>
Signed-off-by: NStanislaw Gruszka <sgruszka@redhat.com>
Acked-by: NHelmut Schaa <helmut.schaa@googlemail.com>
Signed-off-by: NJohn W. Linville <linville@tuxdriver.com>
上级 283dafa1
...@@ -947,6 +947,40 @@ static inline u8 rt2800_get_beacon_offset(struct rt2x00_dev *rt2x00dev, ...@@ -947,6 +947,40 @@ static inline u8 rt2800_get_beacon_offset(struct rt2x00_dev *rt2x00dev,
return BEACON_BASE_TO_OFFSET(rt2800_hw_beacon_base(rt2x00dev, index)); return BEACON_BASE_TO_OFFSET(rt2800_hw_beacon_base(rt2x00dev, index));
} }
static void rt2800_update_beacons_setup(struct rt2x00_dev *rt2x00dev)
{
struct data_queue *queue = rt2x00dev->bcn;
struct queue_entry *entry;
int i, bcn_num = 0;
u64 off, reg = 0;
u32 bssid_dw1;
/*
* Setup offsets of all active beacons in BCN_OFFSET{0,1} registers.
*/
for (i = 0; i < queue->limit; i++) {
entry = &queue->entries[i];
if (!test_bit(ENTRY_BCN_ENABLED, &entry->flags))
continue;
off = rt2800_get_beacon_offset(rt2x00dev, entry->entry_idx);
reg |= off << (8 * bcn_num);
bcn_num++;
}
WARN_ON_ONCE(bcn_num != rt2x00dev->intf_beaconing);
rt2800_register_write(rt2x00dev, BCN_OFFSET0, (u32) reg);
rt2800_register_write(rt2x00dev, BCN_OFFSET1, (u32) (reg >> 32));
/*
* H/W sends up to MAC_BSSID_DW1_BSS_BCN_NUM + 1 consecutive beacons.
*/
rt2800_register_read(rt2x00dev, MAC_BSSID_DW1, &bssid_dw1);
rt2x00_set_field32(&bssid_dw1, MAC_BSSID_DW1_BSS_BCN_NUM,
bcn_num > 0 ? bcn_num - 1 : 0);
rt2800_register_write(rt2x00dev, MAC_BSSID_DW1, bssid_dw1);
}
void rt2800_write_beacon(struct queue_entry *entry, struct txentry_desc *txdesc) void rt2800_write_beacon(struct queue_entry *entry, struct txentry_desc *txdesc)
{ {
struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev; struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
...@@ -1003,6 +1037,12 @@ void rt2800_write_beacon(struct queue_entry *entry, struct txentry_desc *txdesc) ...@@ -1003,6 +1037,12 @@ void rt2800_write_beacon(struct queue_entry *entry, struct txentry_desc *txdesc)
rt2800_register_multiwrite(rt2x00dev, beacon_base, entry->skb->data, rt2800_register_multiwrite(rt2x00dev, beacon_base, entry->skb->data,
entry->skb->len + padding_len); entry->skb->len + padding_len);
__set_bit(ENTRY_BCN_ENABLED, &entry->flags);
/*
* Change global beacons settings.
*/
rt2800_update_beacons_setup(rt2x00dev);
/* /*
* Restore beaconing state. * Restore beaconing state.
...@@ -1053,7 +1093,12 @@ void rt2800_clear_beacon(struct queue_entry *entry) ...@@ -1053,7 +1093,12 @@ void rt2800_clear_beacon(struct queue_entry *entry)
* Clear beacon. * Clear beacon.
*/ */
rt2800_clear_beacon_register(rt2x00dev, entry->entry_idx); rt2800_clear_beacon_register(rt2x00dev, entry->entry_idx);
__clear_bit(ENTRY_BCN_ENABLED, &entry->flags);
/*
* Change global beacons settings.
*/
rt2800_update_beacons_setup(rt2x00dev);
/* /*
* Restore beaconing state. * Restore beaconing state.
*/ */
......
...@@ -353,6 +353,7 @@ struct txentry_desc { ...@@ -353,6 +353,7 @@ struct txentry_desc {
*/ */
enum queue_entry_flags { enum queue_entry_flags {
ENTRY_BCN_ASSIGNED, ENTRY_BCN_ASSIGNED,
ENTRY_BCN_ENABLED,
ENTRY_OWNER_DEVICE_DATA, ENTRY_OWNER_DEVICE_DATA,
ENTRY_DATA_PENDING, ENTRY_DATA_PENDING,
ENTRY_DATA_IO_FAILED, ENTRY_DATA_IO_FAILED,
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册