Merge branch 'for-upstream' of git://git.kernel.org/pub/scm/linux/kernel/git/dvrabel/uwb
[pandora-kernel.git] / drivers / net / wireless / iwlwifi / iwl-power.c
index 47c8945..f2ea3f0 100644 (file)
 #include "iwl-power.h"
 
 /*
- * Setting power level allow the card to go to sleep when not busy
- * there are three factor that decide the power level to go to, they
- * are list here with its priority
- *  1- critical_power_setting this will be set according to card temperature.
- *  2- system_power_setting this will be set by system PM manager.
- *  3- user_power_setting this will be set by user either by writing to sys or
- *     mac80211
+ * Setting power level allow the card to go to sleep when not busy.
  *
- * if system_power_setting and user_power_setting is set to auto
- * the power level will be decided according to association status and battery
- * status.
+ * The power level is set to INDEX_1 (the least deep state) by
+ * default, and will, in the future, be the deepest state unless
+ * otherwise required by pm_qos network latency requirements.
  *
+ * Using INDEX_1 without pm_qos is ok because mac80211 will disable
+ * PS when even checking every beacon for the TIM bit would exceed
+ * the required latency.
  */
 
-#define MSEC_TO_USEC 1024
 #define IWL_POWER_RANGE_0_MAX  (2)
 #define IWL_POWER_RANGE_1_MAX  (10)
 
 
-
-#define IWL_POWER_ON_BATTERY           IWL_POWER_INDEX_5
-#define IWL_POWER_ON_AC_DISASSOC       IWL_POWER_MODE_CAM
-#define IWL_POWER_ON_AC_ASSOC          IWL_POWER_MODE_CAM
-
-
-#define IWL_CT_KILL_TEMPERATURE                110
-#define IWL_MIN_POWER_TEMPERATURE      100
-#define IWL_REDUCED_POWER_TEMPERATURE  95
-
+#define NOSLP cpu_to_le16(0), 0, 0
+#define SLP IWL_POWER_DRIVER_ALLOW_SLEEP_MSK, 0, 0
+#define TU_TO_USEC 1024
+#define SLP_TOUT(T) cpu_to_le32((T) * TU_TO_USEC)
+#define SLP_VEC(X0, X1, X2, X3, X4) {cpu_to_le32(X0), \
+                                    cpu_to_le32(X1), \
+                                    cpu_to_le32(X2), \
+                                    cpu_to_le32(X3), \
+                                    cpu_to_le32(X4)}
 /* default power management (not Tx power) table values */
-/* for TIM  0-10 */
-static struct iwl_power_vec_entry range_0[IWL_POWER_MAX] = {
+/* for DTIM period 0 through IWL_POWER_RANGE_0_MAX */
+static const struct iwl_power_vec_entry range_0[IWL_POWER_NUM] = {
        {{NOSLP, SLP_TOUT(0), SLP_TOUT(0), SLP_VEC(0, 0, 0, 0, 0)}, 0},
        {{SLP, SLP_TOUT(200), SLP_TOUT(500), SLP_VEC(1, 2, 2, 2, 0xFF)}, 0},
        {{SLP, SLP_TOUT(200), SLP_TOUT(300), SLP_VEC(1, 2, 2, 2, 0xFF)}, 0},
@@ -82,8 +77,8 @@ static struct iwl_power_vec_entry range_0[IWL_POWER_MAX] = {
 };
 
 
-/* for TIM = 3-10 */
-static struct iwl_power_vec_entry range_1[IWL_POWER_MAX] = {
+/* for DTIM period IWL_POWER_RANGE_0_MAX + 1 through IWL_POWER_RANGE_1_MAX */
+static const struct iwl_power_vec_entry range_1[IWL_POWER_NUM] = {
        {{NOSLP, SLP_TOUT(0), SLP_TOUT(0), SLP_VEC(0, 0, 0, 0, 0)}, 0},
        {{SLP, SLP_TOUT(200), SLP_TOUT(500), SLP_VEC(1, 2, 3, 4, 4)}, 0},
        {{SLP, SLP_TOUT(200), SLP_TOUT(300), SLP_VEC(1, 2, 3, 4, 7)}, 0},
@@ -92,8 +87,8 @@ static struct iwl_power_vec_entry range_1[IWL_POWER_MAX] = {
        {{SLP, SLP_TOUT(25), SLP_TOUT(25), SLP_VEC(2, 4, 7, 10, 10)}, 2}
 };
 
-/* for TIM > 11 */
-static struct iwl_power_vec_entry range_2[IWL_POWER_MAX] = {
+/* for DTIM period > IWL_POWER_RANGE_1_MAX */
+static const struct iwl_power_vec_entry range_2[IWL_POWER_NUM] = {
        {{NOSLP, SLP_TOUT(0), SLP_TOUT(0), SLP_VEC(0, 0, 0, 0, 0)}, 0},
        {{SLP, SLP_TOUT(200), SLP_TOUT(500), SLP_VEC(1, 2, 3, 4, 0xFF)}, 0},
        {{SLP, SLP_TOUT(200), SLP_TOUT(300), SLP_VEC(2, 4, 6, 7, 0xFF)}, 0},
@@ -106,39 +101,15 @@ static struct iwl_power_vec_entry range_2[IWL_POWER_MAX] = {
 /* set card power command */
 static int iwl_set_power(struct iwl_priv *priv, void *cmd)
 {
-       return iwl_send_cmd_pdu_async(priv, POWER_TABLE_CMD,
-                                     sizeof(struct iwl_powertable_cmd),
-                                     cmd, NULL);
-}
-/* decide the right power level according to association status
- * and battery status
- */
-static u16 iwl_get_auto_power_mode(struct iwl_priv *priv)
-{
-       u16 mode;
-
-       switch (priv->power_data.user_power_setting) {
-       case IWL_POWER_AUTO:
-               /* if running on battery */
-               if (priv->power_data.is_battery_active)
-                       mode = IWL_POWER_ON_BATTERY;
-               else if (iwl_is_associated(priv))
-                       mode = IWL_POWER_ON_AC_ASSOC;
-               else
-                       mode = IWL_POWER_ON_AC_DISASSOC;
-               break;
-       default:
-               mode = priv->power_data.user_power_setting;
-               break;
-       }
-       return mode;
+       return iwl_send_cmd_pdu(priv, POWER_TABLE_CMD,
+                               sizeof(struct iwl_powertable_cmd), cmd);
 }
 
 /* initialize to default */
 static void iwl_power_init_handle(struct iwl_priv *priv)
 {
        struct iwl_power_mgr *pow_data;
-       int size = sizeof(struct iwl_power_vec_entry) * IWL_POWER_MAX;
+       int size = sizeof(struct iwl_power_vec_entry) * IWL_POWER_NUM;
        struct iwl_powertable_cmd *cmd;
        int i;
        u16 lctl;
@@ -157,7 +128,7 @@ static void iwl_power_init_handle(struct iwl_priv *priv)
 
        IWL_DEBUG_POWER(priv, "adjust power command flags\n");
 
-       for (i = 0; i < IWL_POWER_MAX; i++) {
+       for (i = 0; i < IWL_POWER_NUM; i++) {
                cmd = &pow_data->pwr_range_0[i].cmd;
 
                if (lctl & PCI_CFG_LINK_CTRL_VAL_L0S_EN)
@@ -247,33 +218,12 @@ int iwl_power_update_mode(struct iwl_priv *priv, bool force)
        update_chains = priv->chain_noise_data.state == IWL_CHAIN_NOISE_DONE ||
                        priv->chain_noise_data.state == IWL_CHAIN_NOISE_ALIVE;
 
-       /* If on battery, set to 3,
-        * if plugged into AC power, set to CAM ("continuously aware mode"),
-        * else user level */
-
-       switch (setting->system_power_setting) {
-       case IWL_POWER_SYS_AUTO:
-               final_mode = iwl_get_auto_power_mode(priv);
-               break;
-       case IWL_POWER_SYS_BATTERY:
-               final_mode = IWL_POWER_INDEX_3;
-               break;
-       case IWL_POWER_SYS_AC:
-               final_mode = IWL_POWER_MODE_CAM;
-               break;
-       default:
-               final_mode = IWL_POWER_INDEX_3;
-               WARN_ON(1);
-       }
-
-       if (setting->critical_power_setting > final_mode)
-               final_mode = setting->critical_power_setting;
+       final_mode = priv->power_data.user_power_setting;
 
-       /* driver only support CAM for non STA network */
-       if (priv->iw_mode != NL80211_IFTYPE_STATION)
+       if (setting->power_disabled)
                final_mode = IWL_POWER_MODE_CAM;
 
-       if (iwl_is_ready_rf(priv) && !setting->power_disabled &&
+       if (iwl_is_ready_rf(priv) &&
            ((setting->power_mode != final_mode) || force)) {
                struct iwl_powertable_cmd cmd;
 
@@ -290,8 +240,6 @@ int iwl_power_update_mode(struct iwl_priv *priv, bool force)
 
                if (final_mode == IWL_POWER_MODE_CAM)
                        clear_bit(STATUS_POWER_PMI, &priv->status);
-               else
-                       set_bit(STATUS_POWER_PMI, &priv->status);
 
                if (priv->cfg->ops->lib->update_chain_flags && update_chains)
                        priv->cfg->ops->lib->update_chain_flags(priv);
@@ -307,51 +255,10 @@ int iwl_power_update_mode(struct iwl_priv *priv, bool force)
 }
 EXPORT_SYMBOL(iwl_power_update_mode);
 
-/* Allow other iwl code to disable/enable power management active
- * this will be useful for rate scale to disable PM during heavy
- * Tx/Rx activities
- */
-int iwl_power_disable_management(struct iwl_priv *priv, u32 ms)
-{
-       u16 prev_mode;
-       int ret = 0;
-
-       if (priv->power_data.power_disabled)
-               return -EBUSY;
-
-       prev_mode = priv->power_data.user_power_setting;
-       priv->power_data.user_power_setting = IWL_POWER_MODE_CAM;
-       ret = iwl_power_update_mode(priv, 0);
-       priv->power_data.power_disabled = 1;
-       priv->power_data.user_power_setting = prev_mode;
-       cancel_delayed_work(&priv->set_power_save);
-       if (ms)
-               queue_delayed_work(priv->workqueue, &priv->set_power_save,
-                                  msecs_to_jiffies(ms));
-
-
-       return ret;
-}
-EXPORT_SYMBOL(iwl_power_disable_management);
-
-/* Allow other iwl code to disable/enable power management active
- * this will be useful for rate scale to disable PM during high
- * volume activities
- */
-int iwl_power_enable_management(struct iwl_priv *priv)
-{
-       int ret = 0;
-
-       priv->power_data.power_disabled = 0;
-       ret = iwl_power_update_mode(priv, 0);
-       return ret;
-}
-EXPORT_SYMBOL(iwl_power_enable_management);
-
 /* set user_power_setting */
 int iwl_power_set_user_mode(struct iwl_priv *priv, u16 mode)
 {
-       if (mode > IWL_POWER_MAX)
+       if (mode >= IWL_POWER_NUM)
                return -EINVAL;
 
        priv->power_data.user_power_setting = mode;
@@ -360,86 +267,12 @@ int iwl_power_set_user_mode(struct iwl_priv *priv, u16 mode)
 }
 EXPORT_SYMBOL(iwl_power_set_user_mode);
 
-/* set system_power_setting. This should be set by over all
- * PM application.
- */
-int iwl_power_set_system_mode(struct iwl_priv *priv, u16 mode)
-{
-       if (mode < IWL_POWER_SYS_MAX)
-               priv->power_data.system_power_setting = mode;
-       else
-               return -EINVAL;
-       return iwl_power_update_mode(priv, 0);
-}
-EXPORT_SYMBOL(iwl_power_set_system_mode);
-
 /* initialize to default */
 void iwl_power_initialize(struct iwl_priv *priv)
 {
        iwl_power_init_handle(priv);
-       priv->power_data.user_power_setting = IWL_POWER_AUTO;
-       priv->power_data.system_power_setting = IWL_POWER_SYS_AUTO;
-       priv->power_data.power_disabled = 0;
-       priv->power_data.is_battery_active = 0;
-       priv->power_data.critical_power_setting = 0;
+       priv->power_data.user_power_setting = IWL_POWER_INDEX_1;
+       /* default to disabled until mac80211 says otherwise */
+       priv->power_data.power_disabled = 1;
 }
 EXPORT_SYMBOL(iwl_power_initialize);
-
-/* set critical_power_setting according to temperature value */
-int iwl_power_temperature_change(struct iwl_priv *priv)
-{
-       int ret = 0;
-       s32 temperature = KELVIN_TO_CELSIUS(priv->last_temperature);
-       u16 new_critical = priv->power_data.critical_power_setting;
-
-       if (temperature > IWL_CT_KILL_TEMPERATURE)
-               return 0;
-       else if (temperature > IWL_MIN_POWER_TEMPERATURE)
-               new_critical = IWL_POWER_INDEX_5;
-       else if (temperature > IWL_REDUCED_POWER_TEMPERATURE)
-               new_critical = IWL_POWER_INDEX_3;
-       else
-               new_critical = IWL_POWER_MODE_CAM;
-
-       if (new_critical != priv->power_data.critical_power_setting)
-               priv->power_data.critical_power_setting = new_critical;
-
-       if (priv->power_data.critical_power_setting >
-                               priv->power_data.power_mode)
-               ret = iwl_power_update_mode(priv, 0);
-
-       return ret;
-}
-EXPORT_SYMBOL(iwl_power_temperature_change);
-
-static void iwl_bg_set_power_save(struct work_struct *work)
-{
-       struct iwl_priv *priv = container_of(work,
-                               struct iwl_priv, set_power_save.work);
-       IWL_DEBUG_POWER(priv, "update power\n");
-
-       if (test_bit(STATUS_EXIT_PENDING, &priv->status))
-               return;
-
-       mutex_lock(&priv->mutex);
-
-       /* on starting association we disable power management
-        * until association, if association failed then this
-        * timer will expire and enable PM again.
-        */
-       if (!iwl_is_associated(priv))
-               iwl_power_enable_management(priv);
-
-       mutex_unlock(&priv->mutex);
-}
-void iwl_setup_power_deferred_work(struct iwl_priv *priv)
-{
-       INIT_DELAYED_WORK(&priv->set_power_save, iwl_bg_set_power_save);
-}
-EXPORT_SYMBOL(iwl_setup_power_deferred_work);
-
-void iwl_power_cancel_timeout(struct iwl_priv *priv)
-{
-       cancel_delayed_work(&priv->set_power_save);
-}
-EXPORT_SYMBOL(iwl_power_cancel_timeout);