Download raw body.
iwx: scan command version 17
> Date: Tue, 24 Feb 2026 16:19:08 +0100
> From: Stefan Sperling <stsp@stsp.name>
>
> 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?
Also tested on AX210 (MA).
ok kettenis@
> 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
>
>
iwx: scan command version 17