]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
wifi: ath12k: add EHT rate handling to existing set rate functions
authorMuna Sinada <muna.sinada@oss.qualcomm.com>
Fri, 24 Oct 2025 00:19:24 +0000 (17:19 -0700)
committerJeff Johnson <jeff.johnson@oss.qualcomm.com>
Thu, 30 Oct 2025 21:55:07 +0000 (14:55 -0700)
Add EHT rate handling to the existing rate functions that validate,
prepare and set rates.

Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0.1-00029-QCAHKSWPL_SILICONZ-1

Co-developed-by: Aloka Dixit <aloka.dixit@oss.qualcomm.com>
Signed-off-by: Aloka Dixit <aloka.dixit@oss.qualcomm.com>
Signed-off-by: Muna Sinada <muna.sinada@oss.qualcomm.com>
Reviewed-by: Vasanthakumar Thiagarajan <vasanthakumar.thiagarajan@oss.qualcomm.com>
Link: https://patch.msgid.link/20251024001928.257356-3-muna.sinada@oss.qualcomm.com
Signed-off-by: Jeff Johnson <jeff.johnson@oss.qualcomm.com>
drivers/net/wireless/ath/ath12k/mac.c

index c17500a3e95f9f24457f928ae01a424f06ff9896..0efdf87153e2fa70d689351d182963368ea6e631 100644 (file)
@@ -533,6 +533,18 @@ ath12k_mac_max_he_nss(const u16 he_mcs_mask[NL80211_HE_NSS_MAX])
        return 1;
 }
 
+static u32
+ath12k_mac_max_eht_nss(const u16 eht_mcs_mask[NL80211_EHT_NSS_MAX])
+{
+       int nss;
+
+       for (nss = NL80211_EHT_NSS_MAX - 1; nss >= 0; nss--)
+               if (eht_mcs_mask[nss])
+                       return nss + 1;
+
+       return 1;
+}
+
 static u8 ath12k_parse_mpdudensity(u8 mpdudensity)
 {
 /*  From IEEE Std 802.11-2020 defined values for "Minimum MPDU Start Spacing":
@@ -3102,37 +3114,50 @@ static void ath12k_peer_assoc_h_phymode(struct ath12k *ar,
        WARN_ON(phymode == MODE_UNKNOWN);
 }
 
+#define ATH12K_EHT_MCS_7_ENABLED       0x00FF
+#define ATH12K_EHT_MCS_9_ENABLED       0x0300
+#define ATH12K_EHT_MCS_11_ENABLED      0x0C00
+#define ATH12K_EHT_MCS_13_ENABLED      0x3000
+
 static void ath12k_mac_set_eht_mcs(u8 rx_tx_mcs7, u8 rx_tx_mcs9,
                                   u8 rx_tx_mcs11, u8 rx_tx_mcs13,
-                                  u32 *rx_mcs, u32 *tx_mcs)
-{
-       *rx_mcs = 0;
-       u32p_replace_bits(rx_mcs,
-                         u8_get_bits(rx_tx_mcs7, IEEE80211_EHT_MCS_NSS_RX),
-                         WMI_EHT_MCS_NSS_0_7);
-       u32p_replace_bits(rx_mcs,
-                         u8_get_bits(rx_tx_mcs9, IEEE80211_EHT_MCS_NSS_RX),
-                         WMI_EHT_MCS_NSS_8_9);
-       u32p_replace_bits(rx_mcs,
-                         u8_get_bits(rx_tx_mcs11, IEEE80211_EHT_MCS_NSS_RX),
-                         WMI_EHT_MCS_NSS_10_11);
-       u32p_replace_bits(rx_mcs,
-                         u8_get_bits(rx_tx_mcs13, IEEE80211_EHT_MCS_NSS_RX),
-                         WMI_EHT_MCS_NSS_12_13);
-
-       *tx_mcs = 0;
-       u32p_replace_bits(tx_mcs,
-                         u8_get_bits(rx_tx_mcs7, IEEE80211_EHT_MCS_NSS_TX),
-                         WMI_EHT_MCS_NSS_0_7);
-       u32p_replace_bits(tx_mcs,
-                         u8_get_bits(rx_tx_mcs9, IEEE80211_EHT_MCS_NSS_TX),
-                         WMI_EHT_MCS_NSS_8_9);
-       u32p_replace_bits(tx_mcs,
-                         u8_get_bits(rx_tx_mcs11, IEEE80211_EHT_MCS_NSS_TX),
-                         WMI_EHT_MCS_NSS_10_11);
-       u32p_replace_bits(tx_mcs,
-                         u8_get_bits(rx_tx_mcs13, IEEE80211_EHT_MCS_NSS_TX),
-                         WMI_EHT_MCS_NSS_12_13);
+                                  u32 *rx_mcs, u32 *tx_mcs,
+                                  const u16 eht_mcs_limit[NL80211_EHT_NSS_MAX])
+{
+       int nss;
+       u8 mcs_7 = 0, mcs_9 = 0, mcs_11 = 0, mcs_13 = 0;
+       u8 peer_mcs_7, peer_mcs_9, peer_mcs_11, peer_mcs_13;
+
+       for (nss = 0; nss < NL80211_EHT_NSS_MAX; nss++) {
+               if (eht_mcs_limit[nss] & ATH12K_EHT_MCS_7_ENABLED)
+                       mcs_7++;
+               if (eht_mcs_limit[nss] & ATH12K_EHT_MCS_9_ENABLED)
+                       mcs_9++;
+               if (eht_mcs_limit[nss] & ATH12K_EHT_MCS_11_ENABLED)
+                       mcs_11++;
+               if (eht_mcs_limit[nss] & ATH12K_EHT_MCS_13_ENABLED)
+                       mcs_13++;
+       }
+
+       peer_mcs_7 = u8_get_bits(rx_tx_mcs7, IEEE80211_EHT_MCS_NSS_RX);
+       peer_mcs_9 = u8_get_bits(rx_tx_mcs9, IEEE80211_EHT_MCS_NSS_RX);
+       peer_mcs_11 = u8_get_bits(rx_tx_mcs11, IEEE80211_EHT_MCS_NSS_RX);
+       peer_mcs_13 = u8_get_bits(rx_tx_mcs13, IEEE80211_EHT_MCS_NSS_RX);
+
+       *rx_mcs = u32_encode_bits(min(peer_mcs_7, mcs_7), WMI_EHT_MCS_NSS_0_7) |
+                 u32_encode_bits(min(peer_mcs_9, mcs_9), WMI_EHT_MCS_NSS_8_9) |
+                 u32_encode_bits(min(peer_mcs_11, mcs_11), WMI_EHT_MCS_NSS_10_11) |
+                 u32_encode_bits(min(peer_mcs_13, mcs_13), WMI_EHT_MCS_NSS_12_13);
+
+       peer_mcs_7 = u8_get_bits(rx_tx_mcs7, IEEE80211_EHT_MCS_NSS_TX);
+       peer_mcs_9 = u8_get_bits(rx_tx_mcs9, IEEE80211_EHT_MCS_NSS_TX);
+       peer_mcs_11 = u8_get_bits(rx_tx_mcs11, IEEE80211_EHT_MCS_NSS_TX);
+       peer_mcs_13 = u8_get_bits(rx_tx_mcs13, IEEE80211_EHT_MCS_NSS_TX);
+
+       *tx_mcs = u32_encode_bits(min(peer_mcs_7, mcs_7), WMI_EHT_MCS_NSS_0_7) |
+                 u32_encode_bits(min(peer_mcs_9, mcs_9), WMI_EHT_MCS_NSS_8_9) |
+                 u32_encode_bits(min(peer_mcs_11, mcs_11), WMI_EHT_MCS_NSS_10_11) |
+                 u32_encode_bits(min(peer_mcs_13, mcs_13), WMI_EHT_MCS_NSS_12_13);
 }
 
 static void ath12k_mac_set_eht_ppe_threshold(const u8 *ppe_thres,
@@ -3171,13 +3196,17 @@ static void ath12k_peer_assoc_h_eht(struct ath12k *ar,
                                    struct ath12k_wmi_peer_assoc_arg *arg)
 {
        struct ieee80211_sta *sta = ath12k_ahsta_to_sta(arsta->ahsta);
+       struct ieee80211_vif *vif = ath12k_ahvif_to_vif(arvif->ahvif);
        const struct ieee80211_eht_mcs_nss_supp_20mhz_only *bw_20;
        const struct ieee80211_eht_mcs_nss_supp_bw *bw;
        const struct ieee80211_sta_eht_cap *eht_cap;
        const struct ieee80211_sta_he_cap *he_cap;
        struct ieee80211_link_sta *link_sta;
        struct ieee80211_bss_conf *link_conf;
+       struct cfg80211_chan_def def;
+       enum nl80211_band band;
        u32 *rx_mcs, *tx_mcs;
+       u16 *eht_mcs_mask;
 
        lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy);
 
@@ -3199,6 +3228,12 @@ static void ath12k_peer_assoc_h_eht(struct ath12k *ar,
        if (!he_cap->has_he || !eht_cap->has_eht)
                return;
 
+       if (WARN_ON(ath12k_mac_vif_link_chan(vif, arvif->link_id, &def)))
+               return;
+
+       band = def.chan->band;
+       eht_mcs_mask = arvif->bitrate_mask.control[band].eht_mcs;
+
        arg->eht_flag = true;
 
        if ((eht_cap->eht_cap_elem.phy_cap_info[5] &
@@ -3223,7 +3258,8 @@ static void ath12k_peer_assoc_h_eht(struct ath12k *ar,
                                       bw->rx_tx_mcs11_max_nss,
                                       bw->rx_tx_mcs13_max_nss,
                                       &rx_mcs[WMI_EHTCAP_TXRX_MCS_NSS_IDX_320],
-                                      &tx_mcs[WMI_EHTCAP_TXRX_MCS_NSS_IDX_320]);
+                                      &tx_mcs[WMI_EHTCAP_TXRX_MCS_NSS_IDX_320],
+                                      eht_mcs_mask);
                arg->peer_eht_mcs_count++;
                fallthrough;
        case IEEE80211_STA_RX_BW_160:
@@ -3233,7 +3269,8 @@ static void ath12k_peer_assoc_h_eht(struct ath12k *ar,
                                       bw->rx_tx_mcs11_max_nss,
                                       bw->rx_tx_mcs13_max_nss,
                                       &rx_mcs[WMI_EHTCAP_TXRX_MCS_NSS_IDX_160],
-                                      &tx_mcs[WMI_EHTCAP_TXRX_MCS_NSS_IDX_160]);
+                                      &tx_mcs[WMI_EHTCAP_TXRX_MCS_NSS_IDX_160],
+                                      eht_mcs_mask);
                arg->peer_eht_mcs_count++;
                fallthrough;
        default:
@@ -3249,7 +3286,8 @@ static void ath12k_peer_assoc_h_eht(struct ath12k *ar,
                                               bw_20->rx_tx_mcs11_max_nss,
                                               bw_20->rx_tx_mcs13_max_nss,
                                               &rx_mcs[WMI_EHTCAP_TXRX_MCS_NSS_IDX_80],
-                                              &tx_mcs[WMI_EHTCAP_TXRX_MCS_NSS_IDX_80]);
+                                              &tx_mcs[WMI_EHTCAP_TXRX_MCS_NSS_IDX_80],
+                                              eht_mcs_mask);
                } else {
                        bw = &eht_cap->eht_mcs_nss_supp.bw._80;
                        ath12k_mac_set_eht_mcs(bw->rx_tx_mcs9_max_nss,
@@ -3257,7 +3295,8 @@ static void ath12k_peer_assoc_h_eht(struct ath12k *ar,
                                               bw->rx_tx_mcs11_max_nss,
                                               bw->rx_tx_mcs13_max_nss,
                                               &rx_mcs[WMI_EHTCAP_TXRX_MCS_NSS_IDX_80],
-                                              &tx_mcs[WMI_EHTCAP_TXRX_MCS_NSS_IDX_80]);
+                                              &tx_mcs[WMI_EHTCAP_TXRX_MCS_NSS_IDX_80],
+                                              eht_mcs_mask);
                }
 
                arg->peer_eht_mcs_count++;
@@ -3908,6 +3947,8 @@ static void ath12k_mac_init_arvif(struct ath12k_vif *ahvif,
                       sizeof(arvif->bitrate_mask.control[i].vht_mcs));
                memset(arvif->bitrate_mask.control[i].he_mcs, 0xff,
                       sizeof(arvif->bitrate_mask.control[i].he_mcs));
+               memset(arvif->bitrate_mask.control[i].eht_mcs, 0xff,
+                      sizeof(arvif->bitrate_mask.control[i].eht_mcs));
        }
 
        /* Handle MLO related assignments */
@@ -5835,6 +5876,20 @@ ath12k_mac_bitrate_mask_num_he_rates(struct ath12k *ar,
        return num_rates;
 }
 
+static int
+ath12k_mac_bitrate_mask_num_eht_rates(struct ath12k *ar,
+                                     enum nl80211_band band,
+                                     const struct cfg80211_bitrate_mask *mask)
+{
+       int num_rates = 0;
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(mask->control[band].eht_mcs); i++)
+               num_rates += hweight16(mask->control[band].eht_mcs[i]);
+
+       return num_rates;
+}
+
 static int
 ath12k_mac_set_peer_vht_fixed_rate(struct ath12k_link_vif *arvif,
                                   struct ath12k_link_sta *arsta,
@@ -11976,6 +12031,9 @@ ath12k_mac_has_single_legacy_rate(struct ath12k *ar,
        if (ath12k_mac_bitrate_mask_num_he_rates(ar, band, mask))
                return false;
 
+       if (ath12k_mac_bitrate_mask_num_eht_rates(ar, band, mask))
+               return false;
+
        return num_rates == 1;
 }
 
@@ -11998,11 +12056,15 @@ ath12k_mac_bitrate_mask_get_single_nss(struct ath12k *ar,
 {
        struct ieee80211_supported_band *sband = &ar->mac.sbands[band];
        u16 vht_mcs_map = le16_to_cpu(sband->vht_cap.vht_mcs.tx_mcs_map);
+       const struct ieee80211_sband_iftype_data *data;
        const struct ieee80211_sta_he_cap *he_cap;
        u16 he_mcs_map = 0;
+       u16 eht_mcs_map = 0;
        u8 ht_nss_mask = 0;
        u8 vht_nss_mask = 0;
        u8 he_nss_mask = 0;
+       u8 eht_nss_mask = 0;
+       u8 mcs_nss_len;
        int i;
 
        /* No need to consider legacy here. Basic rates are always present
@@ -12046,7 +12108,60 @@ ath12k_mac_bitrate_mask_get_single_nss(struct ath12k *ar,
                        return false;
        }
 
-       if (ht_nss_mask != vht_nss_mask || ht_nss_mask != he_nss_mask)
+       data = ieee80211_get_sband_iftype_data(sband, vif->type);
+
+       mcs_nss_len = ieee80211_eht_mcs_nss_size(&data->he_cap.he_cap_elem,
+                                                &data->eht_cap.eht_cap_elem,
+                                                false);
+       if (mcs_nss_len == 4) {
+               /* 20 MHz only STA case */
+               const struct ieee80211_eht_mcs_nss_supp_20mhz_only *eht_mcs_nss =
+                       &data->eht_cap.eht_mcs_nss_supp.only_20mhz;
+               if (eht_mcs_nss->rx_tx_mcs13_max_nss)
+                       eht_mcs_map = 0x1fff;
+               else if (eht_mcs_nss->rx_tx_mcs11_max_nss)
+                       eht_mcs_map = 0x07ff;
+               else if (eht_mcs_nss->rx_tx_mcs9_max_nss)
+                       eht_mcs_map = 0x01ff;
+               else
+                       eht_mcs_map = 0x007f;
+       } else {
+               const struct ieee80211_eht_mcs_nss_supp_bw *eht_mcs_nss;
+
+               switch (mcs_nss_len) {
+               case 9:
+                       eht_mcs_nss = &data->eht_cap.eht_mcs_nss_supp.bw._320;
+                       break;
+               case 6:
+                       eht_mcs_nss = &data->eht_cap.eht_mcs_nss_supp.bw._160;
+                       break;
+               case 3:
+                       eht_mcs_nss = &data->eht_cap.eht_mcs_nss_supp.bw._80;
+                       break;
+               default:
+                       return false;
+               }
+
+               if (eht_mcs_nss->rx_tx_mcs13_max_nss)
+                       eht_mcs_map = 0x1fff;
+               else if (eht_mcs_nss->rx_tx_mcs11_max_nss)
+                       eht_mcs_map = 0x7ff;
+               else
+                       eht_mcs_map = 0x1ff;
+       }
+
+       for (i = 0; i < ARRAY_SIZE(mask->control[band].eht_mcs); i++) {
+               if (mask->control[band].eht_mcs[i] == 0)
+                       continue;
+
+               if (mask->control[band].eht_mcs[i] < eht_mcs_map)
+                       eht_nss_mask |= BIT(i);
+               else
+                       return false;
+       }
+
+       if (ht_nss_mask != vht_nss_mask || ht_nss_mask != he_nss_mask ||
+           ht_nss_mask != eht_nss_mask)
                return false;
 
        if (ht_nss_mask == 0)
@@ -12198,11 +12313,12 @@ static u32 ath12k_mac_nlgi_to_wmigi(enum nl80211_txrate_gi gi)
 
 static int ath12k_mac_set_rate_params(struct ath12k_link_vif *arvif,
                                      u32 rate, u8 nss, u8 sgi, u8 ldpc,
-                                     u8 he_gi, u8 he_ltf, bool he_fixed_rate)
+                                     u8 he_gi, u8 he_ltf, bool he_fixed_rate,
+                                     bool eht_fixed_rate)
 {
        struct ieee80211_bss_conf *link_conf;
        struct ath12k *ar = arvif->ar;
-       bool he_support, gi_ltf_set = false;
+       bool he_support, eht_support, gi_ltf_set = false;
        u32 vdev_param;
        u32 param_value;
        int ret;
@@ -12214,6 +12330,7 @@ static int ath12k_mac_set_rate_params(struct ath12k_link_vif *arvif,
                return -EINVAL;
 
        he_support = link_conf->he_support;
+       eht_support = link_conf->eht_support;
 
        ath12k_dbg(ar->ab, ATH12K_DBG_MAC,
                   "mac set rate params vdev %i rate 0x%02x nss 0x%02x sgi 0x%02x ldpc 0x%02x\n",
@@ -12223,7 +12340,10 @@ static int ath12k_mac_set_rate_params(struct ath12k_link_vif *arvif,
                   "he_gi 0x%02x he_ltf 0x%02x he_fixed_rate %d\n", he_gi,
                   he_ltf, he_fixed_rate);
 
-       if (!he_support) {
+       ath12k_dbg(ar->ab, ATH12K_DBG_MAC, "eht_fixed_rate %d\n",
+                  eht_fixed_rate);
+
+       if (!he_support && !eht_support) {
                vdev_param = WMI_VDEV_PARAM_FIXED_RATE;
                ret = ath12k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id,
                                                    vdev_param, rate);
@@ -12381,15 +12501,16 @@ ath12k_mac_validate_fixed_rate_settings(struct ath12k *ar, enum nl80211_band ban
                                        const struct cfg80211_bitrate_mask *mask,
                                        unsigned int link_id)
 {
-       bool he_fixed_rate = false, vht_fixed_rate = false;
-       const u16 *vht_mcs_mask, *he_mcs_mask;
+       bool eht_fixed_rate = false, he_fixed_rate = false, vht_fixed_rate = false;
+       const u16 *vht_mcs_mask, *he_mcs_mask, *eht_mcs_mask;
        struct ieee80211_link_sta *link_sta;
        struct ath12k_peer *peer, *tmp;
-       u8 vht_nss, he_nss;
+       u8 vht_nss, he_nss, eht_nss;
        int ret = true;
 
        vht_mcs_mask = mask->control[band].vht_mcs;
        he_mcs_mask = mask->control[band].he_mcs;
+       eht_mcs_mask = mask->control[band].eht_mcs;
 
        if (ath12k_mac_bitrate_mask_num_vht_rates(ar, band, mask) == 1)
                vht_fixed_rate = true;
@@ -12397,11 +12518,15 @@ ath12k_mac_validate_fixed_rate_settings(struct ath12k *ar, enum nl80211_band ban
        if (ath12k_mac_bitrate_mask_num_he_rates(ar, band, mask) == 1)
                he_fixed_rate = true;
 
-       if (!vht_fixed_rate && !he_fixed_rate)
+       if (ath12k_mac_bitrate_mask_num_eht_rates(ar, band, mask) == 1)
+               eht_fixed_rate = true;
+
+       if (!vht_fixed_rate && !he_fixed_rate && !eht_fixed_rate)
                return true;
 
        vht_nss = ath12k_mac_max_vht_nss(vht_mcs_mask);
        he_nss =  ath12k_mac_max_he_nss(he_mcs_mask);
+       eht_nss = ath12k_mac_max_eht_nss(eht_mcs_mask);
 
        rcu_read_lock();
        spin_lock_bh(&ar->ab->base_lock);
@@ -12423,6 +12548,11 @@ ath12k_mac_validate_fixed_rate_settings(struct ath12k *ar, enum nl80211_band ban
                                ret = false;
                                goto exit;
                        }
+                       if (eht_fixed_rate && (!link_sta->eht_cap.has_eht ||
+                                              link_sta->rx_nss < eht_nss)) {
+                               ret = false;
+                               goto exit;
+                       }
                }
        }
 exit:
@@ -12454,6 +12584,7 @@ ath12k_mac_op_set_bitrate_mask(struct ieee80211_hw *hw,
        int ret;
        int num_rates;
        bool he_fixed_rate = false;
+       bool eht_fixed_rate = false;
 
        lockdep_assert_wiphy(hw->wiphy);
 
@@ -12578,7 +12709,7 @@ ath12k_mac_op_set_bitrate_mask(struct ieee80211_hw *hw,
        }
 
        ret = ath12k_mac_set_rate_params(arvif, rate, nss, sgi, ldpc, he_gi,
-                                        he_ltf, he_fixed_rate);
+                                        he_ltf, he_fixed_rate, eht_fixed_rate);
        if (ret) {
                ath12k_warn(ar->ab, "failed to set rate params on vdev %i: %d\n",
                            arvif->vdev_id, ret);