Commit ba08910e authored by Stanislaw Gruszka's avatar Stanislaw Gruszka Committed by 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: default avatarMatthias Fend <Matthias.Fend@wolfvision.net>
Signed-off-by: default avatarStanislaw Gruszka <sgruszka@redhat.com>
Acked-by: default avatarHelmut Schaa <helmut.schaa@googlemail.com>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent 283dafa1
......@@ -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));
}
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)
{
struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
......@@ -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,
entry->skb->len + padding_len);
__set_bit(ENTRY_BCN_ENABLED, &entry->flags);
/*
* Change global beacons settings.
*/
rt2800_update_beacons_setup(rt2x00dev);
/*
* Restore beaconing state.
......@@ -1053,7 +1093,12 @@ void rt2800_clear_beacon(struct queue_entry *entry)
* Clear beacon.
*/
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.
*/
......
......@@ -353,6 +353,7 @@ struct txentry_desc {
*/
enum queue_entry_flags {
ENTRY_BCN_ASSIGNED,
ENTRY_BCN_ENABLED,
ENTRY_OWNER_DEVICE_DATA,
ENTRY_DATA_PENDING,
ENTRY_DATA_IO_FAILED,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment