Skip to content

Commit

Permalink
iwlwifi: rework for static power save
Browse files Browse the repository at this point in the history
For static power save, the actual intervals are calculated by driver based on
the default table and DTIM flag, then sent to uCode when the scheme
is changed.

Three tables are defined based on DTIM period.
	1. DTIM 0 - 2
	2. DTIM 3 - 10
	3. DTIM > 11

The actual number of DTIM a station may miss may not exceed the
following:
	. Only 1 DTIM may be skipped at PI=4 when allowed
	. Only 2 DTIMs may be skipped at PI=5 when allowed
	. DTIM may be skipped only 5 sec after last activity
	. DTIM may be skipped only 30 sec after connection establishment

Only allow user to override the power_level when rf is ready to make sure
power level gets changed upon request.

Signed-off-by: Wey-Yi Guy <wey-yi.w.guy@intel.com>
Signed-off-by: Reinette Chatre <reinette.chatre@intel.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
  • Loading branch information
Wey-Yi Guy authored and John W. Linville committed Oct 27, 2009
1 parent 9444b18 commit 4ad177b
Show file tree
Hide file tree
Showing 3 changed files with 59 additions and 23 deletions.
5 changes: 4 additions & 1 deletion drivers/net/wireless/iwlwifi/iwl-debugfs.c
Original file line number Diff line number Diff line change
Expand Up @@ -809,9 +809,12 @@ static ssize_t iwl_dbgfs_sleep_level_override_write(struct file *file,
if (value != -1 && (value < 0 || value >= IWL_POWER_NUM))
return -EINVAL;

if (!iwl_is_ready_rf(priv))
return -EAGAIN;

priv->power_data.debug_sleep_level_override = value;

iwl_power_update_mode(priv, false);
iwl_power_update_mode(priv, true);

return count;
}
Expand Down
75 changes: 53 additions & 22 deletions drivers/net/wireless/iwlwifi/iwl-power.c
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ MODULE_PARM_DESC(no_sleep_autoadjust,

struct iwl_power_vec_entry {
struct iwl_powertable_cmd cmd;
u8 no_dtim;
u8 no_dtim; /* number of skip dtim */
};

#define IWL_DTIM_RANGE_0_MAX 2
Expand All @@ -83,8 +83,9 @@ struct iwl_power_vec_entry {
cpu_to_le32(X4)}
/* default power management (not Tx power) table values */
/* for DTIM period 0 through IWL_DTIM_RANGE_0_MAX */
/* DTIM 0 - 2 */
static const struct iwl_power_vec_entry range_0[IWL_POWER_NUM] = {
{{SLP, SLP_TOUT(200), SLP_TOUT(500), SLP_VEC(1, 2, 2, 2, 0xFF)}, 0},
{{SLP, SLP_TOUT(200), SLP_TOUT(500), SLP_VEC(1, 1, 2, 2, 0xFF)}, 0},
{{SLP, SLP_TOUT(200), SLP_TOUT(300), SLP_VEC(1, 2, 2, 2, 0xFF)}, 0},
{{SLP, SLP_TOUT(50), SLP_TOUT(100), SLP_VEC(2, 2, 2, 2, 0xFF)}, 0},
{{SLP, SLP_TOUT(50), SLP_TOUT(25), SLP_VEC(2, 2, 4, 4, 0xFF)}, 1},
Expand All @@ -93,15 +94,17 @@ static const struct iwl_power_vec_entry range_0[IWL_POWER_NUM] = {


/* for DTIM period IWL_DTIM_RANGE_0_MAX + 1 through IWL_DTIM_RANGE_1_MAX */
/* DTIM 3 - 10 */
static const struct iwl_power_vec_entry range_1[IWL_POWER_NUM] = {
{{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},
{{SLP, SLP_TOUT(50), SLP_TOUT(100), SLP_VEC(2, 4, 6, 7, 9)}, 0},
{{SLP, SLP_TOUT(50), SLP_TOUT(25), SLP_VEC(2, 4, 6, 9, 10)}, 1},
{{SLP, SLP_TOUT(25), SLP_TOUT(25), SLP_VEC(2, 4, 7, 10, 10)}, 2}
{{SLP, SLP_TOUT(25), SLP_TOUT(25), SLP_VEC(2, 4, 6, 10, 10)}, 2}
};

/* for DTIM period > IWL_DTIM_RANGE_1_MAX */
/* DTIM 11 - */
static const struct iwl_power_vec_entry range_2[IWL_POWER_NUM] = {
{{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},
Expand All @@ -115,48 +118,76 @@ static void iwl_static_sleep_cmd(struct iwl_priv *priv,
enum iwl_power_level lvl, int period)
{
const struct iwl_power_vec_entry *table;
int max_sleep, i;
bool skip;
int max_sleep[IWL_POWER_VEC_SIZE] = { 0 };
int i;
u8 skip;
u32 slp_itrvl;

table = range_2;
if (period < IWL_DTIM_RANGE_1_MAX)
if (period <= IWL_DTIM_RANGE_1_MAX)
table = range_1;
if (period < IWL_DTIM_RANGE_0_MAX)
if (period <= IWL_DTIM_RANGE_0_MAX)
table = range_0;

BUG_ON(lvl < 0 || lvl >= IWL_POWER_NUM);

*cmd = table[lvl].cmd;

if (period == 0) {
skip = false;
skip = 0;
period = 1;
for (i = 0; i < IWL_POWER_VEC_SIZE; i++)
max_sleep[i] = 1;

} else {
skip = !!table[lvl].no_dtim;
skip = table[lvl].no_dtim;
for (i = 0; i < IWL_POWER_VEC_SIZE; i++)
max_sleep[i] = le32_to_cpu(cmd->sleep_interval[i]);
max_sleep[IWL_POWER_VEC_SIZE - 1] = skip + 1;
}

if (skip) {
__le32 slp_itrvl = cmd->sleep_interval[IWL_POWER_VEC_SIZE - 1];
max_sleep = le32_to_cpu(slp_itrvl);
if (max_sleep == 0xFF)
max_sleep = period * (skip + 1);
else if (max_sleep > period)
max_sleep = (le32_to_cpu(slp_itrvl) / period) * period;
slp_itrvl = le32_to_cpu(cmd->sleep_interval[IWL_POWER_VEC_SIZE - 1]);
/* figure out the listen interval based on dtim period and skip */
if (slp_itrvl == 0xFF)
cmd->sleep_interval[IWL_POWER_VEC_SIZE - 1] =
cpu_to_le32(period * (skip + 1));

slp_itrvl = le32_to_cpu(cmd->sleep_interval[IWL_POWER_VEC_SIZE - 1]);
if (slp_itrvl > period)
cmd->sleep_interval[IWL_POWER_VEC_SIZE - 1] =
cpu_to_le32((slp_itrvl / period) * period);

if (skip)
cmd->flags |= IWL_POWER_SLEEP_OVER_DTIM_MSK;
} else {
max_sleep = period;
else
cmd->flags &= ~IWL_POWER_SLEEP_OVER_DTIM_MSK;
}

for (i = 0; i < IWL_POWER_VEC_SIZE; i++)
if (le32_to_cpu(cmd->sleep_interval[i]) > max_sleep)
cmd->sleep_interval[i] = cpu_to_le32(max_sleep);
slp_itrvl = le32_to_cpu(cmd->sleep_interval[IWL_POWER_VEC_SIZE - 1]);
if (slp_itrvl > IWL_CONN_LISTEN_INTERVAL)
cmd->sleep_interval[IWL_POWER_VEC_SIZE - 1] =
cpu_to_le32(IWL_CONN_LISTEN_INTERVAL);

/* enforce max sleep interval */
for (i = IWL_POWER_VEC_SIZE - 1; i >= 0 ; i--) {
if (le32_to_cpu(cmd->sleep_interval[i]) >
(max_sleep[i] * period))
cmd->sleep_interval[i] =
cpu_to_le32(max_sleep[i] * period);
if (i != (IWL_POWER_VEC_SIZE - 1)) {
if (le32_to_cpu(cmd->sleep_interval[i]) >
le32_to_cpu(cmd->sleep_interval[i+1]))
cmd->sleep_interval[i] =
cmd->sleep_interval[i+1];
}
}

if (priv->power_data.pci_pm)
cmd->flags |= IWL_POWER_PCI_PM_MSK;
else
cmd->flags &= ~IWL_POWER_PCI_PM_MSK;

IWL_DEBUG_POWER(priv, "numSkipDtim = %u, dtimPeriod = %d\n",
skip, period);
IWL_DEBUG_POWER(priv, "Sleep command for index %d\n", lvl + 1);
}

Expand Down
2 changes: 2 additions & 0 deletions drivers/net/wireless/iwlwifi/iwl-power.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@

#include "iwl-commands.h"

#define IWL_CONN_LISTEN_INTERVAL 10

#define IWL_ABSOLUTE_ZERO 0
#define IWL_ABSOLUTE_MAX 0xFFFFFFFF
#define IWL_TT_INCREASE_MARGIN 5
Expand Down

0 comments on commit 4ad177b

Please sign in to comment.