Index | Thread | Search

From:
Mark Kettenis <mark.kettenis@xs4all.nl>
Subject:
Re: iwx: scan command version 17
To:
Stefan Sperling <stsp@stsp.name>
Cc:
tech@openbsd.org
Date:
Tue, 24 Feb 2026 23:34:52 +0100

Download raw body.

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