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