--- /dev/null
+From: Ming Yen Hsieh <mingyen.hsieh@mediatek.com>
+Date: Wed, 4 Sep 2024 19:12:56 +0800
+Subject: [PATCH] wifi: mac80211: introduce EHT rate support in AQL airtime
+
+Add definitions related to EHT mode and airtime calculation
+according to the 802.11BE_D4.0.
+
+Co-developed-by: Bo Jiao <Bo.Jiao@mediatek.com>
+Signed-off-by: Bo Jiao <Bo.Jiao@mediatek.com>
+Signed-off-by: Deren Wu <deren.wu@mediatek.com>
+Signed-off-by: Quan Zhou <quan.zhou@mediatek.com>
+Signed-off-by: Ming Yen Hsieh <mingyen.hsieh@mediatek.com>
+Link: https://patch.msgid.link/20240904111256.11734-1-mingyen.hsieh@mediatek.com
+Signed-off-by: Johannes Berg <johannes.berg@intel.com>
+---
+
+--- a/net/mac80211/airtime.c
++++ b/net/mac80211/airtime.c
+@@ -55,10 +55,21 @@
+ #define HE_DURATION_S(shift, streams, gi, bps) \
+ (HE_DURATION(streams, gi, bps) >> shift)
+
++/* gi in HE/EHT is identical. It matches enum nl80211_eht_gi as well */
++#define EHT_GI_08 HE_GI_08
++#define EHT_GI_16 HE_GI_16
++#define EHT_GI_32 HE_GI_32
++
++#define EHT_DURATION(streams, gi, bps) \
++ HE_DURATION(streams, gi, bps)
++#define EHT_DURATION_S(shift, streams, gi, bps) \
++ HE_DURATION_S(shift, streams, gi, bps)
++
+ #define BW_20 0
+ #define BW_40 1
+ #define BW_80 2
+ #define BW_160 3
++#define BW_320 4
+
+ /*
+ * Define group sort order: HT40 -> SGI -> #streams
+@@ -68,17 +79,26 @@
+ #define IEEE80211_VHT_STREAM_GROUPS 8 /* BW(=4) * SGI(=2) */
+
+ #define IEEE80211_HE_MAX_STREAMS 8
++#define IEEE80211_HE_STREAM_GROUPS 12 /* BW(=4) * GI(=3) */
++
++#define IEEE80211_EHT_MAX_STREAMS 8
++#define IEEE80211_EHT_STREAM_GROUPS 15 /* BW(=5) * GI(=3) */
+
+ #define IEEE80211_HT_GROUPS_NB (IEEE80211_MAX_STREAMS * \
+ IEEE80211_HT_STREAM_GROUPS)
+ #define IEEE80211_VHT_GROUPS_NB (IEEE80211_MAX_STREAMS * \
+ IEEE80211_VHT_STREAM_GROUPS)
++#define IEEE80211_HE_GROUPS_NB (IEEE80211_HE_MAX_STREAMS * \
++ IEEE80211_HE_STREAM_GROUPS)
++#define IEEE80211_EHT_GROUPS_NB (IEEE80211_EHT_MAX_STREAMS * \
++ IEEE80211_EHT_STREAM_GROUPS)
+
+ #define IEEE80211_HT_GROUP_0 0
+ #define IEEE80211_VHT_GROUP_0 (IEEE80211_HT_GROUP_0 + IEEE80211_HT_GROUPS_NB)
+ #define IEEE80211_HE_GROUP_0 (IEEE80211_VHT_GROUP_0 + IEEE80211_VHT_GROUPS_NB)
++#define IEEE80211_EHT_GROUP_0 (IEEE80211_HE_GROUP_0 + IEEE80211_HE_GROUPS_NB)
+
+-#define MCS_GROUP_RATES 12
++#define MCS_GROUP_RATES 14
+
+ #define HT_GROUP_IDX(_streams, _sgi, _ht40) \
+ IEEE80211_HT_GROUP_0 + \
+@@ -203,6 +223,69 @@
+ #define HE_GROUP(_streams, _gi, _bw) \
+ __HE_GROUP(_streams, _gi, _bw, \
+ HE_GROUP_SHIFT(_streams, _gi, _bw))
++
++#define EHT_BW2VBPS(_bw, r5, r4, r3, r2, r1) \
++ ((_bw) == BW_320 ? r5 : BW2VBPS(_bw, r4, r3, r2, r1))
++
++#define EHT_GROUP_IDX(_streams, _gi, _bw) \
++ (IEEE80211_EHT_GROUP_0 + \
++ IEEE80211_EHT_MAX_STREAMS * 3 * (_bw) + \
++ IEEE80211_EHT_MAX_STREAMS * (_gi) + \
++ (_streams) - 1)
++
++#define __EHT_GROUP(_streams, _gi, _bw, _s) \
++ [EHT_GROUP_IDX(_streams, _gi, _bw)] = { \
++ .shift = _s, \
++ .duration = { \
++ EHT_DURATION_S(_s, _streams, _gi, \
++ EHT_BW2VBPS(_bw, 1960, 980, 490, 234, 117)), \
++ EHT_DURATION_S(_s, _streams, _gi, \
++ EHT_BW2VBPS(_bw, 3920, 1960, 980, 468, 234)), \
++ EHT_DURATION_S(_s, _streams, _gi, \
++ EHT_BW2VBPS(_bw, 5880, 2937, 1470, 702, 351)), \
++ EHT_DURATION_S(_s, _streams, _gi, \
++ EHT_BW2VBPS(_bw, 7840, 3920, 1960, 936, 468)), \
++ EHT_DURATION_S(_s, _streams, _gi, \
++ EHT_BW2VBPS(_bw, 11760, 5880, 2940, 1404, 702)), \
++ EHT_DURATION_S(_s, _streams, _gi, \
++ EHT_BW2VBPS(_bw, 15680, 7840, 3920, 1872, 936)), \
++ EHT_DURATION_S(_s, _streams, _gi, \
++ EHT_BW2VBPS(_bw, 17640, 8820, 4410, 2106, 1053)), \
++ EHT_DURATION_S(_s, _streams, _gi, \
++ EHT_BW2VBPS(_bw, 19600, 9800, 4900, 2340, 1170)), \
++ EHT_DURATION_S(_s, _streams, _gi, \
++ EHT_BW2VBPS(_bw, 23520, 11760, 5880, 2808, 1404)), \
++ EHT_DURATION_S(_s, _streams, _gi, \
++ EHT_BW2VBPS(_bw, 26133, 13066, 6533, 3120, 1560)), \
++ EHT_DURATION_S(_s, _streams, _gi, \
++ EHT_BW2VBPS(_bw, 29400, 14700, 7350, 3510, 1755)), \
++ EHT_DURATION_S(_s, _streams, _gi, \
++ EHT_BW2VBPS(_bw, 32666, 16333, 8166, 3900, 1950)), \
++ EHT_DURATION_S(_s, _streams, _gi, \
++ EHT_BW2VBPS(_bw, 35280, 17640, 8820, 4212, 2106)), \
++ EHT_DURATION_S(_s, _streams, _gi, \
++ EHT_BW2VBPS(_bw, 39200, 19600, 9800, 4680, 2340)) \
++ } \
++}
++
++#define EHT_GROUP_SHIFT(_streams, _gi, _bw) \
++ GROUP_SHIFT(EHT_DURATION(_streams, _gi, \
++ EHT_BW2VBPS(_bw, 1960, 980, 490, 234, 117)))
++
++#define EHT_GROUP(_streams, _gi, _bw) \
++ __EHT_GROUP(_streams, _gi, _bw, \
++ EHT_GROUP_SHIFT(_streams, _gi, _bw))
++
++#define EHT_GROUP_RANGE(_gi, _bw) \
++ EHT_GROUP(1, _gi, _bw), \
++ EHT_GROUP(2, _gi, _bw), \
++ EHT_GROUP(3, _gi, _bw), \
++ EHT_GROUP(4, _gi, _bw), \
++ EHT_GROUP(5, _gi, _bw), \
++ EHT_GROUP(6, _gi, _bw), \
++ EHT_GROUP(7, _gi, _bw), \
++ EHT_GROUP(8, _gi, _bw)
++
+ struct mcs_group {
+ u8 shift;
+ u16 duration[MCS_GROUP_RATES];
+@@ -376,6 +459,26 @@ static const struct mcs_group airtime_mc
+ HE_GROUP(6, HE_GI_32, BW_160),
+ HE_GROUP(7, HE_GI_32, BW_160),
+ HE_GROUP(8, HE_GI_32, BW_160),
++
++ EHT_GROUP_RANGE(EHT_GI_08, BW_20),
++ EHT_GROUP_RANGE(EHT_GI_16, BW_20),
++ EHT_GROUP_RANGE(EHT_GI_32, BW_20),
++
++ EHT_GROUP_RANGE(EHT_GI_08, BW_40),
++ EHT_GROUP_RANGE(EHT_GI_16, BW_40),
++ EHT_GROUP_RANGE(EHT_GI_32, BW_40),
++
++ EHT_GROUP_RANGE(EHT_GI_08, BW_80),
++ EHT_GROUP_RANGE(EHT_GI_16, BW_80),
++ EHT_GROUP_RANGE(EHT_GI_32, BW_80),
++
++ EHT_GROUP_RANGE(EHT_GI_08, BW_160),
++ EHT_GROUP_RANGE(EHT_GI_16, BW_160),
++ EHT_GROUP_RANGE(EHT_GI_32, BW_160),
++
++ EHT_GROUP_RANGE(EHT_GI_08, BW_320),
++ EHT_GROUP_RANGE(EHT_GI_16, BW_320),
++ EHT_GROUP_RANGE(EHT_GI_32, BW_320),
+ };
+
+ static u32
+@@ -422,6 +525,9 @@ static u32 ieee80211_get_rate_duration(s
+ case RATE_INFO_BW_160:
+ bw = BW_160;
+ break;
++ case RATE_INFO_BW_320:
++ bw = BW_320;
++ break;
+ default:
+ WARN_ON_ONCE(1);
+ return 0;
+@@ -443,14 +549,27 @@ static u32 ieee80211_get_rate_duration(s
+ idx = status->rate_idx;
+ group = HE_GROUP_IDX(streams, status->he_gi, bw);
+ break;
++ case RX_ENC_EHT:
++ streams = status->nss;
++ idx = status->rate_idx;
++ group = EHT_GROUP_IDX(streams, status->eht.gi, bw);
++ break;
+ default:
+ WARN_ON_ONCE(1);
+ return 0;
+ }
+
+- if (WARN_ON_ONCE((status->encoding != RX_ENC_HE && streams > 4) ||
+- (status->encoding == RX_ENC_HE && streams > 8)))
+- return 0;
++ switch (status->encoding) {
++ case RX_ENC_EHT:
++ case RX_ENC_HE:
++ if (WARN_ON_ONCE(streams > 8))
++ return 0;
++ break;
++ default:
++ if (WARN_ON_ONCE(streams > 4))
++ return 0;
++ break;
++ }
+
+ if (idx >= MCS_GROUP_RATES)
+ return 0;
+@@ -517,7 +636,9 @@ static bool ieee80211_fill_rate_info(str
+ stat->nss = ri->nss;
+ stat->rate_idx = ri->mcs;
+
+- if (ri->flags & RATE_INFO_FLAGS_HE_MCS)
++ if (ri->flags & RATE_INFO_FLAGS_EHT_MCS)
++ stat->encoding = RX_ENC_EHT;
++ else if (ri->flags & RATE_INFO_FLAGS_HE_MCS)
+ stat->encoding = RX_ENC_HE;
+ else if (ri->flags & RATE_INFO_FLAGS_VHT_MCS)
+ stat->encoding = RX_ENC_VHT;
+@@ -529,7 +650,14 @@ static bool ieee80211_fill_rate_info(str
+ if (ri->flags & RATE_INFO_FLAGS_SHORT_GI)
+ stat->enc_flags |= RX_ENC_FLAG_SHORT_GI;
+
+- stat->he_gi = ri->he_gi;
++ switch (stat->encoding) {
++ case RX_ENC_EHT:
++ stat->eht.gi = ri->eht_gi;
++ break;
++ default:
++ stat->he_gi = ri->he_gi;
++ break;
++ }
+
+ if (stat->encoding != RX_ENC_LEGACY)
+ return true;