Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit e312c24c authored by Johannes Berg's avatar Johannes Berg Committed by John W. Linville
Browse files

iwlwifi: automatically adjust sleep level



Depending on required latency requested by pm_qos (via mac80211)
we can automatically adjust the sleep state. Also, mac80211 has
a user-visible dynamic sleep feature where we are supposed to
stay awake after sending/receiving frames to better receive
response frames to our packets, this can be integrated into the
sleep command.

Currently, and this patch doesn't change that yet, we default
to using sleep level 1 if PS is enabled. With a module parameter
to iwlcore, automatic adjustment to changing network latency
requirements can be enabled -- this isn't yet the default due
to requiring more testing.

The goal is to enable automatic adjustment and then go into the
deepest possible sleep state possible depending on the networking
latency requirements.

This patch does, however, enable IEEE80211_HW_SUPPORTS_DYNAMIC_PS
to avoid the double-timer (one in software and one in the device)
when transmitting -- the exact timeout may be ignored but that is
not of big concern.

Note also that we keep the hard-coded power indices around for
thermal throttling -- the specification of that calls for using
the specified power levels. Those can also be selected in debugfs
to allow easier testing of such parameters.

Signed-off-by: default avatarJohannes Berg <johannes@sipsolutions.net>
Signed-off-by: default avatarReinette Chatre <reinette.chatre@intel.com>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent d91b1ba3
Loading
Loading
Loading
Loading
+2 −44
Original line number Diff line number Diff line
@@ -1606,7 +1606,7 @@ static void iwl_alive_start(struct iwl_priv *priv)
	set_bit(STATUS_READY, &priv->status);
	wake_up_interruptible(&priv->wait_command_queue);

	iwl_power_update_mode(priv, 1);
	iwl_power_update_mode(priv, true);

	/* reassociate for ADHOC mode */
	if (priv->vif && (priv->iw_mode == NL80211_IFTYPE_ADHOC)) {
@@ -2075,7 +2075,7 @@ void iwl_post_associate(struct iwl_priv *priv)
	 * If chain noise has already been run, then we need to enable
	 * power management here */
	if (priv->chain_noise_data.state == IWL_CHAIN_NOISE_DONE)
		iwl_power_update_mode(priv, 0);
		iwl_power_update_mode(priv, false);

	/* Enable Rx differential gain and sensitivity calibrations */
	iwl_chain_noise_reset(priv);
@@ -2565,47 +2565,6 @@ static ssize_t store_filter_flags(struct device *d,
static DEVICE_ATTR(filter_flags, S_IWUSR | S_IRUGO, show_filter_flags,
		   store_filter_flags);

static ssize_t store_power_level(struct device *d,
				 struct device_attribute *attr,
				 const char *buf, size_t count)
{
	struct iwl_priv *priv = dev_get_drvdata(d);
	int ret;
	unsigned long mode;


	mutex_lock(&priv->mutex);

	ret = strict_strtoul(buf, 10, &mode);
	if (ret)
		goto out;

	ret = iwl_power_set_user_mode(priv, mode);
	if (ret) {
		IWL_DEBUG_MAC80211(priv, "failed setting power mode.\n");
		goto out;
	}
	ret = count;

 out:
	mutex_unlock(&priv->mutex);
	return ret;
}

static ssize_t show_power_level(struct device *d,
				struct device_attribute *attr, char *buf)
{
	struct iwl_priv *priv = dev_get_drvdata(d);
	int level = priv->power_data.power_mode;
	char *p = buf;

	p += sprintf(p, "%d\n", level);
	return p - buf + 1;
}

static DEVICE_ATTR(power_level, S_IWUSR | S_IRUSR, show_power_level,
		   store_power_level);


static ssize_t show_statistics(struct device *d,
			       struct device_attribute *attr, char *buf)
@@ -2698,7 +2657,6 @@ static void iwl_cancel_deferred_work(struct iwl_priv *priv)
static struct attribute *iwl_sysfs_entries[] = {
	&dev_attr_flags.attr,
	&dev_attr_filter_flags.attr,
	&dev_attr_power_level.attr,
	&dev_attr_statistics.attr,
	&dev_attr_temperature.attr,
	&dev_attr_tx_power.attr,
+1 −1
Original line number Diff line number Diff line
@@ -852,7 +852,7 @@ void iwl_chain_noise_calibration(struct iwl_priv *priv,
		priv->cfg->ops->lib->update_chain_flags(priv);

	data->state = IWL_CHAIN_NOISE_DONE;
	iwl_power_update_mode(priv, 0);
	iwl_power_update_mode(priv, false);
}
EXPORT_SYMBOL(iwl_chain_noise_calibration);

+7 −0
Original line number Diff line number Diff line
@@ -2313,15 +2313,22 @@ struct iwl_spectrum_notification {
 * PM allow:
 *   bit 0 - '0' Driver not allow power management
 *           '1' Driver allow PM (use rest of parameters)
 *
 * uCode send sleep notifications:
 *   bit 1 - '0' Don't send sleep notification
 *           '1' send sleep notification (SEND_PM_NOTIFICATION)
 *
 * Sleep over DTIM
 *   bit 2 - '0' PM have to walk up every DTIM
 *           '1' PM could sleep over DTIM till listen Interval.
 *
 * PCI power managed
 *   bit 3 - '0' (PCI_CFG_LINK_CTRL & 0x1)
 *           '1' !(PCI_CFG_LINK_CTRL & 0x1)
 *
 * Fast PD
 *   bit 4 - '1' Put radio to sleep when receiving frame for others
 *
 * Force sleep Modes
 *   bit 31/30- '00' use both mac/xtal sleeps
 *              '01' force Mac sleep
+5 −10
Original line number Diff line number Diff line
@@ -1568,7 +1568,8 @@ int iwl_setup_mac(struct iwl_priv *priv)
		    IEEE80211_HW_NOISE_DBM |
		    IEEE80211_HW_AMPDU_AGGREGATION |
		    IEEE80211_HW_SPECTRUM_MGMT |
		    IEEE80211_HW_SUPPORTS_PS;
		    IEEE80211_HW_SUPPORTS_PS |
		    IEEE80211_HW_SUPPORTS_DYNAMIC_PS;
	hw->wiphy->interface_modes =
		BIT(NL80211_IFTYPE_STATION) |
		BIT(NL80211_IFTYPE_ADHOC);
@@ -1663,8 +1664,6 @@ int iwl_init_drv(struct iwl_priv *priv)
	priv->qos_data.qos_cap.val = 0;

	priv->rates_mask = IWL_RATES_MASK;
	/* If power management is turned on, default to CAM mode */
	priv->power_mode = IWL_POWER_MODE_CAM;
	priv->tx_power_user_lmt = IWL_TX_POWER_TARGET_POWER_MAX;

	ret = iwl_init_channel_map(priv);
@@ -2551,7 +2550,6 @@ void iwl_bss_info_changed(struct ieee80211_hw *hw,
		if (bss_conf->assoc) {
			priv->assoc_id = bss_conf->aid;
			priv->beacon_int = bss_conf->beacon_int;
			priv->power_data.dtim_period = bss_conf->dtim_period;
			priv->timestamp = bss_conf->timestamp;
			priv->assoc_capability = bss_conf->assoc_capability;

@@ -2801,13 +2799,10 @@ int iwl_mac_config(struct ieee80211_hw *hw, u32 changed)
		iwl_set_rate(priv);
	}

	if (changed & IEEE80211_CONF_CHANGE_PS &&
	    priv->iw_mode == NL80211_IFTYPE_STATION) {
		priv->power_data.power_disabled =
			!(conf->flags & IEEE80211_CONF_PS);
		ret = iwl_power_update_mode(priv, 0);
	if (changed & IEEE80211_CONF_CHANGE_PS) {
		ret = iwl_power_update_mode(priv, false);
		if (ret)
			IWL_DEBUG_MAC80211(priv, "Error setting power level\n");
			IWL_DEBUG_MAC80211(priv, "Error setting sleep level\n");
	}

	if (changed & IEEE80211_CONF_CHANGE_POWER) {
+2 −0
Original line number Diff line number Diff line
@@ -88,6 +88,8 @@ struct iwl_debugfs {
		struct dentry *file_led;
#endif
		struct dentry *file_disable_ht40;
		struct dentry *file_sleep_level_override;
		struct dentry *file_current_sleep_command;
	} dbgfs_data_files;
	struct dir_rf_files {
		struct dentry *file_disable_sensitivity;
Loading