OSDN Git Service

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 edd3734..dc93e14 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 afad3e1..5572732 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 f21b77c..c0c38f9 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);
 
@@ -1052,6 +1064,12 @@ static int rt2800pci_probe_hw(struct rt2x00_dev *rt2x00dev)
        __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.
         */
        if (!rt2x00_is_soc(rt2x00dev))
index 0fa2141..9dd0d17 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 ae0adff..f59b9f7 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)
 {