From: Seth Forshee <seth.forshee@canonical.com>
To: "Luis R. Rodriguez" <rodrigue@qca.qualcomm.com>,
Arend van Spriel <arend@broadcom.com>
Cc: linux-wireless@vger.kernel.org
Subject: Re: Problems with regulatory domain support and BCM43224
Date: Tue, 20 Mar 2012 17:07:06 -0500 [thread overview]
Message-ID: <20120320220706.GA17272@thinkpad-t410> (raw)
In-Reply-To: <CAB=NE6XnorRDEu976uMkPFNKHQjhRT0Craf3ZjL9dYysPjmQng@mail.gmail.com>
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 ? ®d->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);
next prev parent reply other threads:[~2012-03-20 22:07 UTC|newest]
Thread overview: 30+ messages / expand[flat|nested] mbox.gz Atom feed top
2012-03-07 19:40 Problems with regulatory domain support and BCM43224 Seth Forshee
2012-03-08 17:41 ` Seth Forshee
2012-03-08 18:53 ` Luis R. Rodriguez
2012-03-08 19:07 ` Quan, David
2012-03-08 19:36 ` Luis R. Rodriguez
2012-03-08 19:45 ` Quan, David
2012-03-08 19:51 ` Luis R. Rodriguez
2012-03-08 20:07 ` Seth Forshee
2012-03-08 20:17 ` Luis R. Rodriguez
2012-03-08 21:01 ` Arend van Spriel
2012-03-08 21:06 ` Luis R. Rodriguez
2012-03-08 21:31 ` Arend van Spriel
2012-03-08 21:42 ` Seth Forshee
2012-03-20 22:07 ` Seth Forshee [this message]
2012-03-21 11:05 ` Arend van Spriel
2012-03-21 14:19 ` Seth Forshee
2012-03-21 17:51 ` Arend van Spriel
2012-03-21 18:17 ` Luis R. Rodriguez
2012-03-21 19:37 ` Seth Forshee
2012-03-22 0:27 ` Luis R. Rodriguez
2012-03-26 19:36 ` Seth Forshee
2012-04-04 2:46 ` Seth Forshee
2012-04-04 7:03 ` Arend van Spriel
2012-04-10 16:28 ` Seth Forshee
2012-04-11 10:16 ` Arend van Spriel
2012-04-11 13:39 ` Seth Forshee
2012-04-11 16:52 ` Arend van Spriel
2012-03-08 21:59 ` Seth Forshee
2012-03-08 22:12 ` Luis R. Rodriguez
2012-03-08 22:30 ` Seth Forshee
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20120320220706.GA17272@thinkpad-t410 \
--to=seth.forshee@canonical.com \
--cc=arend@broadcom.com \
--cc=linux-wireless@vger.kernel.org \
--cc=rodrigue@qca.qualcomm.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).