1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3 * KUnit tests for TPE element handling
4 *
5 * Copyright (C) 2024 Intel Corporation
6 */
7 #include <kunit/test.h>
8 #include "../ieee80211_i.h"
9
10 MODULE_IMPORT_NS("EXPORTED_FOR_KUNIT_TESTING");
11
12 static struct ieee80211_channel chan6g_1 = {
13 .band = NL80211_BAND_6GHZ,
14 .center_freq = 5955,
15 };
16
17 static struct ieee80211_channel chan6g_33 = {
18 .band = NL80211_BAND_6GHZ,
19 .center_freq = 6115,
20 };
21
22 static struct ieee80211_channel chan6g_61 = {
23 .band = NL80211_BAND_6GHZ,
24 .center_freq = 6255,
25 };
26
27 static const struct subchan_test_case {
28 const char *desc;
29 struct cfg80211_chan_def c;
30 u8 n;
31 int expect;
32 } subchan_offset_cases[] = {
33 {
34 .desc = "identical 20 MHz",
35 .c.width = NL80211_CHAN_WIDTH_20,
36 .c.chan = &chan6g_1,
37 .c.center_freq1 = 5955,
38 .n = 1,
39 .expect = 0,
40 },
41 {
42 .desc = "identical 40 MHz",
43 .c.width = NL80211_CHAN_WIDTH_40,
44 .c.chan = &chan6g_1,
45 .c.center_freq1 = 5965,
46 .n = 2,
47 .expect = 0,
48 },
49 {
50 .desc = "identical 80+80 MHz",
51 /* not really is valid? doesn't matter for the test */
52 .c.width = NL80211_CHAN_WIDTH_80P80,
53 .c.chan = &chan6g_1,
54 .c.center_freq1 = 5985,
55 .c.center_freq2 = 6225,
56 .n = 16,
57 .expect = 0,
58 },
59 {
60 .desc = "identical 320 MHz",
61 .c.width = NL80211_CHAN_WIDTH_320,
62 .c.chan = &chan6g_1,
63 .c.center_freq1 = 6105,
64 .n = 16,
65 .expect = 0,
66 },
67 {
68 .desc = "lower 160 MHz of 320 MHz",
69 .c.width = NL80211_CHAN_WIDTH_320,
70 .c.chan = &chan6g_1,
71 .c.center_freq1 = 6105,
72 .n = 8,
73 .expect = 0,
74 },
75 {
76 .desc = "upper 160 MHz of 320 MHz",
77 .c.width = NL80211_CHAN_WIDTH_320,
78 .c.chan = &chan6g_61,
79 .c.center_freq1 = 6105,
80 .n = 8,
81 .expect = 8,
82 },
83 {
84 .desc = "upper 160 MHz of 320 MHz, go to 40",
85 .c.width = NL80211_CHAN_WIDTH_320,
86 .c.chan = &chan6g_61,
87 .c.center_freq1 = 6105,
88 .n = 2,
89 .expect = 8 + 4 + 2,
90 },
91 {
92 .desc = "secondary 80 above primary in 80+80 MHz",
93 /* not really is valid? doesn't matter for the test */
94 .c.width = NL80211_CHAN_WIDTH_80P80,
95 .c.chan = &chan6g_1,
96 .c.center_freq1 = 5985,
97 .c.center_freq2 = 6225,
98 .n = 4,
99 .expect = 0,
100 },
101 {
102 .desc = "secondary 80 below primary in 80+80 MHz",
103 /* not really is valid? doesn't matter for the test */
104 .c.width = NL80211_CHAN_WIDTH_80P80,
105 .c.chan = &chan6g_61,
106 .c.center_freq1 = 6225,
107 .c.center_freq2 = 5985,
108 .n = 4,
109 .expect = 4,
110 },
111 {
112 .desc = "secondary 80 below primary in 80+80 MHz, go to 20",
113 /* not really is valid? doesn't matter for the test */
114 .c.width = NL80211_CHAN_WIDTH_80P80,
115 .c.chan = &chan6g_61,
116 .c.center_freq1 = 6225,
117 .c.center_freq2 = 5985,
118 .n = 1,
119 .expect = 7,
120 },
121 };
122
123 KUNIT_ARRAY_PARAM_DESC(subchan_offset, subchan_offset_cases, desc);
124
subchan_offset(struct kunit * test)125 static void subchan_offset(struct kunit *test)
126 {
127 const struct subchan_test_case *params = test->param_value;
128 int offset;
129
130 KUNIT_ASSERT_EQ(test, cfg80211_chandef_valid(¶ms->c), true);
131
132 offset = ieee80211_calc_chandef_subchan_offset(¶ms->c, params->n);
133
134 KUNIT_EXPECT_EQ(test, params->expect, offset);
135 }
136
137 static const struct psd_reorder_test_case {
138 const char *desc;
139 struct cfg80211_chan_def ap, used;
140 struct ieee80211_parsed_tpe_psd psd, out;
141 } psd_reorder_cases[] = {
142 {
143 .desc = "no changes, 320 MHz",
144
145 .ap.width = NL80211_CHAN_WIDTH_320,
146 .ap.chan = &chan6g_1,
147 .ap.center_freq1 = 6105,
148
149 .used.width = NL80211_CHAN_WIDTH_320,
150 .used.chan = &chan6g_1,
151 .used.center_freq1 = 6105,
152
153 .psd.valid = true,
154 .psd.count = 16,
155 .psd.n = 8,
156 .psd.power = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 },
157
158 .out.valid = true,
159 .out.count = 16,
160 .out.n = 8,
161 .out.power = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 },
162 },
163 {
164 .desc = "no changes, 320 MHz, 160 MHz used, n=0",
165
166 .ap.width = NL80211_CHAN_WIDTH_320,
167 .ap.chan = &chan6g_1,
168 .ap.center_freq1 = 6105,
169
170 .used.width = NL80211_CHAN_WIDTH_160,
171 .used.chan = &chan6g_1,
172 .used.center_freq1 = 6025,
173
174 .psd.valid = true,
175 .psd.count = 16,
176 .psd.n = 0,
177 .psd.power = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, },
178
179 .out.valid = true,
180 .out.count = 8,
181 .out.n = 0,
182 .out.power = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, },
183 },
184 {
185 .desc = "320 MHz, HE is 80, used 160, all lower",
186
187 .ap.width = NL80211_CHAN_WIDTH_320,
188 .ap.chan = &chan6g_1,
189 .ap.center_freq1 = 6105,
190
191 .used.width = NL80211_CHAN_WIDTH_160,
192 .used.chan = &chan6g_1,
193 .used.center_freq1 = 6025,
194
195 .psd.valid = true,
196 .psd.count = 16,
197 .psd.n = 4,
198 .psd.power = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 },
199
200 .out.valid = true,
201 .out.count = 8,
202 .out.n = 4,
203 .out.power = { 0, 1, 2, 3, 4, 5, 6, 7, 127, 127, 127, 127, 127, 127, 127, 127},
204 },
205 {
206 .desc = "320 MHz, HE is 80, used 160, all upper",
207 /*
208 * EHT: | | | | | | | | | | | | | | | | |
209 * HE: | | | | |
210 * used: | | | | | | | | |
211 */
212
213 .ap.width = NL80211_CHAN_WIDTH_320,
214 .ap.chan = &chan6g_61,
215 .ap.center_freq1 = 6105,
216
217 .used.width = NL80211_CHAN_WIDTH_160,
218 .used.chan = &chan6g_61,
219 .used.center_freq1 = 6185,
220
221 .psd.valid = true,
222 .psd.count = 16,
223 .psd.n = 4,
224 .psd.power = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 },
225
226 .out.valid = true,
227 .out.count = 8,
228 .out.n = 4,
229 .out.power = { 12, 13, 14, 15, 0, 1, 2, 3, 127, 127, 127, 127, 127, 127, 127, 127},
230 },
231 {
232 .desc = "320 MHz, HE is 80, used 160, split",
233 /*
234 * EHT: | | | | | | | | | | | | | | | | |
235 * HE: | | | | |
236 * used: | | | | | | | | |
237 */
238
239 .ap.width = NL80211_CHAN_WIDTH_320,
240 .ap.chan = &chan6g_33,
241 .ap.center_freq1 = 6105,
242
243 .used.width = NL80211_CHAN_WIDTH_160,
244 .used.chan = &chan6g_33,
245 .used.center_freq1 = 6185,
246
247 .psd.valid = true,
248 .psd.count = 16,
249 .psd.n = 4,
250 .psd.power = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 },
251
252 .out.valid = true,
253 .out.count = 8,
254 .out.n = 4,
255 .out.power = { 0, 1, 2, 3, 12, 13, 14, 15, 127, 127, 127, 127, 127, 127, 127, 127},
256 },
257 };
258
259 KUNIT_ARRAY_PARAM_DESC(psd_reorder, psd_reorder_cases, desc);
260
psd_reorder(struct kunit * test)261 static void psd_reorder(struct kunit *test)
262 {
263 const struct psd_reorder_test_case *params = test->param_value;
264 struct ieee80211_parsed_tpe_psd tmp = params->psd;
265
266 KUNIT_ASSERT_EQ(test, cfg80211_chandef_valid(¶ms->ap), true);
267 KUNIT_ASSERT_EQ(test, cfg80211_chandef_valid(¶ms->used), true);
268
269 ieee80211_rearrange_tpe_psd(&tmp, ¶ms->ap, ¶ms->used);
270 KUNIT_EXPECT_MEMEQ(test, &tmp, ¶ms->out, sizeof(tmp));
271 }
272
273 static struct kunit_case tpe_test_cases[] = {
274 KUNIT_CASE_PARAM(subchan_offset, subchan_offset_gen_params),
275 KUNIT_CASE_PARAM(psd_reorder, psd_reorder_gen_params),
276 {}
277 };
278
279 static struct kunit_suite tpe = {
280 .name = "mac80211-tpe",
281 .test_cases = tpe_test_cases,
282 };
283
284 kunit_test_suite(tpe);
285