Skip site navigation (1)Skip section navigation (2)
Date:      Sat, 25 Mar 2017 02:49:20 +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: r315925 - head/sys/dev/iwm
Message-ID:  <201703250249.v2P2nKJW038546@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: adrian
Date: Sat Mar 25 02:49:20 2017
New Revision: 315925
URL: https://svnweb.freebsd.org/changeset/base/315925

Log:
  [iwm] Enable Energy Based Scan (EBS).
  
  This can significantly reduce scan duration thus saving time and power.
  EBS failure reported by FW disables EBS for current connection. It is
  re-enabled upon new connection attempt on any WLAN interface.
  
  Obtained from:	dragonflybsd.git 89f579e9823a5c446ca172cf82bbc210d6a054a4

Modified:
  head/sys/dev/iwm/if_iwm.c
  head/sys/dev/iwm/if_iwm_scan.c
  head/sys/dev/iwm/if_iwm_scan.h
  head/sys/dev/iwm/if_iwmreg.h
  head/sys/dev/iwm/if_iwmvar.h

Modified: head/sys/dev/iwm/if_iwm.c
==============================================================================
--- head/sys/dev/iwm/if_iwm.c	Sat Mar 25 02:44:25 2017	(r315924)
+++ head/sys/dev/iwm/if_iwm.c	Sat Mar 25 02:49:20 2017	(r315925)
@@ -4518,6 +4518,11 @@ iwm_newstate(struct ieee80211vap *vap, e
 		break;
 
 	case IEEE80211_S_ASSOC:
+		/*
+		 * EBS may be disabled due to previous failures reported by FW.
+		 * Reset EBS status here assuming environment has been changed.
+		 */
+                sc->last_ebs_successful = TRUE;
 		if ((error = iwm_assoc(vap, sc)) != 0) {
 			device_printf(sc->sc_dev,
 			    "%s: failed to associate: %d\n", __func__,
@@ -5525,36 +5530,27 @@ iwm_notif_intr(struct iwm_softc *sc)
 		case IWM_INIT_COMPLETE_NOTIF:
 			break;
 
-		case IWM_SCAN_OFFLOAD_COMPLETE: {
-			struct iwm_periodic_scan_complete *notif;
-			notif = (void *)pkt->data;
+		case IWM_SCAN_OFFLOAD_COMPLETE:
+			iwm_mvm_rx_lmac_scan_complete_notif(sc, pkt);
 			if (sc->sc_flags & IWM_FLAG_SCAN_RUNNING) {
 				sc->sc_flags &= ~IWM_FLAG_SCAN_RUNNING;
 				ieee80211_runtask(ic, &sc->sc_es_task);
 			}
 			break;
-		}
 
 		case IWM_SCAN_ITERATION_COMPLETE: {
 			struct iwm_lmac_scan_complete_notif *notif;
 			notif = (void *)pkt->data;
-			ieee80211_runtask(&sc->sc_ic, &sc->sc_es_task);
- 			break;
+			break;
 		}
- 
-		case IWM_SCAN_COMPLETE_UMAC: {
-			struct iwm_umac_scan_complete *notif;
-			notif = (void *)pkt->data;
 
-			IWM_DPRINTF(sc, IWM_DEBUG_SCAN,
-			    "UMAC scan complete, status=0x%x\n",
-			    notif->status);
+		case IWM_SCAN_COMPLETE_UMAC:
+			iwm_mvm_rx_umac_scan_complete_notif(sc, pkt);
 			if (sc->sc_flags & IWM_FLAG_SCAN_RUNNING) {
 				sc->sc_flags &= ~IWM_FLAG_SCAN_RUNNING;
 				ieee80211_runtask(ic, &sc->sc_es_task);
 			}
 			break;
-		}
 
 		case IWM_SCAN_ITERATION_COMPLETE_UMAC: {
 			struct iwm_umac_scan_iter_complete_notif *notif;
@@ -5563,7 +5559,6 @@ iwm_notif_intr(struct iwm_softc *sc)
 			IWM_DPRINTF(sc, IWM_DEBUG_SCAN, "UMAC scan iteration "
 			    "complete, status=0x%x, %d channels scanned\n",
 			    notif->status, notif->scanned_channels);
-			ieee80211_runtask(&sc->sc_ic, &sc->sc_es_task);
 			break;
 		}
 
@@ -5967,6 +5962,9 @@ iwm_attach(device_t dev)
 		goto fail;
 	}
 
+	/* Set EBS as successful as long as not stated otherwise by the FW. */
+	sc->last_ebs_successful = TRUE;
+
 	/* PCI attach */
 	error = iwm_pci_attach(dev);
 	if (error != 0)

Modified: head/sys/dev/iwm/if_iwm_scan.c
==============================================================================
--- head/sys/dev/iwm/if_iwm_scan.c	Sat Mar 25 02:44:25 2017	(r315924)
+++ head/sys/dev/iwm/if_iwm_scan.c	Sat Mar 25 02:49:20 2017	(r315925)
@@ -161,6 +161,9 @@ __FBSDID("$FreeBSD$");
  * BEGIN mvm/scan.c
  */
 
+#define IWM_DENSE_EBS_SCAN_RATIO 5
+#define IWM_SPARSE_EBS_SCAN_RATIO 1
+
 static uint16_t
 iwm_mvm_scan_rx_chain(struct iwm_softc *sc)
 {
@@ -198,6 +201,67 @@ iwm_mvm_scan_rate_n_flags(struct iwm_sof
 		return htole32(IWM_RATE_6M_PLCP | tx_ant);
 }
 
+static const char *
+iwm_mvm_ebs_status_str(enum iwm_scan_ebs_status status)
+{
+	switch (status) {
+	case IWM_SCAN_EBS_SUCCESS:
+		return "successful";
+	case IWM_SCAN_EBS_INACTIVE:
+		return "inactive";
+	case IWM_SCAN_EBS_FAILED:
+	case IWM_SCAN_EBS_CHAN_NOT_FOUND:
+	default:
+		return "failed";
+	}
+}
+
+void
+iwm_mvm_rx_lmac_scan_complete_notif(struct iwm_softc *sc,
+    struct iwm_rx_packet *pkt)
+{
+	struct iwm_periodic_scan_complete *scan_notif = (void *)pkt->data;
+	boolean_t aborted = (scan_notif->status == IWM_SCAN_OFFLOAD_ABORTED);
+
+	/* If this happens, the firmware has mistakenly sent an LMAC
+	 * notification during UMAC scans -- warn and ignore it.
+	 */
+	if (fw_has_capa(&sc->ucode_capa, IWM_UCODE_TLV_CAPA_UMAC_SCAN)) {
+		device_printf(sc->sc_dev,
+		    "%s: Mistakenly got LMAC notification during UMAC scan\n",
+		    __func__);
+		return;
+	}
+
+	IWM_DPRINTF(sc, IWM_DEBUG_SCAN, "Regular scan %s, EBS status %s (FW)\n",
+	    aborted ? "aborted" : "completed",
+	    iwm_mvm_ebs_status_str(scan_notif->ebs_status));
+
+	sc->last_ebs_successful =
+			scan_notif->ebs_status == IWM_SCAN_EBS_SUCCESS ||
+			scan_notif->ebs_status == IWM_SCAN_EBS_INACTIVE;
+
+}
+
+void
+iwm_mvm_rx_umac_scan_complete_notif(struct iwm_softc *sc,
+    struct iwm_rx_packet *pkt)
+{
+	struct iwm_umac_scan_complete *notif = (void *)pkt->data;
+	uint32_t uid = le32toh(notif->uid);
+	boolean_t aborted = (notif->status == IWM_SCAN_OFFLOAD_ABORTED);
+
+	IWM_DPRINTF(sc, IWM_DEBUG_SCAN,
+	    "Scan completed, uid %u, status %s, EBS status %s\n",
+	    uid,
+	    aborted ? "aborted" : "completed",
+	    iwm_mvm_ebs_status_str(notif->ebs_status));
+
+	if (notif->ebs_status != IWM_SCAN_EBS_SUCCESS &&
+	    notif->ebs_status != IWM_SCAN_EBS_INACTIVE)
+		sc->last_ebs_successful = FALSE;
+}
+
 static int
 iwm_mvm_scan_skip_channel(struct ieee80211_channel *c)
 {
@@ -480,6 +544,21 @@ iwm_mvm_config_umac_scan(struct iwm_soft
 	return ret;
 }
 
+static boolean_t
+iwm_mvm_scan_use_ebs(struct iwm_softc *sc)
+{
+	const struct iwm_ucode_capabilities *capa = &sc->ucode_capa;
+
+	/* We can only use EBS if:
+	 *	1. the feature is supported;
+	 *	2. the last EBS was successful;
+	 *	3. if only single scan, the single scan EBS API is supported;
+	 *	4. it's not a p2p find operation.
+	 */
+	return ((capa->flags & IWM_UCODE_TLV_FLAGS_EBS_SUPPORT) &&
+		sc->last_ebs_successful);
+}
+
 int
 iwm_mvm_umac_scan(struct iwm_softc *sc)
 {
@@ -549,6 +628,11 @@ iwm_mvm_umac_scan(struct iwm_softc *sc)
 	} else
 		req->general_flags |= htole32(IWM_UMAC_SCAN_GEN_FLAGS_PASSIVE);
 
+	if (iwm_mvm_scan_use_ebs(sc))
+		req->channel_flags = IWM_SCAN_CHANNEL_FLAG_EBS |
+				     IWM_SCAN_CHANNEL_FLAG_EBS_ACCURATE |
+				     IWM_SCAN_CHANNEL_FLAG_CACHE_ADD;
+
 	if (fw_has_capa(&sc->ucode_capa,
 	    IWM_UCODE_TLV_CAPA_DS_PARAM_SET_IE_SUPPORT))
 		req->general_flags |=
@@ -674,9 +758,20 @@ iwm_mvm_lmac_scan(struct iwm_softc *sc)
 	req->schedule[0].iterations = 1;
 	req->schedule[0].full_scan_mul = 1;
 
-	/* Disable EBS. */
-	req->channel_opt[0].non_ebs_ratio = 1;
-	req->channel_opt[1].non_ebs_ratio = 1;
+	if (iwm_mvm_scan_use_ebs(sc)) {
+		req->channel_opt[0].flags =
+			htole16(IWM_SCAN_CHANNEL_FLAG_EBS |
+				IWM_SCAN_CHANNEL_FLAG_EBS_ACCURATE |
+				IWM_SCAN_CHANNEL_FLAG_CACHE_ADD);
+		req->channel_opt[0].non_ebs_ratio =
+			htole16(IWM_DENSE_EBS_SCAN_RATIO);
+		req->channel_opt[1].flags =
+			htole16(IWM_SCAN_CHANNEL_FLAG_EBS |
+				IWM_SCAN_CHANNEL_FLAG_EBS_ACCURATE |
+				IWM_SCAN_CHANNEL_FLAG_CACHE_ADD);
+		req->channel_opt[1].non_ebs_ratio =
+			htole16(IWM_SPARSE_EBS_SCAN_RATIO);
+	}
 
 	ret = iwm_send_cmd(sc, &hcmd);
 	if (!ret) {

Modified: head/sys/dev/iwm/if_iwm_scan.h
==============================================================================
--- head/sys/dev/iwm/if_iwm_scan.h	Sat Mar 25 02:44:25 2017	(r315924)
+++ head/sys/dev/iwm/if_iwm_scan.h	Sat Mar 25 02:49:20 2017	(r315925)
@@ -106,9 +106,13 @@
 #ifndef	__IF_IWN_SCAN_H__
 #define	__IF_IWN_SCAN_H__
 
-extern	int iwm_mvm_lmac_scan(struct iwm_softc *sc);
+extern	int iwm_mvm_lmac_scan(struct iwm_softc *);
 extern	int iwm_mvm_config_umac_scan(struct iwm_softc *);
 extern	int iwm_mvm_umac_scan(struct iwm_softc *);
-extern	int iwm_mvm_scan_stop_wait(struct iwm_softc *sc);
+extern	int iwm_mvm_scan_stop_wait(struct iwm_softc *);
+extern	void iwm_mvm_rx_lmac_scan_complete_notif(struct iwm_softc *,
+						 struct iwm_rx_packet *);
+extern	void iwm_mvm_rx_umac_scan_complete_notif(struct iwm_softc *,
+						 struct iwm_rx_packet *);
 
 #endif	/* __IF_IWN_SCAN_H__ */

Modified: head/sys/dev/iwm/if_iwmreg.h
==============================================================================
--- head/sys/dev/iwm/if_iwmreg.h	Sat Mar 25 02:44:25 2017	(r315924)
+++ head/sys/dev/iwm/if_iwmreg.h	Sat Mar 25 02:49:20 2017	(r315925)
@@ -5076,6 +5076,13 @@ enum iwm_scan_offload_complete_status {
 	IWM_SCAN_OFFLOAD_ABORTED	= 2,
 };
 
+enum iwm_scan_ebs_status {
+	IWM_SCAN_EBS_SUCCESS,
+	IWM_SCAN_EBS_FAILED,
+	IWM_SCAN_EBS_CHAN_NOT_FOUND,
+	IWM_SCAN_EBS_INACTIVE,
+};
+
 /**
  * struct iwm_lmac_scan_complete_notif - notifies end of scanning (all channels)
  *	SCAN_COMPLETE_NTF_API_S_VER_3

Modified: head/sys/dev/iwm/if_iwmvar.h
==============================================================================
--- head/sys/dev/iwm/if_iwmvar.h	Sat Mar 25 02:44:25 2017	(r315924)
+++ head/sys/dev/iwm/if_iwmvar.h	Sat Mar 25 02:49:20 2017	(r315925)
@@ -536,6 +536,8 @@ struct iwm_softc {
 	struct iwm_fw_paging	fw_paging_db[IWM_NUM_OF_FW_PAGING_BLOCKS];
 	uint16_t		num_of_paging_blk;
 	uint16_t		num_of_pages_in_last_blk;
+
+	boolean_t		last_ebs_successful;
 };
 
 #define IWM_LOCK_INIT(_sc) \



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201703250249.v2P2nKJW038546>