iwlwifi: use sleep interval succession
authorJohannes Berg <johannes@sipsolutions.net>
Fri, 28 Aug 2009 16:44:48 +0000 (09:44 -0700)
committerJohn W. Linville <linville@tuxdriver.com>
Mon, 31 Aug 2009 18:42:10 +0000 (14:42 -0400)
Some concerns were raised about the automatic adjustment
of sleep intervals to all the same, potentially high,
value, and I can imagine the hardware behaving better
when we don't ask too much of it.

So let's convert to use a succession of sleep levels
when requesting to go to deeper sleeps (which can only
happen with large DTIM intervals), using the succession
values from power level three, which have the benefit of
also having been tested extensively already.

As a result, the automatic sleep level adjustment will
now be mostly equivalent to power level three, except
for the RX/TX timeouts and possibly using smaller sleep
vectors to account for networking latency.

Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
Signed-off-by: Reinette Chatre <reinette.chatre@intel.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
drivers/net/wireless/iwlwifi/iwl-power.c

index 0b16841..081a7ea 100644 (file)
@@ -216,8 +216,27 @@ static void iwl_power_fill_sleep_cmd(struct iwl_priv *priv,
                                     struct iwl_powertable_cmd *cmd,
                                     int dynps_ms, int wakeup_period)
 {
+       /*
+        * These are the original power level 3 sleep successions. The
+        * device may behave better with such succession and was also
+        * only tested with that. Just like the original sleep commands,
+        * also adjust the succession here to the wakeup_period below.
+        * The ranges are the same as for the sleep commands, 0-2, 3-9
+        * and >10, which is selected based on the DTIM interval for
+        * the sleep index but here we use the wakeup period since that
+        * is what we need to do for the latency requirements.
+        */
+       static const u8 slp_succ_r0[IWL_POWER_VEC_SIZE] = { 2, 2, 2, 2, 2 };
+       static const u8 slp_succ_r1[IWL_POWER_VEC_SIZE] = { 2, 4, 6, 7, 9 };
+       static const u8 slp_succ_r2[IWL_POWER_VEC_SIZE] = { 2, 7, 9, 9, 0xFF };
+       const u8 *slp_succ = slp_succ_r0;
        int i;
 
+       if (wakeup_period > IWL_DTIM_RANGE_0_MAX)
+               slp_succ = slp_succ_r1;
+       if (wakeup_period > IWL_DTIM_RANGE_1_MAX)
+               slp_succ = slp_succ_r2;
+
        memset(cmd, 0, sizeof(*cmd));
 
        cmd->flags = IWL_POWER_DRIVER_ALLOW_SLEEP_MSK |
@@ -230,7 +249,8 @@ static void iwl_power_fill_sleep_cmd(struct iwl_priv *priv,
        cmd->tx_data_timeout = cpu_to_le32(1000 * dynps_ms);
 
        for (i = 0; i < IWL_POWER_VEC_SIZE; i++)
-               cmd->sleep_interval[i] = cpu_to_le32(wakeup_period);
+               cmd->sleep_interval[i] =
+                       cpu_to_le32(min_t(int, slp_succ[i], wakeup_period));
 
        IWL_DEBUG_POWER(priv, "Automatic sleep command\n");
 }