Index | Thread | Search

From:
Stefan Sperling <stsp@stsp.name>
Subject:
iwx: scan command version 17
To:
tech@openbsd.org
Date:
Tue, 24 Feb 2026 16:19:08 +0100

Download raw body.

Thread
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