1cd684decSAdrian Chadd /* 2cd684decSAdrian Chadd * Copyright (c) 2014 genua mbh <info@genua.de> 3cd684decSAdrian Chadd * Copyright (c) 2014 Fixup Software Ltd. 4cd684decSAdrian Chadd * 5cd684decSAdrian Chadd * Permission to use, copy, modify, and distribute this software for any 6cd684decSAdrian Chadd * purpose with or without fee is hereby granted, provided that the above 7cd684decSAdrian Chadd * copyright notice and this permission notice appear in all copies. 8cd684decSAdrian Chadd * 9cd684decSAdrian Chadd * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10cd684decSAdrian Chadd * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11cd684decSAdrian Chadd * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12cd684decSAdrian Chadd * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13cd684decSAdrian Chadd * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14cd684decSAdrian Chadd * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15cd684decSAdrian Chadd * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16cd684decSAdrian Chadd */ 17cd684decSAdrian Chadd 18cd684decSAdrian Chadd /*- 19cd684decSAdrian Chadd * Based on BSD-licensed source modules in the Linux iwlwifi driver, 20cd684decSAdrian Chadd * which were used as the reference documentation for this implementation. 21cd684decSAdrian Chadd * 22cd684decSAdrian Chadd * Driver version we are currently based off of is 23cd684decSAdrian Chadd * Linux 4.7.3 (tag id d7f6728f57e3ecbb7ef34eb7d9f564d514775d75) 24cd684decSAdrian Chadd * 25cd684decSAdrian Chadd ****************************************************************************** 26cd684decSAdrian Chadd * 27cd684decSAdrian Chadd * This file is provided under a dual BSD/GPLv2 license. When using or 28cd684decSAdrian Chadd * redistributing this file, you may do so under either license. 29cd684decSAdrian Chadd * 30cd684decSAdrian Chadd * GPL LICENSE SUMMARY 31cd684decSAdrian Chadd * 32cd684decSAdrian Chadd * Copyright(c) 2013 - 2014 Intel Corporation. All rights reserved. 33cd684decSAdrian Chadd * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH 34cd684decSAdrian Chadd * 35cd684decSAdrian Chadd * This program is free software; you can redistribute it and/or modify 36cd684decSAdrian Chadd * it under the terms of version 2 of the GNU General Public License as 37cd684decSAdrian Chadd * published by the Free Software Foundation. 38cd684decSAdrian Chadd * 39cd684decSAdrian Chadd * This program is distributed in the hope that it will be useful, but 40cd684decSAdrian Chadd * WITHOUT ANY WARRANTY; without even the implied warranty of 41cd684decSAdrian Chadd * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 42cd684decSAdrian Chadd * General Public License for more details. 43cd684decSAdrian Chadd * 44cd684decSAdrian Chadd * You should have received a copy of the GNU General Public License 45cd684decSAdrian Chadd * along with this program; if not, write to the Free Software 46cd684decSAdrian Chadd * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, 47cd684decSAdrian Chadd * USA 48cd684decSAdrian Chadd * 49cd684decSAdrian Chadd * The full GNU General Public License is included in this distribution 50cd684decSAdrian Chadd * in the file called COPYING. 51cd684decSAdrian Chadd * 52cd684decSAdrian Chadd * Contact Information: 53cd684decSAdrian Chadd * Intel Linux Wireless <linuxwifi@intel.com> 54cd684decSAdrian Chadd * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 55cd684decSAdrian Chadd * 56cd684decSAdrian Chadd * BSD LICENSE 57cd684decSAdrian Chadd * 58cd684decSAdrian Chadd * Copyright(c) 2013 - 2014 Intel Corporation. All rights reserved. 59cd684decSAdrian Chadd * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH 60cd684decSAdrian Chadd * All rights reserved. 61cd684decSAdrian Chadd * 62cd684decSAdrian Chadd * Redistribution and use in source and binary forms, with or without 63cd684decSAdrian Chadd * modification, are permitted provided that the following conditions 64cd684decSAdrian Chadd * are met: 65cd684decSAdrian Chadd * 66cd684decSAdrian Chadd * * Redistributions of source code must retain the above copyright 67cd684decSAdrian Chadd * notice, this list of conditions and the following disclaimer. 68cd684decSAdrian Chadd * * Redistributions in binary form must reproduce the above copyright 69cd684decSAdrian Chadd * notice, this list of conditions and the following disclaimer in 70cd684decSAdrian Chadd * the documentation and/or other materials provided with the 71cd684decSAdrian Chadd * distribution. 72cd684decSAdrian Chadd * * Neither the name Intel Corporation nor the names of its 73cd684decSAdrian Chadd * contributors may be used to endorse or promote products derived 74cd684decSAdrian Chadd * from this software without specific prior written permission. 75cd684decSAdrian Chadd * 76cd684decSAdrian Chadd * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 77cd684decSAdrian Chadd * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 78cd684decSAdrian Chadd * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 79cd684decSAdrian Chadd * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 80cd684decSAdrian Chadd * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 81cd684decSAdrian Chadd * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 82cd684decSAdrian Chadd * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 83cd684decSAdrian Chadd * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 84cd684decSAdrian Chadd * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 85cd684decSAdrian Chadd * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 86cd684decSAdrian Chadd * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 87cd684decSAdrian Chadd * 88cd684decSAdrian Chadd *****************************************************************************/ 89cd684decSAdrian Chadd 90cd684decSAdrian Chadd #include <sys/cdefs.h> 91cd684decSAdrian Chadd __FBSDID("$FreeBSD$"); 92cd684decSAdrian Chadd 93cd684decSAdrian Chadd #include "opt_wlan.h" 94cd684decSAdrian Chadd #include "opt_iwm.h" 95cd684decSAdrian Chadd 96cd684decSAdrian Chadd #include <sys/param.h> 97cd684decSAdrian Chadd #include <sys/bus.h> 98cd684decSAdrian Chadd #include <sys/conf.h> 99cd684decSAdrian Chadd #include <sys/endian.h> 100cd684decSAdrian Chadd #include <sys/firmware.h> 101cd684decSAdrian Chadd #include <sys/kernel.h> 102cd684decSAdrian Chadd #include <sys/malloc.h> 103cd684decSAdrian Chadd #include <sys/mbuf.h> 104cd684decSAdrian Chadd #include <sys/mutex.h> 105cd684decSAdrian Chadd #include <sys/module.h> 106cd684decSAdrian Chadd #include <sys/proc.h> 107cd684decSAdrian Chadd #include <sys/rman.h> 108cd684decSAdrian Chadd #include <sys/socket.h> 109cd684decSAdrian Chadd #include <sys/sockio.h> 110cd684decSAdrian Chadd #include <sys/sysctl.h> 111cd684decSAdrian Chadd #include <sys/linker.h> 112cd684decSAdrian Chadd 113cd684decSAdrian Chadd #include <machine/bus.h> 114cd684decSAdrian Chadd #include <machine/endian.h> 115cd684decSAdrian Chadd #include <machine/resource.h> 116cd684decSAdrian Chadd 117cd684decSAdrian Chadd #include <net/if.h> 118cd684decSAdrian Chadd #include <net/if_var.h> 119cd684decSAdrian Chadd #include <net/if_arp.h> 120cd684decSAdrian Chadd #include <net/if_dl.h> 121cd684decSAdrian Chadd #include <net/if_media.h> 122cd684decSAdrian Chadd #include <net/if_types.h> 123cd684decSAdrian Chadd #include <net/bpf.h> 124cd684decSAdrian Chadd 125cd684decSAdrian Chadd #include <netinet/in.h> 126cd684decSAdrian Chadd #include <netinet/in_systm.h> 127cd684decSAdrian Chadd #include <netinet/if_ether.h> 128cd684decSAdrian Chadd #include <netinet/ip.h> 129cd684decSAdrian Chadd 130cd684decSAdrian Chadd #include <net80211/ieee80211_var.h> 131cd684decSAdrian Chadd #include <net80211/ieee80211_regdomain.h> 132cd684decSAdrian Chadd #include <net80211/ieee80211_ratectl.h> 133cd684decSAdrian Chadd #include <net80211/ieee80211_radiotap.h> 134cd684decSAdrian Chadd 135cd684decSAdrian Chadd #include <dev/iwm/if_iwmreg.h> 136cd684decSAdrian Chadd #include <dev/iwm/if_iwmvar.h> 137cd684decSAdrian Chadd #include <dev/iwm/if_iwm_config.h> 138cd684decSAdrian Chadd #include <dev/iwm/if_iwm_debug.h> 139cd684decSAdrian Chadd #include <dev/iwm/if_iwm_util.h> 140cd684decSAdrian Chadd #include <dev/iwm/if_iwm_sf.h> 141cd684decSAdrian Chadd 142cd684decSAdrian Chadd /* 143cd684decSAdrian Chadd * Aging and idle timeouts for the different possible scenarios 144cd684decSAdrian Chadd * in default configuration 145cd684decSAdrian Chadd */ 146cd684decSAdrian Chadd static const uint32_t 147cd684decSAdrian Chadd sf_full_timeout_def[IWM_SF_NUM_SCENARIO][IWM_SF_NUM_TIMEOUT_TYPES] = { 148cd684decSAdrian Chadd { 149cd684decSAdrian Chadd htole32(IWM_SF_SINGLE_UNICAST_AGING_TIMER_DEF), 150cd684decSAdrian Chadd htole32(IWM_SF_SINGLE_UNICAST_IDLE_TIMER_DEF) 151cd684decSAdrian Chadd }, 152cd684decSAdrian Chadd { 153cd684decSAdrian Chadd htole32(IWM_SF_AGG_UNICAST_AGING_TIMER_DEF), 154cd684decSAdrian Chadd htole32(IWM_SF_AGG_UNICAST_IDLE_TIMER_DEF) 155cd684decSAdrian Chadd }, 156cd684decSAdrian Chadd { 157cd684decSAdrian Chadd htole32(IWM_SF_MCAST_AGING_TIMER_DEF), 158cd684decSAdrian Chadd htole32(IWM_SF_MCAST_IDLE_TIMER_DEF) 159cd684decSAdrian Chadd }, 160cd684decSAdrian Chadd { 161cd684decSAdrian Chadd htole32(IWM_SF_BA_AGING_TIMER_DEF), 162cd684decSAdrian Chadd htole32(IWM_SF_BA_IDLE_TIMER_DEF) 163cd684decSAdrian Chadd }, 164cd684decSAdrian Chadd { 165cd684decSAdrian Chadd htole32(IWM_SF_TX_RE_AGING_TIMER_DEF), 166cd684decSAdrian Chadd htole32(IWM_SF_TX_RE_IDLE_TIMER_DEF) 167cd684decSAdrian Chadd }, 168cd684decSAdrian Chadd }; 169cd684decSAdrian Chadd 170cd684decSAdrian Chadd /* 171cd684decSAdrian Chadd * Aging and idle timeouts for the different possible scenarios 172cd684decSAdrian Chadd * in single BSS MAC configuration. 173cd684decSAdrian Chadd */ 174cd684decSAdrian Chadd static const uint32_t 175cd684decSAdrian Chadd sf_full_timeout[IWM_SF_NUM_SCENARIO][IWM_SF_NUM_TIMEOUT_TYPES] = { 176cd684decSAdrian Chadd { 177cd684decSAdrian Chadd htole32(IWM_SF_SINGLE_UNICAST_AGING_TIMER), 178cd684decSAdrian Chadd htole32(IWM_SF_SINGLE_UNICAST_IDLE_TIMER) 179cd684decSAdrian Chadd }, 180cd684decSAdrian Chadd { 181cd684decSAdrian Chadd htole32(IWM_SF_AGG_UNICAST_AGING_TIMER), 182cd684decSAdrian Chadd htole32(IWM_SF_AGG_UNICAST_IDLE_TIMER) 183cd684decSAdrian Chadd }, 184cd684decSAdrian Chadd { 185cd684decSAdrian Chadd htole32(IWM_SF_MCAST_AGING_TIMER), 186cd684decSAdrian Chadd htole32(IWM_SF_MCAST_IDLE_TIMER) 187cd684decSAdrian Chadd }, 188cd684decSAdrian Chadd { 189cd684decSAdrian Chadd htole32(IWM_SF_BA_AGING_TIMER), 190cd684decSAdrian Chadd htole32(IWM_SF_BA_IDLE_TIMER) 191cd684decSAdrian Chadd }, 192cd684decSAdrian Chadd { 193cd684decSAdrian Chadd htole32(IWM_SF_TX_RE_AGING_TIMER), 194cd684decSAdrian Chadd htole32(IWM_SF_TX_RE_IDLE_TIMER) 195cd684decSAdrian Chadd }, 196cd684decSAdrian Chadd }; 197cd684decSAdrian Chadd 198cd684decSAdrian Chadd static void 199*e7065dd1SMark Johnston iwm_fill_sf_command(struct iwm_softc *sc, struct iwm_sf_cfg_cmd *sf_cmd, 200cd684decSAdrian Chadd struct ieee80211_node *ni) 201cd684decSAdrian Chadd { 202cd684decSAdrian Chadd int i, j, watermark; 203cd684decSAdrian Chadd 204cd684decSAdrian Chadd sf_cmd->watermark[IWM_SF_LONG_DELAY_ON] = htole32(IWM_SF_W_MARK_SCAN); 205cd684decSAdrian Chadd 206cd684decSAdrian Chadd /* 207cd684decSAdrian Chadd * If we are in association flow - check antenna configuration 208cd684decSAdrian Chadd * capabilities of the AP station, and choose the watermark accordingly. 209cd684decSAdrian Chadd */ 210cd684decSAdrian Chadd if (ni) { 211cd684decSAdrian Chadd if (ni->ni_flags & IEEE80211_NODE_HT) { 212cd684decSAdrian Chadd watermark = IWM_SF_W_MARK_SISO; 213cd684decSAdrian Chadd } else { 214cd684decSAdrian Chadd watermark = IWM_SF_W_MARK_LEGACY; 215cd684decSAdrian Chadd } 216cd684decSAdrian Chadd /* default watermark value for unassociated mode. */ 217cd684decSAdrian Chadd } else { 218cd684decSAdrian Chadd watermark = IWM_SF_W_MARK_MIMO2; 219cd684decSAdrian Chadd } 220cd684decSAdrian Chadd sf_cmd->watermark[IWM_SF_FULL_ON] = htole32(watermark); 221cd684decSAdrian Chadd 222cd684decSAdrian Chadd for (i = 0; i < IWM_SF_NUM_SCENARIO; i++) { 223cd684decSAdrian Chadd for (j = 0; j < IWM_SF_NUM_TIMEOUT_TYPES; j++) { 224cd684decSAdrian Chadd sf_cmd->long_delay_timeouts[i][j] = 225cd684decSAdrian Chadd htole32(IWM_SF_LONG_DELAY_AGING_TIMER); 226cd684decSAdrian Chadd } 227cd684decSAdrian Chadd } 228cd684decSAdrian Chadd 229cd684decSAdrian Chadd if (ni) { 230cd684decSAdrian Chadd _Static_assert(sizeof(sf_full_timeout) == sizeof(uint32_t) * 231cd684decSAdrian Chadd IWM_SF_NUM_SCENARIO * IWM_SF_NUM_TIMEOUT_TYPES, 232cd684decSAdrian Chadd "sf_full_timeout has wrong size"); 233cd684decSAdrian Chadd 234cd684decSAdrian Chadd memcpy(sf_cmd->full_on_timeouts, sf_full_timeout, 235cd684decSAdrian Chadd sizeof(sf_full_timeout)); 236cd684decSAdrian Chadd } else { 237cd684decSAdrian Chadd _Static_assert(sizeof(sf_full_timeout_def) == sizeof(uint32_t) * 238cd684decSAdrian Chadd IWM_SF_NUM_SCENARIO * IWM_SF_NUM_TIMEOUT_TYPES, 239cd684decSAdrian Chadd "sf_full_timeout_def has wrong size"); 240cd684decSAdrian Chadd 241cd684decSAdrian Chadd memcpy(sf_cmd->full_on_timeouts, sf_full_timeout_def, 242cd684decSAdrian Chadd sizeof(sf_full_timeout_def)); 243cd684decSAdrian Chadd } 244cd684decSAdrian Chadd } 245cd684decSAdrian Chadd 246cd684decSAdrian Chadd static int 247*e7065dd1SMark Johnston iwm_sf_config(struct iwm_softc *sc, struct ieee80211_node *ni, 248cd684decSAdrian Chadd enum iwm_sf_state new_state) 249cd684decSAdrian Chadd { 250cd684decSAdrian Chadd struct iwm_sf_cfg_cmd sf_cmd = { 251eecff6a7SAdrian Chadd .state = htole32(new_state), 252cd684decSAdrian Chadd }; 253cd684decSAdrian Chadd int ret = 0; 254cd684decSAdrian Chadd 255cd684decSAdrian Chadd #ifdef notyet /* only relevant for sdio variants */ 256cd684decSAdrian Chadd if (sc->cfg->disable_dummy_notification) 257cd684decSAdrian Chadd sf_cmd.state |= htole32(IWM_SF_CFG_DUMMY_NOTIF_OFF); 258cd684decSAdrian Chadd #endif 259cd684decSAdrian Chadd 260cd684decSAdrian Chadd /* 261cd684decSAdrian Chadd * If an associated AP sta changed its antenna configuration, the state 262cd684decSAdrian Chadd * will remain FULL_ON but SF parameters need to be reconsidered. 263cd684decSAdrian Chadd */ 264cd684decSAdrian Chadd if (new_state != IWM_SF_FULL_ON && sc->sf_state == new_state) 265cd684decSAdrian Chadd return 0; 266cd684decSAdrian Chadd 267cd684decSAdrian Chadd switch (new_state) { 268cd684decSAdrian Chadd case IWM_SF_UNINIT: 269*e7065dd1SMark Johnston iwm_fill_sf_command(sc, &sf_cmd, NULL); 270cd684decSAdrian Chadd break; 271cd684decSAdrian Chadd case IWM_SF_FULL_ON: 272*e7065dd1SMark Johnston iwm_fill_sf_command(sc, &sf_cmd, ni); 273cd684decSAdrian Chadd break; 274cd684decSAdrian Chadd case IWM_SF_INIT_OFF: 275*e7065dd1SMark Johnston iwm_fill_sf_command(sc, &sf_cmd, NULL); 276cd684decSAdrian Chadd break; 277cd684decSAdrian Chadd default: 278cd684decSAdrian Chadd device_printf(sc->sc_dev, 279cd684decSAdrian Chadd "Invalid state: %d. not sending Smart Fifo cmd\n", 280cd684decSAdrian Chadd new_state); 281cd684decSAdrian Chadd return EINVAL; 282cd684decSAdrian Chadd } 283cd684decSAdrian Chadd 284*e7065dd1SMark Johnston ret = iwm_send_cmd_pdu(sc, IWM_REPLY_SF_CFG_CMD, IWM_CMD_ASYNC, 285cd684decSAdrian Chadd sizeof(sf_cmd), &sf_cmd); 286cd684decSAdrian Chadd if (!ret) 287cd684decSAdrian Chadd sc->sf_state = new_state; 288cd684decSAdrian Chadd 289cd684decSAdrian Chadd return ret; 290cd684decSAdrian Chadd } 291cd684decSAdrian Chadd 292cd684decSAdrian Chadd /* 293cd684decSAdrian Chadd * Update Smart fifo: 294cd684decSAdrian Chadd * Count bound interfaces that are not to be removed, ignoring p2p devices, 295cd684decSAdrian Chadd * and set new state accordingly. 296cd684decSAdrian Chadd */ 297cd684decSAdrian Chadd int 298*e7065dd1SMark Johnston iwm_sf_update(struct iwm_softc *sc, struct ieee80211vap *changed_vif, 299cd684decSAdrian Chadd boolean_t remove_vif) 300cd684decSAdrian Chadd { 301cd684decSAdrian Chadd enum iwm_sf_state new_state; 302cd684decSAdrian Chadd struct ieee80211_node *ni = NULL; 303cd684decSAdrian Chadd int num_active_macs = 0; 304cd684decSAdrian Chadd 305cd684decSAdrian Chadd /* If changed_vif exists and is not to be removed, add to the count */ 306cd684decSAdrian Chadd if (changed_vif && !remove_vif) 307cd684decSAdrian Chadd num_active_macs++; 308cd684decSAdrian Chadd 309cd684decSAdrian Chadd switch (num_active_macs) { 310cd684decSAdrian Chadd case 0: 311cd684decSAdrian Chadd /* If there are no active macs - change state to SF_INIT_OFF */ 312cd684decSAdrian Chadd new_state = IWM_SF_INIT_OFF; 313cd684decSAdrian Chadd break; 314cd684decSAdrian Chadd case 1: 315cd684decSAdrian Chadd if (!changed_vif) 316cd684decSAdrian Chadd return EINVAL; 317cd684decSAdrian Chadd ni = changed_vif->iv_bss; 318cd684decSAdrian Chadd if (ni != NULL && IWM_NODE(ni)->in_assoc && 319cd684decSAdrian Chadd changed_vif->iv_dtim_period) { 320cd684decSAdrian Chadd new_state = IWM_SF_FULL_ON; 321cd684decSAdrian Chadd } else { 322cd684decSAdrian Chadd new_state = IWM_SF_INIT_OFF; 323cd684decSAdrian Chadd } 324cd684decSAdrian Chadd break; 325cd684decSAdrian Chadd default: 326cd684decSAdrian Chadd /* If there are multiple active macs - change to SF_UNINIT */ 327cd684decSAdrian Chadd new_state = IWM_SF_UNINIT; 328cd684decSAdrian Chadd } 329*e7065dd1SMark Johnston return iwm_sf_config(sc, ni, new_state); 330cd684decSAdrian Chadd } 331