diff options
Diffstat (limited to 'drivers/net/wireless/iwlwifi/iwl-power.c')
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-power.c | 233 |
1 files changed, 33 insertions, 200 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-power.c b/drivers/net/wireless/iwlwifi/iwl-power.c index 47c894530eb..f2ea3f05f6e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-power.c +++ b/drivers/net/wireless/iwlwifi/iwl-power.c @@ -41,38 +41,33 @@ #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); |