iwlwifi: defer update power mode while scan

Do not set power mode when scanning, and defer that when scan finish.
We still set power mode in force case i.e. when device is overheated.

Signed-off-by: Stanislaw Gruszka <sgruszka@redhat.com>
Acked-by:  Wey-Yi Guy <wey-yi.w.guy@intel.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
This commit is contained in:
Stanislaw Gruszka 2010-10-22 17:04:29 +02:00 committed by John W. Linville
parent 5eda74a405
commit ac4f5457c7
3 changed files with 75 additions and 46 deletions

View File

@ -263,70 +263,95 @@ static int iwl_set_power(struct iwl_priv *priv, struct iwl_powertable_cmd *cmd)
sizeof(struct iwl_powertable_cmd), cmd);
}
/* priv->mutex must be held */
int iwl_power_update_mode(struct iwl_priv *priv, bool force)
static void iwl_power_build_cmd(struct iwl_priv *priv,
struct iwl_powertable_cmd *cmd)
{
int ret = 0;
bool enabled = priv->hw->conf.flags & IEEE80211_CONF_PS;
bool update_chains;
struct iwl_powertable_cmd cmd;
int dtimper;
dtimper = priv->hw->conf.ps_dtim_period ?: 1;
if (priv->cfg->base_params->broken_powersave)
iwl_power_sleep_cam_cmd(priv, cmd);
else if (priv->cfg->base_params->supports_idle &&
priv->hw->conf.flags & IEEE80211_CONF_IDLE)
iwl_static_sleep_cmd(priv, cmd, IWL_POWER_INDEX_5, 20);
else if (priv->cfg->ops->lib->tt_ops.lower_power_detection &&
priv->cfg->ops->lib->tt_ops.tt_power_mode &&
priv->cfg->ops->lib->tt_ops.lower_power_detection(priv)) {
/* in thermal throttling low power state */
iwl_static_sleep_cmd(priv, cmd,
priv->cfg->ops->lib->tt_ops.tt_power_mode(priv), dtimper);
} else if (!enabled)
iwl_power_sleep_cam_cmd(priv, cmd);
else if (priv->power_data.debug_sleep_level_override >= 0)
iwl_static_sleep_cmd(priv, cmd,
priv->power_data.debug_sleep_level_override,
dtimper);
else if (no_sleep_autoadjust)
iwl_static_sleep_cmd(priv, cmd, IWL_POWER_INDEX_1, dtimper);
else
iwl_power_fill_sleep_cmd(priv, cmd,
priv->hw->conf.dynamic_ps_timeout,
priv->hw->conf.max_sleep_period);
}
int iwl_power_set_mode(struct iwl_priv *priv, struct iwl_powertable_cmd *cmd,
bool force)
{
int ret;
bool update_chains;
lockdep_assert_held(&priv->mutex);
/* Don't update the RX chain when chain noise calibration is running */
update_chains = priv->chain_noise_data.state == IWL_CHAIN_NOISE_DONE ||
priv->chain_noise_data.state == IWL_CHAIN_NOISE_ALIVE;
dtimper = priv->hw->conf.ps_dtim_period ?: 1;
if (!memcmp(&priv->power_data.sleep_cmd, cmd, sizeof(*cmd)) && !force)
return 0;
if (priv->cfg->base_params->broken_powersave)
iwl_power_sleep_cam_cmd(priv, &cmd);
else if (priv->cfg->base_params->supports_idle &&
priv->hw->conf.flags & IEEE80211_CONF_IDLE)
iwl_static_sleep_cmd(priv, &cmd, IWL_POWER_INDEX_5, 20);
else if (priv->cfg->ops->lib->tt_ops.lower_power_detection &&
priv->cfg->ops->lib->tt_ops.tt_power_mode &&
priv->cfg->ops->lib->tt_ops.lower_power_detection(priv)) {
/* in thermal throttling low power state */
iwl_static_sleep_cmd(priv, &cmd,
priv->cfg->ops->lib->tt_ops.tt_power_mode(priv), dtimper);
} else if (!enabled)
iwl_power_sleep_cam_cmd(priv, &cmd);
else if (priv->power_data.debug_sleep_level_override >= 0)
iwl_static_sleep_cmd(priv, &cmd,
priv->power_data.debug_sleep_level_override,
dtimper);
else if (no_sleep_autoadjust)
iwl_static_sleep_cmd(priv, &cmd, IWL_POWER_INDEX_1, dtimper);
else
iwl_power_fill_sleep_cmd(priv, &cmd,
priv->hw->conf.dynamic_ps_timeout,
priv->hw->conf.max_sleep_period);
if (!iwl_is_ready_rf(priv))
return -EIO;
if (iwl_is_ready_rf(priv) &&
(memcmp(&priv->power_data.sleep_cmd, &cmd, sizeof(cmd)) || force)) {
if (cmd.flags & IWL_POWER_DRIVER_ALLOW_SLEEP_MSK)
set_bit(STATUS_POWER_PMI, &priv->status);
/* scan complete use sleep_power_next, need to be updated */
memcpy(&priv->power_data.sleep_cmd_next, cmd, sizeof(*cmd));
if (test_bit(STATUS_SCANNING, &priv->status) && !force) {
IWL_DEBUG_INFO(priv, "Defer power set mode while scanning\n");
return 0;
}
ret = iwl_set_power(priv, &cmd);
if (!ret) {
if (!(cmd.flags & IWL_POWER_DRIVER_ALLOW_SLEEP_MSK))
clear_bit(STATUS_POWER_PMI, &priv->status);
if (cmd->flags & IWL_POWER_DRIVER_ALLOW_SLEEP_MSK)
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);
else if (priv->cfg->ops->lib->update_chain_flags)
IWL_DEBUG_POWER(priv,
ret = iwl_set_power(priv, cmd);
if (!ret) {
if (!(cmd->flags & IWL_POWER_DRIVER_ALLOW_SLEEP_MSK))
clear_bit(STATUS_POWER_PMI, &priv->status);
if (priv->cfg->ops->lib->update_chain_flags && update_chains)
priv->cfg->ops->lib->update_chain_flags(priv);
else if (priv->cfg->ops->lib->update_chain_flags)
IWL_DEBUG_POWER(priv,
"Cannot update the power, chain noise "
"calibration running: %d\n",
priv->chain_noise_data.state);
memcpy(&priv->power_data.sleep_cmd, &cmd, sizeof(cmd));
} else
IWL_ERR(priv, "set power fail, ret = %d", ret);
}
memcpy(&priv->power_data.sleep_cmd, cmd, sizeof(*cmd));
} else
IWL_ERR(priv, "set power fail, ret = %d", ret);
return ret;
}
EXPORT_SYMBOL(iwl_power_set_mode);
int iwl_power_update_mode(struct iwl_priv *priv, bool force)
{
struct iwl_powertable_cmd cmd;
iwl_power_build_cmd(priv, &cmd);
return iwl_power_set_mode(priv, &cmd, force);
}
EXPORT_SYMBOL(iwl_power_update_mode);
/* initialize to default */

View File

@ -41,10 +41,13 @@ enum iwl_power_level {
struct iwl_power_mgr {
struct iwl_powertable_cmd sleep_cmd;
struct iwl_powertable_cmd sleep_cmd_next;
int debug_sleep_level_override;
bool pci_pm;
};
int iwl_power_set_mode(struct iwl_priv *priv, struct iwl_powertable_cmd *cmd,
bool force);
int iwl_power_update_mode(struct iwl_priv *priv, bool force);
void iwl_power_initialize(struct iwl_priv *priv);

View File

@ -607,6 +607,7 @@ static void iwl_bg_scan_completed(struct work_struct *work)
* We do not commit power settings while scan is pending,
* do it now if the settings changed.
*/
iwl_power_set_mode(priv, &priv->power_data.sleep_cmd_next, false);
iwl_set_tx_power(priv, priv->tx_power_next, false);
priv->cfg->ops->utils->post_scan(priv);