diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/net/wireless/rt2x00/rt2800lib.c | 45 | ||||
-rw-r--r-- | drivers/net/wireless/rt2x00/rt2x00queue.h | 1 |
2 files changed, 46 insertions, 0 deletions
diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c index c17fcf27272..c45b2d31ea6 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/rt2x00/rt2800lib.c @@ -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,8 +1093,13 @@ 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. */ rt2800_register_write(rt2x00dev, BCN_TIME_CFG, orig_reg); diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.h b/drivers/net/wireless/rt2x00/rt2x00queue.h index c48125be0e3..2233b911a1d 100644 --- a/drivers/net/wireless/rt2x00/rt2x00queue.h +++ b/drivers/net/wireless/rt2x00/rt2x00queue.h @@ -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, |