Linux Audio

Check our new training course

Loading...
Note: File does not exist in v6.2.
  1/******************************************************************************
  2 *
  3 * Copyright(c) 2007 - 2011 Intel Corporation. All rights reserved.
  4 *
  5 * Portions of this file are derived from the ipw3945 project, as well
  6 * as portions of the ieee80211 subsystem header files.
  7 *
  8 * This program is free software; you can redistribute it and/or modify it
  9 * under the terms of version 2 of the GNU General Public License as
 10 * published by the Free Software Foundation.
 11 *
 12 * This program is distributed in the hope that it will be useful, but WITHOUT
 13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 14 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
 15 * more details.
 16 *
 17 * You should have received a copy of the GNU General Public License along with
 18 * this program; if not, write to the Free Software Foundation, Inc.,
 19 * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
 20 *
 21 * The full GNU General Public License is included in this distribution in the
 22 * file called LICENSE.
 23 *
 24 * Contact Information:
 25 *  Intel Linux Wireless <ilw@linux.intel.com>
 26 * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
 27 *****************************************************************************/
 28
 29
 30#include <linux/kernel.h>
 31#include <linux/module.h>
 32#include <linux/slab.h>
 33#include <linux/init.h>
 34
 35#include <net/mac80211.h>
 36
 37#include "iwl-eeprom.h"
 38#include "iwl-dev.h"
 39#include "iwl-core.h"
 40#include "iwl-io.h"
 41#include "iwl-commands.h"
 42#include "iwl-debug.h"
 43#include "iwl-power.h"
 44
 45/*
 46 * Setting power level allows the card to go to sleep when not busy.
 47 *
 48 * We calculate a sleep command based on the required latency, which
 49 * we get from mac80211. In order to handle thermal throttling, we can
 50 * also use pre-defined power levels.
 51 */
 52
 53/*
 54 * This defines the old power levels. They are still used by default
 55 * (level 1) and for thermal throttle (levels 3 through 5)
 56 */
 57
 58struct iwl_power_vec_entry {
 59	struct iwl_powertable_cmd cmd;
 60	u8 no_dtim;	/* number of skip dtim */
 61};
 62
 63static void iwl_legacy_power_sleep_cam_cmd(struct iwl_priv *priv,
 64				    struct iwl_powertable_cmd *cmd)
 65{
 66	memset(cmd, 0, sizeof(*cmd));
 67
 68	if (priv->power_data.pci_pm)
 69		cmd->flags |= IWL_POWER_PCI_PM_MSK;
 70
 71	IWL_DEBUG_POWER(priv, "Sleep command for CAM\n");
 72}
 73
 74static int
 75iwl_legacy_set_power(struct iwl_priv *priv, struct iwl_powertable_cmd *cmd)
 76{
 77	IWL_DEBUG_POWER(priv, "Sending power/sleep command\n");
 78	IWL_DEBUG_POWER(priv, "Flags value = 0x%08X\n", cmd->flags);
 79	IWL_DEBUG_POWER(priv, "Tx timeout = %u\n",
 80					le32_to_cpu(cmd->tx_data_timeout));
 81	IWL_DEBUG_POWER(priv, "Rx timeout = %u\n",
 82					le32_to_cpu(cmd->rx_data_timeout));
 83	IWL_DEBUG_POWER(priv,
 84			"Sleep interval vector = { %d , %d , %d , %d , %d }\n",
 85			le32_to_cpu(cmd->sleep_interval[0]),
 86			le32_to_cpu(cmd->sleep_interval[1]),
 87			le32_to_cpu(cmd->sleep_interval[2]),
 88			le32_to_cpu(cmd->sleep_interval[3]),
 89			le32_to_cpu(cmd->sleep_interval[4]));
 90
 91	return iwl_legacy_send_cmd_pdu(priv, POWER_TABLE_CMD,
 92				sizeof(struct iwl_powertable_cmd), cmd);
 93}
 94
 95int
 96iwl_legacy_power_set_mode(struct iwl_priv *priv, struct iwl_powertable_cmd *cmd,
 97		       bool force)
 98{
 99	int ret;
100	bool update_chains;
101
102	lockdep_assert_held(&priv->mutex);
103
104	/* Don't update the RX chain when chain noise calibration is running */
105	update_chains = priv->chain_noise_data.state == IWL_CHAIN_NOISE_DONE ||
106			priv->chain_noise_data.state == IWL_CHAIN_NOISE_ALIVE;
107
108	if (!memcmp(&priv->power_data.sleep_cmd, cmd, sizeof(*cmd)) && !force)
109		return 0;
110
111	if (!iwl_legacy_is_ready_rf(priv))
112		return -EIO;
113
114	/* scan complete use sleep_power_next, need to be updated */
115	memcpy(&priv->power_data.sleep_cmd_next, cmd, sizeof(*cmd));
116	if (test_bit(STATUS_SCANNING, &priv->status) && !force) {
117		IWL_DEBUG_INFO(priv, "Defer power set mode while scanning\n");
118		return 0;
119	}
120
121	if (cmd->flags & IWL_POWER_DRIVER_ALLOW_SLEEP_MSK)
122		set_bit(STATUS_POWER_PMI, &priv->status);
123
124	ret = iwl_legacy_set_power(priv, cmd);
125	if (!ret) {
126		if (!(cmd->flags & IWL_POWER_DRIVER_ALLOW_SLEEP_MSK))
127			clear_bit(STATUS_POWER_PMI, &priv->status);
128
129		if (priv->cfg->ops->lib->update_chain_flags && update_chains)
130			priv->cfg->ops->lib->update_chain_flags(priv);
131		else if (priv->cfg->ops->lib->update_chain_flags)
132			IWL_DEBUG_POWER(priv,
133					"Cannot update the power, chain noise "
134					"calibration running: %d\n",
135					priv->chain_noise_data.state);
136
137		memcpy(&priv->power_data.sleep_cmd, cmd, sizeof(*cmd));
138	} else
139		IWL_ERR(priv, "set power fail, ret = %d", ret);
140
141	return ret;
142}
143
144int iwl_legacy_power_update_mode(struct iwl_priv *priv, bool force)
145{
146	struct iwl_powertable_cmd cmd;
147
148	iwl_legacy_power_sleep_cam_cmd(priv, &cmd);
149	return iwl_legacy_power_set_mode(priv, &cmd, force);
150}
151EXPORT_SYMBOL(iwl_legacy_power_update_mode);
152
153/* initialize to default */
154void iwl_legacy_power_initialize(struct iwl_priv *priv)
155{
156	u16 lctl = iwl_legacy_pcie_link_ctl(priv);
157
158	priv->power_data.pci_pm = !(lctl & PCI_CFG_LINK_CTRL_VAL_L0S_EN);
159
160	priv->power_data.debug_sleep_level_override = -1;
161
162	memset(&priv->power_data.sleep_cmd, 0,
163		sizeof(priv->power_data.sleep_cmd));
164}
165EXPORT_SYMBOL(iwl_legacy_power_initialize);