iwl-power.c 14.5 KB
Newer Older
M
Mohamed Abbas 已提交
1 2
/******************************************************************************
 *
3
 * Copyright(c) 2007 - 2010 Intel Corporation. All rights reserved.
M
Mohamed Abbas 已提交
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>
M
Mohamed Abbas 已提交
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>
M
Mohamed Abbas 已提交
33 34 35 36 37
#include <linux/init.h>

#include <net/mac80211.h>

#include "iwl-eeprom.h"
38
#include "iwl-dev.h"
M
Mohamed Abbas 已提交
39
#include "iwl-core.h"
40
#include "iwl-io.h"
41
#include "iwl-commands.h"
M
Mohamed Abbas 已提交
42 43 44 45
#include "iwl-debug.h"
#include "iwl-power.h"

/*
46
 * Setting power level allows the card to go to sleep when not busy.
M
Mohamed Abbas 已提交
47
 *
48 49 50
 * 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.
M
Mohamed Abbas 已提交
51 52
 */

53 54 55 56 57 58 59 60 61
/*
 * For now, keep using power level 1 instead of automatically
 * adjusting ...
 */
bool no_sleep_autoadjust = true;
module_param(no_sleep_autoadjust, bool, S_IRUGO);
MODULE_PARM_DESC(no_sleep_autoadjust,
		 "don't automatically adjust sleep level "
		 "according to maximum network latency");
M
Mohamed Abbas 已提交
62

63 64 65 66 67 68 69
/*
 * 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;
W
Wey-Yi Guy 已提交
70
	u8 no_dtim;	/* number of skip dtim */
71 72 73 74
};

#define IWL_DTIM_RANGE_0_MAX	2
#define IWL_DTIM_RANGE_1_MAX	10
M
Mohamed Abbas 已提交
75

J
Johannes Berg 已提交
76 77
#define NOSLP cpu_to_le16(0), 0, 0
#define SLP IWL_POWER_DRIVER_ALLOW_SLEEP_MSK, 0, 0
78 79 80 81
#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)
J
Johannes Berg 已提交
82 83 84 85 86 87 88
#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)}
M
Mohamed Abbas 已提交
89
/* default power management (not Tx power) table values */
90
/* for DTIM period 0 through IWL_DTIM_RANGE_0_MAX */
W
Wey-Yi Guy 已提交
91
/* DTIM 0 - 2 */
J
Johannes Berg 已提交
92
static const struct iwl_power_vec_entry range_0[IWL_POWER_NUM] = {
W
Wey-Yi Guy 已提交
93
	{{SLP, SLP_TOUT(200), SLP_TOUT(500), SLP_VEC(1, 1, 2, 2, 0xFF)}, 0},
M
Mohamed Abbas 已提交
94 95 96 97 98 99 100
	{{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}
};


101
/* for DTIM period IWL_DTIM_RANGE_0_MAX + 1 through IWL_DTIM_RANGE_1_MAX */
W
Wey-Yi Guy 已提交
102
/* DTIM 3 - 10 */
J
Johannes Berg 已提交
103
static const struct iwl_power_vec_entry range_1[IWL_POWER_NUM] = {
M
Mohamed Abbas 已提交
104 105 106 107
	{{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},
W
Wey-Yi Guy 已提交
108
	{{SLP, SLP_TOUT(25), SLP_TOUT(25), SLP_VEC(2, 4, 6, 10, 10)}, 2}
M
Mohamed Abbas 已提交
109 110
};

111
/* for DTIM period > IWL_DTIM_RANGE_1_MAX */
W
Wey-Yi Guy 已提交
112
/* DTIM 11 - */
J
Johannes Berg 已提交
113
static const struct iwl_power_vec_entry range_2[IWL_POWER_NUM] = {
M
Mohamed Abbas 已提交
114 115 116 117 118 119 120
	{{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}
};

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 159 160 161 162 163 164 165 166
/* 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}
};

167 168 169 170 171
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;
W
Wey-Yi Guy 已提交
172 173 174 175
	int max_sleep[IWL_POWER_VEC_SIZE] = { 0 };
	int i;
	u8 skip;
	u32 slp_itrvl;
176

177 178 179 180 181 182 183 184 185 186 187 188 189
	if (priv->cfg->adv_pm) {
		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;
	}
190 191 192 193 194 195

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

	*cmd = table[lvl].cmd;

	if (period == 0) {
W
Wey-Yi Guy 已提交
196
		skip = 0;
197
		period = 1;
W
Wey-Yi Guy 已提交
198 199 200
		for (i = 0; i < IWL_POWER_VEC_SIZE; i++)
			max_sleep[i] =  1;

201
	} else {
W
Wey-Yi Guy 已提交
202 203 204 205
		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;
206 207
	}

W
Wey-Yi Guy 已提交
208 209 210 211 212 213 214 215 216 217 218 219
	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)
220
		cmd->flags |= IWL_POWER_SLEEP_OVER_DTIM_MSK;
W
Wey-Yi Guy 已提交
221
	else
222 223
		cmd->flags &= ~IWL_POWER_SLEEP_OVER_DTIM_MSK;

224 225 226 227 228
	if (priv->cfg->base_params->shadow_reg_enable)
		cmd->flags |= IWL_POWER_SHADOW_REG_ENA;
	else
		cmd->flags &= ~IWL_POWER_SHADOW_REG_ENA;

229
	if (iwl_advanced_bt_coexist(priv)) {
230 231 232 233 234 235 236
		if (!priv->cfg->bt_params->bt_sco_disable)
			cmd->flags |= IWL_POWER_BT_SCO_ENA;
		else
			cmd->flags &= ~IWL_POWER_BT_SCO_ENA;
	}


W
Wey-Yi Guy 已提交
237
	slp_itrvl = le32_to_cpu(cmd->sleep_interval[IWL_POWER_VEC_SIZE - 1]);
W
Wey-Yi Guy 已提交
238
	if (slp_itrvl > IWL_CONN_MAX_LISTEN_INTERVAL)
W
Wey-Yi Guy 已提交
239
		cmd->sleep_interval[IWL_POWER_VEC_SIZE - 1] =
W
Wey-Yi Guy 已提交
240
			cpu_to_le32(IWL_CONN_MAX_LISTEN_INTERVAL);
W
Wey-Yi Guy 已提交
241 242 243 244 245 246 247 248 249 250 251 252 253 254

	/* 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];
		}
	}
255 256 257 258 259 260

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

W
Wey-Yi Guy 已提交
261 262
	IWL_DEBUG_POWER(priv, "numSkipDtim = %u, dtimPeriod = %d\n",
			skip, period);
263 264 265 266 267
	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)
M
Mohamed Abbas 已提交
268
{
269
	memset(cmd, 0, sizeof(*cmd));
M
Mohamed Abbas 已提交
270

271 272
	if (priv->power_data.pci_pm)
		cmd->flags |= IWL_POWER_PCI_PM_MSK;
M
Mohamed Abbas 已提交
273

274
	IWL_DEBUG_POWER(priv, "Sleep command for CAM\n");
M
Mohamed Abbas 已提交
275 276
}

277 278 279
static void iwl_power_fill_sleep_cmd(struct iwl_priv *priv,
				     struct iwl_powertable_cmd *cmd,
				     int dynps_ms, int wakeup_period)
M
Mohamed Abbas 已提交
280
{
281 282 283 284 285 286 287 288 289 290 291 292 293 294
	/*
	 * These are the original power level 3 sleep successions. The
	 * device may behave better with such succession and was also
	 * only tested with that. Just like the original sleep commands,
	 * also adjust the succession here to the wakeup_period below.
	 * The ranges are the same as for the sleep commands, 0-2, 3-9
	 * and >10, which is selected based on the DTIM interval for
	 * the sleep index but here we use the wakeup period since that
	 * is what we need to do for the latency requirements.
	 */
	static const u8 slp_succ_r0[IWL_POWER_VEC_SIZE] = { 2, 2, 2, 2, 2 };
	static const u8 slp_succ_r1[IWL_POWER_VEC_SIZE] = { 2, 4, 6, 7, 9 };
	static const u8 slp_succ_r2[IWL_POWER_VEC_SIZE] = { 2, 7, 9, 9, 0xFF };
	const u8 *slp_succ = slp_succ_r0;
295
	int i;
M
Mohamed Abbas 已提交
296

297 298 299 300 301
	if (wakeup_period > IWL_DTIM_RANGE_0_MAX)
		slp_succ = slp_succ_r1;
	if (wakeup_period > IWL_DTIM_RANGE_1_MAX)
		slp_succ = slp_succ_r2;

302
	memset(cmd, 0, sizeof(*cmd));
303

304 305
	cmd->flags = IWL_POWER_DRIVER_ALLOW_SLEEP_MSK |
		     IWL_POWER_FAST_PD; /* no use seeing frames for others */
M
Mohamed Abbas 已提交
306

307 308
	if (priv->power_data.pci_pm)
		cmd->flags |= IWL_POWER_PCI_PM_MSK;
M
Mohamed Abbas 已提交
309

310 311 312 313 314
	if (priv->cfg->base_params->shadow_reg_enable)
		cmd->flags |= IWL_POWER_SHADOW_REG_ENA;
	else
		cmd->flags &= ~IWL_POWER_SHADOW_REG_ENA;

315
	if (iwl_advanced_bt_coexist(priv)) {
316 317 318 319 320 321
		if (!priv->cfg->bt_params->bt_sco_disable)
			cmd->flags |= IWL_POWER_BT_SCO_ENA;
		else
			cmd->flags &= ~IWL_POWER_BT_SCO_ENA;
	}

322 323
	cmd->rx_data_timeout = cpu_to_le32(1000 * dynps_ms);
	cmd->tx_data_timeout = cpu_to_le32(1000 * dynps_ms);
M
Mohamed Abbas 已提交
324

325
	for (i = 0; i < IWL_POWER_VEC_SIZE; i++)
326 327
		cmd->sleep_interval[i] =
			cpu_to_le32(min_t(int, slp_succ[i], wakeup_period));
328 329 330

	IWL_DEBUG_POWER(priv, "Automatic sleep command\n");
}
M
Mohamed Abbas 已提交
331

332 333 334
static int iwl_set_power(struct iwl_priv *priv, struct iwl_powertable_cmd *cmd)
{
	IWL_DEBUG_POWER(priv, "Sending power/sleep command\n");
335 336 337 338
	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",
M
Mohamed Abbas 已提交
339 340 341 342 343 344
			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]));

345 346
	return iwl_send_cmd_pdu(priv, POWER_TABLE_CMD,
				sizeof(struct iwl_powertable_cmd), cmd);
M
Mohamed Abbas 已提交
347 348
}

349 350
static void iwl_power_build_cmd(struct iwl_priv *priv,
				struct iwl_powertable_cmd *cmd)
M
Mohamed Abbas 已提交
351
{
352
	bool enabled = priv->hw->conf.flags & IEEE80211_CONF_PS;
353
	int dtimper;
M
Mohamed Abbas 已提交
354

355
	dtimper = priv->hw->conf.ps_dtim_period ?: 1;
356

357
	if (priv->cfg->base_params->broken_powersave)
358
		iwl_power_sleep_cam_cmd(priv, cmd);
359
	else if (priv->hw->conf.flags & IEEE80211_CONF_IDLE)
360
		iwl_static_sleep_cmd(priv, cmd, IWL_POWER_INDEX_5, 20);
361
	else if (priv->cfg->ops->lib->tt_ops.lower_power_detection &&
362 363 364
		 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 */
365
		iwl_static_sleep_cmd(priv, cmd,
366
		    priv->cfg->ops->lib->tt_ops.tt_power_mode(priv), dtimper);
367
	} else if (!enabled)
368
		iwl_power_sleep_cam_cmd(priv, cmd);
369
	else if (priv->power_data.debug_sleep_level_override >= 0)
370
		iwl_static_sleep_cmd(priv, cmd,
371 372 373
				     priv->power_data.debug_sleep_level_override,
				     dtimper);
	else if (no_sleep_autoadjust)
374
		iwl_static_sleep_cmd(priv, cmd, IWL_POWER_INDEX_1, dtimper);
375
	else
376
		iwl_power_fill_sleep_cmd(priv, cmd,
377 378
					 priv->hw->conf.dynamic_ps_timeout,
					 priv->hw->conf.max_sleep_period);
379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407
}

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;

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

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

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

	if (cmd->flags & IWL_POWER_DRIVER_ALLOW_SLEEP_MSK)
		set_bit(STATUS_POWER_PMI, &priv->status);
M
Mohamed Abbas 已提交
408

409 410 411 412 413 414 415 416 417
	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,
418
					"Cannot update the power, chain noise "
419 420
					"calibration running: %d\n",
					priv->chain_noise_data.state);
421 422 423 424

		memcpy(&priv->power_data.sleep_cmd, cmd, sizeof(*cmd));
	} else
		IWL_ERR(priv, "set power fail, ret = %d", ret);
M
Mohamed Abbas 已提交
425 426 427

	return ret;
}
428 429 430 431 432 433 434 435

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);
}
M
Mohamed Abbas 已提交
436

T
Tomas Winkler 已提交
437
/* initialize to default */
M
Mohamed Abbas 已提交
438 439
void iwl_power_initialize(struct iwl_priv *priv)
{
440 441 442 443 444 445 446 447
	u16 lctl = iwl_pcie_link_ctl(priv);

	priv->power_data.pci_pm = !(lctl & PCI_CFG_LINK_CTRL_VAL_L0S_EN);

	priv->power_data.debug_sleep_level_override = -1;

	memset(&priv->power_data.sleep_cmd, 0,
		sizeof(priv->power_data.sleep_cmd));
M
Mohamed Abbas 已提交
448
}