forked from ~ljy/RK356X_SDK_RELEASE

hc
2024-05-10 cde9070d9970eef1f7ec2360586c802a16230ad8
kernel/drivers/net/wireless/rockchip_wlan/cywdhd/bcmdhd/bcmwifi_channels.c
....@@ -1,17 +1,18 @@
1
-/* SPDX-License-Identifier: GPL-2.0 */
21 /*
32 * Misc utility routines used by kernel or app-level.
43 * Contents are wifi-specific, used by any kernel or app-level
54 * software that might want wifi things as it grows.
65 *
7
- * Copyright (C) 1999-2019, Broadcom Corporation
8
- *
6
+ * Portions of this code are copyright (c) 2022 Cypress Semiconductor Corporation
7
+ *
8
+ * Copyright (C) 1999-2017, Broadcom Corporation
9
+ *
910 * Unless you and Broadcom execute a separate written software license
1011 * agreement governing use of this software, this software is licensed to you
1112 * under the terms of the GNU General Public License version 2 (the "GPL"),
1213 * available at http://www.broadcom.com/licenses/GPLv2.php, with the
1314 * following added to such license:
14
- *
15
+ *
1516 * As a special exception, the copyright holders of this software give you
1617 * permission to link this software with independent modules, and to copy and
1718 * distribute the resulting executable under terms of your choice, provided that
....@@ -19,7 +20,7 @@
1920 * the license of that module. An independent module is a module which is not
2021 * derived from this software. The special exception does not apply to any
2122 * modifications of the software.
22
- *
23
+ *
2324 * Notwithstanding the above, under no circumstances may you combine this
2425 * software in any way with any other Broadcom software provided under a license
2526 * other than the GPL, without Broadcom's express prior written consent.
....@@ -27,7 +28,7 @@
2728 *
2829 * <<Broadcom-WL-IPTag/Open:>>
2930 *
30
- * $Id: bcmwifi_channels.c 309193 2012-01-19 00:03:57Z $
31
+ * $Id: bcmwifi_channels.c 695288 2017-04-19 17:20:39Z $
3132 */
3233
3334 #include <bcm_cfg.h>
....@@ -44,19 +45,21 @@
4445 #include <ctype.h>
4546 #ifndef ASSERT
4647 #define ASSERT(exp)
47
-#endif
48
+#endif // endif
4849 #endif /* BCMDRIVER */
4950
5051 #include <bcmwifi_channels.h>
5152
5253 #if defined(WIN32) && (defined(BCMDLL) || defined(WLMDLL))
5354 #include <bcmstdlib.h> /* For wl/exe/GNUmakefile.brcm_wlu and GNUmakefile.wlm_dll */
54
-#endif
55
+#endif // endif
5556
56
-/* Definitions for D11AC capable Chanspec type */
57
+#include <802.11.h>
5758
58
-/* Chanspec ASCII representation with 802.11ac capability:
59
- * [<band> 'g'] <channel> ['/'<bandwidth> [<ctl-sideband>]['/'<1st80channel>'-'<2nd80channel>]]
59
+/* Definitions for D11AC capable (80MHz+) Chanspec type */
60
+
61
+/* Chanspec ASCII representation:
62
+ * [<band> 'g'] <channel> ['/'<bandwidth> [<primary-sideband>]['/'<1st80channel>'-'<2nd80channel>]]
6063 *
6164 * <band>:
6265 * (optional) 2, 3, 4, 5 for 2.4GHz, 3GHz, 4GHz, and 5GHz respectively.
....@@ -82,18 +85,18 @@
8285 * <1st80Channel>:
8386 * <2nd80Channel>:
8487 * Required for 80+80, otherwise not allowed.
85
- * Specifies the center channel of the first and second 80MHz band.
88
+ * Specifies the center channel of the primary and secondary 80MHz band.
8689 *
8790 * In its simplest form, it is a 20MHz channel number, with the implied band
8891 * of 2.4GHz if channel number <= 14, and 5GHz otherwise.
8992 *
9093 * To allow for backward compatibility with scripts, the old form for
91
- * 40MHz channels is also allowed: <channel><ctl-sideband>
94
+ * 40MHz channels is also allowed: <channel><primary-sideband>
9295 *
9396 * <channel>:
9497 * primary channel of 40MHz, channel <= 14 is 2GHz, otherwise 5GHz
95
- * <ctl-sideband>:
96
- * "U" for upper, "L" for lower (or lower case "u" "l")
98
+ * <primary-sideband>:
99
+ * "U" for upper, "L" for lower (or lower case "u" "l")
97100 *
98101 * 5 GHz Examples:
99102 * Chanspec BW Center Ch Channel Range Primary Ch
....@@ -130,11 +133,7 @@
130133 "80",
131134 "160",
132135 "80+80",
133
-#ifdef WL11ULB
134
- "2.5"
135
-#else /* WL11ULB */
136136 "na"
137
-#endif /* WL11ULB */
138137 };
139138
140139 static const uint8 wf_chspec_bw_mhz[] =
....@@ -145,13 +144,13 @@
145144
146145 /* 40MHz channels in 5GHz band */
147146 static const uint8 wf_5g_40m_chans[] =
148
-{38, 46, 54, 62, 102, 110, 118, 126, 134, 142, 151, 159};
147
+{38, 46, 54, 62, 102, 110, 118, 126, 134, 142, 151, 159, 167, 175};
149148 #define WF_NUM_5G_40M_CHANS \
150149 (sizeof(wf_5g_40m_chans)/sizeof(uint8))
151150
152151 /* 80MHz channels in 5GHz band */
153152 static const uint8 wf_5g_80m_chans[] =
154
-{42, 58, 106, 122, 138, 155};
153
+{42, 58, 106, 122, 138, 155, 171};
155154 #define WF_NUM_5G_80M_CHANS \
156155 (sizeof(wf_5g_80m_chans)/sizeof(uint8))
157156
....@@ -161,10 +160,82 @@
161160 #define WF_NUM_5G_160M_CHANS \
162161 (sizeof(wf_5g_160m_chans)/sizeof(uint8))
163162
163
+/* Based on IEEE 802.11ax D6.1 */
164
+/* 40MHz channels in 6GHz band */
165
+static const uint8 wf_6g_40m_chans[] =
166
+{3, 11, 19, 27, 35, 43, 51, 59, 67, 75, 83, 91, 99,
167
+107, 115, 123, 131, 139, 147, 155, 163, 171, 179,
168
+187, 195, 203, 211, 219, 227};
169
+#define WF_NUM_6G_40M_CHANS \
170
+ (sizeof(wf_6g_40m_chans)/sizeof(uint8))
164171
165
-/* convert bandwidth from chanspec to MHz */
166
-static uint
167
-bw_chspec_to_mhz(chanspec_t chspec)
172
+/* 80MHz channels in 6GHz band */
173
+static const uint8 wf_6g_80m_chans[] =
174
+{7, 23, 39, 55, 71, 87, 103, 119, 135, 151, 167, 183,
175
+199, 215};
176
+#define WF_NUM_6G_80M_CHANS \
177
+ (sizeof(wf_6g_80m_chans)/sizeof(uint8))
178
+
179
+/* 160MHz channels in 6GHz band */
180
+static const uint8 wf_6g_160m_chans[] =
181
+{15, 47, 79, 111, 143, 175, 207};
182
+#define WF_NUM_6G_160M_CHANS \
183
+ (sizeof(wf_6g_160m_chans)/sizeof(uint8))
184
+
185
+/* 6GHz PSC channels */
186
+uint8 wf_6g_psc_chans[] =
187
+{5, 21, 37, 53, 69, 85, 101, 117, 133, 149, 165, 181,
188
+197, 213, 229};
189
+#define WF_NUM_6G_PSC_CHANS \
190
+ (sizeof(wf_6g_psc_chans)/sizeof(uint8))
191
+
192
+/* opclass and channel information for US. Table E-1 */
193
+static const uint16 opclass_data[] = {
194
+ (WL_CHANSPEC_BAND_5G |((WL_CHANSPEC_BW_20)&WL_CHANSPEC_BW_MASK)),
195
+ (WL_CHANSPEC_BAND_5G |((WL_CHANSPEC_BW_20)&WL_CHANSPEC_BW_MASK)),
196
+ (WL_CHANSPEC_BAND_5G |((WL_CHANSPEC_BW_20)&WL_CHANSPEC_BW_MASK)),
197
+ (WL_CHANSPEC_BAND_5G |((WL_CHANSPEC_BW_20)&WL_CHANSPEC_BW_MASK)),
198
+ (WL_CHANSPEC_BAND_5G |((WL_CHANSPEC_BW_20)&WL_CHANSPEC_BW_MASK)),
199
+ (WL_CHANSPEC_BAND_5G |((WL_CHANSPEC_BW_5)&WL_CHANSPEC_BW_MASK)),
200
+ (WL_CHANSPEC_BAND_5G |((WL_CHANSPEC_BW_5)&WL_CHANSPEC_BW_MASK)),
201
+ (WL_CHANSPEC_BAND_5G |((WL_CHANSPEC_BW_10)&WL_CHANSPEC_BW_MASK)),
202
+ (WL_CHANSPEC_BAND_5G |((WL_CHANSPEC_BW_10)&WL_CHANSPEC_BW_MASK)),
203
+ (WL_CHANSPEC_BAND_5G |((WL_CHANSPEC_BW_20)&WL_CHANSPEC_BW_MASK)),
204
+ (WL_CHANSPEC_BAND_5G |((WL_CHANSPEC_BW_20)&WL_CHANSPEC_BW_MASK)),
205
+ (WL_CHANSPEC_BAND_2G |((WL_CHANSPEC_BW_20)&WL_CHANSPEC_BW_MASK)),
206
+ (WL_CHANSPEC_BAND_3G |((WL_CHANSPEC_BW_20)&WL_CHANSPEC_BW_MASK)),
207
+ (WL_CHANSPEC_BAND_3G |((WL_CHANSPEC_BW_10)&WL_CHANSPEC_BW_MASK)),
208
+ (WL_CHANSPEC_BAND_3G |((WL_CHANSPEC_BW_5)&WL_CHANSPEC_BW_MASK)),
209
+ (WL_CHANSPEC_BAND_5G |((WL_CHANSPEC_BW_5)&WL_CHANSPEC_BW_MASK)),
210
+ (WL_CHANSPEC_BAND_5G |((WL_CHANSPEC_BW_10)&WL_CHANSPEC_BW_MASK)),
211
+ (WL_CHANSPEC_BAND_5G |((WL_CHANSPEC_BW_20)&WL_CHANSPEC_BW_MASK)),
212
+ 0,
213
+ 0,
214
+ 0,
215
+ (WL_CHANSPEC_BAND_5G |((WL_CHANSPEC_BW_40)&WL_CHANSPEC_BW_MASK)|WL_CHANSPEC_CTL_SB_LOWER),
216
+ (WL_CHANSPEC_BAND_5G |((WL_CHANSPEC_BW_40)&WL_CHANSPEC_BW_MASK)|WL_CHANSPEC_CTL_SB_LOWER),
217
+ (WL_CHANSPEC_BAND_5G |((WL_CHANSPEC_BW_40)&WL_CHANSPEC_BW_MASK)|WL_CHANSPEC_CTL_SB_LOWER),
218
+ (WL_CHANSPEC_BAND_5G |((WL_CHANSPEC_BW_40)&WL_CHANSPEC_BW_MASK)|WL_CHANSPEC_CTL_SB_LOWER),
219
+ (WL_CHANSPEC_BAND_5G |((WL_CHANSPEC_BW_40)&WL_CHANSPEC_BW_MASK)|WL_CHANSPEC_CTL_SB_LOWER),
220
+ (WL_CHANSPEC_BAND_5G |((WL_CHANSPEC_BW_40)&WL_CHANSPEC_BW_MASK)|WL_CHANSPEC_CTL_SB_UPPER),
221
+ (WL_CHANSPEC_BAND_5G |((WL_CHANSPEC_BW_40)&WL_CHANSPEC_BW_MASK)|WL_CHANSPEC_CTL_SB_UPPER),
222
+ (WL_CHANSPEC_BAND_5G |((WL_CHANSPEC_BW_40)&WL_CHANSPEC_BW_MASK)|WL_CHANSPEC_CTL_SB_UPPER),
223
+ (WL_CHANSPEC_BAND_5G |((WL_CHANSPEC_BW_40)&WL_CHANSPEC_BW_MASK)|WL_CHANSPEC_CTL_SB_UPPER),
224
+ (WL_CHANSPEC_BAND_5G |((WL_CHANSPEC_BW_40)&WL_CHANSPEC_BW_MASK)|WL_CHANSPEC_CTL_SB_UPPER),
225
+ (WL_CHANSPEC_BAND_2G |((WL_CHANSPEC_BW_40)&WL_CHANSPEC_BW_MASK)|WL_CHANSPEC_CTL_SB_LOWER),
226
+ (WL_CHANSPEC_BAND_2G |((WL_CHANSPEC_BW_40)&WL_CHANSPEC_BW_MASK)|WL_CHANSPEC_CTL_SB_UPPER),
227
+};
228
+
229
+/**
230
+ * Return the chanspec bandwidth in MHz
231
+ * Bandwidth of 160 MHz will be returned for 80+80MHz chanspecs.
232
+ *
233
+ * @param chspec chanspec_t
234
+ *
235
+ * @return bandwidth of chspec in MHz units
236
+ */
237
+uint
238
+wf_bw_chspec_to_mhz(chanspec_t chspec)
168239 {
169240 uint bw;
170241
....@@ -194,34 +265,34 @@
194265 return (uint8)(center_ch - center_chan_to_edge(bw));
195266 }
196267
197
-/* return side band number given center channel and control channel
268
+/* return side band number given center channel and primary20 channel
198269 * return -1 on error
199270 */
200271 static int
201
-channel_to_sb(uint center_ch, uint ctl_ch, uint bw)
272
+channel_to_sb(uint center_ch, uint primary_ch, uint bw)
202273 {
203274 uint lowest = channel_low_edge(center_ch, bw);
204275 uint sb;
205276
206
- if ((ctl_ch - lowest) % 4) {
207
- /* bad ctl channel, not mult 4 */
277
+ if ((primary_ch - lowest) % 4) {
278
+ /* bad primary channel, not mult 4 */
208279 return -1;
209280 }
210281
211
- sb = ((ctl_ch - lowest) / 4);
282
+ sb = ((primary_ch - lowest) / 4);
212283
213284 /* sb must be a index to a 20MHz channel in range */
214285 if (sb >= (bw / 20)) {
215
- /* ctl_ch must have been too high for the center_ch */
286
+ /* primary_ch must have been too high for the center_ch */
216287 return -1;
217288 }
218289
219
- return sb;
290
+ return (int)sb;
220291 }
221292
222
-/* return control channel given center channel and side band */
293
+/* return primary20 channel given center channel and side band */
223294 static uint8
224
-channel_to_ctl_chan(uint center_ch, uint bw, uint sb)
295
+channel_to_primary20_chan(uint center_ch, uint bw, uint sb)
225296 {
226297 return (uint8)(channel_low_edge(center_ch, bw) + sb * 4);
227298 }
....@@ -235,7 +306,7 @@
235306 uint i;
236307 for (i = 0; i < WF_NUM_5G_80M_CHANS; i ++) {
237308 if (ch == wf_5g_80m_chans[i])
238
- return i;
309
+ return (int)i;
239310 }
240311
241312 return -1;
....@@ -262,7 +333,7 @@
262333 wf_chspec_ntoa(chanspec_t chspec, char *buf)
263334 {
264335 const char *band;
265
- uint ctl_chan;
336
+ uint pri_chan;
266337
267338 if (wf_chspec_malformed(chspec))
268339 return NULL;
....@@ -274,32 +345,32 @@
274345 (CHSPEC_IS5G(chspec) && CHSPEC_CHANNEL(chspec) <= CH_MAX_2G_CHANNEL))
275346 band = (CHSPEC_IS2G(chspec)) ? "2g" : "5g";
276347
277
- /* ctl channel */
278
- ctl_chan = wf_chspec_ctlchan(chspec);
348
+ /* primary20 channel */
349
+ pri_chan = wf_chspec_primary20_chan(chspec);
279350
280
- /* bandwidth and ctl sideband */
351
+ /* bandwidth and primary20 sideband */
281352 if (CHSPEC_IS20(chspec)) {
282
- snprintf(buf, CHANSPEC_STR_LEN, "%s%d", band, ctl_chan);
353
+ snprintf(buf, CHANSPEC_STR_LEN, "%s%d", band, pri_chan);
283354 } else if (!CHSPEC_IS8080(chspec)) {
284355 const char *bw;
285356 const char *sb = "";
286357
287
- bw = wf_chspec_bw_str[(chspec & WL_CHANSPEC_BW_MASK) >> WL_CHANSPEC_BW_SHIFT];
358
+ bw = wf_chspec_to_bw_str(chspec);
288359
289360 #ifdef CHANSPEC_NEW_40MHZ_FORMAT
290
- /* ctl sideband string if needed for 2g 40MHz */
361
+ /* primary20 sideband string if needed for 2g 40MHz */
291362 if (CHSPEC_IS40(chspec) && CHSPEC_IS2G(chspec)) {
292363 sb = CHSPEC_SB_UPPER(chspec) ? "u" : "l";
293364 }
294365
295
- snprintf(buf, CHANSPEC_STR_LEN, "%s%d/%s%s", band, ctl_chan, bw, sb);
366
+ snprintf(buf, CHANSPEC_STR_LEN, "%s%d/%s%s", band, pri_chan, bw, sb);
296367 #else
297
- /* ctl sideband string instead of BW for 40MHz */
368
+ /* primary20 sideband string instead of BW for 40MHz */
298369 if (CHSPEC_IS40(chspec)) {
299370 sb = CHSPEC_SB_UPPER(chspec) ? "u" : "l";
300
- snprintf(buf, CHANSPEC_STR_LEN, "%s%d%s", band, ctl_chan, sb);
371
+ snprintf(buf, CHANSPEC_STR_LEN, "%s%d%s", band, pri_chan, sb);
301372 } else {
302
- snprintf(buf, CHANSPEC_STR_LEN, "%s%d/%s", band, ctl_chan, bw);
373
+ snprintf(buf, CHANSPEC_STR_LEN, "%s%d/%s", band, pri_chan, bw);
303374 }
304375 #endif /* CHANSPEC_NEW_40MHZ_FORMAT */
305376
....@@ -313,7 +384,7 @@
313384 chan2 = (chan2 < WF_NUM_5G_80M_CHANS) ? wf_5g_80m_chans[chan2] : 0;
314385
315386 /* Outputs a max of CHANSPEC_STR_LEN chars including '\0' */
316
- snprintf(buf, CHANSPEC_STR_LEN, "%d/80+80/%d-%d", ctl_chan, chan1, chan2);
387
+ snprintf(buf, CHANSPEC_STR_LEN, "%d/80+80/%d-%d", pri_chan, chan1, chan2);
317388 }
318389
319390 return (buf);
....@@ -339,14 +410,15 @@
339410 }
340411
341412 /* given a chanspec string, convert to a chanspec.
413
+ * if bandwidth not specified in chanspec input string, then use default_bw as bandwidth.
342414 * On error return 0
343415 */
344416 chanspec_t
345
-wf_chspec_aton(const char *a)
417
+wf_chspec_aton_ex(const char *a, const uint default_bw)
346418 {
347419 chanspec_t chspec;
348420 uint chspec_ch, chspec_band, bw, chspec_bw, chspec_sb;
349
- uint num, ctl_ch;
421
+ uint num, pri_ch;
350422 uint ch1, ch2;
351423 char c, sb_ul = '\0';
352424 int i;
....@@ -359,7 +431,7 @@
359431 if (!read_uint(&a, &num))
360432 return 0;
361433 /* if we are looking at a 'g', then the first number was a band */
362
- c = tolower((int)a[0]);
434
+ c = tolower(a[0]);
363435 if (c == 'g') {
364436 a++; /* consume the char */
365437
....@@ -372,21 +444,22 @@
372444 return 0;
373445
374446 /* read the channel number */
375
- if (!read_uint(&a, &ctl_ch))
447
+ if (!read_uint(&a, &pri_ch))
376448 return 0;
377449
378
- c = tolower((int)a[0]);
450
+ c = tolower(a[0]);
379451 }
380452 else {
381453 /* first number is channel, use default for band */
382
- ctl_ch = num;
383
- chspec_band = ((ctl_ch <= CH_MAX_2G_CHANNEL) ?
454
+ pri_ch = num;
455
+ chspec_band = ((pri_ch <= CH_MAX_2G_CHANNEL) ?
384456 WL_CHANSPEC_BAND_2G : WL_CHANSPEC_BAND_5G);
385457 }
386458
387459 if (c == '\0') {
388
- /* default BW of 20MHz */
389
- chspec_bw = WL_CHANSPEC_BW_20;
460
+ /* bandwidth not specified in chanspec input string, so use default_bw bandwidth */
461
+ chspec_bw = default_bw;
462
+ bw = wf_bw_chspec_to_mhz(default_bw);
390463 goto done_read;
391464 }
392465
....@@ -408,9 +481,7 @@
408481 return 0;
409482
410483 /* convert to chspec value */
411
- if (bw == 2) {
412
- chspec_bw = WL_CHANSPEC_BW_2P5;
413
- } else if (bw == 5) {
484
+ if (bw == 5) {
414485 chspec_bw = WL_CHANSPEC_BW_5;
415486 } else if (bw == 10) {
416487 chspec_bw = WL_CHANSPEC_BW_10;
....@@ -428,11 +499,10 @@
428499
429500 /* So far we have <band>g<chan>/<bw>
430501 * Can now be followed by u/l if bw = 40,
431
- * or '+80' if bw = 80, to make '80+80' bw,
432
- * or '.5' if bw = 2.5 to make '2.5' bw .
502
+ * or '+80' if bw = 80, to make '80+80' bw.
433503 */
434504
435
- c = tolower((int)a[0]);
505
+ c = (char)tolower((int)a[0]);
436506
437507 /* if we have a 2g/40 channel, we should have a l/u spec now */
438508 if (chspec_band == WL_CHANSPEC_BAND_2G && bw == 40) {
....@@ -474,19 +544,6 @@
474544 /* read secondary 80MHz channel */
475545 if (!read_uint(&a, &ch2))
476546 return 0;
477
- } else if (c == '.') {
478
- /* 2.5 */
479
- /* must be looking at '.5'
480
- * check and consume this string.
481
- */
482
- chspec_bw = WL_CHANSPEC_BW_2P5;
483
-
484
- a ++; /* consume the char '.' */
485
-
486
- /* consume the '5' string */
487
- if (*a++ != '5') {
488
- return 0;
489
- }
490547 }
491548
492549 done_read:
....@@ -500,9 +557,9 @@
500557 return 0;
501558
502559 /* Now have all the chanspec string parts read;
503
- * chspec_band, ctl_ch, chspec_bw, sb_ul, ch1, ch2.
560
+ * chspec_band, pri_ch, chspec_bw, sb_ul, ch1, ch2.
504561 * chspec_band and chspec_bw are chanspec values.
505
- * Need to convert ctl_ch, sb_ul, and ch1,ch2 into
562
+ * Need to convert pri_ch, sb_ul, and ch1,ch2 into
506563 * a center channel (or two) and sideband.
507564 */
508565
....@@ -511,23 +568,23 @@
511568 */
512569 if (sb_ul != '\0') {
513570 if (sb_ul == 'l') {
514
- chspec_ch = UPPER_20_SB(ctl_ch);
571
+ chspec_ch = UPPER_20_SB(pri_ch);
515572 chspec_sb = WL_CHANSPEC_CTL_SB_LLL;
516573 } else if (sb_ul == 'u') {
517
- chspec_ch = LOWER_20_SB(ctl_ch);
574
+ chspec_ch = LOWER_20_SB(pri_ch);
518575 chspec_sb = WL_CHANSPEC_CTL_SB_LLU;
519576 }
520577 }
521578 /* if the bw is 20, center and sideband are trivial */
522
- else if (BW_LE20(chspec_bw)) {
523
- chspec_ch = ctl_ch;
579
+ else if (chspec_bw == WL_CHANSPEC_BW_20) {
580
+ chspec_ch = pri_ch;
524581 chspec_sb = WL_CHANSPEC_CTL_SB_NONE;
525582 }
526583 /* if the bw is 40/80/160, not 80+80, a single method
527584 * can be used to to find the center and sideband
528585 */
529586 else if (chspec_bw != WL_CHANSPEC_BW_8080) {
530
- /* figure out ctl sideband based on ctl channel and bandwidth */
587
+ /* figure out primary20 sideband based on primary20 channel and bandwidth */
531588 const uint8 *center_ch = NULL;
532589 int num_ch = 0;
533590 int sb = -1;
....@@ -546,10 +603,10 @@
546603 }
547604
548605 for (i = 0; i < num_ch; i ++) {
549
- sb = channel_to_sb(center_ch[i], ctl_ch, bw);
606
+ sb = channel_to_sb(center_ch[i], pri_ch, bw);
550607 if (sb >= 0) {
551608 chspec_ch = center_ch[i];
552
- chspec_sb = sb << WL_CHANSPEC_CTL_SB_SHIFT;
609
+ chspec_sb = (uint)(sb << WL_CHANSPEC_CTL_SB_SHIFT);
553610 break;
554611 }
555612 }
....@@ -579,16 +636,16 @@
579636 /* figure out primary 20 MHz sideband */
580637
581638 /* is the primary channel contained in the 1st 80MHz channel? */
582
- sb = channel_to_sb(ch1, ctl_ch, bw);
639
+ sb = channel_to_sb(ch1, pri_ch, bw);
583640 if (sb < 0) {
584
- /* no match for primary channel 'ctl_ch' in segment0 80MHz channel */
641
+ /* no match for primary channel 'pri_ch' in segment0 80MHz channel */
585642 return 0;
586643 }
587644
588
- chspec_sb = sb << WL_CHANSPEC_CTL_SB_SHIFT;
645
+ chspec_sb = (uint)(sb << WL_CHANSPEC_CTL_SB_SHIFT);
589646 }
590647
591
- chspec = (chspec_ch | chspec_band | chspec_bw | chspec_sb);
648
+ chspec = (chanspec_t)(chspec_ch | chspec_band | chspec_bw | chspec_sb);
592649
593650 if (wf_chspec_malformed(chspec))
594651 return 0;
....@@ -596,9 +653,18 @@
596653 return chspec;
597654 }
598655
656
+/* given a chanspec string, convert to a chanspec.
657
+ * On error return 0
658
+ */
659
+chanspec_t
660
+wf_chspec_aton(const char *a)
661
+{
662
+ return wf_chspec_aton_ex(a, WL_CHANSPEC_BW_20);
663
+}
664
+
599665 /*
600666 * Verify the chanspec is using a legal set of parameters, i.e. that the
601
- * chanspec specified a band, bw, ctl_sb and channel and that the
667
+ * chanspec specified a band, bw, pri_sb and channel and that the
602668 * combination could be legal given any set of circumstances.
603669 * RETURNS: TRUE is the chanspec is malformed, false if it looks good.
604670 */
....@@ -608,10 +674,9 @@
608674 uint chspec_bw = CHSPEC_BW(chanspec);
609675 uint chspec_ch = CHSPEC_CHANNEL(chanspec);
610676
611
- /* must be 2G or 5G band */
612677 if (CHSPEC_IS2G(chanspec)) {
613
- /* must be valid bandwidth */
614
- if (!BW_LE40(chspec_bw)) {
678
+ /* must be valid bandwidth and channel */
679
+ if (!BW_LE40(chspec_bw) || (chspec_ch > CH_MAX_2G_CHANNEL)) {
615680 return TRUE;
616681 }
617682 } else if (CHSPEC_IS5G(chanspec)) {
....@@ -624,7 +689,29 @@
624689 if (ch1_id >= WF_NUM_5G_80M_CHANS || ch2_id >= WF_NUM_5G_80M_CHANS)
625690 return TRUE;
626691
627
- } else if (BW_LE160(chspec_bw)) {
692
+ } else if (chspec_bw == WL_CHANSPEC_BW_20 || chspec_bw == WL_CHANSPEC_BW_40 ||
693
+ chspec_bw == WL_CHANSPEC_BW_80 || chspec_bw == WL_CHANSPEC_BW_160) {
694
+
695
+ if (chspec_ch > MAXCHANNEL) {
696
+ return TRUE;
697
+ }
698
+ } else {
699
+ /* invalid bandwidth */
700
+ return TRUE;
701
+ }
702
+ } else if (CHSPEC_IS6G(chanspec)) {
703
+ if (chspec_bw == WL_CHANSPEC_BW_8080) {
704
+ uint ch1_id, ch2_id;
705
+
706
+ /* channel IDs in 80+80 must be in range */
707
+ ch1_id = CHSPEC_CHAN1(chanspec);
708
+ ch2_id = CHSPEC_CHAN2(chanspec);
709
+ if (ch1_id >= WF_NUM_6G_80M_CHANS || ch2_id >= WF_NUM_6G_80M_CHANS)
710
+ return TRUE;
711
+
712
+ } else if (chspec_bw == WL_CHANSPEC_BW_20 || chspec_bw == WL_CHANSPEC_BW_40 ||
713
+ chspec_bw == WL_CHANSPEC_BW_80 || chspec_bw == WL_CHANSPEC_BW_160) {
714
+
628715 if (chspec_ch > MAXCHANNEL) {
629716 return TRUE;
630717 }
....@@ -633,12 +720,13 @@
633720 return TRUE;
634721 }
635722 } else {
636
- /* must be 2G or 5G band */
723
+
724
+ /* must be 2G, 5G or 6G band */
637725 return TRUE;
638726 }
639727
640728 /* side band needs to be consistent with bandwidth */
641
- if (BW_LE20(chspec_bw)) {
729
+ if (chspec_bw == WL_CHANSPEC_BW_20) {
642730 if (CHSPEC_CTL_SB(chanspec) != WL_CHANSPEC_CTL_SB_LLL)
643731 return TRUE;
644732 } else if (chspec_bw == WL_CHANSPEC_BW_40) {
....@@ -646,6 +734,9 @@
646734 return TRUE;
647735 } else if (chspec_bw == WL_CHANSPEC_BW_80 ||
648736 chspec_bw == WL_CHANSPEC_BW_8080) {
737
+ /* both 80MHz and 80+80MHz use 80MHz side bands.
738
+ * 80+80 SB info is relative to the primary 80MHz sub-band.
739
+ */
649740 if (CHSPEC_CTL_SB(chanspec) > WL_CHANSPEC_CTL_SB_LUU)
650741 return TRUE;
651742 }
....@@ -670,7 +761,7 @@
670761
671762 if (CHSPEC_IS2G(chanspec)) {
672763 /* must be valid bandwidth and channel range */
673
- if (BW_LE20(chspec_bw)) {
764
+ if (chspec_bw == WL_CHANSPEC_BW_20) {
674765 if (chspec_ch >= 1 && chspec_ch <= 14)
675766 return TRUE;
676767 } else if (chspec_bw == WL_CHANSPEC_BW_40) {
....@@ -692,7 +783,7 @@
692783 const uint8 *center_ch;
693784 uint num_ch, i;
694785
695
- if (BW_LE40(chspec_bw)) {
786
+ if (chspec_bw == WL_CHANSPEC_BW_20 || chspec_bw == WL_CHANSPEC_BW_40) {
696787 center_ch = wf_5g_40m_chans;
697788 num_ch = WF_NUM_5G_40M_CHANS;
698789 } else if (chspec_bw == WL_CHANSPEC_BW_80) {
....@@ -707,7 +798,7 @@
707798 }
708799
709800 /* check for a valid center channel */
710
- if (BW_LE20(chspec_bw)) {
801
+ if (chspec_bw == WL_CHANSPEC_BW_20) {
711802 /* We don't have an array of legal 20MHz 5G channels, but they are
712803 * each side of the legal 40MHz channels. Check the chanspec
713804 * channel against either side of the 40MHz channels.
....@@ -749,12 +840,66 @@
749840 }
750841
751842 /*
752
- * This function returns the channel number that control traffic is being sent on, for 20MHz
753
- * channels this is just the channel number, for 40MHZ, 80MHz, 160MHz channels it is the 20MHZ
754
- * sideband depending on the chanspec selected
843
+ * This function returns TRUE if both the chanspec can co-exist in PHY.
844
+ * Addition to primary20 channel, the function checks for side band for 2g 40 channels
845
+ */
846
+bool
847
+wf_chspec_coexist(chanspec_t chspec1, chanspec_t chspec2)
848
+{
849
+ bool same_primary;
850
+
851
+ same_primary = (wf_chspec_primary20_chan(chspec1) == wf_chspec_primary20_chan(chspec2));
852
+
853
+ if (same_primary && CHSPEC_IS2G(chspec1)) {
854
+ if (CHSPEC_IS40(chspec1) && CHSPEC_IS40(chspec2)) {
855
+ return (CHSPEC_CTL_SB(chspec1) == CHSPEC_CTL_SB(chspec2));
856
+ }
857
+ }
858
+ return same_primary;
859
+}
860
+
861
+/**
862
+ * Create a 20MHz chanspec for the given band.
863
+ *
864
+ * This function returns a 20MHz chanspec in the given band.
865
+ *
866
+ * @param channel 20MHz channel number
867
+ * @param band a chanspec band (e.g. WL_CHANSPEC_BAND_2G)
868
+ *
869
+ * @return Returns a 20MHz chanspec, or IVNCHANSPEC in case of error.
870
+ */
871
+chanspec_t
872
+wf_create_20MHz_chspec(uint channel, chanspec_band_t band)
873
+{
874
+ chanspec_t chspec;
875
+
876
+ if (channel <= WL_CHANSPEC_CHAN_MASK &&
877
+ (band == WL_CHANSPEC_BAND_2G ||
878
+ band == WL_CHANSPEC_BAND_5G)) {
879
+ chspec = band | WL_CHANSPEC_BW_20 | WL_CHANSPEC_CTL_SB_NONE | channel;
880
+ if (!wf_chspec_valid(chspec)) {
881
+ chspec = INVCHANSPEC;
882
+ }
883
+ } else {
884
+ chspec = INVCHANSPEC;
885
+ }
886
+
887
+ return chspec;
888
+}
889
+
890
+/**
891
+ * Return the primary 20MHz channel.
892
+ *
893
+ * This function returns the channel number of the primary 20MHz channel. For
894
+ * 20MHz channels this is just the channel number. For 40MHz or wider channels
895
+ * it is the primary 20MHz channel specified by the chanspec.
896
+ *
897
+ * @param chspec input chanspec
898
+ *
899
+ * @return Returns the channel number of the primary 20MHz channel
755900 */
756901 uint8
757
-wf_chspec_ctlchan(chanspec_t chspec)
902
+wf_chspec_primary20_chan(chanspec_t chspec)
758903 {
759904 uint center_chan;
760905 uint bw_mhz;
....@@ -763,7 +908,7 @@
763908 ASSERT(!wf_chspec_malformed(chspec));
764909
765910 /* Is there a sideband ? */
766
- if (CHSPEC_BW_LE20(chspec)) {
911
+ if (CHSPEC_IS20(chspec)) {
767912 return CHSPEC_CHANNEL(chspec);
768913 } else {
769914 sb = CHSPEC_CTL_SB(chspec) >> WL_CHANSPEC_CTL_SB_SHIFT;
....@@ -780,46 +925,46 @@
780925 center_chan = wf_5g_80m_chans[chan_id];
781926 }
782927 else {
783
- bw_mhz = bw_chspec_to_mhz(chspec);
928
+ bw_mhz = wf_bw_chspec_to_mhz(chspec);
784929 center_chan = CHSPEC_CHANNEL(chspec) >> WL_CHANSPEC_CHAN_SHIFT;
785930 }
786931
787
- return (channel_to_ctl_chan(center_chan, bw_mhz, sb));
932
+ return (channel_to_primary20_chan(center_chan, bw_mhz, sb));
788933 }
789934 }
790935
791936 /* given a chanspec, return the bandwidth string */
792
-char *
793
-wf_chspec_to_bw_str(chanspec_t chspec)
937
+const char *
938
+BCMRAMFN(wf_chspec_to_bw_str)(chanspec_t chspec)
794939 {
795
- return (char *)wf_chspec_bw_str[(CHSPEC_BW(chspec) >> WL_CHANSPEC_BW_SHIFT)];
940
+ return wf_chspec_bw_str[(CHSPEC_BW(chspec) >> WL_CHANSPEC_BW_SHIFT)];
796941 }
797942
798943 /*
799
- * This function returns the chanspec of the control channel of a given chanspec
944
+ * Return the primary 20MHz chanspec of the given chanspec
800945 */
801946 chanspec_t
802
-wf_chspec_ctlchspec(chanspec_t chspec)
947
+wf_chspec_primary20_chspec(chanspec_t chspec)
803948 {
804
- chanspec_t ctl_chspec = chspec;
805
- uint8 ctl_chan;
949
+ chanspec_t pri_chspec = chspec;
950
+ uint8 pri_chan;
806951
807952 ASSERT(!wf_chspec_malformed(chspec));
808953
809954 /* Is there a sideband ? */
810
- if (!CHSPEC_BW_LE20(chspec)) {
811
- ctl_chan = wf_chspec_ctlchan(chspec);
812
- ctl_chspec = ctl_chan | WL_CHANSPEC_BW_20;
813
- ctl_chspec |= CHSPEC_BAND(chspec);
955
+ if (!CHSPEC_IS20(chspec)) {
956
+ pri_chan = wf_chspec_primary20_chan(chspec);
957
+ pri_chspec = pri_chan | WL_CHANSPEC_BW_20;
958
+ pri_chspec |= CHSPEC_BAND(chspec);
814959 }
815
- return ctl_chspec;
960
+ return pri_chspec;
816961 }
817962
818
-/* return chanspec given control channel and bandwidth
963
+/* return chanspec given primary 20MHz channel and bandwidth
819964 * return 0 on error
820965 */
821966 uint16
822
-wf_channel2chspec(uint ctl_ch, uint bw)
967
+wf_channel2chspec(uint pri_ch, uint bw)
823968 {
824969 uint16 chspec;
825970 const uint8 *center_ch = NULL;
....@@ -827,7 +972,7 @@
827972 int sb = -1;
828973 int i = 0;
829974
830
- chspec = ((ctl_ch <= CH_MAX_2G_CHANNEL) ? WL_CHANSPEC_BAND_2G : WL_CHANSPEC_BAND_5G);
975
+ chspec = ((pri_ch <= CH_MAX_2G_CHANNEL) ? WL_CHANSPEC_BAND_2G : WL_CHANSPEC_BAND_5G);
831976
832977 chspec |= bw;
833978
....@@ -843,15 +988,15 @@
843988 center_ch = wf_5g_160m_chans;
844989 num_ch = WF_NUM_5G_160M_CHANS;
845990 bw = 160;
846
- } else if (BW_LE20(bw)) {
847
- chspec |= ctl_ch;
991
+ } else if (bw == WL_CHANSPEC_BW_20) {
992
+ chspec |= pri_ch;
848993 return chspec;
849994 } else {
850995 return 0;
851996 }
852997
853998 for (i = 0; i < num_ch; i ++) {
854
- sb = channel_to_sb(center_ch[i], ctl_ch, bw);
999
+ sb = channel_to_sb(center_ch[i], pri_ch, bw);
8551000 if (sb >= 0) {
8561001 chspec |= center_ch[i];
8571002 chspec |= (sb << WL_CHANSPEC_CTL_SB_SHIFT);
....@@ -868,9 +1013,9 @@
8681013 }
8691014
8701015 /*
871
- * This function returns the chanspec for the primary 40MHz of an 80MHz channel.
872
- * The control sideband specifies the same 20MHz channel that the 80MHz channel is using
873
- * as the primary 20MHz channel.
1016
+ * This function returns the chanspec for the primary 40MHz of an 80MHz or wider channel.
1017
+ * The primary 20MHz channel of the returned 40MHz chanspec is the same as the primary 20MHz
1018
+ * channel of the input chanspec.
8741019 */
8751020 extern chanspec_t wf_chspec_primary40_chspec(chanspec_t chspec)
8761021 {
....@@ -902,7 +1047,7 @@
9021047 }
9031048
9041049 /* Create primary 40MHz chanspec */
905
- chspec40 = (WL_CHANSPEC_BAND_5G | WL_CHANSPEC_BW_40 |
1050
+ chspec40 = (chanspec_t)(WL_CHANSPEC_BAND_5G | WL_CHANSPEC_BW_40 |
9061051 sb | center_chan);
9071052 }
9081053
....@@ -926,7 +1071,7 @@
9261071 * frequency is not a 2.4 GHz channel, or if the frequency is not and even
9271072 * multiple of 5 MHz from the base frequency to the base plus 1 GHz.
9281073 *
929
- * Reference 802.11 REVma, section 17.3.8.3, and 802.11B section 18.4.6.2
1074
+ * Reference 802.11-2016, section 17.3.8.3 and section 16.3.6.3
9301075 */
9311076 int
9321077 wf_mhz2channel(uint freq, uint start_factor)
....@@ -952,7 +1097,7 @@
9521097 if ((freq < base) || (freq > base + 1000))
9531098 return -1;
9541099
955
- offset = freq - base;
1100
+ offset = (int)(freq - base);
9561101 ch = offset / 5;
9571102
9581103 /* check that frequency is a 5MHz multiple from the base */
....@@ -980,7 +1125,7 @@
9801125 * the answer is rounded down to an integral MHz.
9811126 * -1 is returned for an out of range channel.
9821127 *
983
- * Reference 802.11 REVma, section 17.3.8.3, and 802.11B section 18.4.6.2
1128
+ * Reference 802.11-2016, section 17.3.8.3 and section 16.3.6.3
9841129 */
9851130 int
9861131 wf_channel2mhz(uint ch, uint start_factor)
....@@ -993,7 +1138,7 @@
9931138 else if ((start_factor == WF_CHAN_FACTOR_2_4_G) && (ch == 14))
9941139 freq = 2484;
9951140 else
996
- freq = ch * 5 + start_factor / 2;
1141
+ freq = (int)(ch * 5 + start_factor / 2);
9971142
9981143 return freq;
9991144 }
....@@ -1026,7 +1171,7 @@
10261171
10271172 for (i = 0; i < WF_NUM_SIDEBANDS_80MHZ; i++) {
10281173 chanspec_cur = CH80MHZ_CHSPEC(center_channel, sidebands[i]);
1029
- if (primary_channel == wf_chspec_ctlchan(chanspec_cur)) {
1174
+ if (primary_channel == wf_chspec_primary20_chan(chanspec_cur)) {
10301175 chanspec = chanspec_cur;
10311176 break;
10321177 }
....@@ -1051,7 +1196,7 @@
10511196 *
10521197 * Returns INVCHANSPEC in case of error.
10531198 *
1054
- * Refer to IEEE802.11ac section 22.3.14 "Channelization".
1199
+ * Refer to 802.11-2016 section 22.3.14 "Channelization".
10551200 */
10561201 chanspec_t
10571202 wf_chspec_get8080_chspec(uint8 primary_20mhz, uint8 chan0, uint8 chan1)
....@@ -1078,7 +1223,7 @@
10781223 /* no, so does the primary channel fit with the 2nd 80MHz channel ? */
10791224 sb = channel_to_sb(chan1, primary_20mhz, 80);
10801225 if (sb < 0) {
1081
- /* no match for ctl_ch to either 80MHz center channel */
1226
+ /* no match for pri_ch to either 80MHz center channel */
10821227 return INVCHANSPEC;
10831228 }
10841229 /* swapped, so chan1 is frequency segment 0, and chan0 is seg 1 */
....@@ -1086,7 +1231,7 @@
10861231 seg1 = chan0_id;
10871232 }
10881233
1089
- chanspec = ((seg0 << WL_CHANSPEC_CHAN1_SHIFT) |
1234
+ chanspec = (uint16)((seg0 << WL_CHANSPEC_CHAN1_SHIFT) |
10901235 (seg1 << WL_CHANSPEC_CHAN2_SHIFT) |
10911236 (sb << WL_CHANSPEC_CTL_SB_SHIFT) |
10921237 WL_CHANSPEC_BW_8080 |
....@@ -1108,93 +1253,47 @@
11081253 }
11091254
11101255 /*
1111
- * Returns the primary 80 Mhz channel for the provided chanspec
1112
- *
1113
- * chanspec - Input chanspec for which the 80MHz primary channel has to be retrieved
1114
- *
1115
- * returns -1 in case the provided channel is 20/40 Mhz chanspec
1256
+ * Returns the center channel of the primary 80 MHz sub-band of the provided chanspec
11161257 */
1117
-
11181258 uint8
11191259 wf_chspec_primary80_channel(chanspec_t chanspec)
11201260 {
1261
+ chanspec_t primary80_chspec;
11211262 uint8 primary80_chan;
11221263
1123
- if (CHSPEC_IS80(chanspec)) {
1124
- primary80_chan = CHSPEC_CHANNEL(chanspec);
1125
- }
1126
- else if (CHSPEC_IS8080(chanspec)) {
1127
- /* Channel ID 1 corresponds to frequency segment 0, the primary 80 MHz segment */
1128
- primary80_chan = wf_chspec_get80Mhz_ch(CHSPEC_CHAN1(chanspec));
1129
- }
1130
- else if (CHSPEC_IS160(chanspec)) {
1131
- uint8 center_chan = CHSPEC_CHANNEL(chanspec);
1132
- uint sb = CHSPEC_CTL_SB(chanspec) >> WL_CHANSPEC_CTL_SB_SHIFT;
1264
+ primary80_chspec = wf_chspec_primary80_chspec(chanspec);
11331265
1134
- /* based on the sb value primary 80 channel can be retrieved
1135
- * if sb is in range 0 to 3 the lower band is the 80Mhz primary band
1136
- */
1137
- if (sb < 4) {
1138
- primary80_chan = center_chan - CH_40MHZ_APART;
1139
- }
1140
- /* if sb is in range 4 to 7 the upper band is the 80Mhz primary band */
1141
- else
1142
- {
1143
- primary80_chan = center_chan + CH_40MHZ_APART;
1144
- }
1266
+ if (primary80_chspec == INVCHANSPEC) {
1267
+ primary80_chan = INVCHANNEL;
1268
+ } else {
1269
+ primary80_chan = CHSPEC_CHANNEL(primary80_chspec);
11451270 }
1146
- else {
1147
- /* for 20 and 40 Mhz */
1148
- primary80_chan = -1;
1149
- }
1271
+
11501272 return primary80_chan;
11511273 }
11521274
11531275 /*
1154
- * Returns the secondary 80 Mhz channel for the provided chanspec
1155
- *
1156
- * chanspec - Input chanspec for which the 80MHz secondary channel has to be retrieved
1157
- *
1158
- * returns -1 in case the provided channel is 20/40/80 Mhz chanspec
1276
+ * Returns the center channel of the secondary 80 MHz sub-band of the provided chanspec
11591277 */
11601278 uint8
11611279 wf_chspec_secondary80_channel(chanspec_t chanspec)
11621280 {
1281
+ chanspec_t secondary80_chspec;
11631282 uint8 secondary80_chan;
11641283
1165
- if (CHSPEC_IS8080(chanspec)) {
1166
- secondary80_chan = wf_chspec_get80Mhz_ch(CHSPEC_CHAN2(chanspec));
1167
- }
1168
- else if (CHSPEC_IS160(chanspec)) {
1169
- uint8 center_chan = CHSPEC_CHANNEL(chanspec);
1170
- uint sb = CHSPEC_CTL_SB(chanspec) >> WL_CHANSPEC_CTL_SB_SHIFT;
1284
+ secondary80_chspec = wf_chspec_secondary80_chspec(chanspec);
11711285
1172
- /* based on the sb value secondary 80 channel can be retrieved
1173
- * if sb is in range 0 to 3 upper band is the secondary 80Mhz band
1174
- */
1175
- if (sb < 4) {
1176
- secondary80_chan = center_chan + CH_40MHZ_APART;
1177
- }
1178
- /* if sb is in range 4 to 7 the lower band is the secondary 80Mhz band */
1179
- else
1180
- {
1181
- secondary80_chan = center_chan - CH_40MHZ_APART;
1182
- }
1286
+ if (secondary80_chspec == INVCHANSPEC) {
1287
+ secondary80_chan = INVCHANNEL;
1288
+ } else {
1289
+ secondary80_chan = CHSPEC_CHANNEL(secondary80_chspec);
11831290 }
1184
- else {
1185
- /* for 20, 40, and 80 Mhz */
1186
- secondary80_chan = -1;
1187
- }
1291
+
11881292 return secondary80_chan;
11891293 }
11901294
11911295 /*
1192
- * This function returns the chanspec for the primary 80MHz of an 160MHz or 80+80 channel.
1193
- *
1194
- * chanspec - Input chanspec for which the primary 80Mhz chanspec has to be retreived
1195
- *
1196
- * returns the input chanspec in case the provided chanspec is an 80 MHz chanspec
1197
- * returns INVCHANSPEC in case the provided channel is 20/40 MHz chanspec
1296
+ * Returns the chanspec for the primary 80MHz sub-band of an 160MHz or 80+80 channel
11981297 */
11991298 chanspec_t
12001299 wf_chspec_primary80_chspec(chanspec_t chspec)
....@@ -1204,18 +1303,18 @@
12041303 uint sb;
12051304
12061305 ASSERT(!wf_chspec_malformed(chspec));
1306
+
12071307 if (CHSPEC_IS80(chspec)) {
12081308 chspec80 = chspec;
12091309 }
12101310 else if (CHSPEC_IS8080(chspec)) {
1211
-
1212
- /* Channel ID 1 corresponds to frequency segment 0, the primary 80 MHz segment */
1213
- center_chan = wf_chspec_get80Mhz_ch(CHSPEC_CHAN1(chspec));
1214
-
12151311 sb = CHSPEC_CTL_SB(chspec);
12161312
1313
+ /* primary sub-band is stored in seg0 */
1314
+ center_chan = wf_chspec_get80Mhz_ch(CHSPEC_CHAN1(chspec));
1315
+
12171316 /* Create primary 80MHz chanspec */
1218
- chspec80 = (WL_CHANSPEC_BAND_5G | WL_CHANSPEC_BW_80 | sb | center_chan);
1317
+ chspec80 = (chanspec_t)(WL_CHANSPEC_BAND_5G | WL_CHANSPEC_BW_80 | sb | center_chan);
12191318 }
12201319 else if (CHSPEC_IS160(chspec)) {
12211320 center_chan = CHSPEC_CHANNEL(chspec);
....@@ -1230,14 +1329,88 @@
12301329 center_chan += CH_40MHZ_APART;
12311330 sb -= WL_CHANSPEC_CTL_SB_ULL;
12321331 }
1332
+
12331333 /* Create primary 80MHz chanspec */
1234
- chspec80 = (WL_CHANSPEC_BAND_5G | WL_CHANSPEC_BW_80 | sb | center_chan);
1334
+ chspec80 = (chanspec_t)(WL_CHANSPEC_BAND_5G | WL_CHANSPEC_BW_80 | sb | center_chan);
12351335 }
12361336 else {
12371337 chspec80 = INVCHANSPEC;
12381338 }
12391339
12401340 return chspec80;
1341
+}
1342
+
1343
+/*
1344
+ * Returns the chanspec for the secondary 80MHz sub-band of an 160MHz or 80+80 channel
1345
+ */
1346
+chanspec_t
1347
+wf_chspec_secondary80_chspec(chanspec_t chspec)
1348
+{
1349
+ chanspec_t chspec80;
1350
+ uint center_chan;
1351
+
1352
+ ASSERT(!wf_chspec_malformed(chspec));
1353
+
1354
+ if (CHSPEC_IS8080(chspec)) {
1355
+ /* secondary sub-band is stored in seg1 */
1356
+ center_chan = wf_chspec_get80Mhz_ch(CHSPEC_CHAN2(chspec));
1357
+
1358
+ /* Create secondary 80MHz chanspec */
1359
+ chspec80 = (chanspec_t)(WL_CHANSPEC_BAND_5G |
1360
+ WL_CHANSPEC_BW_80 |
1361
+ WL_CHANSPEC_CTL_SB_LL |
1362
+ center_chan);
1363
+ }
1364
+ else if (CHSPEC_IS160(chspec)) {
1365
+ center_chan = CHSPEC_CHANNEL(chspec);
1366
+
1367
+ if (CHSPEC_CTL_SB(chspec) < WL_CHANSPEC_CTL_SB_ULL) {
1368
+ /* Primary 80MHz is on lower side */
1369
+ center_chan -= CH_40MHZ_APART;
1370
+ }
1371
+ else {
1372
+ /* Primary 80MHz is on upper side */
1373
+ center_chan += CH_40MHZ_APART;
1374
+ }
1375
+
1376
+ /* Create secondary 80MHz chanspec */
1377
+ chspec80 = (chanspec_t)(WL_CHANSPEC_BAND_5G |
1378
+ WL_CHANSPEC_BW_80 |
1379
+ WL_CHANSPEC_CTL_SB_LL |
1380
+ center_chan);
1381
+ }
1382
+ else {
1383
+ chspec80 = INVCHANSPEC;
1384
+ }
1385
+
1386
+ return chspec80;
1387
+}
1388
+
1389
+/*
1390
+ * For 160MHz or 80P80 chanspec, set ch[0]/ch[1] to be the low/high 80 Mhz channels
1391
+ *
1392
+ * For 20/40/80MHz chanspec, set ch[0] to be the center freq, and chan[1]=-1
1393
+ */
1394
+void
1395
+wf_chspec_get_80p80_channels(chanspec_t chspec, uint8 *ch)
1396
+{
1397
+
1398
+ if (CHSPEC_IS8080(chspec)) {
1399
+ ch[0] = wf_chspec_get80Mhz_ch(CHSPEC_CHAN1(chspec));
1400
+ ch[1] = wf_chspec_get80Mhz_ch(CHSPEC_CHAN2(chspec));
1401
+ }
1402
+ else if (CHSPEC_IS160(chspec)) {
1403
+ uint8 center_chan = CHSPEC_CHANNEL(chspec);
1404
+ ch[0] = center_chan - CH_40MHZ_APART;
1405
+ ch[1] = center_chan + CH_40MHZ_APART;
1406
+ }
1407
+ else {
1408
+ /* for 20, 40, and 80 Mhz */
1409
+ ch[0] = CHSPEC_CHANNEL(chspec);
1410
+ ch[1] = 0xFFu;
1411
+ }
1412
+ return;
1413
+
12411414 }
12421415
12431416 #ifdef WL11AC_80P80
....@@ -1253,40 +1426,130 @@
12531426 }
12541427 #endif /* WL11AC_80P80 */
12551428
1256
-#ifdef WL_OLDPPR
1257
-/* given a chanspec and a string buffer, format the chanspec as a
1258
- * string, and return the original pointer a.
1259
- * Min buffer length must be CHANSPEC_STR_LEN.
1260
- * On error return NULL
1429
+/* This routine returns the chanspec for a given operating class and
1430
+ * channel number
12611431 */
1262
-char *
1263
-wf_chspec_ntoa_old(chanspec_t chspec, char *buf)
1432
+chanspec_t
1433
+wf_channel_create_chspec_frm_opclass(uint8 opclass, uint8 channel)
12641434 {
1265
- const char *band, *bw, *sb;
1266
- uint channel;
1267
-
1268
- band = "";
1269
- bw = "";
1270
- sb = "";
1271
- channel = CHSPEC_CHANNEL_OLD(chspec);
1272
- /* check for non-default band spec */
1273
- if ((CHSPEC_IS2G_OLD(chspec) && channel > CH_MAX_2G_CHANNEL) ||
1274
- (CHSPEC_IS5G_OLD(chspec) && channel <= CH_MAX_2G_CHANNEL))
1275
- band = (CHSPEC_IS2G_OLD(chspec)) ? "b" : "a";
1276
- if (CHSPEC_IS40_OLD(chspec)) {
1277
- if (CHSPEC_SB_UPPER_OLD(chspec)) {
1278
- sb = "u";
1279
- channel += CH_10MHZ_APART;
1280
- } else {
1281
- sb = "l";
1282
- channel -= CH_10MHZ_APART;
1283
- }
1284
- } else if (CHSPEC_IS10_OLD(chspec)) {
1285
- bw = "n";
1435
+ chanspec_t chanspec = 0;
1436
+ uint16 opclass_info = 0;
1437
+ uint16 lookupindex = 0;
1438
+ switch (opclass) {
1439
+ case 115:
1440
+ lookupindex = 1;
1441
+ break;
1442
+ case 124:
1443
+ lookupindex = 3;
1444
+ break;
1445
+ case 125:
1446
+ lookupindex = 5;
1447
+ break;
1448
+ case 81:
1449
+ lookupindex = 12;
1450
+ break;
1451
+ case 116:
1452
+ lookupindex = 22;
1453
+ break;
1454
+ case 119:
1455
+ lookupindex = 23;
1456
+ break;
1457
+ case 126:
1458
+ lookupindex = 25;
1459
+ break;
1460
+ case 83:
1461
+ lookupindex = 32;
1462
+ break;
1463
+ case 84:
1464
+ lookupindex = 33;
1465
+ break;
1466
+ default:
1467
+ lookupindex = 12;
12861468 }
12871469
1288
- /* Outputs a max of 6 chars including '\0' */
1289
- snprintf(buf, 6, "%d%s%s%s", channel, band, bw, sb);
1290
- return (buf);
1470
+ if (lookupindex < 33) {
1471
+ opclass_info = opclass_data[lookupindex-1];
1472
+ }
1473
+ else {
1474
+ opclass_info = opclass_data[11];
1475
+ }
1476
+ chanspec = opclass_info | (uint16)channel;
1477
+ return chanspec;
12911478 }
1292
-#endif /* WL_OLDPPR */
1479
+
1480
+/* This routine returns the opclass for a given chanspec */
1481
+int
1482
+wf_channel_create_opclass_frm_chspec(chanspec_t chspec)
1483
+{
1484
+ BCM_REFERENCE(chspec);
1485
+ /* TODO: Implement this function ! */
1486
+ return 12; /* opclass 12 for basic 2G channels */
1487
+}
1488
+
1489
+/* Populates array with all 20MHz side bands of a given chanspec_t in the following order:
1490
+ * primary20, secondary20, two secondary40s, four secondary80s.
1491
+ * 'chspec' is the chanspec of interest
1492
+ * 'pext' must point to an uint8 array of long enough to hold all side bands of the given chspec
1493
+ *
1494
+ * Works with 20, 40, 80, 80p80 and 160MHz chspec
1495
+ */
1496
+void
1497
+wf_get_all_ext(chanspec_t chspec, uint8 *pext)
1498
+{
1499
+#ifdef WL11N_20MHZONLY
1500
+ GET_ALL_SB(chspec, pext);
1501
+#else /* !WL11N_20MHZONLY */
1502
+ chanspec_t t = (CHSPEC_IS160(chspec) || CHSPEC_IS8080(chspec)) ? /* if bw > 80MHz */
1503
+ wf_chspec_primary80_chspec(chspec) : (chspec); /* extract primary 80 */
1504
+ /* primary20 channel as first element */
1505
+ uint8 pri_ch = (pext)[0] = wf_chspec_primary20_chan(t);
1506
+ if (CHSPEC_IS20(chspec)) return; /* nothing more to do since 20MHz chspec */
1507
+ /* 20MHz EXT */
1508
+ (pext)[1] = pri_ch + (uint8)(IS_CTL_IN_L20(t) ? CH_20MHZ_APART : -CH_20MHZ_APART);
1509
+ if (CHSPEC_IS40(chspec)) return; /* nothing more to do since 40MHz chspec */
1510
+ /* center 40MHz EXT */
1511
+ t = wf_channel2chspec((uint)(pri_ch + (IS_CTL_IN_L40(chspec) ?
1512
+ CH_40MHZ_APART : -CH_40MHZ_APART)), WL_CHANSPEC_BW_40);
1513
+ GET_ALL_SB(t, &((pext)[2])); /* get the 20MHz side bands in 40MHz EXT */
1514
+ if (CHSPEC_IS80(chspec)) return; /* nothing more to do since 80MHz chspec */
1515
+ t = CH80MHZ_CHSPEC(wf_chspec_secondary80_channel(chspec), WL_CHANSPEC_CTL_SB_LLL);
1516
+ /* get the 20MHz side bands in 80MHz EXT (secondary) */
1517
+ GET_ALL_SB(t, &((pext)[4]));
1518
+#endif /* !WL11N_20MHZONLY */
1519
+}
1520
+
1521
+/*
1522
+ * Given two chanspecs, returns true if they overlap.
1523
+ * (Overlap: At least one 20MHz subband is common between the two chanspecs provided)
1524
+ */
1525
+bool wf_chspec_overlap(chanspec_t chspec0, chanspec_t chspec1)
1526
+{
1527
+ uint8 ch0, ch1;
1528
+
1529
+ FOREACH_20_SB(chspec0, ch0) {
1530
+ FOREACH_20_SB(chspec1, ch1) {
1531
+ if (ABS(ch0 - ch1) < CH_20MHZ_APART) {
1532
+ return TRUE;
1533
+ }
1534
+ }
1535
+ }
1536
+
1537
+ return FALSE;
1538
+}
1539
+
1540
+uint8
1541
+channel_bw_to_width(chanspec_t chspec)
1542
+{
1543
+ uint8 channel_width;
1544
+
1545
+ if (CHSPEC_IS80(chspec))
1546
+ channel_width = VHT_OP_CHAN_WIDTH_80;
1547
+ else if (CHSPEC_IS160(chspec))
1548
+ channel_width = VHT_OP_CHAN_WIDTH_160;
1549
+ else if (CHSPEC_IS8080(chspec))
1550
+ channel_width = VHT_OP_CHAN_WIDTH_80_80;
1551
+ else
1552
+ channel_width = VHT_OP_CHAN_WIDTH_20_40;
1553
+
1554
+ return channel_width;
1555
+}