Date: Fri, 12 May 2017 06:03:23 +0000 (UTC) From: Adrian Chadd <adrian@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r318222 - in head/sys: conf dev/iwm modules/iwm Message-ID: <201705120603.v4C63Nc3061120@repo.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: adrian Date: Fri May 12 06:03:23 2017 New Revision: 318222 URL: https://svnweb.freebsd.org/changeset/base/318222 Log: [iwm] Factor out firmware station handling into if_iwm_sta.c. * This adds iwm_mvm_rm_sta(), which will be used to tear down firmware state for better/cleaner iwm_newstate() handling. * Makes iwm_enable_txq() and iwm_mvm_flush_tx_path() non-static, add the declarations to if_iwm_util.h for now. Obtained from: dragonflybsd.git 85d1c6190c4c3564b1a347f253e823aa95c202b2 Added: head/sys/dev/iwm/if_iwm_sta.c (contents, props changed) head/sys/dev/iwm/if_iwm_sta.h (contents, props changed) Modified: head/sys/conf/files head/sys/dev/iwm/if_iwm.c head/sys/dev/iwm/if_iwm_util.h head/sys/modules/iwm/Makefile Modified: head/sys/conf/files ============================================================================== --- head/sys/conf/files Fri May 12 05:53:28 2017 (r318221) +++ head/sys/conf/files Fri May 12 06:03:23 2017 (r318222) @@ -1855,6 +1855,7 @@ dev/iwm/if_iwm_phy_ctxt.c optional iwm dev/iwm/if_iwm_phy_db.c optional iwm dev/iwm/if_iwm_power.c optional iwm dev/iwm/if_iwm_scan.c optional iwm +dev/iwm/if_iwm_sta.c optional iwm dev/iwm/if_iwm_time_event.c optional iwm dev/iwm/if_iwm_util.c optional iwm iwm3160fw.c optional iwm3160fw | iwmfw \ Modified: head/sys/dev/iwm/if_iwm.c ============================================================================== --- head/sys/dev/iwm/if_iwm.c Fri May 12 05:53:28 2017 (r318221) +++ head/sys/dev/iwm/if_iwm.c Fri May 12 06:03:23 2017 (r318222) @@ -164,6 +164,7 @@ __FBSDID("$FreeBSD$"); #include <dev/iwm/if_iwm_time_event.h> #include <dev/iwm/if_iwm_power.h> #include <dev/iwm/if_iwm_scan.h> +#include <dev/iwm/if_iwm_sta.h> #include <dev/iwm/if_iwm_pcie_trans.h> #include <dev/iwm/if_iwm_led.h> @@ -265,7 +266,6 @@ static void iwm_mvm_nic_config(struct iw static int iwm_nic_rx_init(struct iwm_softc *); static int iwm_nic_tx_init(struct iwm_softc *); static int iwm_nic_init(struct iwm_softc *); -static int iwm_enable_txq(struct iwm_softc *, int, int, int); static int iwm_trans_pcie_fw_alive(struct iwm_softc *, uint32_t); static int iwm_nvm_read_chunk(struct iwm_softc *, uint16_t, uint16_t, uint16_t, uint8_t *, uint16_t *); @@ -344,19 +344,6 @@ static int iwm_tx(struct iwm_softc *, st struct ieee80211_node *, int); static int iwm_raw_xmit(struct ieee80211_node *, struct mbuf *, const struct ieee80211_bpf_params *); -static int iwm_mvm_flush_tx_path(struct iwm_softc *sc, - uint32_t tfd_msk, uint32_t flags); -static int iwm_mvm_send_add_sta_cmd_status(struct iwm_softc *, - struct iwm_mvm_add_sta_cmd *, - int *); -static int iwm_mvm_sta_send_to_fw(struct iwm_softc *, struct iwm_node *, - int); -static int iwm_mvm_add_sta(struct iwm_softc *, struct iwm_node *); -static int iwm_mvm_update_sta(struct iwm_softc *, struct iwm_node *); -static int iwm_mvm_add_int_sta_common(struct iwm_softc *, - struct iwm_int_sta *, - const uint8_t *, uint16_t, uint16_t); -static int iwm_mvm_add_aux_sta(struct iwm_softc *); static int iwm_mvm_update_quotas(struct iwm_softc *, struct iwm_vap *); static int iwm_auth(struct ieee80211vap *, struct iwm_softc *); static int iwm_release(struct iwm_softc *, struct iwm_node *); @@ -1532,7 +1519,7 @@ iwm_nic_init(struct iwm_softc *sc) return 0; } -static int +int iwm_enable_txq(struct iwm_softc *sc, int sta_id, int qid, int fifo) { if (!iwm_nic_lock(sc)) { @@ -3884,137 +3871,6 @@ iwm_mvm_flush_tx_path(struct iwm_softc * } /* - * BEGIN mvm/sta.c - */ - -static int -iwm_mvm_send_add_sta_cmd_status(struct iwm_softc *sc, - struct iwm_mvm_add_sta_cmd *cmd, int *status) -{ - return iwm_mvm_send_cmd_pdu_status(sc, IWM_ADD_STA, sizeof(*cmd), - cmd, status); -} - -/* send station add/update command to firmware */ -static int -iwm_mvm_sta_send_to_fw(struct iwm_softc *sc, struct iwm_node *in, int update) -{ - struct iwm_vap *ivp = IWM_VAP(in->in_ni.ni_vap); - struct iwm_mvm_add_sta_cmd add_sta_cmd; - int ret; - uint32_t status; - - memset(&add_sta_cmd, 0, sizeof(add_sta_cmd)); - - add_sta_cmd.sta_id = IWM_STATION_ID; - add_sta_cmd.mac_id_n_color - = htole32(IWM_FW_CMD_ID_AND_COLOR(ivp->id, ivp->color)); - if (!update) { - int ac; - for (ac = 0; ac < WME_NUM_AC; ac++) { - add_sta_cmd.tfd_queue_msk |= - htole32(1 << iwm_mvm_ac_to_tx_fifo[ac]); - } - IEEE80211_ADDR_COPY(&add_sta_cmd.addr, in->in_ni.ni_bssid); - } - add_sta_cmd.add_modify = update ? 1 : 0; - add_sta_cmd.station_flags_msk - |= htole32(IWM_STA_FLG_FAT_EN_MSK | IWM_STA_FLG_MIMO_EN_MSK); - add_sta_cmd.tid_disable_tx = htole16(0xffff); - if (update) - add_sta_cmd.modify_mask |= (IWM_STA_MODIFY_TID_DISABLE_TX); - - status = IWM_ADD_STA_SUCCESS; - ret = iwm_mvm_send_add_sta_cmd_status(sc, &add_sta_cmd, &status); - if (ret) - return ret; - - switch (status & IWM_ADD_STA_STATUS_MASK) { - case IWM_ADD_STA_SUCCESS: - break; - default: - ret = EIO; - device_printf(sc->sc_dev, "IWM_ADD_STA failed\n"); - break; - } - - return ret; -} - -static int -iwm_mvm_add_sta(struct iwm_softc *sc, struct iwm_node *in) -{ - return iwm_mvm_sta_send_to_fw(sc, in, 0); -} - -static int -iwm_mvm_update_sta(struct iwm_softc *sc, struct iwm_node *in) -{ - return iwm_mvm_sta_send_to_fw(sc, in, 1); -} - -static int -iwm_mvm_add_int_sta_common(struct iwm_softc *sc, struct iwm_int_sta *sta, - const uint8_t *addr, uint16_t mac_id, uint16_t color) -{ - struct iwm_mvm_add_sta_cmd cmd; - int ret; - uint32_t status; - - memset(&cmd, 0, sizeof(cmd)); - cmd.sta_id = sta->sta_id; - cmd.mac_id_n_color = htole32(IWM_FW_CMD_ID_AND_COLOR(mac_id, color)); - - cmd.tfd_queue_msk = htole32(sta->tfd_queue_msk); - cmd.tid_disable_tx = htole16(0xffff); - - if (addr) - IEEE80211_ADDR_COPY(cmd.addr, addr); - - ret = iwm_mvm_send_add_sta_cmd_status(sc, &cmd, &status); - if (ret) - return ret; - - switch (status & IWM_ADD_STA_STATUS_MASK) { - case IWM_ADD_STA_SUCCESS: - IWM_DPRINTF(sc, IWM_DEBUG_RESET, - "%s: Internal station added.\n", __func__); - return 0; - default: - device_printf(sc->sc_dev, - "%s: Add internal station failed, status=0x%x\n", - __func__, status); - ret = EIO; - break; - } - return ret; -} - -static int -iwm_mvm_add_aux_sta(struct iwm_softc *sc) -{ - int ret; - - sc->sc_aux_sta.sta_id = IWM_AUX_STA_ID; - sc->sc_aux_sta.tfd_queue_msk = (1 << IWM_MVM_AUX_QUEUE); - - ret = iwm_enable_txq(sc, 0, IWM_MVM_AUX_QUEUE, IWM_MVM_TX_FIFO_MCAST); - if (ret) - return ret; - - ret = iwm_mvm_add_int_sta_common(sc, - &sc->sc_aux_sta, NULL, IWM_MAC_INDEX_AUX, 0); - - if (ret) - memset(&sc->sc_aux_sta, 0, sizeof(sc->sc_aux_sta)); - return ret; -} - -/* - * END mvm/sta.c - */ - -/* * BEGIN mvm/quota.c */ Added: head/sys/dev/iwm/if_iwm_sta.c ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ head/sys/dev/iwm/if_iwm_sta.c Fri May 12 06:03:23 2017 (r318222) @@ -0,0 +1,378 @@ +/*- + * Based on BSD-licensed source modules in the Linux iwlwifi driver, + * which were used as the reference documentation for this implementation. + * + * Driver version we are currently based off of is + * Linux 4.7.3 (tag id d7f6728f57e3ecbb7ef34eb7d9f564d514775d75) + * + *********************************************************************** + * + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * Copyright(c) 2012 - 2015 Intel Corporation. All rights reserved. + * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH + * Copyright(c) 2016 Intel Deutschland GmbH + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, + * USA + * + * The full GNU General Public License is included in this distribution + * in the file called COPYING. + * + * Contact Information: + * Intel Linux Wireless <linuxwifi@intel.com> + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + * + * BSD LICENSE + * + * Copyright(c) 2012 - 2015 Intel Corporation. All rights reserved. + * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH + * Copyright(c) 2016 Intel Deutschland GmbH + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + *****************************************************************************/ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include "opt_wlan.h" +#include "opt_iwm.h" + +#include <sys/param.h> +#include <sys/bus.h> +#include <sys/conf.h> +#include <sys/endian.h> +#include <sys/firmware.h> +#include <sys/kernel.h> +#include <sys/malloc.h> +#include <sys/mbuf.h> +#include <sys/mutex.h> +#include <sys/module.h> +#include <sys/proc.h> +#include <sys/rman.h> +#include <sys/socket.h> +#include <sys/sockio.h> +#include <sys/sysctl.h> +#include <sys/linker.h> + +#include <machine/bus.h> +#include <machine/endian.h> +#include <machine/resource.h> + +#include <dev/pci/pcivar.h> +#include <dev/pci/pcireg.h> + +#include <net/bpf.h> + +#include <net/if.h> +#include <net/if_var.h> +#include <net/if_arp.h> +#include <net/if_dl.h> +#include <net/if_media.h> +#include <net/if_types.h> + +#include <netinet/in.h> +#include <netinet/in_systm.h> +#include <netinet/if_ether.h> +#include <netinet/ip.h> + +#include <net80211/ieee80211_var.h> +#include <net80211/ieee80211_regdomain.h> +#include <net80211/ieee80211_ratectl.h> +#include <net80211/ieee80211_radiotap.h> + +#include <dev/iwm/if_iwmreg.h> +#include <dev/iwm/if_iwmvar.h> +#include <dev/iwm/if_iwm_config.h> +#include <dev/iwm/if_iwm_debug.h> +#include <dev/iwm/if_iwm_constants.h> +#include <dev/iwm/if_iwm_util.h> +#include <dev/iwm/if_iwm_mac_ctxt.h> +#include <dev/iwm/if_iwm_sta.h> + +/* + * New version of ADD_STA_sta command added new fields at the end of the + * structure, so sending the size of the relevant API's structure is enough to + * support both API versions. + */ +static inline int +iwm_mvm_add_sta_cmd_size(struct iwm_softc *sc) +{ +#ifdef notyet + return iwm_mvm_has_new_rx_api(mvm) ? + sizeof(struct iwm_mvm_add_sta_cmd) : + sizeof(struct iwm_mvm_add_sta_cmd_v7); +#else + return sizeof(struct iwm_mvm_add_sta_cmd); +#endif +} + +/* send station add/update command to firmware */ +int +iwm_mvm_sta_send_to_fw(struct iwm_softc *sc, struct iwm_node *in, + boolean_t update) +{ + struct iwm_vap *ivp = IWM_VAP(in->in_ni.ni_vap); + struct iwm_mvm_add_sta_cmd add_sta_cmd = { + .sta_id = IWM_STATION_ID, + .mac_id_n_color = + htole32(IWM_FW_CMD_ID_AND_COLOR(ivp->id, ivp->color)), + .add_modify = update ? 1 : 0, + .station_flags_msk = htole32(IWM_STA_FLG_FAT_EN_MSK | + IWM_STA_FLG_MIMO_EN_MSK), + .tid_disable_tx = htole16(0xffff), + }; + int ret; + uint32_t status; + uint32_t agg_size = 0, mpdu_dens = 0; + + if (!update) { + int ac; + for (ac = 0; ac < WME_NUM_AC; ac++) { + add_sta_cmd.tfd_queue_msk |= + htole32(1 << iwm_mvm_ac_to_tx_fifo[ac]); + } + IEEE80211_ADDR_COPY(&add_sta_cmd.addr, in->in_ni.ni_bssid); + } + + add_sta_cmd.station_flags |= + htole32(agg_size << IWM_STA_FLG_MAX_AGG_SIZE_SHIFT); + add_sta_cmd.station_flags |= + htole32(mpdu_dens << IWM_STA_FLG_AGG_MPDU_DENS_SHIFT); + + status = IWM_ADD_STA_SUCCESS; + ret = iwm_mvm_send_cmd_pdu_status(sc, IWM_ADD_STA, + iwm_mvm_add_sta_cmd_size(sc), + &add_sta_cmd, &status); + if (ret) + return ret; + + switch (status & IWM_ADD_STA_STATUS_MASK) { + case IWM_ADD_STA_SUCCESS: + IWM_DPRINTF(sc, IWM_DEBUG_NODE, "IWM_ADD_STA PASSED\n"); + break; + default: + ret = EIO; + device_printf(sc->sc_dev, "IWM_ADD_STA failed\n"); + break; + } + + return ret; +} + +int +iwm_mvm_add_sta(struct iwm_softc *sc, struct iwm_node *in) +{ + return iwm_mvm_sta_send_to_fw(sc, in, FALSE); +} + +int +iwm_mvm_update_sta(struct iwm_softc *sc, struct iwm_node *in) +{ + return iwm_mvm_sta_send_to_fw(sc, in, TRUE); +} + +int +iwm_mvm_drain_sta(struct iwm_softc *sc, struct iwm_node *in, boolean_t drain) +{ + struct iwm_mvm_add_sta_cmd cmd = {}; + struct iwm_vap *ivp = IWM_VAP(in->in_ni.ni_vap); + int ret; + uint32_t status; + + cmd.mac_id_n_color = + htole32(IWM_FW_CMD_ID_AND_COLOR(ivp->id, ivp->color)); + cmd.sta_id = IWM_STATION_ID; + cmd.add_modify = IWM_STA_MODE_MODIFY; + cmd.station_flags = drain ? htole32(IWM_STA_FLG_DRAIN_FLOW) : 0; + cmd.station_flags_msk = htole32(IWM_STA_FLG_DRAIN_FLOW); + + status = IWM_ADD_STA_SUCCESS; + ret = iwm_mvm_send_cmd_pdu_status(sc, IWM_ADD_STA, + iwm_mvm_add_sta_cmd_size(sc), + &cmd, &status); + if (ret) + return ret; + + switch (status & IWM_ADD_STA_STATUS_MASK) { + case IWM_ADD_STA_SUCCESS: + IWM_DPRINTF(sc, IWM_DEBUG_NODE, + "Frames for staid %d will drained in fw\n", IWM_STATION_ID); + break; + default: + ret = EIO; + device_printf(sc->sc_dev, + "Couldn't drain frames for staid %d\n", IWM_STATION_ID); + break; + } + + return ret; +} + +/* + * Remove a station from the FW table. Before sending the command to remove + * the station validate that the station is indeed known to the driver (sanity + * only). + */ +static int +iwm_mvm_rm_sta_common(struct iwm_softc *sc) +{ + struct iwm_mvm_rm_sta_cmd rm_sta_cmd = { + .sta_id = IWM_STATION_ID, + }; + int ret; + + ret = iwm_mvm_send_cmd_pdu(sc, IWM_REMOVE_STA, 0, + sizeof(rm_sta_cmd), &rm_sta_cmd); + if (ret) { + device_printf(sc->sc_dev, + "Failed to remove station. Id=%d\n", IWM_STATION_ID); + return ret; + } + + return 0; +} + +int +iwm_mvm_rm_sta(struct iwm_softc *sc, struct ieee80211vap *vap, + struct iwm_node *in) +{ + uint32_t tfd_queue_msk = 0; + int ret; + int ac; + + ret = iwm_mvm_drain_sta(sc, in, TRUE); + if (ret) + return ret; + mbufq_drain(&sc->sc_snd); /* XXX needed ? */ + for (ac = 0; ac < WME_NUM_AC; ac++) { + tfd_queue_msk |= htole32(1 << iwm_mvm_ac_to_tx_fifo[ac]); + } + ret = iwm_mvm_flush_tx_path(sc, tfd_queue_msk, 0); + if (ret) + return ret; +#ifdef notyet /* function not yet implemented */ + ret = iwl_trans_wait_tx_queue_empty(mvm->trans, + mvm_sta->tfd_queue_msk); + if (ret) + return ret; +#endif + ret = iwm_mvm_drain_sta(sc, in, FALSE); + +#if 0 + /* if we are associated - we can't remove the AP STA now */ + if (sta->assoc) + return ret; +#endif + /* XXX wait until STA is drained */ + + ret = iwm_mvm_rm_sta_common(sc); + + return ret; +} + +static int +iwm_mvm_add_int_sta_common(struct iwm_softc *sc, struct iwm_int_sta *sta, + const uint8_t *addr, uint16_t mac_id, uint16_t color) +{ + struct iwm_mvm_add_sta_cmd cmd; + int ret; + uint32_t status; + + memset(&cmd, 0, sizeof(cmd)); + cmd.sta_id = sta->sta_id; + cmd.mac_id_n_color = htole32(IWM_FW_CMD_ID_AND_COLOR(mac_id, color)); + + cmd.tfd_queue_msk = htole32(sta->tfd_queue_msk); + cmd.tid_disable_tx = htole16(0xffff); + + if (addr) + IEEE80211_ADDR_COPY(cmd.addr, addr); + + ret = iwm_mvm_send_cmd_pdu_status(sc, IWM_ADD_STA, + iwm_mvm_add_sta_cmd_size(sc), + &cmd, &status); + if (ret) + return ret; + + switch (status & IWM_ADD_STA_STATUS_MASK) { + case IWM_ADD_STA_SUCCESS: + IWM_DPRINTF(sc, IWM_DEBUG_NODE, "Internal station added.\n"); + return 0; + default: + ret = EIO; + device_printf(sc->sc_dev, + "Add internal station failed, status=0x%x\n", status); + break; + } + return ret; +} + +int +iwm_mvm_add_aux_sta(struct iwm_softc *sc) +{ + int ret; + + sc->sc_aux_sta.sta_id = IWM_AUX_STA_ID; + sc->sc_aux_sta.tfd_queue_msk = (1 << IWM_MVM_AUX_QUEUE); + + /* Map Aux queue to fifo - needs to happen before adding Aux station */ + ret = iwm_enable_txq(sc, 0, IWM_MVM_AUX_QUEUE, IWM_MVM_TX_FIFO_MCAST); + if (ret) + return ret; + + ret = iwm_mvm_add_int_sta_common(sc, &sc->sc_aux_sta, NULL, + IWM_MAC_INDEX_AUX, 0); + + if (ret) { + memset(&sc->sc_aux_sta, 0, sizeof(sc->sc_aux_sta)); + sc->sc_aux_sta.sta_id = IWM_MVM_STATION_COUNT; + } + return ret; +} + +void iwm_mvm_del_aux_sta(struct iwm_softc *sc) +{ + memset(&sc->sc_aux_sta, 0, sizeof(sc->sc_aux_sta)); + sc->sc_aux_sta.sta_id = IWM_MVM_STATION_COUNT; +} Added: head/sys/dev/iwm/if_iwm_sta.h ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ head/sys/dev/iwm/if_iwm_sta.h Fri May 12 06:03:23 2017 (r318222) @@ -0,0 +1,222 @@ +/*- + * Based on BSD-licensed source modules in the Linux iwlwifi driver, + * which were used as the reference documentation for this implementation. + * + * Driver version we are currently based off of is + * Linux 4.7.3 (tag id d7f6728f57e3ecbb7ef34eb7d9f564d514775d75) + * + *********************************************************************** + * + * + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH + * Copyright(c) 2015 - 2016 Intel Deutschland GmbH + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, + * USA + * + * The full GNU General Public License is included in this distribution + * in the file called COPYING. + * + * Contact Information: + * Intel Linux Wireless <linuxwifi@intel.com> + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + * + * BSD LICENSE + * + * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH + * Copyright(c) 2015 - 2016 Intel Deutschland GmbH + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + *****************************************************************************/ + +/* $FreeBSD$ */ + +#ifndef __IF_IWM_STA_H__ +#define __IF_IWM_STA_H__ + +/** + * DOC: station table - introduction + * + * The station table is a list of data structure that reprensent the stations. + * In STA/P2P client mode, the driver will hold one station for the AP/ GO. + * In GO/AP mode, the driver will have as many stations as associated clients. + * All these stations are reflected in the fw's station table. The driver + * keeps the fw's station table up to date with the ADD_STA command. Stations + * can be removed by the REMOVE_STA command. + * + * All the data related to a station is held in the structure %iwl_mvm_sta + * which is embed in the mac80211's %ieee80211_sta (in the drv_priv) area. + * This data includes the index of the station in the fw, per tid information + * (sequence numbers, Block-ack state machine, etc...). The stations are + * created and deleted by the %sta_state callback from %ieee80211_ops. + * + * The driver holds a map: %fw_id_to_mac_id that allows to fetch a + * %ieee80211_sta (and the %iwl_mvm_sta embedded into it) based on a fw + * station index. That way, the driver is able to get the tid related data in + * O(1) in time sensitive paths (Tx / Tx response / BA notification). These + * paths are triggered by the fw, and the driver needs to get a pointer to the + * %ieee80211 structure. This map helps to get that pointer quickly. + */ + +/** + * DOC: station table - locking + * + * As stated before, the station is created / deleted by mac80211's %sta_state + * callback from %ieee80211_ops which can sleep. The next paragraph explains + * the locking of a single stations, the next ones relates to the station + * table. + * + * The station holds the sequence number per tid. So this data needs to be + * accessed in the Tx path (which is softIRQ). It also holds the Block-Ack + * information (the state machine / and the logic that checks if the queues + * were drained), so it also needs to be accessible from the Tx response flow. + * In short, the station needs to be access from sleepable context as well as + * from tasklets, so the station itself needs a spinlock. + * + * The writers of %fw_id_to_mac_id map are serialized by the global mutex of + * the mvm op_mode. This is possible since %sta_state can sleep. + * The pointers in this map are RCU protected, hence we won't replace the + * station while we have Tx / Tx response / BA notification running. + * + * If a station is deleted while it still has packets in its A-MPDU queues, + * then the reclaim flow will notice that there is no station in the map for + * sta_id and it will dump the responses. + */ + +/** + * DOC: station table - internal stations + * + * The FW needs a few internal stations that are not reflected in + * mac80211, such as broadcast station in AP / GO mode, or AUX sta for + * scanning and P2P device (during the GO negotiation). + * For these kind of stations we have %iwl_mvm_int_sta struct which holds the + * data relevant for them from both %iwl_mvm_sta and %ieee80211_sta. + * Usually the data for these stations is static, so no locking is required, + * and no TID data as this is also not needed. + * One thing to note, is that these stations have an ID in the fw, but not + * in mac80211. In order to "reserve" them a sta_id in %fw_id_to_mac_id + * we fill ERR_PTR(EINVAL) in this mapping and all other dereferencing of + * pointers from this mapping need to check that the value is not error + * or NULL. + * + * Currently there is only one auxiliary station for scanning, initialized + * on init. + */ + +/** + * DOC: station table - AP Station in STA mode + * + * %iwl_mvm_vif includes the index of the AP station in the fw's STA table: + * %ap_sta_id. To get the point to the corresponding %ieee80211_sta, + * &fw_id_to_mac_id can be used. Due to the way the fw works, we must not remove + * the AP station from the fw before setting the MAC context as unassociated. + * Hence, %fw_id_to_mac_id[%ap_sta_id] will be NULLed when the AP station is + * removed by mac80211, but the station won't be removed in the fw until the + * VIF is set as unassociated. Then, %ap_sta_id will be invalidated. + */ + +/** + * DOC: station table - Drain vs. Flush + * + * Flush means that all the frames in the SCD queue are dumped regardless the + * station to which they were sent. We do that when we disassociate and before + * we remove the STA of the AP. The flush can be done synchronously against the + * fw. + * Drain means that the fw will drop all the frames sent to a specific station. + * This is useful when a client (if we are IBSS / GO or AP) disassociates. In + * that case, we need to drain all the frames for that client from the AC queues + * that are shared with the other clients. Only then, we can remove the STA in + * the fw. In order to do so, we track the non-AMPDU packets for each station. + * If mac80211 removes a STA and if it still has non-AMPDU packets pending in + * the queues, we mark this station as %EBUSY in %fw_id_to_mac_id, and drop all + * the frames for this STA (%iwl_mvm_rm_sta). When the last frame is dropped + * (we know about it with its Tx response), we remove the station in fw and set + * it as %NULL in %fw_id_to_mac_id: this is the purpose of + * %iwl_mvm_sta_drained_wk. + */ + +/** + * DOC: station table - fw restart + * + * When the fw asserts, or we have any other issue that requires to reset the + * driver, we require mac80211 to reconfigure the driver. Since the private + * data of the stations is embed in mac80211's %ieee80211_sta, that data will + * not be zeroed and needs to be reinitialized manually. + * %IWL_MVM_STATUS_IN_HW_RESTART is set during restart and that will hint us + * that we must not allocate a new sta_id but reuse the previous one. This + * means that the stations being re-added after the reset will have the same + * place in the fw as before the reset. We do need to zero the %fw_id_to_mac_id + * map, since the stations aren't in the fw any more. Internal stations that + * are not added by mac80211 will be re-added in the init flow that is called + * after the restart: mac80211 call's %iwl_mvm_mac_start which calls to + * %iwl_mvm_up. + */ + +/** + * Send the STA info to the FW. + * + * @sc: the iwm_softc* to use + * @sta: the STA + * @update: this is true if the FW is being updated about a STA it already knows + * about. Otherwise (if this is a new STA), this should be false. + * @flags: if update==true, this marks what is being changed via ORs of values + * from enum iwm_sta_modify_flag. Otherwise, this is ignored. + */ +extern int iwm_mvm_sta_send_to_fw(struct iwm_softc *sc, struct iwm_node *in, + boolean_t update); +extern int iwm_mvm_add_sta(struct iwm_softc *sc, struct iwm_node *in); +extern int iwm_mvm_update_sta(struct iwm_softc *sc, struct iwm_node *in); +extern int iwm_mvm_rm_sta(struct iwm_softc *sc, struct ieee80211vap *vap, + struct iwm_node *in); + +extern int iwm_mvm_add_aux_sta(struct iwm_softc *sc); +extern void iwm_mvm_del_aux_sta(struct iwm_softc *sc); + +extern int iwm_mvm_drain_sta(struct iwm_softc *sc, struct iwm_node *in, + boolean_t drain); + +#endif /* __IF_IWM_STA_H__ */ Modified: head/sys/dev/iwm/if_iwm_util.h ============================================================================== --- head/sys/dev/iwm/if_iwm_util.h Fri May 12 05:53:28 2017 (r318221) +++ head/sys/dev/iwm/if_iwm_util.h Fri May 12 06:03:23 2017 (r318222) @@ -123,6 +123,9 @@ extern void iwm_dma_contig_free(struct i extern boolean_t iwm_mvm_rx_diversity_allowed(struct iwm_softc *sc); extern uint8_t iwm_ridx2rate(struct ieee80211_rateset *rs, int ridx); +extern int iwm_enable_txq(struct iwm_softc *sc, int sta_id, int qid, int fifo); +extern int iwm_mvm_flush_tx_path(struct iwm_softc *sc, uint32_t tfd_msk, + uint32_t flags); static inline uint8_t iwm_mvm_get_valid_tx_ant(struct iwm_softc *sc) Modified: head/sys/modules/iwm/Makefile ============================================================================== --- head/sys/modules/iwm/Makefile Fri May 12 05:53:28 2017 (r318221) +++ head/sys/modules/iwm/Makefile Fri May 12 06:03:23 2017 (r318222) @@ -7,10 +7,10 @@ KMOD= if_iwm SRCS= if_iwm.c if_iwm_binding.c if_iwm_util.c if_iwm_phy_db.c SRCS+= if_iwm_mac_ctxt.c if_iwm_phy_ctxt.c if_iwm_time_event.c SRCS+= if_iwm_power.c if_iwm_scan.c if_iwm_led.c if_iwm_notif_wait.c -SRCS+= if_iwm_7000.c if_iwm_8000.c if_iwm_fw.c +SRCS+= if_iwm_7000.c if_iwm_8000.c if_iwm_fw.c if_iwm_sta.c # bus layer SRCS+= if_iwm_pcie_trans.c -SRCS+= device_if.h bus_if.h pci_if.h opt_wlan.h +SRCS+= device_if.h bus_if.h pci_if.h opt_wlan.h opt_iwm.h CFLAGS+= -DIWM_DEBUG
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201705120603.v4C63Nc3061120>