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) \
_______________________________________________
svn-src-all@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to