brcmfmac: Prefer a ccode from OTP over nvram file
authorPhil Elwell <phil@raspberrypi.com>
Fri, 26 Jun 2020 10:51:05 +0000 (11:51 +0100)
committerpopcornmix <popcornmix@gmail.com>
Wed, 1 Jul 2020 15:34:13 +0000 (16:34 +0100)
Allow the nvram file to set a default ccode (regulatory domain) without
overriding one set in OTP.

Signed-off-by: Phil Elwell <phil@raspberrypi.com>
drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.c

index 329c386..2b725af 100644 (file)
@@ -9,6 +9,7 @@
 #include <linux/etherdevice.h>
 #include <linux/module.h>
 #include <linux/vmalloc.h>
+#include <linux/ctype.h>
 #include <net/cfg80211.h>
 #include <net/netlink.h>
 
@@ -6966,31 +6967,45 @@ static void brcmf_cfg80211_reg_notifier(struct wiphy *wiphy,
        struct brcmf_if *ifp = brcmf_get_ifp(cfg->pub, 0);
        struct brcmf_pub *drvr = cfg->pub;
        struct brcmf_fil_country_le ccreq;
+       char *alpha2;
        s32 err;
        int i;
 
-       /* The country code gets set to "00" by default at boot, ignore */
-       if (req->alpha2[0] == '0' && req->alpha2[1] == '0')
+       err = brcmf_fil_iovar_data_get(ifp, "country", &ccreq, sizeof(ccreq));
+       if (err) {
+               bphy_err(drvr, "Country code iovar returned err = %d\n", err);
                return;
+       }
+
+       /* The country code gets set to "00" by default at boot - substitute
+        * any saved ccode from the nvram file unless there is a valid code
+        * already set.
+        */
+       alpha2 = req->alpha2;
+       if (alpha2[0] == '0' && alpha2[1] == '0') {
+               extern char saved_ccode[2];
+
+               if ((isupper(ccreq.country_abbrev[0]) &&
+                    isupper(ccreq.country_abbrev[1])) ||
+                   !saved_ccode[0])
+                       return;
+               alpha2 = saved_ccode;
+               pr_debug("brcmfmac: substituting saved ccode %c%c\n",
+                        alpha2[0], alpha2[1]);
+       }
 
        /* ignore non-ISO3166 country codes */
        for (i = 0; i < 2; i++)
-               if (req->alpha2[i] < 'A' || req->alpha2[i] > 'Z') {
+               if (alpha2[i] < 'A' || alpha2[i] > 'Z') {
                        bphy_err(drvr, "not an ISO3166 code (0x%02x 0x%02x)\n",
-                                req->alpha2[0], req->alpha2[1]);
+                                alpha2[0], alpha2[1]);
                        return;
                }
 
        brcmf_dbg(TRACE, "Enter: initiator=%d, alpha=%c%c\n", req->initiator,
-                 req->alpha2[0], req->alpha2[1]);
-
-       err = brcmf_fil_iovar_data_get(ifp, "country", &ccreq, sizeof(ccreq));
-       if (err) {
-               bphy_err(drvr, "Country code iovar returned err = %d\n", err);
-               return;
-       }
+                 alpha2[0], alpha2[1]);
 
-       err = brcmf_translate_country_code(ifp->drvr, req->alpha2, &ccreq);
+       err = brcmf_translate_country_code(ifp->drvr, alpha2, &ccreq);
        if (err)
                return;
 
index 3aed4c4..a926c46 100644 (file)
@@ -10,6 +10,7 @@
 #include <linux/firmware.h>
 #include <linux/module.h>
 #include <linux/bcm47xx_nvram.h>
+#include <linux/ctype.h>
 
 #include "debug.h"
 #include "firmware.h"
@@ -30,6 +31,8 @@ enum nvram_parser_state {
        END
 };
 
+char saved_ccode[2] = {};
+
 /**
  * struct nvram_parser - internal info for parser.
  *
@@ -545,10 +548,26 @@ static int brcmf_fw_request_nvram_done(const struct firmware *fw, void *ctx)
                        goto fail;
        }
 
-       if (data)
+       if (data) {
+               char *ccode = strnstr((char *)data, "ccode=", data_len);
+               /* Ensure this is a whole token */
+               if (ccode && ((void *)ccode == (void *)data || isspace(ccode[-1]))) {
+                       /* Comment out the line */
+                       ccode[0] = '#';
+                       ccode += 6;
+                       if (isupper(ccode[0]) && isupper(ccode[1]) &&
+                           isspace(ccode[2])) {
+                               pr_debug("brcmfmac: intercepting ccode=%c%c\n",
+                                        ccode[0], ccode[1]);
+                               saved_ccode[0] = ccode[0];
+                               saved_ccode[1] = ccode[1];
+                       }
+               };
+
                nvram = brcmf_fw_nvram_strip(data, data_len, &nvram_length,
                                             fwctx->req->domain_nr,
                                             fwctx->req->bus_nr);
+       }
 
        if (free_bcm47xx_nvram)
                bcm47xx_nvram_release_contents(data);