From: Stefan Sperling Subject: iwx: scan command version 17 To: tech@openbsd.org Date: Tue, 24 Feb 2026 16:19:08 +0100 Add support for scan command version 17 to iwx(4). This will be needed for Bz devices. Tested on AX200, and on AX211 (Bz) with other local changes. ok? M sys/dev/pci/if_iwx.c | 202+ 2- M sys/dev/pci/if_iwxreg.h | 107+ 0- 2 files changed, 309 insertions(+), 2 deletions(-) commit - ad326fcaf0c83015c73f258e04d6180e2cc40891 commit + 18247b7c795ec847bd60dd111d274b8a2e518b06 blob - 6181f1267153c75984dedfa0f3d82a8898e69b0a blob + 03d36027340740248ccbb4c47f118b183ae1414e --- sys/dev/pci/if_iwx.c +++ sys/dev/pci/if_iwx.c @@ -420,8 +420,13 @@ void iwx_scan_umac_dwell_v10(struct iwx_softc *, struct iwx_scan_general_params_v10 *, int); void iwx_scan_umac_fill_general_p_v10(struct iwx_softc *, struct iwx_scan_general_params_v10 *, uint16_t, int); +void iwx_scan_umac_fill_general_p_v11(struct iwx_softc *, + struct iwx_scan_general_params_v11 *, uint16_t, int); void iwx_scan_umac_fill_ch_p_v6(struct iwx_softc *, struct iwx_scan_channel_params_v6 *, uint32_t, int); +void iwx_scan_umac_fill_ch_p_v7(struct iwx_softc *, + struct iwx_scan_channel_params_v7 *, uint32_t, int); +int iwx_umac_scan_v17(struct iwx_softc *, int); int iwx_umac_scan_v14(struct iwx_softc *, int); void iwx_mcc_update(struct iwx_softc *, struct iwx_mcc_chub_notif *); uint8_t iwx_ridx2rate(struct ieee80211_rateset *, int); @@ -437,6 +442,7 @@ int iwx_mld_mac_ctxt_cmd(struct iwx_softc *, struct iw int iwx_clear_statistics(struct iwx_softc *); void iwx_add_task(struct iwx_softc *, struct taskq *, struct task *); void iwx_del_task(struct iwx_softc *, struct taskq *, struct task *); +int iwx_initiate_scan(struct iwx_softc *, int); int iwx_scan(struct iwx_softc *); int iwx_bgscan(struct ieee80211com *); void iwx_bgscan_done(struct ieee80211com *, @@ -7179,6 +7185,45 @@ iwx_umac_scan_fill_channels(struct iwx_softc *sc, return nchan; } +uint8_t +iwx_umac_scan_fill_channels_v5(struct iwx_softc *sc, + struct iwx_scan_channel_cfg_umac_v5 *chan, size_t chan_nitems, + int n_ssids, uint32_t channel_cfg_flags) +{ + struct ieee80211com *ic = &sc->sc_ic; + struct ieee80211_channel *c; + uint8_t nchan; + + for (nchan = 0, c = &ic->ic_channels[1]; + c <= &ic->ic_channels[IEEE80211_CHAN_MAX] && + nchan < chan_nitems && + nchan < sc->sc_capa_n_scan_channels; + c++) { + uint8_t channel_num, band; + + if (c->ic_flags == 0) + continue; + + channel_num = ieee80211_mhz2ieee(c->ic_freq, 0); + if (IEEE80211_IS_CHAN_2GHZ(c)) + band = IWX_PHY_BAND_24; + else + band = IWX_PHY_BAND_5; + + chan->channel_num = channel_num; + chan->psd_20 = -128; + chan->iter_count = 1; + chan->iter_interval = 0; + + chan->flags = htole32(channel_cfg_flags | + (band << IWX_CHAN_CFG_FLAGS_BAND_POS)); + chan++; + nchan++; + } + + return nchan; +} + int iwx_fill_probe_req(struct iwx_softc *sc, struct iwx_scan_probe_req *preq) { @@ -7395,6 +7440,51 @@ iwx_scan_umac_dwell_v10(struct iwx_softc *sc, } void +iwx_scan_umac_dwell_v11(struct iwx_softc *sc, + struct iwx_scan_general_params_v11 *general_params, int bgscan) +{ + uint32_t suspend_time, max_out_time; + uint8_t active_dwell, passive_dwell; + + active_dwell = IWX_SCAN_DWELL_ACTIVE; + passive_dwell = IWX_SCAN_DWELL_PASSIVE; + + general_params->adwell_default_social_chn = + IWX_SCAN_ADWELL_DEFAULT_N_APS_SOCIAL; + general_params->adwell_default_2g = IWX_SCAN_ADWELL_DEFAULT_LB_N_APS; + general_params->adwell_default_5g = IWX_SCAN_ADWELL_DEFAULT_HB_N_APS; + + if (bgscan) + general_params->adwell_max_budget = + htole16(IWX_SCAN_ADWELL_MAX_BUDGET_DIRECTED_SCAN); + else + general_params->adwell_max_budget = + htole16(IWX_SCAN_ADWELL_MAX_BUDGET_FULL_SCAN); + + general_params->scan_priority = htole32(IWX_SCAN_PRIORITY_EXT_6); + if (bgscan) { + max_out_time = htole32(120); + suspend_time = htole32(120); + } else { + max_out_time = htole32(0); + suspend_time = htole32(0); + } + general_params->max_out_of_time[IWX_SCAN_LB_LMAC_IDX] = + htole32(max_out_time); + general_params->suspend_time[IWX_SCAN_LB_LMAC_IDX] = + htole32(suspend_time); + general_params->max_out_of_time[IWX_SCAN_HB_LMAC_IDX] = + htole32(max_out_time); + general_params->suspend_time[IWX_SCAN_HB_LMAC_IDX] = + htole32(suspend_time); + + general_params->active_dwell[IWX_SCAN_LB_LMAC_IDX] = active_dwell; + general_params->passive_dwell[IWX_SCAN_LB_LMAC_IDX] = passive_dwell; + general_params->active_dwell[IWX_SCAN_HB_LMAC_IDX] = active_dwell; + general_params->passive_dwell[IWX_SCAN_HB_LMAC_IDX] = passive_dwell; +} + +void iwx_scan_umac_fill_general_p_v10(struct iwx_softc *sc, struct iwx_scan_general_params_v10 *gp, uint16_t gen_flags, int bgscan) { @@ -7411,6 +7501,21 @@ iwx_scan_umac_fill_general_p_v10(struct iwx_softc *sc, } void +iwx_scan_umac_fill_general_p_v11(struct iwx_softc *sc, + struct iwx_scan_general_params_v11 *gp, uint16_t gen_flags, int bgscan) +{ + iwx_scan_umac_dwell_v11(sc, gp, bgscan); + + gp->flags = htole16(gen_flags); + gp->scan_start_mac_or_link_id = 0; + + if (gen_flags & IWX_UMAC_SCAN_GEN_FLAGS_V2_FRAGMENTED_LMAC1) + gp->num_of_fragments[IWX_SCAN_LB_LMAC_IDX] = 3; + if (gen_flags & IWX_UMAC_SCAN_GEN_FLAGS_V2_FRAGMENTED_LMAC2) + gp->num_of_fragments[IWX_SCAN_HB_LMAC_IDX] = 3; +} + +void iwx_scan_umac_fill_ch_p_v6(struct iwx_softc *sc, struct iwx_scan_channel_params_v6 *cp, uint32_t channel_cfg_flags, int n_ssid) @@ -7424,6 +7529,20 @@ iwx_scan_umac_fill_ch_p_v6(struct iwx_softc *sc, cp->n_aps_override[1] = IWX_SCAN_ADWELL_N_APS_SOCIAL_CHS; } +void +iwx_scan_umac_fill_ch_p_v7(struct iwx_softc *sc, + struct iwx_scan_channel_params_v7 *cp, uint32_t channel_cfg_flags, + int n_ssid) +{ + cp->flags = IWX_SCAN_CHANNEL_FLAG_ENABLE_CHAN_ORDER; + + cp->count = iwx_umac_scan_fill_channels_v5(sc, cp->channel_config, + nitems(cp->channel_config), n_ssid, channel_cfg_flags); + + cp->n_aps_override[0] = IWX_SCAN_ADWELL_N_APS_GO_FRIENDLY; + cp->n_aps_override[1] = IWX_SCAN_ADWELL_N_APS_SOCIAL_CHS; +} + int iwx_umac_scan_v14(struct iwx_softc *sc, int bgscan) { @@ -7484,6 +7603,66 @@ iwx_umac_scan_v14(struct iwx_softc *sc, int bgscan) return err; } +int +iwx_umac_scan_v17(struct iwx_softc *sc, int bgscan) +{ + struct ieee80211com *ic = &sc->sc_ic; + struct iwx_host_cmd hcmd = { + .id = iwx_cmd_id(IWX_SCAN_REQ_UMAC, IWX_LONG_GROUP, 0), + .len = { 0, }, + .data = { NULL, }, + .flags = 0, + }; + struct iwx_scan_req_umac_v17 *cmd; + struct iwx_scan_req_params_v17 *scan_p; + int err, async = bgscan, n_ssid = 0; + uint16_t gen_flags; + uint32_t bitmap_ssid = 0; + + cmd = malloc(sizeof(*cmd), M_DEVBUF, + (async ? M_NOWAIT : M_WAIT) | M_CANFAIL | M_ZERO); + if (cmd == NULL) + return ENOMEM; + + scan_p = &cmd->scan_params; + + cmd->ooc_priority = htole32(IWX_SCAN_PRIORITY_EXT_6); + cmd->uid = htole32(0); + + gen_flags = iwx_scan_umac_flags_v2(sc, bgscan); + iwx_scan_umac_fill_general_p_v11(sc, &scan_p->general_params, + gen_flags, bgscan); + + scan_p->periodic_params.schedule[0].interval = htole16(0); + scan_p->periodic_params.schedule[0].iter_count = 1; + + err = iwx_fill_probe_req(sc, &scan_p->probe_params.preq); + if (err) { + free(cmd, M_DEVBUF, sizeof(*cmd)); + return err; + } + + if (ic->ic_des_esslen != 0) { + scan_p->probe_params.direct_scan[0].id = IEEE80211_ELEMID_SSID; + scan_p->probe_params.direct_scan[0].len = ic->ic_des_esslen; + memcpy(scan_p->probe_params.direct_scan[0].ssid, + ic->ic_des_essid, ic->ic_des_esslen); + bitmap_ssid |= (1 << 0); + n_ssid = 1; + } + + iwx_scan_umac_fill_ch_p_v7(sc, &scan_p->channel_params, bitmap_ssid, + n_ssid); + + hcmd.len[0] = sizeof(*cmd); + hcmd.data[0] = (void *)cmd; + hcmd.flags |= async ? IWX_CMD_ASYNC : 0; + + err = iwx_send_cmd(sc, &hcmd); + free(cmd, M_DEVBUF, sizeof(*cmd)); + return err; +} + void iwx_mcc_update(struct iwx_softc *sc, struct iwx_mcc_chub_notif *notif) { @@ -7872,6 +8051,27 @@ iwx_del_task(struct iwx_softc *sc, struct taskq *taskq } int +iwx_initiate_scan(struct iwx_softc *sc, int bgscan) +{ + int err; + uint8_t version; + + version = iwx_lookup_cmd_ver(sc, IWX_LONG_GROUP, IWX_SCAN_REQ_UMAC); + DPRINTF(("%s: scan command version %u\n", DEVNAME(sc), version)); + + switch (version) { + case 17: + err = iwx_umac_scan_v17(sc, bgscan); + break; + default: + err = iwx_umac_scan_v14(sc, bgscan); + break; + } + + return err; +} + +int iwx_scan(struct iwx_softc *sc) { struct ieee80211com *ic = &sc->sc_ic; @@ -7887,7 +8087,7 @@ iwx_scan(struct iwx_softc *sc) } } - err = iwx_umac_scan_v14(sc, 0); + err = iwx_initiate_scan(sc, 0); if (err) { printf("%s: could not initiate scan\n", DEVNAME(sc)); return err; @@ -7924,7 +8124,7 @@ iwx_bgscan(struct ieee80211com *ic) if (sc->sc_flags & IWX_FLAG_SCANNING) return 0; - err = iwx_umac_scan_v14(sc, 1); + err = iwx_initiate_scan(sc, 1); if (err) { printf("%s: could not initiate scan\n", DEVNAME(sc)); return err; blob - a6556c35edaf25e52203713e2701ee6a45431a30 blob + 379c265ad8b23e0f535fb9da089800655229e90a --- sys/dev/pci/if_iwxreg.h +++ sys/dev/pci/if_iwxreg.h @@ -3300,6 +3300,7 @@ struct iwx_time_quota_cmd { /* Supported bands */ #define IWX_PHY_BAND_5 (0) #define IWX_PHY_BAND_24 (1) +#define IWX_PHY_BAND_6 (2) /* Supported channel width, vary if there is VHT support */ #define IWX_PHY_VHT_CHANNEL_MODE20 (0x0) @@ -7281,6 +7282,26 @@ struct iwx_scan_channel_cfg_umac { } __packed; /** + * struct iwx_scan_channel_cfg_umac_v5 + * @flags: bitmap - 0-19: directed scan to i'th ssid. + * bits 30/31: band number (IWX_PHY_BAND_*) + * @channel_num: channel number 1-13 etc. + * @psd_20: highest PSD value for all APs known so far + * on this channel. + * @iter_count: repetition count for the channel. + * @iter_interval: interval between two scan iterations on one channel. + */ +struct iwx_scan_channel_cfg_umac_v5 { + uint32_t flags; + uint8_t channel_num; + uint8_t psd_20; + uint8_t iter_count; + uint8_t iter_interval; +} __packed; /* SCAN_CHANNEL_CONFIG_API_S_VER_5 */ + +#define IWX_CHAN_CFG_FLAGS_BAND_POS 30 + +/** * struct iwx_scan_umac_schedule * @interval: interval in seconds between scan iterations * @iter_count: num of scan iterations for schedule plan, 0xff for infinite loop @@ -7578,6 +7599,92 @@ struct iwx_scan_req_umac_v14 { } __packed; /* SCAN_REQUEST_CMD_UMAC_API_S_VER_14 */ /** + * struct iwx_scan_general_params_v11 - channel params + * @flags: &enum iwl_umac_scan_general_flags_v2 + * @reserved: reserved for future + * @scan_start_mac_or_link_id: report the scan start TSF time according to this + * mac (up to verion 11) or link (starting with version 12) TSF + * @active_dwell: dwell time for active scan per LMAC + * @adwell_default_2g: adaptive dwell default number of APs + * for 2.4GHz channel + * @adwell_default_5g: adaptive dwell default number of APs + * for 5GHz channels + * @adwell_default_social_chn: adaptive dwell default number of + * APs per social channel + * @flags2: for version 11 see &enum iwl_umac_scan_general_params_flags2. + * Otherwise reserved. + * @adwell_max_budget: the maximal number of TUs that adaptive dwell + * can add to the total scan time + * @max_out_of_time: max out of serving channel time, per LMAC + * @suspend_time: max suspend time, per LMAC + * @scan_priority: priority of the request + * @passive_dwell: continues dwell time for passive channel + * (without adaptive dwell) + * @num_of_fragments: number of fragments needed for full fragmented + * scan coverage. + */ +struct iwx_scan_general_params_v11 { + uint16_t flags; + uint8_t reserved; + uint8_t scan_start_mac_or_link_id; + uint8_t active_dwell[IWX_SCAN_TWO_LMACS]; + uint8_t adwell_default_2g; + uint8_t adwell_default_5g; + uint8_t adwell_default_social_chn; + uint8_t flags2; + uint16_t adwell_max_budget; + uint32_t max_out_of_time[IWX_SCAN_TWO_LMACS]; + uint32_t suspend_time[IWX_SCAN_TWO_LMACS]; + uint32_t scan_priority; + uint8_t passive_dwell[IWX_SCAN_TWO_LMACS]; + uint8_t num_of_fragments[IWX_SCAN_TWO_LMACS]; +} __packed; /* SCAN_GENERAL_PARAMS_API_S_VER_12, *_VER_11 and *_VER_10 */ + +/** + * struct iwx_scan_channel_params_v7 - channel params + * @flags: channel flags &enum iwl_scan_channel_flags + * @count: num of channels in scan request + * @n_aps_override: override the number of APs the FW uses to calculate dwell + * time when adaptive dwell is used. + * Channel k will use n_aps_override[i] when BIT(20 + i) is set in + * channel_config[k].flags + * @channel_config: array of explicit channel configurations + * for 2.4Ghz and 5.2Ghz bands + */ +struct iwx_scan_channel_params_v7 { + uint8_t flags; + uint8_t count; + uint8_t n_aps_override[2]; + struct iwx_scan_channel_cfg_umac_v5 channel_config[67]; +} __packed; /* SCAN_CHANNEL_PARAMS_API_S_VER_7 */ + +/** + * struct iwx_scan_req_params_v17 - scan request parameters (v17) + * @general_params: &struct iwx_scan_general_params_v11 + * @channel_params: &struct iwx_scan_channel_params_v7 + * @periodic_params: &struct iwx_scan_periodic_parms_v1 + * @probe_params: &struct iwx_scan_probe_params_v4 + */ +struct iwx_scan_req_params_v17 { + struct iwx_scan_general_params_v11 general_params; + struct iwx_scan_channel_params_v7 channel_params; + struct iwx_scan_periodic_parms_v1 periodic_params; + struct iwx_scan_probe_params_v4 probe_params; +} __packed; /* SCAN_REQUEST_PARAMS_API_S_VER_17 - 14 */ + +/* + * struct iwx_scan_req_umac_v17 - scan request command (v17) + * @uid: scan id, &enum iwl_umac_scan_uid_offsets + * @ooc_priority: out of channel priority - &enum iwl_scan_priority + * @scan_params: scan parameters + */ +struct iwx_scan_req_umac_v17 { + uint32_t uid; + uint32_t ooc_priority; + struct iwx_scan_req_params_v17 scan_params; +} __packed; /* SCAN_REQUEST_CMD_UMAC_API_S_VER_17 - 14 */ + +/** * struct iwx_umac_scan_abort * @uid: scan id, &enum iwx_umac_scan_uid_offsets * @flags: reserved