iwl-power.c 12.5 KB
Newer Older
1
2
/******************************************************************************
 *
Wey-Yi Guy's avatar
Wey-Yi Guy committed
3
 * Copyright(c) 2007 - 2012 Intel Corporation. All rights reserved.
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
 *
 * Portions of this file are derived from the ipw3945 project, as well
 * as portions of the ieee80211 subsystem header files.
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of version 2 of the GNU General Public License as
 * published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
 * more details.
 *
 * You should have received a copy of the GNU General Public License along with
 * this program; if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
 *
 * The full GNU General Public License is included in this distribution in the
 * file called LICENSE.
 *
 * Contact Information:
25
 *  Intel Linux Wireless <ilw@linux.intel.com>
26
27
28
29
30
31
 * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
 *****************************************************************************/


#include <linux/kernel.h>
#include <linux/module.h>
32
#include <linux/slab.h>
33
34
35
36
37
#include <linux/init.h>

#include <net/mac80211.h>

#include "iwl-eeprom.h"
38
#include "iwl-dev.h"
39
#include "iwl-agn.h"
40
#include "iwl-io.h"
41
#include "iwl-commands.h"
42
43
#include "iwl-debug.h"
#include "iwl-power.h"
44
#include "iwl-trans.h"
45
#include "iwl-modparams.h"
46
47

/*
48
 * Setting power level allows the card to go to sleep when not busy.
49
 *
50
51
52
 * We calculate a sleep command based on the required latency, which
 * we get from mac80211. In order to handle thermal throttling, we can
 * also use pre-defined power levels.
53
54
 */

55
56
57
58
59
60
61
/*
 * This defines the old power levels. They are still used by default
 * (level 1) and for thermal throttle (levels 3 through 5)
 */

struct iwl_power_vec_entry {
	struct iwl_powertable_cmd cmd;
62
	u8 no_dtim;	/* number of skip dtim */
63
64
65
66
};

#define IWL_DTIM_RANGE_0_MAX	2
#define IWL_DTIM_RANGE_1_MAX	10
67

Johannes Berg's avatar
Johannes Berg committed
68
69
#define NOSLP cpu_to_le16(0), 0, 0
#define SLP IWL_POWER_DRIVER_ALLOW_SLEEP_MSK, 0, 0
70
71
72
73
#define ASLP (IWL_POWER_POWER_SAVE_ENA_MSK |	\
		IWL_POWER_POWER_MANAGEMENT_ENA_MSK | \
		IWL_POWER_ADVANCE_PM_ENA_MSK)
#define ASLP_TOUT(T) cpu_to_le32(T)
Johannes Berg's avatar
Johannes Berg committed
74
75
76
77
78
79
80
#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)}
81
/* default power management (not Tx power) table values */
82
/* for DTIM period 0 through IWL_DTIM_RANGE_0_MAX */
83
/* DTIM 0 - 2 */
Johannes Berg's avatar
Johannes Berg committed
84
static const struct iwl_power_vec_entry range_0[IWL_POWER_NUM] = {
85
	{{SLP, SLP_TOUT(200), SLP_TOUT(500), SLP_VEC(1, 1, 2, 2, 0xFF)}, 0},
86
87
88
89
90
91
92
	{{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},
	{{SLP, SLP_TOUT(25), SLP_TOUT(25), SLP_VEC(2, 2, 4, 6, 0xFF)}, 2}
};


93
/* for DTIM period IWL_DTIM_RANGE_0_MAX + 1 through IWL_DTIM_RANGE_1_MAX */
94
/* DTIM 3 - 10 */
Johannes Berg's avatar
Johannes Berg committed
95
static const struct iwl_power_vec_entry range_1[IWL_POWER_NUM] = {
96
97
98
99
	{{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},
100
	{{SLP, SLP_TOUT(25), SLP_TOUT(25), SLP_VEC(2, 4, 6, 10, 10)}, 2}
101
102
};

103
/* for DTIM period > IWL_DTIM_RANGE_1_MAX */
104
/* DTIM 11 - */
Johannes Berg's avatar
Johannes Berg committed
105
static const struct iwl_power_vec_entry range_2[IWL_POWER_NUM] = {
106
107
108
109
110
111
112
	{{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},
	{{SLP, SLP_TOUT(50), SLP_TOUT(100), SLP_VEC(2, 7, 9, 9, 0xFF)}, 0},
	{{SLP, SLP_TOUT(50), SLP_TOUT(25), SLP_VEC(2, 7, 9, 9, 0xFF)}, 0},
	{{SLP, SLP_TOUT(25), SLP_TOUT(25), SLP_VEC(4, 7, 10, 10, 0xFF)}, 0}
};

113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
/* advance power management */
/* DTIM 0 - 2 */
static const struct iwl_power_vec_entry apm_range_0[IWL_POWER_NUM] = {
	{{ASLP, 0, 0, ASLP_TOUT(50), ASLP_TOUT(50),
		SLP_VEC(1, 2, 4, 6, 0xFF), 0}, 0},
	{{ASLP, 0, 0, ASLP_TOUT(50), ASLP_TOUT(50),
		SLP_VEC(1, 2, 4, 6, 0xFF), 0}, 0},
	{{ASLP, 0, 0, ASLP_TOUT(50), ASLP_TOUT(50),
		SLP_VEC(1, 2, 4, 6, 0xFF), 0}, 0},
	{{ASLP, 0, 0, ASLP_TOUT(50), ASLP_TOUT(50),
		SLP_VEC(1, 2, 4, 6, 0xFF), 0}, 0},
	{{ASLP, 0, 0, ASLP_TOUT(50), ASLP_TOUT(50),
		SLP_VEC(1, 2, 6, 8, 0xFF), ASLP_TOUT(2)}, 2}
};


/* 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 apm_range_1[IWL_POWER_NUM] = {
	{{ASLP, 0, 0, ASLP_TOUT(50), ASLP_TOUT(50),
		SLP_VEC(1, 2, 4, 6, 0xFF), 0}, 0},
	{{ASLP, 0, 0, ASLP_TOUT(50), ASLP_TOUT(50),
		SLP_VEC(1, 2, 4, 6, 0xFF), 0}, 0},
	{{ASLP, 0, 0, ASLP_TOUT(50), ASLP_TOUT(50),
		SLP_VEC(1, 2, 4, 6, 0xFF), 0}, 0},
	{{ASLP, 0, 0, ASLP_TOUT(50), ASLP_TOUT(50),
		SLP_VEC(1, 2, 4, 6, 0xFF), 0}, 0},
	{{ASLP, 0, 0, ASLP_TOUT(50), ASLP_TOUT(50),
		SLP_VEC(1, 2, 6, 8, 0xFF), 0}, 2}
};

/* for DTIM period > IWL_DTIM_RANGE_1_MAX */
/* DTIM 11 - */
static const struct iwl_power_vec_entry apm_range_2[IWL_POWER_NUM] = {
	{{ASLP, 0, 0, ASLP_TOUT(50), ASLP_TOUT(50),
		SLP_VEC(1, 2, 4, 6, 0xFF), 0}, 0},
	{{ASLP, 0, 0, ASLP_TOUT(50), ASLP_TOUT(50),
		SLP_VEC(1, 2, 4, 6, 0xFF), 0}, 0},
	{{ASLP, 0, 0, ASLP_TOUT(50), ASLP_TOUT(50),
		SLP_VEC(1, 2, 4, 6, 0xFF), 0}, 0},
	{{ASLP, 0, 0, ASLP_TOUT(50), ASLP_TOUT(50),
		SLP_VEC(1, 2, 4, 6, 0xFF), 0}, 0},
	{{ASLP, 0, 0, ASLP_TOUT(50), ASLP_TOUT(50),
		SLP_VEC(1, 2, 6, 8, 0xFF), ASLP_TOUT(2)}, 2}
};

159
160
161
162
163
static void iwl_static_sleep_cmd(struct iwl_priv *priv,
				 struct iwl_powertable_cmd *cmd,
				 enum iwl_power_level lvl, int period)
{
	const struct iwl_power_vec_entry *table;
164
165
166
167
	int max_sleep[IWL_POWER_VEC_SIZE] = { 0 };
	int i;
	u8 skip;
	u32 slp_itrvl;
168

169
	if (priv->cfg->adv_pm) {
170
171
172
173
174
175
176
177
178
179
180
181
		table = apm_range_2;
		if (period <= IWL_DTIM_RANGE_1_MAX)
			table = apm_range_1;
		if (period <= IWL_DTIM_RANGE_0_MAX)
			table = apm_range_0;
	} else {
		table = range_2;
		if (period <= IWL_DTIM_RANGE_1_MAX)
			table = range_1;
		if (period <= IWL_DTIM_RANGE_0_MAX)
			table = range_0;
	}
182

183
184
185
186
	if (WARN_ON(lvl < 0 || lvl >= IWL_POWER_NUM))
		memset(cmd, 0, sizeof(*cmd));
	else
		*cmd = table[lvl].cmd;
187
188

	if (period == 0) {
189
		skip = 0;
190
		period = 1;
191
192
193
		for (i = 0; i < IWL_POWER_VEC_SIZE; i++)
			max_sleep[i] =  1;

194
	} else {
195
196
197
198
		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;
199
200
	}

201
202
203
204
205
206
207
208
209
210
211
212
	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)
213
		cmd->flags |= IWL_POWER_SLEEP_OVER_DTIM_MSK;
214
	else
215
216
		cmd->flags &= ~IWL_POWER_SLEEP_OVER_DTIM_MSK;

217
	if (priv->cfg->base_params->shadow_reg_enable)
218
219
220
221
		cmd->flags |= IWL_POWER_SHADOW_REG_ENA;
	else
		cmd->flags &= ~IWL_POWER_SHADOW_REG_ENA;

222
	if (iwl_advanced_bt_coexist(priv)) {
223
		if (!priv->cfg->bt_params->bt_sco_disable)
224
225
226
227
228
229
			cmd->flags |= IWL_POWER_BT_SCO_ENA;
		else
			cmd->flags &= ~IWL_POWER_BT_SCO_ENA;
	}


230
	slp_itrvl = le32_to_cpu(cmd->sleep_interval[IWL_POWER_VEC_SIZE - 1]);
Wey-Yi Guy's avatar
Wey-Yi Guy committed
231
	if (slp_itrvl > IWL_CONN_MAX_LISTEN_INTERVAL)
232
		cmd->sleep_interval[IWL_POWER_VEC_SIZE - 1] =
Wey-Yi Guy's avatar
Wey-Yi Guy committed
233
			cpu_to_le32(IWL_CONN_MAX_LISTEN_INTERVAL);
234
235
236
237
238
239
240
241
242
243
244
245
246
247

	/* 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];
		}
	}
248

249
	if (priv->power_data.bus_pm)
250
251
252
253
		cmd->flags |= IWL_POWER_PCI_PM_MSK;
	else
		cmd->flags &= ~IWL_POWER_PCI_PM_MSK;

254
255
	IWL_DEBUG_POWER(priv, "numSkipDtim = %u, dtimPeriod = %d\n",
			skip, period);
Amit Beka's avatar
Amit Beka committed
256
257
	/* The power level here is 0-4 (used as array index), but user expects
	to see 1-5 (according to spec). */
258
259
260
261
262
	IWL_DEBUG_POWER(priv, "Sleep command for index %d\n", lvl + 1);
}

static void iwl_power_sleep_cam_cmd(struct iwl_priv *priv,
				    struct iwl_powertable_cmd *cmd)
263
{
264
	memset(cmd, 0, sizeof(*cmd));
265

266
	if (priv->power_data.bus_pm)
267
		cmd->flags |= IWL_POWER_PCI_PM_MSK;
268

269
	IWL_DEBUG_POWER(priv, "Sleep command for CAM\n");
270
271
}

272
273
274
static int iwl_set_power(struct iwl_priv *priv, struct iwl_powertable_cmd *cmd)
{
	IWL_DEBUG_POWER(priv, "Sending power/sleep command\n");
275
276
277
278
	IWL_DEBUG_POWER(priv, "Flags value = 0x%08X\n", cmd->flags);
	IWL_DEBUG_POWER(priv, "Tx timeout = %u\n", le32_to_cpu(cmd->tx_data_timeout));
	IWL_DEBUG_POWER(priv, "Rx timeout = %u\n", le32_to_cpu(cmd->rx_data_timeout));
	IWL_DEBUG_POWER(priv, "Sleep interval vector = { %d , %d , %d , %d , %d }\n",
279
280
281
282
283
284
			le32_to_cpu(cmd->sleep_interval[0]),
			le32_to_cpu(cmd->sleep_interval[1]),
			le32_to_cpu(cmd->sleep_interval[2]),
			le32_to_cpu(cmd->sleep_interval[3]),
			le32_to_cpu(cmd->sleep_interval[4]));

285
	return iwl_dvm_send_cmd_pdu(priv, POWER_TABLE_CMD, CMD_SYNC,
286
				sizeof(struct iwl_powertable_cmd), cmd);
287
288
}

289
290
static void iwl_power_build_cmd(struct iwl_priv *priv,
				struct iwl_powertable_cmd *cmd)
291
{
292
	bool enabled = priv->hw->conf.flags & IEEE80211_CONF_PS;
293
	int dtimper;
294

295
	dtimper = priv->hw->conf.ps_dtim_period ?: 1;
296

297
	if (priv->wowlan)
Johannes Berg's avatar
Johannes Berg committed
298
		iwl_static_sleep_cmd(priv, cmd, IWL_POWER_INDEX_5, dtimper);
299
	else if (!priv->cfg->base_params->no_idle_support &&
300
		 priv->hw->conf.flags & IEEE80211_CONF_IDLE)
301
		iwl_static_sleep_cmd(priv, cmd, IWL_POWER_INDEX_5, 20);
302
	else if (iwl_tt_is_low_power_state(priv)) {
303
		/* in thermal throttling low power state */
304
		iwl_static_sleep_cmd(priv, cmd,
305
		    iwl_tt_current_power_mode(priv), dtimper);
306
	} else if (!enabled)
307
		iwl_power_sleep_cam_cmd(priv, cmd);
308
	else if (priv->power_data.debug_sleep_level_override >= 0)
309
		iwl_static_sleep_cmd(priv, cmd,
310
311
				     priv->power_data.debug_sleep_level_override,
				     dtimper);
312
	else {
Amit Beka's avatar
Amit Beka committed
313
314
		/* Note that the user parameter is 1-5 (according to spec),
		but we pass 0-4 because it acts as an array index. */
315
		if (iwlwifi_mod_params.power_level > IWL_POWER_INDEX_1 &&
Amit Beka's avatar
Amit Beka committed
316
		    iwlwifi_mod_params.power_level <= IWL_POWER_NUM)
317
			iwl_static_sleep_cmd(priv, cmd,
Amit Beka's avatar
Amit Beka committed
318
				iwlwifi_mod_params.power_level - 1, dtimper);
319
320
321
		else
			iwl_static_sleep_cmd(priv, cmd,
				IWL_POWER_INDEX_1, dtimper);
322
	}
323
324
325
326
327
328
329
330
}

int iwl_power_set_mode(struct iwl_priv *priv, struct iwl_powertable_cmd *cmd,
		       bool force)
{
	int ret;
	bool update_chains;

331
	lockdep_assert_held(&priv->mutex);
332
333
334
335
336
337
338
339

	/* 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;

	if (!memcmp(&priv->power_data.sleep_cmd, cmd, sizeof(*cmd)) && !force)
		return 0;

Don Fry's avatar
Don Fry committed
340
	if (!iwl_is_ready_rf(priv))
341
342
343
344
		return -EIO;

	/* scan complete use sleep_power_next, need to be updated */
	memcpy(&priv->power_data.sleep_cmd_next, cmd, sizeof(*cmd));
Don Fry's avatar
Don Fry committed
345
	if (test_bit(STATUS_SCANNING, &priv->status) && !force) {
346
347
348
349
350
		IWL_DEBUG_INFO(priv, "Defer power set mode while scanning\n");
		return 0;
	}

	if (cmd->flags & IWL_POWER_DRIVER_ALLOW_SLEEP_MSK)
Don Fry's avatar
Don Fry committed
351
		iwl_dvm_set_pmi(priv, true);
352

353
354
355
	ret = iwl_set_power(priv, cmd);
	if (!ret) {
		if (!(cmd->flags & IWL_POWER_DRIVER_ALLOW_SLEEP_MSK))
Don Fry's avatar
Don Fry committed
356
			iwl_dvm_set_pmi(priv, false);
357

358
359
360
		if (update_chains)
			iwl_update_chain_flags(priv);
		else
361
			IWL_DEBUG_POWER(priv,
362
					"Cannot update the power, chain noise "
363
364
					"calibration running: %d\n",
					priv->chain_noise_data.state);
365
366
367
368

		memcpy(&priv->power_data.sleep_cmd, cmd, sizeof(*cmd));
	} else
		IWL_ERR(priv, "set power fail, ret = %d", ret);
369
370
371

	return ret;
}
372
373
374
375
376
377
378
379

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);
}
380

381
/* initialize to default */
382
383
void iwl_power_initialize(struct iwl_priv *priv)
{
384
	priv->power_data.bus_pm = priv->trans->pm_support;
385
386
387
388
389

	priv->power_data.debug_sleep_level_override = -1;

	memset(&priv->power_data.sleep_cmd, 0,
		sizeof(priv->power_data.sleep_cmd));
390
}