Skip site navigation (1)Skip section navigation (2)
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>