diff mbox series

[RFC,v1,030/256] cl8k: add cap.c

Message ID 20210617160223.160998-31-viktor.barna@celeno.com
State New
Headers show
Series wireless: cl8k driver for Celeno IEEE 802.11ax devices | expand

Commit Message

Viktor Barna June 17, 2021, 3:58 p.m. UTC
From: Viktor Barna <viktor.barna@celeno.com>

(Part of the split. Please, take a look at the cover letter for more
details).

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 drivers/net/wireless/celeno/cl8k/cap.c | 928 +++++++++++++++++++++++++
 1 file changed, 928 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/cap.c

--
2.30.0
diff mbox series

Patch

diff --git a/drivers/net/wireless/celeno/cl8k/cap.c b/drivers/net/wireless/celeno/cl8k/cap.c
new file mode 100644
index 000000000000..bfd884706aa7
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/cap.c
@@ -0,0 +1,928 @@ 
+// SPDX-License-Identifier: MIT
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#include "cap.h"
+#include "utils/utils.h"
+#include "debug.h"
+#include "band.h"
+#include "chan_info.h"
+#include "tx/tx.h"
+#include "sta.h"
+#include "rx/rx_amsdu.h"
+
+#define CL_HT_CAPABILITIES                                              \
+{                                                                       \
+       .ht_supported = true,                                           \
+       .cap = IEEE80211_HT_CAP_DSSSCCK40 | IEEE80211_HT_CAP_MAX_AMSDU, \
+       .ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K,                     \
+       .ampdu_density = IEEE80211_HT_MPDU_DENSITY_1,                   \
+       .mcs = {                                                        \
+               .rx_mask = { 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0 },         \
+               .rx_highest = cpu_to_le16(65),                          \
+               .tx_params = IEEE80211_HT_MCS_TX_DEFINED,               \
+       },                                                              \
+}
+
+#define CL_VHT_CAPABILITIES                                             \
+{                                                                       \
+       .vht_supported = false,                                         \
+       .cap =                                                          \
+               IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE |               \
+               IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE |               \
+               IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE |               \
+               IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE |               \
+               (3 << IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_SHIFT) |    \
+               (3 << IEEE80211_VHT_CAP_BEAMFORMEE_STS_SHIFT),          \
+       .vht_mcs = {                                                    \
+               .rx_mcs_map = cpu_to_le16(                              \
+                               IEEE80211_VHT_MCS_SUPPORT_0_7   << 0  | \
+                               IEEE80211_VHT_MCS_NOT_SUPPORTED << 2  | \
+                               IEEE80211_VHT_MCS_NOT_SUPPORTED << 4  | \
+                               IEEE80211_VHT_MCS_NOT_SUPPORTED << 6  | \
+                               IEEE80211_VHT_MCS_NOT_SUPPORTED << 8  | \
+                               IEEE80211_VHT_MCS_NOT_SUPPORTED << 10 | \
+                               IEEE80211_VHT_MCS_NOT_SUPPORTED << 12 | \
+                               IEEE80211_VHT_MCS_NOT_SUPPORTED << 14), \
+               .tx_mcs_map = cpu_to_le16(                              \
+                               IEEE80211_VHT_MCS_SUPPORT_0_7   << 0  | \
+                               IEEE80211_VHT_MCS_NOT_SUPPORTED << 2  | \
+                               IEEE80211_VHT_MCS_NOT_SUPPORTED << 4  | \
+                               IEEE80211_VHT_MCS_NOT_SUPPORTED << 6  | \
+                               IEEE80211_VHT_MCS_NOT_SUPPORTED << 8  | \
+                               IEEE80211_VHT_MCS_NOT_SUPPORTED << 10 | \
+                               IEEE80211_VHT_MCS_NOT_SUPPORTED << 12 | \
+                               IEEE80211_VHT_MCS_NOT_SUPPORTED << 14), \
+       }                                                               \
+}
+
+#define CL_HE_CAP_ELEM_STATION                                                       \
+{                                                                                    \
+       .mac_cap_info[0] = IEEE80211_HE_MAC_CAP0_HTC_HE,                             \
+       .mac_cap_info[1] = 0,                                                        \
+       .mac_cap_info[2] = 0,                                                        \
+       .mac_cap_info[3] = IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_EXT_2,            \
+       .mac_cap_info[4] = IEEE80211_HE_MAC_CAP4_BQR,                                \
+       .mac_cap_info[5] = IEEE80211_HE_MAC_CAP5_HT_VHT_TRIG_FRAME_RX,               \
+       .phy_cap_info[0] = IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_RU_MAPPING_IN_2G, \
+       .phy_cap_info[1] = IEEE80211_HE_PHY_CAP1_DEVICE_CLASS_A,                     \
+       .phy_cap_info[2] = 0,                                                        \
+       .phy_cap_info[3] = 0,                                                        \
+       .phy_cap_info[4] = 0,                                                        \
+       .phy_cap_info[5] = 0,                                                        \
+       .phy_cap_info[6] = 0,                                                        \
+       .phy_cap_info[7] = 0,                                                        \
+       .phy_cap_info[8] = IEEE80211_HE_PHY_CAP8_20MHZ_IN_40MHZ_HE_PPDU_IN_2G,       \
+       .phy_cap_info[9] = IEEE80211_HE_PHY_CAP9_NOMIMAL_PKT_PADDING_16US,           \
+       .phy_cap_info[10] = 0,                                                       \
+}
+
+#define CL_HE_CAP_ELEM_AP                                                       \
+{                                                                               \
+       .mac_cap_info[0] = IEEE80211_HE_MAC_CAP0_HTC_HE,                        \
+       .mac_cap_info[1] = 0,                                                   \
+       .mac_cap_info[2] = 0,                                                   \
+       .mac_cap_info[3] = IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_EXT_2,       \
+       .mac_cap_info[4] = IEEE80211_HE_MAC_CAP4_BQR,                           \
+       .mac_cap_info[5] = 0,                                                   \
+       .phy_cap_info[0] = 0,                                                   \
+       .phy_cap_info[1] = IEEE80211_HE_PHY_CAP1_DEVICE_CLASS_A,                \
+       .phy_cap_info[2] = 0,                                                   \
+       .phy_cap_info[3] = 0,                                                   \
+       .phy_cap_info[4] = 0,                                                   \
+       .phy_cap_info[5] = 0,                                                   \
+       .phy_cap_info[6] = 0,                                                   \
+       .phy_cap_info[7] = 0,                                                   \
+       .phy_cap_info[8] = 0,                                                   \
+       .phy_cap_info[9] = IEEE80211_HE_PHY_CAP9_NOMIMAL_PKT_PADDING_16US,      \
+       .phy_cap_info[10] = 0,                                                  \
+}
+
+#define CL_HE_CAP_ELEM_MESH_POINT                                               \
+{                                                                               \
+       .mac_cap_info[0] = IEEE80211_HE_MAC_CAP0_HTC_HE,                        \
+       .mac_cap_info[1] = 0,                                                   \
+       .mac_cap_info[2] = 0,                                                   \
+       .mac_cap_info[3] = IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_EXT_2,       \
+       .mac_cap_info[4] = IEEE80211_HE_MAC_CAP4_BQR,                           \
+       .mac_cap_info[5] = 0,                                                   \
+       .phy_cap_info[0] = 0,                                                   \
+       .phy_cap_info[1] = IEEE80211_HE_PHY_CAP1_DEVICE_CLASS_A,                \
+       .phy_cap_info[2] = 0,                                                   \
+       .phy_cap_info[3] = 0,                                                   \
+       .phy_cap_info[4] = 0,                                                   \
+       .phy_cap_info[5] = 0,                                                   \
+       .phy_cap_info[6] = 0,                                                   \
+       .phy_cap_info[7] = 0,                                                   \
+       .phy_cap_info[8] = 0,                                                   \
+       .phy_cap_info[9] = IEEE80211_HE_PHY_CAP9_NOMIMAL_PKT_PADDING_16US,      \
+       .phy_cap_info[10] = 0,                                                  \
+}
+
+#define CL_HE_MCS_NSS_SUPP                   \
+{                                            \
+       .rx_mcs_80 = cpu_to_le16(0xff00),    \
+       .tx_mcs_80 = cpu_to_le16(0xff00),    \
+       .rx_mcs_160 = cpu_to_le16(0xff00),   \
+       .tx_mcs_160 = cpu_to_le16(0xff00),   \
+       .rx_mcs_80p80 = cpu_to_le16(0xffff), \
+       .tx_mcs_80p80 = cpu_to_le16(0xffff), \
+}
+
+#define RATE(_bitrate, _hw_rate, _flags) { \
+       .bitrate = (_bitrate),             \
+       .flags = (_flags),                 \
+       .hw_value = (_hw_rate),            \
+}
+
+#define CHAN(_freq, _idx) {     \
+       .center_freq = (_freq), \
+       .hw_value = (_idx),     \
+       .max_power = 18,        \
+}
+
+#define CHANF(_freq, _idx, _flags) { \
+       .center_freq = (_freq),      \
+       .hw_value = (_idx),          \
+       .flags = (_flags),           \
+       .max_power = 18,             \
+}
+
+static struct ieee80211_sband_iftype_data cl_he_data[] = {
+       {
+               .types_mask = BIT(NL80211_IFTYPE_STATION),
+               .he_cap = {
+                       .has_he = true,
+                       .he_cap_elem = CL_HE_CAP_ELEM_STATION,
+                       .he_mcs_nss_supp = CL_HE_MCS_NSS_SUPP,
+               },
+       },
+       {
+               .types_mask = BIT(NL80211_IFTYPE_AP),
+               .he_cap = {
+                       .has_he = true,
+                       .he_cap_elem = CL_HE_CAP_ELEM_AP,
+                       .he_mcs_nss_supp = CL_HE_MCS_NSS_SUPP,
+               },
+       },
+       {
+               .types_mask = BIT(NL80211_IFTYPE_MESH_POINT),
+               .he_cap = {
+                       .has_he = true,
+                       .he_cap_elem = CL_HE_CAP_ELEM_MESH_POINT,
+                       .he_mcs_nss_supp = CL_HE_MCS_NSS_SUPP,
+               },
+       },
+};
+
+static struct ieee80211_rate cl_ratetable[] = {
+       RATE(10,  0x00, 0),
+       RATE(20,  0x01, IEEE80211_RATE_SHORT_PREAMBLE),
+       RATE(55,  0x02, IEEE80211_RATE_SHORT_PREAMBLE),
+       RATE(110, 0x03, IEEE80211_RATE_SHORT_PREAMBLE),
+       RATE(60,  0x04, 0),
+       RATE(90,  0x05, 0),
+       RATE(120, 0x06, 0),
+       RATE(180, 0x07, 0),
+       RATE(240, 0x08, 0),
+       RATE(360, 0x09, 0),
+       RATE(480, 0x0A, 0),
+       RATE(540, 0x0B, 0),
+};
+
+/* The channels indexes here are not used anymore */
+static struct ieee80211_channel cl_2ghz_channels[] = {
+       CHAN(2412, 0),
+       CHAN(2417, 1),
+       CHAN(2422, 2),
+       CHAN(2427, 3),
+       CHAN(2432, 4),
+       CHAN(2437, 5),
+       CHAN(2442, 6),
+       CHAN(2447, 7),
+       CHAN(2452, 8),
+       CHAN(2457, 9),
+       CHAN(2462, 10),
+       CHAN(2467, 11),
+       CHAN(2472, 12),
+       CHAN(2484, 13),
+};
+
+static struct ieee80211_channel cl_5ghz_channels[] = {
+       CHAN(5180, 0),  /* 36 -  20MHz */
+       CHAN(5200, 1),  /* 40 -  20MHz */
+       CHAN(5220, 2),  /* 44 -  20MHz */
+       CHAN(5240, 3),  /* 48 -  20MHz */
+
+       CHANF(5260, 4,  IEEE80211_CHAN_RADAR),  /* 52 -  20MHz */
+       CHANF(5280, 5,  IEEE80211_CHAN_RADAR),  /* 56 -  20MHz */
+       CHANF(5300, 6,  IEEE80211_CHAN_RADAR),  /* 60 -  20MHz */
+       CHANF(5320, 7,  IEEE80211_CHAN_RADAR),  /* 64 -  20MHz */
+       CHANF(5500, 8,  IEEE80211_CHAN_RADAR),  /* 100 - 20MHz */
+       CHANF(5520, 9,  IEEE80211_CHAN_RADAR),  /* 104 - 20MHz */
+       CHANF(5540, 10, IEEE80211_CHAN_RADAR), /* 108 - 20MHz */
+       CHANF(5560, 11, IEEE80211_CHAN_RADAR), /* 112 - 20MHz */
+       CHANF(5580, 12, IEEE80211_CHAN_RADAR), /* 116 - 20MHz */
+       CHANF(5600, 13, IEEE80211_CHAN_RADAR), /* 120 - 20MHz */
+       CHANF(5620, 14, IEEE80211_CHAN_RADAR), /* 124 - 20MHz */
+       CHANF(5640, 15, IEEE80211_CHAN_RADAR), /* 128 - 20MHz */
+       CHANF(5660, 16, IEEE80211_CHAN_RADAR), /* 132 - 20MHz */
+       CHANF(5680, 17, IEEE80211_CHAN_RADAR), /* 136 - 20MHz */
+       CHANF(5700, 18, IEEE80211_CHAN_RADAR), /* 140 - 20MHz */
+
+       CHAN(5720, 19), /* 144 - 20MHz */
+       CHAN(5745, 20), /* 149 - 20MHz */
+       CHAN(5765, 21), /* 153 - 20MHz */
+       CHAN(5785, 22), /* 157 - 20MHz */
+       CHAN(5805, 23), /* 161 - 20MHz */
+       CHAN(5825, 24), /* 165 - 20MHz */
+};
+
+static struct ieee80211_channel cl_6ghz_channels[] = {
+       CHAN(5955, 1),  /* 1 - 20MHz */
+       CHAN(5935, 2),  /* 2 - 20MHz */
+       CHAN(5975, 5),  /* 5 - 20MHz */
+       CHAN(5995, 9),  /* 9 - 20MHz */
+       CHAN(6015, 13),  /* 13 - 20MHz */
+       CHAN(6035, 17),  /* 17 - 20MHz */
+       CHAN(6055, 21),  /* 21 - 20MHz */
+       CHAN(6075, 25),  /* 25 - 20MHz */
+       CHAN(6095, 29),  /* 29 - 20MHz */
+       CHAN(6115, 33),  /* 33 - 20MHz */
+       CHAN(6135, 37),  /* 37 - 20MHz */
+       CHAN(6155, 41),  /* 41 - 20MHz */
+       CHAN(6175, 45),  /* 45 - 20MHz */
+       CHAN(6195, 49),  /* 49 - 20MHz */
+       CHAN(6215, 53),  /* 53 - 20MHz */
+       CHAN(6235, 57),  /* 57 - 20MHz */
+       CHAN(6255, 61),  /* 61 - 20MHz */
+       CHAN(6275, 65),  /* 65 - 20MHz */
+       CHAN(6295, 69),  /* 69 - 20MHz */
+       CHAN(6315, 73),  /* 73 - 20MHz */
+       CHAN(6335, 77),  /* 77 - 20MHz */
+       CHAN(6355, 81),  /* 81 - 20MHz */
+       CHAN(6375, 85),  /* 85 - 20MHz */
+       CHAN(6395, 89),  /* 89 - 20MHz */
+       CHAN(6415, 93),  /* 93 - 20MHz */
+       CHAN(6435, 97),  /* 97 - 20MHz */
+       CHAN(6455, 101),  /* 101 - 20MHz */
+       CHAN(6475, 105),  /* 105 - 20MHz */
+       CHAN(6495, 109),  /* 109 - 20MHz */
+       CHAN(6515, 113),  /* 113 - 20MHz */
+       CHAN(6535, 117),  /* 117 - 20MHz */
+       CHAN(6555, 121),  /* 121 - 20MHz */
+       CHAN(6575, 125),  /* 125 - 20MHz */
+       CHAN(6595, 129),  /* 129 - 20MHz */
+       CHAN(6615, 133),  /* 133 - 20MHz */
+       CHAN(6635, 137),  /* 137 - 20MHz */
+       CHAN(6655, 141),  /* 141 - 20MHz */
+       CHAN(6675, 145),  /* 145 - 20MHz */
+       CHAN(6695, 149),  /* 149 - 20MHz */
+       CHAN(6715, 153),  /* 153 - 20MHz */
+       CHAN(6735, 157),  /* 157 - 20MHz */
+       CHAN(6755, 161),  /* 161 - 20MHz */
+       CHAN(6775, 165),  /* 165 - 20MHz */
+       CHAN(6795, 169),  /* 169 - 20MHz */
+       CHAN(6815, 173),  /* 173 - 20MHz */
+       CHAN(6835, 177),  /* 177 - 20MHz */
+       CHAN(6855, 181),  /* 181 - 20MHz */
+       CHAN(6875, 188),  /* 185 - 20MHz */
+       CHAN(6895, 189),  /* 189 - 20MHz */
+       CHAN(6915, 193),  /* 193 - 20MHz */
+       CHAN(6935, 197),  /* 197 - 20MHz */
+       CHAN(6955, 201),  /* 201 - 20MHz */
+       CHAN(6975, 205),  /* 205 - 20MHz */
+       CHAN(6995, 209),  /* 209 - 20MHz */
+       CHAN(7015, 213),  /* 213 - 20MHz */
+       CHAN(7035, 217),  /* 217 - 20MHz */
+       CHAN(7055, 221),  /* 221 - 20MHz */
+       CHAN(7075, 225),  /* 225 - 20MHz */
+       CHAN(7095, 229),  /* 229 - 20MHz */
+       CHAN(7115, 233),  /* 233 - 20MHz */
+};
+
+static struct ieee80211_supported_band cl_band_2ghz = {
+       .channels   = cl_2ghz_channels,
+       .n_channels = ARRAY_SIZE(cl_2ghz_channels),
+       .bitrates   = cl_ratetable,
+       .n_bitrates = ARRAY_SIZE(cl_ratetable),
+       .ht_cap     = CL_HT_CAPABILITIES,
+       .vht_cap    = CL_VHT_CAPABILITIES,
+};
+
+static struct ieee80211_supported_band cl_band_5ghz = {
+       .channels   = cl_5ghz_channels,
+       .n_channels = ARRAY_SIZE(cl_5ghz_channels),
+       .bitrates   = &cl_ratetable[4],
+       .n_bitrates = ARRAY_SIZE(cl_ratetable) - 4,
+       .ht_cap     = CL_HT_CAPABILITIES,
+       .vht_cap    = CL_VHT_CAPABILITIES,
+};
+
+static struct ieee80211_supported_band cl_band_6ghz = {
+       .channels   = cl_6ghz_channels,
+       .n_channels = ARRAY_SIZE(cl_6ghz_channels),
+       .bitrates   = &cl_ratetable[4],
+       .n_bitrates = ARRAY_SIZE(cl_ratetable) - 4,
+};
+
+static const struct ieee80211_iface_limit cl_limits[] = {
+       {
+               .max   = MAX_BSS_NUM,
+               .types = BIT(NL80211_IFTYPE_AP) |
+                        BIT(NL80211_IFTYPE_STATION) |
+                        BIT(NL80211_IFTYPE_MESH_POINT),
+       },
+};
+
+static const u8 cl_if_types_ext_capa_ap[] = {
+       [0]  = WLAN_EXT_CAPA1_EXT_CHANNEL_SWITCHING,
+       [7]  = WLAN_EXT_CAPA8_OPMODE_NOTIF,
+       [10] = WLAN_EXT_CAPA11_COMPLETE_LIST_OF_NONTXBSSID_PROFILES,
+};
+
+static const struct wiphy_iftype_ext_capab cl_iftypes_ext_capa[] = {
+       {
+               .iftype = NL80211_IFTYPE_AP,
+               .extended_capabilities = cl_if_types_ext_capa_ap,
+               .extended_capabilities_mask = cl_if_types_ext_capa_ap,
+               .extended_capabilities_len = sizeof(cl_if_types_ext_capa_ap),
+       },
+};
+
+static const struct ieee80211_iface_combination cl_combinations[] = {
+       {
+               .limits = cl_limits,
+               .n_limits = ARRAY_SIZE(cl_limits),
+               .num_different_channels = 1,
+               .max_interfaces = MAX_BSS_NUM,
+               .beacon_int_min_gcd = 100,
+               .radar_detect_widths = BIT(NL80211_CHAN_WIDTH_20) |
+                                      BIT(NL80211_CHAN_WIDTH_40) |
+                                      BIT(NL80211_CHAN_WIDTH_80) |
+                                      BIT(NL80211_CHAN_WIDTH_160),
+       }
+};
+
+static u8 he_mcs_supp_tx(struct cl_hw *cl_hw, u8 nss)
+{
+       u8 mcs = cl_hw->conf->ce_he_mcs_nss_supp_tx[nss];
+
+       switch (mcs) {
+       case WRS_MCS_7:
+               return IEEE80211_HE_MCS_SUPPORT_0_7;
+       case WRS_MCS_9:
+               return IEEE80211_HE_MCS_SUPPORT_0_9;
+       case WRS_MCS_11:
+               return IEEE80211_HE_MCS_SUPPORT_0_11;
+       }
+
+       cl_dbg_err(cl_hw, "Invalid mcs %u for nss %u. Must be 7, 9 or 11!\n", mcs, nss);
+       return IEEE80211_HE_MCS_NOT_SUPPORTED;
+}
+
+static u8 he_mcs_supp_rx(struct cl_hw *cl_hw, u8 nss)
+{
+       u8 mcs = cl_hw->conf->ce_he_mcs_nss_supp_rx[nss];
+
+       switch (mcs) {
+       case WRS_MCS_7:
+               return IEEE80211_HE_MCS_SUPPORT_0_7;
+       case WRS_MCS_9:
+               return IEEE80211_HE_MCS_SUPPORT_0_9;
+       case WRS_MCS_11:
+               return IEEE80211_HE_MCS_SUPPORT_0_11;
+       }
+
+       cl_dbg_err(cl_hw, "Invalid mcs %u for nss %u. Must be 7, 9 or 11!\n", mcs, nss);
+       return IEEE80211_HE_MCS_NOT_SUPPORTED;
+}
+
+static u8 vht_mcs_supp_tx(struct cl_hw *cl_hw, u8 nss)
+{
+       u8 mcs = cl_hw->conf->ce_vht_mcs_nss_supp_tx[nss];
+
+       switch (mcs) {
+       case WRS_MCS_7:
+               return IEEE80211_VHT_MCS_SUPPORT_0_7;
+       case WRS_MCS_8:
+               return IEEE80211_VHT_MCS_SUPPORT_0_8;
+       case WRS_MCS_9:
+               return IEEE80211_VHT_MCS_SUPPORT_0_9;
+       }
+
+       cl_dbg_err(cl_hw, "Invalid mcs %u for nss %u. Must be 7-9!\n", mcs, nss);
+       return IEEE80211_VHT_MCS_NOT_SUPPORTED;
+}
+
+static u8 vht_mcs_supp_rx(struct cl_hw *cl_hw, u8 nss)
+{
+       u8 mcs = cl_hw->conf->ce_vht_mcs_nss_supp_rx[nss];
+
+       switch (mcs) {
+       case WRS_MCS_7:
+               return IEEE80211_VHT_MCS_SUPPORT_0_7;
+       case WRS_MCS_8:
+               return IEEE80211_VHT_MCS_SUPPORT_0_8;
+       case WRS_MCS_9:
+               return IEEE80211_VHT_MCS_SUPPORT_0_9;
+       }
+
+       cl_dbg_err(cl_hw, "Invalid mcs %u for nss %u. Must be 7-9!\n", mcs, nss);
+       return IEEE80211_VHT_MCS_NOT_SUPPORTED;
+}
+
+static void cl_set_he_6ghz_capab(struct cl_hw *cl_hw)
+{
+       struct ieee80211_he_6ghz_capa *he_6ghz_cap0 = &cl_hw->iftype_data[0].he_6ghz_capa;
+       struct ieee80211_he_6ghz_capa *he_6ghz_cap1 = &cl_hw->iftype_data[1].he_6ghz_capa;
+       struct ieee80211_he_6ghz_capa *he_6ghz_cap2 = &cl_hw->iftype_data[2].he_6ghz_capa;
+
+       he_6ghz_cap0->capa = cpu_to_le16(IEEE80211_HT_MPDU_DENSITY_1);
+       he_6ghz_cap0->capa |=
+               cpu_to_le16(cl_hw->conf->ha_max_mpdu_len << HE_6GHZ_CAP_MAX_MPDU_LEN_OFFSET);
+       he_6ghz_cap0->capa |=
+               cpu_to_le16(IEEE80211_VHT_MAX_AMPDU_1024K << HE_6GHZ_CAP_MAX_AMPDU_LEN_EXP_OFFSET);
+
+       he_6ghz_cap1->capa = he_6ghz_cap0->capa;
+       he_6ghz_cap2->capa = he_6ghz_cap0->capa;
+}
+
+static void _cl_set_he_capab(struct cl_hw *cl_hw, u8 idx)
+{
+       struct ieee80211_sta_he_cap *he_cap = &cl_hw->iftype_data[idx].he_cap;
+       struct ieee80211_he_mcs_nss_supp *he_mcs_nss_supp = &he_cap->he_mcs_nss_supp;
+       struct ieee80211_he_cap_elem *he_cap_elem = &he_cap->he_cap_elem;
+       u8 rx_nss = cl_hw->conf->ce_rx_nss;
+       u8 tx_nss = cl_hw->conf->ce_tx_nss;
+       int i = 0;
+
+       if (BAND_IS_5G_6G(cl_hw)) {
+               he_cap_elem->phy_cap_info[0] |=
+                       IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G;
+
+               for (i = 0; i < rx_nss; i++)
+                       he_mcs_nss_supp->rx_mcs_160 |=
+                               cpu_to_le16(he_mcs_supp_rx(cl_hw, i) << (i * 2));
+
+               for (i = 0; i < tx_nss; i++)
+                       he_mcs_nss_supp->tx_mcs_160 |=
+                               cpu_to_le16(he_mcs_supp_tx(cl_hw, i) << (i * 2));
+
+               he_cap_elem->phy_cap_info[0] |=
+                       IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G;
+
+               for (i = 0; i < rx_nss; i++)
+                       he_mcs_nss_supp->rx_mcs_80 |=
+                               cpu_to_le16(he_mcs_supp_rx(cl_hw, i) << (i * 2));
+
+               for (i = 0; i < tx_nss; i++)
+                       he_mcs_nss_supp->tx_mcs_80 |=
+                               cpu_to_le16(he_mcs_supp_tx(cl_hw, i) << (i * 2));
+       } else {
+               he_cap_elem->phy_cap_info[0] |=
+                       IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_IN_2G;
+
+               for (i = 0; i < rx_nss; i++)
+                       he_mcs_nss_supp->rx_mcs_80 |=
+                               cpu_to_le16(he_mcs_supp_rx(cl_hw, i) << (i * 2));
+
+               for (i = 0; i < tx_nss; i++)
+                       he_mcs_nss_supp->tx_mcs_80 |=
+                               cpu_to_le16(he_mcs_supp_tx(cl_hw, i) << (i * 2));
+       }
+
+       for (i = rx_nss; i < 8; i++) {
+               he_mcs_nss_supp->rx_mcs_80 |=
+                       cpu_to_le16(IEEE80211_HE_MCS_NOT_SUPPORTED << (i * 2));
+               he_mcs_nss_supp->rx_mcs_160 |=
+                       cpu_to_le16(IEEE80211_HE_MCS_NOT_SUPPORTED << (i * 2));
+       }
+
+       for (i = tx_nss; i < 8; i++) {
+               he_mcs_nss_supp->tx_mcs_80 |=
+                       cpu_to_le16(IEEE80211_HE_MCS_NOT_SUPPORTED << (i * 2));
+               he_mcs_nss_supp->tx_mcs_160 |=
+                       cpu_to_le16(IEEE80211_HE_MCS_NOT_SUPPORTED << (i * 2));
+       }
+
+       if (cl_hw->conf->ce_he_rxldpc_en)
+               he_cap_elem->phy_cap_info[1] |=
+                       IEEE80211_HE_PHY_CAP1_LDPC_CODING_IN_PAYLOAD;
+
+       if (cl_hw->conf->ci_rx_he_mu_ppdu)
+               he_cap_elem->phy_cap_info[3] |=
+                       IEEE80211_HE_PHY_CAP3_RX_PARTIAL_BW_SU_IN_20MHZ_MU;
+
+       he_cap_elem->phy_cap_info[3] |=
+               IEEE80211_HE_PHY_CAP3_SU_BEAMFORMER;
+       he_cap_elem->phy_cap_info[5] |=
+               IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_UNDER_80MHZ_4;
+}
+
+static void cl_set_he_capab(struct cl_hw *cl_hw)
+{
+       struct ieee80211_sta_he_cap *he_cap0 = &cl_hw->iftype_data[0].he_cap;
+       struct ieee80211_sta_he_cap *he_cap1 = &cl_hw->iftype_data[1].he_cap;
+       struct ieee80211_he_cap_elem *he_cap_elem0 = &he_cap0->he_cap_elem;
+       struct ieee80211_he_cap_elem *he_cap_elem1 = &he_cap1->he_cap_elem;
+
+       struct cl_tcv_conf *conf = cl_hw->conf;
+       u8 tf_mac_pad_dur = conf->ci_tf_mac_pad_dur;
+
+       memcpy(&cl_hw->iftype_data, cl_he_data, sizeof(cl_hw->iftype_data));
+
+       /* TWT support */
+       if (conf->ce_twt_en) {
+               /* STA mode */
+               he_cap_elem0->mac_cap_info[0] |= IEEE80211_HE_MAC_CAP0_TWT_REQ;
+               /* AP mode */
+               he_cap_elem1->mac_cap_info[0] |= IEEE80211_HE_MAC_CAP0_TWT_RES;
+       }
+
+       /* OMI support */
+       if (conf->ce_omi_en) {
+               /* STA mode */
+               he_cap_elem0->mac_cap_info[3] |= IEEE80211_HE_MAC_CAP3_OMI_CONTROL;
+               /* AP mode */
+               he_cap_elem1->mac_cap_info[3] |= IEEE80211_HE_MAC_CAP3_OMI_CONTROL;
+               he_cap_elem1->mac_cap_info[5] |= IEEE80211_HE_MAC_CAP5_OM_CTRL_UL_MU_DATA_DIS_RX;
+       }
+
+       if (tf_mac_pad_dur == 1)
+               he_cap_elem0->mac_cap_info[1] |= IEEE80211_HE_MAC_CAP1_TF_MAC_PAD_DUR_8US;
+       else if (tf_mac_pad_dur == 2)
+               he_cap_elem0->mac_cap_info[1] |= IEEE80211_HE_MAC_CAP1_TF_MAC_PAD_DUR_16US;
+
+       _cl_set_he_capab(cl_hw, 0);
+       _cl_set_he_capab(cl_hw, 1);
+       _cl_set_he_capab(cl_hw, 2);
+
+       if (cl_band_is_6g(cl_hw))
+               cl_set_he_6ghz_capab(cl_hw);
+
+       cl_hw->sband.n_iftype_data = ARRAY_SIZE(cl_he_data);
+       cl_hw->sband.iftype_data = cl_hw->iftype_data;
+}
+
+void cl_cap_dyn_params(struct cl_hw *cl_hw)
+{
+       struct ieee80211_hw *hw = cl_hw->hw;
+       struct wiphy *wiphy = hw->wiphy;
+       struct cl_tcv_conf *conf = cl_hw->conf;
+       u8 rx_nss = conf->ce_rx_nss;
+       u8 tx_nss = conf->ce_tx_nss;
+       u8 guard_interval = conf->ha_short_guard_interval;
+       u8 i;
+       u8 bw = cl_hw->conf->ce_channel_bandwidth;
+       struct ieee80211_supported_band *sband = &cl_hw->sband;
+       struct ieee80211_sta_ht_cap *sband_ht_cap = &sband->ht_cap;
+       struct ieee80211_sta_vht_cap *sband_vht_cap = &sband->vht_cap;
+
+       if (cl_band_is_6g(cl_hw)) {
+               memcpy(sband, &cl_band_6ghz, sizeof(struct ieee80211_supported_band));
+       } else if (cl_band_is_5g(cl_hw)) {
+               memcpy(sband, &cl_band_5ghz, sizeof(struct ieee80211_supported_band));
+               if (!conf->ci_ieee80211h) {
+                       int i;
+
+                       for (i = 0; i < sband->n_channels; i++)
+                               sband->channels[i].flags &= ~IEEE80211_CHAN_RADAR;
+               }
+       } else {
+               memcpy(sband, &cl_band_2ghz, sizeof(struct ieee80211_supported_band));
+
+               if (!conf->ci_vht_cap_24g)
+                       memset(&sband->vht_cap, 0, sizeof(struct ieee80211_sta_vht_cap));
+       }
+
+       /* 6GHz doesn't support HT/VHT */
+       if (!cl_band_is_6g(cl_hw)) {
+               if (bw > CHNL_BW_20)
+                       sband_ht_cap->cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40;
+
+               /* Guard_interval */
+               if (guard_interval) {
+                       sband_ht_cap->cap |= IEEE80211_HT_CAP_SGI_20;
+
+                       if (bw >= CHNL_BW_40)
+                               sband_ht_cap->cap |= IEEE80211_HT_CAP_SGI_40;
+
+                       if (bw >= CHNL_BW_80)
+                               sband_vht_cap->cap |= IEEE80211_VHT_CAP_SHORT_GI_80;
+
+                       if (bw == CHNL_BW_160)
+                               sband_vht_cap->cap |= IEEE80211_VHT_CAP_SHORT_GI_160;
+               }
+       }
+
+       /* Amsdu */
+       cl_rx_amsdu_hw_en(hw, conf->ce_rxamsdu_en);
+       cl_hw->txamsdu_en = conf->ce_txamsdu_en;
+
+       /* Hw flags */
+       ieee80211_hw_set(hw, HOST_BROADCAST_PS_BUFFERING);
+       ieee80211_hw_set(hw, SIGNAL_DBM);
+       ieee80211_hw_set(hw, REPORTS_TX_ACK_STATUS);
+       ieee80211_hw_set(hw, QUEUE_CONTROL);
+       ieee80211_hw_set(hw, WANT_MONITOR_VIF);
+       ieee80211_hw_set(hw, SPECTRUM_MGMT);
+       ieee80211_hw_set(hw, SUPPORTS_HT_CCK_RATES);
+       ieee80211_hw_set(hw, HAS_RATE_CONTROL);
+       ieee80211_hw_set(hw, SUPPORT_FAST_XMIT);
+       ieee80211_hw_set(hw, NO_AUTO_VIF);
+
+       wiphy->features |= NL80211_FEATURE_AP_MODE_CHAN_WIDTH_CHANGE;
+
+       /* Turn on "20/40 Coex Mgmt Support" bit (24g only) */
+       if (cl_band_is_24g(cl_hw)) {
+               struct ieee80211_local *local = hw_to_local(hw);
+
+               if (conf->ce_coex_en)
+                       local->ext_capa[0] |= WLAN_EXT_CAPA1_2040_BSS_COEX_MGMT_ENABLED;
+               else
+                       wiphy->features &= ~NL80211_FEATURE_AP_MODE_CHAN_WIDTH_CHANGE;
+       }
+
+       if (conf->ci_fast_rx_en) {
+               ieee80211_hw_set(hw, SUPPORTS_REORDERING_BUFFER);
+               ieee80211_hw_set(hw, AP_LINK_PS);
+       }
+
+       /*
+        * To disable the dynamic PS we say to the stack that we support it in
+        * HW. This will force mac80211 rely on us to handle this.
+        */
+       ieee80211_hw_set(hw, SUPPORTS_DYNAMIC_PS);
+
+       if (conf->ci_agg_tx)
+               ieee80211_hw_set(hw, AMPDU_AGGREGATION);
+
+       if (conf->ci_ieee80211w)
+               ieee80211_hw_set(hw, MFP_CAPABLE);
+
+       wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
+                                BIT(NL80211_IFTYPE_AP) |
+                                BIT(NL80211_IFTYPE_MESH_POINT);
+
+       wiphy->flags |= WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL |
+                       WIPHY_FLAG_HAS_CHANNEL_SWITCH;
+
+       if (conf->ce_uapsd_en)
+               wiphy->flags |= WIPHY_FLAG_AP_UAPSD;
+
+       wiphy->iface_combinations = cl_combinations;
+       wiphy->n_iface_combinations = ARRAY_SIZE(cl_combinations);
+
+       hw->max_rates = IEEE80211_TX_MAX_RATES;
+       hw->max_report_rates = IEEE80211_TX_MAX_RATES;
+       hw->max_rate_tries = 1;
+
+       hw->max_tx_aggregation_subframes = conf->ce_max_agg_size_tx;
+       hw->max_rx_aggregation_subframes = conf->ce_max_agg_size_rx;
+
+       hw->vif_data_size = sizeof(struct cl_vif);
+       hw->sta_data_size = sizeof(struct cl_sta);
+
+       hw->extra_tx_headroom = 0;
+       hw->queues = IEEE80211_MAX_QUEUES;
+       hw->offchannel_tx_hw_queue = CL_HWQ_VO;
+
+       if (!cl_band_is_6g(cl_hw)) {
+               if (conf->ce_ht_rxldpc_en)
+                       sband_ht_cap->cap |= IEEE80211_HT_CAP_LDPC_CODING;
+
+               sband_ht_cap->cap |= IEEE80211_HT_CAP_MAX_AMSDU;
+               sband_vht_cap->cap |= cl_hw->conf->ha_max_mpdu_len;
+       }
+
+       if (cl_band_is_5g(cl_hw) || (cl_band_is_24g(cl_hw) && conf->ci_vht_cap_24g)) {
+               if (bw == CHNL_BW_160)
+                       sband_vht_cap->cap |= IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ;
+
+               sband_vht_cap->cap |= (conf->ha_vht_max_ampdu_len_exp <<
+                                      IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_SHIFT);
+
+               if (conf->ce_vht_rxldpc_en)
+                       sband_vht_cap->cap |= IEEE80211_VHT_CAP_RXLDPC;
+
+               sband_vht_cap->vht_mcs.rx_mcs_map = cpu_to_le16(0);
+               sband_vht_cap->vht_mcs.tx_mcs_map = cpu_to_le16(0);
+
+               for (i = 0; i < rx_nss; i++)
+                       sband_vht_cap->vht_mcs.rx_mcs_map |=
+                               cpu_to_le16(vht_mcs_supp_rx(cl_hw, i) << (i * 2));
+
+               for (; i < 8; i++)
+                       sband_vht_cap->vht_mcs.rx_mcs_map |=
+                               cpu_to_le16(IEEE80211_VHT_MCS_NOT_SUPPORTED << (i * 2));
+
+               for (i = 0; i < tx_nss; i++)
+                       sband_vht_cap->vht_mcs.tx_mcs_map |=
+                               cpu_to_le16(vht_mcs_supp_tx(cl_hw, i) << (i * 2));
+
+               for (; i < 8; i++)
+                       sband_vht_cap->vht_mcs.tx_mcs_map |=
+                               cpu_to_le16(IEEE80211_VHT_MCS_NOT_SUPPORTED << (i * 2));
+
+               sband_vht_cap->vht_mcs.rx_highest = cpu_to_le16(390 * rx_nss);
+               sband_vht_cap->vht_mcs.tx_highest = cpu_to_le16(390 * tx_nss);
+               sband_vht_cap->vht_supported = true;
+       }
+
+       /* 6GHz band supports HE only */
+       if (!cl_band_is_6g(cl_hw)) {
+               for (i = 0; i < rx_nss; i++)
+                       sband_ht_cap->mcs.rx_mask[i] = U8_MAX;
+
+               if (bw == CHNL_BW_20)
+                       sband_ht_cap->mcs.rx_highest = guard_interval ?
+                               cpu_to_le16(72 * rx_nss) : cpu_to_le16(65 * rx_nss);
+               else
+                       sband_ht_cap->mcs.rx_highest = guard_interval ?
+                               cpu_to_le16(150 * rx_nss) : cpu_to_le16(135 * rx_nss);
+       }
+
+       if (cl_hw->conf->ce_wireless_mode > WIRELESS_MODE_HT_VHT)
+               cl_set_he_capab(cl_hw);
+
+       /* Get channels and power limitations information from ChannelInfo file */
+       cl_chan_info_init(cl_hw);
+
+       if (cl_band_is_6g(cl_hw)) {
+               wiphy->bands[NL80211_BAND_2GHZ] = NULL;
+               wiphy->bands[NL80211_BAND_5GHZ] = NULL;
+               wiphy->bands[NL80211_BAND_6GHZ] = sband;
+       } else if (cl_band_is_5g(cl_hw)) {
+               wiphy->bands[NL80211_BAND_2GHZ] = NULL;
+               wiphy->bands[NL80211_BAND_5GHZ] = sband;
+               wiphy->bands[NL80211_BAND_6GHZ] = NULL;
+       } else {
+               wiphy->bands[NL80211_BAND_2GHZ] = sband;
+               wiphy->bands[NL80211_BAND_5GHZ] = NULL;
+               wiphy->bands[NL80211_BAND_6GHZ] = NULL;
+       }
+
+       wiphy->regulatory_flags |= REGULATORY_WIPHY_SELF_MANAGED;
+}
+
+enum he_pkt_ext_constellations {
+       HE_PKT_EXT_BPSK = 0,
+       HE_PKT_EXT_QPSK,
+       HE_PKT_EXT_16QAM,
+       HE_PKT_EXT_64QAM,
+       HE_PKT_EXT_256QAM,
+       HE_PKT_EXT_1024QAM,
+       HE_PKT_EXT_RESERVED,
+       HE_PKT_EXT_NONE,
+};
+
+static u8 mcs_to_constellation[WRS_MCS_MAX_HE] = {
+       HE_PKT_EXT_BPSK,
+       HE_PKT_EXT_QPSK,
+       HE_PKT_EXT_QPSK,
+       HE_PKT_EXT_16QAM,
+       HE_PKT_EXT_16QAM,
+       HE_PKT_EXT_64QAM,
+       HE_PKT_EXT_64QAM,
+       HE_PKT_EXT_64QAM,
+       HE_PKT_EXT_256QAM,
+       HE_PKT_EXT_256QAM,
+       HE_PKT_EXT_1024QAM,
+       HE_PKT_EXT_1024QAM
+};
+
+#define QAM_THR_1 0
+#define QAM_THR_2 1
+#define QAM_THR_MAX 2
+
+static u8 get_ppe_val(u8 *ppe, u8 ppe_pos_bit)
+{
+       u8 byte_num = ppe_pos_bit / 8;
+       u8 bit_num = ppe_pos_bit % 8;
+       u8 residue_bits;
+       u8 res;
+
+       if (bit_num <= 5)
+               return (ppe[byte_num] >> bit_num) &
+                      (BIT(IEEE80211_PPE_THRES_INFO_PPET_SIZE) - 1);
+
+       /*
+        * If bit_num > 5, we have to combine bits with next byte.
+        * Calculate how many bits we need to take from current byte (called
+        * here "residue_bits"), and add them to bits from next byte.
+        */
+       residue_bits = 8 - bit_num;
+
+       res = (ppe[byte_num + 1] &
+              (BIT(IEEE80211_PPE_THRES_INFO_PPET_SIZE - residue_bits) - 1)) <<
+             residue_bits;
+       res += (ppe[byte_num] >> bit_num) & (BIT(residue_bits) - 1);
+
+       return res;
+}
+
+static void set_fixed_ppe_val(u8 pe_dur[CHNL_BW_MAX][WRS_MCS_MAX_HE], u8 dur)
+{
+       u8 val = ((dur << 6) | (dur << 4) | (dur << 2) | dur);
+
+       memset(pe_dur, val, CHNL_BW_MAX * WRS_MCS_MAX_HE);
+}
+
+void cl_cap_ppe_duration(struct cl_hw *cl_hw, struct ieee80211_sta *sta,
+                        u8 pe_dur[CHNL_BW_MAX][WRS_MCS_MAX_HE])
+{
+       /* Force NVRAM parameter */
+       if (cl_hw->conf->ci_pe_duration <= PPE_16US) {
+               set_fixed_ppe_val(pe_dur, cl_hw->conf->ci_pe_duration);
+               return;
+       }
+
+       /*
+        * If STA sets the PPE Threshold Present subfield to 0,
+        * the value should be set according to the Nominal Packet Padding subfield
+        */
+       if ((sta->he_cap.he_cap_elem.phy_cap_info[6] &
+            IEEE80211_HE_PHY_CAP6_PPE_THRESHOLD_PRESENT) == 0) {
+               switch (sta->he_cap.he_cap_elem.phy_cap_info[9] &
+                       IEEE80211_HE_PHY_CAP9_NOMIMAL_PKT_PADDING_MASK) {
+               case IEEE80211_HE_PHY_CAP9_NOMIMAL_PKT_PADDING_0US:
+                       set_fixed_ppe_val(pe_dur, PPE_0US);
+                       break;
+               case IEEE80211_HE_PHY_CAP9_NOMIMAL_PKT_PADDING_8US:
+                       set_fixed_ppe_val(pe_dur, PPE_8US);
+                       break;
+               case IEEE80211_HE_PHY_CAP9_NOMIMAL_PKT_PADDING_16US:
+               default:
+                       set_fixed_ppe_val(pe_dur, PPE_16US);
+                       break;
+               }
+
+               return;
+       }
+
+       /*
+        * struct iwl_he_pkt_ext - QAM thresholds
+        * The required PPE is set via HE Capabilities IE, per Nss x BW x MCS
+        * The IE is organized in the following way:
+        * Support for Nss x BW (or RU) matrix:
+        *      (0=SISO, 1=MIMO2) x (0-20MHz, 1-40MHz, 2-80MHz, 3-160MHz)
+        * Each entry contains 2 QAM thresholds for 8us and 16us:
+        *      0=BPSK, 1=QPSK, 2=16QAM, 3=64QAM, 4=256QAM, 5=1024QAM, 6=RES, 7=NONE
+        * i.e. QAM_th1 < QAM_th2 such if TX uses QAM_tx:
+        *      QAM_tx < QAM_th1            --> PPE=0us
+        *      QAM_th1 <= QAM_tx < QAM_th2 --> PPE=8us
+        *      QAM_th2 <= QAM_tx           --> PPE=16us
+        * @pkt_ext_qam_th: QAM thresholds
+        *      For each Nss/Bw define 2 QAM thrsholds (0..5)
+        *      For rates below the low_th, no need for PPE
+        *      For rates between low_th and high_th, need 8us PPE
+        *      For rates equal or higher then the high_th, need 16us PPE
+        *      Nss (0-siso, 1-mimo2) x BW (0-20MHz, 1-40MHz, 2-80MHz, 3-160MHz) x
+        *              (0-low_th, 1-high_th)
+        */
+       u8 pkt_ext_qam_th[WRS_SS_MAX][CHNL_BW_MAX][QAM_THR_MAX];
+
+       /* If PPE Thresholds exist, parse them into a FW-familiar format. */
+       u8 nss = (sta->he_cap.ppe_thres[0] & IEEE80211_PPE_THRES_NSS_MASK) + 1;
+       u8 ru_index_bitmap = u32_get_bits(sta->he_cap.ppe_thres[0],
+                                         IEEE80211_PPE_THRES_RU_INDEX_BITMASK_MASK);
+       u8 *ppe = &sta->he_cap.ppe_thres[0];
+       u8 ppe_pos_bit = 7; /* Starting after PPE header */
+       u8 bw, ss, mcs, constellation;
+
+       if (nss > WRS_SS_MAX)
+               nss = WRS_SS_MAX;
+
+       for (ss = 0; ss < nss; ss++) {
+               u8 ru_index_tmp = ru_index_bitmap << 1;
+
+               for (bw = 0; bw <= cl_hw->bw; bw++) {
+                       ru_index_tmp >>= 1;
+                       if (!(ru_index_tmp & 1))
+                               continue;
+
+                       pkt_ext_qam_th[ss][bw][QAM_THR_2] = get_ppe_val(ppe, ppe_pos_bit);
+                       ppe_pos_bit += IEEE80211_PPE_THRES_INFO_PPET_SIZE;
+                       pkt_ext_qam_th[ss][bw][QAM_THR_1] = get_ppe_val(ppe, ppe_pos_bit);
+                       ppe_pos_bit += IEEE80211_PPE_THRES_INFO_PPET_SIZE;
+               }
+       }
+
+       /* Reset PE duration before filling it */
+       memset(pe_dur, 0, CHNL_BW_MAX * WRS_MCS_MAX_HE);
+
+       for (ss = 0; ss < nss; ss++) {
+               for (bw = 0; bw <= cl_hw->bw; bw++) {
+                       for (mcs = 0; mcs < WRS_MCS_MAX_HE; mcs++) {
+                               constellation = mcs_to_constellation[mcs];
+
+                               if (constellation < pkt_ext_qam_th[ss][bw][QAM_THR_1])
+                                       pe_dur[bw][mcs] |= (PPE_0US << (ss * 2));
+                               else if (constellation < pkt_ext_qam_th[ss][bw][QAM_THR_2])
+                                       pe_dur[bw][mcs] |= (PPE_8US << (ss * 2));
+                               else
+                                       pe_dur[bw][mcs] |= (PPE_16US << (ss * 2));
+                       }
+               }
+       }
+}