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