2012-03-07 19:40:05

by Seth Forshee

[permalink] [raw]
Subject: Problems with regulatory domain support and BCM43224

I set up an AP recently in the 5 GHz band and noticed that a MacBook Air
with BCM43224 wireless can't see it. iw shows that the 5260-5700 MHz
frequency range is disabled. I compared this to an Intel Centrino 6205
card which shows passive scanning is allowed in this range. Both show
that they're using the world regulatory domain, and I can get the
BCM43224 to see my AP when I force the domain to US.

I've been going through the regulatory code trying to understand what's
happening, and while I haven't fully grokked it yet it seems to me the
difference is that iwlwifi is setting WIPHY_FLAG_CUSTOM_REGULATORY and
brcmsmac is not. iwlwifi isn't supplying a regulatory hint, and mac80211
doesn't end up applying any regulatory settings due to the flag.
brcmsmac supplies a hint using the country code it reads from its srom,
"X0" (which Google tells me is an interim code that Apple uses while the
actual country code is unknown). Since this code is bogus the world
domain gets applied.

mac80211 doesn't appear to update the regulatory domain from the beacons
unless connected to an AP that happens to be providing the country IE,
so we're left in the unfortunate situation of being unable to scan
certain frequencies unless the user connects to such an AP or sets the
domain manually.

Am I understanding the situation correctly? If so, what can be done
about it? Should brcmsmac set WIPHY_FLAG_CUSTOM_REGULATORY when it reads
XO from its srom?

Thanks,
Seth



2012-03-08 21:32:03

by Arend van Spriel

[permalink] [raw]
Subject: Re: Problems with regulatory domain support and BCM43224

On 03/08/2012 10:06 PM, Luis R. Rodriguez wrote:
> On Thu, Mar 8, 2012 at 1:01 PM, Arend van Spriel<[email protected]> wrote:
>> On 03/08/2012 09:07 PM, Seth Forshee wrote:
>>>
>>> On Thu, Mar 08, 2012 at 11:51:03AM -0800, Luis R. Rodriguez wrote:
>>>>
>>>> On Thu, Mar 8, 2012 at 11:45 AM, Quan, David<[email protected]>
>>>> wrote:
>>>>>
>>>>> I think there is to it more than SW.
>>>>> Where ever you get this card, is the card tested and regulatory approved
>>>>> for those countries, DFS or not?
>>>>
>>>>
>>>> Seth, what driver are you using? I know you are using a BCM43224 card.
>>>
>>>
>>> brcmsmac
>>>
>>>>> It is possible that this card is only regulatory tested for non DFS
>>>>> channels, but now you enable them for passive.
>>>>
>>>>
>>>> That's a good point.
>>>>
>>>>> This means that yes, you are save and not violate DFS rules because you
>>>>> are in passive mode. However, you are in complete violation if the STA finds
>>>>> an AP on that DFS channel and then connects and transmits as this STA is not
>>>>> allow to transmit on that channel since it is not approved.
>>>>
>>>>
>>>> If the driver being used is a supported vendor driver then I'll punt
>>>> this to the vendor (Broadcom). If this is the reversed engineered
>>>> driver (b43) that Broadcom to this day seems to blindly ignore even
>>>> for regulatory, then I'm happy to recommend based on your input to
>>>> leave the regulatory domain as-is given that we cannot guarantee what
>>>> the vendor meant as they have not done any work on releasing either
>>>> documentation or code to help with their regulatory situation.
>>>
>>>
>>> It would be nice if Broadcom could weigh in. Cc-ing Arend.
>>
>>
>> Hi, Seth
>>
>> Noticed your email yesterday, but did not get to chime into the
>> conversation. brcmsmac does indeed provide a regulatory hint, which is
>> either from SPROM or hard-coded to "US". Since "X0" is not a known
>> regulatory domain for crda it does not make sense to pass it as a regulatory
>> hint. However, the "full" story is told on linuxwireless.org (see [1]).
>
> The Linux kernel allows you to define custom regulatory domains, the
> ath module uses these, it defines 13 of them. You can review that code
> for an example of how to use them. So your X0 can still be used, you
> just have to define the data structure.
>

Thanks, Luis

I will dive into that.

Gr. AvS



2012-03-08 21:07:18

by Luis R. Rodriguez

[permalink] [raw]
Subject: Re: Problems with regulatory domain support and BCM43224

On Thu, Mar 8, 2012 at 1:01 PM, Arend van Spriel <[email protected]> wrote:
> On 03/08/2012 09:07 PM, Seth Forshee wrote:
>>
>> On Thu, Mar 08, 2012 at 11:51:03AM -0800, Luis R. Rodriguez wrote:
>>>
>>> On Thu, Mar 8, 2012 at 11:45 AM, Quan, David<[email protected]>
>>>  wrote:
>>>>
>>>> I think there is to it more than SW.
>>>> Where ever you get this card, is the card tested and regulatory approved
>>>> for those countries, DFS or not?
>>>
>>>
>>> Seth, what driver are you using? I know you are using a BCM43224 card.
>>
>>
>> brcmsmac
>>
>>>> It is possible that this card is only regulatory tested for non DFS
>>>> channels, but now you enable them for passive.
>>>
>>>
>>> That's a good point.
>>>
>>>> This means that yes, you are save and not violate DFS rules because you
>>>> are in passive mode. However, you are in complete violation if the STA finds
>>>> an AP on that DFS channel and then connects and transmits as this STA is not
>>>> allow to transmit on that channel since it is not approved.
>>>
>>>
>>> If the driver being used is a supported vendor driver then I'll punt
>>> this to the vendor (Broadcom). If this is the reversed engineered
>>> driver (b43) that Broadcom to this day seems to blindly ignore even
>>> for regulatory, then I'm happy to recommend based on your input to
>>> leave the regulatory domain as-is given that we cannot guarantee what
>>> the vendor meant as they have not done any work on releasing either
>>> documentation or code to help with their regulatory situation.
>>
>>
>> It would be nice if Broadcom could weigh in. Cc-ing Arend.
>
>
> Hi, Seth
>
> Noticed your email yesterday, but did not get to chime into the
> conversation. brcmsmac does indeed provide a regulatory hint, which is
> either from SPROM or hard-coded to "US". Since "X0" is not a known
> regulatory domain for crda it does not make sense to pass it as a regulatory
> hint. However, the "full" story is told on linuxwireless.org (see [1]).

The Linux kernel allows you to define custom regulatory domains, the
ath module uses these, it defines 13 of them. You can review that code
for an example of how to use them. So your X0 can still be used, you
just have to define the data structure.

Luis

2012-03-20 22:07:14

by Seth Forshee

[permalink] [raw]
Subject: Re: Problems with regulatory domain support and BCM43224

On Thu, Mar 08, 2012 at 01:06:57PM -0800, Luis R. Rodriguez wrote:
> > Hi, Seth
> >
> > Noticed your email yesterday, but did not get to chime into the
> > conversation. brcmsmac does indeed provide a regulatory hint, which is
> > either from SPROM or hard-coded to "US". Since "X0" is not a known
> > regulatory domain for crda it does not make sense to pass it as a regulatory
> > hint. However, the "full" story is told on linuxwireless.org (see [1]).
>
> The Linux kernel allows you to define custom regulatory domains, the
> ath module uses these, it defines 13 of them. You can review that code
> for an example of how to use them. So your X0 can still be used, you
> just have to define the data structure.

I took a shot at implementing custom regulatory domain support for
brcmsmac. I've got it working to the point of letting me see APs on the
DFS channels at least. The patch is below. A number of issues
undoubtedly remain to be resolved. Some that I can think of:

- I set up two custom domains, X0 and X2, which are identical. I'm not
sure precisely how each needs to be set up, but I took a reasonable
guess.

- I tried to integrate with the existing X2 domain support, but this
could probably be improved. I avoided making large changes because
there's some complexity in the current code that doesn't seem to
serve a purpose currently, but I assume it's there for a reason.

- The flow of the initialization and organization of the code make it
necessary to search through the list of custom regulatory domains
many times. It would be nice to improve upon this.

Does this look to be on the right track?

Thanks,
Seth


diff --git a/drivers/net/wireless/brcm80211/brcmsmac/channel.c b/drivers/net/wireless/brcm80211/brcmsmac/channel.c
index 55e9f45..d9c755c 100644
--- a/drivers/net/wireless/brcm80211/brcmsmac/channel.c
+++ b/drivers/net/wireless/brcm80211/brcmsmac/channel.c
@@ -16,6 +16,7 @@

#include <linux/types.h>
#include <net/mac80211.h>
+#include <net/regulatory.h>

#include <defs.h>
#include "pub.h"
@@ -24,6 +25,48 @@
#include "stf.h"
#include "channel.h"

+#define BRCM_2GHZ_2412_2462 REG_RULE(2412-10, 2462+10, 40, 0, 20, 0)
+#define BRCM_2GHZ_2467_2472 REG_RULE(2467-10, 2472+10, 20, 0, 20, \
+ NL80211_RRF_PASSIVE_SCAN | \
+ NL80211_RRF_NO_IBSS)
+#define BRCM_2GHZ_2484 REG_RULE(2484-10, 2484+10, 40, 0, 20, \
+ NL80211_RRF_PASSIVE_SCAN | \
+ NL80211_RRF_NO_OFDM)
+
+#define BRCM_5GHZ_5150_5240 REG_RULE(5150-10, 5240+10, 40, 0, 30, 0)
+#define BRCM_5GHZ_5260_5320 REG_RULE(5260-10, 5320+10, 40, 0, 30, \
+ NL80211_RRF_PASSIVE_SCAN | \
+ NL80211_RRF_NO_IBSS)
+#define BRCM_5GHZ_5470_5850 REG_RULE(5470-10, 5850+10, 40, 0, 30, \
+ NL80211_RRF_PASSIVE_SCAN | \
+ NL80211_RRF_NO_IBSS)
+
+/* Aggregate rules */
+#define BRCM_2GHZ_ALL BRCM_2GHZ_2412_2462, \
+ BRCM_2GHZ_2467_2472, \
+ BRCM_2GHZ_2484
+#define BRCM_5GHZ_ALL BRCM_5GHZ_5150_5240, \
+ BRCM_5GHZ_5260_5320, \
+ BRCM_5GHZ_5470_5850
+
+static const struct ieee80211_regdomain brcms_regdomain_x0 = {
+ .n_reg_rules = 6,
+ .alpha2 = "X0",
+ .reg_rules = {
+ BRCM_2GHZ_ALL,
+ BRCM_5GHZ_ALL,
+ }
+};
+
+static const struct ieee80211_regdomain brcms_regdomain_x2 = {
+ .n_reg_rules = 6,
+ .alpha2 = "X2",
+ .reg_rules = {
+ BRCM_2GHZ_ALL,
+ BRCM_5GHZ_ALL,
+ }
+};
+
/* QDB() macro takes a dB value and converts to a quarter dB value */
#define QDB(n) ((n) * BRCMS_TXPWR_DB_FACTOR)

@@ -504,14 +547,42 @@ static const struct locale_mimo_info *g_mimo_5g_table[] = {
&locale_11n
};

-static const struct {
+struct brcms_regdomain {
char abbrev[BRCM_CNTRY_BUF_SZ]; /* country abbreviation */
struct country_info country;
-} cntry_locales[] = {
+ const struct ieee80211_regdomain *regdomain;
+};
+
+static const struct brcms_regdomain cntry_locales[] = {
+ /* Worldwide Row 0 */
+ {
+ .abbrev = "X0",
+ .country = LOCALES(i, 11, bn, 11n),
+ .regdomain = &brcms_regdomain_x0,
+ },
+ /* Worldwide Row 2 */
{
- "X2", LOCALES(i, 11, bn, 11n)}, /* Worldwide RoW 2 */
+ .abbrev = "X2",
+ .country = LOCALES(i, 11, bn, 11n),
+ .regdomain = &brcms_regdomain_x2,
+ },
};

+static const struct brcms_regdomain *brcms_world_regd(const char *regdom)
+{
+ const struct brcms_regdomain *regd = NULL;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(cntry_locales); i++) {
+ if (!strcmp(regdom, cntry_locales[i].abbrev)) {
+ regd = &cntry_locales[i];
+ break;
+ }
+ }
+
+ return regd;
+}
+
#ifdef SUPPORT_40MHZ
/* 20MHz channel info for 40MHz pairing support */
struct chan20_info {
@@ -634,7 +705,7 @@ brcms_c_country_aggregate_map(struct brcms_cm_info *wlc_cm, const char *ccode,
static const struct country_info *
brcms_c_country_lookup_direct(const char *ccode, uint regrev)
{
- uint size, i;
+ const struct brcms_regdomain *regd;

/* Should just return 0 for single locale driver. */
/* Keep it this way in case we add more locales. (for now anyway) */
@@ -646,13 +717,8 @@ brcms_c_country_lookup_direct(const char *ccode, uint regrev)
if (regrev > 0)
return NULL;

- /* find matched table entry from country code */
- size = ARRAY_SIZE(cntry_locales);
- for (i = 0; i < size; i++) {
- if (strcmp(ccode, cntry_locales[i].abbrev) == 0)
- return &cntry_locales[i].country;
- }
- return NULL;
+ regd = brcms_world_regd(ccode);
+ return regd ? &regd->country : NULL;
}

static const struct country_info *
@@ -1073,8 +1139,7 @@ brcms_c_set_countrycode(struct brcms_cm_info *wlc_cm, const char *ccode)
struct brcms_cm_info *brcms_c_channel_mgr_attach(struct brcms_c_info *wlc)
{
struct brcms_cm_info *wlc_cm;
- char country_abbrev[BRCM_CNTRY_BUF_SZ];
- const struct country_info *country;
+ const struct brcms_regdomain *regd = NULL;
struct brcms_pub *pub = wlc->pub;
char *ccode;

@@ -1089,24 +1154,34 @@ struct brcms_cm_info *brcms_c_channel_mgr_attach(struct brcms_c_info *wlc)

/* store the country code for passing up as a regulatory hint */
ccode = getvar(wlc->hw->sih, BRCMS_SROM_CCODE);
- if (ccode)
+ if (ccode) {
strncpy(wlc->pub->srom_ccode, ccode, BRCM_CNTRY_BUF_SZ - 1);
+ regd = brcms_world_regd(ccode);
+ }

/*
- * internal country information which must match
- * regulatory constraints in firmware
+ * If no custom world domain is found in the SROM, use the
+ * default "X2" domain.
*/
- memset(country_abbrev, 0, BRCM_CNTRY_BUF_SZ);
- strncpy(country_abbrev, "X2", sizeof(country_abbrev) - 1);
- country = brcms_c_country_lookup(wlc, country_abbrev);
+ if (!regd) {
+ ccode = "X2";
+ regd = brcms_world_regd(ccode);
+ }
+
+ if (WARN_ON(!regd)) {
+ wiphy_err(wlc->wiphy, "No world regulatory domain found\n");
+ wlc->cmi = NULL;
+ kfree(wlc_cm);
+ return NULL;
+ }

/* save default country for exiting 11d regulatory mode */
- strncpy(wlc->country_default, country_abbrev, BRCM_CNTRY_BUF_SZ - 1);
+ strncpy(wlc->country_default, ccode, BRCM_CNTRY_BUF_SZ - 1);

/* initialize autocountry_default to driver default */
- strncpy(wlc->autocountry_default, "X2", BRCM_CNTRY_BUF_SZ - 1);
+ strncpy(wlc->autocountry_default, ccode, BRCM_CNTRY_BUF_SZ - 1);

- brcms_c_set_countrycode(wlc_cm, country_abbrev);
+ brcms_c_set_countrycode(wlc_cm, ccode);

return wlc_cm;
}
@@ -1471,3 +1546,23 @@ bool brcms_c_valid_chanspec_db(struct brcms_cm_info *wlc_cm, u16 chspec)
{
return brcms_c_valid_chanspec_ext(wlc_cm, chspec, true);
}
+
+bool brcms_is_world_regd(const char *regdom)
+{
+ return !!brcms_world_regd(regdom);
+}
+
+void brcms_c_regd_init(struct brcms_c_info *wlc)
+{
+ const struct brcms_regdomain *regd = NULL;
+ const char *ccode = wlc->pub->srom_ccode;
+
+ if (!ccode[0])
+ return;
+
+ regd = brcms_world_regd(ccode);
+ if (regd) {
+ wlc->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY;
+ wiphy_apply_custom_regulatory(wlc->wiphy, regd->regdomain);
+ }
+}
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/channel.h b/drivers/net/wireless/brcm80211/brcmsmac/channel.h
index 808cb4f..a9251cd 100644
--- a/drivers/net/wireless/brcm80211/brcmsmac/channel.h
+++ b/drivers/net/wireless/brcm80211/brcmsmac/channel.h
@@ -50,4 +50,8 @@ extern void brcms_c_channel_set_chanspec(struct brcms_cm_info *wlc_cm,
u16 chanspec,
u8 local_constraint_qdbm);

+extern bool brcms_is_world_regd(const char *regdom);
+
+extern void brcms_c_regd_init(struct brcms_c_info *wlc);
+
#endif /* _WLC_CHANNEL_H */
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c b/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c
index 569ab8a..db1d277 100644
--- a/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c
+++ b/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c
@@ -727,7 +727,9 @@ static const struct ieee80211_ops brcms_ops = {
*/
static int brcms_set_hint(struct brcms_info *wl, char *abbrev)
{
- return regulatory_hint(wl->pub->ieee_hw->wiphy, abbrev);
+ if (!brcms_is_world_regd(abbrev))
+ return regulatory_hint(wl->pub->ieee_hw->wiphy, abbrev);
+ return 0;
}

void brcms_dpc(unsigned long data)
@@ -1059,6 +1061,8 @@ static struct brcms_info *brcms_attach(struct bcma_device *pdev)
goto fail;
}

+ brcms_c_regd_init(wl->wlc);
+
memcpy(perm, &wl->pub->cur_etheraddr, ETH_ALEN);
if (WARN_ON(!is_valid_ether_addr(perm)))
goto fail;
@@ -1071,8 +1075,6 @@ static struct brcms_info *brcms_attach(struct bcma_device *pdev)

if (wl->pub->srom_ccode[0])
err = brcms_set_hint(wl, wl->pub->srom_ccode);
- else
- err = brcms_set_hint(wl, "US");
if (err)
wiphy_err(wl->wiphy, "%s: regulatory_hint failed, status %d\n",
__func__, err);


2012-03-08 21:59:16

by Seth Forshee

[permalink] [raw]
Subject: Re: Problems with regulatory domain support and BCM43224

On Thu, Mar 08, 2012 at 11:51:03AM -0800, Luis R. Rodriguez wrote:
> On Thu, Mar 8, 2012 at 11:45 AM, Quan, David <[email protected]> wrote:
> > I think there is to it more than SW.
> > Where ever you get this card, is the card tested and regulatory approved for those countries, DFS or not?
>
> Seth, what driver are you using? I know you are using a BCM43224 card.
>
> > It is possible that this card is only regulatory tested for non DFS channels, but now you enable them for passive.
>
> That's a good point.
>
> > This means that yes, you are save and not violate DFS rules because you are in passive mode. However, you are in complete violation if the STA finds an AP on that DFS channel and then connects and transmits as this STA is not allow to transmit on that channel since it is not approved.

I was thinking about this some more. I still don't understand why it
makes sense to omit these frequencies from the world domain. Isn't the
point of geographic domains to communicate the rules for wherever the
user happens to be at the time? Does the core regulatory support really
ever know which frequencies the hardware has ben approved for, even
among those it already allows?

It seems to me that it's the job of the driver to communicate
hardware-specific regulatory hints. So _if_ passive scanning of the DFS
frequencies is allowed worldwide (I emphasize the if because I don't
know whether or not that's true), why should the world domain not allow
this?

Seth


2012-03-08 21:42:15

by Seth Forshee

[permalink] [raw]
Subject: Re: Problems with regulatory domain support and BCM43224

On Thu, Mar 08, 2012 at 10:31:46PM +0100, Arend van Spriel wrote:
> >>Noticed your email yesterday, but did not get to chime into the
> >>conversation. brcmsmac does indeed provide a regulatory hint, which is
> >>either from SPROM or hard-coded to "US". Since "X0" is not a known
> >>regulatory domain for crda it does not make sense to pass it as a regulatory
> >>hint. However, the "full" story is told on linuxwireless.org (see [1]).
> >
> >The Linux kernel allows you to define custom regulatory domains, the
> >ath module uses these, it defines 13 of them. You can review that code
> >for an example of how to use them. So your X0 can still be used, you
> >just have to define the data structure.
> >
>
> Thanks, Luis
>
> I will dive into that.

Luis, Arend, thanks to both of you. Let me know if there's anything I
can do to help.

Seth


2012-03-08 20:17:50

by Luis R. Rodriguez

[permalink] [raw]
Subject: Re: Problems with regulatory domain support and BCM43224

On Thu, Mar 8, 2012 at 12:07 PM, Seth Forshee
<[email protected]> wrote:
> On Thu, Mar 08, 2012 at 11:51:03AM -0800, Luis R. Rodriguez wrote:
>> On Thu, Mar 8, 2012 at 11:45 AM, Quan, David <[email protected]> wrote:
>> > I think there is to it more than SW.
>> > Where ever you get this card, is the card tested and regulatory approved for those countries, DFS or not?
>>
>> Seth, what driver are you using? I know you are using a BCM43224 card.
>
> brcmsmac

Oh this is a driver fully supported by Broadcom :D

>> > It is possible that this card is only regulatory tested for non DFS channels, but now you enable them for passive.
>>
>> That's a good point.
>>
>> > This means that yes, you are save and not violate DFS rules because you are in passive mode. However, you are in complete violation if the STA finds an AP on that DFS channel and then connects and transmits as this STA is not allow to transmit on that channel since it is not approved.
>>
>> If the driver being used is a supported vendor driver then I'll punt
>> this to the vendor (Broadcom). If this is the reversed engineered
>> driver (b43) that Broadcom to this day seems to blindly ignore even
>> for regulatory, then I'm happy to recommend based on your input to
>> leave the regulatory domain as-is given that we cannot guarantee what
>> the vendor meant as they have not done any work on releasing either
>> documentation or code to help with their regulatory situation.
>
> It would be nice if Broadcom could weigh in. Cc-ing Arend.

Indeed.

> This is actually a special case. This is an Apple machine, and it's not
> that there's no regulatory hint in the ROM, it's that the hint is the
> bogus country code "X0". From reading online, Apple uses this to
> indicate the regulatory domain is unknown, and it uses the first
> regulatory hint it sees in a country IE. I can connect to DFS channels
> using MacOS on the machine, so I'll assume it was approved for DFS
> channels.

I'll let Broadcom weigh in.

> Since Linux (afaict) only uses hits from country IEs for APs it's
> connected to, much of the time this card ends up using the world domain
> and is unable to scan DFS channels.

Indeed, we only process the IE if we connect to the AP.

Luis

2012-03-08 19:36:30

by Luis R. Rodriguez

[permalink] [raw]
Subject: Re: Problems with regulatory domain support and BCM43224

On Thu, Mar 8, 2012 at 11:07 AM, Quan, David <[email protected]> wrote:
> 1) Depending on which WW sku number you selected, it may and may not support the DFS channels. So this is not true that we do not support DFS channels in WW mode.

David, sorry I should have clarified, this is not for ath9k. This is
for other drivers which do not have custom regulatory domains nor do
they have any regulatory hint obtainable from their EEPROM. For those
cards that do not have anything like this we make them use the world
regulatory domain by default.

> 2) Today, I do not believe ath9k code supports DFS detection. If that is what you mean. Therefore STA mode will not support DFS detection. However, STA does support DFS channels. DFS channel support vs DFS detection support is two different things. DFS channel support as a slave device, only has to do passive scanning.
>
> Let me know if that answers your questions.

It does, but would like your advice / review on the idea of enabling
DFS channels as passive scan, no-ibss (or any radiation enabled) for
cards that use the static default world regulatory domain in the
kernel. This would not in any way affect ath9k, ath6kl, or any of our
cards, but just help other cards that do not have anything
implemented.

Luis

2012-03-08 17:41:07

by Seth Forshee

[permalink] [raw]
Subject: Re: Problems with regulatory domain support and BCM43224

Adding some Cc's.

On Wed, Mar 07, 2012 at 01:40:01PM -0600, Seth Forshee wrote:
> I set up an AP recently in the 5 GHz band and noticed that a MacBook Air
> with BCM43224 wireless can't see it. iw shows that the 5260-5700 MHz
> frequency range is disabled. I compared this to an Intel Centrino 6205
> card which shows passive scanning is allowed in this range. Both show
> that they're using the world regulatory domain, and I can get the
> BCM43224 to see my AP when I force the domain to US.
>
> I've been going through the regulatory code trying to understand what's
> happening, and while I haven't fully grokked it yet it seems to me the
> difference is that iwlwifi is setting WIPHY_FLAG_CUSTOM_REGULATORY and
> brcmsmac is not. iwlwifi isn't supplying a regulatory hint, and mac80211
> doesn't end up applying any regulatory settings due to the flag.
> brcmsmac supplies a hint using the country code it reads from its srom,
> "X0" (which Google tells me is an interim code that Apple uses while the
> actual country code is unknown). Since this code is bogus the world
> domain gets applied.
>
> mac80211 doesn't appear to update the regulatory domain from the beacons
> unless connected to an AP that happens to be providing the country IE,
> so we're left in the unfortunate situation of being unable to scan
> certain frequencies unless the user connects to such an AP or sets the
> domain manually.

As I understand it, the DFS channels aren't included in the world domain
because Linux does not yet fully support DFS. But I can then specify a
domain that's known to require DFS on these channels, and they are
enabled. This seems illogical. If passive scanning is okay when we know
DFS is required, why can't it be enabled in the world domain when we
simply don't know if it's required?

Thanks,
Seth


2012-03-08 18:53:33

by Luis R. Rodriguez

[permalink] [raw]
Subject: Re: Problems with regulatory domain support and BCM43224

David, Michael,

below is a thread on world regulatory domains and DFS. This is a
public thread so replying to this is public. The question is simple:
why not add DFS channels to the world regulatory domain provided that
1) we only passive scan on them 2) STA does support DFS support. It
seems logical to me now that this should be enabled, but I can't
recall if perhaps I am forgetting something.

The beacon hint code we have, which enables radiation upon finding a
beacon from an AP on a 5 GHz channel only does beacon hints for
non-DFS channels, so a device using the world regulatory domain is
guaranteed to not initiate radiation on these channels.

Seth, my response to you below.

On Thu, Mar 8, 2012 at 9:41 AM, Seth Forshee <[email protected]> wrote:
> As I understand it, the DFS channels aren't included in the world domain
> because Linux does not yet fully support DFS.

A STA device can connect to a DFS AP when the STA device does have
those DFS channels as part of its world regulatory domain, but the STA
will passively scan on those channels given that sending a probe
request is active radiation and active radiation requires a bit of
code which is not yet complete and only used as a AP. You are right
though that the Linux regulatory code though does not include any DFS
channels in the world regulatory domain. The world regulatory domain
is the mathematical intersection of all the regulatory domains in the
world (see intersect.c on CRDA) but a few set of channels were added
as well which are not DFS with the condition that we do passive scans.
We did remove the DFS channels completely.

> But I can then specify a
> domain that's known to require DFS on these channels, and they are
> enabled. This seems illogical. If passive scanning is okay when we know
> DFS is required, why can't it be enabled in the world domain when we
> simply don't know if it's required?

Its a fair point and given the way we handle beacon hints and not
enabling them for DFS channels at all, and if we only passively scan
for DFS channels I think this should be good.

Luis

2012-03-08 19:45:26

by Quan, David

[permalink] [raw]
Subject: RE: Problems with regulatory domain support and BCM43224

SSB0aGluayB0aGVyZSBpcyB0byBpdCBtb3JlIHRoYW4gU1cuDQpXaGVyZSBldmVyIHlvdSBnZXQg
dGhpcyBjYXJkLCBpcyB0aGUgY2FyZCB0ZXN0ZWQgYW5kIHJlZ3VsYXRvcnkgYXBwcm92ZWQgZm9y
IHRob3NlIGNvdW50cmllcywgREZTIG9yIG5vdD8NCg0KSXQgaXMgcG9zc2libGUgdGhhdCB0aGlz
IGNhcmQgaXMgb25seSByZWd1bGF0b3J5IHRlc3RlZCBmb3Igbm9uIERGUyBjaGFubmVscywgYnV0
IG5vdyB5b3UgZW5hYmxlIHRoZW0gZm9yIHBhc3NpdmUuIFRoaXMgbWVhbnMgdGhhdCB5ZXMsIHlv
dSBhcmUgc2F2ZSBhbmQgbm90IHZpb2xhdGUgREZTIHJ1bGVzIGJlY2F1c2UgeW91IGFyZSBpbiBw
YXNzaXZlIG1vZGUuIEhvd2V2ZXIsIHlvdSBhcmUgaW4gY29tcGxldGUgdmlvbGF0aW9uIGlmIHRo
ZSBTVEEgZmluZHMgYW4gQVAgb24gdGhhdCBERlMgY2hhbm5lbCBhbmQgdGhlbiBjb25uZWN0cyBh
bmQgdHJhbnNtaXRzIGFzIHRoaXMgU1RBIGlzIG5vdCBhbGxvdyB0byB0cmFuc21pdCBvbiB0aGF0
IGNoYW5uZWwgc2luY2UgaXQgaXMgbm90IGFwcHJvdmVkLg0KDQpEYXZpZA0KDQoNCi0tLS0tT3Jp
Z2luYWwgTWVzc2FnZS0tLS0tDQpGcm9tOiBtY2dyb2ZAZ21haWwuY29tIFttYWlsdG86bWNncm9m
QGdtYWlsLmNvbV0gT24gQmVoYWxmIE9mIEx1aXMgUi4gUm9kcmlndWV6DQpTZW50OiBUaHVyc2Rh
eSwgTWFyY2ggMDgsIDIwMTIgMTE6MzYgQU0NClRvOiBRdWFuLCBEYXZpZA0KQ2M6IFNldGggRm9y
c2hlZTsgR3JlZW4sIE1pY2hhZWw7IGxpbnV4LXdpcmVsZXNzQHZnZXIua2VybmVsLm9yZzsgSm9o
YW5uZXMgQmVyZw0KU3ViamVjdDogUmU6IFByb2JsZW1zIHdpdGggcmVndWxhdG9yeSBkb21haW4g
c3VwcG9ydCBhbmQgQkNNNDMyMjQNCg0KT24gVGh1LCBNYXIgOCwgMjAxMiBhdCAxMTowNyBBTSwg
UXVhbiwgRGF2aWQgPGRxdWFuQHFjYS5xdWFsY29tbS5jb20+IHdyb3RlOg0KPiAxKSBEZXBlbmRp
bmcgb24gd2hpY2ggV1cgc2t1IG51bWJlciB5b3Ugc2VsZWN0ZWQsIGl0IG1heSBhbmQgbWF5IG5v
dCBzdXBwb3J0IHRoZSBERlMgY2hhbm5lbHMuIFNvIHRoaXMgaXMgbm90IHRydWUgdGhhdCB3ZSBk
byBub3Qgc3VwcG9ydCBERlMgY2hhbm5lbHMgaW4gV1cgbW9kZS4NCg0KRGF2aWQsIHNvcnJ5IEkg
c2hvdWxkIGhhdmUgY2xhcmlmaWVkLCB0aGlzIGlzIG5vdCBmb3IgYXRoOWsuIFRoaXMgaXMgZm9y
IG90aGVyIGRyaXZlcnMgd2hpY2ggZG8gbm90IGhhdmUgY3VzdG9tIHJlZ3VsYXRvcnkgZG9tYWlu
cyBub3IgZG8gdGhleSBoYXZlIGFueSByZWd1bGF0b3J5IGhpbnQgb2J0YWluYWJsZSBmcm9tIHRo
ZWlyIEVFUFJPTS4gRm9yIHRob3NlIGNhcmRzIHRoYXQgZG8gbm90IGhhdmUgYW55dGhpbmcgbGlr
ZSB0aGlzIHdlIG1ha2UgdGhlbSB1c2UgdGhlIHdvcmxkIHJlZ3VsYXRvcnkgZG9tYWluIGJ5IGRl
ZmF1bHQuDQoNCj4gMikgVG9kYXksIEkgZG8gbm90IGJlbGlldmUgYXRoOWsgY29kZSBzdXBwb3J0
cyBERlMgZGV0ZWN0aW9uLiBJZiB0aGF0IGlzIHdoYXQgeW91IG1lYW4uIFRoZXJlZm9yZSBTVEEg
bW9kZSB3aWxsIG5vdCBzdXBwb3J0IERGUyBkZXRlY3Rpb24uIEhvd2V2ZXIsIFNUQSBkb2VzIHN1
cHBvcnQgREZTIGNoYW5uZWxzLiBERlMgY2hhbm5lbCBzdXBwb3J0IHZzIERGUyBkZXRlY3Rpb24g
c3VwcG9ydCBpcyB0d28gZGlmZmVyZW50IHRoaW5ncy4gREZTIGNoYW5uZWwgc3VwcG9ydCBhcyBh
IHNsYXZlIGRldmljZSwgb25seSBoYXMgdG8gZG8gcGFzc2l2ZSBzY2FubmluZy4NCj4NCj4gTGV0
IG1lIGtub3cgaWYgdGhhdCBhbnN3ZXJzIHlvdXIgcXVlc3Rpb25zLg0KDQpJdCBkb2VzLCBidXQg
d291bGQgbGlrZSB5b3VyIGFkdmljZSAvIHJldmlldyBvbiB0aGUgaWRlYSBvZiBlbmFibGluZyBE
RlMgY2hhbm5lbHMgYXMgcGFzc2l2ZSBzY2FuLCBuby1pYnNzIChvciBhbnkgcmFkaWF0aW9uIGVu
YWJsZWQpIGZvciBjYXJkcyB0aGF0IHVzZSB0aGUgc3RhdGljIGRlZmF1bHQgd29ybGQgcmVndWxh
dG9yeSBkb21haW4gaW4gdGhlIGtlcm5lbC4gVGhpcyB3b3VsZCBub3QgaW4gYW55IHdheSBhZmZl
Y3QgYXRoOWssIGF0aDZrbCwgb3IgYW55IG9mIG91ciBjYXJkcywgYnV0IGp1c3QgaGVscCBvdGhl
ciBjYXJkcyB0aGF0IGRvIG5vdCBoYXZlIGFueXRoaW5nIGltcGxlbWVudGVkLg0KDQogIEx1aXMN
Cg==

2012-03-08 19:51:24

by Luis R. Rodriguez

[permalink] [raw]
Subject: Re: Problems with regulatory domain support and BCM43224

On Thu, Mar 8, 2012 at 11:45 AM, Quan, David <[email protected]> wrote:
> I think there is to it more than SW.
> Where ever you get this card, is the card tested and regulatory approved for those countries, DFS or not?

Seth, what driver are you using? I know you are using a BCM43224 card.

> It is possible that this card is only regulatory tested for non DFS channels, but now you enable them for passive.

That's a good point.

> This means that yes, you are save and not violate DFS rules because you are in passive mode. However, you are in complete violation if the STA finds an AP on that DFS channel and then connects and transmits as this STA is not allow to transmit on that channel since it is not approved.

If the driver being used is a supported vendor driver then I'll punt
this to the vendor (Broadcom). If this is the reversed engineered
driver (b43) that Broadcom to this day seems to blindly ignore even
for regulatory, then I'm happy to recommend based on your input to
leave the regulatory domain as-is given that we cannot guarantee what
the vendor meant as they have not done any work on releasing either
documentation or code to help with their regulatory situation.

Luis

2012-03-21 14:19:21

by Seth Forshee

[permalink] [raw]
Subject: Re: Problems with regulatory domain support and BCM43224

On Wed, Mar 21, 2012 at 12:05:40PM +0100, Arend van Spriel wrote:
> On 03/20/2012 11:07 PM, Seth Forshee wrote:
> >On Thu, Mar 08, 2012 at 01:06:57PM -0800, Luis R. Rodriguez wrote:
> >>>Hi, Seth
> >>>
> >>>Noticed your email yesterday, but did not get to chime into the
> >>>conversation. brcmsmac does indeed provide a regulatory hint, which is
> >>>either from SPROM or hard-coded to "US". Since "X0" is not a known
> >>>regulatory domain for crda it does not make sense to pass it as a regulatory
> >>>hint. However, the "full" story is told on linuxwireless.org (see [1]).
> >>
> >>The Linux kernel allows you to define custom regulatory domains, the
> >>ath module uses these, it defines 13 of them. You can review that code
> >>for an example of how to use them. So your X0 can still be used, you
> >>just have to define the data structure.
> >
> >I took a shot at implementing custom regulatory domain support for
> >brcmsmac. I've got it working to the point of letting me see APs on the
> >DFS channels at least. The patch is below. A number of issues
> >undoubtedly remain to be resolved. Some that I can think of:
>
> Hi Seth,
>
> Thanks for looking into this. I also did some tinkering over here,
> but not sure which way to go here, ie. 1) define and use custom
> regulatory domains, or 2) be happy with world regulatory domain as
> is and do not pass the custom codes if found in sprom.

For 2 I think you also have to set WIPGHY_FLAG_CUSTOM_REGULATORY or else
the default world domain will still be applied. That certainly seems to
be the quick-and-easy fix, but I'm not sure about what's preferable.

However, I do think that passing up the custom codes as hints doesn't
make sense, and the patch I sent only passes it up if it's not known to
be one of the custom domains.

> > - I set up two custom domains, X0 and X2, which are identical. I'm not
> > sure precisely how each needs to be set up, but I took a reasonable
> > guess.
>
> There are 9 custom domains in the proprietary driver. X0 only allows
> using channels 1-11. X2 allows 1-13. There are other parameters like
> rates and txpower that may differ.

That's the kind if information I would need to make this patch viable.
I'll go ahead and update the patch to remove channels 12-13 from X0, and
14 from both. Are the 5 GHz rules correct?

Are the custom domains named X[0-8]? If that's the case I can simplify
some of the code.

> > - I tried to integrate with the existing X2 domain support, but this
> > could probably be improved. I avoided making large changes because
> > there's some complexity in the current code that doesn't seem to
> > serve a purpose currently, but I assume it's there for a reason.
>
> The code in channel.c was taken from our proprietary driver.
> Basically, the LOCALES hold the same information as the rules in
> regdomain.

I assumed as much, but I haven't made much of an effort to understand it
yet.

But the complexity I'm referring to is really the infrastructure to
support multiple locales and revisions that just isn't used right now. I
can only assume that there are plans to use additional locales and
revisions at some point.

> > - The flow of the initialization and organization of the code make it
> > necessary to search through the list of custom regulatory domains
> > many times. It would be nice to improve upon this.
> >
> >Does this look to be on the right track?
> >
>
> Looks good. I will see if I can map the LOCALES for these to
> regdomain rules.

Great! Thanks for you comments.

Seth

2012-03-22 00:27:19

by Luis R. Rodriguez

[permalink] [raw]
Subject: Re: Problems with regulatory domain support and BCM43224

On Wed, Mar 21, 2012 at 02:37:06PM -0500, Seth Forshee wrote:
> On Wed, Mar 21, 2012 at 11:17:53AM -0700, Luis R. Rodriguez wrote:
> > Adding Michael and David just for their information. I know Henry
> > is not with Broadcom any more but hey, hey may be interested.
> >
> > On Wed, Mar 21, 2012 at 06:51:16PM +0100, Arend van Spriel wrote:
> > > On 03/21/2012 03:19 PM, Seth Forshee wrote:
> > > >On Wed, Mar 21, 2012 at 12:05:40PM +0100, Arend van Spriel wrote:
> > > >>On 03/20/2012 11:07 PM, Seth Forshee wrote:
> > > >>>On Thu, Mar 08, 2012 at 01:06:57PM -0800, Luis R. Rodriguez wrote:
> > > >>>>>Hi, Seth
> > > >>>>>
> > > >>>>>Noticed your email yesterday, but did not get to chime into the
> > > >>>>>conversation. brcmsmac does indeed provide a regulatory hint, which is
> > > >>>>>either from SPROM or hard-coded to "US". Since "X0" is not a known
> > > >>>>>regulatory domain for crda it does not make sense to pass it as a regulatory
> > > >>>>>hint. However, the "full" story is told on linuxwireless.org (see [1]).
> > > >>>>
> > > >>>>The Linux kernel allows you to define custom regulatory domains, the
> > > >>>>ath module uses these, it defines 13 of them. You can review that code
> > > >>>>for an example of how to use them. So your X0 can still be used, you
> > > >>>>just have to define the data structure.
> > > >>>
> > > >>>I took a shot at implementing custom regulatory domain support for
> > > >>>brcmsmac. I've got it working to the point of letting me see APs on the
> > > >>>DFS channels at least. The patch is below. A number of issues
> > > >>>undoubtedly remain to be resolved. Some that I can think of:
> > > >>
> > > >>Hi Seth,
> > > >>
> > > >>Thanks for looking into this. I also did some tinkering over here,
> > > >>but not sure which way to go here, ie. 1) define and use custom
> > > >>regulatory domains, or 2) be happy with world regulatory domain as
> > > >>is and do not pass the custom codes if found in sprom.
> > > >
> > > >For 2 I think you also have to set WIPGHY_FLAG_CUSTOM_REGULATORY or else
> > > >the default world domain will still be applied. That certainly seems to
> > > >be the quick-and-easy fix, but I'm not sure about what's preferable.
> > > >
> > > >However, I do think that passing up the custom codes as hints doesn't
> > > >make sense, and the patch I sent only passes it up if it's not known to
> > > >be one of the custom domains.
> > >
> > > Ok. so the wiphy_apply_custom_regulatory() does not make the custom
> > > domains known by their code (.alpha2).
> > >
> > > >>> - I set up two custom domains, X0 and X2, which are identical. I'm not
> > > >>> sure precisely how each needs to be set up, but I took a reasonable
> > > >>> guess.
> > > >>
> > > >>There are 9 custom domains in the proprietary driver. X0 only allows
> > > >>using channels 1-11. X2 allows 1-13. There are other parameters like
> > > >>rates and txpower that may differ.
> > > >
> > > >That's the kind if information I would need to make this patch viable.
> > > >I'll go ahead and update the patch to remove channels 12-13 from X0, and
> > > >14 from both. Are the 5 GHz rules correct?
> > >
> > > 5G channels are all considered passive by brcmsmac. Not sure whether
> > > that should be made explicit in the rules. Also the driver does not
> > > support IBSS so those flags are redundant now, but it is good to
> > > have it already in place.
> > >
> > > >Are the custom domains named X[0-8]? If that's the case I can simplify
> > > >some of the code.
> > >
> > > Unfortunately, no.
> > >
> > > >>> - I tried to integrate with the existing X2 domain support, but this
> > > >>> could probably be improved. I avoided making large changes because
> > > >>> there's some complexity in the current code that doesn't seem to
> > > >>> serve a purpose currently, but I assume it's there for a reason.
> > > >>
> > > >>The code in channel.c was taken from our proprietary driver.
> > > >>Basically, the LOCALES hold the same information as the rules in
> > > >>regdomain.
> > > >
> > > >I assumed as much, but I haven't made much of an effort to understand it
> > > >yet.
> > > >
> > > >But the complexity I'm referring to is really the infrastructure to
> > > >support multiple locales and revisions that just isn't used right now. I
> > > >can only assume that there are plans to use additional locales and
> > > >revisions at some point.
> > >
> > > Understood. The proprietary driver (which is not a mac80211 driver)
> > > supports a lot of locales, which are selected on country code and
> > > regulatory revision (both read from sprom). I suspect this is done
> > > to support the regulatory rules for which the device was certified.
> > > Revisiting channel.c is on our work list, but it would mean more
> > > moving toward using the regdomain approach you started on instead of
> > > locales.
> >
> > Let me first explain a little on how Atheros' regulatory mapping works, hope
> > this helps you.
> >
> > If companies have a map of a regdomain to an alpha2 then the country alpha2
> > approach makes sense. For Atheros it just so happens that some EEPROM codes map
> > to a direct alpha2, which is a direct map. In other cases we have an EEPROM
> > code map to a region, but such region allows usage of a card in set of
> > different countries -- these countries all happen to have the same regulatory
> > domain, which is why for these regions we just ask for the first alphabetical
> > alpha2. Regardless of the country in the region the regulatory domain in CRDA
> > is expected to be the same. Then we have 12 custom world regulatory domains
> > which are exactly for that -- world roaming. In these cases we have 12 custom
> > regulatory domains and disable initiating radiation on them until we know where
> > we are through a country IE. We also take advantage of the beacon regulatory
> > hints in this case. The custom regulatory domains should be used only if you
> > really cannot map a region code to any alpha2, but consider the case of
> > grouping countries together if you know the assumption was that different
> > countries had the same regulatory domain. This can help simoplify your
> > implementation. For more details please read:
> >
> > http://wireless.kernel.org/en/users/Drivers/ath#Regulatory
> > http://wireless.kernel.org/en/developers/Regulatory/processing_rules
> >
> > One idea that occcurs to me to help simplify this even further is --
> > for us to consider mapping a region to a set of different alpha2s, then
> > send a custom regdomain building request to userspace based on these
> > group of alpha2s, userpace could respond with an intersection of the
> > alpha2s. CRDA already implements the capability to intersect regulatory
> > domains, so the code is already there, we'd just need the hooks for
> > the kernel if this is deemed desirable. This is just and idea and
> > worth considering for the revamp of regulatory code.
> >
> > More and more I see things like this getting complicated by the
> > years, perhaps its a good time to review the possibility of getting
> > together and sticking to something simple for the better or simplicity.
> > I realize that the difficulty lies here in supporting other OSes, which
> > is why we have worked hard at ensuring we permissively license all
> > regulatory code and recently we even relicensed cfg80211's reg.c
> > and other regulatory components. To help with this even further I
> > have also started a userspace regulatory simulator [0] complete permissively
> > licensed which allows us to simulate and engineer regulatory solutions
> > completley in userspace and if we are happy later adapt the code to
> > kernelspace / firmware / proprietary software / whatever.
> >
> > So -- please consider all these things when implmenting your solution
> > on the Broadcom driver. Keep in mind the ways to improve regulatory
> > and current work and design considreations.
> >
> > [0] git://github.com/mcgrof/regsim.git
>
> Great information, Luis. Thanks so much.
>
> Arend, in order to proceed it looks like what we need to know is what
> the custom domains represent, i.e. whether they map to a specific
> country or set of countries, etc.

This is why it is crucial for vendors themselves to get involved in this
process. Only they will truly know and completely understand what this
all means. Since it is hard to keep track of this information it is also
why we have documented what our EEPROM regulatory domains look like and
what they mean / map to.

http://wireless.kernel.org/en/users/Drivers/ath

Something similar may be worthy for this driver. But just my own 0.02
costarican colones.

> From what you've said so far it looks
> like X0 may map to US

BTW if this is the case, you may be able to send the regulatory hint
for "US" and then apply any thing you need on top of that after
through the reg_notifier() callback.

> while X2 is more of a world roaming domain, but again I'm just guessing.

Luis

2012-03-08 22:13:07

by Luis R. Rodriguez

[permalink] [raw]
Subject: Re: Problems with regulatory domain support and BCM43224

On Thu, Mar 8, 2012 at 1:59 PM, Seth Forshee <[email protected]> wrote:
> On Thu, Mar 08, 2012 at 11:51:03AM -0800, Luis R. Rodriguez wrote:
>> On Thu, Mar 8, 2012 at 11:45 AM, Quan, David <[email protected]> wrote:
>> > I think there is to it more than SW.
>> > Where ever you get this card, is the card tested and regulatory approved for those countries, DFS or not?
>>
>> Seth, what driver are you using? I know you are using a BCM43224 card.
>>
>> > It is possible that this card is only regulatory tested for non DFS channels, but now you enable them for passive.
>>
>> That's a good point.
>>
>> > This means that yes, you are save and not violate DFS rules because you are in passive mode. However, you are in complete violation if the STA finds an AP on that DFS channel and then connects and transmits as this STA is not allow to transmit on that channel since it is not approved.
>
> I was thinking about this some more. I still don't understand why it
> makes sense to omit these frequencies from the world domain. Isn't the
> point of geographic domains to communicate the rules for wherever the
> user happens to be at the time?

Yes

> Does the core regulatory support really
> ever know which frequencies the hardware has ben approved for, even
> among those it already allows?

It depends, some drivers are hacks, some drivers are vendor supported.
For those driver with vendor support yes, you do know what the
hardware should have been approved for. For reversed engineers
drivers, no.

Problem with using frequencies a card was not properly tested with is
that those frequencies may not have calibrated data for it on the
actual card, this may take the card out of compliance.

> It seems to me that it's the job of the driver to communicate
> hardware-specific regulatory hints.

It is!

> So _if_ passive scanning of the DFS
> frequencies is allowed worldwide (I emphasize the if because I don't
> know whether or not that's true), why should the world domain not allow
> this?

This is what I am in agreement with but you are missing that some
cards do not have programmed certain frequencies on them certain
calibration information. For DFS -- its a pain, and DFS is one of the
areas where regulatory bodies tend to be more proactive on enforcing
so the better thing to do is to avoid these at all costs -- unless the
driver knows it can certainly use them.

Fortunately today we get proper vendor support for all 802.11 drivers
now on Linux so moving forward this is not an issue and I rather have
safer and cautious code in place than not, specially for DFS.

Luis

2012-03-21 18:17:56

by Luis R. Rodriguez

[permalink] [raw]
Subject: Re: Problems with regulatory domain support and BCM43224

Adding Michael and David just for their information. I know Henry
is not with Broadcom any more but hey, hey may be interested.

On Wed, Mar 21, 2012 at 06:51:16PM +0100, Arend van Spriel wrote:
> On 03/21/2012 03:19 PM, Seth Forshee wrote:
> >On Wed, Mar 21, 2012 at 12:05:40PM +0100, Arend van Spriel wrote:
> >>On 03/20/2012 11:07 PM, Seth Forshee wrote:
> >>>On Thu, Mar 08, 2012 at 01:06:57PM -0800, Luis R. Rodriguez wrote:
> >>>>>Hi, Seth
> >>>>>
> >>>>>Noticed your email yesterday, but did not get to chime into the
> >>>>>conversation. brcmsmac does indeed provide a regulatory hint, which is
> >>>>>either from SPROM or hard-coded to "US". Since "X0" is not a known
> >>>>>regulatory domain for crda it does not make sense to pass it as a regulatory
> >>>>>hint. However, the "full" story is told on linuxwireless.org (see [1]).
> >>>>
> >>>>The Linux kernel allows you to define custom regulatory domains, the
> >>>>ath module uses these, it defines 13 of them. You can review that code
> >>>>for an example of how to use them. So your X0 can still be used, you
> >>>>just have to define the data structure.
> >>>
> >>>I took a shot at implementing custom regulatory domain support for
> >>>brcmsmac. I've got it working to the point of letting me see APs on the
> >>>DFS channels at least. The patch is below. A number of issues
> >>>undoubtedly remain to be resolved. Some that I can think of:
> >>
> >>Hi Seth,
> >>
> >>Thanks for looking into this. I also did some tinkering over here,
> >>but not sure which way to go here, ie. 1) define and use custom
> >>regulatory domains, or 2) be happy with world regulatory domain as
> >>is and do not pass the custom codes if found in sprom.
> >
> >For 2 I think you also have to set WIPGHY_FLAG_CUSTOM_REGULATORY or else
> >the default world domain will still be applied. That certainly seems to
> >be the quick-and-easy fix, but I'm not sure about what's preferable.
> >
> >However, I do think that passing up the custom codes as hints doesn't
> >make sense, and the patch I sent only passes it up if it's not known to
> >be one of the custom domains.
>
> Ok. so the wiphy_apply_custom_regulatory() does not make the custom
> domains known by their code (.alpha2).
>
> >>> - I set up two custom domains, X0 and X2, which are identical. I'm not
> >>> sure precisely how each needs to be set up, but I took a reasonable
> >>> guess.
> >>
> >>There are 9 custom domains in the proprietary driver. X0 only allows
> >>using channels 1-11. X2 allows 1-13. There are other parameters like
> >>rates and txpower that may differ.
> >
> >That's the kind if information I would need to make this patch viable.
> >I'll go ahead and update the patch to remove channels 12-13 from X0, and
> >14 from both. Are the 5 GHz rules correct?
>
> 5G channels are all considered passive by brcmsmac. Not sure whether
> that should be made explicit in the rules. Also the driver does not
> support IBSS so those flags are redundant now, but it is good to
> have it already in place.
>
> >Are the custom domains named X[0-8]? If that's the case I can simplify
> >some of the code.
>
> Unfortunately, no.
>
> >>> - I tried to integrate with the existing X2 domain support, but this
> >>> could probably be improved. I avoided making large changes because
> >>> there's some complexity in the current code that doesn't seem to
> >>> serve a purpose currently, but I assume it's there for a reason.
> >>
> >>The code in channel.c was taken from our proprietary driver.
> >>Basically, the LOCALES hold the same information as the rules in
> >>regdomain.
> >
> >I assumed as much, but I haven't made much of an effort to understand it
> >yet.
> >
> >But the complexity I'm referring to is really the infrastructure to
> >support multiple locales and revisions that just isn't used right now. I
> >can only assume that there are plans to use additional locales and
> >revisions at some point.
>
> Understood. The proprietary driver (which is not a mac80211 driver)
> supports a lot of locales, which are selected on country code and
> regulatory revision (both read from sprom). I suspect this is done
> to support the regulatory rules for which the device was certified.
> Revisiting channel.c is on our work list, but it would mean more
> moving toward using the regdomain approach you started on instead of
> locales.

Let me first explain a little on how Atheros' regulatory mapping works, hope
this helps you.

If companies have a map of a regdomain to an alpha2 then the country alpha2
approach makes sense. For Atheros it just so happens that some EEPROM codes map
to a direct alpha2, which is a direct map. In other cases we have an EEPROM
code map to a region, but such region allows usage of a card in set of
different countries -- these countries all happen to have the same regulatory
domain, which is why for these regions we just ask for the first alphabetical
alpha2. Regardless of the country in the region the regulatory domain in CRDA
is expected to be the same. Then we have 12 custom world regulatory domains
which are exactly for that -- world roaming. In these cases we have 12 custom
regulatory domains and disable initiating radiation on them until we know where
we are through a country IE. We also take advantage of the beacon regulatory
hints in this case. The custom regulatory domains should be used only if you
really cannot map a region code to any alpha2, but consider the case of
grouping countries together if you know the assumption was that different
countries had the same regulatory domain. This can help simoplify your
implementation. For more details please read:

http://wireless.kernel.org/en/users/Drivers/ath#Regulatory
http://wireless.kernel.org/en/developers/Regulatory/processing_rules

One idea that occcurs to me to help simplify this even further is --
for us to consider mapping a region to a set of different alpha2s, then
send a custom regdomain building request to userspace based on these
group of alpha2s, userpace could respond with an intersection of the
alpha2s. CRDA already implements the capability to intersect regulatory
domains, so the code is already there, we'd just need the hooks for
the kernel if this is deemed desirable. This is just and idea and
worth considering for the revamp of regulatory code.

More and more I see things like this getting complicated by the
years, perhaps its a good time to review the possibility of getting
together and sticking to something simple for the better or simplicity.
I realize that the difficulty lies here in supporting other OSes, which
is why we have worked hard at ensuring we permissively license all
regulatory code and recently we even relicensed cfg80211's reg.c
and other regulatory components. To help with this even further I
have also started a userspace regulatory simulator [0] complete permissively
licensed which allows us to simulate and engineer regulatory solutions
completley in userspace and if we are happy later adapt the code to
kernelspace / firmware / proprietary software / whatever.

So -- please consider all these things when implmenting your solution
on the Broadcom driver. Keep in mind the ways to improve regulatory
and current work and design considreations.

[0] git://github.com/mcgrof/regsim.git

Luis

2012-03-08 22:30:26

by Seth Forshee

[permalink] [raw]
Subject: Re: Problems with regulatory domain support and BCM43224

On Thu, Mar 08, 2012 at 02:12:46PM -0800, Luis R. Rodriguez wrote:
> On Thu, Mar 8, 2012 at 1:59 PM, Seth Forshee <[email protected]> wrote:
> > On Thu, Mar 08, 2012 at 11:51:03AM -0800, Luis R. Rodriguez wrote:
> >> On Thu, Mar 8, 2012 at 11:45 AM, Quan, David <[email protected]> wrote:
> >> > I think there is to it more than SW.
> >> > Where ever you get this card, is the card tested and regulatory approved for those countries, DFS or not?
> >>
> >> Seth, what driver are you using? I know you are using a BCM43224 card.
> >>
> >> > It is possible that this card is only regulatory tested for non DFS channels, but now you enable them for passive.
> >>
> >> That's a good point.
> >>
> >> > This means that yes, you are save and not violate DFS rules because you are in passive mode. However, you are in complete violation if the STA finds an AP on that DFS channel and then connects and transmits as this STA is not allow to transmit on that channel since it is not approved.
> >
> > I was thinking about this some more. I still don't understand why it
> > makes sense to omit these frequencies from the world domain. Isn't the
> > point of geographic domains to communicate the rules for wherever the
> > user happens to be at the time?
>
> Yes
>
> > Does the core regulatory support really
> > ever know which frequencies the hardware has ben approved for, even
> > among those it already allows?
>
> It depends, some drivers are hacks, some drivers are vendor supported.
> For those driver with vendor support yes, you do know what the
> hardware should have been approved for. For reversed engineers
> drivers, no.
>
> Problem with using frequencies a card was not properly tested with is
> that those frequencies may not have calibrated data for it on the
> actual card, this may take the card out of compliance.
>
> > It seems to me that it's the job of the driver to communicate
> > hardware-specific regulatory hints.
>
> It is!
>
> > So _if_ passive scanning of the DFS
> > frequencies is allowed worldwide (I emphasize the if because I don't
> > know whether or not that's true), why should the world domain not allow
> > this?
>
> This is what I am in agreement with but you are missing that some
> cards do not have programmed certain frequencies on them certain
> calibration information. For DFS -- its a pain, and DFS is one of the
> areas where regulatory bodies tend to be more proactive on enforcing
> so the better thing to do is to avoid these at all costs -- unless the
> driver knows it can certainly use them.
>
> Fortunately today we get proper vendor support for all 802.11 drivers
> now on Linux so moving forward this is not an issue and I rather have
> safer and cautious code in place than not, specially for DFS.

Okay, taking all that information into account it does seem pragmatic to
leave the DFS channels out of the world domain. Thanks for taking the
time to explain it all to me!

Seth

>
> Luis

2012-03-08 21:01:18

by Arend van Spriel

[permalink] [raw]
Subject: Re: Problems with regulatory domain support and BCM43224

On 03/08/2012 09:07 PM, Seth Forshee wrote:
> On Thu, Mar 08, 2012 at 11:51:03AM -0800, Luis R. Rodriguez wrote:
>> On Thu, Mar 8, 2012 at 11:45 AM, Quan, David<[email protected]> wrote:
>>> I think there is to it more than SW.
>>> Where ever you get this card, is the card tested and regulatory approved for those countries, DFS or not?
>>
>> Seth, what driver are you using? I know you are using a BCM43224 card.
>
> brcmsmac
>
>>> It is possible that this card is only regulatory tested for non DFS channels, but now you enable them for passive.
>>
>> That's a good point.
>>
>>> This means that yes, you are save and not violate DFS rules because you are in passive mode. However, you are in complete violation if the STA finds an AP on that DFS channel and then connects and transmits as this STA is not allow to transmit on that channel since it is not approved.
>>
>> If the driver being used is a supported vendor driver then I'll punt
>> this to the vendor (Broadcom). If this is the reversed engineered
>> driver (b43) that Broadcom to this day seems to blindly ignore even
>> for regulatory, then I'm happy to recommend based on your input to
>> leave the regulatory domain as-is given that we cannot guarantee what
>> the vendor meant as they have not done any work on releasing either
>> documentation or code to help with their regulatory situation.
>
> It would be nice if Broadcom could weigh in. Cc-ing Arend.

Hi, Seth

Noticed your email yesterday, but did not get to chime into the
conversation. brcmsmac does indeed provide a regulatory hint, which is
either from SPROM or hard-coded to "US". Since "X0" is not a known
regulatory domain for crda it does not make sense to pass it as a
regulatory hint. However, the "full" story is told on linuxwireless.org
(see [1]).

Gr. AvS

[1] http://linuxwireless.org/en/users/Drivers/brcm80211


2012-03-21 17:51:32

by Arend van Spriel

[permalink] [raw]
Subject: Re: Problems with regulatory domain support and BCM43224

On 03/21/2012 03:19 PM, Seth Forshee wrote:
> On Wed, Mar 21, 2012 at 12:05:40PM +0100, Arend van Spriel wrote:
>> On 03/20/2012 11:07 PM, Seth Forshee wrote:
>>> On Thu, Mar 08, 2012 at 01:06:57PM -0800, Luis R. Rodriguez wrote:
>>>>> Hi, Seth
>>>>>
>>>>> Noticed your email yesterday, but did not get to chime into the
>>>>> conversation. brcmsmac does indeed provide a regulatory hint, which is
>>>>> either from SPROM or hard-coded to "US". Since "X0" is not a known
>>>>> regulatory domain for crda it does not make sense to pass it as a regulatory
>>>>> hint. However, the "full" story is told on linuxwireless.org (see [1]).
>>>>
>>>> The Linux kernel allows you to define custom regulatory domains, the
>>>> ath module uses these, it defines 13 of them. You can review that code
>>>> for an example of how to use them. So your X0 can still be used, you
>>>> just have to define the data structure.
>>>
>>> I took a shot at implementing custom regulatory domain support for
>>> brcmsmac. I've got it working to the point of letting me see APs on the
>>> DFS channels at least. The patch is below. A number of issues
>>> undoubtedly remain to be resolved. Some that I can think of:
>>
>> Hi Seth,
>>
>> Thanks for looking into this. I also did some tinkering over here,
>> but not sure which way to go here, ie. 1) define and use custom
>> regulatory domains, or 2) be happy with world regulatory domain as
>> is and do not pass the custom codes if found in sprom.
>
> For 2 I think you also have to set WIPGHY_FLAG_CUSTOM_REGULATORY or else
> the default world domain will still be applied. That certainly seems to
> be the quick-and-easy fix, but I'm not sure about what's preferable.
>
> However, I do think that passing up the custom codes as hints doesn't
> make sense, and the patch I sent only passes it up if it's not known to
> be one of the custom domains.

Ok. so the wiphy_apply_custom_regulatory() does not make the custom
domains known by their code (.alpha2).

>>> - I set up two custom domains, X0 and X2, which are identical. I'm not
>>> sure precisely how each needs to be set up, but I took a reasonable
>>> guess.
>>
>> There are 9 custom domains in the proprietary driver. X0 only allows
>> using channels 1-11. X2 allows 1-13. There are other parameters like
>> rates and txpower that may differ.
>
> That's the kind if information I would need to make this patch viable.
> I'll go ahead and update the patch to remove channels 12-13 from X0, and
> 14 from both. Are the 5 GHz rules correct?

5G channels are all considered passive by brcmsmac. Not sure whether
that should be made explicit in the rules. Also the driver does not
support IBSS so those flags are redundant now, but it is good to have it
already in place.

> Are the custom domains named X[0-8]? If that's the case I can simplify
> some of the code.

Unfortunately, no.

>>> - I tried to integrate with the existing X2 domain support, but this
>>> could probably be improved. I avoided making large changes because
>>> there's some complexity in the current code that doesn't seem to
>>> serve a purpose currently, but I assume it's there for a reason.
>>
>> The code in channel.c was taken from our proprietary driver.
>> Basically, the LOCALES hold the same information as the rules in
>> regdomain.
>
> I assumed as much, but I haven't made much of an effort to understand it
> yet.
>
> But the complexity I'm referring to is really the infrastructure to
> support multiple locales and revisions that just isn't used right now. I
> can only assume that there are plans to use additional locales and
> revisions at some point.

Understood. The proprietary driver (which is not a mac80211 driver)
supports a lot of locales, which are selected on country code and
regulatory revision (both read from sprom). I suspect this is done to
support the regulatory rules for which the device was certified.
Revisiting channel.c is on our work list, but it would mean more moving
toward using the regdomain approach you started on instead of locales.

>>> - The flow of the initialization and organization of the code make it
>>> necessary to search through the list of custom regulatory domains
>>> many times. It would be nice to improve upon this.
>>>
>>> Does this look to be on the right track?
>>>
>>
>> Looks good. I will see if I can map the LOCALES for these to
>> regdomain rules.
>
> Great! Thanks for you comments.
>
> Seth
>

Gr. AvS


2012-03-08 20:07:39

by Seth Forshee

[permalink] [raw]
Subject: Re: Problems with regulatory domain support and BCM43224

On Thu, Mar 08, 2012 at 11:51:03AM -0800, Luis R. Rodriguez wrote:
> On Thu, Mar 8, 2012 at 11:45 AM, Quan, David <[email protected]> wrote:
> > I think there is to it more than SW.
> > Where ever you get this card, is the card tested and regulatory approved for those countries, DFS or not?
>
> Seth, what driver are you using? I know you are using a BCM43224 card.

brcmsmac

> > It is possible that this card is only regulatory tested for non DFS channels, but now you enable them for passive.
>
> That's a good point.
>
> > This means that yes, you are save and not violate DFS rules because you are in passive mode. However, you are in complete violation if the STA finds an AP on that DFS channel and then connects and transmits as this STA is not allow to transmit on that channel since it is not approved.
>
> If the driver being used is a supported vendor driver then I'll punt
> this to the vendor (Broadcom). If this is the reversed engineered
> driver (b43) that Broadcom to this day seems to blindly ignore even
> for regulatory, then I'm happy to recommend based on your input to
> leave the regulatory domain as-is given that we cannot guarantee what
> the vendor meant as they have not done any work on releasing either
> documentation or code to help with their regulatory situation.

It would be nice if Broadcom could weigh in. Cc-ing Arend.

This is actually a special case. This is an Apple machine, and it's not
that there's no regulatory hint in the ROM, it's that the hint is the
bogus country code "X0". From reading online, Apple uses this to
indicate the regulatory domain is unknown, and it uses the first
regulatory hint it sees in a country IE. I can connect to DFS channels
using MacOS on the machine, so I'll assume it was approved for DFS
channels.

Since Linux (afaict) only uses hits from country IEs for APs it's
connected to, much of the time this card ends up using the world domain
and is unable to scan DFS channels.

Thanks,
Seth


2012-03-21 11:05:58

by Arend van Spriel

[permalink] [raw]
Subject: Re: Problems with regulatory domain support and BCM43224

On 03/20/2012 11:07 PM, Seth Forshee wrote:
> On Thu, Mar 08, 2012 at 01:06:57PM -0800, Luis R. Rodriguez wrote:
>>> Hi, Seth
>>>
>>> Noticed your email yesterday, but did not get to chime into the
>>> conversation. brcmsmac does indeed provide a regulatory hint, which is
>>> either from SPROM or hard-coded to "US". Since "X0" is not a known
>>> regulatory domain for crda it does not make sense to pass it as a regulatory
>>> hint. However, the "full" story is told on linuxwireless.org (see [1]).
>>
>> The Linux kernel allows you to define custom regulatory domains, the
>> ath module uses these, it defines 13 of them. You can review that code
>> for an example of how to use them. So your X0 can still be used, you
>> just have to define the data structure.
>
> I took a shot at implementing custom regulatory domain support for
> brcmsmac. I've got it working to the point of letting me see APs on the
> DFS channels at least. The patch is below. A number of issues
> undoubtedly remain to be resolved. Some that I can think of:

Hi Seth,

Thanks for looking into this. I also did some tinkering over here, but
not sure which way to go here, ie. 1) define and use custom regulatory
domains, or 2) be happy with world regulatory domain as is and do not
pass the custom codes if found in sprom.

> - I set up two custom domains, X0 and X2, which are identical. I'm not
> sure precisely how each needs to be set up, but I took a reasonable
> guess.

There are 9 custom domains in the proprietary driver. X0 only allows
using channels 1-11. X2 allows 1-13. There are other parameters like
rates and txpower that may differ.

> - I tried to integrate with the existing X2 domain support, but this
> could probably be improved. I avoided making large changes because
> there's some complexity in the current code that doesn't seem to
> serve a purpose currently, but I assume it's there for a reason.

The code in channel.c was taken from our proprietary driver. Basically,
the LOCALES hold the same information as the rules in regdomain.

> - The flow of the initialization and organization of the code make it
> necessary to search through the list of custom regulatory domains
> many times. It would be nice to improve upon this.
>
> Does this look to be on the right track?
>

Looks good. I will see if I can map the LOCALES for these to regdomain
rules.

Gr. AvS


2012-03-21 19:37:12

by Seth Forshee

[permalink] [raw]
Subject: Re: Problems with regulatory domain support and BCM43224

On Wed, Mar 21, 2012 at 11:17:53AM -0700, Luis R. Rodriguez wrote:
> Adding Michael and David just for their information. I know Henry
> is not with Broadcom any more but hey, hey may be interested.
>
> On Wed, Mar 21, 2012 at 06:51:16PM +0100, Arend van Spriel wrote:
> > On 03/21/2012 03:19 PM, Seth Forshee wrote:
> > >On Wed, Mar 21, 2012 at 12:05:40PM +0100, Arend van Spriel wrote:
> > >>On 03/20/2012 11:07 PM, Seth Forshee wrote:
> > >>>On Thu, Mar 08, 2012 at 01:06:57PM -0800, Luis R. Rodriguez wrote:
> > >>>>>Hi, Seth
> > >>>>>
> > >>>>>Noticed your email yesterday, but did not get to chime into the
> > >>>>>conversation. brcmsmac does indeed provide a regulatory hint, which is
> > >>>>>either from SPROM or hard-coded to "US". Since "X0" is not a known
> > >>>>>regulatory domain for crda it does not make sense to pass it as a regulatory
> > >>>>>hint. However, the "full" story is told on linuxwireless.org (see [1]).
> > >>>>
> > >>>>The Linux kernel allows you to define custom regulatory domains, the
> > >>>>ath module uses these, it defines 13 of them. You can review that code
> > >>>>for an example of how to use them. So your X0 can still be used, you
> > >>>>just have to define the data structure.
> > >>>
> > >>>I took a shot at implementing custom regulatory domain support for
> > >>>brcmsmac. I've got it working to the point of letting me see APs on the
> > >>>DFS channels at least. The patch is below. A number of issues
> > >>>undoubtedly remain to be resolved. Some that I can think of:
> > >>
> > >>Hi Seth,
> > >>
> > >>Thanks for looking into this. I also did some tinkering over here,
> > >>but not sure which way to go here, ie. 1) define and use custom
> > >>regulatory domains, or 2) be happy with world regulatory domain as
> > >>is and do not pass the custom codes if found in sprom.
> > >
> > >For 2 I think you also have to set WIPGHY_FLAG_CUSTOM_REGULATORY or else
> > >the default world domain will still be applied. That certainly seems to
> > >be the quick-and-easy fix, but I'm not sure about what's preferable.
> > >
> > >However, I do think that passing up the custom codes as hints doesn't
> > >make sense, and the patch I sent only passes it up if it's not known to
> > >be one of the custom domains.
> >
> > Ok. so the wiphy_apply_custom_regulatory() does not make the custom
> > domains known by their code (.alpha2).
> >
> > >>> - I set up two custom domains, X0 and X2, which are identical. I'm not
> > >>> sure precisely how each needs to be set up, but I took a reasonable
> > >>> guess.
> > >>
> > >>There are 9 custom domains in the proprietary driver. X0 only allows
> > >>using channels 1-11. X2 allows 1-13. There are other parameters like
> > >>rates and txpower that may differ.
> > >
> > >That's the kind if information I would need to make this patch viable.
> > >I'll go ahead and update the patch to remove channels 12-13 from X0, and
> > >14 from both. Are the 5 GHz rules correct?
> >
> > 5G channels are all considered passive by brcmsmac. Not sure whether
> > that should be made explicit in the rules. Also the driver does not
> > support IBSS so those flags are redundant now, but it is good to
> > have it already in place.
> >
> > >Are the custom domains named X[0-8]? If that's the case I can simplify
> > >some of the code.
> >
> > Unfortunately, no.
> >
> > >>> - I tried to integrate with the existing X2 domain support, but this
> > >>> could probably be improved. I avoided making large changes because
> > >>> there's some complexity in the current code that doesn't seem to
> > >>> serve a purpose currently, but I assume it's there for a reason.
> > >>
> > >>The code in channel.c was taken from our proprietary driver.
> > >>Basically, the LOCALES hold the same information as the rules in
> > >>regdomain.
> > >
> > >I assumed as much, but I haven't made much of an effort to understand it
> > >yet.
> > >
> > >But the complexity I'm referring to is really the infrastructure to
> > >support multiple locales and revisions that just isn't used right now. I
> > >can only assume that there are plans to use additional locales and
> > >revisions at some point.
> >
> > Understood. The proprietary driver (which is not a mac80211 driver)
> > supports a lot of locales, which are selected on country code and
> > regulatory revision (both read from sprom). I suspect this is done
> > to support the regulatory rules for which the device was certified.
> > Revisiting channel.c is on our work list, but it would mean more
> > moving toward using the regdomain approach you started on instead of
> > locales.
>
> Let me first explain a little on how Atheros' regulatory mapping works, hope
> this helps you.
>
> If companies have a map of a regdomain to an alpha2 then the country alpha2
> approach makes sense. For Atheros it just so happens that some EEPROM codes map
> to a direct alpha2, which is a direct map. In other cases we have an EEPROM
> code map to a region, but such region allows usage of a card in set of
> different countries -- these countries all happen to have the same regulatory
> domain, which is why for these regions we just ask for the first alphabetical
> alpha2. Regardless of the country in the region the regulatory domain in CRDA
> is expected to be the same. Then we have 12 custom world regulatory domains
> which are exactly for that -- world roaming. In these cases we have 12 custom
> regulatory domains and disable initiating radiation on them until we know where
> we are through a country IE. We also take advantage of the beacon regulatory
> hints in this case. The custom regulatory domains should be used only if you
> really cannot map a region code to any alpha2, but consider the case of
> grouping countries together if you know the assumption was that different
> countries had the same regulatory domain. This can help simoplify your
> implementation. For more details please read:
>
> http://wireless.kernel.org/en/users/Drivers/ath#Regulatory
> http://wireless.kernel.org/en/developers/Regulatory/processing_rules
>
> One idea that occcurs to me to help simplify this even further is --
> for us to consider mapping a region to a set of different alpha2s, then
> send a custom regdomain building request to userspace based on these
> group of alpha2s, userpace could respond with an intersection of the
> alpha2s. CRDA already implements the capability to intersect regulatory
> domains, so the code is already there, we'd just need the hooks for
> the kernel if this is deemed desirable. This is just and idea and
> worth considering for the revamp of regulatory code.
>
> More and more I see things like this getting complicated by the
> years, perhaps its a good time to review the possibility of getting
> together and sticking to something simple for the better or simplicity.
> I realize that the difficulty lies here in supporting other OSes, which
> is why we have worked hard at ensuring we permissively license all
> regulatory code and recently we even relicensed cfg80211's reg.c
> and other regulatory components. To help with this even further I
> have also started a userspace regulatory simulator [0] complete permissively
> licensed which allows us to simulate and engineer regulatory solutions
> completley in userspace and if we are happy later adapt the code to
> kernelspace / firmware / proprietary software / whatever.
>
> So -- please consider all these things when implmenting your solution
> on the Broadcom driver. Keep in mind the ways to improve regulatory
> and current work and design considreations.
>
> [0] git://github.com/mcgrof/regsim.git

Great information, Luis. Thanks so much.

Arend, in order to proceed it looks like what we need to know is what
the custom domains represent, i.e. whether they map to a specific
country or set of countries, etc. From what you've said so far it looks
like X0 may map to US while X2 is more of a world roaming domain, but
again I'm just guessing.

Seth


2012-03-08 19:07:44

by Quan, David

[permalink] [raw]
Subject: RE: Problems with regulatory domain support and BCM43224

MSkgRGVwZW5kaW5nIG9uIHdoaWNoIFdXIHNrdSBudW1iZXIgeW91IHNlbGVjdGVkLCBpdCBtYXkg
YW5kIG1heSBub3Qgc3VwcG9ydCB0aGUgREZTIGNoYW5uZWxzLiBTbyB0aGlzIGlzIG5vdCB0cnVl
IHRoYXQgd2UgZG8gbm90IHN1cHBvcnQgREZTIGNoYW5uZWxzIGluIFdXIG1vZGUuDQoyKSBUb2Rh
eSwgSSBkbyBub3QgYmVsaWV2ZSBhdGg5ayBjb2RlIHN1cHBvcnRzIERGUyBkZXRlY3Rpb24uIElm
IHRoYXQgaXMgd2hhdCB5b3UgbWVhbi4gVGhlcmVmb3JlIFNUQSBtb2RlIHdpbGwgbm90IHN1cHBv
cnQgREZTIGRldGVjdGlvbi4gSG93ZXZlciwgU1RBIGRvZXMgc3VwcG9ydCBERlMgY2hhbm5lbHMu
IERGUyBjaGFubmVsIHN1cHBvcnQgdnMgREZTIGRldGVjdGlvbiBzdXBwb3J0IGlzIHR3byBkaWZm
ZXJlbnQgdGhpbmdzLiBERlMgY2hhbm5lbCBzdXBwb3J0IGFzIGEgc2xhdmUgZGV2aWNlLCBvbmx5
IGhhcyB0byBkbyBwYXNzaXZlIHNjYW5uaW5nLg0KDQpMZXQgbWUga25vdyBpZiB0aGF0IGFuc3dl
cnMgeW91ciBxdWVzdGlvbnMuDQpEYXZpZA0KDQoNCi0tLS0tT3JpZ2luYWwgTWVzc2FnZS0tLS0t
DQpGcm9tOiBtY2dyb2ZAZ21haWwuY29tIFttYWlsdG86bWNncm9mQGdtYWlsLmNvbV0gT24gQmVo
YWxmIE9mIEx1aXMgUi4gUm9kcmlndWV6DQpTZW50OiBUaHVyc2RheSwgTWFyY2ggMDgsIDIwMTIg
MTA6NTMgQU0NClRvOiBTZXRoIEZvcnNoZWU7IFF1YW4sIERhdmlkOyBHcmVlbiwgTWljaGFlbA0K
Q2M6IGxpbnV4LXdpcmVsZXNzQHZnZXIua2VybmVsLm9yZzsgSm9oYW5uZXMgQmVyZw0KU3ViamVj
dDogUmU6IFByb2JsZW1zIHdpdGggcmVndWxhdG9yeSBkb21haW4gc3VwcG9ydCBhbmQgQkNNNDMy
MjQNCg0KRGF2aWQsIE1pY2hhZWwsDQoNCmJlbG93IGlzIGEgdGhyZWFkIG9uIHdvcmxkIHJlZ3Vs
YXRvcnkgZG9tYWlucyBhbmQgREZTLiBUaGlzIGlzIGEgcHVibGljIHRocmVhZCBzbyByZXBseWlu
ZyB0byB0aGlzIGlzIHB1YmxpYy4gVGhlIHF1ZXN0aW9uIGlzIHNpbXBsZToNCndoeSBub3QgYWRk
IERGUyBjaGFubmVscyB0byB0aGUgd29ybGQgcmVndWxhdG9yeSBkb21haW4gcHJvdmlkZWQgdGhh
dA0KMSkgd2Ugb25seSBwYXNzaXZlIHNjYW4gb24gdGhlbSAyKSBTVEEgZG9lcyBzdXBwb3J0IERG
UyBzdXBwb3J0LiBJdCBzZWVtcyBsb2dpY2FsIHRvIG1lIG5vdyB0aGF0IHRoaXMgc2hvdWxkIGJl
IGVuYWJsZWQsIGJ1dCBJIGNhbid0IHJlY2FsbCBpZiBwZXJoYXBzIEkgYW0gZm9yZ2V0dGluZyBz
b21ldGhpbmcuDQoNClRoZSBiZWFjb24gaGludCBjb2RlIHdlIGhhdmUsIHdoaWNoIGVuYWJsZXMg
cmFkaWF0aW9uIHVwb24gZmluZGluZyBhIGJlYWNvbiBmcm9tIGFuIEFQIG9uIGEgNSBHSHogY2hh
bm5lbCBvbmx5IGRvZXMgYmVhY29uIGhpbnRzIGZvciBub24tREZTIGNoYW5uZWxzLCBzbyBhIGRl
dmljZSB1c2luZyB0aGUgd29ybGQgcmVndWxhdG9yeSBkb21haW4gaXMgZ3VhcmFudGVlZCB0byBu
b3QgaW5pdGlhdGUgcmFkaWF0aW9uIG9uIHRoZXNlIGNoYW5uZWxzLg0KDQoNClNldGgsIG15IHJl
c3BvbnNlIHRvIHlvdSBiZWxvdy4NCg0KT24gVGh1LCBNYXIgOCwgMjAxMiBhdCA5OjQxIEFNLCBT
ZXRoIEZvcnNoZWUgPHNldGguZm9yc2hlZUBjYW5vbmljYWwuY29tPiB3cm90ZToNCj4gQXMgSSB1
bmRlcnN0YW5kIGl0LCB0aGUgREZTIGNoYW5uZWxzIGFyZW4ndCBpbmNsdWRlZCBpbiB0aGUgd29y
bGQgDQo+IGRvbWFpbiBiZWNhdXNlIExpbnV4IGRvZXMgbm90IHlldCBmdWxseSBzdXBwb3J0IERG
Uy4NCg0KQSBTVEEgZGV2aWNlIGNhbiBjb25uZWN0IHRvIGEgREZTIEFQIHdoZW4gdGhlIFNUQSBk
ZXZpY2UgZG9lcyBoYXZlIHRob3NlIERGUyBjaGFubmVscyBhcyBwYXJ0IG9mIGl0cyB3b3JsZCBy
ZWd1bGF0b3J5IGRvbWFpbiwgYnV0IHRoZSBTVEEgd2lsbCBwYXNzaXZlbHkgc2NhbiBvbiB0aG9z
ZSBjaGFubmVscyBnaXZlbiB0aGF0IHNlbmRpbmcgYSBwcm9iZSByZXF1ZXN0IGlzIGFjdGl2ZSBy
YWRpYXRpb24gYW5kIGFjdGl2ZSByYWRpYXRpb24gcmVxdWlyZXMgYSBiaXQgb2YgY29kZSB3aGlj
aCBpcyBub3QgeWV0IGNvbXBsZXRlIGFuZCBvbmx5IHVzZWQgYXMgYSBBUC4gWW91IGFyZSByaWdo
dCB0aG91Z2ggdGhhdCB0aGUgTGludXggcmVndWxhdG9yeSBjb2RlIHRob3VnaCBkb2VzIG5vdCBp
bmNsdWRlIGFueSBERlMgY2hhbm5lbHMgaW4gdGhlIHdvcmxkIHJlZ3VsYXRvcnkgZG9tYWluLiBU
aGUgd29ybGQgcmVndWxhdG9yeSBkb21haW4gaXMgdGhlIG1hdGhlbWF0aWNhbCBpbnRlcnNlY3Rp
b24gb2YgYWxsIHRoZSByZWd1bGF0b3J5IGRvbWFpbnMgaW4gdGhlIHdvcmxkIChzZWUgaW50ZXJz
ZWN0LmMgb24gQ1JEQSkgYnV0IGEgZmV3IHNldCBvZiBjaGFubmVscyB3ZXJlIGFkZGVkIGFzIHdl
bGwgd2hpY2ggYXJlIG5vdCBERlMgd2l0aCB0aGUgY29uZGl0aW9uIHRoYXQgd2UgZG8gcGFzc2l2
ZSBzY2Fucy4NCldlIGRpZCByZW1vdmUgdGhlIERGUyBjaGFubmVscyBjb21wbGV0ZWx5Lg0KDQo+
IEJ1dCBJIGNhbiB0aGVuIHNwZWNpZnkgYQ0KPiBkb21haW4gdGhhdCdzIGtub3duIHRvIHJlcXVp
cmUgREZTIG9uIHRoZXNlIGNoYW5uZWxzLCBhbmQgdGhleSBhcmUgDQo+IGVuYWJsZWQuIFRoaXMg
c2VlbXMgaWxsb2dpY2FsLiBJZiBwYXNzaXZlIHNjYW5uaW5nIGlzIG9rYXkgd2hlbiB3ZSANCj4g
a25vdyBERlMgaXMgcmVxdWlyZWQsIHdoeSBjYW4ndCBpdCBiZSBlbmFibGVkIGluIHRoZSB3b3Js
ZCBkb21haW4gd2hlbiANCj4gd2Ugc2ltcGx5IGRvbid0IGtub3cgaWYgaXQncyByZXF1aXJlZD8N
Cg0KSXRzIGEgZmFpciBwb2ludCBhbmQgZ2l2ZW4gdGhlIHdheSB3ZSBoYW5kbGUgYmVhY29uIGhp
bnRzIGFuZCBub3QgZW5hYmxpbmcgdGhlbSBmb3IgREZTIGNoYW5uZWxzIGF0IGFsbCwgYW5kIGlm
IHdlIG9ubHkgcGFzc2l2ZWx5IHNjYW4gZm9yIERGUyBjaGFubmVscyBJIHRoaW5rIHRoaXMgc2hv
dWxkIGJlIGdvb2QuDQoNCiAgTHVpcw0K

2012-03-26 19:36:14

by Seth Forshee

[permalink] [raw]
Subject: Re: Problems with regulatory domain support and BCM43224

On Wed, Mar 21, 2012 at 05:27:15PM -0700, Luis R. Rodriguez wrote:
> > Arend, in order to proceed it looks like what we need to know is what
> > the custom domains represent, i.e. whether they map to a specific
> > country or set of countries, etc.
>
> This is why it is crucial for vendors themselves to get involved in this
> process. Only they will truly know and completely understand what this
> all means. Since it is hard to keep track of this information it is also
> why we have documented what our EEPROM regulatory domains look like and
> what they mean / map to.
>
> http://wireless.kernel.org/en/users/Drivers/ath
>
> Something similar may be worthy for this driver. But just my own 0.02
> costarican colones.
>
> > From what you've said so far it looks
> > like X0 may map to US
>
> BTW if this is the case, you may be able to send the regulatory hint
> for "US" and then apply any thing you need on top of that after
> through the reg_notifier() callback.
>
> > while X2 is more of a world roaming domain, but again I'm just guessing.

I've been studying the existing brcmsmac regulatory code in more detail,
and I think there's a lot of potential to make the integration with the
core regulatory support much better. I'm still making my way through
some of the code, but here's what I see so far.

Once full and accurate regdomain information is provided to the core
regulatory code, all the code in channel.c that's checking against
regulatory constraints can be eliminated, as that will get done at a
higher level. I think the code to set the Tx power should also be
reworked to use the constraints from the core regdom code. At that point
the need for the custom regdom structures is mostly eliminated.

I'm going to start toying with implementing some of this this week, time
permitting. I think X2 is the only domain I have enough information on
to realistically implement. But even with that one it would be helpful
to understand what it's meant to represent, as Luis pointed out.

I have one other question as well. Does the data in channel.c generally
represent the most permissive regulatory parameters that ought to be
used? That's the assumption I'm working under right now.

Thanks,
Seth


2012-04-10 16:28:41

by Seth Forshee

[permalink] [raw]
Subject: Re: Problems with regulatory domain support and BCM43224

On Tue, Apr 03, 2012 at 09:46:32PM -0500, Seth Forshee wrote:
> Below is a diff of the changes I've made locally to the brcmsmac
> regulatory support. I haven't started thinking about dividing it up into
> more digestible chunks, so for now it's just one massive diff. I've made
> a lot of progress towards moving brcmsmac away from its custom formats
> for regulatory information, but there are a few points I'm still having
> difficulty with.

Please find an updated diff below. I've made some progress, but it still
isn't complete.

> The patch builds, and kind of works. Scanning seems to be fine; I can
> see all the APs I expect in my area, including the one on a DFS channel
> that I couldn't see previously. I can associate with my 2.4 GHz APs, but
> not the 5 GHz AP. I see timme outs waiting for probe responses, and I'm
> hitting the WARN_ON_ONCE in brcms_c_wait_for_tx_completion(). I haven't
> really debugged this yet -- I thought I'd send out the patch to collect
> comments while I debug. Suggestions of what's causing this are also
> welcome :)

This was due to always passing true for the value of mute_tx to
brcms_b_set_chanspec() on passive channels. For now I'm just always
passing false, which looks like it ought to be okay as we shouldn't have
any tx on passive channels unless beacons are seen on the channel.

> One of the major unresolved issues in the patch is what to do with the
> data in struct locale_mimo_info. The regulatory rules only hold one
> power level. I'm unsure why the brcmsmac implementation differs in this
> regard. Suggestions?

This is still one of the largest unsolved issues. I'm probably going to
need some advice on how to fill out the txpwr information when
regualtory rules external to the driver can be applied.

> The txpwr calculations are modified, both to use the regdomain data so
> far as possible and to eliminate redundant code. I'd appreciate review
> of these changes in addition to the suggestions on how to handle the
> MIMO power limits as I've already mentioned.
>
> Initialization has also changed somewhat. The piece that looks most
> significant to me is that wlc_phy_txpower_limit_set() gets called later,
> not until after the ieee80211_hw device is registered.
>
> Beyond these I still have a number of comments with my initials (SAF)
> that contain questions, comments, and TODOs. Feedback regarding these
> items, or anything else, are greatly appreciated.
>
> Looking forward to your comments.
>
> Thanks,
> Seth

diff --git a/drivers/net/wireless/brcm80211/brcmsmac/channel.c b/drivers/net/wireless/brcm80211/brcmsmac/channel.c
index 55e9f45..a31a15b 100644
--- a/drivers/net/wireless/brcm80211/brcmsmac/channel.c
+++ b/drivers/net/wireless/brcm80211/brcmsmac/channel.c
@@ -15,7 +15,10 @@
*/

#include <linux/types.h>
+#include <linux/bitops.h>
#include <net/mac80211.h>
+#include <net/cfg80211.h>
+#include <net/regulatory.h>

#include <defs.h>
#include "pub.h"
@@ -23,54 +26,49 @@
#include "main.h"
#include "stf.h"
#include "channel.h"
+#include "mac80211_if.h"
+
+/* SAF: Some of the 5G rules might be able to be combinded */
+#define BRCM_2GHZ_2412_2462 REG_RULE(2412-10, 2462+10, 40, 0, 19, 0)
+#define BRCM_2GHZ_2467_2472 REG_RULE(2467-10, 2472+10, 20, 0, 19, \
+ NL80211_RRF_PASSIVE_SCAN | \
+ NL80211_RRF_NO_IBSS)
+#define BRCM_2GHZ_2484 REG_RULE(2484-10, 2484+10, 40, 0, 19, \
+ NL80211_RRF_PASSIVE_SCAN | \
+ NL80211_RRF_NO_OFDM)
+
+#define BRCM_5GHZ_5180_5240 REG_RULE(5180-10, 5240+10, 40, 0, 21, \
+ NL80211_RRF_PASSIVE_SCAN | \
+ NL80211_RRF_NO_IBSS)
+#define BRCM_5GHZ_5260_5320 REG_RULE(5260-10, 5320+10, 40, 0, 21, \
+ NL80211_RRF_PASSIVE_SCAN | \
+ NL80211_RRF_DFS | \
+ NL80211_RRF_NO_IBSS)
+#define BRCM_5GHZ_5500_5700 REG_RULE(5500-10, 5700+10, 40, 0, 21, \
+ NL80211_RRF_PASSIVE_SCAN | \
+ NL80211_RRF_DFS | \
+ NL80211_RRF_NO_IBSS)
+#define BRCM_5GHZ_5745_5825 REG_RULE(5745-10, 5825+10, 40, 0, 21, \
+ NL80211_RRF_PASSIVE_SCAN | \
+ NL80211_RRF_NO_IBSS)
+
+static const struct ieee80211_regdomain brcms_regdom_x2 = {
+ .n_reg_rules = 7,
+ .alpha2 = "X2",
+ .reg_rules = {
+ BRCM_2GHZ_2412_2462,
+ BRCM_2GHZ_2467_2472,
+ BRCM_2GHZ_2484,
+ BRCM_5GHZ_5180_5240,
+ BRCM_5GHZ_5260_5320,
+ BRCM_5GHZ_5500_5700,
+ BRCM_5GHZ_5745_5825,
+ }
+};

/* QDB() macro takes a dB value and converts to a quarter dB value */
#define QDB(n) ((n) * BRCMS_TXPWR_DB_FACTOR)

-#define LOCALE_CHAN_01_11 (1<<0)
-#define LOCALE_CHAN_12_13 (1<<1)
-#define LOCALE_CHAN_14 (1<<2)
-#define LOCALE_SET_5G_LOW_JP1 (1<<3) /* 34-48, step 2 */
-#define LOCALE_SET_5G_LOW_JP2 (1<<4) /* 34-46, step 4 */
-#define LOCALE_SET_5G_LOW1 (1<<5) /* 36-48, step 4 */
-#define LOCALE_SET_5G_LOW2 (1<<6) /* 52 */
-#define LOCALE_SET_5G_LOW3 (1<<7) /* 56-64, step 4 */
-#define LOCALE_SET_5G_MID1 (1<<8) /* 100-116, step 4 */
-#define LOCALE_SET_5G_MID2 (1<<9) /* 120-124, step 4 */
-#define LOCALE_SET_5G_MID3 (1<<10) /* 128 */
-#define LOCALE_SET_5G_HIGH1 (1<<11) /* 132-140, step 4 */
-#define LOCALE_SET_5G_HIGH2 (1<<12) /* 149-161, step 4 */
-#define LOCALE_SET_5G_HIGH3 (1<<13) /* 165 */
-#define LOCALE_CHAN_52_140_ALL (1<<14)
-#define LOCALE_SET_5G_HIGH4 (1<<15) /* 184-216 */
-
-#define LOCALE_CHAN_36_64 (LOCALE_SET_5G_LOW1 | \
- LOCALE_SET_5G_LOW2 | \
- LOCALE_SET_5G_LOW3)
-#define LOCALE_CHAN_52_64 (LOCALE_SET_5G_LOW2 | LOCALE_SET_5G_LOW3)
-#define LOCALE_CHAN_100_124 (LOCALE_SET_5G_MID1 | LOCALE_SET_5G_MID2)
-#define LOCALE_CHAN_100_140 (LOCALE_SET_5G_MID1 | LOCALE_SET_5G_MID2 | \
- LOCALE_SET_5G_MID3 | LOCALE_SET_5G_HIGH1)
-#define LOCALE_CHAN_149_165 (LOCALE_SET_5G_HIGH2 | LOCALE_SET_5G_HIGH3)
-#define LOCALE_CHAN_184_216 LOCALE_SET_5G_HIGH4
-
-#define LOCALE_CHAN_01_14 (LOCALE_CHAN_01_11 | \
- LOCALE_CHAN_12_13 | \
- LOCALE_CHAN_14)
-
-#define LOCALE_RADAR_SET_NONE 0
-#define LOCALE_RADAR_SET_1 1
-
-#define LOCALE_RESTRICTED_NONE 0
-#define LOCALE_RESTRICTED_SET_2G_SHORT 1
-#define LOCALE_RESTRICTED_CHAN_165 2
-#define LOCALE_CHAN_ALL_5G 3
-#define LOCALE_RESTRICTED_JAPAN_LEGACY 4
-#define LOCALE_RESTRICTED_11D_2G 5
-#define LOCALE_RESTRICTED_11D_5G 6
-#define LOCALE_RESTRICTED_LOW_HI 7
-#define LOCALE_RESTRICTED_12_13_14 8
-
#define LOCALE_2G_IDX_i 0
#define LOCALE_5G_IDX_11 0
#define LOCALE_MIMO_IDX_bn 0
@@ -118,18 +116,12 @@
(((c) < 100) ? 2 : \
(((c) < 149) ? 3 : 4))))

-#define ISDFS_EU(fl) (((fl) & BRCMS_DFS_EU) == BRCMS_DFS_EU)
-
+/*
+ * SAF: This can be eliminated once we know what to do with locale_flags
+ */
struct brcms_cm_band {
/* struct locale_info flags */
u8 locale_flags;
- /* List of valid channels in the country */
- struct brcms_chanvec valid_channels;
- /* List of restricted use channels */
- const struct brcms_chanvec *restricted_channels;
- /* List of radar sensitive channels */
- const struct brcms_chanvec *radar_channels;
- u8 PAD[8];
};

/* locale per-channel tx power limits for MIMO frames
@@ -141,6 +133,8 @@ struct locale_mimo_info {
s8 maxpwr20[BRCMS_MAXPWR_MIMO_TBL_SIZE];
/* tx 40 MHz power limits, qdBm units */
s8 maxpwr40[BRCMS_MAXPWR_MIMO_TBL_SIZE];
+ /* SAF: Flags here and in locale_info are essentially unused,
+ * should be able to eliminate them with a little effort */
u8 flags;
};

@@ -152,304 +146,36 @@ struct country_info {
const u8 locale_mimo_5G; /* 5G mimo info */
};

+struct brcms_regd {
+ char abbrev[BRCM_CNTRY_BUF_SZ]; /* country abbreviation */
+ struct country_info country;
+ const struct ieee80211_regdomain *regdomain;
+};
+
struct brcms_cm_info {
struct brcms_pub *pub;
struct brcms_c_info *wlc;
+ const struct brcms_regd *world_regd;
char srom_ccode[BRCM_CNTRY_BUF_SZ]; /* Country Code in SROM */
- uint srom_regrev; /* Regulatory Rev for the SROM ccode */
- const struct country_info *country; /* current country def */
- char ccode[BRCM_CNTRY_BUF_SZ]; /* current internal Country Code */
- uint regrev; /* current Regulatory Revision */
- char country_abbrev[BRCM_CNTRY_BUF_SZ]; /* current advertised ccode */
/* per-band state (one per phy/radio) */
struct brcms_cm_band bandstate[MAXBANDS];
- /* quiet channels currently for radar sensitivity or 11h support */
- /* channels on which we cannot transmit */
- struct brcms_chanvec quiet_channels;
};

/* locale channel and power info. */
struct locale_info {
- u32 valid_channels;
- /* List of radar sensitive channels */
- u8 radar_channels;
- /* List of channels used only if APs are detected */
- u8 restricted_channels;
- /* Max tx pwr in qdBm for each sub-band */
- s8 maxpwr[BRCMS_MAXPWR_TBL_SIZE];
- /* Country IE advertised max tx pwr in dBm per sub-band */
- s8 pub_maxpwr[BAND_5G_PWR_LVLS];
+ /* SAF: We should be able to get rid of flags */
u8 flags;
};

-/* Regulatory Matrix Spreadsheet (CLM) MIMO v3.7.9 */
-
-/*
- * Some common channel sets
- */
-
-/* No channels */
-static const struct brcms_chanvec chanvec_none = {
- {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00}
-};
-
-/* All 2.4 GHz HW channels */
-static const struct brcms_chanvec chanvec_all_2G = {
- {0xfe, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00}
-};
-
-/* All 5 GHz HW channels */
-static const struct brcms_chanvec chanvec_all_5G = {
- {0x00, 0x00, 0x00, 0x00, 0x54, 0x55, 0x11, 0x11,
- 0x01, 0x00, 0x00, 0x00, 0x10, 0x11, 0x11, 0x11,
- 0x11, 0x11, 0x20, 0x22, 0x22, 0x00, 0x00, 0x11,
- 0x11, 0x11, 0x11, 0x01}
-};
-
-/*
- * Radar channel sets
- */
-
-/* Channels 52 - 64, 100 - 140 */
-static const struct brcms_chanvec radar_set1 = {
- {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x11, /* 52 - 60 */
- 0x01, 0x00, 0x00, 0x00, 0x10, 0x11, 0x11, 0x11, /* 64, 100 - 124 */
- 0x11, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 128 - 140 */
- 0x00, 0x00, 0x00, 0x00}
-};
-
-/*
- * Restricted channel sets
- */
-
-/* Channels 34, 38, 42, 46 */
-static const struct brcms_chanvec restricted_set_japan_legacy = {
- {0x00, 0x00, 0x00, 0x00, 0x44, 0x44, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00}
-};
-
-/* Channels 12, 13 */
-static const struct brcms_chanvec restricted_set_2g_short = {
- {0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00}
-};
-
-/* Channel 165 */
-static const struct brcms_chanvec restricted_chan_165 = {
- {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00}
-};
-
-/* Channels 36 - 48 & 149 - 165 */
-static const struct brcms_chanvec restricted_low_hi = {
- {0x00, 0x00, 0x00, 0x00, 0x10, 0x11, 0x01, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x20, 0x22, 0x22, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00}
-};
-
-/* Channels 12 - 14 */
-static const struct brcms_chanvec restricted_set_12_13_14 = {
- {0x00, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00}
-};
-
-/* global memory to provide working buffer for expanded locale */
-
-static const struct brcms_chanvec *g_table_radar_set[] = {
- &chanvec_none,
- &radar_set1
-};
-
-static const struct brcms_chanvec *g_table_restricted_chan[] = {
- &chanvec_none, /* restricted_set_none */
- &restricted_set_2g_short,
- &restricted_chan_165,
- &chanvec_all_5G,
- &restricted_set_japan_legacy,
- &chanvec_all_2G, /* restricted_set_11d_2G */
- &chanvec_all_5G, /* restricted_set_11d_5G */
- &restricted_low_hi,
- &restricted_set_12_13_14
-};
-
-static const struct brcms_chanvec locale_2g_01_11 = {
- {0xfe, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00}
-};
-
-static const struct brcms_chanvec locale_2g_12_13 = {
- {0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00}
-};
-
-static const struct brcms_chanvec locale_2g_14 = {
- {0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00}
-};
-
-static const struct brcms_chanvec locale_5g_LOW_JP1 = {
- {0x00, 0x00, 0x00, 0x00, 0x54, 0x55, 0x01, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00}
-};
-
-static const struct brcms_chanvec locale_5g_LOW_JP2 = {
- {0x00, 0x00, 0x00, 0x00, 0x44, 0x44, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00}
-};
-
-static const struct brcms_chanvec locale_5g_LOW1 = {
- {0x00, 0x00, 0x00, 0x00, 0x10, 0x11, 0x01, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00}
-};
-
-static const struct brcms_chanvec locale_5g_LOW2 = {
- {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00}
-};
-
-static const struct brcms_chanvec locale_5g_LOW3 = {
- {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11,
- 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00}
-};
-
-static const struct brcms_chanvec locale_5g_MID1 = {
- {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x10, 0x11, 0x11, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00}
-};
-
-static const struct brcms_chanvec locale_5g_MID2 = {
- {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00}
-};
-
-static const struct brcms_chanvec locale_5g_MID3 = {
- {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00}
-};
-
-static const struct brcms_chanvec locale_5g_HIGH1 = {
- {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x10, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00}
-};
-
-static const struct brcms_chanvec locale_5g_HIGH2 = {
- {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x20, 0x22, 0x02, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00}
-};
-
-static const struct brcms_chanvec locale_5g_HIGH3 = {
- {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00}
-};
-
-static const struct brcms_chanvec locale_5g_52_140_ALL = {
- {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x11,
- 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
- 0x11, 0x11, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00}
-};
-
-static const struct brcms_chanvec locale_5g_HIGH4 = {
- {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11,
- 0x11, 0x11, 0x11, 0x11}
-};
-
-static const struct brcms_chanvec *g_table_locale_base[] = {
- &locale_2g_01_11,
- &locale_2g_12_13,
- &locale_2g_14,
- &locale_5g_LOW_JP1,
- &locale_5g_LOW_JP2,
- &locale_5g_LOW1,
- &locale_5g_LOW2,
- &locale_5g_LOW3,
- &locale_5g_MID1,
- &locale_5g_MID2,
- &locale_5g_MID3,
- &locale_5g_HIGH1,
- &locale_5g_HIGH2,
- &locale_5g_HIGH3,
- &locale_5g_52_140_ALL,
- &locale_5g_HIGH4
-};
-
-static void brcms_c_locale_add_channels(struct brcms_chanvec *target,
- const struct brcms_chanvec *channels)
+static inline struct wiphy *brcms_c_get_wiphy(struct brcms_cm_info *wlc_cm)
{
- u8 i;
- for (i = 0; i < sizeof(struct brcms_chanvec); i++)
- target->vec[i] |= channels->vec[i];
-}
-
-static void brcms_c_locale_get_channels(const struct locale_info *locale,
- struct brcms_chanvec *channels)
-{
- u8 i;
-
- memset(channels, 0, sizeof(struct brcms_chanvec));
-
- for (i = 0; i < ARRAY_SIZE(g_table_locale_base); i++) {
- if (locale->valid_channels & (1 << i))
- brcms_c_locale_add_channels(channels,
- g_table_locale_base[i]);
- }
+ return wlc_cm->pub->ieee_hw->wiphy;
}

/*
* Locale Definitions - 2.4 GHz
*/
static const struct locale_info locale_i = { /* locale i. channel 1 - 13 */
- LOCALE_CHAN_01_11 | LOCALE_CHAN_12_13,
- LOCALE_RADAR_SET_NONE,
- LOCALE_RESTRICTED_SET_2G_SHORT,
- {QDB(19), QDB(19), QDB(19),
- QDB(19), QDB(19), QDB(19)},
- {20, 20, 20, 0},
BRCMS_EIRP
};

@@ -457,12 +183,6 @@ static const struct locale_info locale_i = { /* locale i. channel 1 - 13 */
* Locale Definitions - 5 GHz
*/
static const struct locale_info locale_11 = {
- /* locale 11. channel 36 - 48, 52 - 64, 100 - 140, 149 - 165 */
- LOCALE_CHAN_36_64 | LOCALE_CHAN_100_140 | LOCALE_CHAN_149_165,
- LOCALE_RADAR_SET_1,
- LOCALE_RESTRICTED_NONE,
- {QDB(21), QDB(21), QDB(21), QDB(21), QDB(21)},
- {23, 23, 23, 30, 30},
BRCMS_EIRP | BRCMS_DFS_EU
};

@@ -504,90 +224,34 @@ static const struct locale_mimo_info *g_mimo_5g_table[] = {
&locale_11n
};

-static const struct {
- char abbrev[BRCM_CNTRY_BUF_SZ]; /* country abbreviation */
- struct country_info country;
-} cntry_locales[] = {
+static const struct brcms_regd cntry_locales[] = {
+ /* Worldwide Row 2, must always be at index 0 */
{
- "X2", LOCALES(i, 11, bn, 11n)}, /* Worldwide RoW 2 */
+ .abbrev = "X2",
+ .country = LOCALES(i, 11, bn, 11n),
+ .regdomain = &brcms_regdom_x2,
+ },
};

-#ifdef SUPPORT_40MHZ
-/* 20MHz channel info for 40MHz pairing support */
-struct chan20_info {
- u8 sb;
- u8 adj_sbs;
-};
+static const struct brcms_regd *brcms_world_regd(const char *regdom)
+{
+ const struct brcms_regd *regd = NULL;
+ int i;

-/* indicates adjacent channels that are allowed for a 40 Mhz channel and
- * those that permitted by the HT
- */
-struct chan20_info chan20_info[] = {
- /* 11b/11g */
-/* 0 */ {1, (CH_UPPER_SB | CH_EWA_VALID)},
-/* 1 */ {2, (CH_UPPER_SB | CH_EWA_VALID)},
-/* 2 */ {3, (CH_UPPER_SB | CH_EWA_VALID)},
-/* 3 */ {4, (CH_UPPER_SB | CH_EWA_VALID)},
-/* 4 */ {5, (CH_UPPER_SB | CH_LOWER_SB | CH_EWA_VALID)},
-/* 5 */ {6, (CH_UPPER_SB | CH_LOWER_SB | CH_EWA_VALID)},
-/* 6 */ {7, (CH_UPPER_SB | CH_LOWER_SB | CH_EWA_VALID)},
-/* 7 */ {8, (CH_UPPER_SB | CH_LOWER_SB | CH_EWA_VALID)},
-/* 8 */ {9, (CH_UPPER_SB | CH_LOWER_SB | CH_EWA_VALID)},
-/* 9 */ {10, (CH_LOWER_SB | CH_EWA_VALID)},
-/* 10 */ {11, (CH_LOWER_SB | CH_EWA_VALID)},
-/* 11 */ {12, (CH_LOWER_SB)},
-/* 12 */ {13, (CH_LOWER_SB)},
-/* 13 */ {14, (CH_LOWER_SB)},
-
-/* 11a japan high */
-/* 14 */ {34, (CH_UPPER_SB)},
-/* 15 */ {38, (CH_LOWER_SB)},
-/* 16 */ {42, (CH_LOWER_SB)},
-/* 17 */ {46, (CH_LOWER_SB)},
-
-/* 11a usa low */
-/* 18 */ {36, (CH_UPPER_SB | CH_EWA_VALID)},
-/* 19 */ {40, (CH_LOWER_SB | CH_EWA_VALID)},
-/* 20 */ {44, (CH_UPPER_SB | CH_EWA_VALID)},
-/* 21 */ {48, (CH_LOWER_SB | CH_EWA_VALID)},
-/* 22 */ {52, (CH_UPPER_SB | CH_EWA_VALID)},
-/* 23 */ {56, (CH_LOWER_SB | CH_EWA_VALID)},
-/* 24 */ {60, (CH_UPPER_SB | CH_EWA_VALID)},
-/* 25 */ {64, (CH_LOWER_SB | CH_EWA_VALID)},
-
-/* 11a Europe */
-/* 26 */ {100, (CH_UPPER_SB | CH_EWA_VALID)},
-/* 27 */ {104, (CH_LOWER_SB | CH_EWA_VALID)},
-/* 28 */ {108, (CH_UPPER_SB | CH_EWA_VALID)},
-/* 29 */ {112, (CH_LOWER_SB | CH_EWA_VALID)},
-/* 30 */ {116, (CH_UPPER_SB | CH_EWA_VALID)},
-/* 31 */ {120, (CH_LOWER_SB | CH_EWA_VALID)},
-/* 32 */ {124, (CH_UPPER_SB | CH_EWA_VALID)},
-/* 33 */ {128, (CH_LOWER_SB | CH_EWA_VALID)},
-/* 34 */ {132, (CH_UPPER_SB | CH_EWA_VALID)},
-/* 35 */ {136, (CH_LOWER_SB | CH_EWA_VALID)},
-/* 36 */ {140, (CH_LOWER_SB)},
-
-/* 11a usa high, ref5 only */
-/* The 0x80 bit in pdiv means these are REF5, other entries are REF20 */
-/* 37 */ {149, (CH_UPPER_SB | CH_EWA_VALID)},
-/* 38 */ {153, (CH_LOWER_SB | CH_EWA_VALID)},
-/* 39 */ {157, (CH_UPPER_SB | CH_EWA_VALID)},
-/* 40 */ {161, (CH_LOWER_SB | CH_EWA_VALID)},
-/* 41 */ {165, (CH_LOWER_SB)},
-
-/* 11a japan */
-/* 42 */ {184, (CH_UPPER_SB)},
-/* 43 */ {188, (CH_LOWER_SB)},
-/* 44 */ {192, (CH_UPPER_SB)},
-/* 45 */ {196, (CH_LOWER_SB)},
-/* 46 */ {200, (CH_UPPER_SB)},
-/* 47 */ {204, (CH_LOWER_SB)},
-/* 48 */ {208, (CH_UPPER_SB)},
-/* 49 */ {212, (CH_LOWER_SB)},
-/* 50 */ {216, (CH_LOWER_SB)}
-};
-#endif /* SUPPORT_40MHZ */
+ for (i = 0; i < ARRAY_SIZE(cntry_locales); i++) {
+ if (!strcmp(regdom, cntry_locales[i].abbrev)) {
+ regd = &cntry_locales[i];
+ break;
+ }
+ }
+
+ return regd;
+}
+
+static const struct brcms_regd *brcms_default_world_regd(void)
+{
+ return &cntry_locales[0];
+}

static const struct locale_info *brcms_c_get_locale_2g(u8 locale_idx)
{
@@ -621,164 +285,6 @@ static const struct locale_mimo_info *brcms_c_get_mimo_5g(u8 locale_idx)
return g_mimo_5g_table[locale_idx];
}

-static int
-brcms_c_country_aggregate_map(struct brcms_cm_info *wlc_cm, const char *ccode,
- char *mapped_ccode, uint *mapped_regrev)
-{
- return false;
-}
-
-/* Lookup a country info structure from a null terminated country
- * abbreviation and regrev directly with no translation.
- */
-static const struct country_info *
-brcms_c_country_lookup_direct(const char *ccode, uint regrev)
-{
- uint size, i;
-
- /* Should just return 0 for single locale driver. */
- /* Keep it this way in case we add more locales. (for now anyway) */
-
- /*
- * all other country def arrays are for regrev == 0, so if
- * regrev is non-zero, fail
- */
- if (regrev > 0)
- return NULL;
-
- /* find matched table entry from country code */
- size = ARRAY_SIZE(cntry_locales);
- for (i = 0; i < size; i++) {
- if (strcmp(ccode, cntry_locales[i].abbrev) == 0)
- return &cntry_locales[i].country;
- }
- return NULL;
-}
-
-static const struct country_info *
-brcms_c_countrycode_map(struct brcms_cm_info *wlc_cm, const char *ccode,
- char *mapped_ccode, uint *mapped_regrev)
-{
- struct brcms_c_info *wlc = wlc_cm->wlc;
- const struct country_info *country;
- uint srom_regrev = wlc_cm->srom_regrev;
- const char *srom_ccode = wlc_cm->srom_ccode;
- int mapped;
-
- /* check for currently supported ccode size */
- if (strlen(ccode) > (BRCM_CNTRY_BUF_SZ - 1)) {
- wiphy_err(wlc->wiphy, "wl%d: %s: ccode \"%s\" too long for "
- "match\n", wlc->pub->unit, __func__, ccode);
- return NULL;
- }
-
- /* default mapping is the given ccode and regrev 0 */
- strncpy(mapped_ccode, ccode, BRCM_CNTRY_BUF_SZ);
- *mapped_regrev = 0;
-
- /* If the desired country code matches the srom country code,
- * then the mapped country is the srom regulatory rev.
- * Otherwise look for an aggregate mapping.
- */
- if (!strcmp(srom_ccode, ccode)) {
- *mapped_regrev = srom_regrev;
- mapped = 0;
- wiphy_err(wlc->wiphy, "srom_code == ccode %s\n", __func__);
- } else {
- mapped =
- brcms_c_country_aggregate_map(wlc_cm, ccode, mapped_ccode,
- mapped_regrev);
- }
-
- /* find the matching built-in country definition */
- country = brcms_c_country_lookup_direct(mapped_ccode, *mapped_regrev);
-
- /* if there is not an exact rev match, default to rev zero */
- if (country == NULL && *mapped_regrev != 0) {
- *mapped_regrev = 0;
- country =
- brcms_c_country_lookup_direct(mapped_ccode, *mapped_regrev);
- }
-
- return country;
-}
-
-/* Lookup a country info structure from a null terminated country code
- * The lookup is case sensitive.
- */
-static const struct country_info *
-brcms_c_country_lookup(struct brcms_c_info *wlc, const char *ccode)
-{
- const struct country_info *country;
- char mapped_ccode[BRCM_CNTRY_BUF_SZ];
- uint mapped_regrev;
-
- /*
- * map the country code to a built-in country code, regrev, and
- * country_info struct
- */
- country = brcms_c_countrycode_map(wlc->cmi, ccode, mapped_ccode,
- &mapped_regrev);
-
- return country;
-}
-
-/*
- * reset the quiet channels vector to the union
- * of the restricted and radar channel sets
- */
-static void brcms_c_quiet_channels_reset(struct brcms_cm_info *wlc_cm)
-{
- struct brcms_c_info *wlc = wlc_cm->wlc;
- uint i, j;
- struct brcms_band *band;
- const struct brcms_chanvec *chanvec;
-
- memset(&wlc_cm->quiet_channels, 0, sizeof(struct brcms_chanvec));
-
- band = wlc->band;
- for (i = 0; i < wlc->pub->_nbands;
- i++, band = wlc->bandstate[OTHERBANDUNIT(wlc)]) {
-
- /* initialize quiet channels for restricted channels */
- chanvec = wlc_cm->bandstate[band->bandunit].restricted_channels;
- for (j = 0; j < sizeof(struct brcms_chanvec); j++)
- wlc_cm->quiet_channels.vec[j] |= chanvec->vec[j];
-
- }
-}
-
-/* Is the channel valid for the current locale and current band? */
-static bool brcms_c_valid_channel20(struct brcms_cm_info *wlc_cm, uint val)
-{
- struct brcms_c_info *wlc = wlc_cm->wlc;
-
- return ((val < MAXCHANNEL) &&
- isset(wlc_cm->bandstate[wlc->band->bandunit].valid_channels.vec,
- val));
-}
-
-/* Is the channel valid for the current locale and specified band? */
-static bool brcms_c_valid_channel20_in_band(struct brcms_cm_info *wlc_cm,
- uint bandunit, uint val)
-{
- return ((val < MAXCHANNEL)
- && isset(wlc_cm->bandstate[bandunit].valid_channels.vec, val));
-}
-
-/* Is the channel valid for the current locale? (but don't consider channels not
- * available due to bandlocking)
- */
-static bool brcms_c_valid_channel20_db(struct brcms_cm_info *wlc_cm, uint val)
-{
- struct brcms_c_info *wlc = wlc_cm->wlc;
-
- return brcms_c_valid_channel20(wlc->cmi, val) ||
- (!wlc->bandlocked
- && brcms_c_valid_channel20_in_band(wlc->cmi,
- OTHERBANDUNIT(wlc), val));
-}
-
/* JP, J1 - J10 are Japan ccodes */
static bool brcms_c_japan_ccode(const char *ccode)
{
@@ -786,12 +292,6 @@ static bool brcms_c_japan_ccode(const char *ccode)
(ccode[1] == 'P' || (ccode[1] >= '1' && ccode[1] <= '9')));
}

-/* Returns true if currently set country is Japan or variant */
-static bool brcms_c_japan(struct brcms_c_info *wlc)
-{
- return brcms_c_japan_ccode(wlc->cmi->country_abbrev);
-}
-
static void
brcms_c_channel_min_txpower_limits_with_local_constraint(
struct brcms_cm_info *wlc_cm, struct txpwr_limits *txpwr,
@@ -867,74 +367,45 @@ brcms_c_channel_min_txpower_limits_with_local_constraint(

}

+/*
+ * SAF: Is this needed? We don't have channel information until
+ * ieee80211_register_hw is called.
+ */
+#if 0
/* Update the radio state (enable/disable) and tx power targets
* based on a new set of channel/regulatory information
*/
static void brcms_c_channels_commit(struct brcms_cm_info *wlc_cm)
{
+ struct ieee80211_channel *ch = wlc_cm->pub->ieee_hw->conf.channel;
+ u16 chanspec = ch20mhz_chspec(ch->hw_value);
struct brcms_c_info *wlc = wlc_cm->wlc;
- uint chan;
struct txpwr_limits txpwr;

- /* search for the existence of any valid channel */
- for (chan = 0; chan < MAXCHANNEL; chan++) {
- if (brcms_c_valid_channel20_db(wlc->cmi, chan))
- break;
- }
- if (chan == MAXCHANNEL)
- chan = INVCHANNEL;
-
- /*
- * based on the channel search above, set or
- * clear WL_RADIO_COUNTRY_DISABLE.
- */
- if (chan == INVCHANNEL) {
- /*
- * country/locale with no valid channels, set
- * the radio disable bit
- */
- mboolset(wlc->pub->radio_disabled, WL_RADIO_COUNTRY_DISABLE);
- wiphy_err(wlc->wiphy, "wl%d: %s: no valid channel for \"%s\" "
- "nbands %d bandlocked %d\n", wlc->pub->unit,
- __func__, wlc_cm->country_abbrev, wlc->pub->_nbands,
- wlc->bandlocked);
- } else if (mboolisset(wlc->pub->radio_disabled,
- WL_RADIO_COUNTRY_DISABLE)) {
- /*
- * country/locale with valid channel, clear
- * the radio disable bit
- */
- mboolclr(wlc->pub->radio_disabled, WL_RADIO_COUNTRY_DISABLE);
- }
-
- /*
- * Now that the country abbreviation is set, if the radio supports 2G,
- * then set channel 14 restrictions based on the new locale.
- */
- if (wlc->pub->_nbands > 1 || wlc->band->bandtype == BRCM_BAND_2G)
- wlc_phy_chanspec_ch14_widefilter_set(wlc->band->pi,
- brcms_c_japan(wlc) ? true :
- false);
-
- if (wlc->pub->up && chan != INVCHANNEL) {
- brcms_c_channel_reg_limits(wlc_cm, wlc->chanspec, &txpwr);
+ if (wlc->pub->up) {
+ brcms_c_channel_reg_limits(wlc_cm, chanspec, ch, &txpwr);
brcms_c_channel_min_txpower_limits_with_local_constraint(wlc_cm,
&txpwr, BRCMS_TXPWR_MAX);
- wlc_phy_txpower_limit_set(wlc->band->pi, &txpwr, wlc->chanspec);
+ wlc_phy_txpower_limit_set(wlc->band->pi, &txpwr, chanspec);
}
}
+#endif

static int
brcms_c_channels_init(struct brcms_cm_info *wlc_cm,
const struct country_info *country)
{
struct brcms_c_info *wlc = wlc_cm->wlc;
- uint i, j;
+ uint i;
struct brcms_band *band;
const struct locale_info *li;
- struct brcms_chanvec sup_chan;
const struct locale_mimo_info *li_mimo;

+ /*
+ * SAF: The only thing we're left doing here right now is locale
+ * flags, which are used very little. It shouldn't be difficult
+ * to eliminate them entirely.
+ */
band = wlc->band;
for (i = 0; i < wlc->pub->_nbands;
i++, band = wlc->bandstate[OTHERBANDUNIT(wlc)]) {
@@ -950,28 +421,15 @@ brcms_c_channels_init(struct brcms_cm_info *wlc_cm,
/* merge the mimo non-mimo locale flags */
wlc_cm->bandstate[band->bandunit].locale_flags |=
li_mimo->flags;
-
- wlc_cm->bandstate[band->bandunit].restricted_channels =
- g_table_restricted_chan[li->restricted_channels];
- wlc_cm->bandstate[band->bandunit].radar_channels =
- g_table_radar_set[li->radar_channels];
-
- /*
- * set the channel availability, masking out the channels
- * that may not be supported on this phy.
- */
- wlc_phy_chanspec_band_validch(band->pi, band->bandtype,
- &sup_chan);
- brcms_c_locale_get_channels(li,
- &wlc_cm->bandstate[band->bandunit].
- valid_channels);
- for (j = 0; j < sizeof(struct brcms_chanvec); j++)
- wlc_cm->bandstate[band->bandunit].valid_channels.
- vec[j] &= sup_chan.vec[j];
}

- brcms_c_quiet_channels_reset(wlc_cm);
+ /*
+ * SAF: Can't really do this here since we don't have a channel
+ * or regulatory information yet.
+ */
+#if 0
brcms_c_channels_commit(wlc_cm);
+#endif

return 0;
}
@@ -982,25 +440,11 @@ brcms_c_channels_init(struct brcms_cm_info *wlc_cm,
* information found with the country code.
*/
static void
-brcms_c_set_country_common(struct brcms_cm_info *wlc_cm,
- const char *country_abbrev,
- const char *ccode, uint regrev,
- const struct country_info *country)
+brcms_c_set_country(struct brcms_cm_info *wlc_cm,
+ const struct brcms_regd *regd)
{
- const struct locale_info *locale;
+ const struct country_info *country = &regd->country;
struct brcms_c_info *wlc = wlc_cm->wlc;
- char prev_country_abbrev[BRCM_CNTRY_BUF_SZ];
-
- /* save current country state */
- wlc_cm->country = country;
-
- memset(&prev_country_abbrev, 0, BRCM_CNTRY_BUF_SZ);
- strncpy(prev_country_abbrev, wlc_cm->country_abbrev,
- BRCM_CNTRY_BUF_SZ - 1);
-
- strncpy(wlc_cm->country_abbrev, country_abbrev, BRCM_CNTRY_BUF_SZ - 1);
- strncpy(wlc_cm->ccode, ccode, BRCM_CNTRY_BUF_SZ - 1);
- wlc_cm->regrev = regrev;

if ((wlc->pub->_n_enab & SUPPORT_11N) !=
wlc->protection->nmode_user)
@@ -1009,74 +453,18 @@ brcms_c_set_country_common(struct brcms_cm_info *wlc_cm,
brcms_c_stf_ss_update(wlc, wlc->bandstate[BAND_2G_INDEX]);
brcms_c_stf_ss_update(wlc, wlc->bandstate[BAND_5G_INDEX]);
/* set or restore gmode as required by regulatory */
- locale = brcms_c_get_locale_2g(country->locale_2G);
- if (locale && (locale->flags & BRCMS_NO_OFDM))
- brcms_c_set_gmode(wlc, GMODE_LEGACY_B, false);
- else
- brcms_c_set_gmode(wlc, wlc->protection->gmode_user, false);
+ brcms_c_set_gmode(wlc, wlc->protection->gmode_user, false);

brcms_c_channels_init(wlc_cm, country);

return;
}

-static int
-brcms_c_set_countrycode_rev(struct brcms_cm_info *wlc_cm,
- const char *country_abbrev,
- const char *ccode, int regrev)
-{
- const struct country_info *country;
- char mapped_ccode[BRCM_CNTRY_BUF_SZ];
- uint mapped_regrev;
-
- /* if regrev is -1, lookup the mapped country code,
- * otherwise use the ccode and regrev directly
- */
- if (regrev == -1) {
- /*
- * map the country code to a built-in country
- * code, regrev, and country_info
- */
- country =
- brcms_c_countrycode_map(wlc_cm, ccode, mapped_ccode,
- &mapped_regrev);
- } else {
- /* find the matching built-in country definition */
- country = brcms_c_country_lookup_direct(ccode, regrev);
- strncpy(mapped_ccode, ccode, BRCM_CNTRY_BUF_SZ);
- mapped_regrev = regrev;
- }
-
- if (country == NULL)
- return -EINVAL;
-
- /* set the driver state for the country */
- brcms_c_set_country_common(wlc_cm, country_abbrev, mapped_ccode,
- mapped_regrev, country);
-
- return 0;
-}
-
-/*
- * set the driver's current country and regulatory information using
- * a country code as the source. Lookup built in country information
- * found with the country code.
- */
-static int
-brcms_c_set_countrycode(struct brcms_cm_info *wlc_cm, const char *ccode)
-{
- char country_abbrev[BRCM_CNTRY_BUF_SZ];
- strncpy(country_abbrev, ccode, BRCM_CNTRY_BUF_SZ);
- return brcms_c_set_countrycode_rev(wlc_cm, country_abbrev, ccode, -1);
-}
-
struct brcms_cm_info *brcms_c_channel_mgr_attach(struct brcms_c_info *wlc)
{
struct brcms_cm_info *wlc_cm;
- char country_abbrev[BRCM_CNTRY_BUF_SZ];
- const struct country_info *country;
struct brcms_pub *pub = wlc->pub;
- char *ccode;
+ const char *ccode;

BCMMSG(wlc->wiphy, "wl%d\n", wlc->pub->unit);

@@ -1089,24 +477,32 @@ struct brcms_cm_info *brcms_c_channel_mgr_attach(struct brcms_c_info *wlc)

/* store the country code for passing up as a regulatory hint */
ccode = getvar(wlc->hw->sih, BRCMS_SROM_CCODE);
- if (ccode)
+ if (ccode) {
strncpy(wlc->pub->srom_ccode, ccode, BRCM_CNTRY_BUF_SZ - 1);
+ wlc_cm->world_regd = brcms_world_regd(ccode);
+ }

/*
- * internal country information which must match
- * regulatory constraints in firmware
+ * If no custom world domain is found in the SROM, use the
+ * default "X2" domain.
*/
- memset(country_abbrev, 0, BRCM_CNTRY_BUF_SZ);
- strncpy(country_abbrev, "X2", sizeof(country_abbrev) - 1);
- country = brcms_c_country_lookup(wlc, country_abbrev);
+ if (!wlc_cm->world_regd) {
+ ccode = "X2";
+ wlc_cm->world_regd = brcms_default_world_regd();
+ }

+ /*
+ * SAF: country_default and autocountry_default aren't really
+ * used, can they be removed? Need to consider what needs to
+ * be done to exit 11d regulatory mode.
+ */
/* save default country for exiting 11d regulatory mode */
- strncpy(wlc->country_default, country_abbrev, BRCM_CNTRY_BUF_SZ - 1);
+ strncpy(wlc->country_default, ccode, BRCM_CNTRY_BUF_SZ - 1);

/* initialize autocountry_default to driver default */
- strncpy(wlc->autocountry_default, "X2", BRCM_CNTRY_BUF_SZ - 1);
+ strncpy(wlc->autocountry_default, ccode, BRCM_CNTRY_BUF_SZ - 1);

- brcms_c_set_countrycode(wlc_cm, country_abbrev);
+ brcms_c_set_country(wlc_cm, wlc_cm->world_regd);

return wlc_cm;
}
@@ -1116,6 +512,9 @@ void brcms_c_channel_mgr_detach(struct brcms_cm_info *wlc_cm)
kfree(wlc_cm);
}

+/*
+ * SAF: Need to use info from struct ieee80211_channel for this instead
+ */
u8
brcms_c_channel_locale_flags_in_band(struct brcms_cm_info *wlc_cm,
uint bandunit)
@@ -1123,38 +522,39 @@ brcms_c_channel_locale_flags_in_band(struct brcms_cm_info *wlc_cm,
return wlc_cm->bandstate[bandunit].locale_flags;
}

-static bool
-brcms_c_quiet_chanspec(struct brcms_cm_info *wlc_cm, u16 chspec)
-{
- return (wlc_cm->wlc->pub->_n_enab & SUPPORT_11N) &&
- CHSPEC_IS40(chspec) ?
- (isset(wlc_cm->quiet_channels.vec,
- lower_20_sb(CHSPEC_CHANNEL(chspec))) ||
- isset(wlc_cm->quiet_channels.vec,
- upper_20_sb(CHSPEC_CHANNEL(chspec)))) :
- isset(wlc_cm->quiet_channels.vec, CHSPEC_CHANNEL(chspec));
-}
-
void
brcms_c_channel_set_chanspec(struct brcms_cm_info *wlc_cm, u16 chanspec,
- u8 local_constraint_qdbm)
+ u8 local_constraint_qdbm)
{
struct brcms_c_info *wlc = wlc_cm->wlc;
+ struct ieee80211_conf *conf = &wlc_cm->pub->ieee_hw->conf;
+ struct ieee80211_channel *ch = conf->channel;
struct txpwr_limits txpwr;

- brcms_c_channel_reg_limits(wlc_cm, chanspec, &txpwr);
+ brcms_c_channel_reg_limits(wlc_cm, chanspec, ch, &txpwr);

brcms_c_channel_min_txpower_limits_with_local_constraint(
wlc_cm, &txpwr, local_constraint_qdbm
);

- brcms_b_set_chanspec(wlc->hw, chanspec,
- (brcms_c_quiet_chanspec(wlc_cm, chanspec) != 0),
- &txpwr);
+ /*
+ * SAF: Passing false for mute_tx. Not sure if this is okay,
+ * but I'm also not sure how to tell whether or not mute_tx
+ * should be set ...
+ */
+ brcms_b_set_chanspec(wlc->hw, chanspec, false, &txpwr);
}

+/*
+ * SAF: Much of the data here still comes from internal structures, but
+ * I'm not sure where else to store this data.
+ *
+ * Also I wonder whether we ought to be getting the power from
+ * ieee80211_conf instead.
+ */
void
brcms_c_channel_reg_limits(struct brcms_cm_info *wlc_cm, u16 chanspec,
+ struct ieee80211_channel *channel,
struct txpwr_limits *txpwr)
{
struct brcms_c_info *wlc = wlc_cm->wlc;
@@ -1166,7 +566,6 @@ brcms_c_channel_reg_limits(struct brcms_cm_info *wlc_cm, u16 chanspec,
struct brcms_band *band;
const struct locale_info *li;
int conducted_max = BRCMS_TXPWR_MAX;
- int conducted_ofdm_max = BRCMS_TXPWR_MAX;
const struct locale_mimo_info *li_mimo;
int maxpwr20, maxpwr40;
int maxpwr_idx;
@@ -1174,14 +573,23 @@ brcms_c_channel_reg_limits(struct brcms_cm_info *wlc_cm, u16 chanspec,

memset(txpwr, 0, sizeof(struct txpwr_limits));

- if (!brcms_c_valid_chanspec_db(wlc_cm, chanspec)) {
- country = brcms_c_country_lookup(wlc, wlc->autocountry_default);
- if (country == NULL)
- return;
- } else {
- country = wlc_cm->country;
- }
+ /*
+ * SAF: What to do if we don't have a channel?
+ */
+ if (WARN_ON(!channel))
+ return;
+
+ /*
+ * SAF: Will this even work properly if the chanspec isn't valid?
+ * Previously the code would proceed, but for now let's warn and
+ * return. In reality if channel is valid then chanspec should be
+ * valid as well, but we can also get all the information we need
+ * without using chanspec at all.
+ */
+ if (WARN_ON(!brcms_c_valid_chanspec_db(wlc_cm, chanspec)))
+ return;

+ country = &wlc_cm->world_regd->country;
chan = CHSPEC_CHANNEL(chanspec);
band = wlc->bandstate[chspec_bandunit(chanspec)];
li = (band->bandtype == BRCM_BAND_5G) ?
@@ -1192,6 +600,10 @@ brcms_c_channel_reg_limits(struct brcms_cm_info *wlc_cm, u16 chanspec,
brcms_c_get_mimo_5g(country->locale_mimo_5G) :
brcms_c_get_mimo_2g(country->locale_mimo_2G);

+ /*
+ * SAF: Currently all locales have BRCMS_EIRP set, so only first
+ * case matters.
+ */
if (li->flags & BRCMS_EIRP) {
delta = band->antgain;
} else {
@@ -1200,41 +612,28 @@ brcms_c_channel_reg_limits(struct brcms_cm_info *wlc_cm, u16 chanspec,
delta = band->antgain - QDB(6); /* Excess over 6 dB */
}

- if (li == &locale_i) {
+ /*
+ * SAF: After this function is done,
+ * brcms_c_channel_min_txpower_limits_with_local_constraint() is
+ * going to clamp down all these values to BRCMS_TXPWR_MAX anyway.
+ * So what's the point of conducted_max?
+ */
+ if (li == &locale_i)
conducted_max = QDB(22);
- conducted_ofdm_max = QDB(22);
- }
+
+ maxpwr = QDB(channel->max_power) - delta;
+ maxpwr = max(maxpwr, 0);
+ maxpwr = min(maxpwr, conducted_max);

/* CCK txpwr limits for 2.4G band */
if (band->bandtype == BRCM_BAND_2G) {
- maxpwr = li->maxpwr[CHANNEL_POWER_IDX_2G_CCK(chan)];
-
- maxpwr = maxpwr - delta;
- maxpwr = max(maxpwr, 0);
- maxpwr = min(maxpwr, conducted_max);
-
for (i = 0; i < BRCMS_NUM_RATES_CCK; i++)
txpwr->cck[i] = (u8) maxpwr;
}

- /* OFDM txpwr limits for 2.4G or 5G bands */
- if (band->bandtype == BRCM_BAND_2G)
- maxpwr = li->maxpwr[CHANNEL_POWER_IDX_2G_OFDM(chan)];
- else
- maxpwr = li->maxpwr[CHANNEL_POWER_IDX_5G(chan)];
-
- maxpwr = maxpwr - delta;
- maxpwr = max(maxpwr, 0);
- maxpwr = min(maxpwr, conducted_ofdm_max);
-
- /* Keep OFDM lmit below CCK limit */
- if (band->bandtype == BRCM_BAND_2G)
- maxpwr = min_t(int, maxpwr, txpwr->cck[0]);
-
- for (i = 0; i < BRCMS_NUM_RATES_OFDM; i++)
+ for (i = 0; i < BRCMS_NUM_RATES_OFDM; i++) {
txpwr->ofdm[i] = (u8) maxpwr;

- for (i = 0; i < BRCMS_NUM_RATES_OFDM; i++) {
/*
* OFDM 40 MHz SISO has the same power as the corresponding
* MCS0-7 rate unless overriden by the locale specific code.
@@ -1249,6 +648,15 @@ brcms_c_channel_reg_limits(struct brcms_cm_info *wlc_cm, u16 chanspec,
txpwr->ofdm_40_cdd[i] = 0;
}

+ /*
+ * SAF: I'm not sure how to transition the MIMO limits to using the
+ * standard regulatory structures.
+ */
+
+ /*
+ * SAF: none of the MIMO locales have BRCMS_EIRP set, so only the
+ * second case currently matters.
+ */
/* MIMO/HT specific limits */
if (li_mimo->flags & BRCMS_EIRP) {
delta = band->antgain;
@@ -1392,14 +800,8 @@ static bool brcms_c_chspec_malformed(u16 chanspec)
return false;
}

-/*
- * Validate the chanspec for this locale, for 40MHZ we need to also
- * check that the sidebands are valid 20MZH channels in this locale
- * and they are also a legal HT combination
- */
static bool
-brcms_c_valid_chanspec_ext(struct brcms_cm_info *wlc_cm, u16 chspec,
- bool dualband)
+brcms_c_valid_chanspec_ext(struct brcms_cm_info *wlc_cm, u16 chspec)
{
struct brcms_c_info *wlc = wlc_cm->wlc;
u8 channel = CHSPEC_CHANNEL(chspec);
@@ -1415,59 +817,148 @@ brcms_c_valid_chanspec_ext(struct brcms_cm_info *wlc_cm, u16 chspec,
chspec_bandunit(chspec))
return false;

- /* Check a 20Mhz channel */
- if (CHSPEC_IS20(chspec)) {
- if (dualband)
- return brcms_c_valid_channel20_db(wlc_cm->wlc->cmi,
- channel);
- else
- return brcms_c_valid_channel20(wlc_cm->wlc->cmi,
- channel);
+ return true;
+}
+
+bool brcms_c_valid_chanspec_db(struct brcms_cm_info *wlc_cm, u16 chspec)
+{
+ return brcms_c_valid_chanspec_ext(wlc_cm, chspec);
+}
+
+bool brcms_is_world_regd(const char *regdom)
+{
+ return !!brcms_world_regd(regdom);
+}
+
+static inline bool brcms_is_radar_freq(u16 center_freq)
+{
+ return center_freq >= 5260 && center_freq <= 5700;
+}
+
+static void brcms_reg_apply_radar_flags(struct wiphy *wiphy)
+{
+ struct ieee80211_supported_band *sband;
+ struct ieee80211_channel *ch;
+ int i;
+
+ sband = wiphy->bands[IEEE80211_BAND_5GHZ];
+ if (!sband)
+ return;
+
+ for (i = 0; i < sband->n_channels; i++) {
+ ch = &sband->channels[i];
+
+ if (!brcms_is_radar_freq(ch->center_freq))
+ continue;
+
+ /*
+ * All channels in this range should be passive and have
+ * DFS enabled.
+ */
+ if (!(ch->flags & IEEE80211_CHAN_DISABLED))
+ ch->flags |= IEEE80211_CHAN_RADAR |
+ IEEE80211_CHAN_NO_IBSS |
+ IEEE80211_CHAN_PASSIVE_SCAN;
}
-#ifdef SUPPORT_40MHZ
- /*
- * We know we are now checking a 40MHZ channel, so we should
- * only be here for NPHYS
- */
- if (BRCMS_ISNPHY(wlc->band) || BRCMS_ISSSLPNPHY(wlc->band)) {
- u8 upper_sideband = 0, idx;
- u8 num_ch20_entries =
- sizeof(chan20_info) / sizeof(struct chan20_info);
-
- if (!VALID_40CHANSPEC_IN_BAND(wlc, chspec_bandunit(chspec)))
- return false;
-
- if (dualband) {
- if (!brcms_c_valid_channel20_db(wlc->cmi,
- lower_20_sb(channel)) ||
- !brcms_c_valid_channel20_db(wlc->cmi,
- upper_20_sb(channel)))
- return false;
- } else {
- if (!brcms_c_valid_channel20(wlc->cmi,
- lower_20_sb(channel)) ||
- !brcms_c_valid_channel20(wlc->cmi,
- upper_20_sb(channel)))
- return false;
- }
+}

- /* find the lower sideband info in the sideband array */
- for (idx = 0; idx < num_ch20_entries; idx++) {
- if (chan20_info[idx].sb == lower_20_sb(channel))
- upper_sideband = chan20_info[idx].adj_sbs;
+static void brcms_reg_apply_beaconing_flags(struct wiphy *wiphy,
+ enum nl80211_reg_initiator initiator)
+{
+ struct ieee80211_supported_band *sband;
+ struct ieee80211_channel *ch;
+ const struct ieee80211_reg_rule *reg_rule;
+ int band, i, ret;
+
+ for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
+ sband = wiphy->bands[band];
+ if (!sband)
+ continue;
+
+ for (i = 0; i < sband->n_channels; i++) {
+ ch = &sband->channels[i];
+
+ if (brcms_is_radar_freq(ch->center_freq) ||
+ (ch->flags & IEEE80211_CHAN_RADAR))
+ continue;
+
+ if (initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE) {
+ ret = freq_reg_info(wiphy, ch->center_freq,
+ 0, &reg_rule);
+ if (ret)
+ continue;
+
+ if (!(reg_rule->flags & NL80211_RRF_NO_IBSS))
+ ch->flags &= ~IEEE80211_CHAN_NO_IBSS;
+ if (!(reg_rule->flags & NL80211_RRF_PASSIVE_SCAN))
+ ch->flags &= ~IEEE80211_CHAN_PASSIVE_SCAN;
+ } else {
+ if (ch->beacon_found)
+ ch->flags &= ~(IEEE80211_CHAN_NO_IBSS |
+ IEEE80211_CHAN_PASSIVE_SCAN);
+ }
}
- /* check that the lower sideband allows an upper sideband */
- if ((upper_sideband & (CH_UPPER_SB | CH_EWA_VALID)) ==
- (CH_UPPER_SB | CH_EWA_VALID))
- return true;
- return false;
}
-#endif /* 40 MHZ */
+}

- return false;
+static int brcms_reg_notifier(struct wiphy *wiphy,
+ struct regulatory_request *request)
+{
+ struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy);
+ struct brcms_info *wl = hw->priv;
+ struct brcms_c_info *wlc = wl->wlc;
+ /*
+ * SAF: Do we need any special handling for channels 12 and 13?
+ */
+
+ brcms_reg_apply_radar_flags(wiphy);
+
+ if (request && request->initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE)
+ brcms_reg_apply_beaconing_flags(wiphy, request->initiator);
+
+ /*
+ * SAF: Should this still be based off alpha2? And is it really
+ * needed? The channel_14_wide_filter flag isn't actually used
+ * anywhere.
+ */
+ if (wlc->pub->_nbands > 1 || wlc->band->bandtype == BRCM_BAND_2G)
+ wlc_phy_chanspec_ch14_widefilter_set(wlc->band->pi,
+ brcms_c_japan_ccode(request->alpha2));
+
+ return 0;
}

-bool brcms_c_valid_chanspec_db(struct brcms_cm_info *wlc_cm, u16 chspec)
+void brcms_c_regd_init(struct brcms_c_info *wlc)
{
- return brcms_c_valid_chanspec_ext(wlc_cm, chspec, true);
+ struct wiphy *wiphy = brcms_c_get_wiphy(wlc->cmi);
+ const struct brcms_regd *regd = wlc->cmi->world_regd;
+ struct ieee80211_supported_band *sband;
+ struct ieee80211_channel *ch;
+ struct brcms_chanvec sup_chan;
+ struct brcms_band *band;
+ int band_idx, i;
+
+ /* Disable any channels not supported by the phy */
+ for (band_idx = 0; band_idx < IEEE80211_NUM_BANDS; band_idx++) {
+ if (band_idx == IEEE80211_BAND_2GHZ)
+ band = wlc->bandstate[BAND_2G_INDEX];
+ else
+ band = wlc->bandstate[BAND_5G_INDEX];
+ wlc_phy_chanspec_band_validch(band->pi, band->bandtype,
+ &sup_chan);
+
+ sband = wiphy->bands[band_idx];
+ for (i = 0; i < sband->n_channels; i++) {
+ ch = &sband->channels[i];
+ if (!isset(sup_chan.vec, ch->hw_value))
+ ch->flags |= IEEE80211_CHAN_DISABLED;
+ }
+ }
+
+ wlc->wiphy->reg_notifier = brcms_reg_notifier;
+ wlc->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY |
+ WIPHY_FLAG_STRICT_REGULATORY;
+ wiphy_apply_custom_regulatory(wlc->wiphy, regd->regdomain);
+ brcms_reg_apply_radar_flags(wiphy);
+ brcms_reg_apply_beaconing_flags(wiphy, NL80211_REGDOM_SET_BY_DRIVER);
}
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/channel.h b/drivers/net/wireless/brcm80211/brcmsmac/channel.h
index 808cb4f..4758108 100644
--- a/drivers/net/wireless/brcm80211/brcmsmac/channel.h
+++ b/drivers/net/wireless/brcm80211/brcmsmac/channel.h
@@ -44,10 +44,15 @@ extern bool brcms_c_valid_chanspec_db(struct brcms_cm_info *wlc_cm,
u16 chspec);

extern void brcms_c_channel_reg_limits(struct brcms_cm_info *wlc_cm,
- u16 chanspec,
- struct txpwr_limits *txpwr);
+ u16 chanspec,
+ struct ieee80211_channel *channel,
+ struct txpwr_limits *txpwr);
extern void brcms_c_channel_set_chanspec(struct brcms_cm_info *wlc_cm,
- u16 chanspec,
- u8 local_constraint_qdbm);
+ u16 chanspec,
+ u8 local_constraint_qdbm);
+
+extern bool brcms_is_world_regd(const char *regdom);
+
+extern void brcms_c_regd_init(struct brcms_c_info *wlc);

#endif /* _WLC_CHANNEL_H */
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c b/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c
index 569ab8a..a9703eb 100644
--- a/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c
+++ b/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c
@@ -396,8 +396,7 @@ static int brcms_ops_config(struct ieee80211_hw *hw, u32 changed)
if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
if (conf->channel_type == NL80211_CHAN_HT20 ||
conf->channel_type == NL80211_CHAN_NO_HT)
- err = brcms_c_set_channel(wl->wlc,
- conf->channel->hw_value);
+ err = brcms_c_set_channel(wl->wlc, conf->channel);
else
err = -ENOTSUPP;
}
@@ -727,7 +726,9 @@ static const struct ieee80211_ops brcms_ops = {
*/
static int brcms_set_hint(struct brcms_info *wl, char *abbrev)
{
- return regulatory_hint(wl->pub->ieee_hw->wiphy, abbrev);
+ if (!brcms_is_world_regd(abbrev))
+ return regulatory_hint(wl->pub->ieee_hw->wiphy, abbrev);
+ return 0;
}

void brcms_dpc(unsigned long data)
@@ -1059,6 +1060,8 @@ static struct brcms_info *brcms_attach(struct bcma_device *pdev)
goto fail;
}

+ brcms_c_regd_init(wl->wlc);
+
memcpy(perm, &wl->pub->cur_etheraddr, ETH_ALEN);
if (WARN_ON(!is_valid_ether_addr(perm)))
goto fail;
@@ -1071,8 +1074,6 @@ static struct brcms_info *brcms_attach(struct bcma_device *pdev)

if (wl->pub->srom_ccode[0])
err = brcms_set_hint(wl, wl->pub->srom_ccode);
- else
- err = brcms_set_hint(wl, "US");
if (err)
wiphy_err(wl->wiphy, "%s: regulatory_hint failed, status %d\n",
__func__, err);
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/main.c b/drivers/net/wireless/brcm80211/brcmsmac/main.c
index 86186fa..2b8734b 100644
--- a/drivers/net/wireless/brcm80211/brcmsmac/main.c
+++ b/drivers/net/wireless/brcm80211/brcmsmac/main.c
@@ -3150,20 +3150,6 @@ void brcms_c_reset(struct brcms_c_info *wlc)
brcms_b_reset(wlc->hw);
}

-/* Return the channel the driver should initialize during brcms_c_init.
- * the channel may have to be changed from the currently configured channel
- * if other configurations are in conflict (bandlocked, 11n mode disabled,
- * invalid channel for current country, etc.)
- */
-static u16 brcms_c_init_chanspec(struct brcms_c_info *wlc)
-{
- u16 chanspec =
- 1 | WL_CHANSPEC_BW_20 | WL_CHANSPEC_CTL_SB_NONE |
- WL_CHANSPEC_BAND_2G;
-
- return chanspec;
-}
-
void brcms_c_init_scb(struct scb *scb)
{
int i;
@@ -3409,8 +3395,7 @@ static brcms_b_init(struct brcms_hardware *wlc_hw, u16 chanspec) {
brcms_b_clkctl_clk(wlc_hw, CLK_DYNAMIC);
}

-static void brcms_c_set_phy_chanspec(struct brcms_c_info *wlc,
- u16 chanspec)
+static void brcms_c_set_phy_chanspec(struct brcms_c_info *wlc, u16 chanspec)
{
/* Save our copy of the chanspec */
wlc->chanspec = chanspec;
@@ -3530,8 +3515,7 @@ static void brcms_c_rate_lookup_init(struct brcms_c_info *wlc,
}
}

-static void brcms_c_bandinit_ordered(struct brcms_c_info *wlc,
- u16 chanspec)
+static void brcms_c_bandinit_ordered(struct brcms_c_info *wlc, u16 chanspec)
{
struct brcms_c_rateset default_rateset;
uint parkband;
@@ -5152,6 +5136,8 @@ static void brcms_c_wme_retries_write(struct brcms_c_info *wlc)
/* make interface operational */
int brcms_c_up(struct brcms_c_info *wlc)
{
+ struct ieee80211_channel *ch;
+
BCMMSG(wlc->wiphy, "wl%d\n", wlc->pub->unit);

/* HW is turned off so don't try to access it */
@@ -5218,8 +5204,9 @@ int brcms_c_up(struct brcms_c_info *wlc)
wlc->pub->up = true;

if (wlc->bandinit_pending) {
+ ch = wlc->pub->ieee_hw->conf.channel;
brcms_c_suspend_mac_and_wait(wlc);
- brcms_c_set_chanspec(wlc, wlc->default_bss->chanspec);
+ brcms_c_set_chanspec(wlc, ch20mhz_chspec(ch->hw_value));
wlc->bandinit_pending = false;
brcms_c_enable_mac(wlc);
}
@@ -5421,6 +5408,8 @@ int brcms_c_set_gmode(struct brcms_c_info *wlc, u8 gmode, bool config)
return -EINVAL;

/* Legacy or bust when no OFDM is supported by regulatory */
+ /*
+ * SAF: Use actual reg rule to check for OFDM? */
if ((brcms_c_channel_locale_flags_in_band(wlc->cmi, band->bandunit) &
BRCMS_NO_OFDM) && (gmode != GMODE_LEGACY_B))
return -EINVAL;
@@ -5576,8 +5565,9 @@ static void brcms_c_ofdm_rateset_war(struct brcms_c_info *wlc)
wlc_phy_ofdm_rateset_war(wlc->band->pi, war);
}

-int brcms_c_set_channel(struct brcms_c_info *wlc, u16 channel)
+int brcms_c_set_channel(struct brcms_c_info *wlc, struct ieee80211_channel *ch)
{
+ int channel = ch->hw_value;
u16 chspec = ch20mhz_chspec(channel);

if (channel < 0 || channel > MAXCHANNEL)
@@ -5586,7 +5576,6 @@ int brcms_c_set_channel(struct brcms_c_info *wlc, u16 channel)
if (!brcms_c_valid_chanspec_db(wlc->cmi, chspec))
return -EINVAL;

-
if (!wlc->pub->up && brcms_is_mband_unlocked(wlc)) {
if (wlc->band->bandunit != chspec_bandunit(chspec))
wlc->bandinit_pending = true;
@@ -8216,19 +8205,12 @@ bool brcms_c_dpc(struct brcms_c_info *wlc, bool bounded)
void brcms_c_init(struct brcms_c_info *wlc, bool mute_tx)
{
struct bcma_device *core = wlc->hw->d11core;
+ struct ieee80211_channel *ch = wlc->pub->ieee_hw->conf.channel;
u16 chanspec;

BCMMSG(wlc->wiphy, "wl%d\n", wlc->pub->unit);

- /*
- * This will happen if a big-hammer was executed. In
- * that case, we want to go back to the channel that
- * we were on and not new channel
- */
- if (wlc->pub->associated)
- chanspec = wlc->home_chanspec;
- else
- chanspec = brcms_c_init_chanspec(wlc);
+ chanspec = ch20mhz_chspec(ch->hw_value);

brcms_b_init(wlc->hw, chanspec);

diff --git a/drivers/net/wireless/brcm80211/brcmsmac/pub.h b/drivers/net/wireless/brcm80211/brcmsmac/pub.h
index f0038ad..4de7f1d 100644
--- a/drivers/net/wireless/brcm80211/brcmsmac/pub.h
+++ b/drivers/net/wireless/brcm80211/brcmsmac/pub.h
@@ -18,6 +18,8 @@
#define _BRCM_PUB_H_

#include <linux/bcma/bcma.h>
+#include <net/mac80211.h>
+#include <net/cfg80211.h>
#include <brcmu_wifi.h>
#include "types.h"
#include "defs.h"
@@ -580,7 +582,8 @@ extern void brcms_c_scan_stop(struct brcms_c_info *wlc);
extern int brcms_c_get_curband(struct brcms_c_info *wlc);
extern void brcms_c_wait_for_tx_completion(struct brcms_c_info *wlc,
bool drop);
-extern int brcms_c_set_channel(struct brcms_c_info *wlc, u16 channel);
+extern int brcms_c_set_channel(struct brcms_c_info *wlc,
+ struct ieee80211_channel *channel);
extern int brcms_c_set_rate_limit(struct brcms_c_info *wlc, u16 srl, u16 lrl);
extern void brcms_c_get_current_rateset(struct brcms_c_info *wlc,
struct brcm_rateset *currs);

2012-04-04 07:03:37

by Arend van Spriel

[permalink] [raw]
Subject: Re: Problems with regulatory domain support and BCM43224

On 04/04/2012 04:46 AM, Seth Forshee wrote:
> On Mon, Mar 26, 2012 at 02:36:08PM -0500, Seth Forshee wrote:
>> I've been studying the existing brcmsmac regulatory code in more detail,
>> and I think there's a lot of potential to make the integration with the
>> core regulatory support much better. I'm still making my way through
>> some of the code, but here's what I see so far.
>>
>> Once full and accurate regdomain information is provided to the core
>> regulatory code, all the code in channel.c that's checking against
>> regulatory constraints can be eliminated, as that will get done at a
>> higher level. I think the code to set the Tx power should also be
>> reworked to use the constraints from the core regdom code. At that point
>> the need for the custom regdom structures is mostly eliminated.
>>
>> I'm going to start toying with implementing some of this this week, time
>> permitting. I think X2 is the only domain I have enough information on
>> to realistically implement. But even with that one it would be helpful
>> to understand what it's meant to represent, as Luis pointed out.
>>
>> I have one other question as well. Does the data in channel.c generally
>> represent the most permissive regulatory parameters that ought to be
>> used? That's the assumption I'm working under right now.
>
> Below is a diff of the changes I've made locally to the brcmsmac
> regulatory support. I haven't started thinking about dividing it up into
> more digestible chunks, so for now it's just one massive diff. I've made
> a lot of progress towards moving brcmsmac away from its custom formats
> for regulatory information, but there are a few points I'm still having
> difficulty with.
>
> The patch builds, and kind of works. Scanning seems to be fine; I can
> see all the APs I expect in my area, including the one on a DFS channel
> that I couldn't see previously. I can associate with my 2.4 GHz APs, but
> not the 5 GHz AP. I see timme outs waiting for probe responses, and I'm
> hitting the WARN_ON_ONCE in brcms_c_wait_for_tx_completion(). I haven't
> really debugged this yet -- I thought I'd send out the patch to collect
> comments while I debug. Suggestions of what's causing this are also
> welcome :)
>
> One of the major unresolved issues in the patch is what to do with the
> data in struct locale_mimo_info. The regulatory rules only hold one
> power level. I'm unsure why the brcmsmac implementation differs in this
> regard. Suggestions?
>
> The txpwr calculations are modified, both to use the regdomain data so
> far as possible and to eliminate redundant code. I'd appreciate review
> of these changes in addition to the suggestions on how to handle the
> MIMO power limits as I've already mentioned.
>
> Initialization has also changed somewhat. The piece that looks most
> significant to me is that wlc_phy_txpower_limit_set() gets called later,
> not until after the ieee80211_hw device is registered.
>
> Beyond these I still have a number of comments with my initials (SAF)
> that contain questions, comments, and TODOs. Feedback regarding these
> items, or anything else, are greatly appreciated.
>
> Looking forward to your comments.
>
> Thanks,
> Seth
>

Thanks, Seth

I am sure you are moving in the right direction here. Unfortunately, I
am currently unable to give the patch a spin. I am attending the linux
collaboration summit in San Francisco and I can only do some basic
testing on it. I will be back in my office next week to do some more
elaborate testing on it.

Gr. AvS


2012-04-11 16:52:08

by Arend van Spriel

[permalink] [raw]
Subject: Re: Problems with regulatory domain support and BCM43224

On 04/11/2012 03:39 PM, Seth Forshee wrote:
> On Wed, Apr 11, 2012 at 12:16:40PM +0200, Arend van Spriel wrote:
>> On 04/10/2012 06:28 PM, Seth Forshee wrote:
>>>> The patch builds, and kind of works. Scanning seems to be fine; I can
>>>>> see all the APs I expect in my area, including the one on a DFS channel
>>>>> that I couldn't see previously. I can associate with my 2.4 GHz APs, but
>>>>> not the 5 GHz AP. I see timme outs waiting for probe responses, and I'm
>>>>> hitting the WARN_ON_ONCE in brcms_c_wait_for_tx_completion(). I haven't
>>>>> really debugged this yet -- I thought I'd send out the patch to collect
>>>>> comments while I debug. Suggestions of what's causing this are also
>>>>> welcome:)
>>> This was due to always passing true for the value of mute_tx to
>>> brcms_b_set_chanspec() on passive channels. For now I'm just always
>>> passing false, which looks like it ought to be okay as we shouldn't have
>>> any tx on passive channels unless beacons are seen on the channel.
>>
>> Yes. I discovered this as well. Actually, I sent out a patch for
>> some people to test it. I submitted a slightly different patch to
>> John in which tx in unmuted upon receiving a beacon.
>
> I assume you're talking about this patch?
>
> http://www.spinics.net/lists/linux-wireless/msg88107.html
>
> My original changes would mute tx whenever IEEE80211_CHAN_PASSIVE_SCAN
> is set for the current channel. I'll try that again with your patch.
>

That is the one.

>>>>> One of the major unresolved issues in the patch is what to do with the
>>>>> data in struct locale_mimo_info. The regulatory rules only hold one
>>>>> power level. I'm unsure why the brcmsmac implementation differs in this
>>>>> regard. Suggestions?
>>> This is still one of the largest unsolved issues. I'm probably going to
>>> need some advice on how to fill out the txpwr information when
>>> regualtory rules external to the driver can be applied.
>>>
>>
>> The power constraints for HT (covered by struct locale_mimo_info)
>> are handled differently from non-HT. I have to confirm internally
>> whether this is specific for our devices or actually needed to be
>> compliant.
>
> Great, thanks.
>

No answer on this one yet, but keep you posted.

Gr. AvS


2012-04-04 02:46:40

by Seth Forshee

[permalink] [raw]
Subject: Re: Problems with regulatory domain support and BCM43224

On Mon, Mar 26, 2012 at 02:36:08PM -0500, Seth Forshee wrote:
> I've been studying the existing brcmsmac regulatory code in more detail,
> and I think there's a lot of potential to make the integration with the
> core regulatory support much better. I'm still making my way through
> some of the code, but here's what I see so far.
>
> Once full and accurate regdomain information is provided to the core
> regulatory code, all the code in channel.c that's checking against
> regulatory constraints can be eliminated, as that will get done at a
> higher level. I think the code to set the Tx power should also be
> reworked to use the constraints from the core regdom code. At that point
> the need for the custom regdom structures is mostly eliminated.
>
> I'm going to start toying with implementing some of this this week, time
> permitting. I think X2 is the only domain I have enough information on
> to realistically implement. But even with that one it would be helpful
> to understand what it's meant to represent, as Luis pointed out.
>
> I have one other question as well. Does the data in channel.c generally
> represent the most permissive regulatory parameters that ought to be
> used? That's the assumption I'm working under right now.

Below is a diff of the changes I've made locally to the brcmsmac
regulatory support. I haven't started thinking about dividing it up into
more digestible chunks, so for now it's just one massive diff. I've made
a lot of progress towards moving brcmsmac away from its custom formats
for regulatory information, but there are a few points I'm still having
difficulty with.

The patch builds, and kind of works. Scanning seems to be fine; I can
see all the APs I expect in my area, including the one on a DFS channel
that I couldn't see previously. I can associate with my 2.4 GHz APs, but
not the 5 GHz AP. I see timme outs waiting for probe responses, and I'm
hitting the WARN_ON_ONCE in brcms_c_wait_for_tx_completion(). I haven't
really debugged this yet -- I thought I'd send out the patch to collect
comments while I debug. Suggestions of what's causing this are also
welcome :)

One of the major unresolved issues in the patch is what to do with the
data in struct locale_mimo_info. The regulatory rules only hold one
power level. I'm unsure why the brcmsmac implementation differs in this
regard. Suggestions?

The txpwr calculations are modified, both to use the regdomain data so
far as possible and to eliminate redundant code. I'd appreciate review
of these changes in addition to the suggestions on how to handle the
MIMO power limits as I've already mentioned.

Initialization has also changed somewhat. The piece that looks most
significant to me is that wlc_phy_txpower_limit_set() gets called later,
not until after the ieee80211_hw device is registered.

Beyond these I still have a number of comments with my initials (SAF)
that contain questions, comments, and TODOs. Feedback regarding these
items, or anything else, are greatly appreciated.

Looking forward to your comments.

Thanks,
Seth


diff --git a/drivers/net/wireless/brcm80211/brcmsmac/channel.c b/drivers/net/wireless/brcm80211/brcmsmac/channel.c
index 55e9f45..d963f2a 100644
--- a/drivers/net/wireless/brcm80211/brcmsmac/channel.c
+++ b/drivers/net/wireless/brcm80211/brcmsmac/channel.c
@@ -15,7 +15,10 @@
*/

#include <linux/types.h>
+#include <linux/bitops.h>
#include <net/mac80211.h>
+#include <net/cfg80211.h>
+#include <net/regulatory.h>

#include <defs.h>
#include "pub.h"
@@ -23,54 +26,48 @@
#include "main.h"
#include "stf.h"
#include "channel.h"
+#include "mac80211_if.h"
+
+#define BRCM_2GHZ_2412_2462 REG_RULE(2412-10, 2462+10, 40, 0, 19, 0)
+#define BRCM_2GHZ_2467_2472 REG_RULE(2467-10, 2472+10, 20, 0, 19, \
+ NL80211_RRF_PASSIVE_SCAN | \
+ NL80211_RRF_NO_IBSS)
+#define BRCM_2GHZ_2484 REG_RULE(2484-10, 2484+10, 40, 0, 19, \
+ NL80211_RRF_PASSIVE_SCAN | \
+ NL80211_RRF_NO_OFDM)
+
+#define BRCM_5GHZ_5180_5240 REG_RULE(5180-10, 5240+10, 40, 0, 21, \
+ NL80211_RRF_PASSIVE_SCAN | \
+ NL80211_RRF_NO_IBSS)
+#define BRCM_5GHZ_5260_5320 REG_RULE(5260-10, 5320+10, 40, 0, 21, \
+ NL80211_RRF_PASSIVE_SCAN | \
+ NL80211_RRF_DFS | \
+ NL80211_RRF_NO_IBSS)
+#define BRCM_5GHZ_5500_5700 REG_RULE(5500-10, 5700+10, 40, 0, 21, \
+ NL80211_RRF_PASSIVE_SCAN | \
+ NL80211_RRF_DFS | \
+ NL80211_RRF_NO_IBSS)
+#define BRCM_5GHZ_5745_5825 REG_RULE(5745-10, 5825+10, 40, 0, 21, \
+ NL80211_RRF_PASSIVE_SCAN | \
+ NL80211_RRF_NO_IBSS)
+
+static const struct ieee80211_regdomain brcms_regdom_x2 = {
+ .n_reg_rules = 7,
+ .alpha2 = "X2",
+ .reg_rules = {
+ BRCM_2GHZ_2412_2462,
+ BRCM_2GHZ_2467_2472,
+ BRCM_2GHZ_2484,
+ BRCM_5GHZ_5180_5240,
+ BRCM_5GHZ_5260_5320,
+ BRCM_5GHZ_5500_5700,
+ BRCM_5GHZ_5745_5825,
+ }
+};

/* QDB() macro takes a dB value and converts to a quarter dB value */
#define QDB(n) ((n) * BRCMS_TXPWR_DB_FACTOR)

-#define LOCALE_CHAN_01_11 (1<<0)
-#define LOCALE_CHAN_12_13 (1<<1)
-#define LOCALE_CHAN_14 (1<<2)
-#define LOCALE_SET_5G_LOW_JP1 (1<<3) /* 34-48, step 2 */
-#define LOCALE_SET_5G_LOW_JP2 (1<<4) /* 34-46, step 4 */
-#define LOCALE_SET_5G_LOW1 (1<<5) /* 36-48, step 4 */
-#define LOCALE_SET_5G_LOW2 (1<<6) /* 52 */
-#define LOCALE_SET_5G_LOW3 (1<<7) /* 56-64, step 4 */
-#define LOCALE_SET_5G_MID1 (1<<8) /* 100-116, step 4 */
-#define LOCALE_SET_5G_MID2 (1<<9) /* 120-124, step 4 */
-#define LOCALE_SET_5G_MID3 (1<<10) /* 128 */
-#define LOCALE_SET_5G_HIGH1 (1<<11) /* 132-140, step 4 */
-#define LOCALE_SET_5G_HIGH2 (1<<12) /* 149-161, step 4 */
-#define LOCALE_SET_5G_HIGH3 (1<<13) /* 165 */
-#define LOCALE_CHAN_52_140_ALL (1<<14)
-#define LOCALE_SET_5G_HIGH4 (1<<15) /* 184-216 */
-
-#define LOCALE_CHAN_36_64 (LOCALE_SET_5G_LOW1 | \
- LOCALE_SET_5G_LOW2 | \
- LOCALE_SET_5G_LOW3)
-#define LOCALE_CHAN_52_64 (LOCALE_SET_5G_LOW2 | LOCALE_SET_5G_LOW3)
-#define LOCALE_CHAN_100_124 (LOCALE_SET_5G_MID1 | LOCALE_SET_5G_MID2)
-#define LOCALE_CHAN_100_140 (LOCALE_SET_5G_MID1 | LOCALE_SET_5G_MID2 | \
- LOCALE_SET_5G_MID3 | LOCALE_SET_5G_HIGH1)
-#define LOCALE_CHAN_149_165 (LOCALE_SET_5G_HIGH2 | LOCALE_SET_5G_HIGH3)
-#define LOCALE_CHAN_184_216 LOCALE_SET_5G_HIGH4
-
-#define LOCALE_CHAN_01_14 (LOCALE_CHAN_01_11 | \
- LOCALE_CHAN_12_13 | \
- LOCALE_CHAN_14)
-
-#define LOCALE_RADAR_SET_NONE 0
-#define LOCALE_RADAR_SET_1 1
-
-#define LOCALE_RESTRICTED_NONE 0
-#define LOCALE_RESTRICTED_SET_2G_SHORT 1
-#define LOCALE_RESTRICTED_CHAN_165 2
-#define LOCALE_CHAN_ALL_5G 3
-#define LOCALE_RESTRICTED_JAPAN_LEGACY 4
-#define LOCALE_RESTRICTED_11D_2G 5
-#define LOCALE_RESTRICTED_11D_5G 6
-#define LOCALE_RESTRICTED_LOW_HI 7
-#define LOCALE_RESTRICTED_12_13_14 8
-
#define LOCALE_2G_IDX_i 0
#define LOCALE_5G_IDX_11 0
#define LOCALE_MIMO_IDX_bn 0
@@ -118,18 +115,12 @@
(((c) < 100) ? 2 : \
(((c) < 149) ? 3 : 4))))

-#define ISDFS_EU(fl) (((fl) & BRCMS_DFS_EU) == BRCMS_DFS_EU)
-
+/*
+ * SAF: This can be eliminated once we know what to do with locale_flags
+ */
struct brcms_cm_band {
/* struct locale_info flags */
u8 locale_flags;
- /* List of valid channels in the country */
- struct brcms_chanvec valid_channels;
- /* List of restricted use channels */
- const struct brcms_chanvec *restricted_channels;
- /* List of radar sensitive channels */
- const struct brcms_chanvec *radar_channels;
- u8 PAD[8];
};

/* locale per-channel tx power limits for MIMO frames
@@ -141,6 +132,7 @@ struct locale_mimo_info {
s8 maxpwr20[BRCMS_MAXPWR_MIMO_TBL_SIZE];
/* tx 40 MHz power limits, qdBm units */
s8 maxpwr40[BRCMS_MAXPWR_MIMO_TBL_SIZE];
+ /* SAF: We should be able to get rid of flags */
u8 flags;
};

@@ -152,301 +144,40 @@ struct country_info {
const u8 locale_mimo_5G; /* 5G mimo info */
};

+struct brcms_regd {
+ char abbrev[BRCM_CNTRY_BUF_SZ]; /* country abbreviation */
+ struct country_info country;
+ const struct ieee80211_regdomain *regdomain;
+};
+
struct brcms_cm_info {
struct brcms_pub *pub;
struct brcms_c_info *wlc;
+ const struct brcms_regd *world_regd;
char srom_ccode[BRCM_CNTRY_BUF_SZ]; /* Country Code in SROM */
- uint srom_regrev; /* Regulatory Rev for the SROM ccode */
- const struct country_info *country; /* current country def */
- char ccode[BRCM_CNTRY_BUF_SZ]; /* current internal Country Code */
- uint regrev; /* current Regulatory Revision */
- char country_abbrev[BRCM_CNTRY_BUF_SZ]; /* current advertised ccode */
/* per-band state (one per phy/radio) */
struct brcms_cm_band bandstate[MAXBANDS];
- /* quiet channels currently for radar sensitivity or 11h support */
- /* channels on which we cannot transmit */
- struct brcms_chanvec quiet_channels;
};

/* locale channel and power info. */
struct locale_info {
- u32 valid_channels;
- /* List of radar sensitive channels */
- u8 radar_channels;
- /* List of channels used only if APs are detected */
- u8 restricted_channels;
/* Max tx pwr in qdBm for each sub-band */
s8 maxpwr[BRCMS_MAXPWR_TBL_SIZE];
/* Country IE advertised max tx pwr in dBm per sub-band */
s8 pub_maxpwr[BAND_5G_PWR_LVLS];
+ /* SAF: We should be able to get rid of flags */
u8 flags;
};

-/* Regulatory Matrix Spreadsheet (CLM) MIMO v3.7.9 */
-
-/*
- * Some common channel sets
- */
-
-/* No channels */
-static const struct brcms_chanvec chanvec_none = {
- {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00}
-};
-
-/* All 2.4 GHz HW channels */
-static const struct brcms_chanvec chanvec_all_2G = {
- {0xfe, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00}
-};
-
-/* All 5 GHz HW channels */
-static const struct brcms_chanvec chanvec_all_5G = {
- {0x00, 0x00, 0x00, 0x00, 0x54, 0x55, 0x11, 0x11,
- 0x01, 0x00, 0x00, 0x00, 0x10, 0x11, 0x11, 0x11,
- 0x11, 0x11, 0x20, 0x22, 0x22, 0x00, 0x00, 0x11,
- 0x11, 0x11, 0x11, 0x01}
-};
-
-/*
- * Radar channel sets
- */
-
-/* Channels 52 - 64, 100 - 140 */
-static const struct brcms_chanvec radar_set1 = {
- {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x11, /* 52 - 60 */
- 0x01, 0x00, 0x00, 0x00, 0x10, 0x11, 0x11, 0x11, /* 64, 100 - 124 */
- 0x11, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 128 - 140 */
- 0x00, 0x00, 0x00, 0x00}
-};
-
-/*
- * Restricted channel sets
- */
-
-/* Channels 34, 38, 42, 46 */
-static const struct brcms_chanvec restricted_set_japan_legacy = {
- {0x00, 0x00, 0x00, 0x00, 0x44, 0x44, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00}
-};
-
-/* Channels 12, 13 */
-static const struct brcms_chanvec restricted_set_2g_short = {
- {0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00}
-};
-
-/* Channel 165 */
-static const struct brcms_chanvec restricted_chan_165 = {
- {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00}
-};
-
-/* Channels 36 - 48 & 149 - 165 */
-static const struct brcms_chanvec restricted_low_hi = {
- {0x00, 0x00, 0x00, 0x00, 0x10, 0x11, 0x01, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x20, 0x22, 0x22, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00}
-};
-
-/* Channels 12 - 14 */
-static const struct brcms_chanvec restricted_set_12_13_14 = {
- {0x00, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00}
-};
-
-/* global memory to provide working buffer for expanded locale */
-
-static const struct brcms_chanvec *g_table_radar_set[] = {
- &chanvec_none,
- &radar_set1
-};
-
-static const struct brcms_chanvec *g_table_restricted_chan[] = {
- &chanvec_none, /* restricted_set_none */
- &restricted_set_2g_short,
- &restricted_chan_165,
- &chanvec_all_5G,
- &restricted_set_japan_legacy,
- &chanvec_all_2G, /* restricted_set_11d_2G */
- &chanvec_all_5G, /* restricted_set_11d_5G */
- &restricted_low_hi,
- &restricted_set_12_13_14
-};
-
-static const struct brcms_chanvec locale_2g_01_11 = {
- {0xfe, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00}
-};
-
-static const struct brcms_chanvec locale_2g_12_13 = {
- {0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00}
-};
-
-static const struct brcms_chanvec locale_2g_14 = {
- {0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00}
-};
-
-static const struct brcms_chanvec locale_5g_LOW_JP1 = {
- {0x00, 0x00, 0x00, 0x00, 0x54, 0x55, 0x01, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00}
-};
-
-static const struct brcms_chanvec locale_5g_LOW_JP2 = {
- {0x00, 0x00, 0x00, 0x00, 0x44, 0x44, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00}
-};
-
-static const struct brcms_chanvec locale_5g_LOW1 = {
- {0x00, 0x00, 0x00, 0x00, 0x10, 0x11, 0x01, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00}
-};
-
-static const struct brcms_chanvec locale_5g_LOW2 = {
- {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00}
-};
-
-static const struct brcms_chanvec locale_5g_LOW3 = {
- {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11,
- 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00}
-};
-
-static const struct brcms_chanvec locale_5g_MID1 = {
- {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x10, 0x11, 0x11, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00}
-};
-
-static const struct brcms_chanvec locale_5g_MID2 = {
- {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00}
-};
-
-static const struct brcms_chanvec locale_5g_MID3 = {
- {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00}
-};
-
-static const struct brcms_chanvec locale_5g_HIGH1 = {
- {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x10, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00}
-};
-
-static const struct brcms_chanvec locale_5g_HIGH2 = {
- {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x20, 0x22, 0x02, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00}
-};
-
-static const struct brcms_chanvec locale_5g_HIGH3 = {
- {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00}
-};
-
-static const struct brcms_chanvec locale_5g_52_140_ALL = {
- {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x11,
- 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
- 0x11, 0x11, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00}
-};
-
-static const struct brcms_chanvec locale_5g_HIGH4 = {
- {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11,
- 0x11, 0x11, 0x11, 0x11}
-};
-
-static const struct brcms_chanvec *g_table_locale_base[] = {
- &locale_2g_01_11,
- &locale_2g_12_13,
- &locale_2g_14,
- &locale_5g_LOW_JP1,
- &locale_5g_LOW_JP2,
- &locale_5g_LOW1,
- &locale_5g_LOW2,
- &locale_5g_LOW3,
- &locale_5g_MID1,
- &locale_5g_MID2,
- &locale_5g_MID3,
- &locale_5g_HIGH1,
- &locale_5g_HIGH2,
- &locale_5g_HIGH3,
- &locale_5g_52_140_ALL,
- &locale_5g_HIGH4
-};
-
-static void brcms_c_locale_add_channels(struct brcms_chanvec *target,
- const struct brcms_chanvec *channels)
+static inline struct wiphy *brcms_c_get_wiphy(struct brcms_cm_info *wlc_cm)
{
- u8 i;
- for (i = 0; i < sizeof(struct brcms_chanvec); i++)
- target->vec[i] |= channels->vec[i];
-}
-
-static void brcms_c_locale_get_channels(const struct locale_info *locale,
- struct brcms_chanvec *channels)
-{
- u8 i;
-
- memset(channels, 0, sizeof(struct brcms_chanvec));
-
- for (i = 0; i < ARRAY_SIZE(g_table_locale_base); i++) {
- if (locale->valid_channels & (1 << i))
- brcms_c_locale_add_channels(channels,
- g_table_locale_base[i]);
- }
+ return wlc_cm->pub->ieee_hw->wiphy;
}

/*
* Locale Definitions - 2.4 GHz
*/
static const struct locale_info locale_i = { /* locale i. channel 1 - 13 */
- LOCALE_CHAN_01_11 | LOCALE_CHAN_12_13,
- LOCALE_RADAR_SET_NONE,
- LOCALE_RESTRICTED_SET_2G_SHORT,
{QDB(19), QDB(19), QDB(19),
QDB(19), QDB(19), QDB(19)},
{20, 20, 20, 0},
@@ -457,10 +188,6 @@ static const struct locale_info locale_i = { /* locale i. channel 1 - 13 */
* Locale Definitions - 5 GHz
*/
static const struct locale_info locale_11 = {
- /* locale 11. channel 36 - 48, 52 - 64, 100 - 140, 149 - 165 */
- LOCALE_CHAN_36_64 | LOCALE_CHAN_100_140 | LOCALE_CHAN_149_165,
- LOCALE_RADAR_SET_1,
- LOCALE_RESTRICTED_NONE,
{QDB(21), QDB(21), QDB(21), QDB(21), QDB(21)},
{23, 23, 23, 30, 30},
BRCMS_EIRP | BRCMS_DFS_EU
@@ -504,90 +231,34 @@ static const struct locale_mimo_info *g_mimo_5g_table[] = {
&locale_11n
};

-static const struct {
- char abbrev[BRCM_CNTRY_BUF_SZ]; /* country abbreviation */
- struct country_info country;
-} cntry_locales[] = {
+static const struct brcms_regd cntry_locales[] = {
+ /* Worldwide Row 2, must always be at index 0 */
{
- "X2", LOCALES(i, 11, bn, 11n)}, /* Worldwide RoW 2 */
+ .abbrev = "X2",
+ .country = LOCALES(i, 11, bn, 11n),
+ .regdomain = &brcms_regdom_x2,
+ },
};

-#ifdef SUPPORT_40MHZ
-/* 20MHz channel info for 40MHz pairing support */
-struct chan20_info {
- u8 sb;
- u8 adj_sbs;
-};
+static const struct brcms_regd *brcms_world_regd(const char *regdom)
+{
+ const struct brcms_regd *regd = NULL;
+ int i;

-/* indicates adjacent channels that are allowed for a 40 Mhz channel and
- * those that permitted by the HT
- */
-struct chan20_info chan20_info[] = {
- /* 11b/11g */
-/* 0 */ {1, (CH_UPPER_SB | CH_EWA_VALID)},
-/* 1 */ {2, (CH_UPPER_SB | CH_EWA_VALID)},
-/* 2 */ {3, (CH_UPPER_SB | CH_EWA_VALID)},
-/* 3 */ {4, (CH_UPPER_SB | CH_EWA_VALID)},
-/* 4 */ {5, (CH_UPPER_SB | CH_LOWER_SB | CH_EWA_VALID)},
-/* 5 */ {6, (CH_UPPER_SB | CH_LOWER_SB | CH_EWA_VALID)},
-/* 6 */ {7, (CH_UPPER_SB | CH_LOWER_SB | CH_EWA_VALID)},
-/* 7 */ {8, (CH_UPPER_SB | CH_LOWER_SB | CH_EWA_VALID)},
-/* 8 */ {9, (CH_UPPER_SB | CH_LOWER_SB | CH_EWA_VALID)},
-/* 9 */ {10, (CH_LOWER_SB | CH_EWA_VALID)},
-/* 10 */ {11, (CH_LOWER_SB | CH_EWA_VALID)},
-/* 11 */ {12, (CH_LOWER_SB)},
-/* 12 */ {13, (CH_LOWER_SB)},
-/* 13 */ {14, (CH_LOWER_SB)},
-
-/* 11a japan high */
-/* 14 */ {34, (CH_UPPER_SB)},
-/* 15 */ {38, (CH_LOWER_SB)},
-/* 16 */ {42, (CH_LOWER_SB)},
-/* 17 */ {46, (CH_LOWER_SB)},
-
-/* 11a usa low */
-/* 18 */ {36, (CH_UPPER_SB | CH_EWA_VALID)},
-/* 19 */ {40, (CH_LOWER_SB | CH_EWA_VALID)},
-/* 20 */ {44, (CH_UPPER_SB | CH_EWA_VALID)},
-/* 21 */ {48, (CH_LOWER_SB | CH_EWA_VALID)},
-/* 22 */ {52, (CH_UPPER_SB | CH_EWA_VALID)},
-/* 23 */ {56, (CH_LOWER_SB | CH_EWA_VALID)},
-/* 24 */ {60, (CH_UPPER_SB | CH_EWA_VALID)},
-/* 25 */ {64, (CH_LOWER_SB | CH_EWA_VALID)},
-
-/* 11a Europe */
-/* 26 */ {100, (CH_UPPER_SB | CH_EWA_VALID)},
-/* 27 */ {104, (CH_LOWER_SB | CH_EWA_VALID)},
-/* 28 */ {108, (CH_UPPER_SB | CH_EWA_VALID)},
-/* 29 */ {112, (CH_LOWER_SB | CH_EWA_VALID)},
-/* 30 */ {116, (CH_UPPER_SB | CH_EWA_VALID)},
-/* 31 */ {120, (CH_LOWER_SB | CH_EWA_VALID)},
-/* 32 */ {124, (CH_UPPER_SB | CH_EWA_VALID)},
-/* 33 */ {128, (CH_LOWER_SB | CH_EWA_VALID)},
-/* 34 */ {132, (CH_UPPER_SB | CH_EWA_VALID)},
-/* 35 */ {136, (CH_LOWER_SB | CH_EWA_VALID)},
-/* 36 */ {140, (CH_LOWER_SB)},
-
-/* 11a usa high, ref5 only */
-/* The 0x80 bit in pdiv means these are REF5, other entries are REF20 */
-/* 37 */ {149, (CH_UPPER_SB | CH_EWA_VALID)},
-/* 38 */ {153, (CH_LOWER_SB | CH_EWA_VALID)},
-/* 39 */ {157, (CH_UPPER_SB | CH_EWA_VALID)},
-/* 40 */ {161, (CH_LOWER_SB | CH_EWA_VALID)},
-/* 41 */ {165, (CH_LOWER_SB)},
-
-/* 11a japan */
-/* 42 */ {184, (CH_UPPER_SB)},
-/* 43 */ {188, (CH_LOWER_SB)},
-/* 44 */ {192, (CH_UPPER_SB)},
-/* 45 */ {196, (CH_LOWER_SB)},
-/* 46 */ {200, (CH_UPPER_SB)},
-/* 47 */ {204, (CH_LOWER_SB)},
-/* 48 */ {208, (CH_UPPER_SB)},
-/* 49 */ {212, (CH_LOWER_SB)},
-/* 50 */ {216, (CH_LOWER_SB)}
-};
-#endif /* SUPPORT_40MHZ */
+ for (i = 0; i < ARRAY_SIZE(cntry_locales); i++) {
+ if (!strcmp(regdom, cntry_locales[i].abbrev)) {
+ regd = &cntry_locales[i];
+ break;
+ }
+ }
+
+ return regd;
+}
+
+static const struct brcms_regd *brcms_default_world_regd(void)
+{
+ return &cntry_locales[0];
+}

static const struct locale_info *brcms_c_get_locale_2g(u8 locale_idx)
{
@@ -621,164 +292,6 @@ static const struct locale_mimo_info *brcms_c_get_mimo_5g(u8 locale_idx)
return g_mimo_5g_table[locale_idx];
}

-static int
-brcms_c_country_aggregate_map(struct brcms_cm_info *wlc_cm, const char *ccode,
- char *mapped_ccode, uint *mapped_regrev)
-{
- return false;
-}
-
-/* Lookup a country info structure from a null terminated country
- * abbreviation and regrev directly with no translation.
- */
-static const struct country_info *
-brcms_c_country_lookup_direct(const char *ccode, uint regrev)
-{
- uint size, i;
-
- /* Should just return 0 for single locale driver. */
- /* Keep it this way in case we add more locales. (for now anyway) */
-
- /*
- * all other country def arrays are for regrev == 0, so if
- * regrev is non-zero, fail
- */
- if (regrev > 0)
- return NULL;
-
- /* find matched table entry from country code */
- size = ARRAY_SIZE(cntry_locales);
- for (i = 0; i < size; i++) {
- if (strcmp(ccode, cntry_locales[i].abbrev) == 0)
- return &cntry_locales[i].country;
- }
- return NULL;
-}
-
-static const struct country_info *
-brcms_c_countrycode_map(struct brcms_cm_info *wlc_cm, const char *ccode,
- char *mapped_ccode, uint *mapped_regrev)
-{
- struct brcms_c_info *wlc = wlc_cm->wlc;
- const struct country_info *country;
- uint srom_regrev = wlc_cm->srom_regrev;
- const char *srom_ccode = wlc_cm->srom_ccode;
- int mapped;
-
- /* check for currently supported ccode size */
- if (strlen(ccode) > (BRCM_CNTRY_BUF_SZ - 1)) {
- wiphy_err(wlc->wiphy, "wl%d: %s: ccode \"%s\" too long for "
- "match\n", wlc->pub->unit, __func__, ccode);
- return NULL;
- }
-
- /* default mapping is the given ccode and regrev 0 */
- strncpy(mapped_ccode, ccode, BRCM_CNTRY_BUF_SZ);
- *mapped_regrev = 0;
-
- /* If the desired country code matches the srom country code,
- * then the mapped country is the srom regulatory rev.
- * Otherwise look for an aggregate mapping.
- */
- if (!strcmp(srom_ccode, ccode)) {
- *mapped_regrev = srom_regrev;
- mapped = 0;
- wiphy_err(wlc->wiphy, "srom_code == ccode %s\n", __func__);
- } else {
- mapped =
- brcms_c_country_aggregate_map(wlc_cm, ccode, mapped_ccode,
- mapped_regrev);
- }
-
- /* find the matching built-in country definition */
- country = brcms_c_country_lookup_direct(mapped_ccode, *mapped_regrev);
-
- /* if there is not an exact rev match, default to rev zero */
- if (country == NULL && *mapped_regrev != 0) {
- *mapped_regrev = 0;
- country =
- brcms_c_country_lookup_direct(mapped_ccode, *mapped_regrev);
- }
-
- return country;
-}
-
-/* Lookup a country info structure from a null terminated country code
- * The lookup is case sensitive.
- */
-static const struct country_info *
-brcms_c_country_lookup(struct brcms_c_info *wlc, const char *ccode)
-{
- const struct country_info *country;
- char mapped_ccode[BRCM_CNTRY_BUF_SZ];
- uint mapped_regrev;
-
- /*
- * map the country code to a built-in country code, regrev, and
- * country_info struct
- */
- country = brcms_c_countrycode_map(wlc->cmi, ccode, mapped_ccode,
- &mapped_regrev);
-
- return country;
-}
-
-/*
- * reset the quiet channels vector to the union
- * of the restricted and radar channel sets
- */
-static void brcms_c_quiet_channels_reset(struct brcms_cm_info *wlc_cm)
-{
- struct brcms_c_info *wlc = wlc_cm->wlc;
- uint i, j;
- struct brcms_band *band;
- const struct brcms_chanvec *chanvec;
-
- memset(&wlc_cm->quiet_channels, 0, sizeof(struct brcms_chanvec));
-
- band = wlc->band;
- for (i = 0; i < wlc->pub->_nbands;
- i++, band = wlc->bandstate[OTHERBANDUNIT(wlc)]) {
-
- /* initialize quiet channels for restricted channels */
- chanvec = wlc_cm->bandstate[band->bandunit].restricted_channels;
- for (j = 0; j < sizeof(struct brcms_chanvec); j++)
- wlc_cm->quiet_channels.vec[j] |= chanvec->vec[j];
-
- }
-}
-
-/* Is the channel valid for the current locale and current band? */
-static bool brcms_c_valid_channel20(struct brcms_cm_info *wlc_cm, uint val)
-{
- struct brcms_c_info *wlc = wlc_cm->wlc;
-
- return ((val < MAXCHANNEL) &&
- isset(wlc_cm->bandstate[wlc->band->bandunit].valid_channels.vec,
- val));
-}
-
-/* Is the channel valid for the current locale and specified band? */
-static bool brcms_c_valid_channel20_in_band(struct brcms_cm_info *wlc_cm,
- uint bandunit, uint val)
-{
- return ((val < MAXCHANNEL)
- && isset(wlc_cm->bandstate[bandunit].valid_channels.vec, val));
-}
-
-/* Is the channel valid for the current locale? (but don't consider channels not
- * available due to bandlocking)
- */
-static bool brcms_c_valid_channel20_db(struct brcms_cm_info *wlc_cm, uint val)
-{
- struct brcms_c_info *wlc = wlc_cm->wlc;
-
- return brcms_c_valid_channel20(wlc->cmi, val) ||
- (!wlc->bandlocked
- && brcms_c_valid_channel20_in_band(wlc->cmi,
- OTHERBANDUNIT(wlc), val));
-}
-
/* JP, J1 - J10 are Japan ccodes */
static bool brcms_c_japan_ccode(const char *ccode)
{
@@ -786,12 +299,6 @@ static bool brcms_c_japan_ccode(const char *ccode)
(ccode[1] == 'P' || (ccode[1] >= '1' && ccode[1] <= '9')));
}

-/* Returns true if currently set country is Japan or variant */
-static bool brcms_c_japan(struct brcms_c_info *wlc)
-{
- return brcms_c_japan_ccode(wlc->cmi->country_abbrev);
-}
-
static void
brcms_c_channel_min_txpower_limits_with_local_constraint(
struct brcms_cm_info *wlc_cm, struct txpwr_limits *txpwr,
@@ -867,74 +374,45 @@ brcms_c_channel_min_txpower_limits_with_local_constraint(

}

+/*
+ * SAF: Is this needed? We don't have channel information until
+ * ieee80211_register_hw is called.
+ */
+#if 0
/* Update the radio state (enable/disable) and tx power targets
* based on a new set of channel/regulatory information
*/
static void brcms_c_channels_commit(struct brcms_cm_info *wlc_cm)
{
+ struct ieee80211_channel *ch = wlc_cm->pub->ieee_hw->conf.channel;
+ u16 chanspec = ch20mhz_chspec(ch->hw_value);
struct brcms_c_info *wlc = wlc_cm->wlc;
- uint chan;
struct txpwr_limits txpwr;

- /* search for the existence of any valid channel */
- for (chan = 0; chan < MAXCHANNEL; chan++) {
- if (brcms_c_valid_channel20_db(wlc->cmi, chan))
- break;
- }
- if (chan == MAXCHANNEL)
- chan = INVCHANNEL;
-
- /*
- * based on the channel search above, set or
- * clear WL_RADIO_COUNTRY_DISABLE.
- */
- if (chan == INVCHANNEL) {
- /*
- * country/locale with no valid channels, set
- * the radio disable bit
- */
- mboolset(wlc->pub->radio_disabled, WL_RADIO_COUNTRY_DISABLE);
- wiphy_err(wlc->wiphy, "wl%d: %s: no valid channel for \"%s\" "
- "nbands %d bandlocked %d\n", wlc->pub->unit,
- __func__, wlc_cm->country_abbrev, wlc->pub->_nbands,
- wlc->bandlocked);
- } else if (mboolisset(wlc->pub->radio_disabled,
- WL_RADIO_COUNTRY_DISABLE)) {
- /*
- * country/locale with valid channel, clear
- * the radio disable bit
- */
- mboolclr(wlc->pub->radio_disabled, WL_RADIO_COUNTRY_DISABLE);
- }
-
- /*
- * Now that the country abbreviation is set, if the radio supports 2G,
- * then set channel 14 restrictions based on the new locale.
- */
- if (wlc->pub->_nbands > 1 || wlc->band->bandtype == BRCM_BAND_2G)
- wlc_phy_chanspec_ch14_widefilter_set(wlc->band->pi,
- brcms_c_japan(wlc) ? true :
- false);
-
- if (wlc->pub->up && chan != INVCHANNEL) {
- brcms_c_channel_reg_limits(wlc_cm, wlc->chanspec, &txpwr);
+ if (wlc->pub->up) {
+ brcms_c_channel_reg_limits(wlc_cm, chanspec, ch, &txpwr);
brcms_c_channel_min_txpower_limits_with_local_constraint(wlc_cm,
&txpwr, BRCMS_TXPWR_MAX);
- wlc_phy_txpower_limit_set(wlc->band->pi, &txpwr, wlc->chanspec);
+ wlc_phy_txpower_limit_set(wlc->band->pi, &txpwr, chanspec);
}
}
+#endif

static int
brcms_c_channels_init(struct brcms_cm_info *wlc_cm,
const struct country_info *country)
{
struct brcms_c_info *wlc = wlc_cm->wlc;
- uint i, j;
+ uint i;
struct brcms_band *band;
const struct locale_info *li;
- struct brcms_chanvec sup_chan;
const struct locale_mimo_info *li_mimo;

+ /*
+ * SAF: This should work out to be unnecessary. Locale flags are
+ * the only thing that remain, and we should be getting the same
+ * information from other sources.
+ */
band = wlc->band;
for (i = 0; i < wlc->pub->_nbands;
i++, band = wlc->bandstate[OTHERBANDUNIT(wlc)]) {
@@ -950,28 +428,15 @@ brcms_c_channels_init(struct brcms_cm_info *wlc_cm,
/* merge the mimo non-mimo locale flags */
wlc_cm->bandstate[band->bandunit].locale_flags |=
li_mimo->flags;
-
- wlc_cm->bandstate[band->bandunit].restricted_channels =
- g_table_restricted_chan[li->restricted_channels];
- wlc_cm->bandstate[band->bandunit].radar_channels =
- g_table_radar_set[li->radar_channels];
-
- /*
- * set the channel availability, masking out the channels
- * that may not be supported on this phy.
- */
- wlc_phy_chanspec_band_validch(band->pi, band->bandtype,
- &sup_chan);
- brcms_c_locale_get_channels(li,
- &wlc_cm->bandstate[band->bandunit].
- valid_channels);
- for (j = 0; j < sizeof(struct brcms_chanvec); j++)
- wlc_cm->bandstate[band->bandunit].valid_channels.
- vec[j] &= sup_chan.vec[j];
}

- brcms_c_quiet_channels_reset(wlc_cm);
+ /*
+ * SAF: Can't really do this here since we don't have a channel
+ * or regulatory information yet.
+ */
+#if 0
brcms_c_channels_commit(wlc_cm);
+#endif

return 0;
}
@@ -982,25 +447,14 @@ brcms_c_channels_init(struct brcms_cm_info *wlc_cm,
* information found with the country code.
*/
static void
-brcms_c_set_country_common(struct brcms_cm_info *wlc_cm,
- const char *country_abbrev,
- const char *ccode, uint regrev,
- const struct country_info *country)
+brcms_c_set_country(struct brcms_cm_info *wlc_cm,
+ const struct brcms_regd *regd)
{
+ const struct country_info *country = &regd->country;
+#if 0
const struct locale_info *locale;
+#endif
struct brcms_c_info *wlc = wlc_cm->wlc;
- char prev_country_abbrev[BRCM_CNTRY_BUF_SZ];
-
- /* save current country state */
- wlc_cm->country = country;
-
- memset(&prev_country_abbrev, 0, BRCM_CNTRY_BUF_SZ);
- strncpy(prev_country_abbrev, wlc_cm->country_abbrev,
- BRCM_CNTRY_BUF_SZ - 1);
-
- strncpy(wlc_cm->country_abbrev, country_abbrev, BRCM_CNTRY_BUF_SZ - 1);
- strncpy(wlc_cm->ccode, ccode, BRCM_CNTRY_BUF_SZ - 1);
- wlc_cm->regrev = regrev;

if ((wlc->pub->_n_enab & SUPPORT_11N) !=
wlc->protection->nmode_user)
@@ -1009,10 +463,17 @@ brcms_c_set_country_common(struct brcms_cm_info *wlc_cm,
brcms_c_stf_ss_update(wlc, wlc->bandstate[BAND_2G_INDEX]);
brcms_c_stf_ss_update(wlc, wlc->bandstate[BAND_5G_INDEX]);
/* set or restore gmode as required by regulatory */
+ /*
+ * SAF: Need to figure out how to determine gmode. Currently
+ * BRCMS_NO_OFDM is never set anyway. OFDM is disabled on a
+ * per-rule basis, not per-domain basis as is expected here.
+ */
+#if 0
locale = brcms_c_get_locale_2g(country->locale_2G);
if (locale && (locale->flags & BRCMS_NO_OFDM))
brcms_c_set_gmode(wlc, GMODE_LEGACY_B, false);
else
+#endif
brcms_c_set_gmode(wlc, wlc->protection->gmode_user, false);

brcms_c_channels_init(wlc_cm, country);
@@ -1020,63 +481,11 @@ brcms_c_set_country_common(struct brcms_cm_info *wlc_cm,
return;
}

-static int
-brcms_c_set_countrycode_rev(struct brcms_cm_info *wlc_cm,
- const char *country_abbrev,
- const char *ccode, int regrev)
-{
- const struct country_info *country;
- char mapped_ccode[BRCM_CNTRY_BUF_SZ];
- uint mapped_regrev;
-
- /* if regrev is -1, lookup the mapped country code,
- * otherwise use the ccode and regrev directly
- */
- if (regrev == -1) {
- /*
- * map the country code to a built-in country
- * code, regrev, and country_info
- */
- country =
- brcms_c_countrycode_map(wlc_cm, ccode, mapped_ccode,
- &mapped_regrev);
- } else {
- /* find the matching built-in country definition */
- country = brcms_c_country_lookup_direct(ccode, regrev);
- strncpy(mapped_ccode, ccode, BRCM_CNTRY_BUF_SZ);
- mapped_regrev = regrev;
- }
-
- if (country == NULL)
- return -EINVAL;
-
- /* set the driver state for the country */
- brcms_c_set_country_common(wlc_cm, country_abbrev, mapped_ccode,
- mapped_regrev, country);
-
- return 0;
-}
-
-/*
- * set the driver's current country and regulatory information using
- * a country code as the source. Lookup built in country information
- * found with the country code.
- */
-static int
-brcms_c_set_countrycode(struct brcms_cm_info *wlc_cm, const char *ccode)
-{
- char country_abbrev[BRCM_CNTRY_BUF_SZ];
- strncpy(country_abbrev, ccode, BRCM_CNTRY_BUF_SZ);
- return brcms_c_set_countrycode_rev(wlc_cm, country_abbrev, ccode, -1);
-}
-
struct brcms_cm_info *brcms_c_channel_mgr_attach(struct brcms_c_info *wlc)
{
struct brcms_cm_info *wlc_cm;
- char country_abbrev[BRCM_CNTRY_BUF_SZ];
- const struct country_info *country;
struct brcms_pub *pub = wlc->pub;
- char *ccode;
+ const char *ccode;

BCMMSG(wlc->wiphy, "wl%d\n", wlc->pub->unit);

@@ -1089,24 +498,27 @@ struct brcms_cm_info *brcms_c_channel_mgr_attach(struct brcms_c_info *wlc)

/* store the country code for passing up as a regulatory hint */
ccode = getvar(wlc->hw->sih, BRCMS_SROM_CCODE);
- if (ccode)
+ if (ccode) {
strncpy(wlc->pub->srom_ccode, ccode, BRCM_CNTRY_BUF_SZ - 1);
+ wlc_cm->world_regd = brcms_world_regd(ccode);
+ }

/*
- * internal country information which must match
- * regulatory constraints in firmware
+ * If no custom world domain is found in the SROM, use the
+ * default "X2" domain.
*/
- memset(country_abbrev, 0, BRCM_CNTRY_BUF_SZ);
- strncpy(country_abbrev, "X2", sizeof(country_abbrev) - 1);
- country = brcms_c_country_lookup(wlc, country_abbrev);
+ if (!wlc_cm->world_regd) {
+ ccode = "X2";
+ wlc_cm->world_regd = brcms_default_world_regd();
+ }

/* save default country for exiting 11d regulatory mode */
- strncpy(wlc->country_default, country_abbrev, BRCM_CNTRY_BUF_SZ - 1);
+ strncpy(wlc->country_default, ccode, BRCM_CNTRY_BUF_SZ - 1);

/* initialize autocountry_default to driver default */
- strncpy(wlc->autocountry_default, "X2", BRCM_CNTRY_BUF_SZ - 1);
+ strncpy(wlc->autocountry_default, ccode, BRCM_CNTRY_BUF_SZ - 1);

- brcms_c_set_countrycode(wlc_cm, country_abbrev);
+ brcms_c_set_country(wlc_cm, wlc_cm->world_regd);

return wlc_cm;
}
@@ -1116,6 +528,9 @@ void brcms_c_channel_mgr_detach(struct brcms_cm_info *wlc_cm)
kfree(wlc_cm);
}

+/*
+ * SAF: Need to use info from struct ieee80211_channel for this instead
+ */
u8
brcms_c_channel_locale_flags_in_band(struct brcms_cm_info *wlc_cm,
uint bandunit)
@@ -1123,38 +538,32 @@ brcms_c_channel_locale_flags_in_band(struct brcms_cm_info *wlc_cm,
return wlc_cm->bandstate[bandunit].locale_flags;
}

-static bool
-brcms_c_quiet_chanspec(struct brcms_cm_info *wlc_cm, u16 chspec)
-{
- return (wlc_cm->wlc->pub->_n_enab & SUPPORT_11N) &&
- CHSPEC_IS40(chspec) ?
- (isset(wlc_cm->quiet_channels.vec,
- lower_20_sb(CHSPEC_CHANNEL(chspec))) ||
- isset(wlc_cm->quiet_channels.vec,
- upper_20_sb(CHSPEC_CHANNEL(chspec)))) :
- isset(wlc_cm->quiet_channels.vec, CHSPEC_CHANNEL(chspec));
-}
-
void
brcms_c_channel_set_chanspec(struct brcms_cm_info *wlc_cm, u16 chanspec,
- u8 local_constraint_qdbm)
+ struct ieee80211_channel *channel,
+ u8 local_constraint_qdbm)
{
struct brcms_c_info *wlc = wlc_cm->wlc;
struct txpwr_limits txpwr;

- brcms_c_channel_reg_limits(wlc_cm, chanspec, &txpwr);
+ brcms_c_channel_reg_limits(wlc_cm, chanspec, channel, &txpwr);

brcms_c_channel_min_txpower_limits_with_local_constraint(
wlc_cm, &txpwr, local_constraint_qdbm
);

brcms_b_set_chanspec(wlc->hw, chanspec,
- (brcms_c_quiet_chanspec(wlc_cm, chanspec) != 0),
- &txpwr);
+ !!(channel->flags & IEEE80211_CHAN_PASSIVE_SCAN),
+ &txpwr);
}

+/*
+ * SAF: Much of the data here still comes from internal structures, but
+ * I'm not sure where else to store this data.
+ */
void
brcms_c_channel_reg_limits(struct brcms_cm_info *wlc_cm, u16 chanspec,
+ struct ieee80211_channel *channel,
struct txpwr_limits *txpwr)
{
struct brcms_c_info *wlc = wlc_cm->wlc;
@@ -1166,7 +575,6 @@ brcms_c_channel_reg_limits(struct brcms_cm_info *wlc_cm, u16 chanspec,
struct brcms_band *band;
const struct locale_info *li;
int conducted_max = BRCMS_TXPWR_MAX;
- int conducted_ofdm_max = BRCMS_TXPWR_MAX;
const struct locale_mimo_info *li_mimo;
int maxpwr20, maxpwr40;
int maxpwr_idx;
@@ -1174,14 +582,22 @@ brcms_c_channel_reg_limits(struct brcms_cm_info *wlc_cm, u16 chanspec,

memset(txpwr, 0, sizeof(struct txpwr_limits));

- if (!brcms_c_valid_chanspec_db(wlc_cm, chanspec)) {
- country = brcms_c_country_lookup(wlc, wlc->autocountry_default);
- if (country == NULL)
- return;
- } else {
- country = wlc_cm->country;
- }
+ /*
+ * SAF: What to do if we don't have a channel?
+ */
+ if (WARN_ON(!channel))
+ return;

+ /*
+ * SAF: Will this even work properly if the chanspec isn't valid?
+ * Previously the code would proceed, but for now let's warn and
+ * return. In reality if channel is valid then chanspec should be
+ * valid as well.
+ */
+ if (WARN_ON(!brcms_c_valid_chanspec_db(wlc_cm, chanspec)))
+ return;
+
+ country = &wlc_cm->world_regd->country;
chan = CHSPEC_CHANNEL(chanspec);
band = wlc->bandstate[chspec_bandunit(chanspec)];
li = (band->bandtype == BRCM_BAND_5G) ?
@@ -1192,6 +608,10 @@ brcms_c_channel_reg_limits(struct brcms_cm_info *wlc_cm, u16 chanspec,
brcms_c_get_mimo_5g(country->locale_mimo_5G) :
brcms_c_get_mimo_2g(country->locale_mimo_2G);

+ /*
+ * SAF: Currently all locales have BRCMS_EIRP set, so only first
+ * case matters.
+ */
if (li->flags & BRCMS_EIRP) {
delta = band->antgain;
} else {
@@ -1200,41 +620,28 @@ brcms_c_channel_reg_limits(struct brcms_cm_info *wlc_cm, u16 chanspec,
delta = band->antgain - QDB(6); /* Excess over 6 dB */
}

- if (li == &locale_i) {
+ /*
+ * SAF: After this function is done,
+ * brcms_c_channel_min_txpower_limits_with_local_constraint() is
+ * going to clamp down all these values to BRCMS_TXPWR_MAX anyway.
+ * So what's the point of conducted_max?
+ */
+ if (li == &locale_i)
conducted_max = QDB(22);
- conducted_ofdm_max = QDB(22);
- }
+
+ maxpwr = QDB(channel->max_power) - delta;
+ maxpwr = max(maxpwr, 0);
+ maxpwr = min(maxpwr, conducted_max);

/* CCK txpwr limits for 2.4G band */
if (band->bandtype == BRCM_BAND_2G) {
- maxpwr = li->maxpwr[CHANNEL_POWER_IDX_2G_CCK(chan)];
-
- maxpwr = maxpwr - delta;
- maxpwr = max(maxpwr, 0);
- maxpwr = min(maxpwr, conducted_max);
-
for (i = 0; i < BRCMS_NUM_RATES_CCK; i++)
txpwr->cck[i] = (u8) maxpwr;
}

- /* OFDM txpwr limits for 2.4G or 5G bands */
- if (band->bandtype == BRCM_BAND_2G)
- maxpwr = li->maxpwr[CHANNEL_POWER_IDX_2G_OFDM(chan)];
- else
- maxpwr = li->maxpwr[CHANNEL_POWER_IDX_5G(chan)];
-
- maxpwr = maxpwr - delta;
- maxpwr = max(maxpwr, 0);
- maxpwr = min(maxpwr, conducted_ofdm_max);
-
- /* Keep OFDM lmit below CCK limit */
- if (band->bandtype == BRCM_BAND_2G)
- maxpwr = min_t(int, maxpwr, txpwr->cck[0]);
-
- for (i = 0; i < BRCMS_NUM_RATES_OFDM; i++)
+ for (i = 0; i < BRCMS_NUM_RATES_OFDM; i++) {
txpwr->ofdm[i] = (u8) maxpwr;

- for (i = 0; i < BRCMS_NUM_RATES_OFDM; i++) {
/*
* OFDM 40 MHz SISO has the same power as the corresponding
* MCS0-7 rate unless overriden by the locale specific code.
@@ -1249,6 +656,15 @@ brcms_c_channel_reg_limits(struct brcms_cm_info *wlc_cm, u16 chanspec,
txpwr->ofdm_40_cdd[i] = 0;
}

+ /*
+ * SAF: I'm not sure how to transition the MIMO limits to using the
+ * standard regulatory structures.
+ */
+
+ /*
+ * SAF: none of the MIMO locales have BRCMS_EIRP set, so only the
+ * second case currently matters.
+ */
/* MIMO/HT specific limits */
if (li_mimo->flags & BRCMS_EIRP) {
delta = band->antgain;
@@ -1392,11 +808,6 @@ static bool brcms_c_chspec_malformed(u16 chanspec)
return false;
}

-/*
- * Validate the chanspec for this locale, for 40MHZ we need to also
- * check that the sidebands are valid 20MZH channels in this locale
- * and they are also a legal HT combination
- */
static bool
brcms_c_valid_chanspec_ext(struct brcms_cm_info *wlc_cm, u16 chspec,
bool dualband)
@@ -1415,59 +826,87 @@ brcms_c_valid_chanspec_ext(struct brcms_cm_info *wlc_cm, u16 chspec,
chspec_bandunit(chspec))
return false;

- /* Check a 20Mhz channel */
- if (CHSPEC_IS20(chspec)) {
- if (dualband)
- return brcms_c_valid_channel20_db(wlc_cm->wlc->cmi,
- channel);
- else
- return brcms_c_valid_channel20(wlc_cm->wlc->cmi,
- channel);
- }
-#ifdef SUPPORT_40MHZ
- /*
- * We know we are now checking a 40MHZ channel, so we should
- * only be here for NPHYS
- */
- if (BRCMS_ISNPHY(wlc->band) || BRCMS_ISSSLPNPHY(wlc->band)) {
- u8 upper_sideband = 0, idx;
- u8 num_ch20_entries =
- sizeof(chan20_info) / sizeof(struct chan20_info);
-
- if (!VALID_40CHANSPEC_IN_BAND(wlc, chspec_bandunit(chspec)))
- return false;
-
- if (dualband) {
- if (!brcms_c_valid_channel20_db(wlc->cmi,
- lower_20_sb(channel)) ||
- !brcms_c_valid_channel20_db(wlc->cmi,
- upper_20_sb(channel)))
- return false;
- } else {
- if (!brcms_c_valid_channel20(wlc->cmi,
- lower_20_sb(channel)) ||
- !brcms_c_valid_channel20(wlc->cmi,
- upper_20_sb(channel)))
- return false;
- }
+ return true;
+}
+
+bool brcms_c_valid_chanspec_db(struct brcms_cm_info *wlc_cm, u16 chspec)
+{
+ return brcms_c_valid_chanspec_ext(wlc_cm, chspec, true);
+}

- /* find the lower sideband info in the sideband array */
- for (idx = 0; idx < num_ch20_entries; idx++) {
- if (chan20_info[idx].sb == lower_20_sb(channel))
- upper_sideband = chan20_info[idx].adj_sbs;
+bool brcms_is_world_regd(const char *regdom)
+{
+ return !!brcms_world_regd(regdom);
+}
+
+static int brcms_reg_notifier(struct wiphy *wiphy,
+ struct regulatory_request *request)
+{
+ struct brcms_info *wl = wiphy_to_ieee80211_hw(wiphy)->priv;
+ struct brcms_c_info *wlc = wl->wlc;
+ struct ieee80211_supported_band *sband =
+ wiphy->bands[IEEE80211_BAND_5GHZ];
+ struct ieee80211_channel *ch;
+ int i;
+
+ sband = wiphy->bands[IEEE80211_BAND_5GHZ];
+ if (sband) {
+ /*
+ * brcmsmac treats all 5 GHz channels as passive;
+ * mark them as such
+ */
+ for (i = 0; i < sband->n_channels; i++) {
+ ch = &sband->channels[i];
+
+ if (ch->flags & IEEE80211_CHAN_DISABLED)
+ continue;
+
+ ch->flags |= IEEE80211_CHAN_PASSIVE_SCAN |
+ IEEE80211_CHAN_NO_IBSS;
}
- /* check that the lower sideband allows an upper sideband */
- if ((upper_sideband & (CH_UPPER_SB | CH_EWA_VALID)) ==
- (CH_UPPER_SB | CH_EWA_VALID))
- return true;
- return false;
}
-#endif /* 40 MHZ */

- return false;
+ /*
+ * SAF: Should this still be based off alpha2? And is it really
+ * needed? The channel_14_wide_filter flag isn't actually used
+ * anywhere.
+ */
+ if (wlc->pub->_nbands > 1 || wlc->band->bandtype == BRCM_BAND_2G)
+ wlc_phy_chanspec_ch14_widefilter_set(wl->wlc->band->pi,
+ brcms_c_japan_ccode(request->alpha2));
+
+ return 0;
}

-bool brcms_c_valid_chanspec_db(struct brcms_cm_info *wlc_cm, u16 chspec)
+void brcms_c_regd_init(struct brcms_c_info *wlc)
{
- return brcms_c_valid_chanspec_ext(wlc_cm, chspec, true);
+ struct wiphy *wiphy = brcms_c_get_wiphy(wlc->cmi);
+ const struct brcms_regd *regd = wlc->cmi->world_regd;
+ struct ieee80211_supported_band *sband;
+ struct ieee80211_channel *ch;
+ struct brcms_chanvec sup_chan;
+ struct brcms_band *band;
+ int band_idx, i;
+
+ /* Disable any channels not supported by the phy */
+ for (band_idx = 0; band_idx < IEEE80211_NUM_BANDS; band_idx++) {
+ if (band_idx == IEEE80211_BAND_2GHZ)
+ band = wlc->bandstate[BAND_2G_INDEX];
+ else
+ band = wlc->bandstate[BAND_5G_INDEX];
+ wlc_phy_chanspec_band_validch(band->pi, band->bandtype,
+ &sup_chan);
+
+ sband = wiphy->bands[band_idx];
+ for (i = 0; i < sband->n_channels; i++) {
+ ch = &sband->channels[i];
+ if (!isset(sup_chan.vec, ch->hw_value))
+ ch->flags |= IEEE80211_CHAN_DISABLED;
+ }
+ }
+
+ wlc->wiphy->reg_notifier = brcms_reg_notifier;
+ wlc->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY |
+ WIPHY_FLAG_STRICT_REGULATORY;
+ wiphy_apply_custom_regulatory(wlc->wiphy, regd->regdomain);
}
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/channel.h b/drivers/net/wireless/brcm80211/brcmsmac/channel.h
index 808cb4f..ad85c82 100644
--- a/drivers/net/wireless/brcm80211/brcmsmac/channel.h
+++ b/drivers/net/wireless/brcm80211/brcmsmac/channel.h
@@ -44,10 +44,16 @@ extern bool brcms_c_valid_chanspec_db(struct brcms_cm_info *wlc_cm,
u16 chspec);

extern void brcms_c_channel_reg_limits(struct brcms_cm_info *wlc_cm,
- u16 chanspec,
- struct txpwr_limits *txpwr);
+ u16 chanspec,
+ struct ieee80211_channel *channel,
+ struct txpwr_limits *txpwr);
extern void brcms_c_channel_set_chanspec(struct brcms_cm_info *wlc_cm,
- u16 chanspec,
- u8 local_constraint_qdbm);
+ u16 chanspec,
+ struct ieee80211_channel *channel,
+ u8 local_constraint_qdbm);
+
+extern bool brcms_is_world_regd(const char *regdom);
+
+extern void brcms_c_regd_init(struct brcms_c_info *wlc);

#endif /* _WLC_CHANNEL_H */
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c b/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c
index 569ab8a..a9703eb 100644
--- a/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c
+++ b/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c
@@ -396,8 +396,7 @@ static int brcms_ops_config(struct ieee80211_hw *hw, u32 changed)
if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
if (conf->channel_type == NL80211_CHAN_HT20 ||
conf->channel_type == NL80211_CHAN_NO_HT)
- err = brcms_c_set_channel(wl->wlc,
- conf->channel->hw_value);
+ err = brcms_c_set_channel(wl->wlc, conf->channel);
else
err = -ENOTSUPP;
}
@@ -727,7 +726,9 @@ static const struct ieee80211_ops brcms_ops = {
*/
static int brcms_set_hint(struct brcms_info *wl, char *abbrev)
{
- return regulatory_hint(wl->pub->ieee_hw->wiphy, abbrev);
+ if (!brcms_is_world_regd(abbrev))
+ return regulatory_hint(wl->pub->ieee_hw->wiphy, abbrev);
+ return 0;
}

void brcms_dpc(unsigned long data)
@@ -1059,6 +1060,8 @@ static struct brcms_info *brcms_attach(struct bcma_device *pdev)
goto fail;
}

+ brcms_c_regd_init(wl->wlc);
+
memcpy(perm, &wl->pub->cur_etheraddr, ETH_ALEN);
if (WARN_ON(!is_valid_ether_addr(perm)))
goto fail;
@@ -1071,8 +1074,6 @@ static struct brcms_info *brcms_attach(struct bcma_device *pdev)

if (wl->pub->srom_ccode[0])
err = brcms_set_hint(wl, wl->pub->srom_ccode);
- else
- err = brcms_set_hint(wl, "US");
if (err)
wiphy_err(wl->wiphy, "%s: regulatory_hint failed, status %d\n",
__func__, err);
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/main.c b/drivers/net/wireless/brcm80211/brcmsmac/main.c
index 86186fa..e75d376 100644
--- a/drivers/net/wireless/brcm80211/brcmsmac/main.c
+++ b/drivers/net/wireless/brcm80211/brcmsmac/main.c
@@ -3150,20 +3150,6 @@ void brcms_c_reset(struct brcms_c_info *wlc)
brcms_b_reset(wlc->hw);
}

-/* Return the channel the driver should initialize during brcms_c_init.
- * the channel may have to be changed from the currently configured channel
- * if other configurations are in conflict (bandlocked, 11n mode disabled,
- * invalid channel for current country, etc.)
- */
-static u16 brcms_c_init_chanspec(struct brcms_c_info *wlc)
-{
- u16 chanspec =
- 1 | WL_CHANSPEC_BW_20 | WL_CHANSPEC_CTL_SB_NONE |
- WL_CHANSPEC_BAND_2G;
-
- return chanspec;
-}
-
void brcms_c_init_scb(struct scb *scb)
{
int i;
@@ -3409,14 +3395,15 @@ static brcms_b_init(struct brcms_hardware *wlc_hw, u16 chanspec) {
brcms_b_clkctl_clk(wlc_hw, CLK_DYNAMIC);
}

-static void brcms_c_set_phy_chanspec(struct brcms_c_info *wlc,
- u16 chanspec)
+static void brcms_c_set_phy_chanspec(struct brcms_c_info *wlc, u16 chanspec,
+ struct ieee80211_channel *channel)
{
/* Save our copy of the chanspec */
wlc->chanspec = chanspec;

/* Set the chanspec and power limits for this locale */
- brcms_c_channel_set_chanspec(wlc->cmi, chanspec, BRCMS_TXPWR_MAX);
+ brcms_c_channel_set_chanspec(wlc->cmi, chanspec, channel,
+ BRCMS_TXPWR_MAX);

if (wlc->stf->ss_algosel_auto)
brcms_c_stf_ss_algo_channel_get(wlc, &wlc->stf->ss_algo_channel,
@@ -3530,8 +3517,8 @@ static void brcms_c_rate_lookup_init(struct brcms_c_info *wlc,
}
}

-static void brcms_c_bandinit_ordered(struct brcms_c_info *wlc,
- u16 chanspec)
+static void brcms_c_bandinit_ordered(struct brcms_c_info *wlc, u16 chanspec,
+ struct ieee80211_channel *ch)
{
struct brcms_c_rateset default_rateset;
uint parkband;
@@ -3573,7 +3560,7 @@ static void brcms_c_bandinit_ordered(struct brcms_c_info *wlc,
}

/* sync up phy/radio chanspec */
- brcms_c_set_phy_chanspec(wlc, chanspec);
+ brcms_c_set_phy_chanspec(wlc, chanspec, ch);
}

/*
@@ -3943,7 +3930,8 @@ static void brcms_c_setband(struct brcms_c_info *wlc,
brcms_c_bsinit(wlc);
}

-static void brcms_c_set_chanspec(struct brcms_c_info *wlc, u16 chanspec)
+static void brcms_c_set_chanspec(struct brcms_c_info *wlc, u16 chanspec,
+ struct ieee80211_channel *channel)
{
uint bandunit;
bool switchband = false;
@@ -3980,7 +3968,7 @@ static void brcms_c_set_chanspec(struct brcms_c_info *wlc, u16 chanspec)
}

/* sync up phy/radio chanspec */
- brcms_c_set_phy_chanspec(wlc, chanspec);
+ brcms_c_set_phy_chanspec(wlc, chanspec, channel);

/* init antenna selection */
if (brcms_chspec_bw(old_chanspec) != brcms_chspec_bw(chanspec)) {
@@ -5152,6 +5140,8 @@ static void brcms_c_wme_retries_write(struct brcms_c_info *wlc)
/* make interface operational */
int brcms_c_up(struct brcms_c_info *wlc)
{
+ struct ieee80211_channel *ch;
+
BCMMSG(wlc->wiphy, "wl%d\n", wlc->pub->unit);

/* HW is turned off so don't try to access it */
@@ -5218,8 +5208,9 @@ int brcms_c_up(struct brcms_c_info *wlc)
wlc->pub->up = true;

if (wlc->bandinit_pending) {
+ ch = wlc->pub->ieee_hw->conf.channel;
brcms_c_suspend_mac_and_wait(wlc);
- brcms_c_set_chanspec(wlc, wlc->default_bss->chanspec);
+ brcms_c_set_chanspec(wlc, ch20mhz_chspec(ch->hw_value), ch);
wlc->bandinit_pending = false;
brcms_c_enable_mac(wlc);
}
@@ -5576,8 +5567,9 @@ static void brcms_c_ofdm_rateset_war(struct brcms_c_info *wlc)
wlc_phy_ofdm_rateset_war(wlc->band->pi, war);
}

-int brcms_c_set_channel(struct brcms_c_info *wlc, u16 channel)
+int brcms_c_set_channel(struct brcms_c_info *wlc, struct ieee80211_channel *ch)
{
+ int channel = ch->hw_value;
u16 chspec = ch20mhz_chspec(channel);

if (channel < 0 || channel > MAXCHANNEL)
@@ -5586,7 +5578,6 @@ int brcms_c_set_channel(struct brcms_c_info *wlc, u16 channel)
if (!brcms_c_valid_chanspec_db(wlc->cmi, chspec))
return -EINVAL;

-
if (!wlc->pub->up && brcms_is_mband_unlocked(wlc)) {
if (wlc->band->bandunit != chspec_bandunit(chspec))
wlc->bandinit_pending = true;
@@ -5600,7 +5591,7 @@ int brcms_c_set_channel(struct brcms_c_info *wlc, u16 channel)
if (wlc->pub->up && (wlc_phy_chanspec_get(wlc->band->pi) != chspec)) {
brcms_c_set_home_chanspec(wlc, chspec);
brcms_c_suspend_mac_and_wait(wlc);
- brcms_c_set_chanspec(wlc, chspec);
+ brcms_c_set_chanspec(wlc, chspec, ch);
brcms_c_enable_mac(wlc);
}
return 0;
@@ -8216,19 +8207,12 @@ bool brcms_c_dpc(struct brcms_c_info *wlc, bool bounded)
void brcms_c_init(struct brcms_c_info *wlc, bool mute_tx)
{
struct bcma_device *core = wlc->hw->d11core;
+ struct ieee80211_channel *ch = wlc->pub->ieee_hw->conf.channel;
u16 chanspec;

BCMMSG(wlc->wiphy, "wl%d\n", wlc->pub->unit);

- /*
- * This will happen if a big-hammer was executed. In
- * that case, we want to go back to the channel that
- * we were on and not new channel
- */
- if (wlc->pub->associated)
- chanspec = wlc->home_chanspec;
- else
- chanspec = brcms_c_init_chanspec(wlc);
+ chanspec = ch20mhz_chspec(ch->hw_value);

brcms_b_init(wlc->hw, chanspec);

@@ -8256,7 +8240,7 @@ void brcms_c_init(struct brcms_c_info *wlc, bool mute_tx)
brcms_c_set_ps_ctrl(wlc);
}

- brcms_c_bandinit_ordered(wlc, chanspec);
+ brcms_c_bandinit_ordered(wlc, chanspec, ch);

/* init probe response timeout */
brcms_b_write_shm(wlc->hw, M_PRS_MAXTIME, wlc->prb_resp_timeout);
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/pub.h b/drivers/net/wireless/brcm80211/brcmsmac/pub.h
index f0038ad..4de7f1d 100644
--- a/drivers/net/wireless/brcm80211/brcmsmac/pub.h
+++ b/drivers/net/wireless/brcm80211/brcmsmac/pub.h
@@ -18,6 +18,8 @@
#define _BRCM_PUB_H_

#include <linux/bcma/bcma.h>
+#include <net/mac80211.h>
+#include <net/cfg80211.h>
#include <brcmu_wifi.h>
#include "types.h"
#include "defs.h"
@@ -580,7 +582,8 @@ extern void brcms_c_scan_stop(struct brcms_c_info *wlc);
extern int brcms_c_get_curband(struct brcms_c_info *wlc);
extern void brcms_c_wait_for_tx_completion(struct brcms_c_info *wlc,
bool drop);
-extern int brcms_c_set_channel(struct brcms_c_info *wlc, u16 channel);
+extern int brcms_c_set_channel(struct brcms_c_info *wlc,
+ struct ieee80211_channel *channel);
extern int brcms_c_set_rate_limit(struct brcms_c_info *wlc, u16 srl, u16 lrl);
extern void brcms_c_get_current_rateset(struct brcms_c_info *wlc,
struct brcm_rateset *currs);

2012-04-11 13:39:47

by Seth Forshee

[permalink] [raw]
Subject: Re: Problems with regulatory domain support and BCM43224

On Wed, Apr 11, 2012 at 12:16:40PM +0200, Arend van Spriel wrote:
> On 04/10/2012 06:28 PM, Seth Forshee wrote:
> >>The patch builds, and kind of works. Scanning seems to be fine; I can
> >>> see all the APs I expect in my area, including the one on a DFS channel
> >>> that I couldn't see previously. I can associate with my 2.4 GHz APs, but
> >>> not the 5 GHz AP. I see timme outs waiting for probe responses, and I'm
> >>> hitting the WARN_ON_ONCE in brcms_c_wait_for_tx_completion(). I haven't
> >>> really debugged this yet -- I thought I'd send out the patch to collect
> >>> comments while I debug. Suggestions of what's causing this are also
> >>> welcome:)
> >This was due to always passing true for the value of mute_tx to
> >brcms_b_set_chanspec() on passive channels. For now I'm just always
> >passing false, which looks like it ought to be okay as we shouldn't have
> >any tx on passive channels unless beacons are seen on the channel.
>
> Yes. I discovered this as well. Actually, I sent out a patch for
> some people to test it. I submitted a slightly different patch to
> John in which tx in unmuted upon receiving a beacon.

I assume you're talking about this patch?

http://www.spinics.net/lists/linux-wireless/msg88107.html

My original changes would mute tx whenever IEEE80211_CHAN_PASSIVE_SCAN
is set for the current channel. I'll try that again with your patch.

> >>> One of the major unresolved issues in the patch is what to do with the
> >>> data in struct locale_mimo_info. The regulatory rules only hold one
> >>> power level. I'm unsure why the brcmsmac implementation differs in this
> >>> regard. Suggestions?
> >This is still one of the largest unsolved issues. I'm probably going to
> >need some advice on how to fill out the txpwr information when
> >regualtory rules external to the driver can be applied.
> >
>
> The power constraints for HT (covered by struct locale_mimo_info)
> are handled differently from non-HT. I have to confirm internally
> whether this is specific for our devices or actually needed to be
> compliant.

Great, thanks.

Seth


2012-04-11 10:16:53

by Arend van Spriel

[permalink] [raw]
Subject: Re: Problems with regulatory domain support and BCM43224

On 04/10/2012 06:28 PM, Seth Forshee wrote:
>> The patch builds, and kind of works. Scanning seems to be fine; I can
>> > see all the APs I expect in my area, including the one on a DFS channel
>> > that I couldn't see previously. I can associate with my 2.4 GHz APs, but
>> > not the 5 GHz AP. I see timme outs waiting for probe responses, and I'm
>> > hitting the WARN_ON_ONCE in brcms_c_wait_for_tx_completion(). I haven't
>> > really debugged this yet -- I thought I'd send out the patch to collect
>> > comments while I debug. Suggestions of what's causing this are also
>> > welcome:)
> This was due to always passing true for the value of mute_tx to
> brcms_b_set_chanspec() on passive channels. For now I'm just always
> passing false, which looks like it ought to be okay as we shouldn't have
> any tx on passive channels unless beacons are seen on the channel.

Yes. I discovered this as well. Actually, I sent out a patch for some
people to test it. I submitted a slightly different patch to John in
which tx in unmuted upon receiving a beacon.

>> > One of the major unresolved issues in the patch is what to do with the
>> > data in struct locale_mimo_info. The regulatory rules only hold one
>> > power level. I'm unsure why the brcmsmac implementation differs in this
>> > regard. Suggestions?
> This is still one of the largest unsolved issues. I'm probably going to
> need some advice on how to fill out the txpwr information when
> regualtory rules external to the driver can be applied.
>

The power constraints for HT (covered by struct locale_mimo_info) are
handled differently from non-HT. I have to confirm internally whether
this is specific for our devices or actually needed to be compliant.

Gr. AvS