Linux Audio

Check our new training course

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