[PATCH AUTOSEL 6.19-6.18] wifi: ath12k: fix mac phy capability parsing

Sasha Levin
2026-02-14T21:26:03Z

From: Baochen Qiang <baochen.qiang@oss.qualcomm.com>

[ Upstream commit b5151c9b6e3a347416a4b4b55fc00195526d8771 ]

Currently ath12k_pull_mac_phy_cap_svc_ready_ext() assumes only one band
supported in each phy, hence it skips 5 GHz band if 2 GHz band support
is detected. This does not work for device which gets only one phy but
has both bands supported, such as QCC2072.

Change to check each band individually to fix this issue.

Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.1.c5-00302-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1.115823.3

Signed-off-by: Baochen Qiang <baochen.qiang@oss.qualcomm.com>
Reviewed-by: Vasanthakumar Thiagarajan <vasanthakumar.thiagarajan@oss.qualcomm.com>
Link: https://patch.msgid.link/20260112-ath12k-support-qcc2072-v2-6-fc8ce1e43969@oss.qualcomm.com
Signed-off-by: Jeff Johnson <jeff.johnson@oss.qualcomm.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---

LLM Generated explanations, may be completely bogus:

### Dependency Concerns

The investigation reveals an important dependency issue:

- The constants were **renamed** from
`WMI_HOST_WLAN_2G_CAP`/`WMI_HOST_WLAN_5G_CAP` to
`WMI_HOST_WLAN_2GHZ_CAP`/`WMI_HOST_WLAN_5GHZ_CAP` in March 2025
(commit `6a88093f79ea0`). If backporting to a stable tree that
predates this rename, the constant names would need adjustment.
- The `nss_ratio` fields were added in June 2025 - older stable trees
may not have these.
- The ath12k driver itself was introduced in November 2022, so stable
trees from 6.1.y onward should have the driver.

The core logic change (if/else if → independent if checks) is self-
contained and the fix concept applies regardless of these naming
differences, though minor backport adjustments to constant names may be
needed for older stable trees.

### Risk vs. Benefit

- **Benefit:** Fixes a real functional bug where dual-band single-PHY
WiFi devices (like QCC2072) cannot use 5 GHz band at all. This is a
significant hardware functionality issue.
- **Risk:** Very low. The logic change is straightforward and doesn't
affect single-band devices. The only behavioral change for dual-band
devices is that both bands are now properly initialized instead of
only one.

### Conclusion

This is a clear bug fix in a wireless driver that prevents hardware from
working correctly. The fix is:
- Small and contained (single function, single file)
- Obviously correct (the if/else if logic was clearly wrong for dual-
band PHYs)
- Tested and reviewed
- Low risk of regression
- Fixes a real user-visible issue (5 GHz band not working)

The only minor concern is that backporting may require adjusting
constant names for older stable trees, but this is a trivial mechanical
adjustment.

**YES**

drivers/net/wireless/ath/ath12k/wmi.c | 22 ++++++++++++++--------
1 file changed, 14 insertions(+), 8 deletions(-)

diff --git a/drivers/net/wireless/ath/ath12k/wmi.c b/drivers/net/wireless/ath/ath12k/wmi.c
index 12f4d378f50d4..1613492b38350 100644
--- a/drivers/net/wireless/ath/ath12k/wmi.c
+++ b/drivers/net/wireless/ath/ath12k/wmi.c
@@ -496,6 +496,7 @@ ath12k_pull_mac_phy_cap_svc_ready_ext(struct ath12k_wmi_pdev *wmi_handle,
struct ath12k_band_cap *cap_band;
struct ath12k_pdev_cap *pdev_cap = &pdev->cap;
struct ath12k_fw_pdev *fw_pdev;
+ u32 supported_bands;
u32 phy_map;
u32 hw_idx, phy_idx = 0;
int i;
@@ -519,14 +520,19 @@ ath12k_pull_mac_phy_cap_svc_ready_ext(struct ath12k_wmi_pdev *wmi_handle,
return -EINVAL;

mac_caps = wmi_mac_phy_caps + phy_idx;
+ supported_bands = le32_to_cpu(mac_caps->supported_bands);
+
+ if (!(supported_bands & WMI_HOST_WLAN_2GHZ_CAP) &&
+ !(supported_bands & WMI_HOST_WLAN_5GHZ_CAP))
+ return -EINVAL;

pdev->pdev_id = ath12k_wmi_mac_phy_get_pdev_id(mac_caps);
pdev->hw_link_id = ath12k_wmi_mac_phy_get_hw_link_id(mac_caps);
- pdev_cap->supported_bands |= le32_to_cpu(mac_caps->supported_bands);
+ pdev_cap->supported_bands |= supported_bands;
pdev_cap->ampdu_density = le32_to_cpu(mac_caps->ampdu_density);

fw_pdev = &ab->fw_pdev[ab->fw_pdev_count];
- fw_pdev->supported_bands = le32_to_cpu(mac_caps->supported_bands);
+ fw_pdev->supported_bands = supported_bands;
fw_pdev->pdev_id = ath12k_wmi_mac_phy_get_pdev_id(mac_caps);
fw_pdev->phy_id = le32_to_cpu(mac_caps->phy_id);
ab->fw_pdev_count++;
@@ -535,10 +541,12 @@ ath12k_pull_mac_phy_cap_svc_ready_ext(struct ath12k_wmi_pdev *wmi_handle,
* band to band for a single radio, need to see how this should be
* handled.
*/
- if (le32_to_cpu(mac_caps->supported_bands) & WMI_HOST_WLAN_2GHZ_CAP) {
+ if (supported_bands & WMI_HOST_WLAN_2GHZ_CAP) {
pdev_cap->tx_chain_mask = le32_to_cpu(mac_caps->tx_chain_mask_2g);
pdev_cap->rx_chain_mask = le32_to_cpu(mac_caps->rx_chain_mask_2g);
- } else if (le32_to_cpu(mac_caps->supported_bands) & WMI_HOST_WLAN_5GHZ_CAP) {
+ }
+
+ if (supported_bands & WMI_HOST_WLAN_5GHZ_CAP) {
pdev_cap->vht_cap = le32_to_cpu(mac_caps->vht_cap_info_5g);
pdev_cap->vht_mcs = le32_to_cpu(mac_caps->vht_supp_mcs_5g);
pdev_cap->he_mcs = le32_to_cpu(mac_caps->he_supp_mcs_5g);
@@ -548,8 +556,6 @@ ath12k_pull_mac_phy_cap_svc_ready_ext(struct ath12k_wmi_pdev *wmi_handle,
WMI_NSS_RATIO_EN_DIS_GET(mac_caps->nss_ratio);
pdev_cap->nss_ratio_info =
WMI_NSS_RATIO_INFO_GET(mac_caps->nss_ratio);
- } else {
- return -EINVAL;
}

/* tx/rx chainmask reported from fw depends on the actual hw chains used,
@@ -565,7 +571,7 @@ ath12k_pull_mac_phy_cap_svc_ready_ext(struct ath12k_wmi_pdev *wmi_handle,
pdev_cap->rx_chain_mask_shift =
find_first_bit((unsigned long *)&pdev_cap->rx_chain_mask, 32);

- if (le32_to_cpu(mac_caps->supported_bands) & WMI_HOST_WLAN_2GHZ_CAP) {
+ if (supported_bands & WMI_HOST_WLAN_2GHZ_CAP) {
cap_band = &pdev_cap->band[NL80211_BAND_2GHZ];
cap_band->phy_id = le32_to_cpu(mac_caps->phy_id);
cap_band->max_bw_supported = le32_to_cpu(mac_caps->max_bw_supported_2g);
@@ -585,7 +591,7 @@ ath12k_pull_mac_phy_cap_svc_ready_ext(struct ath12k_wmi_pdev *wmi_handle,
le32_to_cpu(mac_caps->he_ppet2g.ppet16_ppet8_ru3_ru0[i]);
}

- if (le32_to_cpu(mac_caps->supported_bands) & WMI_HOST_WLAN_5GHZ_CAP) {
+ if (supported_bands & WMI_HOST_WLAN_5GHZ_CAP) {
cap_band = &pdev_cap->band[NL80211_BAND_5GHZ];
cap_band->phy_id = le32_to_cpu(mac_caps->phy_id);
cap_band->max_bw_supported =
--
2.51.0