iwm: Implement support for scans with "adaptive" dwell time.

This is required by 9000-series firmware.

MFC after:	2 weeks
Sponsored by:	The FreeBSD Foundation
This commit is contained in:
Mark Johnston 2019-11-07 23:39:04 +00:00
parent c513f15bf0
commit 666c8655f2
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=354515
2 changed files with 138 additions and 61 deletions

View File

@ -580,6 +580,29 @@ iwm_mvm_scan_use_ebs(struct iwm_softc *sc)
sc->last_ebs_successful);
}
static int
iwm_mvm_scan_size(struct iwm_softc *sc)
{
int base_size;
if (iwm_fw_has_capa(sc, IWM_UCODE_TLV_CAPA_UMAC_SCAN)) {
if (iwm_fw_has_api(sc, IWM_UCODE_TLV_API_ADAPTIVE_DWELL))
base_size = IWM_SCAN_REQ_UMAC_SIZE_V7;
else
base_size = IWM_SCAN_REQ_UMAC_SIZE_V1;
return base_size +
sizeof(struct iwm_scan_channel_cfg_umac) *
sc->sc_fw.ucode_capa.n_scan_channels +
sizeof(struct iwm_scan_req_umac_tail);
} else {
return sizeof(struct iwm_scan_req_lmac) +
sizeof(struct iwm_scan_channel_cfg_lmac) *
sc->sc_fw.ucode_capa.n_scan_channels +
sizeof(struct iwm_scan_probe_req);
}
}
int
iwm_mvm_umac_scan(struct iwm_softc *sc)
{
@ -593,13 +616,11 @@ iwm_mvm_umac_scan(struct iwm_softc *sc)
struct iwm_scan_req_umac *req;
struct iwm_scan_req_umac_tail *tail;
size_t req_len;
uint8_t i, nssid;
uint16_t general_flags;
uint8_t channel_flags, i, nssid;
int ret;
req_len = sizeof(struct iwm_scan_req_umac) +
(sizeof(struct iwm_scan_channel_cfg_umac) *
sc->sc_fw.ucode_capa.n_scan_channels) +
sizeof(struct iwm_scan_req_umac_tail);
req_len = iwm_mvm_scan_size(sc);
if (req_len > IWM_MAX_CMD_PAYLOAD_SIZE)
return ENOMEM;
req = malloc(req_len, M_DEVBUF, M_NOWAIT | M_ZERO);
@ -611,28 +632,58 @@ iwm_mvm_umac_scan(struct iwm_softc *sc)
IWM_DPRINTF(sc, IWM_DEBUG_SCAN, "Handling ieee80211 scan request\n");
/* These timings correspond to iwlwifi's UNASSOC scan. */
req->active_dwell = 10;
req->passive_dwell = 110;
req->fragmented_dwell = 44;
req->extended_dwell = 90;
req->max_out_time = 0;
req->suspend_time = 0;
nssid = MIN(ss->ss_nssid, IWM_PROBE_OPTION_MAX);
req->scan_priority = htole32(IWM_SCAN_PRIORITY_HIGH);
general_flags = IWM_UMAC_SCAN_GEN_FLAGS_PASS_ALL |
IWM_UMAC_SCAN_GEN_FLAGS_ITER_COMPLETE;
if (!iwm_fw_has_api(sc, IWM_UCODE_TLV_API_ADAPTIVE_DWELL))
general_flags |= IWM_UMAC_SCAN_GEN_FLAGS_EXTENDED_DWELL;
if (iwm_mvm_rrm_scan_needed(sc))
general_flags |= IWM_UMAC_SCAN_GEN_FLAGS_RRM_ENABLED;
if (nssid != 0)
general_flags |= IWM_UMAC_SCAN_GEN_FLAGS_PRE_CONNECT;
else
general_flags |= IWM_UMAC_SCAN_GEN_FLAGS_PASSIVE;
channel_flags = 0;
if (iwm_mvm_scan_use_ebs(sc))
channel_flags = IWM_SCAN_CHANNEL_FLAG_EBS |
IWM_SCAN_CHANNEL_FLAG_EBS_ACCURATE |
IWM_SCAN_CHANNEL_FLAG_CACHE_ADD;
req->general_flags = htole16(general_flags);
req->ooc_priority = htole32(IWM_SCAN_PRIORITY_HIGH);
nssid = MIN(ss->ss_nssid, IWM_PROBE_OPTION_MAX);
req->n_channels = iwm_mvm_umac_scan_fill_channels(sc,
(struct iwm_scan_channel_cfg_umac *)req->data, nssid);
/* These timings correspond to iwlwifi's UNASSOC scan. */
if (iwm_fw_has_api(sc, IWM_UCODE_TLV_API_ADAPTIVE_DWELL)) {
req->v7.active_dwell = 10;
req->v7.passive_dwell = 110;
req->v7.fragmented_dwell = 44;
req->v7.adwell_default_n_aps_social = 10;
req->v7.adwell_default_n_aps = 2;
req->v7.adwell_max_budget = htole16(300);
req->v7.scan_priority = htole32(IWM_SCAN_PRIORITY_HIGH);
req->v7.channel.flags = channel_flags;
req->v7.channel.count = iwm_mvm_umac_scan_fill_channels(sc,
(struct iwm_scan_channel_cfg_umac *)req->v7.data, nssid);
req->general_flags = htole32(IWM_UMAC_SCAN_GEN_FLAGS_PASS_ALL |
IWM_UMAC_SCAN_GEN_FLAGS_ITER_COMPLETE |
IWM_UMAC_SCAN_GEN_FLAGS_EXTENDED_DWELL);
tail = (void *)((char *)&req->v7.data +
sizeof(struct iwm_scan_channel_cfg_umac) *
sc->sc_fw.ucode_capa.n_scan_channels);
} else {
req->v1.active_dwell = 10;
req->v1.passive_dwell = 110;
req->v1.fragmented_dwell = 44;
req->v1.extended_dwell = 90;
req->v1.scan_priority = htole32(IWM_SCAN_PRIORITY_HIGH);
req->v1.channel.flags = channel_flags;
req->v1.channel.count = iwm_mvm_umac_scan_fill_channels(sc,
(struct iwm_scan_channel_cfg_umac *)req->v1.data, nssid);
tail = (void *)((char *)&req->data +
sizeof(struct iwm_scan_channel_cfg_umac) *
sc->sc_fw.ucode_capa.n_scan_channels);
tail = (void *)((char *)&req->v1.data +
sizeof(struct iwm_scan_channel_cfg_umac) *
sc->sc_fw.ucode_capa.n_scan_channels);
}
/* Check if we're doing an active directed scan. */
for (i = 0; i < nssid; i++) {
@ -643,20 +694,6 @@ iwm_mvm_umac_scan(struct iwm_softc *sc)
tail->direct_scan[i].len);
/* XXX debug */
}
if (nssid != 0) {
req->general_flags |=
htole32(IWM_UMAC_SCAN_GEN_FLAGS_PRE_CONNECT);
} 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 (iwm_mvm_rrm_scan_needed(sc))
req->general_flags |=
htole32(IWM_UMAC_SCAN_GEN_FLAGS_RRM_ENABLED);
ret = iwm_mvm_fill_probe_req(sc, &tail->preq);
if (ret) {
@ -694,9 +731,7 @@ iwm_mvm_lmac_scan(struct iwm_softc *sc)
IWM_DPRINTF(sc, IWM_DEBUG_SCAN,
"Handling ieee80211 scan request\n");
req_len = sizeof(struct iwm_scan_req_lmac) +
(sizeof(struct iwm_scan_channel_cfg_lmac) *
sc->sc_fw.ucode_capa.n_scan_channels) + sizeof(struct iwm_scan_probe_req);
req_len = iwm_mvm_scan_size(sc);
if (req_len > IWM_MAX_CMD_PAYLOAD_SIZE)
return ENOMEM;
req = malloc(req_len, M_DEVBUF, M_NOWAIT | M_ZERO);

View File

@ -5487,22 +5487,45 @@ struct iwm_scan_req_umac_tail {
struct iwm_ssid_ie direct_scan[IWM_PROBE_OPTION_MAX];
} __packed;
/**
* struct iwm_scan_uma_chan_param
* @flags: channel flags &enum iwm_scan_channel_flags
* @count: num of channels in scan request
* @reserved: for future use and alignment
*/
struct iwm_scan_umac_chan_param {
uint8_t flags;
uint8_t count;
uint16_t reserved;
} __packed;
/**
* struct iwm_scan_req_umac
* @flags: &enum iwm_umac_scan_flags
* @uid: scan id, &enum iwm_umac_scan_uid_offsets
* @ooc_priority: out of channel priority - &enum iwm_scan_priority
* @general_flags: &enum iwm_umac_scan_general_flags
* @scan_start_mac_id: report the scan start TSF time according to this mac TSF
* @extended_dwell: dwell time for channels 1, 6 and 11
* @active_dwell: dwell time for active scan
* @passive_dwell: dwell time for passive scan
* @active_dwell: dwell time for active scan per LMAC
* @passive_dwell: dwell time for passive scan per LMAC
* @fragmented_dwell: dwell time for fragmented passive scan
* @max_out_time: max out of serving channel time
* @suspend_time: max suspend time
* @scan_priority: scan internal prioritization &enum iwm_scan_priority
* @channel_flags: &enum iwm_scan_channel_flags
* @n_channels: num of channels in scan request
* @adwell_default_n_aps: for adaptive dwell the default number of APs
* per channel
* @adwell_default_n_aps_social: for adaptive dwell the default
* number of APs per social (1,6,11) channel
* @general_flags2: &enum iwl_umac_scan_general_flags2
* @adwell_max_budget: for adaptive dwell the maximal budget of TU to be added
* to total scan time
* @max_out_time: max out of serving channel time, per LMAC - for CDB there
* are 2 LMACs
* @suspend_time: max suspend time, per LMAC - for CDB there are 2 LMACs
* @scan_priority: scan internal prioritization &enum iwl_scan_priority
* @num_of_fragments: Number of fragments needed for full coverage per band.
* Relevant only for fragmented scan.
* @channel: &struct iwl_scan_umac_chan_param
* @reserved: for future use and alignment
* @reserved3: for future use and alignment
* @data: &struct iwm_scan_channel_cfg_umac and
* &struct iwm_scan_req_umac_tail
*/
@ -5510,21 +5533,40 @@ struct iwm_scan_req_umac {
uint32_t flags;
uint32_t uid;
uint32_t ooc_priority;
/* SCAN_GENERAL_PARAMS_API_S_VER_1 */
uint32_t general_flags;
uint8_t extended_dwell;
uint8_t active_dwell;
uint8_t passive_dwell;
uint8_t fragmented_dwell;
uint32_t max_out_time;
uint32_t suspend_time;
uint32_t scan_priority;
/* SCAN_CHANNEL_PARAMS_API_S_VER_1 */
uint8_t channel_flags;
uint8_t n_channels;
uint16_t reserved;
uint8_t data[];
} __packed; /* SCAN_REQUEST_CMD_UMAC_API_S_VER_1 */
uint16_t general_flags;
uint8_t reserved;
uint8_t scan_start_mac_id;
union {
struct {
uint8_t extended_dwell;
uint8_t active_dwell;
uint8_t passive_dwell;
uint8_t fragmented_dwell;
uint32_t max_out_time;
uint32_t suspend_time;
uint32_t scan_priority;
struct iwm_scan_umac_chan_param channel;
uint8_t data[];
} v1;
struct {
uint8_t active_dwell;
uint8_t passive_dwell;
uint8_t fragmented_dwell;
uint8_t adwell_default_n_aps;
uint8_t adwell_default_n_aps_social;
uint8_t reserved3;
uint16_t adwell_max_budget;
uint32_t max_out_time[2];
uint32_t suspend_time[2];
uint32_t scan_priority;
struct iwm_scan_umac_chan_param channel;
uint8_t data[];
} v7;
};
} __packed;
#define IWM_SCAN_REQ_UMAC_SIZE_V7 48
#define IWM_SCAN_REQ_UMAC_SIZE_V1 36
/**
* struct iwm_umac_scan_abort