Linux wireless drivers development
 help / color / mirror / Atom feed
From: Jeff Johnson <jeff.johnson@oss.qualcomm.com>
To: Gaole Zhang <gaole.zhang@oss.qualcomm.com>,
	ath12k@lists.infradead.org, linux-wireless@vger.kernel.org,
	baochen.qiang@oss.qualcomm.com,
	rameshkumar.sundaram@oss.qualcomm.com
Cc: gaolez@qti.qualcomm.com, miaoqing.pan@oss.qualcomm.com,
	hangtian.zhu@oss.qualcomm.com
Subject: Re: [PATCH v2 ath-next] wifi: ath12k: Add EHT capabilities to scan probe frame
Date: Sun, 4 Oct 2026 11:50:51 -0700	[thread overview]
Message-ID: <93d5fc5e-8174-40ea-9fb0-7beca2f37aa9@oss.qualcomm.com> (raw)
In-Reply-To: <20261001083940.3051840-1-gaole.zhang@oss.qualcomm.com>

On 10/1/2026 1:39 AM, Gaole Zhang wrote:
> ath12k hardware scan Probe Request frames do not include the EHT
> Capabilities element. Without this element, an AP cannot identify the
> STA as EHT-capable during active scanning and may omit EHT-related
> information from its Probe Response. This can result in incomplete scan
> information and prevent userspace from correctly determining the AP's
> EHT capabilities.
> 
> For firmware to include the EHT Capabilities element in scan Probe
> Request frames, two conditions are required:
> 
>   - The scan channel must have WMI_CHAN_INFO_ALLOW_EHT set, which allows
>     firmware to add the EHT Capabilities element to Probe Request frames.
>   - The EHT Capabilities element must be configured on the vdev through
>     WMI_VDEV_SET_IE_CMDID, so firmware can use it when building Probe
>     Request frames.
> 
> Set WMI_CHAN_INFO_ALLOW_EHT for channels when 11be is supported by
> firmware and not disabled by ACPI. Also configure the EHT Capabilities
> element before each hardware scan when the element is present in the
> mac80211 scan IE buffer.
> 
> Firmware retains the configured element in the vdev context until it is
> replaced or the vdev is deleted. However, ath12k scans may either reuse
> an already started vdev or create a temporary scan vdev that is cleaned
> up after scan completion. Sending WMI_VDEV_SET_IE_CMDID for each scan
> request ensures correct behavior in both cases.
> 
> Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.1.c7-00108-QCAHMTSWPL_V1.0_V2.0_SILICONZ_UPSTREAM-3
> 
> Signed-off-by: Gaole Zhang <gaole.zhang@oss.qualcomm.com>
> ---
> v2:
>  - Clarify the firmware requirements for adding the EHT Capabilities
>    element to scan Probe Request frames.
>  - Explain why the EHT Capabilities element is configured before each
>    hardware scan, covering both reused vdevs and temporary scan vdevs.
>  - No code changes.
> 
>  drivers/net/wireless/ath/ath12k/core.h |  6 ++++
>  drivers/net/wireless/ath/ath12k/mac.c  | 29 +++++++++++++--
>  drivers/net/wireless/ath/ath12k/reg.c  |  4 +++
>  drivers/net/wireless/ath/ath12k/wmi.c  | 50 ++++++++++++++++++++++++++
>  drivers/net/wireless/ath/ath12k/wmi.h  | 23 +++++++++++-
>  5 files changed, 109 insertions(+), 3 deletions(-)
> 
> diff --git a/drivers/net/wireless/ath/ath12k/core.h b/drivers/net/wireless/ath/ath12k/core.h
> index a98fc6e0699d..e7373a523dc3 100644
> --- a/drivers/net/wireless/ath/ath12k/core.h
> +++ b/drivers/net/wireless/ath/ath12k/core.h
> @@ -1394,6 +1394,12 @@ static inline struct ath12k *ath12k_ah_to_ar(struct ath12k_hw *ah, u8 radio_idx)
>  	return &ah->radio[radio_idx];
>  }
>  
> +static inline bool ath12k_is_11be_enabled(struct ath12k_base *ab)
> +{
> +	return test_bit(WMI_TLV_SERVICE_11BE, ab->wmi_ab.svc_map) &&
> +	       !ath12k_acpi_get_disable_11be(ab);
> +}
> +
>  static inline struct ath12k_hw *ath12k_ar_to_ah(struct ath12k *ar)
>  {
>  	return ar->ah;
> diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c
> index d4116ba0da08..f353af63c5eb 100644
> --- a/drivers/net/wireless/ath/ath12k/mac.c
> +++ b/drivers/net/wireless/ath/ath12k/mac.c
> @@ -5602,6 +5602,25 @@ ath12k_mac_find_link_id_by_ar(struct ath12k_vif *ahvif, struct ath12k *ar)
>  	return ATH12K_FIRST_SCAN_LINK;
>  }
>  
> +static int ath12k_mac_set_scan_eht_cap_ie(struct ath12k *ar,
> +					  struct ath12k_link_vif *arvif,
> +					  const u8 *ies, size_t ies_len)
> +{
> +	const struct element *eht_cap;
> +
> +	lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy);
> +
> +	eht_cap = cfg80211_find_ext_elem(WLAN_EID_EXT_EHT_CAPABILITY, ies,
> +					 ies_len);
> +	if (!eht_cap || eht_cap->datalen <= 1)
> +		return 0;
> +
> +	return ath12k_wmi_vdev_set_ie(ar, arvif->vdev_id,
> +				      WLAN_EID_EXTENSION,
> +				      eht_cap->data, eht_cap->datalen,
> +				      WMI_SET_VDEV_IE_BAND_ALL);
> +}
> +
>  static int ath12k_mac_initiate_hw_scan(struct ieee80211_hw *hw,
>  				       struct ieee80211_vif *vif,
>  				       struct ieee80211_scan_request *hw_req,
> @@ -5718,6 +5737,13 @@ static int ath12k_mac_initiate_hw_scan(struct ieee80211_hw *hw,
>  			goto exit;
>  		}
>  		arg->extraie.len = req->ie_len;
> +		ret = ath12k_mac_set_scan_eht_cap_ie(ar, arvif, req->ie,
> +						     req->ie_len);
> +		if (ret) {
> +			ath12k_dbg(ar->ab, ATH12K_DBG_MAC,
> +				   "failed to set eht cap ie, ret %d\n", ret);
> +			goto exit;

do we really want to bypass scanning in this case?
would it be better to still scan, just without added capability?

> +		}
>  	}
>  
>  	if (req->n_ssids) {
> @@ -8983,8 +9009,7 @@ static void ath12k_mac_copy_eht_cap(struct ath12k *ar,
>  
>  	memset(eht_cap, 0, sizeof(struct ieee80211_sta_eht_cap));
>  
> -	if (!(test_bit(WMI_TLV_SERVICE_11BE, ar->ab->wmi_ab.svc_map)) ||
> -	    ath12k_acpi_get_disable_11be(ar->ab))
> +	if (!ath12k_is_11be_enabled(ar->ab))
>  		return;
>  
>  	eht_cap->has_eht = true;
> diff --git a/drivers/net/wireless/ath/ath12k/reg.c b/drivers/net/wireless/ath/ath12k/reg.c
> index 89abf2e87ad1..0aba1e74a3e9 100644
> --- a/drivers/net/wireless/ath/ath12k/reg.c
> +++ b/drivers/net/wireless/ath/ath12k/reg.c
> @@ -140,6 +140,7 @@ int ath12k_reg_update_chan_list(struct ath12k *ar, bool wait)
>  	enum nl80211_band band;
>  	int num_channels = 0;
>  	int i, ret = 0;
> +	bool has_eht;
>  
>  	if (ar->ah->state == ATH12K_HW_STATE_RESTARTING)
>  		return 0;
> @@ -180,6 +181,8 @@ int ath12k_reg_update_chan_list(struct ath12k *ar, bool wait)
>  
>  	ch = arg->channel;
>  
> +	has_eht = ath12k_is_11be_enabled(ar->ab);
> +
>  	for (band = 0; band < NUM_NL80211_BANDS; band++) {
>  		if (!(ar->mac.sbands[band].channels && bands[band]))
>  			continue;
> @@ -201,6 +204,7 @@ int ath12k_reg_update_chan_list(struct ath12k *ar, bool wait)
>  			ch->allow_ht = true;
>  			ch->allow_vht = true;
>  			ch->allow_he = true;
> +			ch->allow_eht = has_eht;
>  
>  			ch->dfs_set =
>  				!!(channel->flags & IEEE80211_CHAN_RADAR);
> diff --git a/drivers/net/wireless/ath/ath12k/wmi.c b/drivers/net/wireless/ath/ath12k/wmi.c
> index a63bbda0219c..5fe7af731a4e 100644
> --- a/drivers/net/wireless/ath/ath12k/wmi.c
> +++ b/drivers/net/wireless/ath/ath12k/wmi.c
> @@ -2005,6 +2005,54 @@ int ath12k_wmi_p2p_go_bcn_ie(struct ath12k *ar, u32 vdev_id,
>  	return ret;
>  }
>  
> +int ath12k_wmi_vdev_set_ie(struct ath12k *ar, u32 vdev_id, u32 ie_id,
> +			   const u8 *ie, size_t ie_len, u32 band)
> +{
> +	struct ath12k_wmi_pdev *wmi = ar->wmi;
> +	struct wmi_vdev_set_ie_cmd *cmd;
> +	struct sk_buff *skb;
> +	struct wmi_tlv *tlv;
> +	size_t aligned_len;
> +	int ret, len;
> +	void *ptr;
> +
> +	aligned_len = roundup(ie_len, sizeof(u32));
> +	len = sizeof(*cmd) + TLV_HDR_SIZE + aligned_len;
> +
> +	skb = ath12k_wmi_alloc_skb(wmi->wmi_ab, len);
> +	if (!skb)
> +		return -ENOMEM;
> +
> +	ptr = skb->data;
> +	cmd = ptr;
> +	cmd->tlv_header = ath12k_wmi_tlv_cmd_hdr(WMI_TAG_VDEV_SET_IE_CMD,
> +						 sizeof(*cmd));
> +	cmd->vdev_id = cpu_to_le32(vdev_id);
> +	cmd->ie_id = cpu_to_le32(ie_id);
> +	cmd->ie_len = cpu_to_le32(ie_len);
> +	cmd->ie_source = cpu_to_le32(WMI_SET_VDEV_IE_SOURCE_HOST);
> +	cmd->band = cpu_to_le32(band);
> +
> +	ath12k_dbg(ar->ab, ATH12K_DBG_WMI,
> +		   "WMI set ie vdev_id %u ie_id %u ie_len %zu band %u\n",
> +		   vdev_id, ie_id, ie_len, band);
> +
> +	ptr += sizeof(*cmd);
> +	tlv = ptr;
> +	tlv->header = ath12k_wmi_tlv_hdr(WMI_TAG_ARRAY_BYTE, aligned_len);
> +	memcpy(tlv->value, ie, ie_len);
> +
> +	ret = ath12k_wmi_cmd_send(wmi, skb, WMI_VDEV_SET_IE_CMDID);
> +	if (ret) {
> +		ath12k_warn(ar->ab,
> +			    "failed to send WMI_VDEV_SET_IE_CMDID for vdev %u ie %u: %d\n",
> +			    vdev_id, ie_id, ret);
> +		dev_kfree_skb(skb);
> +	}
> +
> +	return ret;
> +}
> +
>  int ath12k_wmi_bcn_tmpl(struct ath12k_link_vif *arvif,
>  			struct ieee80211_mutable_offsets *offs,
>  			struct sk_buff *bcn,
> @@ -2946,6 +2994,8 @@ int ath12k_wmi_send_scan_chan_list_cmd(struct ath12k *ar,
>  				chan_info->info |= cpu_to_le32(WMI_CHAN_INFO_ALLOW_VHT);
>  			else if (channel_arg->allow_ht)
>  				chan_info->info |= cpu_to_le32(WMI_CHAN_INFO_ALLOW_HT);
> +			if (channel_arg->allow_eht)
> +				chan_info->info |= cpu_to_le32(WMI_CHAN_INFO_ALLOW_EHT);
>  			if (channel_arg->half_rate)
>  				chan_info->info |= cpu_to_le32(WMI_CHAN_INFO_HALF_RATE);
>  			if (channel_arg->quarter_rate)
> diff --git a/drivers/net/wireless/ath/ath12k/wmi.h b/drivers/net/wireless/ath/ath12k/wmi.h
> index b508aa759bd8..e51b3bdab77b 100644
> --- a/drivers/net/wireless/ath/ath12k/wmi.h
> +++ b/drivers/net/wireless/ath/ath12k/wmi.h
> @@ -3075,7 +3075,8 @@ struct ath12k_wmi_channel_arg {
>  	    allow_vht:1,
>  	    allow_he:1,
>  	    set_agile:1,
> -	    psc_channel:1;
> +	    psc_channel:1,
> +	    allow_eht:1;

add after allow_he to keep in a logical order since this isn't ABI?

>  	u32 phy_mode;
>  	u32 cfreq1;
>  	u32 cfreq2;
> @@ -3694,6 +3695,7 @@ struct ath12k_wmi_scan_cancel_arg {
>  #define WMI_CHAN_INFO_DFS_FREQ2		BIT(16)
>  #define WMI_CHAN_INFO_ALLOW_HE		BIT(17)
>  #define WMI_CHAN_INFO_PSC		BIT(18)
> +#define WMI_CHAN_INFO_ALLOW_EHT		BIT(21)
>  
>  #define WMI_CHAN_REG_INFO1_MIN_PWR	GENMASK(7, 0)
>  #define WMI_CHAN_REG_INFO1_MAX_PWR	GENMASK(15, 8)
> @@ -3845,6 +3847,23 @@ struct wmi_p2p_go_set_beacon_ie_cmd {
>  	__le32 ie_buf_len;
>  } __packed;
>  
> +#define WMI_SET_VDEV_IE_SOURCE_HOST	0
> +
> +enum wmi_set_vdev_ie_band {
> +	WMI_SET_VDEV_IE_BAND_ALL,
> +	WMI_SET_VDEV_IE_BAND_2_4GHZ,
> +	WMI_SET_VDEV_IE_BAND_5GHZ,
> +};
> +
> +struct wmi_vdev_set_ie_cmd {
> +	__le32 tlv_header;
> +	__le32 vdev_id;
> +	__le32 ie_id;
> +	__le32 ie_len;
> +	__le32 ie_source;
> +	__le32 band;
> +} __packed;
> +
>  struct wmi_vdev_install_key_cmd {
>  	__le32 tlv_header;
>  	__le32 vdev_id;
> @@ -6583,6 +6602,8 @@ int ath12k_wmi_pdev_resume(struct ath12k *ar, u32 pdev_id);
>  
>  int ath12k_wmi_send_peer_assoc_cmd(struct ath12k *ar,
>  				   struct ath12k_wmi_peer_assoc_arg *arg);
> +int ath12k_wmi_vdev_set_ie(struct ath12k *ar, u32 vdev_id, u32 ie_id,
> +			   const u8 *ie, size_t ie_len, u32 band);
>  int ath12k_wmi_vdev_install_key(struct ath12k *ar,
>  				struct wmi_vdev_install_key_arg *arg);
>  int ath12k_wmi_pdev_bss_chan_info_request(struct ath12k *ar,
> 
> base-commit: c3bace8584ca707e34ba837f65c2e9d566af4c2c


  reply	other threads:[~2026-10-04 18:50 UTC|newest]

Thread overview: 3+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-10-01  8:39 [PATCH v2 ath-next] wifi: ath12k: Add EHT capabilities to scan probe frame Gaole Zhang
2026-10-04 18:50 ` Jeff Johnson [this message]
2026-10-09 12:47   ` Gaole Zhang

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=93d5fc5e-8174-40ea-9fb0-7beca2f37aa9@oss.qualcomm.com \
    --to=jeff.johnson@oss.qualcomm.com \
    --cc=ath12k@lists.infradead.org \
    --cc=baochen.qiang@oss.qualcomm.com \
    --cc=gaole.zhang@oss.qualcomm.com \
    --cc=gaolez@qti.qualcomm.com \
    --cc=hangtian.zhu@oss.qualcomm.com \
    --cc=linux-wireless@vger.kernel.org \
    --cc=miaoqing.pan@oss.qualcomm.com \
    --cc=rameshkumar.sundaram@oss.qualcomm.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox