wifi6 Linux driver - 6 - mac80211 - HE - 2

收錄在 Ameba 的 100 篇


--
續前篇: wifi6 iwlwifi mac80211 linux driver - 5


我們開始更換 mac80211 讓 iwlwifi 可以 compile, 今天遇到的問題是:
struct ieee80211_sband_iftype_data error.
和這個和 cfg80211: Add support for HE patch 所解的問題相同

HE 的說明, 可以參考這篇:  wifi6 - HE

/**
 * struct ieee80211_he_cap_elem - HE capabilities element
 *
 * This structure is the "HE capabilities element" fixed fields as
 * described in P802.11ax_D2.0 section 9.4.2.237.2 and 9.4.2.237.3
 */
struct ieee80211_he_cap_elem {
 u8 mac_cap_info[6];
 u8 phy_cap_info[11];
} __packed;
(和原先 patch 相比, 在新的 v5.4 linux kernel, 長度有增長 )

MAC : B0-B47 : 6 bytes

PHY : B0-B87 - 11 bytes




+#define IEEE80211_TX_RX_MCS_NSS_DESC_MAX_LEN 5

HE MCS support

+/**
+ * enum ieee80211_he_mcs_support - HE MCS support definitions
+ * @IEEE80211_HE_MCS_SUPPORT_0_7: MCSes 0-7 are supported for the
+ * number of streams
+ * @IEEE80211_HE_MCS_SUPPORT_0_9: MCSes 0-9 are supported
+ * @IEEE80211_HE_MCS_SUPPORT_0_11: MCSes 0-11 are supported
+ * @IEEE80211_HE_MCS_NOT_SUPPORTED: This number of streams isn't supported
+ *
+ * These definitions are used in each 2-bit subfield of the rx_mcs_*
+ * and tx_mcs_* fields of &struct ieee80211_he_mcs_nss_supp, which are
+ * both split into 8 subfields by number of streams. These values indicate
+ * which MCSes are supported for the number of streams the value appears
+ * for.
+ */
+enum ieee80211_he_mcs_support {
+ IEEE80211_HE_MCS_SUPPORT_0_7 = 0,
+ IEEE80211_HE_MCS_SUPPORT_0_9 = 1,
+ IEEE80211_HE_MCS_SUPPORT_0_11 = 2,
+ IEEE80211_HE_MCS_NOT_SUPPORTED = 3,
+};

TX/RX HE MCS NSS support

+/**
+ * struct ieee80211_he_mcs_nss_supp - HE Tx/Rx HE MCS NSS Support Field
+ *
+ * This structure holds the data required for the Tx/Rx HE MCS NSS Support Field
+ * described in P802.11ax_D2.0 section 9.4.2.237.4
+ *
+ * @rx_mcs_80: Rx MCS map 2 bits for each stream, total 8 streams, for channel
+ *     widths less than 80MHz.
+ * @tx_mcs_80: Tx MCS map 2 bits for each stream, total 8 streams, for channel
+ *     widths less than 80MHz.
+ * @rx_mcs_160: Rx MCS map 2 bits for each stream, total 8 streams, for channel
+ *     width 160MHz.
+ * @tx_mcs_160: Tx MCS map 2 bits for each stream, total 8 streams, for channel
+ *     width 160MHz.
+ * @rx_mcs_80p80: Rx MCS map 2 bits for each stream, total 8 streams, for
+ *     channel width 80p80MHz.
+ * @tx_mcs_80p80: Tx MCS map 2 bits for each stream, total 8 streams, for
+ *     channel width 80p80MHz.
+ */
+struct ieee80211_he_mcs_nss_supp {
+ __le16 rx_mcs_80;
+ __le16 tx_mcs_80;
+ __le16 rx_mcs_160;
+ __le16 tx_mcs_160;
+ __le16 rx_mcs_80p80;
+ __le16 tx_mcs_80p80;
+} __packed;

HE operation element

2.4G : HT + HE
5G : HT + VHT + HE
6G: HE

+/**
+ * struct ieee80211_he_operation - HE capabilities element
+ *
+ * This structure is the "HE operation element" fields as
+ * described in P802.11ax_D2.0 section 9.4.2.238
+ */
+struct ieee80211_he_operation {
+ __le32 he_oper_params;
+ __le16 he_mcs_nss_set;
+ /* Optional 0,1,3 or 4 bytes: depends on @he_oper_params */
+ u8 optional[0];
+} __packed;



HE Operation Parameters : 4 bytes


association 用 NL80211_CMD_NEW_STATION 時, 帶 NL80211_ATTR_HE_CAPABILITY

+ * @NL80211_ATTR_HE_CAPABILITY: HE Capability information element (from
+ * association request when used with NL80211_CMD_NEW_STATION). Can be set
+ * only if %NL80211_STA_FLAG_WME is set.

HT/VHT 需要  QoS, 沒有的話就降成 g mode, 不設定 HT/VHT,
但 HE 不行, 還是得報錯誤

  if (!(params.sta_flags_set & BIT(NL80211_STA_FLAG_WME))) {
   params.ht_capa = NULL;
   params.vht_capa = NULL;
+
+  /* HE requires WME */
+  if (params.he_capa_len)
+   return -EINVAL;
  }

特別的是, 多了 RU 的分配, 存在 he_ru_alloc

+static u32 cfg80211_calculate_bitrate_he(struct rate_info *rate)
+{
+#define SCALE 2048
+ u16 mcs_divisors[12] = {
+  34133, /* 16.666666... */
+  17067, /*  8.333333... */
+  11378, /*  5.555555... */
+   8533, /*  4.166666... */
+   5689, /*  2.777777... */
+   4267, /*  2.083333... */
+   3923, /*  1.851851... */
+   3413, /*  1.666666... */
+   2844, /*  1.388888... */
+   2560, /*  1.250000... */
+   2276, /*  1.111111... */
+   2048, /*  1.000000... */
+ };
+ u32 rates_160M[3] = { 960777777, 907400000, 816666666 };
+ u32 rates_969[3] =  { 480388888, 453700000, 408333333 };
+ u32 rates_484[3] =  { 229411111, 216666666, 195000000 };
+ u32 rates_242[3] =  { 114711111, 108333333,  97500000 };
+ u32 rates_106[3] =  {  40000000,  37777777,  34000000 };
+ u32 rates_52[3]  =  {  18820000,  17777777,  16000000 };
+ u32 rates_26[3]  =  {   9411111,   8888888,   8000000 };
+ u64 tmp;
+ u32 result;
+
+ if (WARN_ON_ONCE(rate->mcs > 11))
+  return 0;
+
+ if (WARN_ON_ONCE(rate->he_gi > NL80211_RATE_INFO_HE_GI_3_2))
+  return 0;
+ if (WARN_ON_ONCE(rate->he_ru_alloc >
+    NL80211_RATE_INFO_HE_RU_ALLOC_2x996))
+  return 0;
+ if (WARN_ON_ONCE(rate->nss < 1 || rate->nss > 8))
+  return 0;
+
+ if (rate->bw == RATE_INFO_BW_160)
+  result = rates_160M[rate->he_gi];
+ else if (rate->bw == RATE_INFO_BW_80 ||
+   (rate->bw == RATE_INFO_BW_HE_RU &&
+    rate->he_ru_alloc == NL80211_RATE_INFO_HE_RU_ALLOC_996))
+  result = rates_969[rate->he_gi];
+ else if (rate->bw == RATE_INFO_BW_40 ||
+   (rate->bw == RATE_INFO_BW_HE_RU &&
+    rate->he_ru_alloc == NL80211_RATE_INFO_HE_RU_ALLOC_484))
+  result = rates_484[rate->he_gi];
+ else if (rate->bw == RATE_INFO_BW_20 ||
+   (rate->bw == RATE_INFO_BW_HE_RU &&
+    rate->he_ru_alloc == NL80211_RATE_INFO_HE_RU_ALLOC_242))
+  result = rates_242[rate->he_gi];
+ else if (rate->bw == RATE_INFO_BW_HE_RU &&
+   rate->he_ru_alloc == NL80211_RATE_INFO_HE_RU_ALLOC_106)
+  result = rates_106[rate->he_gi];
+ else if (rate->bw == RATE_INFO_BW_HE_RU &&
+   rate->he_ru_alloc == NL80211_RATE_INFO_HE_RU_ALLOC_52)
+  result = rates_52[rate->he_gi];
+ else if (rate->bw == RATE_INFO_BW_HE_RU &&
+   rate->he_ru_alloc == NL80211_RATE_INFO_HE_RU_ALLOC_26)
+  result = rates_26[rate->he_gi];
+ else if (WARN(1, "invalid HE MCS: bw:%d, ru:%d\n",
+        rate->bw, rate->he_ru_alloc))
+  return 0;
+
+ /* now scale to the appropriate MCS */
+ tmp = result;
+ tmp *= SCALE;
+ do_div(tmp, mcs_divisors[rate->mcs]);
+ result = tmp;
+
+ /* and take NSS, DCM into account */
+ result = (result * rate->nss) / 8;
+ if (rate->he_dcm)
+  result /= 2;
+
+ return result;
+}
+





留言

熱門文章