1// SPDX-License-Identifier: ISC
2/* Copyright (C) 2023 MediaTek Inc. */
3
4#include "mt76_connac.h"
5#include "mt76_connac3_mac.h"
6#include "dma.h"
7
8#define HE_BITS(f) cpu_to_le16(IEEE80211_RADIOTAP_HE_##f)
9#define HE_PREP(f, m, v) le16_encode_bits(le32_get_bits(v, MT_CRXV_HE_##m),\
10 IEEE80211_RADIOTAP_HE_##f)
11
12static void
13mt76_connac3_mac_decode_he_radiotap_ru(struct mt76_rx_status *status,
14 struct ieee80211_radiotap_he *he,
15 __le32 *rxv)
16{
17 u32 ru = le32_get_bits(v: rxv[0], MT_PRXV_HE_RU_ALLOC), offs = 0;
18
19 status->bw = RATE_INFO_BW_HE_RU;
20
21 switch (ru) {
22 case 0 ... 36:
23 status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_26;
24 offs = ru;
25 break;
26 case 37 ... 52:
27 status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_52;
28 offs = ru - 37;
29 break;
30 case 53 ... 60:
31 status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_106;
32 offs = ru - 53;
33 break;
34 case 61 ... 64:
35 status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_242;
36 offs = ru - 61;
37 break;
38 case 65 ... 66:
39 status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_484;
40 offs = ru - 65;
41 break;
42 case 67:
43 status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_996;
44 break;
45 case 68:
46 status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_2x996;
47 break;
48 }
49
50 he->data1 |= HE_BITS(DATA1_BW_RU_ALLOC_KNOWN);
51 he->data2 |= HE_BITS(DATA2_RU_OFFSET_KNOWN) |
52 le16_encode_bits(v: offs,
53 field: IEEE80211_RADIOTAP_HE_DATA2_RU_OFFSET);
54}
55
56#define MU_PREP(f, v) le16_encode_bits(v, IEEE80211_RADIOTAP_HE_MU_##f)
57static void
58mt76_connac3_mac_decode_he_mu_radiotap(struct sk_buff *skb, __le32 *rxv)
59{
60 struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
61 static const struct ieee80211_radiotap_he_mu mu_known = {
62 .flags1 = HE_BITS(MU_FLAGS1_SIG_B_MCS_KNOWN) |
63 HE_BITS(MU_FLAGS1_SIG_B_DCM_KNOWN) |
64 HE_BITS(MU_FLAGS1_CH1_RU_KNOWN) |
65 HE_BITS(MU_FLAGS1_SIG_B_SYMS_USERS_KNOWN),
66 .flags2 = HE_BITS(MU_FLAGS2_BW_FROM_SIG_A_BW_KNOWN),
67 };
68 struct ieee80211_radiotap_he_mu *he_mu;
69
70 status->flag |= RX_FLAG_RADIOTAP_HE_MU;
71
72 he_mu = skb_push(skb, len: sizeof(mu_known));
73 memcpy(he_mu, &mu_known, sizeof(mu_known));
74
75 he_mu->flags1 |= MU_PREP(FLAGS1_SIG_B_MCS, status->rate_idx);
76 if (status->he_dcm)
77 he_mu->flags1 |= MU_PREP(FLAGS1_SIG_B_DCM, status->he_dcm);
78
79 he_mu->flags2 |= MU_PREP(FLAGS2_BW_FROM_SIG_A_BW, status->bw) |
80 MU_PREP(FLAGS2_SIG_B_SYMS_USERS,
81 le32_get_bits(rxv[4], MT_CRXV_HE_NUM_USER));
82
83 he_mu->ru_ch1[0] = le32_get_bits(v: rxv[16], MT_CRXV_HE_RU0) & 0xff;
84
85 if (status->bw >= RATE_INFO_BW_40) {
86 he_mu->flags1 |= HE_BITS(MU_FLAGS1_CH2_RU_KNOWN);
87 he_mu->ru_ch2[0] = le32_get_bits(v: rxv[16], MT_CRXV_HE_RU1) & 0xff;
88 }
89
90 if (status->bw >= RATE_INFO_BW_80) {
91 u32 ru_h, ru_l;
92
93 he_mu->ru_ch1[1] = le32_get_bits(v: rxv[16], MT_CRXV_HE_RU2) & 0xff;
94
95 ru_l = le32_get_bits(v: rxv[16], MT_CRXV_HE_RU3_L);
96 ru_h = le32_get_bits(v: rxv[17], MT_CRXV_HE_RU3_H) & 0x7;
97 he_mu->ru_ch2[1] = (u8)(ru_l | ru_h << 4);
98 }
99}
100
101void mt76_connac3_mac_decode_he_radiotap(struct sk_buff *skb, __le32 *rxv,
102 u8 mode)
103{
104 struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
105 static const struct ieee80211_radiotap_he known = {
106 .data1 = HE_BITS(DATA1_DATA_MCS_KNOWN) |
107 HE_BITS(DATA1_DATA_DCM_KNOWN) |
108 HE_BITS(DATA1_STBC_KNOWN) |
109 HE_BITS(DATA1_CODING_KNOWN) |
110 HE_BITS(DATA1_LDPC_XSYMSEG_KNOWN) |
111 HE_BITS(DATA1_DOPPLER_KNOWN) |
112 HE_BITS(DATA1_SPTL_REUSE_KNOWN) |
113 HE_BITS(DATA1_BSS_COLOR_KNOWN),
114 .data2 = HE_BITS(DATA2_GI_KNOWN) |
115 HE_BITS(DATA2_TXBF_KNOWN) |
116 HE_BITS(DATA2_PE_DISAMBIG_KNOWN) |
117 HE_BITS(DATA2_TXOP_KNOWN),
118 };
119 u32 ltf_size = le32_get_bits(v: rxv[4], MT_CRXV_HE_LTF_SIZE) + 1;
120 struct ieee80211_radiotap_he *he;
121
122 status->flag |= RX_FLAG_RADIOTAP_HE;
123
124 he = skb_push(skb, len: sizeof(known));
125 memcpy(he, &known, sizeof(known));
126
127 he->data3 = HE_PREP(DATA3_BSS_COLOR, BSS_COLOR, rxv[9]) |
128 HE_PREP(DATA3_LDPC_XSYMSEG, LDPC_EXT_SYM, rxv[4]);
129 he->data4 = HE_PREP(DATA4_SU_MU_SPTL_REUSE, SR_MASK, rxv[13]);
130 he->data5 = HE_PREP(DATA5_PE_DISAMBIG, PE_DISAMBIG, rxv[5]) |
131 le16_encode_bits(v: ltf_size,
132 field: IEEE80211_RADIOTAP_HE_DATA5_LTF_SIZE);
133 if (le32_to_cpu(rxv[0]) & MT_PRXV_TXBF)
134 he->data5 |= HE_BITS(DATA5_TXBF);
135 he->data6 = HE_PREP(DATA6_TXOP, TXOP_DUR, rxv[9]) |
136 HE_PREP(DATA6_DOPPLER, DOPPLER, rxv[9]);
137
138 switch (mode) {
139 case MT_PHY_TYPE_HE_SU:
140 he->data1 |= HE_BITS(DATA1_FORMAT_SU) |
141 HE_BITS(DATA1_UL_DL_KNOWN) |
142 HE_BITS(DATA1_BEAM_CHANGE_KNOWN) |
143 HE_BITS(DATA1_BW_RU_ALLOC_KNOWN);
144
145 he->data3 |= HE_PREP(DATA3_BEAM_CHANGE, BEAM_CHNG, rxv[8]) |
146 HE_PREP(DATA3_UL_DL, UPLINK, rxv[5]);
147 break;
148 case MT_PHY_TYPE_HE_EXT_SU:
149 he->data1 |= HE_BITS(DATA1_FORMAT_EXT_SU) |
150 HE_BITS(DATA1_UL_DL_KNOWN) |
151 HE_BITS(DATA1_BW_RU_ALLOC_KNOWN);
152
153 he->data3 |= HE_PREP(DATA3_UL_DL, UPLINK, rxv[5]);
154 break;
155 case MT_PHY_TYPE_HE_MU:
156 he->data1 |= HE_BITS(DATA1_FORMAT_MU) |
157 HE_BITS(DATA1_UL_DL_KNOWN);
158
159 he->data3 |= HE_PREP(DATA3_UL_DL, UPLINK, rxv[5]);
160 he->data4 |= HE_PREP(DATA4_MU_STA_ID, MU_AID, rxv[8]);
161
162 mt76_connac3_mac_decode_he_radiotap_ru(status, he, rxv);
163 mt76_connac3_mac_decode_he_mu_radiotap(skb, rxv);
164 break;
165 case MT_PHY_TYPE_HE_TB:
166 he->data1 |= HE_BITS(DATA1_FORMAT_TRIG) |
167 HE_BITS(DATA1_SPTL_REUSE2_KNOWN) |
168 HE_BITS(DATA1_SPTL_REUSE3_KNOWN) |
169 HE_BITS(DATA1_SPTL_REUSE4_KNOWN);
170
171 he->data4 |= HE_PREP(DATA4_TB_SPTL_REUSE1, SR_MASK, rxv[13]) |
172 HE_PREP(DATA4_TB_SPTL_REUSE2, SR1_MASK, rxv[13]) |
173 HE_PREP(DATA4_TB_SPTL_REUSE3, SR2_MASK, rxv[13]) |
174 HE_PREP(DATA4_TB_SPTL_REUSE4, SR3_MASK, rxv[13]);
175
176 mt76_connac3_mac_decode_he_radiotap_ru(status, he, rxv);
177 break;
178 default:
179 break;
180 }
181}
182EXPORT_SYMBOL_GPL(mt76_connac3_mac_decode_he_radiotap);
183

source code of linux/drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c