Commit 9f926fb5 authored by Helmut Schaa's avatar Helmut Schaa Committed by John W. Linville

rt2x00: Use pretbtt irq for fetching beacons on rt2800pci

Updating the beacon on pre tbtt instead of beacondone allows much lower
latency in regard to TIM updates. Hence, use the pre tbtt interrupt for
updating the beacon in rt2800pci (older devices don't provide a pre tbtt
interrupt).

Also, add a new driver flag to indicate if a driver has pre tbtt support
or not and implement the according behavior in rt2x00lib.
Signed-off-by: default avatarHelmut Schaa <helmut.schaa@googlemail.com>
Signed-off-by: default avatarIvo van Doorn <IvDoorn@gmail.com>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent 07896fe2
...@@ -719,14 +719,20 @@ ...@@ -719,14 +719,20 @@
#define TBTT_TIMER 0x1124 #define TBTT_TIMER 0x1124
/* /*
* INT_TIMER_CFG: * INT_TIMER_CFG: timer configuration
* PRE_TBTT_TIMER: leadtime to tbtt for pretbtt interrupt in units of 1/16 TU
* GP_TIMER: period of general purpose timer in units of 1/16 TU
*/ */
#define INT_TIMER_CFG 0x1128 #define INT_TIMER_CFG 0x1128
#define INT_TIMER_CFG_PRE_TBTT_TIMER FIELD32(0x0000ffff)
#define INT_TIMER_CFG_GP_TIMER FIELD32(0xffff0000)
/* /*
* INT_TIMER_EN: GP-timer and pre-tbtt Int enable * INT_TIMER_EN: GP-timer and pre-tbtt Int enable
*/ */
#define INT_TIMER_EN 0x112c #define INT_TIMER_EN 0x112c
#define INT_TIMER_EN_PRE_TBTT_TIMER FIELD32(0x00000001)
#define INT_TIMER_EN_GP_TIMER FIELD32(0x00000002)
/* /*
* CH_IDLE_STA: channel idle time * CH_IDLE_STA: channel idle time
......
...@@ -807,6 +807,15 @@ void rt2800_config_intf(struct rt2x00_dev *rt2x00dev, struct rt2x00_intf *intf, ...@@ -807,6 +807,15 @@ void rt2800_config_intf(struct rt2x00_dev *rt2x00dev, struct rt2x00_intf *intf,
rt2x00_set_field32(&reg, BCN_TIME_CFG_TBTT_ENABLE, rt2x00_set_field32(&reg, BCN_TIME_CFG_TBTT_ENABLE,
(conf->sync == TSF_SYNC_BEACON)); (conf->sync == TSF_SYNC_BEACON));
rt2800_register_write(rt2x00dev, BCN_TIME_CFG, reg); rt2800_register_write(rt2x00dev, BCN_TIME_CFG, reg);
/*
* Enable pre tbtt interrupt for beaconing modes
*/
rt2800_register_read(rt2x00dev, INT_TIMER_EN, &reg);
rt2x00_set_field32(&reg, INT_TIMER_EN_PRE_TBTT_TIMER,
(conf->sync == TSF_SYNC_BEACON));
rt2800_register_write(rt2x00dev, INT_TIMER_EN, reg);
} }
if (flags & CONFIG_UPDATE_MAC) { if (flags & CONFIG_UPDATE_MAC) {
...@@ -1732,6 +1741,13 @@ int rt2800_init_registers(struct rt2x00_dev *rt2x00dev) ...@@ -1732,6 +1741,13 @@ int rt2800_init_registers(struct rt2x00_dev *rt2x00dev)
rt2800_register_read(rt2x00dev, TX_STA_CNT1, &reg); rt2800_register_read(rt2x00dev, TX_STA_CNT1, &reg);
rt2800_register_read(rt2x00dev, TX_STA_CNT2, &reg); rt2800_register_read(rt2x00dev, TX_STA_CNT2, &reg);
/*
* Setup leadtime for pre tbtt interrupt to 6ms
*/
rt2800_register_read(rt2x00dev, INT_TIMER_CFG, &reg);
rt2x00_set_field32(&reg, INT_TIMER_CFG_PRE_TBTT_TIMER, 6 << 4);
rt2800_register_write(rt2x00dev, INT_TIMER_CFG, reg);
return 0; return 0;
} }
EXPORT_SYMBOL_GPL(rt2800_init_registers); EXPORT_SYMBOL_GPL(rt2800_init_registers);
......
...@@ -938,20 +938,32 @@ static irqreturn_t rt2800pci_interrupt_thread(int irq, void *dev_instance) ...@@ -938,20 +938,32 @@ static irqreturn_t rt2800pci_interrupt_thread(int irq, void *dev_instance)
u32 reg = rt2x00dev->irqvalue[0]; u32 reg = rt2x00dev->irqvalue[0];
/* /*
* 1 - Rx ring done interrupt. * 1 - Pre TBTT interrupt.
*/
if (rt2x00_get_field32(reg, INT_SOURCE_CSR_PRE_TBTT))
rt2x00lib_pretbtt(rt2x00dev);
/*
* 2 - Beacondone interrupt.
*/
if (rt2x00_get_field32(reg, INT_SOURCE_CSR_TBTT))
rt2x00lib_beacondone(rt2x00dev);
/*
* 3 - Rx ring done interrupt.
*/ */
if (rt2x00_get_field32(reg, INT_SOURCE_CSR_RX_DONE)) if (rt2x00_get_field32(reg, INT_SOURCE_CSR_RX_DONE))
rt2x00pci_rxdone(rt2x00dev); rt2x00pci_rxdone(rt2x00dev);
/*
* 4 - Tx done interrupt.
*/
if (rt2x00_get_field32(reg, INT_SOURCE_CSR_TX_FIFO_STATUS)) if (rt2x00_get_field32(reg, INT_SOURCE_CSR_TX_FIFO_STATUS))
rt2800pci_txdone(rt2x00dev); rt2800pci_txdone(rt2x00dev);
/* /*
* Current beacon was sent out, fetch the next one * 5 - Auto wakeup interrupt.
*/ */
if (rt2x00_get_field32(reg, INT_SOURCE_CSR_TBTT))
rt2x00lib_beacondone(rt2x00dev);
if (rt2x00_get_field32(reg, INT_SOURCE_CSR_AUTO_WAKEUP)) if (rt2x00_get_field32(reg, INT_SOURCE_CSR_AUTO_WAKEUP))
rt2800pci_wakeup(rt2x00dev); rt2800pci_wakeup(rt2x00dev);
...@@ -1051,6 +1063,12 @@ static int rt2800pci_probe_hw(struct rt2x00_dev *rt2x00dev) ...@@ -1051,6 +1063,12 @@ static int rt2800pci_probe_hw(struct rt2x00_dev *rt2x00dev)
__set_bit(DRIVER_SUPPORT_CONTROL_FILTERS, &rt2x00dev->flags); __set_bit(DRIVER_SUPPORT_CONTROL_FILTERS, &rt2x00dev->flags);
__set_bit(DRIVER_SUPPORT_CONTROL_FILTER_PSPOLL, &rt2x00dev->flags); __set_bit(DRIVER_SUPPORT_CONTROL_FILTER_PSPOLL, &rt2x00dev->flags);
/*
* This device has a pre tbtt interrupt and thus fetches
* a new beacon directly prior to transmission.
*/
__set_bit(DRIVER_SUPPORT_PRE_TBTT_INTERRUPT, &rt2x00dev->flags);
/* /*
* This device requires firmware. * This device requires firmware.
*/ */
......
...@@ -658,6 +658,7 @@ enum rt2x00_flags { ...@@ -658,6 +658,7 @@ enum rt2x00_flags {
CONFIG_SUPPORT_HW_CRYPTO, CONFIG_SUPPORT_HW_CRYPTO,
DRIVER_SUPPORT_CONTROL_FILTERS, DRIVER_SUPPORT_CONTROL_FILTERS,
DRIVER_SUPPORT_CONTROL_FILTER_PSPOLL, DRIVER_SUPPORT_CONTROL_FILTER_PSPOLL,
DRIVER_SUPPORT_PRE_TBTT_INTERRUPT,
DRIVER_SUPPORT_LINK_TUNING, DRIVER_SUPPORT_LINK_TUNING,
DRIVER_SUPPORT_WATCHDOG, DRIVER_SUPPORT_WATCHDOG,
...@@ -1071,6 +1072,7 @@ static inline void rt2x00debug_dump_frame(struct rt2x00_dev *rt2x00dev, ...@@ -1071,6 +1072,7 @@ static inline void rt2x00debug_dump_frame(struct rt2x00_dev *rt2x00dev,
* Interrupt context handlers. * Interrupt context handlers.
*/ */
void rt2x00lib_beacondone(struct rt2x00_dev *rt2x00dev); void rt2x00lib_beacondone(struct rt2x00_dev *rt2x00dev);
void rt2x00lib_pretbtt(struct rt2x00_dev *rt2x00dev);
void rt2x00lib_txdone(struct queue_entry *entry, void rt2x00lib_txdone(struct queue_entry *entry,
struct txdone_entry_desc *txdesc); struct txdone_entry_desc *txdesc);
void rt2x00lib_rxdone(struct rt2x00_dev *rt2x00dev, void rt2x00lib_rxdone(struct rt2x00_dev *rt2x00dev,
......
...@@ -200,8 +200,8 @@ static void rt2x00lib_bc_buffer_iter(void *data, u8 *mac, ...@@ -200,8 +200,8 @@ static void rt2x00lib_bc_buffer_iter(void *data, u8 *mac,
} }
} }
static void rt2x00lib_beacondone_iter(void *data, u8 *mac, static void rt2x00lib_beaconupdate_iter(void *data, u8 *mac,
struct ieee80211_vif *vif) struct ieee80211_vif *vif)
{ {
struct rt2x00_dev *rt2x00dev = data; struct rt2x00_dev *rt2x00dev = data;
...@@ -223,15 +223,33 @@ void rt2x00lib_beacondone(struct rt2x00_dev *rt2x00dev) ...@@ -223,15 +223,33 @@ void rt2x00lib_beacondone(struct rt2x00_dev *rt2x00dev)
ieee80211_iterate_active_interfaces(rt2x00dev->hw, ieee80211_iterate_active_interfaces(rt2x00dev->hw,
rt2x00lib_bc_buffer_iter, rt2x00lib_bc_buffer_iter,
rt2x00dev); rt2x00dev);
/*
* Devices with pre tbtt interrupt don't need to update the beacon
* here as they will fetch the next beacon directly prior to
* transmission.
*/
if (test_bit(DRIVER_SUPPORT_PRE_TBTT_INTERRUPT, &rt2x00dev->flags))
return;
/* fetch next beacon */ /* fetch next beacon */
ieee80211_iterate_active_interfaces(rt2x00dev->hw, ieee80211_iterate_active_interfaces(rt2x00dev->hw,
rt2x00lib_beacondone_iter, rt2x00lib_beaconupdate_iter,
rt2x00dev); rt2x00dev);
} }
EXPORT_SYMBOL_GPL(rt2x00lib_beacondone); EXPORT_SYMBOL_GPL(rt2x00lib_beacondone);
void rt2x00lib_pretbtt(struct rt2x00_dev *rt2x00dev)
{
if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
return;
/* fetch next beacon */
ieee80211_iterate_active_interfaces(rt2x00dev->hw,
rt2x00lib_beaconupdate_iter,
rt2x00dev);
}
EXPORT_SYMBOL_GPL(rt2x00lib_pretbtt);
void rt2x00lib_txdone(struct queue_entry *entry, void rt2x00lib_txdone(struct queue_entry *entry,
struct txdone_entry_desc *txdesc) struct txdone_entry_desc *txdesc)
{ {
......
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