1286441Srpaulo/* $OpenBSD: if_iwm.c,v 1.39 2015/03/23 00:35:19 jsg Exp $ */ 2286441Srpaulo 3286441Srpaulo/* 4286441Srpaulo * Copyright (c) 2014 genua mbh <info@genua.de> 5286441Srpaulo * Copyright (c) 2014 Fixup Software Ltd. 6286441Srpaulo * 7286441Srpaulo * Permission to use, copy, modify, and distribute this software for any 8286441Srpaulo * purpose with or without fee is hereby granted, provided that the above 9286441Srpaulo * copyright notice and this permission notice appear in all copies. 10286441Srpaulo * 11286441Srpaulo * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 12286441Srpaulo * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 13286441Srpaulo * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 14286441Srpaulo * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 15286441Srpaulo * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 16286441Srpaulo * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 17286441Srpaulo * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 18286441Srpaulo */ 19286441Srpaulo 20286441Srpaulo/*- 21286441Srpaulo * Based on BSD-licensed source modules in the Linux iwlwifi driver, 22286441Srpaulo * which were used as the reference documentation for this implementation. 23286441Srpaulo * 24286441Srpaulo * Driver version we are currently based off of is 25286441Srpaulo * Linux 3.14.3 (tag id a2df521e42b1d9a23f620ac79dbfe8655a8391dd) 26286441Srpaulo * 27286441Srpaulo *********************************************************************** 28286441Srpaulo * 29286441Srpaulo * This file is provided under a dual BSD/GPLv2 license. When using or 30286441Srpaulo * redistributing this file, you may do so under either license. 31286441Srpaulo * 32286441Srpaulo * GPL LICENSE SUMMARY 33286441Srpaulo * 34286441Srpaulo * Copyright(c) 2007 - 2013 Intel Corporation. All rights reserved. 35286441Srpaulo * 36286441Srpaulo * This program is free software; you can redistribute it and/or modify 37286441Srpaulo * it under the terms of version 2 of the GNU General Public License as 38286441Srpaulo * published by the Free Software Foundation. 39286441Srpaulo * 40286441Srpaulo * This program is distributed in the hope that it will be useful, but 41286441Srpaulo * WITHOUT ANY WARRANTY; without even the implied warranty of 42286441Srpaulo * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 43286441Srpaulo * General Public License for more details. 44286441Srpaulo * 45286441Srpaulo * You should have received a copy of the GNU General Public License 46286441Srpaulo * along with this program; if not, write to the Free Software 47286441Srpaulo * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, 48286441Srpaulo * USA 49286441Srpaulo * 50286441Srpaulo * The full GNU General Public License is included in this distribution 51286441Srpaulo * in the file called COPYING. 52286441Srpaulo * 53286441Srpaulo * Contact Information: 54286441Srpaulo * Intel Linux Wireless <ilw@linux.intel.com> 55286441Srpaulo * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 56286441Srpaulo * 57286441Srpaulo * 58286441Srpaulo * BSD LICENSE 59286441Srpaulo * 60286441Srpaulo * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved. 61286441Srpaulo * All rights reserved. 62286441Srpaulo * 63286441Srpaulo * Redistribution and use in source and binary forms, with or without 64286441Srpaulo * modification, are permitted provided that the following conditions 65286441Srpaulo * are met: 66286441Srpaulo * 67286441Srpaulo * * Redistributions of source code must retain the above copyright 68286441Srpaulo * notice, this list of conditions and the following disclaimer. 69286441Srpaulo * * Redistributions in binary form must reproduce the above copyright 70286441Srpaulo * notice, this list of conditions and the following disclaimer in 71286441Srpaulo * the documentation and/or other materials provided with the 72286441Srpaulo * distribution. 73286441Srpaulo * * Neither the name Intel Corporation nor the names of its 74286441Srpaulo * contributors may be used to endorse or promote products derived 75286441Srpaulo * from this software without specific prior written permission. 76286441Srpaulo * 77286441Srpaulo * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 78286441Srpaulo * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 79286441Srpaulo * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 80286441Srpaulo * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 81286441Srpaulo * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 82286441Srpaulo * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 83286441Srpaulo * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 84286441Srpaulo * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 85286441Srpaulo * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 86286441Srpaulo * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 87286441Srpaulo * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 88286441Srpaulo */ 89286441Srpaulo#include <sys/cdefs.h> 90286441Srpaulo__FBSDID("$FreeBSD: stable/11/sys/dev/iwm/if_iwm_power.c 330455 2018-03-05 08:05:30Z eadler $"); 91286441Srpaulo 92300248Savos#include "opt_wlan.h" 93330455Seadler#include "opt_iwm.h" 94300248Savos 95286441Srpaulo#include <sys/param.h> 96286441Srpaulo#include <sys/bus.h> 97286441Srpaulo#include <sys/conf.h> 98286441Srpaulo#include <sys/endian.h> 99286441Srpaulo#include <sys/firmware.h> 100286441Srpaulo#include <sys/kernel.h> 101286441Srpaulo#include <sys/malloc.h> 102286441Srpaulo#include <sys/mbuf.h> 103286441Srpaulo#include <sys/mutex.h> 104286441Srpaulo#include <sys/module.h> 105286441Srpaulo#include <sys/proc.h> 106286441Srpaulo#include <sys/rman.h> 107286441Srpaulo#include <sys/socket.h> 108286441Srpaulo#include <sys/sockio.h> 109286441Srpaulo#include <sys/sysctl.h> 110286441Srpaulo#include <sys/linker.h> 111286441Srpaulo 112286441Srpaulo#include <machine/bus.h> 113286441Srpaulo#include <machine/endian.h> 114286441Srpaulo#include <machine/resource.h> 115286441Srpaulo 116286441Srpaulo#include <dev/pci/pcivar.h> 117286441Srpaulo#include <dev/pci/pcireg.h> 118286441Srpaulo 119286441Srpaulo#include <net/bpf.h> 120286441Srpaulo 121286441Srpaulo#include <net/if.h> 122286441Srpaulo#include <net/if_var.h> 123286441Srpaulo#include <net/if_arp.h> 124286441Srpaulo#include <net/if_dl.h> 125286441Srpaulo#include <net/if_media.h> 126286441Srpaulo#include <net/if_types.h> 127286441Srpaulo 128286441Srpaulo#include <netinet/in.h> 129286441Srpaulo#include <netinet/in_systm.h> 130286441Srpaulo#include <netinet/if_ether.h> 131286441Srpaulo#include <netinet/ip.h> 132286441Srpaulo 133286441Srpaulo#include <net80211/ieee80211_var.h> 134286441Srpaulo#include <net80211/ieee80211_regdomain.h> 135286441Srpaulo#include <net80211/ieee80211_ratectl.h> 136286441Srpaulo#include <net80211/ieee80211_radiotap.h> 137286441Srpaulo 138286475Srpaulo#include <dev/iwm/if_iwmreg.h> 139286475Srpaulo#include <dev/iwm/if_iwmvar.h> 140286475Srpaulo#include <dev/iwm/if_iwm_debug.h> 141330201Seadler#include <dev/iwm/if_iwm_constants.h> 142286475Srpaulo#include <dev/iwm/if_iwm_util.h> 143286475Srpaulo#include <dev/iwm/if_iwm_power.h> 144286441Srpaulo 145330201Seadlerstatic int iwm_power_scheme = IWM_POWER_SCHEME_BPS; 146330201Seadler 147330201SeadlerTUNABLE_INT("hw.iwm.power_scheme", &iwm_power_scheme); 148330201Seadler 149286441Srpaulo/* 150286441Srpaulo * BEGIN mvm/power.c 151286441Srpaulo */ 152286441Srpaulo 153286441Srpaulo#define IWM_POWER_KEEP_ALIVE_PERIOD_SEC 25 154286441Srpaulo 155286441Srpaulostatic int 156286441Srpauloiwm_mvm_beacon_filter_send_cmd(struct iwm_softc *sc, 157286441Srpaulo struct iwm_beacon_filter_cmd *cmd) 158286441Srpaulo{ 159286441Srpaulo int ret; 160286441Srpaulo 161286441Srpaulo ret = iwm_mvm_send_cmd_pdu(sc, IWM_REPLY_BEACON_FILTERING_CMD, 162330201Seadler 0, sizeof(struct iwm_beacon_filter_cmd), cmd); 163286441Srpaulo 164286441Srpaulo if (!ret) { 165286441Srpaulo IWM_DPRINTF(sc, IWM_DEBUG_PWRSAVE | IWM_DEBUG_CMD, 166286441Srpaulo "ba_enable_beacon_abort is: %d\n", 167286441Srpaulo le32toh(cmd->ba_enable_beacon_abort)); 168286441Srpaulo IWM_DPRINTF(sc, IWM_DEBUG_PWRSAVE | IWM_DEBUG_CMD, 169286441Srpaulo "ba_escape_timer is: %d\n", 170286441Srpaulo le32toh(cmd->ba_escape_timer)); 171286441Srpaulo IWM_DPRINTF(sc, IWM_DEBUG_PWRSAVE | IWM_DEBUG_CMD, 172286441Srpaulo "bf_debug_flag is: %d\n", 173286441Srpaulo le32toh(cmd->bf_debug_flag)); 174286441Srpaulo IWM_DPRINTF(sc, IWM_DEBUG_PWRSAVE | IWM_DEBUG_CMD, 175286441Srpaulo "bf_enable_beacon_filter is: %d\n", 176286441Srpaulo le32toh(cmd->bf_enable_beacon_filter)); 177286441Srpaulo IWM_DPRINTF(sc, IWM_DEBUG_PWRSAVE | IWM_DEBUG_CMD, 178286441Srpaulo "bf_energy_delta is: %d\n", 179286441Srpaulo le32toh(cmd->bf_energy_delta)); 180286441Srpaulo IWM_DPRINTF(sc, IWM_DEBUG_PWRSAVE | IWM_DEBUG_CMD, 181286441Srpaulo "bf_escape_timer is: %d\n", 182286441Srpaulo le32toh(cmd->bf_escape_timer)); 183286441Srpaulo IWM_DPRINTF(sc, IWM_DEBUG_PWRSAVE | IWM_DEBUG_CMD, 184286441Srpaulo "bf_roaming_energy_delta is: %d\n", 185286441Srpaulo le32toh(cmd->bf_roaming_energy_delta)); 186286441Srpaulo IWM_DPRINTF(sc, IWM_DEBUG_PWRSAVE | IWM_DEBUG_CMD, 187286441Srpaulo "bf_roaming_state is: %d\n", 188286441Srpaulo le32toh(cmd->bf_roaming_state)); 189286441Srpaulo IWM_DPRINTF(sc, IWM_DEBUG_PWRSAVE | IWM_DEBUG_CMD, 190286441Srpaulo "bf_temp_threshold is: %d\n", 191286441Srpaulo le32toh(cmd->bf_temp_threshold)); 192286441Srpaulo IWM_DPRINTF(sc, IWM_DEBUG_PWRSAVE | IWM_DEBUG_CMD, 193286441Srpaulo "bf_temp_fast_filter is: %d\n", 194286441Srpaulo le32toh(cmd->bf_temp_fast_filter)); 195286441Srpaulo IWM_DPRINTF(sc, IWM_DEBUG_PWRSAVE | IWM_DEBUG_CMD, 196286441Srpaulo "bf_temp_slow_filter is: %d\n", 197286441Srpaulo le32toh(cmd->bf_temp_slow_filter)); 198286441Srpaulo } 199286441Srpaulo return ret; 200286441Srpaulo} 201286441Srpaulo 202286441Srpaulostatic void 203286441Srpauloiwm_mvm_beacon_filter_set_cqm_params(struct iwm_softc *sc, 204286441Srpaulo struct iwm_node *in, struct iwm_beacon_filter_cmd *cmd) 205286441Srpaulo{ 206286441Srpaulo cmd->ba_enable_beacon_abort = htole32(sc->sc_bf.ba_enabled); 207286441Srpaulo} 208286441Srpaulo 209286441Srpaulostatic void 210286441Srpauloiwm_mvm_power_log(struct iwm_softc *sc, struct iwm_mac_power_cmd *cmd) 211286441Srpaulo{ 212286441Srpaulo IWM_DPRINTF(sc, IWM_DEBUG_PWRSAVE | IWM_DEBUG_CMD, 213286441Srpaulo "Sending power table command on mac id 0x%X for " 214286441Srpaulo "power level %d, flags = 0x%X\n", 215286441Srpaulo cmd->id_and_color, IWM_POWER_SCHEME_CAM, le16toh(cmd->flags)); 216286441Srpaulo IWM_DPRINTF(sc, IWM_DEBUG_PWRSAVE | IWM_DEBUG_CMD, 217286441Srpaulo "Keep alive = %u sec\n", le16toh(cmd->keep_alive_seconds)); 218286441Srpaulo 219286441Srpaulo if (!(cmd->flags & htole16(IWM_POWER_FLAGS_POWER_MANAGEMENT_ENA_MSK))) { 220286441Srpaulo IWM_DPRINTF(sc, IWM_DEBUG_PWRSAVE | IWM_DEBUG_CMD, 221286441Srpaulo "Disable power management\n"); 222286441Srpaulo return; 223286441Srpaulo } 224330201Seadler 225330201Seadler IWM_DPRINTF(sc, IWM_DEBUG_PWRSAVE | IWM_DEBUG_CMD, 226330201Seadler "Rx timeout = %u usec\n", le32toh(cmd->rx_data_timeout)); 227330201Seadler IWM_DPRINTF(sc, IWM_DEBUG_PWRSAVE | IWM_DEBUG_CMD, 228330201Seadler "Tx timeout = %u usec\n", le32toh(cmd->tx_data_timeout)); 229330201Seadler if (cmd->flags & htole16(IWM_POWER_FLAGS_SKIP_OVER_DTIM_MSK)) 230330201Seadler IWM_DPRINTF(sc, IWM_DEBUG_PWRSAVE | IWM_DEBUG_CMD, 231330201Seadler "DTIM periods to skip = %u\n", cmd->skip_dtim_periods); 232286441Srpaulo} 233286441Srpaulo 234330201Seadlerstatic boolean_t 235330201Seadleriwm_mvm_power_is_radar(struct iwm_softc *sc) 236330201Seadler{ 237330201Seadler struct ieee80211com *ic = &sc->sc_ic; 238330201Seadler struct ieee80211_channel *chan; 239330201Seadler boolean_t radar_detect = FALSE; 240330201Seadler 241330201Seadler chan = ic->ic_bsschan; 242330201Seadler if (chan == IEEE80211_CHAN_ANYC || 243330201Seadler (chan->ic_flags & IEEE80211_CHAN_DFS) != 0) { 244330201Seadler radar_detect = TRUE; 245330201Seadler } 246330201Seadler 247330201Seadler return radar_detect; 248330201Seadler} 249330201Seadler 250286441Srpaulostatic void 251330201Seadleriwm_mvm_power_config_skip_dtim(struct iwm_softc *sc, 252330201Seadler struct iwm_mac_power_cmd *cmd) 253330201Seadler{ 254330201Seadler struct ieee80211com *ic = &sc->sc_ic; 255330201Seadler struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); 256330201Seadler int dtimper = vap->iv_dtim_period ?: 1; 257330201Seadler int skip; 258330201Seadler 259330201Seadler /* disable, in case we're supposed to override */ 260330201Seadler cmd->skip_dtim_periods = 0; 261330201Seadler cmd->flags &= ~htole16(IWM_POWER_FLAGS_SKIP_OVER_DTIM_MSK); 262330201Seadler 263330201Seadler if (iwm_mvm_power_is_radar(sc)) 264330201Seadler return; 265330201Seadler 266330201Seadler if (dtimper >= 10) 267330201Seadler return; 268330201Seadler 269330201Seadler /* TODO: check that multicast wake lock is off */ 270330201Seadler 271330201Seadler if (iwm_power_scheme != IWM_POWER_SCHEME_LP) 272330201Seadler return; 273330201Seadler skip = 2; 274330201Seadler 275330201Seadler /* the firmware really expects "look at every X DTIMs", so add 1 */ 276330201Seadler cmd->skip_dtim_periods = 1 + skip; 277330201Seadler cmd->flags |= htole16(IWM_POWER_FLAGS_SKIP_OVER_DTIM_MSK); 278330201Seadler} 279330201Seadler 280330201Seadlerstatic void 281286441Srpauloiwm_mvm_power_build_cmd(struct iwm_softc *sc, struct iwm_node *in, 282286441Srpaulo struct iwm_mac_power_cmd *cmd) 283286441Srpaulo{ 284286441Srpaulo struct ieee80211_node *ni = &in->in_ni; 285286441Srpaulo int dtimper, dtimper_msec; 286286441Srpaulo int keep_alive; 287287197Sglebius struct ieee80211com *ic = &sc->sc_ic; 288286441Srpaulo struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); 289330204Seadler struct iwm_vap *ivp = IWM_VAP(vap); 290286441Srpaulo 291330204Seadler cmd->id_and_color = htole32(IWM_FW_CMD_ID_AND_COLOR(ivp->id, 292330204Seadler ivp->color)); 293286441Srpaulo dtimper = vap->iv_dtim_period ?: 1; 294286441Srpaulo 295286441Srpaulo /* 296286441Srpaulo * Regardless of power management state the driver must set 297286441Srpaulo * keep alive period. FW will use it for sending keep alive NDPs 298286441Srpaulo * immediately after association. Check that keep alive period 299286441Srpaulo * is at least 3 * DTIM 300286441Srpaulo */ 301286441Srpaulo dtimper_msec = dtimper * ni->ni_intval; 302286441Srpaulo keep_alive 303330201Seadler = imax(3 * dtimper_msec, 1000 * IWM_POWER_KEEP_ALIVE_PERIOD_SEC); 304286441Srpaulo keep_alive = roundup(keep_alive, 1000) / 1000; 305286441Srpaulo cmd->keep_alive_seconds = htole16(keep_alive); 306330201Seadler 307330201Seadler if (sc->sc_ps_disabled) 308330201Seadler return; 309330201Seadler 310330201Seadler cmd->flags |= htole16(IWM_POWER_FLAGS_POWER_SAVE_ENA_MSK); 311330201Seadler cmd->flags |= htole16(IWM_POWER_FLAGS_POWER_MANAGEMENT_ENA_MSK); 312330201Seadler 313330201Seadler iwm_mvm_power_config_skip_dtim(sc, cmd); 314330201Seadler 315330201Seadler cmd->rx_data_timeout = 316330201Seadler htole32(IWM_MVM_DEFAULT_PS_RX_DATA_TIMEOUT); 317330201Seadler cmd->tx_data_timeout = 318330201Seadler htole32(IWM_MVM_DEFAULT_PS_TX_DATA_TIMEOUT); 319286441Srpaulo} 320286441Srpaulo 321330201Seadlerstatic int 322330201Seadleriwm_mvm_power_send_cmd(struct iwm_softc *sc, struct iwm_node *in) 323286441Srpaulo{ 324330201Seadler struct iwm_mac_power_cmd cmd = {}; 325286441Srpaulo 326286441Srpaulo iwm_mvm_power_build_cmd(sc, in, &cmd); 327286441Srpaulo iwm_mvm_power_log(sc, &cmd); 328286441Srpaulo 329330201Seadler return iwm_mvm_send_cmd_pdu(sc, IWM_MAC_PM_POWER_TABLE, 0, 330330201Seadler sizeof(cmd), &cmd); 331286441Srpaulo} 332286441Srpaulo 333330201Seadlerstatic int 334330201Seadler_iwm_mvm_enable_beacon_filter(struct iwm_softc *sc, struct iwm_node *in, 335330201Seadler struct iwm_beacon_filter_cmd *cmd) 336286441Srpaulo{ 337330201Seadler int ret; 338286441Srpaulo 339330201Seadler iwm_mvm_beacon_filter_set_cqm_params(sc, in, cmd); 340330201Seadler ret = iwm_mvm_beacon_filter_send_cmd(sc, cmd); 341286441Srpaulo 342330201Seadler if (!ret) 343330201Seadler sc->sc_bf.bf_enabled = 1; 344330201Seadler 345330201Seadler return ret; 346286441Srpaulo} 347286441Srpaulo 348286441Srpauloint 349286441Srpauloiwm_mvm_enable_beacon_filter(struct iwm_softc *sc, struct iwm_node *in) 350286441Srpaulo{ 351286441Srpaulo struct iwm_beacon_filter_cmd cmd = { 352286441Srpaulo IWM_BF_CMD_CONFIG_DEFAULTS, 353286441Srpaulo .bf_enable_beacon_filter = htole32(1), 354286441Srpaulo }; 355286441Srpaulo 356330201Seadler return _iwm_mvm_enable_beacon_filter(sc, in, &cmd); 357286441Srpaulo} 358286441Srpaulo 359286441Srpauloint 360286441Srpauloiwm_mvm_disable_beacon_filter(struct iwm_softc *sc) 361286441Srpaulo{ 362330195Seadler struct iwm_beacon_filter_cmd cmd = {}; 363286441Srpaulo int ret; 364286441Srpaulo 365286441Srpaulo ret = iwm_mvm_beacon_filter_send_cmd(sc, &cmd); 366286441Srpaulo if (ret == 0) 367286441Srpaulo sc->sc_bf.bf_enabled = 0; 368286441Srpaulo 369286441Srpaulo return ret; 370286441Srpaulo} 371330201Seadler 372330201Seadlerstatic int 373330201Seadleriwm_mvm_power_set_ps(struct iwm_softc *sc) 374330201Seadler{ 375330201Seadler struct ieee80211vap *vap = TAILQ_FIRST(&sc->sc_ic.ic_vaps); 376330201Seadler boolean_t disable_ps; 377330201Seadler int ret; 378330201Seadler 379330201Seadler /* disable PS if CAM */ 380330201Seadler disable_ps = (iwm_power_scheme == IWM_POWER_SCHEME_CAM); 381330201Seadler /* ...or if any of the vifs require PS to be off */ 382330201Seadler if (vap != NULL && (vap->iv_flags & IEEE80211_F_PMGTON) == 0) 383330201Seadler disable_ps = TRUE; 384330201Seadler 385330201Seadler /* update device power state if it has changed */ 386330201Seadler if (sc->sc_ps_disabled != disable_ps) { 387330201Seadler boolean_t old_ps_disabled = sc->sc_ps_disabled; 388330201Seadler 389330201Seadler sc->sc_ps_disabled = disable_ps; 390330201Seadler ret = iwm_mvm_power_update_device(sc); 391330201Seadler if (ret) { 392330201Seadler sc->sc_ps_disabled = old_ps_disabled; 393330201Seadler return ret; 394330201Seadler } 395330201Seadler } 396330201Seadler 397330201Seadler return 0; 398330201Seadler} 399330201Seadler 400330201Seadlerstatic int 401330201Seadleriwm_mvm_power_set_ba(struct iwm_softc *sc, struct iwm_node *in) 402330201Seadler{ 403330201Seadler struct iwm_beacon_filter_cmd cmd = { 404330201Seadler IWM_BF_CMD_CONFIG_DEFAULTS, 405330201Seadler .bf_enable_beacon_filter = htole32(1), 406330201Seadler }; 407330201Seadler 408330201Seadler if (!sc->sc_bf.bf_enabled) 409330201Seadler return 0; 410330201Seadler 411330201Seadler sc->sc_bf.ba_enabled = !sc->sc_ps_disabled; 412330201Seadler 413330201Seadler return _iwm_mvm_enable_beacon_filter(sc, in, &cmd); 414330201Seadler} 415330201Seadler 416330201Seadlerint 417330201Seadleriwm_mvm_power_update_ps(struct iwm_softc *sc) 418330201Seadler{ 419330201Seadler struct ieee80211vap *vap = TAILQ_FIRST(&sc->sc_ic.ic_vaps); 420330201Seadler int ret; 421330201Seadler 422330201Seadler ret = iwm_mvm_power_set_ps(sc); 423330201Seadler if (ret) 424330201Seadler return ret; 425330201Seadler 426330201Seadler if (vap != NULL) 427330201Seadler return iwm_mvm_power_set_ba(sc, IWM_NODE(vap->iv_bss)); 428330201Seadler 429330201Seadler return 0; 430330201Seadler} 431330201Seadler 432330201Seadlerint 433330201Seadleriwm_mvm_power_update_mac(struct iwm_softc *sc) 434330201Seadler{ 435330201Seadler struct ieee80211vap *vap = TAILQ_FIRST(&sc->sc_ic.ic_vaps); 436330201Seadler int ret; 437330201Seadler 438330201Seadler ret = iwm_mvm_power_set_ps(sc); 439330201Seadler if (ret) 440330201Seadler return ret; 441330201Seadler 442330201Seadler if (vap != NULL) { 443330201Seadler ret = iwm_mvm_power_send_cmd(sc, IWM_NODE(vap->iv_bss)); 444330201Seadler if (ret) 445330201Seadler return ret; 446330201Seadler } 447330201Seadler 448330201Seadler if (vap != NULL) 449330201Seadler return iwm_mvm_power_set_ba(sc, IWM_NODE(vap->iv_bss)); 450330201Seadler 451330201Seadler return 0; 452330201Seadler} 453330201Seadler 454330201Seadlerint 455330201Seadleriwm_mvm_power_update_device(struct iwm_softc *sc) 456330201Seadler{ 457330201Seadler struct iwm_device_power_cmd cmd = { 458330201Seadler .flags = 0, 459330201Seadler }; 460330201Seadler 461330201Seadler if (iwm_power_scheme == IWM_POWER_SCHEME_CAM) 462330201Seadler sc->sc_ps_disabled = TRUE; 463330201Seadler 464330201Seadler if (!sc->sc_ps_disabled) 465330201Seadler cmd.flags |= htole16(IWM_DEVICE_POWER_FLAGS_POWER_SAVE_ENA_MSK); 466330201Seadler 467330201Seadler IWM_DPRINTF(sc, IWM_DEBUG_PWRSAVE | IWM_DEBUG_CMD, 468330201Seadler "Sending device power command with flags = 0x%X\n", cmd.flags); 469330201Seadler 470330201Seadler return iwm_mvm_send_cmd_pdu(sc, 471330201Seadler IWM_POWER_TABLE_CMD, 0, sizeof(cmd), &cmd); 472330201Seadler} 473