rt2x00: Use pretbtt irq for fetching beacons on rt2800pci
authorHelmut Schaa <helmut.schaa@googlemail.com>
Sun, 11 Jul 2010 10:28:23 +0000 (12:28 +0200)
committerJohn W. Linville <linville@tuxdriver.com>
Mon, 12 Jul 2010 20:05:35 +0000 (16:05 -0400)
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: Helmut Schaa <helmut.schaa@googlemail.com>
Signed-off-by: Ivo van Doorn <IvDoorn@gmail.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
drivers/net/wireless/rt2x00/rt2800.h
drivers/net/wireless/rt2x00/rt2800lib.c
drivers/net/wireless/rt2x00/rt2800pci.c
drivers/net/wireless/rt2x00/rt2x00.h
drivers/net/wireless/rt2x00/rt2x00dev.c

index edd3734b8b32037acd2e798fdb5ea5686c825e89..dc93e14f7ab7905ce2b2c13c254e7d6cf2cb277e 100644 (file)
 #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_PRE_TBTT_TIMER   FIELD32(0x0000ffff)
+#define INT_TIMER_CFG_GP_TIMER         FIELD32(0xffff0000)
 
 /*
  * INT_TIMER_EN: GP-timer and pre-tbtt Int enable
  */
 #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
index afad3e1c183882a257814b1aa3ca6c9a77b730ba..55727328e227615f4502b8a0320b50008072fca7 100644 (file)
@@ -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,
                                   (conf->sync == TSF_SYNC_BEACON));
                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) {
@@ -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_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;
 }
 EXPORT_SYMBOL_GPL(rt2800_init_registers);
index f21b77c61ad4a6f5b994d8c42ff0a89efbce6faf..c0c38f9705ae78bd8998e4166b0485f4ec546a52 100644 (file)
@@ -938,20 +938,32 @@ static irqreturn_t rt2800pci_interrupt_thread(int irq, void *dev_instance)
        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))
                rt2x00pci_rxdone(rt2x00dev);
 
+       /*
+        * 4 - Tx done interrupt.
+        */
        if (rt2x00_get_field32(reg, INT_SOURCE_CSR_TX_FIFO_STATUS))
                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))
                rt2800pci_wakeup(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_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.
         */
index 0fa21410676f5592abe7c033c745d702f0dfd767..9dd0d171abf13d683279982ae1221816803a7332 100644 (file)
@@ -658,6 +658,7 @@ enum rt2x00_flags {
        CONFIG_SUPPORT_HW_CRYPTO,
        DRIVER_SUPPORT_CONTROL_FILTERS,
        DRIVER_SUPPORT_CONTROL_FILTER_PSPOLL,
+       DRIVER_SUPPORT_PRE_TBTT_INTERRUPT,
        DRIVER_SUPPORT_LINK_TUNING,
        DRIVER_SUPPORT_WATCHDOG,
 
@@ -1071,6 +1072,7 @@ static inline void rt2x00debug_dump_frame(struct rt2x00_dev *rt2x00dev,
  * Interrupt context handlers.
  */
 void rt2x00lib_beacondone(struct rt2x00_dev *rt2x00dev);
+void rt2x00lib_pretbtt(struct rt2x00_dev *rt2x00dev);
 void rt2x00lib_txdone(struct queue_entry *entry,
                      struct txdone_entry_desc *txdesc);
 void rt2x00lib_rxdone(struct rt2x00_dev *rt2x00dev,
index ae0adff0b832b6f94cbdef09a5c67ec03861d5d9..f59b9f7226a836ad0af19d98c1c1fd503a942204 100644 (file)
@@ -200,8 +200,8 @@ static void rt2x00lib_bc_buffer_iter(void *data, u8 *mac,
        }
 }
 
-static void rt2x00lib_beacondone_iter(void *data, u8 *mac,
-                                     struct ieee80211_vif *vif)
+static void rt2x00lib_beaconupdate_iter(void *data, u8 *mac,
+                                       struct ieee80211_vif *vif)
 {
        struct rt2x00_dev *rt2x00dev = data;
 
@@ -223,15 +223,33 @@ void rt2x00lib_beacondone(struct rt2x00_dev *rt2x00dev)
        ieee80211_iterate_active_interfaces(rt2x00dev->hw,
                                            rt2x00lib_bc_buffer_iter,
                                            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 */
        ieee80211_iterate_active_interfaces(rt2x00dev->hw,
-                                           rt2x00lib_beacondone_iter,
+                                           rt2x00lib_beaconupdate_iter,
                                            rt2x00dev);
-
 }
 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,
                      struct txdone_entry_desc *txdesc)
 {