[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
This commit is contained in:
Adrian Chadd 2017-03-25 02:49:20 +00:00
parent 5f00681c7d
commit cd20383e4a
5 changed files with 126 additions and 20 deletions

View File

@ -4518,6 +4518,11 @@ iwm_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg)
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)

View File

@ -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_softc *sc, int flags, int no_cck)
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_softc *sc)
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) {

View File

@ -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__ */

View File

@ -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

View File

@ -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) \