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/cdefs.h> 91 __FBSDID("$FreeBSD$"); 92 93 #include "opt_wlan.h" 94 #include "opt_iwm.h" 95 96 #include <sys/param.h> 97 #include <sys/bus.h> 98 #include <sys/conf.h> 99 #include <sys/endian.h> 100 #include <sys/firmware.h> 101 #include <sys/kernel.h> 102 #include <sys/malloc.h> 103 #include <sys/mbuf.h> 104 #include <sys/mutex.h> 105 #include <sys/module.h> 106 #include <sys/proc.h> 107 #include <sys/rman.h> 108 #include <sys/socket.h> 109 #include <sys/sockio.h> 110 #include <sys/sysctl.h> 111 #include <sys/linker.h> 112 113 #include <machine/bus.h> 114 #include <machine/endian.h> 115 #include <machine/resource.h> 116 117 #include <net/if.h> 118 #include <net/if_var.h> 119 #include <net/if_arp.h> 120 #include <net/if_dl.h> 121 #include <net/if_media.h> 122 #include <net/if_types.h> 123 #include <net/bpf.h> 124 125 #include <netinet/in.h> 126 #include <netinet/in_systm.h> 127 #include <netinet/if_ether.h> 128 #include <netinet/ip.h> 129 130 #include <net80211/ieee80211_var.h> 131 #include <net80211/ieee80211_regdomain.h> 132 #include <net80211/ieee80211_ratectl.h> 133 #include <net80211/ieee80211_radiotap.h> 134 135 #include <dev/iwm/if_iwmreg.h> 136 #include <dev/iwm/if_iwmvar.h> 137 #include <dev/iwm/if_iwm_config.h> 138 #include <dev/iwm/if_iwm_debug.h> 139 #include <dev/iwm/if_iwm_util.h> 140 #include <dev/iwm/if_iwm_sf.h> 141 142 /* 143 * Aging and idle timeouts for the different possible scenarios 144 * in default configuration 145 */ 146 static const uint32_t 147 sf_full_timeout_def[IWM_SF_NUM_SCENARIO][IWM_SF_NUM_TIMEOUT_TYPES] = { 148 { 149 htole32(IWM_SF_SINGLE_UNICAST_AGING_TIMER_DEF), 150 htole32(IWM_SF_SINGLE_UNICAST_IDLE_TIMER_DEF) 151 }, 152 { 153 htole32(IWM_SF_AGG_UNICAST_AGING_TIMER_DEF), 154 htole32(IWM_SF_AGG_UNICAST_IDLE_TIMER_DEF) 155 }, 156 { 157 htole32(IWM_SF_MCAST_AGING_TIMER_DEF), 158 htole32(IWM_SF_MCAST_IDLE_TIMER_DEF) 159 }, 160 { 161 htole32(IWM_SF_BA_AGING_TIMER_DEF), 162 htole32(IWM_SF_BA_IDLE_TIMER_DEF) 163 }, 164 { 165 htole32(IWM_SF_TX_RE_AGING_TIMER_DEF), 166 htole32(IWM_SF_TX_RE_IDLE_TIMER_DEF) 167 }, 168 }; 169 170 /* 171 * Aging and idle timeouts for the different possible scenarios 172 * in single BSS MAC configuration. 173 */ 174 static const uint32_t 175 sf_full_timeout[IWM_SF_NUM_SCENARIO][IWM_SF_NUM_TIMEOUT_TYPES] = { 176 { 177 htole32(IWM_SF_SINGLE_UNICAST_AGING_TIMER), 178 htole32(IWM_SF_SINGLE_UNICAST_IDLE_TIMER) 179 }, 180 { 181 htole32(IWM_SF_AGG_UNICAST_AGING_TIMER), 182 htole32(IWM_SF_AGG_UNICAST_IDLE_TIMER) 183 }, 184 { 185 htole32(IWM_SF_MCAST_AGING_TIMER), 186 htole32(IWM_SF_MCAST_IDLE_TIMER) 187 }, 188 { 189 htole32(IWM_SF_BA_AGING_TIMER), 190 htole32(IWM_SF_BA_IDLE_TIMER) 191 }, 192 { 193 htole32(IWM_SF_TX_RE_AGING_TIMER), 194 htole32(IWM_SF_TX_RE_IDLE_TIMER) 195 }, 196 }; 197 198 static void 199 iwm_fill_sf_command(struct iwm_softc *sc, struct iwm_sf_cfg_cmd *sf_cmd, 200 struct ieee80211_node *ni) 201 { 202 int i, j, watermark; 203 204 sf_cmd->watermark[IWM_SF_LONG_DELAY_ON] = htole32(IWM_SF_W_MARK_SCAN); 205 206 /* 207 * If we are in association flow - check antenna configuration 208 * capabilities of the AP station, and choose the watermark accordingly. 209 */ 210 if (ni) { 211 if (ni->ni_flags & IEEE80211_NODE_HT) { 212 watermark = IWM_SF_W_MARK_SISO; 213 } else { 214 watermark = IWM_SF_W_MARK_LEGACY; 215 } 216 /* default watermark value for unassociated mode. */ 217 } else { 218 watermark = IWM_SF_W_MARK_MIMO2; 219 } 220 sf_cmd->watermark[IWM_SF_FULL_ON] = htole32(watermark); 221 222 for (i = 0; i < IWM_SF_NUM_SCENARIO; i++) { 223 for (j = 0; j < IWM_SF_NUM_TIMEOUT_TYPES; j++) { 224 sf_cmd->long_delay_timeouts[i][j] = 225 htole32(IWM_SF_LONG_DELAY_AGING_TIMER); 226 } 227 } 228 229 if (ni) { 230 _Static_assert(sizeof(sf_full_timeout) == sizeof(uint32_t) * 231 IWM_SF_NUM_SCENARIO * IWM_SF_NUM_TIMEOUT_TYPES, 232 "sf_full_timeout has wrong size"); 233 234 memcpy(sf_cmd->full_on_timeouts, sf_full_timeout, 235 sizeof(sf_full_timeout)); 236 } else { 237 _Static_assert(sizeof(sf_full_timeout_def) == sizeof(uint32_t) * 238 IWM_SF_NUM_SCENARIO * IWM_SF_NUM_TIMEOUT_TYPES, 239 "sf_full_timeout_def has wrong size"); 240 241 memcpy(sf_cmd->full_on_timeouts, sf_full_timeout_def, 242 sizeof(sf_full_timeout_def)); 243 } 244 } 245 246 static int 247 iwm_sf_config(struct iwm_softc *sc, struct ieee80211_node *ni, 248 enum iwm_sf_state new_state) 249 { 250 struct iwm_sf_cfg_cmd sf_cmd = { 251 .state = htole32(new_state), 252 }; 253 int ret = 0; 254 255 #ifdef notyet /* only relevant for sdio variants */ 256 if (sc->cfg->disable_dummy_notification) 257 sf_cmd.state |= htole32(IWM_SF_CFG_DUMMY_NOTIF_OFF); 258 #endif 259 260 /* 261 * If an associated AP sta changed its antenna configuration, the state 262 * will remain FULL_ON but SF parameters need to be reconsidered. 263 */ 264 if (new_state != IWM_SF_FULL_ON && sc->sf_state == new_state) 265 return 0; 266 267 switch (new_state) { 268 case IWM_SF_UNINIT: 269 iwm_fill_sf_command(sc, &sf_cmd, NULL); 270 break; 271 case IWM_SF_FULL_ON: 272 iwm_fill_sf_command(sc, &sf_cmd, ni); 273 break; 274 case IWM_SF_INIT_OFF: 275 iwm_fill_sf_command(sc, &sf_cmd, NULL); 276 break; 277 default: 278 device_printf(sc->sc_dev, 279 "Invalid state: %d. not sending Smart Fifo cmd\n", 280 new_state); 281 return EINVAL; 282 } 283 284 ret = iwm_send_cmd_pdu(sc, IWM_REPLY_SF_CFG_CMD, IWM_CMD_ASYNC, 285 sizeof(sf_cmd), &sf_cmd); 286 if (!ret) 287 sc->sf_state = new_state; 288 289 return ret; 290 } 291 292 /* 293 * Update Smart fifo: 294 * Count bound interfaces that are not to be removed, ignoring p2p devices, 295 * and set new state accordingly. 296 */ 297 int 298 iwm_sf_update(struct iwm_softc *sc, struct ieee80211vap *changed_vif, 299 boolean_t remove_vif) 300 { 301 enum iwm_sf_state new_state; 302 struct ieee80211_node *ni = NULL; 303 int num_active_macs = 0; 304 305 /* If changed_vif exists and is not to be removed, add to the count */ 306 if (changed_vif && !remove_vif) 307 num_active_macs++; 308 309 switch (num_active_macs) { 310 case 0: 311 /* If there are no active macs - change state to SF_INIT_OFF */ 312 new_state = IWM_SF_INIT_OFF; 313 break; 314 case 1: 315 if (!changed_vif) 316 return EINVAL; 317 ni = changed_vif->iv_bss; 318 if (ni != NULL && IWM_NODE(ni)->in_assoc && 319 changed_vif->iv_dtim_period) { 320 new_state = IWM_SF_FULL_ON; 321 } else { 322 new_state = IWM_SF_INIT_OFF; 323 } 324 break; 325 default: 326 /* If there are multiple active macs - change to SF_UNINIT */ 327 new_state = IWM_SF_UNINIT; 328 } 329 return iwm_sf_config(sc, ni, new_state); 330 } 331