From 226ba17bef00080019afa32d6e73b668458a477c Mon Sep 17 00:00:00 2001 From: adrian Date: Tue, 9 May 2017 04:15:07 +0000 Subject: [PATCH] [iwm] Add basic powermanagement support via ifconfig wlan0 powersave. * The DEVICE_POWER_FLAGS_CAM_MSK flag was removed in the upstream iwlwifi in Linux commit ceef91c89480dd18bb3ac51e91280a233d0ca41f. * Add sc_ps_disabled flag to struct iwm_softc, which corresponds to mvm->ps_disabled in struct iwl_mvm in Linux iwlwifi. * Adds a hw.iwm.power_scheme tunable which corresponds to the power_scheme module parameter in Linux iwlwifi. Set this to 1 for completely disabling power management, 2 (default) for balanced powermanagement, and 3 for lowerpower mode (which does dtim period skipping). * Imports the constants.h file from iwlwifi as if_iwm_constants.h. * This doesn't allow changing the powermanagement setting while connected, also one can only choose between enabled and disabled powersaving with ifconfig (so switching between balanced and low-power mode requires rebooting to change the tunable). * After any changes to powermanagement (i.e. "ifconfig wlan0 powersave" to enable powermanagement, or "ifconfig wlan0 -powersave" for disabling powermanagement), one has to disconnect and reconnect to the accespoint for the change to take effect. Obtained from: dragonflybsd.git d7002a7990d077c92585978ea998474af50f91e0 --- sys/dev/iwm/if_iwm.c | 10 +- sys/dev/iwm/if_iwm_constants.h | 154 +++++++++++++++++++++ sys/dev/iwm/if_iwm_power.c | 244 ++++++++++++++++++++++++++------- sys/dev/iwm/if_iwm_power.h | 4 +- sys/dev/iwm/if_iwmreg.h | 18 +-- sys/dev/iwm/if_iwmvar.h | 3 + 6 files changed, 369 insertions(+), 64 deletions(-) create mode 100644 sys/dev/iwm/if_iwm_constants.h diff --git a/sys/dev/iwm/if_iwm.c b/sys/dev/iwm/if_iwm.c index 2713e90dbbd..566a54dc6af 100644 --- a/sys/dev/iwm/if_iwm.c +++ b/sys/dev/iwm/if_iwm.c @@ -4171,6 +4171,12 @@ iwm_auth(struct ieee80211vap *vap, struct iwm_softc *sc) "%s: failed to add MAC\n", __func__); goto out; } + if ((error = iwm_mvm_power_update_mac(sc)) != 0) { + device_printf(sc->sc_dev, + "%s: failed to update power management\n", + __func__); + goto out; + } if ((error = iwm_mvm_phy_ctxt_changed(sc, &sc->sc_phyctxt[0], in->in_ni.ni_chan, 1, 1)) != 0) { device_printf(sc->sc_dev, @@ -4582,8 +4588,8 @@ iwm_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) } in = IWM_NODE(vap->iv_bss); - iwm_mvm_power_mac_update_mode(sc, in); iwm_mvm_enable_beacon_filter(sc, in); + iwm_mvm_power_update_mac(sc); iwm_mvm_update_quotas(sc, in); iwm_setrates(sc, in); @@ -4871,6 +4877,7 @@ iwm_init_hw(struct iwm_softc *sc) * image just loaded */ iwm_stop_device(sc); + sc->sc_ps_disabled = FALSE; if ((error = iwm_start_hw(sc)) != 0) { device_printf(sc->sc_dev, "could not initialize hardware\n"); return error; @@ -6122,6 +6129,7 @@ iwm_attach(device_t dev) IEEE80211_C_STA | IEEE80211_C_WPA | /* WPA/RSN */ IEEE80211_C_WME | + IEEE80211_C_PMGT | IEEE80211_C_SHSLOT | /* short slot time supported */ IEEE80211_C_SHPREAMBLE /* short preamble supported */ // IEEE80211_C_BGSCAN /* capable of bg scanning */ diff --git a/sys/dev/iwm/if_iwm_constants.h b/sys/dev/iwm/if_iwm_constants.h new file mode 100644 index 00000000000..ed8755442ce --- /dev/null +++ b/sys/dev/iwm/if_iwm_constants.h @@ -0,0 +1,154 @@ +/*- + * Based on BSD-licensed source modules in the Linux iwlwifi driver, + * which were used as the reference documentation for this implementation. + * + ****************************************************************************** + * + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * Copyright(c) 2013 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH + * Copyright(c) 2015 Intel Deutschland GmbH + * + * 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 COPYING. + * + * Contact Information: + * Intel Linux Wireless + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + * + * BSD LICENSE + * + * Copyright(c) 2013 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH + * Copyright(c) 2015 Intel Deutschland GmbH + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + *****************************************************************************/ + +/* $FreeBSD$ */ + +#ifndef __IF_IWM_CONSTANTS_H +#define __IF_IWM_CONSTANTS_H + +/* */ + +#define IWM_MVM_DEFAULT_PS_TX_DATA_TIMEOUT (100 * 1000) +#define IWM_MVM_DEFAULT_PS_RX_DATA_TIMEOUT (100 * 1000) +#define IWM_MVM_WOWLAN_PS_TX_DATA_TIMEOUT (10 * 1000) +#define IWM_MVM_WOWLAN_PS_RX_DATA_TIMEOUT (10 * 1000) +#define IWM_MVM_SHORT_PS_TX_DATA_TIMEOUT (2 * 1024) /* defined in TU */ +#define IWM_MVM_SHORT_PS_RX_DATA_TIMEOUT (40 * 1024) /* defined in TU */ +#define IWM_MVM_P2P_LOWLATENCY_PS_ENABLE 0 +#define IWM_MVM_UAPSD_RX_DATA_TIMEOUT (50 * 1000) +#define IWM_MVM_UAPSD_TX_DATA_TIMEOUT (50 * 1000) +#ifdef notyet +/* XXX Find corresponding values from net80211 */ +#define IWM_MVM_UAPSD_QUEUES (IEEE80211_WMM_IE_STA_QOSINFO_AC_VO |\ + IEEE80211_WMM_IE_STA_QOSINFO_AC_VI |\ + IEEE80211_WMM_IE_STA_QOSINFO_AC_BK |\ + IEEE80211_WMM_IE_STA_QOSINFO_AC_BE) +#endif +#define IWM_MVM_PS_HEAVY_TX_THLD_PACKETS 20 +#define IWM_MVM_PS_HEAVY_RX_THLD_PACKETS 8 +#define IWM_MVM_PS_SNOOZE_HEAVY_TX_THLD_PACKETS 30 +#define IWM_MVM_PS_SNOOZE_HEAVY_RX_THLD_PACKETS 20 +#define IWM_MVM_PS_HEAVY_TX_THLD_PERCENT 50 +#define IWM_MVM_PS_HEAVY_RX_THLD_PERCENT 50 +#define IWM_MVM_PS_SNOOZE_INTERVAL 25 +#define IWM_MVM_PS_SNOOZE_WINDOW 50 +#define IWM_MVM_WOWLAN_PS_SNOOZE_WINDOW 25 +#define IWM_MVM_LOWLAT_QUOTA_MIN_PERCENT 64 +#define IWM_MVM_BT_COEX_EN_RED_TXP_THRESH 62 +#define IWM_MVM_BT_COEX_DIS_RED_TXP_THRESH 65 +#define IWM_MVM_BT_COEX_SYNC2SCO 1 +#define IWM_MVM_BT_COEX_CORUNNING 0 +#define IWM_MVM_BT_COEX_MPLUT 1 +#define IWM_MVM_BT_COEX_RRC 1 +#define IWM_MVM_BT_COEX_TTC 1 +#define IWM_MVM_BT_COEX_MPLUT_REG0 0x22002200 +#define IWM_MVM_BT_COEX_MPLUT_REG1 0x11118451 +#define IWM_MVM_BT_COEX_ANTENNA_COUPLING_THRS 30 +#define IWM_MVM_FW_MCAST_FILTER_PASS_ALL 0 +#define IWM_MVM_FW_BCAST_FILTER_PASS_ALL 0 +#define IWM_MVM_QUOTA_THRESHOLD 4 +#define IWM_MVM_RS_RSSI_BASED_INIT_RATE 0 +#define IWM_MVM_RS_80_20_FAR_RANGE_TWEAK 1 +#define IWM_MVM_TOF_IS_RESPONDER 0 +#define IWM_MVM_SW_TX_CSUM_OFFLOAD 0 +#define IWM_MVM_HW_CSUM_DISABLE 0 +#define IWM_MVM_COLLECT_FW_ERR_DUMP 1 +#define IWM_MVM_RS_NUM_TRY_BEFORE_ANT_TOGGLE 1 +#define IWM_MVM_RS_HT_VHT_RETRIES_PER_RATE 2 +#define IWM_MVM_RS_HT_VHT_RETRIES_PER_RATE_TW 1 +#define IWM_MVM_RS_INITIAL_MIMO_NUM_RATES 3 +#define IWM_MVM_RS_INITIAL_SISO_NUM_RATES 3 +#define IWM_MVM_RS_INITIAL_LEGACY_NUM_RATES 2 +#define IWM_MVM_RS_INITIAL_LEGACY_RETRIES 2 +#define IWM_MVM_RS_SECONDARY_LEGACY_RETRIES 1 +#define IWM_MVM_RS_SECONDARY_LEGACY_NUM_RATES 16 +#define IWM_MVM_RS_SECONDARY_SISO_NUM_RATES 3 +#define IWM_MVM_RS_SECONDARY_SISO_RETRIES 1 +#define IWM_MVM_RS_RATE_MIN_FAILURE_TH 3 +#define IWM_MVM_RS_RATE_MIN_SUCCESS_TH 8 +#define IWM_MVM_RS_STAY_IN_COLUMN_TIMEOUT 5 /* Seconds */ +#define IWM_MVM_RS_IDLE_TIMEOUT 5 /* Seconds */ +#define IWM_MVM_RS_MISSED_RATE_MAX 15 +#define IWM_MVM_RS_LEGACY_FAILURE_LIMIT 160 +#define IWM_MVM_RS_LEGACY_SUCCESS_LIMIT 480 +#define IWM_MVM_RS_LEGACY_TABLE_COUNT 160 +#define IWM_MVM_RS_NON_LEGACY_FAILURE_LIMIT 400 +#define IWM_MVM_RS_NON_LEGACY_SUCCESS_LIMIT 4500 +#define IWM_MVM_RS_NON_LEGACY_TABLE_COUNT 1500 +#define IWM_MVM_RS_SR_FORCE_DECREASE 15 /* percent */ +#define IWM_MVM_RS_SR_NO_DECREASE 85 /* percent */ +#define IWM_MVM_RS_AGG_TIME_LIMIT 4000 /* 4 msecs. valid 100-8000 */ +#define IWM_MVM_RS_AGG_DISABLE_START 3 +#define IWM_MVM_RS_TPC_SR_FORCE_INCREASE 75 /* percent */ +#define IWM_MVM_RS_TPC_SR_NO_INCREASE 85 /* percent */ +#define IWM_MVM_RS_TPC_TX_POWER_STEP 3 + +#endif /* __IF_IWM_CONSTANTS_H */ diff --git a/sys/dev/iwm/if_iwm_power.c b/sys/dev/iwm/if_iwm_power.c index 1f8bf14685d..2ddb1fb5df9 100644 --- a/sys/dev/iwm/if_iwm_power.c +++ b/sys/dev/iwm/if_iwm_power.c @@ -138,9 +138,14 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include +static int iwm_power_scheme = IWM_POWER_SCHEME_BPS; + +TUNABLE_INT("hw.iwm.power_scheme", &iwm_power_scheme); + /* * BEGIN mvm/power.c */ @@ -154,7 +159,7 @@ iwm_mvm_beacon_filter_send_cmd(struct iwm_softc *sc, int ret; ret = iwm_mvm_send_cmd_pdu(sc, IWM_REPLY_BEACON_FILTERING_CMD, - IWM_CMD_SYNC, sizeof(struct iwm_beacon_filter_cmd), cmd); + 0, sizeof(struct iwm_beacon_filter_cmd), cmd); if (!ret) { IWM_DPRINTF(sc, IWM_DEBUG_PWRSAVE | IWM_DEBUG_CMD, @@ -201,24 +206,6 @@ iwm_mvm_beacon_filter_set_cqm_params(struct iwm_softc *sc, cmd->ba_enable_beacon_abort = htole32(sc->sc_bf.ba_enabled); } -static int -iwm_mvm_update_beacon_abort(struct iwm_softc *sc, struct iwm_node *in, - int enable) -{ - struct iwm_beacon_filter_cmd cmd = { - IWM_BF_CMD_CONFIG_DEFAULTS, - .bf_enable_beacon_filter = htole32(1), - .ba_enable_beacon_abort = htole32(enable), - }; - - if (!sc->sc_bf.bf_enabled) - return 0; - - sc->sc_bf.ba_enabled = enable; - iwm_mvm_beacon_filter_set_cqm_params(sc, in, &cmd); - return iwm_mvm_beacon_filter_send_cmd(sc, &cmd); -} - static void iwm_mvm_power_log(struct iwm_softc *sc, struct iwm_mac_power_cmd *cmd) { @@ -234,6 +221,60 @@ iwm_mvm_power_log(struct iwm_softc *sc, struct iwm_mac_power_cmd *cmd) "Disable power management\n"); return; } + + IWM_DPRINTF(sc, IWM_DEBUG_PWRSAVE | IWM_DEBUG_CMD, + "Rx timeout = %u usec\n", le32toh(cmd->rx_data_timeout)); + IWM_DPRINTF(sc, IWM_DEBUG_PWRSAVE | IWM_DEBUG_CMD, + "Tx timeout = %u usec\n", le32toh(cmd->tx_data_timeout)); + if (cmd->flags & htole16(IWM_POWER_FLAGS_SKIP_OVER_DTIM_MSK)) + IWM_DPRINTF(sc, IWM_DEBUG_PWRSAVE | IWM_DEBUG_CMD, + "DTIM periods to skip = %u\n", cmd->skip_dtim_periods); +} + +static boolean_t +iwm_mvm_power_is_radar(struct iwm_softc *sc) +{ + struct ieee80211com *ic = &sc->sc_ic; + struct ieee80211_channel *chan; + boolean_t radar_detect = FALSE; + + chan = ic->ic_bsschan; + if (chan == IEEE80211_CHAN_ANYC || + (chan->ic_flags & IEEE80211_CHAN_DFS) != 0) { + radar_detect = TRUE; + } + + return radar_detect; +} + +static void +iwm_mvm_power_config_skip_dtim(struct iwm_softc *sc, + struct iwm_mac_power_cmd *cmd) +{ + struct ieee80211com *ic = &sc->sc_ic; + struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); + int dtimper = vap->iv_dtim_period ?: 1; + int skip; + + /* disable, in case we're supposed to override */ + cmd->skip_dtim_periods = 0; + cmd->flags &= ~htole16(IWM_POWER_FLAGS_SKIP_OVER_DTIM_MSK); + + if (iwm_mvm_power_is_radar(sc)) + return; + + if (dtimper >= 10) + return; + + /* TODO: check that multicast wake lock is off */ + + if (iwm_power_scheme != IWM_POWER_SCHEME_LP) + return; + skip = 2; + + /* the firmware really expects "look at every X DTIMs", so add 1 */ + cmd->skip_dtim_periods = 1 + skip; + cmd->flags |= htole16(IWM_POWER_FLAGS_SKIP_OVER_DTIM_MSK); } static void @@ -258,45 +299,49 @@ iwm_mvm_power_build_cmd(struct iwm_softc *sc, struct iwm_node *in, */ dtimper_msec = dtimper * ni->ni_intval; keep_alive - = MAX(3 * dtimper_msec, 1000 * IWM_POWER_KEEP_ALIVE_PERIOD_SEC); + = imax(3 * dtimper_msec, 1000 * IWM_POWER_KEEP_ALIVE_PERIOD_SEC); keep_alive = roundup(keep_alive, 1000) / 1000; cmd->keep_alive_seconds = htole16(keep_alive); + + if (sc->sc_ps_disabled) + return; + + cmd->flags |= htole16(IWM_POWER_FLAGS_POWER_SAVE_ENA_MSK); + cmd->flags |= htole16(IWM_POWER_FLAGS_POWER_MANAGEMENT_ENA_MSK); + + iwm_mvm_power_config_skip_dtim(sc, cmd); + + cmd->rx_data_timeout = + htole32(IWM_MVM_DEFAULT_PS_RX_DATA_TIMEOUT); + cmd->tx_data_timeout = + htole32(IWM_MVM_DEFAULT_PS_TX_DATA_TIMEOUT); } -int -iwm_mvm_power_mac_update_mode(struct iwm_softc *sc, struct iwm_node *in) +static int +iwm_mvm_power_send_cmd(struct iwm_softc *sc, struct iwm_node *in) { - int ret; - int ba_enable; - struct iwm_mac_power_cmd cmd; - - memset(&cmd, 0, sizeof(cmd)); + struct iwm_mac_power_cmd cmd = {}; iwm_mvm_power_build_cmd(sc, in, &cmd); iwm_mvm_power_log(sc, &cmd); - if ((ret = iwm_mvm_send_cmd_pdu(sc, IWM_MAC_PM_POWER_TABLE, - IWM_CMD_SYNC, sizeof(cmd), &cmd)) != 0) - return ret; - - ba_enable = !!(cmd.flags & - htole16(IWM_POWER_FLAGS_POWER_MANAGEMENT_ENA_MSK)); - return iwm_mvm_update_beacon_abort(sc, in, ba_enable); + return iwm_mvm_send_cmd_pdu(sc, IWM_MAC_PM_POWER_TABLE, 0, + sizeof(cmd), &cmd); } -int -iwm_mvm_power_update_device(struct iwm_softc *sc) +static int +_iwm_mvm_enable_beacon_filter(struct iwm_softc *sc, struct iwm_node *in, + struct iwm_beacon_filter_cmd *cmd) { - struct iwm_device_power_cmd cmd = { - .flags = htole16(IWM_DEVICE_POWER_FLAGS_POWER_SAVE_ENA_MSK), - }; + int ret; - cmd.flags |= htole16(IWM_DEVICE_POWER_FLAGS_CAM_MSK); - IWM_DPRINTF(sc, IWM_DEBUG_PWRSAVE | IWM_DEBUG_CMD, - "Sending device power command with flags = 0x%X\n", cmd.flags); + iwm_mvm_beacon_filter_set_cqm_params(sc, in, cmd); + ret = iwm_mvm_beacon_filter_send_cmd(sc, cmd); - return iwm_mvm_send_cmd_pdu(sc, - IWM_POWER_TABLE_CMD, IWM_CMD_SYNC, sizeof(cmd), &cmd); + if (!ret) + sc->sc_bf.bf_enabled = 1; + + return ret; } int @@ -306,15 +351,8 @@ iwm_mvm_enable_beacon_filter(struct iwm_softc *sc, struct iwm_node *in) IWM_BF_CMD_CONFIG_DEFAULTS, .bf_enable_beacon_filter = htole32(1), }; - int ret; - - iwm_mvm_beacon_filter_set_cqm_params(sc, in, &cmd); - ret = iwm_mvm_beacon_filter_send_cmd(sc, &cmd); - if (ret == 0) - sc->sc_bf.bf_enabled = 1; - - return ret; + return _iwm_mvm_enable_beacon_filter(sc, in, &cmd); } int @@ -329,3 +367,105 @@ iwm_mvm_disable_beacon_filter(struct iwm_softc *sc) return ret; } + +static int +iwm_mvm_power_set_ps(struct iwm_softc *sc) +{ + struct ieee80211vap *vap = TAILQ_FIRST(&sc->sc_ic.ic_vaps); + boolean_t disable_ps; + int ret; + + /* disable PS if CAM */ + disable_ps = (iwm_power_scheme == IWM_POWER_SCHEME_CAM); + /* ...or if any of the vifs require PS to be off */ + if (vap != NULL && (vap->iv_flags & IEEE80211_F_PMGTON) == 0) + disable_ps = TRUE; + + /* update device power state if it has changed */ + if (sc->sc_ps_disabled != disable_ps) { + boolean_t old_ps_disabled = sc->sc_ps_disabled; + + sc->sc_ps_disabled = disable_ps; + ret = iwm_mvm_power_update_device(sc); + if (ret) { + sc->sc_ps_disabled = old_ps_disabled; + return ret; + } + } + + return 0; +} + +static int +iwm_mvm_power_set_ba(struct iwm_softc *sc, struct iwm_node *in) +{ + struct iwm_beacon_filter_cmd cmd = { + IWM_BF_CMD_CONFIG_DEFAULTS, + .bf_enable_beacon_filter = htole32(1), + }; + + if (!sc->sc_bf.bf_enabled) + return 0; + + sc->sc_bf.ba_enabled = !sc->sc_ps_disabled; + + return _iwm_mvm_enable_beacon_filter(sc, in, &cmd); +} + +int +iwm_mvm_power_update_ps(struct iwm_softc *sc) +{ + struct ieee80211vap *vap = TAILQ_FIRST(&sc->sc_ic.ic_vaps); + int ret; + + ret = iwm_mvm_power_set_ps(sc); + if (ret) + return ret; + + if (vap != NULL) + return iwm_mvm_power_set_ba(sc, IWM_NODE(vap->iv_bss)); + + return 0; +} + +int +iwm_mvm_power_update_mac(struct iwm_softc *sc) +{ + struct ieee80211vap *vap = TAILQ_FIRST(&sc->sc_ic.ic_vaps); + int ret; + + ret = iwm_mvm_power_set_ps(sc); + if (ret) + return ret; + + if (vap != NULL) { + ret = iwm_mvm_power_send_cmd(sc, IWM_NODE(vap->iv_bss)); + if (ret) + return ret; + } + + if (vap != NULL) + return iwm_mvm_power_set_ba(sc, IWM_NODE(vap->iv_bss)); + + return 0; +} + +int +iwm_mvm_power_update_device(struct iwm_softc *sc) +{ + struct iwm_device_power_cmd cmd = { + .flags = 0, + }; + + if (iwm_power_scheme == IWM_POWER_SCHEME_CAM) + sc->sc_ps_disabled = TRUE; + + if (!sc->sc_ps_disabled) + cmd.flags |= htole16(IWM_DEVICE_POWER_FLAGS_POWER_SAVE_ENA_MSK); + + IWM_DPRINTF(sc, IWM_DEBUG_PWRSAVE | IWM_DEBUG_CMD, + "Sending device power command with flags = 0x%X\n", cmd.flags); + + return iwm_mvm_send_cmd_pdu(sc, + IWM_POWER_TABLE_CMD, 0, sizeof(cmd), &cmd); +} diff --git a/sys/dev/iwm/if_iwm_power.h b/sys/dev/iwm/if_iwm_power.h index d34c4445a91..d6ffb6a5a8e 100644 --- a/sys/dev/iwm/if_iwm_power.h +++ b/sys/dev/iwm/if_iwm_power.h @@ -90,9 +90,9 @@ #ifndef __IF_IWM_POWER_H__ #define __IF_IWM_POWER_H__ -extern int iwm_mvm_power_mac_update_mode(struct iwm_softc *sc, - struct iwm_node *in); extern int iwm_mvm_power_update_device(struct iwm_softc *sc); +extern int iwm_mvm_power_update_mac(struct iwm_softc *sc); +extern int iwm_mvm_power_update_ps(struct iwm_softc *sc); extern int iwm_mvm_enable_beacon_filter(struct iwm_softc *sc, struct iwm_node *in); extern int iwm_mvm_disable_beacon_filter(struct iwm_softc *sc); diff --git a/sys/dev/iwm/if_iwmreg.h b/sys/dev/iwm/if_iwmreg.h index bce0e370bdc..93364089d0e 100644 --- a/sys/dev/iwm/if_iwmreg.h +++ b/sys/dev/iwm/if_iwmreg.h @@ -3620,17 +3620,11 @@ struct iwm_powertable_cmd { /** * enum iwm_device_power_flags - masks for device power command flags - * @DEVIC_POWER_FLAGS_POWER_SAVE_ENA_MSK: '1' Allow to save power by turning off - * receiver and transmitter. '0' - does not allow. This flag should be - * always set to '1' unless one need to disable actual power down for debug - * purposes. - * @IWM_DEVICE_POWER_FLAGS_CAM_MSK: '1' CAM (Continuous Active Mode) is set, meaning - * that power management is disabled. '0' Power management is enabled, one - * of power schemes is applied. -*/ + * @IWM_DEVICE_POWER_FLAGS_POWER_SAVE_ENA_MSK: '1' Allow to save power by turning off + * receiver and transmitter. '0' - does not allow. + */ enum iwm_device_power_flags { IWM_DEVICE_POWER_FLAGS_POWER_SAVE_ENA_MSK = (1 << 0), - IWM_DEVICE_POWER_FLAGS_CAM_MSK = (1 << 13), }; /** @@ -6043,6 +6037,12 @@ struct iwm_cmd_header_wide { uint8_t version; } __packed; +/** + * enum iwm_power_scheme + * @IWM_POWER_LEVEL_CAM - Continuously Active Mode + * @IWM_POWER_LEVEL_BPS - Balanced Power Save (default) + * @IWM_POWER_LEVEL_LP - Low Power + */ enum iwm_power_scheme { IWM_POWER_SCHEME_CAM = 1, IWM_POWER_SCHEME_BPS, diff --git a/sys/dev/iwm/if_iwmvar.h b/sys/dev/iwm/if_iwmvar.h index b15f123d6e0..b0292308f2b 100644 --- a/sys/dev/iwm/if_iwmvar.h +++ b/sys/dev/iwm/if_iwmvar.h @@ -538,6 +538,9 @@ struct iwm_softc { uint16_t num_of_pages_in_last_blk; boolean_t last_ebs_successful; + + /* Indicate if device power save is allowed */ + boolean_t sc_ps_disabled; }; #define IWM_LOCK_INIT(_sc) \ -- 2.45.0