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