PageRenderTime 1355ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 0ms

/drivers/staging/brcm80211/brcmsmac/channel.c

https://github.com/Mengqi/linux-2.6
C | 1559 lines | 1157 code | 229 blank | 173 comment | 153 complexity | e125b8bdcbd93f07b2ae8dc567f02d2b MD5 | raw file
  1. /*
  2. * Copyright (c) 2010 Broadcom Corporation
  3. *
  4. * Permission to use, copy, modify, and/or distribute this software for any
  5. * purpose with or without fee is hereby granted, provided that the above
  6. * copyright notice and this permission notice appear in all copies.
  7. *
  8. * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
  9. * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  10. * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
  11. * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  12. * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
  13. * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
  14. * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  15. */
  16. #include <linux/types.h>
  17. #include <net/mac80211.h>
  18. #include <defs.h>
  19. #include "pub.h"
  20. #include "phy/phy_hal.h"
  21. #include "bmac.h"
  22. #include "main.h"
  23. #include "stf.h"
  24. #include "channel.h"
  25. #define VALID_CHANNEL20_DB(wlc, val) brcms_c_valid_channel20_db((wlc)->cmi, val)
  26. #define VALID_CHANNEL20_IN_BAND(wlc, bandunit, val) \
  27. brcms_c_valid_channel20_in_band((wlc)->cmi, bandunit, val)
  28. #define VALID_CHANNEL20(wlc, val) brcms_c_valid_channel20((wlc)->cmi, val)
  29. struct brcms_cm_band {
  30. u8 locale_flags; /* struct locale_info flags */
  31. chanvec_t valid_channels; /* List of valid channels in the country */
  32. const chanvec_t *restricted_channels; /* List of restricted use channels */
  33. const chanvec_t *radar_channels; /* List of radar sensitive channels */
  34. u8 PAD[8];
  35. };
  36. struct brcms_cm_info {
  37. struct brcms_pub *pub;
  38. struct brcms_c_info *wlc;
  39. char srom_ccode[BRCM_CNTRY_BUF_SZ]; /* Country Code in SROM */
  40. uint srom_regrev; /* Regulatory Rev for the SROM ccode */
  41. const struct country_info *country; /* current country def */
  42. char ccode[BRCM_CNTRY_BUF_SZ]; /* current internal Country Code */
  43. uint regrev; /* current Regulatory Revision */
  44. char country_abbrev[BRCM_CNTRY_BUF_SZ]; /* current advertised ccode */
  45. /* per-band state (one per phy/radio) */
  46. struct brcms_cm_band bandstate[MAXBANDS];
  47. /* quiet channels currently for radar sensitivity or 11h support */
  48. chanvec_t quiet_channels; /* channels on which we cannot transmit */
  49. };
  50. static int brcms_c_channels_init(struct brcms_cm_info *wlc_cm,
  51. const struct country_info *country);
  52. static void brcms_c_set_country_common(struct brcms_cm_info *wlc_cm,
  53. const char *country_abbrev,
  54. const char *ccode, uint regrev,
  55. const struct country_info *country);
  56. static int brcms_c_set_countrycode(struct brcms_cm_info *wlc_cm,
  57. const char *ccode);
  58. static int brcms_c_set_countrycode_rev(struct brcms_cm_info *wlc_cm,
  59. const char *country_abbrev,
  60. const char *ccode, int regrev);
  61. static int brcms_c_country_aggregate_map(struct brcms_cm_info *wlc_cm,
  62. const char *ccode,
  63. char *mapped_ccode, uint *mapped_regrev);
  64. static const struct country_info *
  65. brcms_c_country_lookup_direct(const char *ccode, uint regrev);
  66. static const struct country_info *
  67. brcms_c_countrycode_map(struct brcms_cm_info *wlc_cm,
  68. const char *ccode, char *mapped_ccode,
  69. uint *mapped_regrev);
  70. static void brcms_c_channels_commit(struct brcms_cm_info *wlc_cm);
  71. static void brcms_c_quiet_channels_reset(struct brcms_cm_info *wlc_cm);
  72. static bool brcms_c_quiet_chanspec(struct brcms_cm_info *wlc_cm,
  73. chanspec_t chspec);
  74. static bool brcms_c_valid_channel20_db(struct brcms_cm_info *wlc_cm, uint val);
  75. static bool brcms_c_valid_channel20_in_band(struct brcms_cm_info *wlc_cm,
  76. uint bandunit, uint val);
  77. static bool brcms_c_valid_channel20(struct brcms_cm_info *wlc_cm, uint val);
  78. static const struct country_info *
  79. brcms_c_country_lookup(struct brcms_c_info *wlc, const char *ccode);
  80. static void brcms_c_locale_get_channels(const struct locale_info *locale,
  81. chanvec_t *valid_channels);
  82. static const struct locale_info *brcms_c_get_locale_2g(u8 locale_idx);
  83. static const struct locale_info *brcms_c_get_locale_5g(u8 locale_idx);
  84. static bool brcms_c_japan(struct brcms_c_info *wlc);
  85. static bool brcms_c_japan_ccode(const char *ccode);
  86. static void brcms_c_channel_min_txpower_limits_with_local_constraint(
  87. struct brcms_cm_info *wlc_cm, struct txpwr_limits *txpwr,
  88. u8 local_constraint_qdbm);
  89. static void brcms_c_locale_add_channels(chanvec_t *target,
  90. const chanvec_t *channels);
  91. static const struct locale_mimo_info *brcms_c_get_mimo_2g(u8 locale_idx);
  92. static const struct locale_mimo_info *brcms_c_get_mimo_5g(u8 locale_idx);
  93. /* QDB() macro takes a dB value and converts to a quarter dB value */
  94. #ifdef QDB
  95. #undef QDB
  96. #endif
  97. #define QDB(n) ((n) * BRCMS_TXPWR_DB_FACTOR)
  98. /* Regulatory Matrix Spreadsheet (CLM) MIMO v3.7.9 */
  99. /*
  100. * Some common channel sets
  101. */
  102. /* No channels */
  103. static const chanvec_t chanvec_none = {
  104. {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  105. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  106. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  107. 0x00, 0x00, 0x00, 0x00}
  108. };
  109. /* All 2.4 GHz HW channels */
  110. const chanvec_t chanvec_all_2G = {
  111. {0xfe, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  112. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  113. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  114. 0x00, 0x00, 0x00, 0x00}
  115. };
  116. /* All 5 GHz HW channels */
  117. const chanvec_t chanvec_all_5G = {
  118. {0x00, 0x00, 0x00, 0x00, 0x54, 0x55, 0x11, 0x11,
  119. 0x01, 0x00, 0x00, 0x00, 0x10, 0x11, 0x11, 0x11,
  120. 0x11, 0x11, 0x20, 0x22, 0x22, 0x00, 0x00, 0x11,
  121. 0x11, 0x11, 0x11, 0x01}
  122. };
  123. /*
  124. * Radar channel sets
  125. */
  126. /* No radar */
  127. #define radar_set_none chanvec_none
  128. static const chanvec_t radar_set1 = { /* Channels 52 - 64, 100 - 140 */
  129. {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x11, /* 52 - 60 */
  130. 0x01, 0x00, 0x00, 0x00, 0x10, 0x11, 0x11, 0x11, /* 64, 100 - 124 */
  131. 0x11, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 128 - 140 */
  132. 0x00, 0x00, 0x00, 0x00}
  133. };
  134. /*
  135. * Restricted channel sets
  136. */
  137. #define restricted_set_none chanvec_none
  138. /* Channels 34, 38, 42, 46 */
  139. static const chanvec_t restricted_set_japan_legacy = {
  140. {0x00, 0x00, 0x00, 0x00, 0x44, 0x44, 0x00, 0x00,
  141. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  142. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  143. 0x00, 0x00, 0x00, 0x00}
  144. };
  145. /* Channels 12, 13 */
  146. static const chanvec_t restricted_set_2g_short = {
  147. {0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  148. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  149. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  150. 0x00, 0x00, 0x00, 0x00}
  151. };
  152. /* Channel 165 */
  153. static const chanvec_t restricted_chan_165 = {
  154. {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  155. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  156. 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,
  157. 0x00, 0x00, 0x00, 0x00}
  158. };
  159. /* Channels 36 - 48 & 149 - 165 */
  160. static const chanvec_t restricted_low_hi = {
  161. {0x00, 0x00, 0x00, 0x00, 0x10, 0x11, 0x01, 0x00,
  162. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  163. 0x00, 0x00, 0x20, 0x22, 0x22, 0x00, 0x00, 0x00,
  164. 0x00, 0x00, 0x00, 0x00}
  165. };
  166. /* Channels 12 - 14 */
  167. static const chanvec_t restricted_set_12_13_14 = {
  168. {0x00, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  169. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  170. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  171. 0x00, 0x00, 0x00, 0x00}
  172. };
  173. #define LOCALE_CHAN_01_11 (1<<0)
  174. #define LOCALE_CHAN_12_13 (1<<1)
  175. #define LOCALE_CHAN_14 (1<<2)
  176. #define LOCALE_SET_5G_LOW_JP1 (1<<3) /* 34-48, step 2 */
  177. #define LOCALE_SET_5G_LOW_JP2 (1<<4) /* 34-46, step 4 */
  178. #define LOCALE_SET_5G_LOW1 (1<<5) /* 36-48, step 4 */
  179. #define LOCALE_SET_5G_LOW2 (1<<6) /* 52 */
  180. #define LOCALE_SET_5G_LOW3 (1<<7) /* 56-64, step 4 */
  181. #define LOCALE_SET_5G_MID1 (1<<8) /* 100-116, step 4 */
  182. #define LOCALE_SET_5G_MID2 (1<<9) /* 120-124, step 4 */
  183. #define LOCALE_SET_5G_MID3 (1<<10) /* 128 */
  184. #define LOCALE_SET_5G_HIGH1 (1<<11) /* 132-140, step 4 */
  185. #define LOCALE_SET_5G_HIGH2 (1<<12) /* 149-161, step 4 */
  186. #define LOCALE_SET_5G_HIGH3 (1<<13) /* 165 */
  187. #define LOCALE_CHAN_52_140_ALL (1<<14)
  188. #define LOCALE_SET_5G_HIGH4 (1<<15) /* 184-216 */
  189. #define LOCALE_CHAN_36_64 (LOCALE_SET_5G_LOW1 | LOCALE_SET_5G_LOW2 | LOCALE_SET_5G_LOW3)
  190. #define LOCALE_CHAN_52_64 (LOCALE_SET_5G_LOW2 | LOCALE_SET_5G_LOW3)
  191. #define LOCALE_CHAN_100_124 (LOCALE_SET_5G_MID1 | LOCALE_SET_5G_MID2)
  192. #define LOCALE_CHAN_100_140 \
  193. (LOCALE_SET_5G_MID1 | LOCALE_SET_5G_MID2 | LOCALE_SET_5G_MID3 | LOCALE_SET_5G_HIGH1)
  194. #define LOCALE_CHAN_149_165 (LOCALE_SET_5G_HIGH2 | LOCALE_SET_5G_HIGH3)
  195. #define LOCALE_CHAN_184_216 LOCALE_SET_5G_HIGH4
  196. #define LOCALE_CHAN_01_14 (LOCALE_CHAN_01_11 | LOCALE_CHAN_12_13 | LOCALE_CHAN_14)
  197. #define LOCALE_RADAR_SET_NONE 0
  198. #define LOCALE_RADAR_SET_1 1
  199. #define LOCALE_RESTRICTED_NONE 0
  200. #define LOCALE_RESTRICTED_SET_2G_SHORT 1
  201. #define LOCALE_RESTRICTED_CHAN_165 2
  202. #define LOCALE_CHAN_ALL_5G 3
  203. #define LOCALE_RESTRICTED_JAPAN_LEGACY 4
  204. #define LOCALE_RESTRICTED_11D_2G 5
  205. #define LOCALE_RESTRICTED_11D_5G 6
  206. #define LOCALE_RESTRICTED_LOW_HI 7
  207. #define LOCALE_RESTRICTED_12_13_14 8
  208. /* global memory to provide working buffer for expanded locale */
  209. static const chanvec_t *g_table_radar_set[] = {
  210. &chanvec_none,
  211. &radar_set1
  212. };
  213. static const chanvec_t *g_table_restricted_chan[] = {
  214. &chanvec_none, /* restricted_set_none */
  215. &restricted_set_2g_short,
  216. &restricted_chan_165,
  217. &chanvec_all_5G,
  218. &restricted_set_japan_legacy,
  219. &chanvec_all_2G, /* restricted_set_11d_2G */
  220. &chanvec_all_5G, /* restricted_set_11d_5G */
  221. &restricted_low_hi,
  222. &restricted_set_12_13_14
  223. };
  224. static const chanvec_t locale_2g_01_11 = {
  225. {0xfe, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  226. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  227. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  228. 0x00, 0x00, 0x00, 0x00}
  229. };
  230. static const chanvec_t locale_2g_12_13 = {
  231. {0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  232. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  233. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  234. 0x00, 0x00, 0x00, 0x00}
  235. };
  236. static const chanvec_t locale_2g_14 = {
  237. {0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  238. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  239. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  240. 0x00, 0x00, 0x00, 0x00}
  241. };
  242. static const chanvec_t locale_5g_LOW_JP1 = {
  243. {0x00, 0x00, 0x00, 0x00, 0x54, 0x55, 0x01, 0x00,
  244. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  245. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  246. 0x00, 0x00, 0x00, 0x00}
  247. };
  248. static const chanvec_t locale_5g_LOW_JP2 = {
  249. {0x00, 0x00, 0x00, 0x00, 0x44, 0x44, 0x00, 0x00,
  250. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  251. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  252. 0x00, 0x00, 0x00, 0x00}
  253. };
  254. static const chanvec_t locale_5g_LOW1 = {
  255. {0x00, 0x00, 0x00, 0x00, 0x10, 0x11, 0x01, 0x00,
  256. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  257. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  258. 0x00, 0x00, 0x00, 0x00}
  259. };
  260. static const chanvec_t locale_5g_LOW2 = {
  261. {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00,
  262. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  263. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  264. 0x00, 0x00, 0x00, 0x00}
  265. };
  266. static const chanvec_t locale_5g_LOW3 = {
  267. {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11,
  268. 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  269. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  270. 0x00, 0x00, 0x00, 0x00}
  271. };
  272. static const chanvec_t locale_5g_MID1 = {
  273. {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  274. 0x00, 0x00, 0x00, 0x00, 0x10, 0x11, 0x11, 0x00,
  275. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  276. 0x00, 0x00, 0x00, 0x00}
  277. };
  278. static const chanvec_t locale_5g_MID2 = {
  279. {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  280. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11,
  281. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  282. 0x00, 0x00, 0x00, 0x00}
  283. };
  284. static const chanvec_t locale_5g_MID3 = {
  285. {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  286. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  287. 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  288. 0x00, 0x00, 0x00, 0x00}
  289. };
  290. static const chanvec_t locale_5g_HIGH1 = {
  291. {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  292. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  293. 0x10, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  294. 0x00, 0x00, 0x00, 0x00}
  295. };
  296. static const chanvec_t locale_5g_HIGH2 = {
  297. {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  298. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  299. 0x00, 0x00, 0x20, 0x22, 0x02, 0x00, 0x00, 0x00,
  300. 0x00, 0x00, 0x00, 0x00}
  301. };
  302. static const chanvec_t locale_5g_HIGH3 = {
  303. {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  304. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  305. 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,
  306. 0x00, 0x00, 0x00, 0x00}
  307. };
  308. static const chanvec_t locale_5g_52_140_ALL = {
  309. {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x11,
  310. 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
  311. 0x11, 0x11, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,
  312. 0x00, 0x00, 0x00, 0x00}
  313. };
  314. static const chanvec_t locale_5g_HIGH4 = {
  315. {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  316. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  317. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11,
  318. 0x11, 0x11, 0x11, 0x11}
  319. };
  320. static const chanvec_t *g_table_locale_base[] = {
  321. &locale_2g_01_11,
  322. &locale_2g_12_13,
  323. &locale_2g_14,
  324. &locale_5g_LOW_JP1,
  325. &locale_5g_LOW_JP2,
  326. &locale_5g_LOW1,
  327. &locale_5g_LOW2,
  328. &locale_5g_LOW3,
  329. &locale_5g_MID1,
  330. &locale_5g_MID2,
  331. &locale_5g_MID3,
  332. &locale_5g_HIGH1,
  333. &locale_5g_HIGH2,
  334. &locale_5g_HIGH3,
  335. &locale_5g_52_140_ALL,
  336. &locale_5g_HIGH4
  337. };
  338. static void brcms_c_locale_add_channels(chanvec_t *target,
  339. const chanvec_t *channels)
  340. {
  341. u8 i;
  342. for (i = 0; i < sizeof(chanvec_t); i++) {
  343. target->vec[i] |= channels->vec[i];
  344. }
  345. }
  346. static void brcms_c_locale_get_channels(const struct locale_info *locale,
  347. chanvec_t *channels)
  348. {
  349. u8 i;
  350. memset(channels, 0, sizeof(chanvec_t));
  351. for (i = 0; i < ARRAY_SIZE(g_table_locale_base); i++) {
  352. if (locale->valid_channels & (1 << i)) {
  353. brcms_c_locale_add_channels(channels,
  354. g_table_locale_base[i]);
  355. }
  356. }
  357. }
  358. /*
  359. * Locale Definitions - 2.4 GHz
  360. */
  361. static const struct locale_info locale_i = { /* locale i. channel 1 - 13 */
  362. LOCALE_CHAN_01_11 | LOCALE_CHAN_12_13,
  363. LOCALE_RADAR_SET_NONE,
  364. LOCALE_RESTRICTED_SET_2G_SHORT,
  365. {QDB(19), QDB(19), QDB(19),
  366. QDB(19), QDB(19), QDB(19)},
  367. {20, 20, 20, 0},
  368. BRCMS_EIRP
  369. };
  370. /*
  371. * Locale Definitions - 5 GHz
  372. */
  373. static const struct locale_info locale_11 = {
  374. /* locale 11. channel 36 - 48, 52 - 64, 100 - 140, 149 - 165 */
  375. LOCALE_CHAN_36_64 | LOCALE_CHAN_100_140 | LOCALE_CHAN_149_165,
  376. LOCALE_RADAR_SET_1,
  377. LOCALE_RESTRICTED_NONE,
  378. {QDB(21), QDB(21), QDB(21), QDB(21), QDB(21)},
  379. {23, 23, 23, 30, 30},
  380. BRCMS_EIRP | BRCMS_DFS_EU
  381. };
  382. #define LOCALE_2G_IDX_i 0
  383. static const struct locale_info *g_locale_2g_table[] = {
  384. &locale_i
  385. };
  386. #define LOCALE_5G_IDX_11 0
  387. static const struct locale_info *g_locale_5g_table[] = {
  388. &locale_11
  389. };
  390. /*
  391. * MIMO Locale Definitions - 2.4 GHz
  392. */
  393. static const struct locale_mimo_info locale_bn = {
  394. {QDB(13), QDB(13), QDB(13), QDB(13), QDB(13),
  395. QDB(13), QDB(13), QDB(13), QDB(13), QDB(13),
  396. QDB(13), QDB(13), QDB(13)},
  397. {0, 0, QDB(13), QDB(13), QDB(13),
  398. QDB(13), QDB(13), QDB(13), QDB(13), QDB(13),
  399. QDB(13), 0, 0},
  400. 0
  401. };
  402. /* locale mimo 2g indexes */
  403. #define LOCALE_MIMO_IDX_bn 0
  404. static const struct locale_mimo_info *g_mimo_2g_table[] = {
  405. &locale_bn
  406. };
  407. /*
  408. * MIMO Locale Definitions - 5 GHz
  409. */
  410. static const struct locale_mimo_info locale_11n = {
  411. { /* 12.5 dBm */ 50, 50, 50, QDB(15), QDB(15)},
  412. {QDB(14), QDB(15), QDB(15), QDB(15), QDB(15)},
  413. 0
  414. };
  415. #define LOCALE_MIMO_IDX_11n 0
  416. static const struct locale_mimo_info *g_mimo_5g_table[] = {
  417. &locale_11n
  418. };
  419. #ifdef LC
  420. #undef LC
  421. #endif
  422. #define LC(id) LOCALE_MIMO_IDX_ ## id
  423. #ifdef LC_2G
  424. #undef LC_2G
  425. #endif
  426. #define LC_2G(id) LOCALE_2G_IDX_ ## id
  427. #ifdef LC_5G
  428. #undef LC_5G
  429. #endif
  430. #define LC_5G(id) LOCALE_5G_IDX_ ## id
  431. #define LOCALES(band2, band5, mimo2, mimo5) {LC_2G(band2), LC_5G(band5), LC(mimo2), LC(mimo5)}
  432. static const struct {
  433. char abbrev[BRCM_CNTRY_BUF_SZ]; /* country abbreviation */
  434. struct country_info country;
  435. } cntry_locales[] = {
  436. {
  437. "X2", LOCALES(i, 11, bn, 11n)}, /* Worldwide RoW 2 */
  438. };
  439. #ifdef SUPPORT_40MHZ
  440. /* 20MHz channel info for 40MHz pairing support */
  441. struct chan20_info {
  442. u8 sb;
  443. u8 adj_sbs;
  444. };
  445. /* indicates adjacent channels that are allowed for a 40 Mhz channel and
  446. * those that permitted by the HT
  447. */
  448. struct chan20_info chan20_info[] = {
  449. /* 11b/11g */
  450. /* 0 */ {1, (CH_UPPER_SB | CH_EWA_VALID)},
  451. /* 1 */ {2, (CH_UPPER_SB | CH_EWA_VALID)},
  452. /* 2 */ {3, (CH_UPPER_SB | CH_EWA_VALID)},
  453. /* 3 */ {4, (CH_UPPER_SB | CH_EWA_VALID)},
  454. /* 4 */ {5, (CH_UPPER_SB | CH_LOWER_SB | CH_EWA_VALID)},
  455. /* 5 */ {6, (CH_UPPER_SB | CH_LOWER_SB | CH_EWA_VALID)},
  456. /* 6 */ {7, (CH_UPPER_SB | CH_LOWER_SB | CH_EWA_VALID)},
  457. /* 7 */ {8, (CH_UPPER_SB | CH_LOWER_SB | CH_EWA_VALID)},
  458. /* 8 */ {9, (CH_UPPER_SB | CH_LOWER_SB | CH_EWA_VALID)},
  459. /* 9 */ {10, (CH_LOWER_SB | CH_EWA_VALID)},
  460. /* 10 */ {11, (CH_LOWER_SB | CH_EWA_VALID)},
  461. /* 11 */ {12, (CH_LOWER_SB)},
  462. /* 12 */ {13, (CH_LOWER_SB)},
  463. /* 13 */ {14, (CH_LOWER_SB)},
  464. /* 11a japan high */
  465. /* 14 */ {34, (CH_UPPER_SB)},
  466. /* 15 */ {38, (CH_LOWER_SB)},
  467. /* 16 */ {42, (CH_LOWER_SB)},
  468. /* 17 */ {46, (CH_LOWER_SB)},
  469. /* 11a usa low */
  470. /* 18 */ {36, (CH_UPPER_SB | CH_EWA_VALID)},
  471. /* 19 */ {40, (CH_LOWER_SB | CH_EWA_VALID)},
  472. /* 20 */ {44, (CH_UPPER_SB | CH_EWA_VALID)},
  473. /* 21 */ {48, (CH_LOWER_SB | CH_EWA_VALID)},
  474. /* 22 */ {52, (CH_UPPER_SB | CH_EWA_VALID)},
  475. /* 23 */ {56, (CH_LOWER_SB | CH_EWA_VALID)},
  476. /* 24 */ {60, (CH_UPPER_SB | CH_EWA_VALID)},
  477. /* 25 */ {64, (CH_LOWER_SB | CH_EWA_VALID)},
  478. /* 11a Europe */
  479. /* 26 */ {100, (CH_UPPER_SB | CH_EWA_VALID)},
  480. /* 27 */ {104, (CH_LOWER_SB | CH_EWA_VALID)},
  481. /* 28 */ {108, (CH_UPPER_SB | CH_EWA_VALID)},
  482. /* 29 */ {112, (CH_LOWER_SB | CH_EWA_VALID)},
  483. /* 30 */ {116, (CH_UPPER_SB | CH_EWA_VALID)},
  484. /* 31 */ {120, (CH_LOWER_SB | CH_EWA_VALID)},
  485. /* 32 */ {124, (CH_UPPER_SB | CH_EWA_VALID)},
  486. /* 33 */ {128, (CH_LOWER_SB | CH_EWA_VALID)},
  487. /* 34 */ {132, (CH_UPPER_SB | CH_EWA_VALID)},
  488. /* 35 */ {136, (CH_LOWER_SB | CH_EWA_VALID)},
  489. /* 36 */ {140, (CH_LOWER_SB)},
  490. /* 11a usa high, ref5 only */
  491. /* The 0x80 bit in pdiv means these are REF5, other entries are REF20 */
  492. /* 37 */ {149, (CH_UPPER_SB | CH_EWA_VALID)},
  493. /* 38 */ {153, (CH_LOWER_SB | CH_EWA_VALID)},
  494. /* 39 */ {157, (CH_UPPER_SB | CH_EWA_VALID)},
  495. /* 40 */ {161, (CH_LOWER_SB | CH_EWA_VALID)},
  496. /* 41 */ {165, (CH_LOWER_SB)},
  497. /* 11a japan */
  498. /* 42 */ {184, (CH_UPPER_SB)},
  499. /* 43 */ {188, (CH_LOWER_SB)},
  500. /* 44 */ {192, (CH_UPPER_SB)},
  501. /* 45 */ {196, (CH_LOWER_SB)},
  502. /* 46 */ {200, (CH_UPPER_SB)},
  503. /* 47 */ {204, (CH_LOWER_SB)},
  504. /* 48 */ {208, (CH_UPPER_SB)},
  505. /* 49 */ {212, (CH_LOWER_SB)},
  506. /* 50 */ {216, (CH_LOWER_SB)}
  507. };
  508. #endif /* SUPPORT_40MHZ */
  509. static const struct locale_info *brcms_c_get_locale_2g(u8 locale_idx)
  510. {
  511. if (locale_idx >= ARRAY_SIZE(g_locale_2g_table)) {
  512. return NULL; /* error condition */
  513. }
  514. return g_locale_2g_table[locale_idx];
  515. }
  516. static const struct locale_info *brcms_c_get_locale_5g(u8 locale_idx)
  517. {
  518. if (locale_idx >= ARRAY_SIZE(g_locale_5g_table)) {
  519. return NULL; /* error condition */
  520. }
  521. return g_locale_5g_table[locale_idx];
  522. }
  523. static const struct locale_mimo_info *brcms_c_get_mimo_2g(u8 locale_idx)
  524. {
  525. if (locale_idx >= ARRAY_SIZE(g_mimo_2g_table)) {
  526. return NULL;
  527. }
  528. return g_mimo_2g_table[locale_idx];
  529. }
  530. static const struct locale_mimo_info *brcms_c_get_mimo_5g(u8 locale_idx)
  531. {
  532. if (locale_idx >= ARRAY_SIZE(g_mimo_5g_table)) {
  533. return NULL;
  534. }
  535. return g_mimo_5g_table[locale_idx];
  536. }
  537. struct brcms_cm_info *brcms_c_channel_mgr_attach(struct brcms_c_info *wlc)
  538. {
  539. struct brcms_cm_info *wlc_cm;
  540. char country_abbrev[BRCM_CNTRY_BUF_SZ];
  541. const struct country_info *country;
  542. struct brcms_pub *pub = wlc->pub;
  543. char *ccode;
  544. BCMMSG(wlc->wiphy, "wl%d\n", wlc->pub->unit);
  545. wlc_cm = kzalloc(sizeof(struct brcms_cm_info), GFP_ATOMIC);
  546. if (wlc_cm == NULL) {
  547. wiphy_err(wlc->wiphy, "wl%d: %s: out of memory", pub->unit,
  548. __func__);
  549. return NULL;
  550. }
  551. wlc_cm->pub = pub;
  552. wlc_cm->wlc = wlc;
  553. wlc->cmi = wlc_cm;
  554. /* store the country code for passing up as a regulatory hint */
  555. ccode = getvar(wlc->pub->vars, "ccode");
  556. if (ccode) {
  557. strncpy(wlc->pub->srom_ccode, ccode, BRCM_CNTRY_BUF_SZ - 1);
  558. }
  559. /* internal country information which must match regulatory constraints in firmware */
  560. memset(country_abbrev, 0, BRCM_CNTRY_BUF_SZ);
  561. strncpy(country_abbrev, "X2", sizeof(country_abbrev) - 1);
  562. country = brcms_c_country_lookup(wlc, country_abbrev);
  563. /* save default country for exiting 11d regulatory mode */
  564. strncpy(wlc->country_default, country_abbrev, BRCM_CNTRY_BUF_SZ - 1);
  565. /* initialize autocountry_default to driver default */
  566. strncpy(wlc->autocountry_default, "X2", BRCM_CNTRY_BUF_SZ - 1);
  567. brcms_c_set_countrycode(wlc_cm, country_abbrev);
  568. return wlc_cm;
  569. }
  570. void brcms_c_channel_mgr_detach(struct brcms_cm_info *wlc_cm)
  571. {
  572. kfree(wlc_cm);
  573. }
  574. u8
  575. brcms_c_channel_locale_flags_in_band(struct brcms_cm_info *wlc_cm,
  576. uint bandunit)
  577. {
  578. return wlc_cm->bandstate[bandunit].locale_flags;
  579. }
  580. /* set the driver's current country and regulatory information using a country code
  581. * as the source. Lookup built in country information found with the country code.
  582. */
  583. static int
  584. brcms_c_set_countrycode(struct brcms_cm_info *wlc_cm, const char *ccode)
  585. {
  586. char country_abbrev[BRCM_CNTRY_BUF_SZ];
  587. strncpy(country_abbrev, ccode, BRCM_CNTRY_BUF_SZ);
  588. return brcms_c_set_countrycode_rev(wlc_cm, country_abbrev, ccode, -1);
  589. }
  590. static int
  591. brcms_c_set_countrycode_rev(struct brcms_cm_info *wlc_cm,
  592. const char *country_abbrev,
  593. const char *ccode, int regrev)
  594. {
  595. const struct country_info *country;
  596. char mapped_ccode[BRCM_CNTRY_BUF_SZ];
  597. uint mapped_regrev;
  598. /* if regrev is -1, lookup the mapped country code,
  599. * otherwise use the ccode and regrev directly
  600. */
  601. if (regrev == -1) {
  602. /* map the country code to a built-in country code, regrev, and country_info */
  603. country =
  604. brcms_c_countrycode_map(wlc_cm, ccode, mapped_ccode,
  605. &mapped_regrev);
  606. } else {
  607. /* find the matching built-in country definition */
  608. country = brcms_c_country_lookup_direct(ccode, regrev);
  609. strncpy(mapped_ccode, ccode, BRCM_CNTRY_BUF_SZ);
  610. mapped_regrev = regrev;
  611. }
  612. if (country == NULL)
  613. return -EINVAL;
  614. /* set the driver state for the country */
  615. brcms_c_set_country_common(wlc_cm, country_abbrev, mapped_ccode,
  616. mapped_regrev, country);
  617. return 0;
  618. }
  619. /* set the driver's current country and regulatory information using a country code
  620. * as the source. Look up built in country information found with the country code.
  621. */
  622. static void
  623. brcms_c_set_country_common(struct brcms_cm_info *wlc_cm,
  624. const char *country_abbrev,
  625. const char *ccode, uint regrev,
  626. const struct country_info *country)
  627. {
  628. const struct locale_mimo_info *li_mimo;
  629. const struct locale_info *locale;
  630. struct brcms_c_info *wlc = wlc_cm->wlc;
  631. char prev_country_abbrev[BRCM_CNTRY_BUF_SZ];
  632. /* save current country state */
  633. wlc_cm->country = country;
  634. memset(&prev_country_abbrev, 0, BRCM_CNTRY_BUF_SZ);
  635. strncpy(prev_country_abbrev, wlc_cm->country_abbrev,
  636. BRCM_CNTRY_BUF_SZ - 1);
  637. strncpy(wlc_cm->country_abbrev, country_abbrev, BRCM_CNTRY_BUF_SZ - 1);
  638. strncpy(wlc_cm->ccode, ccode, BRCM_CNTRY_BUF_SZ - 1);
  639. wlc_cm->regrev = regrev;
  640. /* disable/restore nmode based on country regulations */
  641. li_mimo = brcms_c_get_mimo_2g(country->locale_mimo_2G);
  642. if (li_mimo && (li_mimo->flags & BRCMS_NO_MIMO)) {
  643. brcms_c_set_nmode(wlc, OFF);
  644. wlc->stf->no_cddstbc = true;
  645. } else {
  646. wlc->stf->no_cddstbc = false;
  647. if (N_ENAB(wlc->pub) != wlc->protection->nmode_user)
  648. brcms_c_set_nmode(wlc, wlc->protection->nmode_user);
  649. }
  650. brcms_c_stf_ss_update(wlc, wlc->bandstate[BAND_2G_INDEX]);
  651. brcms_c_stf_ss_update(wlc, wlc->bandstate[BAND_5G_INDEX]);
  652. /* set or restore gmode as required by regulatory */
  653. locale = brcms_c_get_locale_2g(country->locale_2G);
  654. if (locale && (locale->flags & BRCMS_NO_OFDM)) {
  655. brcms_c_set_gmode(wlc, GMODE_LEGACY_B, false);
  656. } else {
  657. brcms_c_set_gmode(wlc, wlc->protection->gmode_user, false);
  658. }
  659. brcms_c_channels_init(wlc_cm, country);
  660. return;
  661. }
  662. /* Lookup a country info structure from a null terminated country code
  663. * The lookup is case sensitive.
  664. */
  665. static const struct country_info *
  666. brcms_c_country_lookup(struct brcms_c_info *wlc, const char *ccode)
  667. {
  668. const struct country_info *country;
  669. char mapped_ccode[BRCM_CNTRY_BUF_SZ];
  670. uint mapped_regrev;
  671. /* map the country code to a built-in country code, regrev, and country_info struct */
  672. country = brcms_c_countrycode_map(wlc->cmi, ccode, mapped_ccode,
  673. &mapped_regrev);
  674. return country;
  675. }
  676. static const struct country_info *
  677. brcms_c_countrycode_map(struct brcms_cm_info *wlc_cm, const char *ccode,
  678. char *mapped_ccode, uint *mapped_regrev)
  679. {
  680. struct brcms_c_info *wlc = wlc_cm->wlc;
  681. const struct country_info *country;
  682. uint srom_regrev = wlc_cm->srom_regrev;
  683. const char *srom_ccode = wlc_cm->srom_ccode;
  684. int mapped;
  685. /* check for currently supported ccode size */
  686. if (strlen(ccode) > (BRCM_CNTRY_BUF_SZ - 1)) {
  687. wiphy_err(wlc->wiphy, "wl%d: %s: ccode \"%s\" too long for "
  688. "match\n", wlc->pub->unit, __func__, ccode);
  689. return NULL;
  690. }
  691. /* default mapping is the given ccode and regrev 0 */
  692. strncpy(mapped_ccode, ccode, BRCM_CNTRY_BUF_SZ);
  693. *mapped_regrev = 0;
  694. /* If the desired country code matches the srom country code,
  695. * then the mapped country is the srom regulatory rev.
  696. * Otherwise look for an aggregate mapping.
  697. */
  698. if (!strcmp(srom_ccode, ccode)) {
  699. *mapped_regrev = srom_regrev;
  700. mapped = 0;
  701. wiphy_err(wlc->wiphy, "srom_code == ccode %s\n", __func__);
  702. } else {
  703. mapped =
  704. brcms_c_country_aggregate_map(wlc_cm, ccode, mapped_ccode,
  705. mapped_regrev);
  706. }
  707. /* find the matching built-in country definition */
  708. country = brcms_c_country_lookup_direct(mapped_ccode, *mapped_regrev);
  709. /* if there is not an exact rev match, default to rev zero */
  710. if (country == NULL && *mapped_regrev != 0) {
  711. *mapped_regrev = 0;
  712. country =
  713. brcms_c_country_lookup_direct(mapped_ccode, *mapped_regrev);
  714. }
  715. return country;
  716. }
  717. static int
  718. brcms_c_country_aggregate_map(struct brcms_cm_info *wlc_cm, const char *ccode,
  719. char *mapped_ccode, uint *mapped_regrev)
  720. {
  721. return false;
  722. }
  723. /* Lookup a country info structure from a null terminated country
  724. * abbreviation and regrev directly with no translation.
  725. */
  726. static const struct country_info *
  727. brcms_c_country_lookup_direct(const char *ccode, uint regrev)
  728. {
  729. uint size, i;
  730. /* Should just return 0 for single locale driver. */
  731. /* Keep it this way in case we add more locales. (for now anyway) */
  732. /* all other country def arrays are for regrev == 0, so if regrev is non-zero, fail */
  733. if (regrev > 0)
  734. return NULL;
  735. /* find matched table entry from country code */
  736. size = ARRAY_SIZE(cntry_locales);
  737. for (i = 0; i < size; i++) {
  738. if (strcmp(ccode, cntry_locales[i].abbrev) == 0) {
  739. return &cntry_locales[i].country;
  740. }
  741. }
  742. return NULL;
  743. }
  744. static int
  745. brcms_c_channels_init(struct brcms_cm_info *wlc_cm,
  746. const struct country_info *country)
  747. {
  748. struct brcms_c_info *wlc = wlc_cm->wlc;
  749. uint i, j;
  750. struct brcms_band *band;
  751. const struct locale_info *li;
  752. chanvec_t sup_chan;
  753. const struct locale_mimo_info *li_mimo;
  754. band = wlc->band;
  755. for (i = 0; i < NBANDS(wlc);
  756. i++, band = wlc->bandstate[OTHERBANDUNIT(wlc)]) {
  757. li = BAND_5G(band->bandtype) ?
  758. brcms_c_get_locale_5g(country->locale_5G) :
  759. brcms_c_get_locale_2g(country->locale_2G);
  760. wlc_cm->bandstate[band->bandunit].locale_flags = li->flags;
  761. li_mimo = BAND_5G(band->bandtype) ?
  762. brcms_c_get_mimo_5g(country->locale_mimo_5G) :
  763. brcms_c_get_mimo_2g(country->locale_mimo_2G);
  764. /* merge the mimo non-mimo locale flags */
  765. wlc_cm->bandstate[band->bandunit].locale_flags |=
  766. li_mimo->flags;
  767. wlc_cm->bandstate[band->bandunit].restricted_channels =
  768. g_table_restricted_chan[li->restricted_channels];
  769. wlc_cm->bandstate[band->bandunit].radar_channels =
  770. g_table_radar_set[li->radar_channels];
  771. /* set the channel availability,
  772. * masking out the channels that may not be supported on this phy
  773. */
  774. wlc_phy_chanspec_band_validch(band->pi, band->bandtype,
  775. &sup_chan);
  776. brcms_c_locale_get_channels(li,
  777. &wlc_cm->bandstate[band->bandunit].
  778. valid_channels);
  779. for (j = 0; j < sizeof(chanvec_t); j++)
  780. wlc_cm->bandstate[band->bandunit].valid_channels.
  781. vec[j] &= sup_chan.vec[j];
  782. }
  783. brcms_c_quiet_channels_reset(wlc_cm);
  784. brcms_c_channels_commit(wlc_cm);
  785. return 0;
  786. }
  787. /* Update the radio state (enable/disable) and tx power targets
  788. * based on a new set of channel/regulatory information
  789. */
  790. static void brcms_c_channels_commit(struct brcms_cm_info *wlc_cm)
  791. {
  792. struct brcms_c_info *wlc = wlc_cm->wlc;
  793. uint chan;
  794. struct txpwr_limits txpwr;
  795. /* search for the existence of any valid channel */
  796. for (chan = 0; chan < MAXCHANNEL; chan++) {
  797. if (VALID_CHANNEL20_DB(wlc, chan)) {
  798. break;
  799. }
  800. }
  801. if (chan == MAXCHANNEL)
  802. chan = INVCHANNEL;
  803. /* based on the channel search above, set or clear WL_RADIO_COUNTRY_DISABLE */
  804. if (chan == INVCHANNEL) {
  805. /* country/locale with no valid channels, set the radio disable bit */
  806. mboolset(wlc->pub->radio_disabled, WL_RADIO_COUNTRY_DISABLE);
  807. wiphy_err(wlc->wiphy, "wl%d: %s: no valid channel for \"%s\" "
  808. "nbands %d bandlocked %d\n", wlc->pub->unit,
  809. __func__, wlc_cm->country_abbrev, NBANDS(wlc),
  810. wlc->bandlocked);
  811. } else
  812. if (mboolisset(wlc->pub->radio_disabled,
  813. WL_RADIO_COUNTRY_DISABLE)) {
  814. /* country/locale with valid channel, clear the radio disable bit */
  815. mboolclr(wlc->pub->radio_disabled, WL_RADIO_COUNTRY_DISABLE);
  816. }
  817. /* Now that the country abbreviation is set, if the radio supports 2G, then
  818. * set channel 14 restrictions based on the new locale.
  819. */
  820. if (NBANDS(wlc) > 1 || BAND_2G(wlc->band->bandtype)) {
  821. wlc_phy_chanspec_ch14_widefilter_set(wlc->band->pi,
  822. brcms_c_japan(wlc) ? true :
  823. false);
  824. }
  825. if (wlc->pub->up && chan != INVCHANNEL) {
  826. brcms_c_channel_reg_limits(wlc_cm, wlc->chanspec, &txpwr);
  827. brcms_c_channel_min_txpower_limits_with_local_constraint(wlc_cm,
  828. &txpwr, BRCMS_TXPWR_MAX);
  829. wlc_phy_txpower_limit_set(wlc->band->pi, &txpwr, wlc->chanspec);
  830. }
  831. }
  832. /* reset the quiet channels vector to the union of the restricted and radar channel sets */
  833. static void brcms_c_quiet_channels_reset(struct brcms_cm_info *wlc_cm)
  834. {
  835. struct brcms_c_info *wlc = wlc_cm->wlc;
  836. uint i, j;
  837. struct brcms_band *band;
  838. const chanvec_t *chanvec;
  839. memset(&wlc_cm->quiet_channels, 0, sizeof(chanvec_t));
  840. band = wlc->band;
  841. for (i = 0; i < NBANDS(wlc);
  842. i++, band = wlc->bandstate[OTHERBANDUNIT(wlc)]) {
  843. /* initialize quiet channels for restricted channels */
  844. chanvec = wlc_cm->bandstate[band->bandunit].restricted_channels;
  845. for (j = 0; j < sizeof(chanvec_t); j++)
  846. wlc_cm->quiet_channels.vec[j] |= chanvec->vec[j];
  847. }
  848. }
  849. static bool
  850. brcms_c_quiet_chanspec(struct brcms_cm_info *wlc_cm, chanspec_t chspec)
  851. {
  852. return N_ENAB(wlc_cm->wlc->pub) && CHSPEC_IS40(chspec) ?
  853. (isset
  854. (wlc_cm->quiet_channels.vec,
  855. LOWER_20_SB(CHSPEC_CHANNEL(chspec)))
  856. || isset(wlc_cm->quiet_channels.vec,
  857. UPPER_20_SB(CHSPEC_CHANNEL(chspec)))) : isset(wlc_cm->
  858. quiet_channels.
  859. vec,
  860. CHSPEC_CHANNEL
  861. (chspec));
  862. }
  863. /* Is the channel valid for the current locale? (but don't consider channels not
  864. * available due to bandlocking)
  865. */
  866. static bool brcms_c_valid_channel20_db(struct brcms_cm_info *wlc_cm, uint val)
  867. {
  868. struct brcms_c_info *wlc = wlc_cm->wlc;
  869. return VALID_CHANNEL20(wlc, val) ||
  870. (!wlc->bandlocked
  871. && VALID_CHANNEL20_IN_BAND(wlc, OTHERBANDUNIT(wlc), val));
  872. }
  873. /* Is the channel valid for the current locale and specified band? */
  874. static bool brcms_c_valid_channel20_in_band(struct brcms_cm_info *wlc_cm,
  875. uint bandunit, uint val)
  876. {
  877. return ((val < MAXCHANNEL)
  878. && isset(wlc_cm->bandstate[bandunit].valid_channels.vec, val));
  879. }
  880. /* Is the channel valid for the current locale and current band? */
  881. static bool brcms_c_valid_channel20(struct brcms_cm_info *wlc_cm, uint val)
  882. {
  883. struct brcms_c_info *wlc = wlc_cm->wlc;
  884. return ((val < MAXCHANNEL) &&
  885. isset(wlc_cm->bandstate[wlc->band->bandunit].valid_channels.vec,
  886. val));
  887. }
  888. static void
  889. brcms_c_channel_min_txpower_limits_with_local_constraint(
  890. struct brcms_cm_info *wlc_cm, struct txpwr_limits *txpwr,
  891. u8 local_constraint_qdbm)
  892. {
  893. int j;
  894. /* CCK Rates */
  895. for (j = 0; j < WL_TX_POWER_CCK_NUM; j++) {
  896. txpwr->cck[j] = min(txpwr->cck[j], local_constraint_qdbm);
  897. }
  898. /* 20 MHz Legacy OFDM SISO */
  899. for (j = 0; j < WL_TX_POWER_OFDM_NUM; j++) {
  900. txpwr->ofdm[j] = min(txpwr->ofdm[j], local_constraint_qdbm);
  901. }
  902. /* 20 MHz Legacy OFDM CDD */
  903. for (j = 0; j < BRCMS_NUM_RATES_OFDM; j++) {
  904. txpwr->ofdm_cdd[j] =
  905. min(txpwr->ofdm_cdd[j], local_constraint_qdbm);
  906. }
  907. /* 40 MHz Legacy OFDM SISO */
  908. for (j = 0; j < BRCMS_NUM_RATES_OFDM; j++) {
  909. txpwr->ofdm_40_siso[j] =
  910. min(txpwr->ofdm_40_siso[j], local_constraint_qdbm);
  911. }
  912. /* 40 MHz Legacy OFDM CDD */
  913. for (j = 0; j < BRCMS_NUM_RATES_OFDM; j++) {
  914. txpwr->ofdm_40_cdd[j] =
  915. min(txpwr->ofdm_40_cdd[j], local_constraint_qdbm);
  916. }
  917. /* 20MHz MCS 0-7 SISO */
  918. for (j = 0; j < BRCMS_NUM_RATES_MCS_1_STREAM; j++) {
  919. txpwr->mcs_20_siso[j] =
  920. min(txpwr->mcs_20_siso[j], local_constraint_qdbm);
  921. }
  922. /* 20MHz MCS 0-7 CDD */
  923. for (j = 0; j < BRCMS_NUM_RATES_MCS_1_STREAM; j++) {
  924. txpwr->mcs_20_cdd[j] =
  925. min(txpwr->mcs_20_cdd[j], local_constraint_qdbm);
  926. }
  927. /* 20MHz MCS 0-7 STBC */
  928. for (j = 0; j < BRCMS_NUM_RATES_MCS_1_STREAM; j++) {
  929. txpwr->mcs_20_stbc[j] =
  930. min(txpwr->mcs_20_stbc[j], local_constraint_qdbm);
  931. }
  932. /* 20MHz MCS 8-15 MIMO */
  933. for (j = 0; j < BRCMS_NUM_RATES_MCS_2_STREAM; j++)
  934. txpwr->mcs_20_mimo[j] =
  935. min(txpwr->mcs_20_mimo[j], local_constraint_qdbm);
  936. /* 40MHz MCS 0-7 SISO */
  937. for (j = 0; j < BRCMS_NUM_RATES_MCS_1_STREAM; j++) {
  938. txpwr->mcs_40_siso[j] =
  939. min(txpwr->mcs_40_siso[j], local_constraint_qdbm);
  940. }
  941. /* 40MHz MCS 0-7 CDD */
  942. for (j = 0; j < BRCMS_NUM_RATES_MCS_1_STREAM; j++) {
  943. txpwr->mcs_40_cdd[j] =
  944. min(txpwr->mcs_40_cdd[j], local_constraint_qdbm);
  945. }
  946. /* 40MHz MCS 0-7 STBC */
  947. for (j = 0; j < BRCMS_NUM_RATES_MCS_1_STREAM; j++) {
  948. txpwr->mcs_40_stbc[j] =
  949. min(txpwr->mcs_40_stbc[j], local_constraint_qdbm);
  950. }
  951. /* 40MHz MCS 8-15 MIMO */
  952. for (j = 0; j < BRCMS_NUM_RATES_MCS_2_STREAM; j++)
  953. txpwr->mcs_40_mimo[j] =
  954. min(txpwr->mcs_40_mimo[j], local_constraint_qdbm);
  955. /* 40MHz MCS 32 */
  956. txpwr->mcs32 = min(txpwr->mcs32, local_constraint_qdbm);
  957. }
  958. void
  959. brcms_c_channel_set_chanspec(struct brcms_cm_info *wlc_cm, chanspec_t chanspec,
  960. u8 local_constraint_qdbm)
  961. {
  962. struct brcms_c_info *wlc = wlc_cm->wlc;
  963. struct txpwr_limits txpwr;
  964. brcms_c_channel_reg_limits(wlc_cm, chanspec, &txpwr);
  965. brcms_c_channel_min_txpower_limits_with_local_constraint(wlc_cm, &txpwr,
  966. local_constraint_qdbm);
  967. brcms_b_set_chanspec(wlc->hw, chanspec,
  968. (brcms_c_quiet_chanspec(wlc_cm, chanspec) != 0),
  969. &txpwr);
  970. }
  971. #ifdef POWER_DBG
  972. static void wlc_phy_txpower_limits_dump(struct txpwr_limits *txpwr)
  973. {
  974. int i;
  975. char buf[80];
  976. char fraction[4][4] = { " ", ".25", ".5 ", ".75" };
  977. sprintf(buf, "CCK ");
  978. for (i = 0; i < BRCMS_NUM_RATES_CCK; i++) {
  979. sprintf(buf[strlen(buf)], " %2d%s",
  980. txpwr->cck[i] / BRCMS_TXPWR_DB_FACTOR,
  981. fraction[txpwr->cck[i] % BRCMS_TXPWR_DB_FACTOR]);
  982. }
  983. printk(KERN_DEBUG "%s\n", buf);
  984. sprintf(buf, "20 MHz OFDM SISO ");
  985. for (i = 0; i < BRCMS_NUM_RATES_OFDM; i++) {
  986. sprintf(buf[strlen(buf)], " %2d%s",
  987. txpwr->ofdm[i] / BRCMS_TXPWR_DB_FACTOR,
  988. fraction[txpwr->ofdm[i] % BRCMS_TXPWR_DB_FACTOR]);
  989. }
  990. printk(KERN_DEBUG "%s\n", buf);
  991. sprintf(buf, "20 MHz OFDM CDD ");
  992. for (i = 0; i < BRCMS_NUM_RATES_OFDM; i++) {
  993. sprintf(buf[strlen(buf)], " %2d%s",
  994. txpwr->ofdm_cdd[i] / BRCMS_TXPWR_DB_FACTOR,
  995. fraction[txpwr->ofdm_cdd[i] % BRCMS_TXPWR_DB_FACTOR]);
  996. }
  997. printk(KERN_DEBUG "%s\n", buf);
  998. sprintf(buf, "40 MHz OFDM SISO ");
  999. for (i = 0; i < BRCMS_NUM_RATES_OFDM; i++) {
  1000. sprintf(buf[strlen(buf)], " %2d%s",
  1001. txpwr->ofdm_40_siso[i] / BRCMS_TXPWR_DB_FACTOR,
  1002. fraction[txpwr->ofdm_40_siso[i] %
  1003. BRCMS_TXPWR_DB_FACTOR]);
  1004. }
  1005. printk(KERN_DEBUG "%s\n", buf);
  1006. sprintf(buf, "40 MHz OFDM CDD ");
  1007. for (i = 0; i < BRCMS_NUM_RATES_OFDM; i++) {
  1008. sprintf(buf[strlen(buf)], " %2d%s",
  1009. txpwr->ofdm_40_cdd[i] / BRCMS_TXPWR_DB_FACTOR,
  1010. fraction[txpwr->ofdm_40_cdd[i] %
  1011. BRCMS_TXPWR_DB_FACTOR]);
  1012. }
  1013. printk(KERN_DEBUG "%s\n", buf);
  1014. sprintf(buf, "20 MHz MCS0-7 SISO ");
  1015. for (i = 0; i < BRCMS_NUM_RATES_MCS_1_STREAM; i++) {
  1016. sprintf(buf[strlen(buf)], " %2d%s",
  1017. txpwr->mcs_20_siso[i] / BRCMS_TXPWR_DB_FACTOR,
  1018. fraction[txpwr->mcs_20_siso[i] %
  1019. BRCMS_TXPWR_DB_FACTOR]);
  1020. }
  1021. printk(KERN_DEBUG "%s\n", buf);
  1022. sprintf(buf, "20 MHz MCS0-7 CDD ");
  1023. for (i = 0; i < BRCMS_NUM_RATES_MCS_1_STREAM; i++) {
  1024. sprintf(buf[strlen(buf)], " %2d%s",
  1025. txpwr->mcs_20_cdd[i] / BRCMS_TXPWR_DB_FACTOR,
  1026. fraction[txpwr->mcs_20_cdd[i] %
  1027. BRCMS_TXPWR_DB_FACTOR]);
  1028. }
  1029. printk(KERN_DEBUG "%s\n", buf);
  1030. sprintf(buf, "20 MHz MCS0-7 STBC ");
  1031. for (i = 0; i < BRCMS_NUM_RATES_MCS_1_STREAM; i++) {
  1032. sprintf(buf[strlen(buf)], " %2d%s",
  1033. txpwr->mcs_20_stbc[i] / BRCMS_TXPWR_DB_FACTOR,
  1034. fraction[txpwr->mcs_20_stbc[i] %
  1035. BRCMS_TXPWR_DB_FACTOR]);
  1036. }
  1037. printk(KERN_DEBUG "%s\n", buf);
  1038. sprintf(buf, "20 MHz MCS8-15 SDM ");
  1039. for (i = 0; i < BRCMS_NUM_RATES_MCS_2_STREAM; i++) {
  1040. sprintf(buf[strlen(buf)], " %2d%s",
  1041. txpwr->mcs_20_mimo[i] / BRCMS_TXPWR_DB_FACTOR,
  1042. fraction[txpwr->mcs_20_mimo[i] %
  1043. BRCMS_TXPWR_DB_FACTOR]);
  1044. }
  1045. printk(KERN_DEBUG "%s\n", buf);
  1046. sprintf(buf, "40 MHz MCS0-7 SISO ");
  1047. for (i = 0; i < BRCMS_NUM_RATES_MCS_1_STREAM; i++) {
  1048. sprintf(buf[strlen(buf)], " %2d%s",
  1049. txpwr->mcs_40_siso[i] / BRCMS_TXPWR_DB_FACTOR,
  1050. fraction[txpwr->mcs_40_siso[i] %
  1051. BRCMS_TXPWR_DB_FACTOR]);
  1052. }
  1053. printk(KERN_DEBUG "%s\n", buf);
  1054. sprintf(buf, "40 MHz MCS0-7 CDD ");
  1055. for (i = 0; i < BRCMS_NUM_RATES_MCS_1_STREAM; i++) {
  1056. sprintf(buf[strlen(buf)], " %2d%s",
  1057. txpwr->mcs_40_cdd[i] / BRCMS_TXPWR_DB_FACTOR,
  1058. fraction[txpwr->mcs_40_cdd[i] %
  1059. BRCMS_TXPWR_DB_FACTOR]);
  1060. }
  1061. printk(KERN_DEBUG "%s\n", buf);
  1062. sprintf(buf, "40 MHz MCS0-7 STBC ");
  1063. for (i = 0; i < BRCMS_NUM_RATES_MCS_1_STREAM; i++) {
  1064. sprintf(buf[strlen(buf)], " %2d%s",
  1065. txpwr->mcs_40_stbc[i] / BRCMS_TXPWR_DB_FACTOR,
  1066. fraction[txpwr->mcs_40_stbc[i] %
  1067. BRCMS_TXPWR_DB_FACTOR]);
  1068. }
  1069. printk(KERN_DEBUG "%s\n", buf);
  1070. sprintf(buf, "40 MHz MCS8-15 SDM ");
  1071. for (i = 0; i < BRCMS_NUM_RATES_MCS_2_STREAM; i++) {
  1072. sprintf(buf[strlen(buf)], " %2d%s",
  1073. txpwr->mcs_40_mimo[i] / BRCMS_TXPWR_DB_FACTOR,
  1074. fraction[txpwr->mcs_40_mimo[i] %
  1075. BRCMS_TXPWR_DB_FACTOR]);
  1076. }
  1077. printk(KERN_DEBUG "%s\n", buf);
  1078. printk(KERN_DEBUG "MCS32 %2d%s\n",
  1079. txpwr->mcs32 / BRCMS_TXPWR_DB_FACTOR,
  1080. fraction[txpwr->mcs32 % BRCMS_TXPWR_DB_FACTOR]);
  1081. }
  1082. #endif /* POWER_DBG */
  1083. void
  1084. brcms_c_channel_reg_limits(struct brcms_cm_info *wlc_cm, chanspec_t chanspec,
  1085. struct txpwr_limits *txpwr)
  1086. {
  1087. struct brcms_c_info *wlc = wlc_cm->wlc;
  1088. uint i;
  1089. uint chan;
  1090. int maxpwr;
  1091. int delta;
  1092. const struct country_info *country;
  1093. struct brcms_band *band;
  1094. const struct locale_info *li;
  1095. int conducted_max;
  1096. int conducted_ofdm_max;
  1097. const struct locale_mimo_info *li_mimo;
  1098. int maxpwr20, maxpwr40;
  1099. int maxpwr_idx;
  1100. uint j;
  1101. memset(txpwr, 0, sizeof(struct txpwr_limits));
  1102. if (!brcms_c_valid_chanspec_db(wlc_cm, chanspec)) {
  1103. country = brcms_c_country_lookup(wlc, wlc->autocountry_default);
  1104. if (country == NULL)
  1105. return;
  1106. } else {
  1107. country = wlc_cm->country;
  1108. }
  1109. chan = CHSPEC_CHANNEL(chanspec);
  1110. band = wlc->bandstate[CHSPEC_BANDUNIT(chanspec)];
  1111. li = BAND_5G(band->bandtype) ?
  1112. brcms_c_get_locale_5g(country->locale_5G) :
  1113. brcms_c_get_locale_2g(country->locale_2G);
  1114. li_mimo = BAND_5G(band->bandtype) ?
  1115. brcms_c_get_mimo_5g(country->locale_mimo_5G) :
  1116. brcms_c_get_mimo_2g(country->locale_mimo_2G);
  1117. if (li->flags & BRCMS_EIRP) {
  1118. delta = band->antgain;
  1119. } else {
  1120. delta = 0;
  1121. if (band->antgain > QDB(6))
  1122. delta = band->antgain - QDB(6); /* Excess over 6 dB */
  1123. }
  1124. if (li == &locale_i) {
  1125. conducted_max = QDB(22);
  1126. conducted_ofdm_max = QDB(22);
  1127. }
  1128. /* CCK txpwr limits for 2.4G band */
  1129. if (BAND_2G(band->bandtype)) {
  1130. maxpwr = li->maxpwr[CHANNEL_POWER_IDX_2G_CCK(chan)];
  1131. maxpwr = maxpwr - delta;
  1132. maxpwr = max(maxpwr, 0);
  1133. maxpwr = min(maxpwr, conducted_max);
  1134. for (i = 0; i < BRCMS_NUM_RATES_CCK; i++)
  1135. txpwr->cck[i] = (u8) maxpwr;
  1136. }
  1137. /* OFDM txpwr limits for 2.4G or 5G bands */
  1138. if (BAND_2G(band->bandtype)) {
  1139. maxpwr = li->maxpwr[CHANNEL_POWER_IDX_2G_OFDM(chan)];
  1140. } else {
  1141. maxpwr = li->maxpwr[CHANNEL_POWER_IDX_5G(chan)];
  1142. }
  1143. maxpwr = maxpwr - delta;
  1144. maxpwr = max(maxpwr, 0);
  1145. maxpwr = min(maxpwr, conducted_ofdm_max);
  1146. /* Keep OFDM lmit below CCK limit */
  1147. if (BAND_2G(band->bandtype))
  1148. maxpwr = min_t(int, maxpwr, txpwr->cck[0]);
  1149. for (i = 0; i < BRCMS_NUM_RATES_OFDM; i++)
  1150. txpwr->ofdm[i] = (u8) maxpwr;
  1151. for (i = 0; i < BRCMS_NUM_RATES_OFDM; i++) {
  1152. /* OFDM 40 MHz SISO has the same power as the corresponding MCS0-7 rate unless
  1153. * overriden by the locale specific code. We set this value to 0 as a
  1154. * flag (presumably 0 dBm isn't a possibility) and then copy the MCS0-7 value
  1155. * to the 40 MHz value if it wasn't explicitly set.
  1156. */
  1157. txpwr->ofdm_40_siso[i] = 0;
  1158. txpwr->ofdm_cdd[i] = (u8) maxpwr;
  1159. txpwr->ofdm_40_cdd[i] = 0;
  1160. }
  1161. /* MIMO/HT specific limits */
  1162. if (li_mimo->flags & BRCMS_EIRP) {
  1163. delta = band->antgain;
  1164. } else {
  1165. delta = 0;
  1166. if (band->antgain > QDB(6))
  1167. delta = band->antgain - QDB(6); /* Excess over 6 dB */
  1168. }
  1169. if (BAND_2G(band->bandtype))
  1170. maxpwr_idx = (chan - 1);
  1171. else
  1172. maxpwr_idx = CHANNEL_POWER_IDX_5G(chan);
  1173. maxpwr20 = li_mimo->maxpwr20[maxpwr_idx];
  1174. maxpwr40 = li_mimo->maxpwr40[maxpwr_idx];
  1175. maxpwr20 = maxpwr20 - delta;
  1176. maxpwr20 = max(maxpwr20, 0);
  1177. maxpwr40 = maxpwr40 - delta;
  1178. maxpwr40 = max(maxpwr40, 0);
  1179. /* Fill in the MCS 0-7 (SISO) rates */
  1180. for (i = 0; i < BRCMS_NUM_RATES_MCS_1_STREAM; i++) {
  1181. /* 20 MHz has the same power as the corresponding OFDM rate unless
  1182. * overriden by the locale specific code.
  1183. */
  1184. txpwr->mcs_20_siso[i] = txpwr->ofdm[i];
  1185. txpwr->mcs_40_siso[i] = 0;
  1186. }
  1187. /* Fill in the MCS 0-7 CDD rates */
  1188. for (i = 0; i < BRCMS_NUM_RATES_MCS_1_STREAM; i++) {
  1189. txpwr->mcs_20_cdd[i] = (u8) maxpwr20;
  1190. txpwr->mcs_40_cdd[i] = (u8) maxpwr40;
  1191. }
  1192. /* These locales have SISO expressed in the table and override CDD later */
  1193. if (li_mimo == &locale_bn) {
  1194. if (li_mimo == &locale_bn) {
  1195. maxpwr20 = QDB(16);
  1196. maxpwr40 = 0;
  1197. if (chan >= 3 && chan <= 11) {
  1198. maxpwr40 = QDB(16);
  1199. }
  1200. }
  1201. for (i = 0; i < BRCMS_NUM_RATES_MCS_1_STREAM; i++) {
  1202. txpwr->mcs_20_siso[i] = (u8) maxpwr20;
  1203. txpwr->mcs_40_siso[i] = (u8) maxpwr40;
  1204. }
  1205. }
  1206. /* Fill in the MCS 0-7 STBC rates */
  1207. for (i = 0; i < BRCMS_NUM_RATES_MCS_1_STREAM; i++) {
  1208. txpwr->mcs_20_stbc[i] = 0;
  1209. txpwr->mcs_40_stbc[i] = 0;
  1210. }
  1211. /* Fill in the MCS 8-15 SDM rates */
  1212. for (i = 0; i < BRCMS_NUM_RATES_MCS_2_STREAM; i++) {
  1213. txpwr->mcs_20_mimo[i] = (u8) maxpwr20;
  1214. txpwr->mcs_40_mimo[i] = (u8) maxpwr40;
  1215. }
  1216. /* Fill in MCS32 */
  1217. txpwr->mcs32 = (u8) maxpwr40;
  1218. for (i = 0, j = 0; i < BRCMS_NUM_RATES_OFDM; i++, j++) {
  1219. if (txpwr->ofdm_40_cdd[i] == 0)
  1220. txpwr->ofdm_40_cdd[i] = txpwr->mcs_40_cdd[j];
  1221. if (i == 0) {
  1222. i = i + 1;
  1223. if (txpwr->ofdm_40_cdd[i] == 0)
  1224. txpwr->ofdm_40_cdd[i] = txpwr->mcs_40_cdd[j];
  1225. }
  1226. }
  1227. /* Copy the 40 MHZ MCS 0-7 CDD value to the 40 MHZ MCS 0-7 SISO value if it wasn't
  1228. * provided explicitly.
  1229. */
  1230. for (i = 0; i < BRCMS_NUM_RATES_MCS_1_STREAM; i++) {
  1231. if (txpwr->mcs_40_siso[i] == 0)
  1232. txpwr->mcs_40_siso[i] = txpwr->mcs_40_cdd[i];
  1233. }
  1234. for (i = 0, j = 0; i < BRCMS_NUM_RATES_OFDM; i++, j++) {
  1235. if (txpwr->ofdm_40_siso[i] == 0)
  1236. txpwr->ofdm_40_siso[i] = txpwr->mcs_40_siso[j];
  1237. if (i == 0) {
  1238. i = i + 1;
  1239. if (txpwr->ofdm_40_siso[i] == 0)
  1240. txpwr->ofdm_40_siso[i] = txpwr->mcs_40_siso[j];
  1241. }
  1242. }
  1243. /* Copy the 20 and 40 MHz MCS0-7 CDD values to the corresponding STBC values if they weren't
  1244. * provided explicitly.
  1245. */
  1246. for (i = 0; i < BRCMS_NUM_RATES_MCS_1_STREAM; i++) {
  1247. if (txpwr->mcs_20_stbc[i] == 0)
  1248. txpwr->mcs_20_stbc[i] = txpwr->mcs_20_cdd[i];
  1249. if (txpwr->mcs_40_stbc[i] == 0)
  1250. txpwr->mcs_40_stbc[i] = txpwr->mcs_40_cdd[i];
  1251. }
  1252. #ifdef POWER_DBG
  1253. wlc_phy_txpower_limits_dump(txpwr);
  1254. #endif
  1255. return;
  1256. }
  1257. /* Returns true if currently set country is Japan or variant */
  1258. static bool brcms_c_japan(struct brcms_c_info *wlc)
  1259. {
  1260. return brcms_c_japan_ccode(wlc->cmi->country_abbrev);
  1261. }
  1262. /* JP, J1 - J10 are Japan ccodes */
  1263. static bool brcms_c_japan_ccode(const char *ccode)
  1264. {
  1265. return (ccode[0] == 'J' &&
  1266. (ccode[1] == 'P' || (ccode[1] >= '1' && ccode[1] <= '9')));
  1267. }
  1268. /*
  1269. * Validate the chanspec for this locale, for 40MHZ we need to also check that the sidebands
  1270. * are valid 20MZH channels in this locale and they are also a legal HT combination
  1271. */
  1272. static bool
  1273. brcms_c_valid_chanspec_ext(struct brcms_cm_info *wlc_cm, chanspec_t chspec,
  1274. bool dualband)
  1275. {
  1276. struct brcms_c_info *wlc = wlc_cm->wlc;
  1277. u8 channel = CHSPEC_CHANNEL(chspec);
  1278. /* check the chanspec */
  1279. if (brcmu_chspec_malformed(chspec)) {
  1280. wiphy_err(wlc->wiphy, "wl%d: malformed chanspec 0x%x\n",
  1281. wlc->pub->unit, chspec);
  1282. return false;
  1283. }
  1284. if (CHANNEL_BANDUNIT(wlc_cm->wlc, channel) !=
  1285. CHSPEC_BANDUNIT(chspec))
  1286. return false;
  1287. /* Check a 20Mhz channel */
  1288. if (CHSPEC_IS20(chspec)) {
  1289. if (dualband)
  1290. return VALID_CHANNEL20_DB(wlc_cm->wlc, channel);
  1291. else
  1292. return VALID_CHANNEL20(wlc_cm->wlc, channel);
  1293. }
  1294. #ifdef SUPPORT_40MHZ
  1295. /* We know we are now checking a 40MHZ channel, so we should only be here
  1296. * for NPHYS
  1297. */
  1298. if (BRCMS_ISNPHY(wlc->band) || BRCMS_ISSSLPNPHY(wlc->band)) {
  1299. u8 upper_sideband = 0, idx;
  1300. u8 num_ch20_entries =
  1301. sizeof(chan20_info) / sizeof(struct chan20_info);
  1302. if (!VALID_40CHANSPEC_IN_BAND(wlc, CHSPEC_BANDUNIT(chspec)))
  1303. return false;
  1304. if (dualband) {
  1305. if (!VALID_CHANNEL20_DB(wlc, LOWER_20_SB(channel)) ||
  1306. !VALID_CHANNEL20_DB(wlc, UPPER_20_SB(channel)))
  1307. return false;
  1308. } else {
  1309. if (!VALID_CHANNEL20(wlc, LOWER_20_SB(channel)) ||
  1310. !VALID_CHANNEL20(wlc, UPPER_20_SB(channel)))
  1311. return false;
  1312. }
  1313. /* find the lower sideband info in the sideband array */
  1314. for (idx = 0; idx < num_ch20_entries; idx++) {
  1315. if (chan20_info[idx].sb == LOWER_20_SB(channel))
  1316. upper_sideband = chan20_info[idx].adj_sbs;
  1317. }
  1318. /* check that the lower sideband allows an upper sideband */
  1319. if ((upper_sideband & (CH_UPPER_SB | CH_EWA_VALID)) ==
  1320. (CH_UPPER_SB | CH_EWA_VALID))
  1321. return true;
  1322. return false;
  1323. }
  1324. #endif /* 40 MHZ */
  1325. return false;
  1326. }
  1327. bool brcms_c_valid_chanspec_db(struct brcms_cm_info *wlc_cm, chanspec_t chspec)
  1328. {
  1329. return brcms_c_valid_chanspec_ext(wlc_cm, chspec, true);
  1330. }