channel.c 35 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254
  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 "main.h"
  22. #include "stf.h"
  23. #include "channel.h"
  24. /* QDB() macro takes a dB value and converts to a quarter dB value */
  25. #define QDB(n) ((n) * BRCMS_TXPWR_DB_FACTOR)
  26. #define LOCALE_CHAN_01_11 (1<<0)
  27. #define LOCALE_CHAN_12_13 (1<<1)
  28. #define LOCALE_CHAN_14 (1<<2)
  29. #define LOCALE_SET_5G_LOW_JP1 (1<<3) /* 34-48, step 2 */
  30. #define LOCALE_SET_5G_LOW_JP2 (1<<4) /* 34-46, step 4 */
  31. #define LOCALE_SET_5G_LOW1 (1<<5) /* 36-48, step 4 */
  32. #define LOCALE_SET_5G_LOW2 (1<<6) /* 52 */
  33. #define LOCALE_SET_5G_LOW3 (1<<7) /* 56-64, step 4 */
  34. #define LOCALE_SET_5G_MID1 (1<<8) /* 100-116, step 4 */
  35. #define LOCALE_SET_5G_MID2 (1<<9) /* 120-124, step 4 */
  36. #define LOCALE_SET_5G_MID3 (1<<10) /* 128 */
  37. #define LOCALE_SET_5G_HIGH1 (1<<11) /* 132-140, step 4 */
  38. #define LOCALE_SET_5G_HIGH2 (1<<12) /* 149-161, step 4 */
  39. #define LOCALE_SET_5G_HIGH3 (1<<13) /* 165 */
  40. #define LOCALE_CHAN_52_140_ALL (1<<14)
  41. #define LOCALE_SET_5G_HIGH4 (1<<15) /* 184-216 */
  42. #define LOCALE_CHAN_36_64 (LOCALE_SET_5G_LOW1 | \
  43. LOCALE_SET_5G_LOW2 | \
  44. LOCALE_SET_5G_LOW3)
  45. #define LOCALE_CHAN_52_64 (LOCALE_SET_5G_LOW2 | LOCALE_SET_5G_LOW3)
  46. #define LOCALE_CHAN_100_124 (LOCALE_SET_5G_MID1 | LOCALE_SET_5G_MID2)
  47. #define LOCALE_CHAN_100_140 (LOCALE_SET_5G_MID1 | LOCALE_SET_5G_MID2 | \
  48. LOCALE_SET_5G_MID3 | LOCALE_SET_5G_HIGH1)
  49. #define LOCALE_CHAN_149_165 (LOCALE_SET_5G_HIGH2 | LOCALE_SET_5G_HIGH3)
  50. #define LOCALE_CHAN_184_216 LOCALE_SET_5G_HIGH4
  51. #define LOCALE_CHAN_01_14 (LOCALE_CHAN_01_11 | \
  52. LOCALE_CHAN_12_13 | \
  53. LOCALE_CHAN_14)
  54. #define LOCALE_RESTRICTED_NONE 0
  55. #define LOCALE_RESTRICTED_SET_2G_SHORT 1
  56. #define LOCALE_2G_IDX_i 0
  57. #define LOCALE_5G_IDX_11 0
  58. #define LOCALE_MIMO_IDX_bn 0
  59. #define LOCALE_MIMO_IDX_11n 0
  60. /* max of BAND_5G_PWR_LVLS and 6 for 2.4 GHz */
  61. #define BRCMS_MAXPWR_TBL_SIZE 6
  62. /* max of BAND_5G_PWR_LVLS and 14 for 2.4 GHz */
  63. #define BRCMS_MAXPWR_MIMO_TBL_SIZE 14
  64. /* power level in group of 2.4GHz band channels:
  65. * maxpwr[0] - CCK channels [1]
  66. * maxpwr[1] - CCK channels [2-10]
  67. * maxpwr[2] - CCK channels [11-14]
  68. * maxpwr[3] - OFDM channels [1]
  69. * maxpwr[4] - OFDM channels [2-10]
  70. * maxpwr[5] - OFDM channels [11-14]
  71. */
  72. /* maxpwr mapping to 5GHz band channels:
  73. * maxpwr[0] - channels [34-48]
  74. * maxpwr[1] - channels [52-60]
  75. * maxpwr[2] - channels [62-64]
  76. * maxpwr[3] - channels [100-140]
  77. * maxpwr[4] - channels [149-165]
  78. */
  79. #define BAND_5G_PWR_LVLS 5 /* 5 power levels for 5G */
  80. #define LC(id) LOCALE_MIMO_IDX_ ## id
  81. #define LC_2G(id) LOCALE_2G_IDX_ ## id
  82. #define LC_5G(id) LOCALE_5G_IDX_ ## id
  83. #define LOCALES(band2, band5, mimo2, mimo5) \
  84. {LC_2G(band2), LC_5G(band5), LC(mimo2), LC(mimo5)}
  85. /* macro to get 2.4 GHz channel group index for tx power */
  86. #define CHANNEL_POWER_IDX_2G_CCK(c) (((c) < 2) ? 0 : (((c) < 11) ? 1 : 2))
  87. #define CHANNEL_POWER_IDX_2G_OFDM(c) (((c) < 2) ? 3 : (((c) < 11) ? 4 : 5))
  88. /* macro to get 5 GHz channel group index for tx power */
  89. #define CHANNEL_POWER_IDX_5G(c) (((c) < 52) ? 0 : \
  90. (((c) < 62) ? 1 : \
  91. (((c) < 100) ? 2 : \
  92. (((c) < 149) ? 3 : 4))))
  93. struct brcms_cm_band {
  94. /* struct locale_info flags */
  95. u8 locale_flags;
  96. /* List of valid channels in the country */
  97. struct brcms_chanvec valid_channels;
  98. /* List of restricted use channels */
  99. const struct brcms_chanvec *restricted_channels;
  100. };
  101. /* locale per-channel tx power limits for MIMO frames
  102. * maxpwr arrays are index by channel for 2.4 GHz limits, and
  103. * by sub-band for 5 GHz limits using CHANNEL_POWER_IDX_5G(channel)
  104. */
  105. struct locale_mimo_info {
  106. /* tx 20 MHz power limits, qdBm units */
  107. s8 maxpwr20[BRCMS_MAXPWR_MIMO_TBL_SIZE];
  108. /* tx 40 MHz power limits, qdBm units */
  109. s8 maxpwr40[BRCMS_MAXPWR_MIMO_TBL_SIZE];
  110. u8 flags;
  111. };
  112. /* Country names and abbreviations with locale defined from ISO 3166 */
  113. struct country_info {
  114. const u8 locale_2G; /* 2.4G band locale */
  115. const u8 locale_5G; /* 5G band locale */
  116. const u8 locale_mimo_2G; /* 2.4G mimo info */
  117. const u8 locale_mimo_5G; /* 5G mimo info */
  118. };
  119. struct brcms_cm_info {
  120. struct brcms_pub *pub;
  121. struct brcms_c_info *wlc;
  122. char srom_ccode[BRCM_CNTRY_BUF_SZ]; /* Country Code in SROM */
  123. uint srom_regrev; /* Regulatory Rev for the SROM ccode */
  124. const struct country_info *country; /* current country def */
  125. uint regrev; /* current Regulatory Revision */
  126. char country_abbrev[BRCM_CNTRY_BUF_SZ]; /* current advertised ccode */
  127. /* per-band state (one per phy/radio) */
  128. struct brcms_cm_band bandstate[MAXBANDS];
  129. /* quiet channels currently for radar sensitivity or 11h support */
  130. /* channels on which we cannot transmit */
  131. struct brcms_chanvec quiet_channels;
  132. };
  133. /* locale channel and power info. */
  134. struct locale_info {
  135. u32 valid_channels;
  136. /* List of channels used only if APs are detected */
  137. u8 restricted_channels;
  138. /* Max tx pwr in qdBm for each sub-band */
  139. s8 maxpwr[BRCMS_MAXPWR_TBL_SIZE];
  140. u8 flags;
  141. };
  142. /* Regulatory Matrix Spreadsheet (CLM) MIMO v3.7.9 */
  143. /*
  144. * Some common channel sets
  145. */
  146. /* No channels */
  147. static const struct brcms_chanvec chanvec_none = {
  148. {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  149. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  150. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  151. 0x00, 0x00, 0x00, 0x00}
  152. };
  153. /*
  154. * Restricted channel sets
  155. */
  156. /* Channels 12, 13 */
  157. static const struct brcms_chanvec restricted_set_2g_short = {
  158. {0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  159. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  160. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  161. 0x00, 0x00, 0x00, 0x00}
  162. };
  163. /* global memory to provide working buffer for expanded locale */
  164. static const struct brcms_chanvec *g_table_restricted_chan[] = {
  165. &chanvec_none, /* restricted_set_none */
  166. &restricted_set_2g_short,
  167. };
  168. static const struct brcms_chanvec locale_2g_01_11 = {
  169. {0xfe, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  170. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  171. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  172. 0x00, 0x00, 0x00, 0x00}
  173. };
  174. static const struct brcms_chanvec locale_2g_12_13 = {
  175. {0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  176. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  177. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  178. 0x00, 0x00, 0x00, 0x00}
  179. };
  180. static const struct brcms_chanvec locale_2g_14 = {
  181. {0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  182. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  183. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  184. 0x00, 0x00, 0x00, 0x00}
  185. };
  186. static const struct brcms_chanvec locale_5g_LOW_JP1 = {
  187. {0x00, 0x00, 0x00, 0x00, 0x54, 0x55, 0x01, 0x00,
  188. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  189. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  190. 0x00, 0x00, 0x00, 0x00}
  191. };
  192. static const struct brcms_chanvec locale_5g_LOW_JP2 = {
  193. {0x00, 0x00, 0x00, 0x00, 0x44, 0x44, 0x00, 0x00,
  194. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  195. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  196. 0x00, 0x00, 0x00, 0x00}
  197. };
  198. static const struct brcms_chanvec locale_5g_LOW1 = {
  199. {0x00, 0x00, 0x00, 0x00, 0x10, 0x11, 0x01, 0x00,
  200. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  201. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  202. 0x00, 0x00, 0x00, 0x00}
  203. };
  204. static const struct brcms_chanvec locale_5g_LOW2 = {
  205. {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00,
  206. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  207. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  208. 0x00, 0x00, 0x00, 0x00}
  209. };
  210. static const struct brcms_chanvec locale_5g_LOW3 = {
  211. {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11,
  212. 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  213. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  214. 0x00, 0x00, 0x00, 0x00}
  215. };
  216. static const struct brcms_chanvec locale_5g_MID1 = {
  217. {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  218. 0x00, 0x00, 0x00, 0x00, 0x10, 0x11, 0x11, 0x00,
  219. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  220. 0x00, 0x00, 0x00, 0x00}
  221. };
  222. static const struct brcms_chanvec locale_5g_MID2 = {
  223. {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  224. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11,
  225. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  226. 0x00, 0x00, 0x00, 0x00}
  227. };
  228. static const struct brcms_chanvec locale_5g_MID3 = {
  229. {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  230. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  231. 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  232. 0x00, 0x00, 0x00, 0x00}
  233. };
  234. static const struct brcms_chanvec locale_5g_HIGH1 = {
  235. {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  236. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  237. 0x10, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  238. 0x00, 0x00, 0x00, 0x00}
  239. };
  240. static const struct brcms_chanvec locale_5g_HIGH2 = {
  241. {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  242. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  243. 0x00, 0x00, 0x20, 0x22, 0x02, 0x00, 0x00, 0x00,
  244. 0x00, 0x00, 0x00, 0x00}
  245. };
  246. static const struct brcms_chanvec locale_5g_HIGH3 = {
  247. {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  248. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  249. 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,
  250. 0x00, 0x00, 0x00, 0x00}
  251. };
  252. static const struct brcms_chanvec locale_5g_52_140_ALL = {
  253. {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x11,
  254. 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
  255. 0x11, 0x11, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,
  256. 0x00, 0x00, 0x00, 0x00}
  257. };
  258. static const struct brcms_chanvec locale_5g_HIGH4 = {
  259. {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  260. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  261. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11,
  262. 0x11, 0x11, 0x11, 0x11}
  263. };
  264. static const struct brcms_chanvec *g_table_locale_base[] = {
  265. &locale_2g_01_11,
  266. &locale_2g_12_13,
  267. &locale_2g_14,
  268. &locale_5g_LOW_JP1,
  269. &locale_5g_LOW_JP2,
  270. &locale_5g_LOW1,
  271. &locale_5g_LOW2,
  272. &locale_5g_LOW3,
  273. &locale_5g_MID1,
  274. &locale_5g_MID2,
  275. &locale_5g_MID3,
  276. &locale_5g_HIGH1,
  277. &locale_5g_HIGH2,
  278. &locale_5g_HIGH3,
  279. &locale_5g_52_140_ALL,
  280. &locale_5g_HIGH4
  281. };
  282. static void brcms_c_locale_add_channels(struct brcms_chanvec *target,
  283. const struct brcms_chanvec *channels)
  284. {
  285. u8 i;
  286. for (i = 0; i < sizeof(struct brcms_chanvec); i++)
  287. target->vec[i] |= channels->vec[i];
  288. }
  289. static void brcms_c_locale_get_channels(const struct locale_info *locale,
  290. struct brcms_chanvec *channels)
  291. {
  292. u8 i;
  293. memset(channels, 0, sizeof(struct brcms_chanvec));
  294. for (i = 0; i < ARRAY_SIZE(g_table_locale_base); i++) {
  295. if (locale->valid_channels & (1 << i))
  296. brcms_c_locale_add_channels(channels,
  297. g_table_locale_base[i]);
  298. }
  299. }
  300. /*
  301. * Locale Definitions - 2.4 GHz
  302. */
  303. static const struct locale_info locale_i = { /* locale i. channel 1 - 13 */
  304. LOCALE_CHAN_01_11 | LOCALE_CHAN_12_13,
  305. LOCALE_RESTRICTED_SET_2G_SHORT,
  306. {QDB(19), QDB(19), QDB(19),
  307. QDB(19), QDB(19), QDB(19)},
  308. BRCMS_EIRP
  309. };
  310. /*
  311. * Locale Definitions - 5 GHz
  312. */
  313. static const struct locale_info locale_11 = {
  314. /* locale 11. channel 36 - 48, 52 - 64, 100 - 140, 149 - 165 */
  315. LOCALE_CHAN_36_64 | LOCALE_CHAN_100_140 | LOCALE_CHAN_149_165,
  316. LOCALE_RESTRICTED_NONE,
  317. {QDB(21), QDB(21), QDB(21), QDB(21), QDB(21)},
  318. BRCMS_EIRP | BRCMS_DFS_EU
  319. };
  320. static const struct locale_info *g_locale_2g_table[] = {
  321. &locale_i
  322. };
  323. static const struct locale_info *g_locale_5g_table[] = {
  324. &locale_11
  325. };
  326. /*
  327. * MIMO Locale Definitions - 2.4 GHz
  328. */
  329. static const struct locale_mimo_info locale_bn = {
  330. {QDB(13), QDB(13), QDB(13), QDB(13), QDB(13),
  331. QDB(13), QDB(13), QDB(13), QDB(13), QDB(13),
  332. QDB(13), QDB(13), QDB(13)},
  333. {0, 0, QDB(13), QDB(13), QDB(13),
  334. QDB(13), QDB(13), QDB(13), QDB(13), QDB(13),
  335. QDB(13), 0, 0},
  336. 0
  337. };
  338. static const struct locale_mimo_info *g_mimo_2g_table[] = {
  339. &locale_bn
  340. };
  341. /*
  342. * MIMO Locale Definitions - 5 GHz
  343. */
  344. static const struct locale_mimo_info locale_11n = {
  345. { /* 12.5 dBm */ 50, 50, 50, QDB(15), QDB(15)},
  346. {QDB(14), QDB(15), QDB(15), QDB(15), QDB(15)},
  347. 0
  348. };
  349. static const struct locale_mimo_info *g_mimo_5g_table[] = {
  350. &locale_11n
  351. };
  352. static const struct {
  353. char abbrev[BRCM_CNTRY_BUF_SZ]; /* country abbreviation */
  354. struct country_info country;
  355. } cntry_locales[] = {
  356. {
  357. "X2", LOCALES(i, 11, bn, 11n)}, /* Worldwide RoW 2 */
  358. };
  359. static const struct locale_info *brcms_c_get_locale_2g(u8 locale_idx)
  360. {
  361. if (locale_idx >= ARRAY_SIZE(g_locale_2g_table))
  362. return NULL; /* error condition */
  363. return g_locale_2g_table[locale_idx];
  364. }
  365. static const struct locale_info *brcms_c_get_locale_5g(u8 locale_idx)
  366. {
  367. if (locale_idx >= ARRAY_SIZE(g_locale_5g_table))
  368. return NULL; /* error condition */
  369. return g_locale_5g_table[locale_idx];
  370. }
  371. static const struct locale_mimo_info *brcms_c_get_mimo_2g(u8 locale_idx)
  372. {
  373. if (locale_idx >= ARRAY_SIZE(g_mimo_2g_table))
  374. return NULL;
  375. return g_mimo_2g_table[locale_idx];
  376. }
  377. static const struct locale_mimo_info *brcms_c_get_mimo_5g(u8 locale_idx)
  378. {
  379. if (locale_idx >= ARRAY_SIZE(g_mimo_5g_table))
  380. return NULL;
  381. return g_mimo_5g_table[locale_idx];
  382. }
  383. /*
  384. * Indicates whether the country provided is valid to pass
  385. * to cfg80211 or not.
  386. *
  387. * returns true if valid; false if not.
  388. */
  389. static bool brcms_c_country_valid(const char *ccode)
  390. {
  391. /*
  392. * only allow ascii alpha uppercase for the first 2
  393. * chars.
  394. */
  395. if (!((0x80 & ccode[0]) == 0 && ccode[0] >= 0x41 && ccode[0] <= 0x5A &&
  396. (0x80 & ccode[1]) == 0 && ccode[1] >= 0x41 && ccode[1] <= 0x5A &&
  397. ccode[2] == '\0'))
  398. return false;
  399. /*
  400. * do not match ISO 3166-1 user assigned country codes
  401. * that may be in the driver table
  402. */
  403. if (!strcmp("AA", ccode) || /* AA */
  404. !strcmp("ZZ", ccode) || /* ZZ */
  405. ccode[0] == 'X' || /* XA - XZ */
  406. (ccode[0] == 'Q' && /* QM - QZ */
  407. (ccode[1] >= 'M' && ccode[1] <= 'Z')))
  408. return false;
  409. if (!strcmp("NA", ccode))
  410. return false;
  411. return true;
  412. }
  413. /* Lookup a country info structure from a null terminated country
  414. * abbreviation and regrev directly with no translation.
  415. */
  416. static const struct country_info *
  417. brcms_c_country_lookup_direct(const char *ccode, uint regrev)
  418. {
  419. uint size, i;
  420. /* Should just return 0 for single locale driver. */
  421. /* Keep it this way in case we add more locales. (for now anyway) */
  422. /*
  423. * all other country def arrays are for regrev == 0, so if
  424. * regrev is non-zero, fail
  425. */
  426. if (regrev > 0)
  427. return NULL;
  428. /* find matched table entry from country code */
  429. size = ARRAY_SIZE(cntry_locales);
  430. for (i = 0; i < size; i++) {
  431. if (strcmp(ccode, cntry_locales[i].abbrev) == 0)
  432. return &cntry_locales[i].country;
  433. }
  434. return NULL;
  435. }
  436. static const struct country_info *
  437. brcms_c_countrycode_map(struct brcms_cm_info *wlc_cm, const char *ccode,
  438. char *mapped_ccode, uint *mapped_regrev)
  439. {
  440. struct brcms_c_info *wlc = wlc_cm->wlc;
  441. const struct country_info *country;
  442. uint srom_regrev = wlc_cm->srom_regrev;
  443. const char *srom_ccode = wlc_cm->srom_ccode;
  444. /* check for currently supported ccode size */
  445. if (strlen(ccode) > (BRCM_CNTRY_BUF_SZ - 1)) {
  446. wiphy_err(wlc->wiphy, "wl%d: %s: ccode \"%s\" too long for "
  447. "match\n", wlc->pub->unit, __func__, ccode);
  448. return NULL;
  449. }
  450. /* default mapping is the given ccode and regrev 0 */
  451. strncpy(mapped_ccode, ccode, BRCM_CNTRY_BUF_SZ);
  452. *mapped_regrev = 0;
  453. /* If the desired country code matches the srom country code,
  454. * then the mapped country is the srom regulatory rev.
  455. * Otherwise look for an aggregate mapping.
  456. */
  457. if (!strcmp(srom_ccode, ccode)) {
  458. *mapped_regrev = srom_regrev;
  459. wiphy_err(wlc->wiphy, "srom_code == ccode %s\n", __func__);
  460. }
  461. /* find the matching built-in country definition */
  462. country = brcms_c_country_lookup_direct(mapped_ccode, *mapped_regrev);
  463. /* if there is not an exact rev match, default to rev zero */
  464. if (country == NULL && *mapped_regrev != 0) {
  465. *mapped_regrev = 0;
  466. country =
  467. brcms_c_country_lookup_direct(mapped_ccode, *mapped_regrev);
  468. }
  469. return country;
  470. }
  471. /* Lookup a country info structure from a null terminated country code
  472. * The lookup is case sensitive.
  473. */
  474. static const struct country_info *
  475. brcms_c_country_lookup(struct brcms_c_info *wlc, const char *ccode)
  476. {
  477. const struct country_info *country;
  478. char mapped_ccode[BRCM_CNTRY_BUF_SZ];
  479. uint mapped_regrev;
  480. /*
  481. * map the country code to a built-in country code, regrev, and
  482. * country_info struct
  483. */
  484. country = brcms_c_countrycode_map(wlc->cmi, ccode, mapped_ccode,
  485. &mapped_regrev);
  486. return country;
  487. }
  488. /*
  489. * reset the quiet channels vector to the union
  490. * of the restricted and radar channel sets
  491. */
  492. static void brcms_c_quiet_channels_reset(struct brcms_cm_info *wlc_cm)
  493. {
  494. struct brcms_c_info *wlc = wlc_cm->wlc;
  495. uint i, j;
  496. struct brcms_band *band;
  497. const struct brcms_chanvec *chanvec;
  498. memset(&wlc_cm->quiet_channels, 0, sizeof(struct brcms_chanvec));
  499. band = wlc->band;
  500. for (i = 0; i < wlc->pub->_nbands;
  501. i++, band = wlc->bandstate[OTHERBANDUNIT(wlc)]) {
  502. /* initialize quiet channels for restricted channels */
  503. chanvec = wlc_cm->bandstate[band->bandunit].restricted_channels;
  504. for (j = 0; j < sizeof(struct brcms_chanvec); j++)
  505. wlc_cm->quiet_channels.vec[j] |= chanvec->vec[j];
  506. }
  507. }
  508. /* Is the channel valid for the current locale and current band? */
  509. static bool brcms_c_valid_channel20(struct brcms_cm_info *wlc_cm, uint val)
  510. {
  511. struct brcms_c_info *wlc = wlc_cm->wlc;
  512. return ((val < MAXCHANNEL) &&
  513. isset(wlc_cm->bandstate[wlc->band->bandunit].valid_channels.vec,
  514. val));
  515. }
  516. /* Is the channel valid for the current locale and specified band? */
  517. static bool brcms_c_valid_channel20_in_band(struct brcms_cm_info *wlc_cm,
  518. uint bandunit, uint val)
  519. {
  520. return ((val < MAXCHANNEL)
  521. && isset(wlc_cm->bandstate[bandunit].valid_channels.vec, val));
  522. }
  523. /* Is the channel valid for the current locale? (but don't consider channels not
  524. * available due to bandlocking)
  525. */
  526. static bool brcms_c_valid_channel20_db(struct brcms_cm_info *wlc_cm, uint val)
  527. {
  528. struct brcms_c_info *wlc = wlc_cm->wlc;
  529. return brcms_c_valid_channel20(wlc->cmi, val) ||
  530. (!wlc->bandlocked
  531. && brcms_c_valid_channel20_in_band(wlc->cmi,
  532. OTHERBANDUNIT(wlc), val));
  533. }
  534. /* JP, J1 - J10 are Japan ccodes */
  535. static bool brcms_c_japan_ccode(const char *ccode)
  536. {
  537. return (ccode[0] == 'J' &&
  538. (ccode[1] == 'P' || (ccode[1] >= '1' && ccode[1] <= '9')));
  539. }
  540. /* Returns true if currently set country is Japan or variant */
  541. static bool brcms_c_japan(struct brcms_c_info *wlc)
  542. {
  543. return brcms_c_japan_ccode(wlc->cmi->country_abbrev);
  544. }
  545. static void
  546. brcms_c_channel_min_txpower_limits_with_local_constraint(
  547. struct brcms_cm_info *wlc_cm, struct txpwr_limits *txpwr,
  548. u8 local_constraint_qdbm)
  549. {
  550. int j;
  551. /* CCK Rates */
  552. for (j = 0; j < WL_TX_POWER_CCK_NUM; j++)
  553. txpwr->cck[j] = min(txpwr->cck[j], local_constraint_qdbm);
  554. /* 20 MHz Legacy OFDM SISO */
  555. for (j = 0; j < WL_TX_POWER_OFDM_NUM; j++)
  556. txpwr->ofdm[j] = min(txpwr->ofdm[j], local_constraint_qdbm);
  557. /* 20 MHz Legacy OFDM CDD */
  558. for (j = 0; j < BRCMS_NUM_RATES_OFDM; j++)
  559. txpwr->ofdm_cdd[j] =
  560. min(txpwr->ofdm_cdd[j], local_constraint_qdbm);
  561. /* 40 MHz Legacy OFDM SISO */
  562. for (j = 0; j < BRCMS_NUM_RATES_OFDM; j++)
  563. txpwr->ofdm_40_siso[j] =
  564. min(txpwr->ofdm_40_siso[j], local_constraint_qdbm);
  565. /* 40 MHz Legacy OFDM CDD */
  566. for (j = 0; j < BRCMS_NUM_RATES_OFDM; j++)
  567. txpwr->ofdm_40_cdd[j] =
  568. min(txpwr->ofdm_40_cdd[j], local_constraint_qdbm);
  569. /* 20MHz MCS 0-7 SISO */
  570. for (j = 0; j < BRCMS_NUM_RATES_MCS_1_STREAM; j++)
  571. txpwr->mcs_20_siso[j] =
  572. min(txpwr->mcs_20_siso[j], local_constraint_qdbm);
  573. /* 20MHz MCS 0-7 CDD */
  574. for (j = 0; j < BRCMS_NUM_RATES_MCS_1_STREAM; j++)
  575. txpwr->mcs_20_cdd[j] =
  576. min(txpwr->mcs_20_cdd[j], local_constraint_qdbm);
  577. /* 20MHz MCS 0-7 STBC */
  578. for (j = 0; j < BRCMS_NUM_RATES_MCS_1_STREAM; j++)
  579. txpwr->mcs_20_stbc[j] =
  580. min(txpwr->mcs_20_stbc[j], local_constraint_qdbm);
  581. /* 20MHz MCS 8-15 MIMO */
  582. for (j = 0; j < BRCMS_NUM_RATES_MCS_2_STREAM; j++)
  583. txpwr->mcs_20_mimo[j] =
  584. min(txpwr->mcs_20_mimo[j], local_constraint_qdbm);
  585. /* 40MHz MCS 0-7 SISO */
  586. for (j = 0; j < BRCMS_NUM_RATES_MCS_1_STREAM; j++)
  587. txpwr->mcs_40_siso[j] =
  588. min(txpwr->mcs_40_siso[j], local_constraint_qdbm);
  589. /* 40MHz MCS 0-7 CDD */
  590. for (j = 0; j < BRCMS_NUM_RATES_MCS_1_STREAM; j++)
  591. txpwr->mcs_40_cdd[j] =
  592. min(txpwr->mcs_40_cdd[j], local_constraint_qdbm);
  593. /* 40MHz MCS 0-7 STBC */
  594. for (j = 0; j < BRCMS_NUM_RATES_MCS_1_STREAM; j++)
  595. txpwr->mcs_40_stbc[j] =
  596. min(txpwr->mcs_40_stbc[j], local_constraint_qdbm);
  597. /* 40MHz MCS 8-15 MIMO */
  598. for (j = 0; j < BRCMS_NUM_RATES_MCS_2_STREAM; j++)
  599. txpwr->mcs_40_mimo[j] =
  600. min(txpwr->mcs_40_mimo[j], local_constraint_qdbm);
  601. /* 40MHz MCS 32 */
  602. txpwr->mcs32 = min(txpwr->mcs32, local_constraint_qdbm);
  603. }
  604. /* Update the radio state (enable/disable) and tx power targets
  605. * based on a new set of channel/regulatory information
  606. */
  607. static void brcms_c_channels_commit(struct brcms_cm_info *wlc_cm)
  608. {
  609. struct brcms_c_info *wlc = wlc_cm->wlc;
  610. uint chan;
  611. /* search for the existence of any valid channel */
  612. for (chan = 0; chan < MAXCHANNEL; chan++) {
  613. if (brcms_c_valid_channel20_db(wlc->cmi, chan))
  614. break;
  615. }
  616. if (chan == MAXCHANNEL)
  617. chan = INVCHANNEL;
  618. /*
  619. * based on the channel search above, set or
  620. * clear WL_RADIO_COUNTRY_DISABLE.
  621. */
  622. if (chan == INVCHANNEL) {
  623. /*
  624. * country/locale with no valid channels, set
  625. * the radio disable bit
  626. */
  627. mboolset(wlc->pub->radio_disabled, WL_RADIO_COUNTRY_DISABLE);
  628. wiphy_err(wlc->wiphy, "wl%d: %s: no valid channel for \"%s\" "
  629. "nbands %d bandlocked %d\n", wlc->pub->unit,
  630. __func__, wlc_cm->country_abbrev, wlc->pub->_nbands,
  631. wlc->bandlocked);
  632. } else if (mboolisset(wlc->pub->radio_disabled,
  633. WL_RADIO_COUNTRY_DISABLE)) {
  634. /*
  635. * country/locale with valid channel, clear
  636. * the radio disable bit
  637. */
  638. mboolclr(wlc->pub->radio_disabled, WL_RADIO_COUNTRY_DISABLE);
  639. }
  640. /*
  641. * Now that the country abbreviation is set, if the radio supports 2G,
  642. * then set channel 14 restrictions based on the new locale.
  643. */
  644. if (wlc->pub->_nbands > 1 || wlc->band->bandtype == BRCM_BAND_2G)
  645. wlc_phy_chanspec_ch14_widefilter_set(wlc->band->pi,
  646. brcms_c_japan(wlc) ? true :
  647. false);
  648. }
  649. static int
  650. brcms_c_channels_init(struct brcms_cm_info *wlc_cm,
  651. const struct country_info *country)
  652. {
  653. struct brcms_c_info *wlc = wlc_cm->wlc;
  654. uint i, j;
  655. struct brcms_band *band;
  656. const struct locale_info *li;
  657. struct brcms_chanvec sup_chan;
  658. const struct locale_mimo_info *li_mimo;
  659. band = wlc->band;
  660. for (i = 0; i < wlc->pub->_nbands;
  661. i++, band = wlc->bandstate[OTHERBANDUNIT(wlc)]) {
  662. li = (band->bandtype == BRCM_BAND_5G) ?
  663. brcms_c_get_locale_5g(country->locale_5G) :
  664. brcms_c_get_locale_2g(country->locale_2G);
  665. wlc_cm->bandstate[band->bandunit].locale_flags = li->flags;
  666. li_mimo = (band->bandtype == BRCM_BAND_5G) ?
  667. brcms_c_get_mimo_5g(country->locale_mimo_5G) :
  668. brcms_c_get_mimo_2g(country->locale_mimo_2G);
  669. /* merge the mimo non-mimo locale flags */
  670. wlc_cm->bandstate[band->bandunit].locale_flags |=
  671. li_mimo->flags;
  672. wlc_cm->bandstate[band->bandunit].restricted_channels =
  673. g_table_restricted_chan[li->restricted_channels];
  674. /*
  675. * set the channel availability, masking out the channels
  676. * that may not be supported on this phy.
  677. */
  678. wlc_phy_chanspec_band_validch(band->pi, band->bandtype,
  679. &sup_chan);
  680. brcms_c_locale_get_channels(li,
  681. &wlc_cm->bandstate[band->bandunit].
  682. valid_channels);
  683. for (j = 0; j < sizeof(struct brcms_chanvec); j++)
  684. wlc_cm->bandstate[band->bandunit].valid_channels.
  685. vec[j] &= sup_chan.vec[j];
  686. }
  687. brcms_c_quiet_channels_reset(wlc_cm);
  688. brcms_c_channels_commit(wlc_cm);
  689. return 0;
  690. }
  691. /*
  692. * set the driver's current country and regulatory information
  693. * using a country code as the source. Look up built in country
  694. * information found with the country code.
  695. */
  696. static void
  697. brcms_c_set_country_common(struct brcms_cm_info *wlc_cm,
  698. const char *country_abbrev,
  699. const char *ccode, uint regrev,
  700. const struct country_info *country)
  701. {
  702. const struct locale_info *locale;
  703. struct brcms_c_info *wlc = wlc_cm->wlc;
  704. /* save current country state */
  705. wlc_cm->country = country;
  706. strncpy(wlc_cm->country_abbrev, country_abbrev, BRCM_CNTRY_BUF_SZ - 1);
  707. wlc_cm->regrev = regrev;
  708. if ((wlc->pub->_n_enab & SUPPORT_11N) !=
  709. wlc->protection->nmode_user)
  710. brcms_c_set_nmode(wlc);
  711. brcms_c_stf_ss_update(wlc, wlc->bandstate[BAND_2G_INDEX]);
  712. brcms_c_stf_ss_update(wlc, wlc->bandstate[BAND_5G_INDEX]);
  713. /* set or restore gmode as required by regulatory */
  714. locale = brcms_c_get_locale_2g(country->locale_2G);
  715. if (locale && (locale->flags & BRCMS_NO_OFDM))
  716. brcms_c_set_gmode(wlc, GMODE_LEGACY_B, false);
  717. else
  718. brcms_c_set_gmode(wlc, wlc->protection->gmode_user, false);
  719. brcms_c_channels_init(wlc_cm, country);
  720. return;
  721. }
  722. static int
  723. brcms_c_set_countrycode_rev(struct brcms_cm_info *wlc_cm,
  724. const char *country_abbrev,
  725. const char *ccode, int regrev)
  726. {
  727. const struct country_info *country;
  728. char mapped_ccode[BRCM_CNTRY_BUF_SZ];
  729. uint mapped_regrev;
  730. /* if regrev is -1, lookup the mapped country code,
  731. * otherwise use the ccode and regrev directly
  732. */
  733. if (regrev == -1) {
  734. /*
  735. * map the country code to a built-in country
  736. * code, regrev, and country_info
  737. */
  738. country =
  739. brcms_c_countrycode_map(wlc_cm, ccode, mapped_ccode,
  740. &mapped_regrev);
  741. } else {
  742. /* find the matching built-in country definition */
  743. country = brcms_c_country_lookup_direct(ccode, regrev);
  744. strncpy(mapped_ccode, ccode, BRCM_CNTRY_BUF_SZ);
  745. mapped_regrev = regrev;
  746. }
  747. if (country == NULL)
  748. return -EINVAL;
  749. /* set the driver state for the country */
  750. brcms_c_set_country_common(wlc_cm, country_abbrev, mapped_ccode,
  751. mapped_regrev, country);
  752. return 0;
  753. }
  754. /*
  755. * set the driver's current country and regulatory information using
  756. * a country code as the source. Lookup built in country information
  757. * found with the country code.
  758. */
  759. static int
  760. brcms_c_set_countrycode(struct brcms_cm_info *wlc_cm, const char *ccode)
  761. {
  762. return brcms_c_set_countrycode_rev(wlc_cm, ccode, ccode, -1);
  763. }
  764. struct brcms_cm_info *brcms_c_channel_mgr_attach(struct brcms_c_info *wlc)
  765. {
  766. struct brcms_cm_info *wlc_cm;
  767. struct brcms_pub *pub = wlc->pub;
  768. struct ssb_sprom *sprom = &wlc->hw->d11core->bus->sprom;
  769. BCMMSG(wlc->wiphy, "wl%d\n", wlc->pub->unit);
  770. wlc_cm = kzalloc(sizeof(struct brcms_cm_info), GFP_ATOMIC);
  771. if (wlc_cm == NULL)
  772. return NULL;
  773. wlc_cm->pub = pub;
  774. wlc_cm->wlc = wlc;
  775. wlc->cmi = wlc_cm;
  776. /* store the country code for passing up as a regulatory hint */
  777. if (sprom->alpha2 && brcms_c_country_valid(sprom->alpha2))
  778. strncpy(wlc->pub->srom_ccode, sprom->alpha2, sizeof(sprom->alpha2));
  779. /* save default country for exiting 11d regulatory mode */
  780. strncpy(wlc->country_default, "X2", BRCM_CNTRY_BUF_SZ - 1);
  781. /* initialize autocountry_default to driver default */
  782. strncpy(wlc->autocountry_default, wlc->country_default,
  783. BRCM_CNTRY_BUF_SZ - 1);
  784. brcms_c_set_countrycode(wlc_cm, wlc->country_default);
  785. return wlc_cm;
  786. }
  787. void brcms_c_channel_mgr_detach(struct brcms_cm_info *wlc_cm)
  788. {
  789. kfree(wlc_cm);
  790. }
  791. u8
  792. brcms_c_channel_locale_flags_in_band(struct brcms_cm_info *wlc_cm,
  793. uint bandunit)
  794. {
  795. return wlc_cm->bandstate[bandunit].locale_flags;
  796. }
  797. static bool
  798. brcms_c_quiet_chanspec(struct brcms_cm_info *wlc_cm, u16 chspec)
  799. {
  800. return (wlc_cm->wlc->pub->_n_enab & SUPPORT_11N) &&
  801. CHSPEC_IS40(chspec) ?
  802. (isset(wlc_cm->quiet_channels.vec,
  803. lower_20_sb(CHSPEC_CHANNEL(chspec))) ||
  804. isset(wlc_cm->quiet_channels.vec,
  805. upper_20_sb(CHSPEC_CHANNEL(chspec)))) :
  806. isset(wlc_cm->quiet_channels.vec, CHSPEC_CHANNEL(chspec));
  807. }
  808. void
  809. brcms_c_channel_set_chanspec(struct brcms_cm_info *wlc_cm, u16 chanspec,
  810. u8 local_constraint_qdbm)
  811. {
  812. struct brcms_c_info *wlc = wlc_cm->wlc;
  813. struct txpwr_limits txpwr;
  814. brcms_c_channel_reg_limits(wlc_cm, chanspec, &txpwr);
  815. brcms_c_channel_min_txpower_limits_with_local_constraint(
  816. wlc_cm, &txpwr, local_constraint_qdbm
  817. );
  818. brcms_b_set_chanspec(wlc->hw, chanspec,
  819. (brcms_c_quiet_chanspec(wlc_cm, chanspec) != 0),
  820. &txpwr);
  821. }
  822. void
  823. brcms_c_channel_reg_limits(struct brcms_cm_info *wlc_cm, u16 chanspec,
  824. struct txpwr_limits *txpwr)
  825. {
  826. struct brcms_c_info *wlc = wlc_cm->wlc;
  827. uint i;
  828. uint chan;
  829. int maxpwr;
  830. int delta;
  831. const struct country_info *country;
  832. struct brcms_band *band;
  833. const struct locale_info *li;
  834. int conducted_max = BRCMS_TXPWR_MAX;
  835. int conducted_ofdm_max = BRCMS_TXPWR_MAX;
  836. const struct locale_mimo_info *li_mimo;
  837. int maxpwr20, maxpwr40;
  838. int maxpwr_idx;
  839. uint j;
  840. memset(txpwr, 0, sizeof(struct txpwr_limits));
  841. if (!brcms_c_valid_chanspec_db(wlc_cm, chanspec)) {
  842. country = brcms_c_country_lookup(wlc, wlc->autocountry_default);
  843. if (country == NULL)
  844. return;
  845. } else {
  846. country = wlc_cm->country;
  847. }
  848. chan = CHSPEC_CHANNEL(chanspec);
  849. band = wlc->bandstate[chspec_bandunit(chanspec)];
  850. li = (band->bandtype == BRCM_BAND_5G) ?
  851. brcms_c_get_locale_5g(country->locale_5G) :
  852. brcms_c_get_locale_2g(country->locale_2G);
  853. li_mimo = (band->bandtype == BRCM_BAND_5G) ?
  854. brcms_c_get_mimo_5g(country->locale_mimo_5G) :
  855. brcms_c_get_mimo_2g(country->locale_mimo_2G);
  856. if (li->flags & BRCMS_EIRP) {
  857. delta = band->antgain;
  858. } else {
  859. delta = 0;
  860. if (band->antgain > QDB(6))
  861. delta = band->antgain - QDB(6); /* Excess over 6 dB */
  862. }
  863. if (li == &locale_i) {
  864. conducted_max = QDB(22);
  865. conducted_ofdm_max = QDB(22);
  866. }
  867. /* CCK txpwr limits for 2.4G band */
  868. if (band->bandtype == BRCM_BAND_2G) {
  869. maxpwr = li->maxpwr[CHANNEL_POWER_IDX_2G_CCK(chan)];
  870. maxpwr = maxpwr - delta;
  871. maxpwr = max(maxpwr, 0);
  872. maxpwr = min(maxpwr, conducted_max);
  873. for (i = 0; i < BRCMS_NUM_RATES_CCK; i++)
  874. txpwr->cck[i] = (u8) maxpwr;
  875. }
  876. /* OFDM txpwr limits for 2.4G or 5G bands */
  877. if (band->bandtype == BRCM_BAND_2G)
  878. maxpwr = li->maxpwr[CHANNEL_POWER_IDX_2G_OFDM(chan)];
  879. else
  880. maxpwr = li->maxpwr[CHANNEL_POWER_IDX_5G(chan)];
  881. maxpwr = maxpwr - delta;
  882. maxpwr = max(maxpwr, 0);
  883. maxpwr = min(maxpwr, conducted_ofdm_max);
  884. /* Keep OFDM lmit below CCK limit */
  885. if (band->bandtype == BRCM_BAND_2G)
  886. maxpwr = min_t(int, maxpwr, txpwr->cck[0]);
  887. for (i = 0; i < BRCMS_NUM_RATES_OFDM; i++)
  888. txpwr->ofdm[i] = (u8) maxpwr;
  889. for (i = 0; i < BRCMS_NUM_RATES_OFDM; i++) {
  890. /*
  891. * OFDM 40 MHz SISO has the same power as the corresponding
  892. * MCS0-7 rate unless overriden by the locale specific code.
  893. * We set this value to 0 as a flag (presumably 0 dBm isn't
  894. * a possibility) and then copy the MCS0-7 value to the 40 MHz
  895. * value if it wasn't explicitly set.
  896. */
  897. txpwr->ofdm_40_siso[i] = 0;
  898. txpwr->ofdm_cdd[i] = (u8) maxpwr;
  899. txpwr->ofdm_40_cdd[i] = 0;
  900. }
  901. /* MIMO/HT specific limits */
  902. if (li_mimo->flags & BRCMS_EIRP) {
  903. delta = band->antgain;
  904. } else {
  905. delta = 0;
  906. if (band->antgain > QDB(6))
  907. delta = band->antgain - QDB(6); /* Excess over 6 dB */
  908. }
  909. if (band->bandtype == BRCM_BAND_2G)
  910. maxpwr_idx = (chan - 1);
  911. else
  912. maxpwr_idx = CHANNEL_POWER_IDX_5G(chan);
  913. maxpwr20 = li_mimo->maxpwr20[maxpwr_idx];
  914. maxpwr40 = li_mimo->maxpwr40[maxpwr_idx];
  915. maxpwr20 = maxpwr20 - delta;
  916. maxpwr20 = max(maxpwr20, 0);
  917. maxpwr40 = maxpwr40 - delta;
  918. maxpwr40 = max(maxpwr40, 0);
  919. /* Fill in the MCS 0-7 (SISO) rates */
  920. for (i = 0; i < BRCMS_NUM_RATES_MCS_1_STREAM; i++) {
  921. /*
  922. * 20 MHz has the same power as the corresponding OFDM rate
  923. * unless overriden by the locale specific code.
  924. */
  925. txpwr->mcs_20_siso[i] = txpwr->ofdm[i];
  926. txpwr->mcs_40_siso[i] = 0;
  927. }
  928. /* Fill in the MCS 0-7 CDD rates */
  929. for (i = 0; i < BRCMS_NUM_RATES_MCS_1_STREAM; i++) {
  930. txpwr->mcs_20_cdd[i] = (u8) maxpwr20;
  931. txpwr->mcs_40_cdd[i] = (u8) maxpwr40;
  932. }
  933. /*
  934. * These locales have SISO expressed in the
  935. * table and override CDD later
  936. */
  937. if (li_mimo == &locale_bn) {
  938. if (li_mimo == &locale_bn) {
  939. maxpwr20 = QDB(16);
  940. maxpwr40 = 0;
  941. if (chan >= 3 && chan <= 11)
  942. maxpwr40 = QDB(16);
  943. }
  944. for (i = 0; i < BRCMS_NUM_RATES_MCS_1_STREAM; i++) {
  945. txpwr->mcs_20_siso[i] = (u8) maxpwr20;
  946. txpwr->mcs_40_siso[i] = (u8) maxpwr40;
  947. }
  948. }
  949. /* Fill in the MCS 0-7 STBC rates */
  950. for (i = 0; i < BRCMS_NUM_RATES_MCS_1_STREAM; i++) {
  951. txpwr->mcs_20_stbc[i] = 0;
  952. txpwr->mcs_40_stbc[i] = 0;
  953. }
  954. /* Fill in the MCS 8-15 SDM rates */
  955. for (i = 0; i < BRCMS_NUM_RATES_MCS_2_STREAM; i++) {
  956. txpwr->mcs_20_mimo[i] = (u8) maxpwr20;
  957. txpwr->mcs_40_mimo[i] = (u8) maxpwr40;
  958. }
  959. /* Fill in MCS32 */
  960. txpwr->mcs32 = (u8) maxpwr40;
  961. for (i = 0, j = 0; i < BRCMS_NUM_RATES_OFDM; i++, j++) {
  962. if (txpwr->ofdm_40_cdd[i] == 0)
  963. txpwr->ofdm_40_cdd[i] = txpwr->mcs_40_cdd[j];
  964. if (i == 0) {
  965. i = i + 1;
  966. if (txpwr->ofdm_40_cdd[i] == 0)
  967. txpwr->ofdm_40_cdd[i] = txpwr->mcs_40_cdd[j];
  968. }
  969. }
  970. /*
  971. * Copy the 40 MHZ MCS 0-7 CDD value to the 40 MHZ MCS 0-7 SISO
  972. * value if it wasn't provided explicitly.
  973. */
  974. for (i = 0; i < BRCMS_NUM_RATES_MCS_1_STREAM; i++) {
  975. if (txpwr->mcs_40_siso[i] == 0)
  976. txpwr->mcs_40_siso[i] = txpwr->mcs_40_cdd[i];
  977. }
  978. for (i = 0, j = 0; i < BRCMS_NUM_RATES_OFDM; i++, j++) {
  979. if (txpwr->ofdm_40_siso[i] == 0)
  980. txpwr->ofdm_40_siso[i] = txpwr->mcs_40_siso[j];
  981. if (i == 0) {
  982. i = i + 1;
  983. if (txpwr->ofdm_40_siso[i] == 0)
  984. txpwr->ofdm_40_siso[i] = txpwr->mcs_40_siso[j];
  985. }
  986. }
  987. /*
  988. * Copy the 20 and 40 MHz MCS0-7 CDD values to the corresponding
  989. * STBC values if they weren't provided explicitly.
  990. */
  991. for (i = 0; i < BRCMS_NUM_RATES_MCS_1_STREAM; i++) {
  992. if (txpwr->mcs_20_stbc[i] == 0)
  993. txpwr->mcs_20_stbc[i] = txpwr->mcs_20_cdd[i];
  994. if (txpwr->mcs_40_stbc[i] == 0)
  995. txpwr->mcs_40_stbc[i] = txpwr->mcs_40_cdd[i];
  996. }
  997. return;
  998. }
  999. /*
  1000. * Verify the chanspec is using a legal set of parameters, i.e. that the
  1001. * chanspec specified a band, bw, ctl_sb and channel and that the
  1002. * combination could be legal given any set of circumstances.
  1003. * RETURNS: true is the chanspec is malformed, false if it looks good.
  1004. */
  1005. static bool brcms_c_chspec_malformed(u16 chanspec)
  1006. {
  1007. /* must be 2G or 5G band */
  1008. if (!CHSPEC_IS5G(chanspec) && !CHSPEC_IS2G(chanspec))
  1009. return true;
  1010. /* must be 20 or 40 bandwidth */
  1011. if (!CHSPEC_IS40(chanspec) && !CHSPEC_IS20(chanspec))
  1012. return true;
  1013. /* 20MHZ b/w must have no ctl sb, 40 must have a ctl sb */
  1014. if (CHSPEC_IS20(chanspec)) {
  1015. if (!CHSPEC_SB_NONE(chanspec))
  1016. return true;
  1017. } else if (!CHSPEC_SB_UPPER(chanspec) && !CHSPEC_SB_LOWER(chanspec)) {
  1018. return true;
  1019. }
  1020. return false;
  1021. }
  1022. /*
  1023. * Validate the chanspec for this locale, for 40MHZ we need to also
  1024. * check that the sidebands are valid 20MZH channels in this locale
  1025. * and they are also a legal HT combination
  1026. */
  1027. static bool
  1028. brcms_c_valid_chanspec_ext(struct brcms_cm_info *wlc_cm, u16 chspec,
  1029. bool dualband)
  1030. {
  1031. struct brcms_c_info *wlc = wlc_cm->wlc;
  1032. u8 channel = CHSPEC_CHANNEL(chspec);
  1033. /* check the chanspec */
  1034. if (brcms_c_chspec_malformed(chspec)) {
  1035. wiphy_err(wlc->wiphy, "wl%d: malformed chanspec 0x%x\n",
  1036. wlc->pub->unit, chspec);
  1037. return false;
  1038. }
  1039. if (CHANNEL_BANDUNIT(wlc_cm->wlc, channel) !=
  1040. chspec_bandunit(chspec))
  1041. return false;
  1042. /* Check a 20Mhz channel */
  1043. if (CHSPEC_IS20(chspec)) {
  1044. if (dualband)
  1045. return brcms_c_valid_channel20_db(wlc_cm->wlc->cmi,
  1046. channel);
  1047. else
  1048. return brcms_c_valid_channel20(wlc_cm->wlc->cmi,
  1049. channel);
  1050. }
  1051. return false;
  1052. }
  1053. bool brcms_c_valid_chanspec_db(struct brcms_cm_info *wlc_cm, u16 chspec)
  1054. {
  1055. return brcms_c_valid_chanspec_ext(wlc_cm, chspec, true);
  1056. }