diff options
Diffstat (limited to 'drivers/net/wireless/brcm80211')
-rw-r--r-- | drivers/net/wireless/brcm80211/brcmfmac/bcmsdh_sdmmc.c | 2 | ||||
-rw-r--r-- | drivers/net/wireless/brcm80211/brcmfmac/dhd_bus.h | 8 | ||||
-rw-r--r-- | drivers/net/wireless/brcm80211/brcmfmac/dhd_common.c | 29 | ||||
-rw-r--r-- | drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c | 2 | ||||
-rw-r--r-- | drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c | 500 | ||||
-rw-r--r-- | drivers/net/wireless/brcm80211/brcmfmac/sdio_chip.c | 17 | ||||
-rw-r--r-- | drivers/net/wireless/brcm80211/brcmsmac/channel.c | 1226 | ||||
-rw-r--r-- | drivers/net/wireless/brcm80211/brcmsmac/channel.h | 4 | ||||
-rw-r--r-- | drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c | 2 | ||||
-rw-r--r-- | drivers/net/wireless/brcm80211/brcmsmac/main.c | 36 | ||||
-rw-r--r-- | drivers/net/wireless/brcm80211/include/brcm_hw_ids.h | 1 |
11 files changed, 715 insertions, 1112 deletions
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh_sdmmc.c b/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh_sdmmc.c index 82f51dbd0d66..49765d34b4e0 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh_sdmmc.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh_sdmmc.c @@ -44,6 +44,7 @@ #define SDIO_DEVICE_ID_BROADCOM_4329 0x4329 #define SDIO_DEVICE_ID_BROADCOM_4330 0x4330 +#define SDIO_DEVICE_ID_BROADCOM_4334 0x4334 #define SDIO_FUNC1_BLOCKSIZE 64 #define SDIO_FUNC2_BLOCKSIZE 512 @@ -52,6 +53,7 @@ static const struct sdio_device_id brcmf_sdmmc_ids[] = { {SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_4329)}, {SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_4330)}, + {SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_4334)}, { /* end: all zeroes */ }, }; MODULE_DEVICE_TABLE(sdio, brcmf_sdmmc_ids); diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_bus.h b/drivers/net/wireless/brcm80211/brcmfmac/dhd_bus.h index 366916494be4..537f499cc5d2 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_bus.h +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_bus.h @@ -36,6 +36,13 @@ struct dngl_stats { unsigned long multicast; /* multicast packets received */ }; +struct brcmf_bus_dcmd { + char *name; + char *param; + int param_len; + struct list_head list; +}; + /* interface structure between common and bus layer */ struct brcmf_bus { u8 type; /* bus type */ @@ -50,6 +57,7 @@ struct brcmf_bus { unsigned long tx_realloc; /* Tx packets realloced for headroom */ struct dngl_stats dstats; /* Stats for dongle-based data */ u8 align; /* bus alignment requirement */ + struct list_head dcmd_list; /* interface functions pointers */ /* Stop bus module: clear pending frames, disable data flow */ diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_common.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_common.c index 236cb9fa460c..2621dd3d7dcd 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_common.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_common.c @@ -800,13 +800,13 @@ int brcmf_c_preinit_dcmds(struct brcmf_pub *drvr) char iovbuf[BRCMF_EVENTING_MASK_LEN + 12]; /* Room for "event_msgs" + '\0' + bitvec */ char buf[128], *ptr; - u32 dongle_align = drvr->bus_if->align; - u32 glom = 0; u32 roaming = 1; uint bcn_timeout = 3; int scan_assoc_time = 40; int scan_unassoc_time = 40; int i; + struct brcmf_bus_dcmd *cmdlst; + struct list_head *cur, *q; mutex_lock(&drvr->proto_block); @@ -827,17 +827,6 @@ int brcmf_c_preinit_dcmds(struct brcmf_pub *drvr) /* Print fw version info */ brcmf_dbg(ERROR, "Firmware version = %s\n", buf); - /* Match Host and Dongle rx alignment */ - brcmf_c_mkiovar("bus:txglomalign", (char *)&dongle_align, 4, iovbuf, - sizeof(iovbuf)); - brcmf_proto_cdc_set_dcmd(drvr, 0, BRCMF_C_SET_VAR, iovbuf, - sizeof(iovbuf)); - - /* disable glom option per default */ - brcmf_c_mkiovar("bus:txglom", (char *)&glom, 4, iovbuf, sizeof(iovbuf)); - brcmf_proto_cdc_set_dcmd(drvr, 0, BRCMF_C_SET_VAR, iovbuf, - sizeof(iovbuf)); - /* Setup timeout if Beacons are lost and roam is off to report link down */ brcmf_c_mkiovar("bcn_timeout", (char *)&bcn_timeout, 4, iovbuf, @@ -874,6 +863,20 @@ int brcmf_c_preinit_dcmds(struct brcmf_pub *drvr) 0, true); } + /* set bus specific command if there is any */ + list_for_each_safe(cur, q, &drvr->bus_if->dcmd_list) { + cmdlst = list_entry(cur, struct brcmf_bus_dcmd, list); + if (cmdlst->name && cmdlst->param && cmdlst->param_len) { + brcmf_c_mkiovar(cmdlst->name, cmdlst->param, + cmdlst->param_len, iovbuf, + sizeof(iovbuf)); + brcmf_proto_cdc_set_dcmd(drvr, 0, BRCMF_C_SET_VAR, + iovbuf, sizeof(iovbuf)); + } + list_del(cur); + kfree(cmdlst); + } + mutex_unlock(&drvr->proto_block); return 0; diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c index 01cf6c03390b..57bf1d7ee80f 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c @@ -1020,6 +1020,8 @@ int brcmf_attach(uint bus_hdrlen, struct device *dev) INIT_WORK(&drvr->setmacaddr_work, _brcmf_set_mac_address); INIT_WORK(&drvr->multicast_work, _brcmf_set_multicast_list); + INIT_LIST_HEAD(&drvr->bus_if->dcmd_list); + return ret; fail: diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c index b023766954a6..472f2ef5c652 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c @@ -31,6 +31,8 @@ #include <linux/firmware.h> #include <linux/module.h> #include <linux/bcma/bcma.h> +#include <linux/debugfs.h> +#include <linux/vmalloc.h> #include <asm/unaligned.h> #include <defs.h> #include <brcmu_wifi.h> @@ -48,6 +50,9 @@ #define CBUF_LEN (128) +/* Device console log buffer state */ +#define CONSOLE_BUFFER_MAX 2024 + struct rte_log_le { __le32 buf; /* Can't be pointer on (64-bit) hosts */ __le32 buf_size; @@ -281,7 +286,7 @@ struct rte_console { * Shared structure between dongle and the host. * The structure contains pointers to trap or assert information. */ -#define SDPCM_SHARED_VERSION 0x0002 +#define SDPCM_SHARED_VERSION 0x0003 #define SDPCM_SHARED_VERSION_MASK 0x00FF #define SDPCM_SHARED_ASSERT_BUILT 0x0100 #define SDPCM_SHARED_ASSERT 0x0200 @@ -428,6 +433,29 @@ struct brcmf_console { u8 *buf; /* Log buffer (host copy) */ uint last; /* Last buffer read index */ }; + +struct brcmf_trap_info { + __le32 type; + __le32 epc; + __le32 cpsr; + __le32 spsr; + __le32 r0; /* a1 */ + __le32 r1; /* a2 */ + __le32 r2; /* a3 */ + __le32 r3; /* a4 */ + __le32 r4; /* v1 */ + __le32 r5; /* v2 */ + __le32 r6; /* v3 */ + __le32 r7; /* v4 */ + __le32 r8; /* v5 */ + __le32 r9; /* sb/v6 */ + __le32 r10; /* sl/v7 */ + __le32 r11; /* fp/v8 */ + __le32 r12; /* ip */ + __le32 r13; /* sp */ + __le32 r14; /* lr */ + __le32 pc; /* r15 */ +}; #endif /* DEBUG */ struct sdpcm_shared { @@ -439,6 +467,7 @@ struct sdpcm_shared { u32 console_addr; /* Address of struct rte_console */ u32 msgtrace_addr; u8 tag[32]; + u32 brpt_addr; }; struct sdpcm_shared_le { @@ -450,6 +479,7 @@ struct sdpcm_shared_le { __le32 console_addr; /* Address of struct rte_console */ __le32 msgtrace_addr; u8 tag[32]; + __le32 brpt_addr; }; @@ -2953,13 +2983,311 @@ brcmf_sdbrcm_bus_txctl(struct device *dev, unsigned char *msg, uint msglen) } #ifdef DEBUG +static inline bool brcmf_sdio_valid_shared_address(u32 addr) +{ + return !(addr == 0 || ((~addr >> 16) & 0xffff) == (addr & 0xffff)); +} + +static int brcmf_sdio_readshared(struct brcmf_sdio *bus, + struct sdpcm_shared *sh) +{ + u32 addr; + int rv; + u32 shaddr = 0; + struct sdpcm_shared_le sh_le; + __le32 addr_le; + + shaddr = bus->ramsize - 4; + + /* + * Read last word in socram to determine + * address of sdpcm_shared structure + */ + rv = brcmf_sdbrcm_membytes(bus, false, shaddr, + (u8 *)&addr_le, 4); + if (rv < 0) + return rv; + + addr = le32_to_cpu(addr_le); + + brcmf_dbg(INFO, "sdpcm_shared address 0x%08X\n", addr); + + /* + * Check if addr is valid. + * NVRAM length at the end of memory should have been overwritten. + */ + if (!brcmf_sdio_valid_shared_address(addr)) { + brcmf_dbg(ERROR, "invalid sdpcm_shared address 0x%08X\n", + addr); + return -EINVAL; + } + + /* Read hndrte_shared structure */ + rv = brcmf_sdbrcm_membytes(bus, false, addr, (u8 *)&sh_le, + sizeof(struct sdpcm_shared_le)); + if (rv < 0) + return rv; + + /* Endianness */ + sh->flags = le32_to_cpu(sh_le.flags); + sh->trap_addr = le32_to_cpu(sh_le.trap_addr); + sh->assert_exp_addr = le32_to_cpu(sh_le.assert_exp_addr); + sh->assert_file_addr = le32_to_cpu(sh_le.assert_file_addr); + sh->assert_line = le32_to_cpu(sh_le.assert_line); + sh->console_addr = le32_to_cpu(sh_le.console_addr); + sh->msgtrace_addr = le32_to_cpu(sh_le.msgtrace_addr); + + if ((sh->flags & SDPCM_SHARED_VERSION_MASK) != SDPCM_SHARED_VERSION) { + brcmf_dbg(ERROR, + "sdpcm_shared version mismatch: dhd %d dongle %d\n", + SDPCM_SHARED_VERSION, + sh->flags & SDPCM_SHARED_VERSION_MASK); + return -EPROTO; + } + + return 0; +} + +static int brcmf_sdio_dump_console(struct brcmf_sdio *bus, + struct sdpcm_shared *sh, char __user *data, + size_t count) +{ + u32 addr, console_ptr, console_size, console_index; + char *conbuf = NULL; + __le32 sh_val; + int rv; + loff_t pos = 0; + int nbytes = 0; + + /* obtain console information from device memory */ + addr = sh->console_addr + offsetof(struct rte_console, log_le); + rv = brcmf_sdbrcm_membytes(bus, false, addr, + (u8 *)&sh_val, sizeof(u32)); + if (rv < 0) + return rv; + console_ptr = le32_to_cpu(sh_val); + + addr = sh->console_addr + offsetof(struct rte_console, log_le.buf_size); + rv = brcmf_sdbrcm_membytes(bus, false, addr, + (u8 *)&sh_val, sizeof(u32)); + if (rv < 0) + return rv; + console_size = le32_to_cpu(sh_val); + + addr = sh->console_addr + offsetof(struct rte_console, log_le.idx); + rv = brcmf_sdbrcm_membytes(bus, false, addr, + (u8 *)&sh_val, sizeof(u32)); + if (rv < 0) + return rv; + console_index = le32_to_cpu(sh_val); + + /* allocate buffer for console data */ + if (console_size <= CONSOLE_BUFFER_MAX) + conbuf = vzalloc(console_size+1); + + if (!conbuf) + return -ENOMEM; + + /* obtain the console data from device */ + conbuf[console_size] = '\0'; + rv = brcmf_sdbrcm_membytes(bus, false, console_ptr, (u8 *)conbuf, + console_size); + if (rv < 0) + goto done; + + rv = simple_read_from_buffer(data, count, &pos, + conbuf + console_index, + console_size - console_index); + if (rv < 0) + goto done; + + nbytes = rv; + if (console_index > 0) { + pos = 0; + rv = simple_read_from_buffer(data+nbytes, count, &pos, + conbuf, console_index - 1); + if (rv < 0) + goto done; + rv += nbytes; + } +done: + vfree(conbuf); + return rv; +} + +static int brcmf_sdio_trap_info(struct brcmf_sdio *bus, struct sdpcm_shared *sh, + char __user *data, size_t count) +{ + int error, res; + char buf[350]; + struct brcmf_trap_info tr; + int nbytes; + loff_t pos = 0; + + if ((sh->flags & SDPCM_SHARED_TRAP) == 0) + return 0; + + error = brcmf_sdbrcm_membytes(bus, false, sh->trap_addr, (u8 *)&tr, + sizeof(struct brcmf_trap_info)); + if (error < 0) + return error; + + nbytes = brcmf_sdio_dump_console(bus, sh, data, count); + if (nbytes < 0) + return nbytes; + + res = scnprintf(buf, sizeof(buf), + "dongle trap info: type 0x%x @ epc 0x%08x\n" + " cpsr 0x%08x spsr 0x%08x sp 0x%08x\n" + " lr 0x%08x pc 0x%08x offset 0x%x\n" + " r0 0x%08x r1 0x%08x r2 0x%08x r3 0x%08x\n" + " r4 0x%08x r5 0x%08x r6 0x%08x r7 0x%08x\n", + le32_to_cpu(tr.type), le32_to_cpu(tr.epc), + le32_to_cpu(tr.cpsr), le32_to_cpu(tr.spsr), + le32_to_cpu(tr.r13), le32_to_cpu(tr.r14), + le32_to_cpu(tr.pc), sh->trap_addr, + le32_to_cpu(tr.r0), le32_to_cpu(tr.r1), + le32_to_cpu(tr.r2), le32_to_cpu(tr.r3), + le32_to_cpu(tr.r4), le32_to_cpu(tr.r5), + le32_to_cpu(tr.r6), le32_to_cpu(tr.r7)); + + error = simple_read_from_buffer(data+nbytes, count, &pos, buf, res); + if (error < 0) + return error; + + nbytes += error; + return nbytes; +} + +static int brcmf_sdio_assert_info(struct brcmf_sdio *bus, + struct sdpcm_shared *sh, char __user *data, + size_t count) +{ + int error = 0; + char buf[200]; + char file[80] = "?"; + char expr[80] = "<???>"; + int res; + loff_t pos = 0; + + if ((sh->flags & SDPCM_SHARED_ASSERT_BUILT) == 0) { + brcmf_dbg(INFO, "firmware not built with -assert\n"); + return 0; + } else if ((sh->flags & SDPCM_SHARED_ASSERT) == 0) { + brcmf_dbg(INFO, "no assert in dongle\n"); + return 0; + } + + if (sh->assert_file_addr != 0) { + error = brcmf_sdbrcm_membytes(bus, false, sh->assert_file_addr, + (u8 *)file, 80); + if (error < 0) + return error; + } + if (sh->assert_exp_addr != 0) { + error = brcmf_sdbrcm_membytes(bus, false, sh->assert_exp_addr, + (u8 *)expr, 80); + if (error < 0) + return error; + } + + res = scnprintf(buf, sizeof(buf), + "dongle assert: %s:%d: assert(%s)\n", + file, sh->assert_line, expr); + return simple_read_from_buffer(data, count, &pos, buf, res); +} + +static int brcmf_sdbrcm_checkdied(struct brcmf_sdio *bus) +{ + int error; + struct sdpcm_shared sh; + + down(&bus->sdsem); + error = brcmf_sdio_readshared(bus, &sh); + up(&bus->sdsem); + + if (error < 0) + return error; + + if ((sh.flags & SDPCM_SHARED_ASSERT_BUILT) == 0) + brcmf_dbg(INFO, "firmware not built with -assert\n"); + else if (sh.flags & SDPCM_SHARED_ASSERT) + brcmf_dbg(ERROR, "assertion in dongle\n"); + + if (sh.flags & SDPCM_SHARED_TRAP) + brcmf_dbg(ERROR, "firmware trap in dongle\n"); + + return 0; +} + +static int brcmf_sdbrcm_died_dump(struct brcmf_sdio *bus, char __user *data, + size_t count, loff_t *ppos) +{ + int error = 0; + struct sdpcm_shared sh; + int nbytes = 0; + loff_t pos = *ppos; + + if (pos != 0) + return 0; + + down(&bus->sdsem); + error = brcmf_sdio_readshared(bus, &sh); + if (error < 0) + goto done; + + error = brcmf_sdio_assert_info(bus, &sh, data, count); + if (error < 0) + goto done; + + nbytes = error; + error = brcmf_sdio_trap_info(bus, &sh, data, count); + if (error < 0) + goto done; + + error += nbytes; + *ppos += error; +done: + up(&bus->sdsem); + return error; +} + +static ssize_t brcmf_sdio_forensic_read(struct file *f, char __user *data, + size_t count, loff_t *ppos) +{ + struct brcmf_sdio *bus = f->private_data; + int res; + + res = brcmf_sdbrcm_died_dump(bus, data, count, ppos); + if (res > 0) + *ppos += res; + return (ssize_t)res; +} + +static const struct file_operations brcmf_sdio_forensic_ops = { + .owner = THIS_MODULE, + .open = simple_open, + .read = brcmf_sdio_forensic_read +}; + static void brcmf_sdio_debugfs_create(struct brcmf_sdio *bus) { struct brcmf_pub *drvr = bus->sdiodev->bus_if->drvr; + struct dentry *dentry = brcmf_debugfs_get_devdir(drvr); + if (IS_ERR_OR_NULL(dentry)) + return; + + debugfs_create_file("forensics", S_IRUGO, dentry, bus, + &brcmf_sdio_forensic_ops); brcmf_debugfs_create_sdio_count(drvr, &bus->sdcnt); } #else +static int brcmf_sdbrcm_checkdied(struct brcmf_sdio *bus) +{ + return 0; +} + static void brcmf_sdio_debugfs_create(struct brcmf_sdio *bus) { } @@ -2991,11 +3319,13 @@ brcmf_sdbrcm_bus_rxctl(struct device *dev, unsigned char *msg, uint msglen) rxlen, msglen); } else if (timeleft == 0) { brcmf_dbg(ERROR, "resumed on timeout\n"); + brcmf_sdbrcm_checkdied(bus); } else if (pending) { brcmf_dbg(CTL, "cancelled\n"); return -ERESTARTSYS; } else { brcmf_dbg(CTL, "resumed for unknown reason?\n"); + brcmf_sdbrcm_checkdied(bus); } if (rxlen) @@ -3006,45 +3336,10 @@ brcmf_sdbrcm_bus_rxctl(struct device *dev, unsigned char *msg, uint msglen) return rxlen ? (int)rxlen : -ETIMEDOUT; } -static int brcmf_sdbrcm_downloadvars(struct brcmf_sdio *bus, void *arg, int len) -{ - int bcmerror = 0; - - brcmf_dbg(TRACE, "Enter\n"); - - /* Basic sanity checks */ - if (bus->sdiodev->bus_if->drvr_up) { - bcmerror = -EISCONN; - goto err; - } - if (!len) { - bcmerror = -EOVERFLOW; - goto err; - } - - /* Free the old ones and replace with passed variables */ - kfree(bus->vars); - - bus->vars = kmalloc(len, GFP_ATOMIC); - bus->varsz = bus->vars ? len : 0; - if (bus->vars == NULL) { - bcmerror = -ENOMEM; - goto err; - } - - /* Copy the passed variables, which should include the - terminating double-null */ - memcpy(bus->vars, arg, bus->varsz); -err: - return bcmerror; -} - static int brcmf_sdbrcm_write_vars(struct brcmf_sdio *bus) { int bcmerror = 0; - u32 varsize; u32 varaddr; - u8 *vbuffer; u32 varsizew; __le32 varsizew_le; #ifdef DEBUG @@ -3053,56 +3348,44 @@ static int brcmf_sdbrcm_write_vars(struct brcmf_sdio *bus) /* Even if there are no vars are to be written, we still need to set the ramsize. */ - varsize = bus->varsz ? roundup(bus->varsz, 4) : 0; - varaddr = (bus->ramsize - 4) - varsize; + varaddr = (bus->ramsize - 4) - bus->varsz; if (bus->vars) { - vbuffer = kzalloc(varsize, GFP_ATOMIC); - if (!vbuffer) - return -ENOMEM; - - memcpy(vbuffer, bus->vars, bus->varsz); - /* Write the vars list */ - bcmerror = - brcmf_sdbrcm_membytes(bus, true, varaddr, vbuffer, varsize); + bcmerror = brcmf_sdbrcm_membytes(bus, true, varaddr, + bus->vars, bus->varsz); #ifdef DEBUG /* Verify NVRAM bytes */ - brcmf_dbg(INFO, "Compare NVRAM dl & ul; varsize=%d\n", varsize); - nvram_ularray = kmalloc(varsize, GFP_ATOMIC); - if (!nvram_ularray) { - kfree(vbuffer); + brcmf_dbg(INFO, "Compare NVRAM dl & ul; varsize=%d\n", + bus->varsz); + nvram_ularray = kmalloc(bus->varsz, GFP_ATOMIC); + if (!nvram_ularray) return -ENOMEM; - } /* Upload image to verify downloaded contents. */ - memset(nvram_ularray, 0xaa, varsize); + memset(nvram_ularray, 0xaa, bus->varsz); /* Read the vars list to temp buffer for comparison */ - bcmerror = - brcmf_sdbrcm_membytes(bus, false, varaddr, nvram_ularray, - varsize); + bcmerror = brcmf_sdbrcm_membytes(bus, false, varaddr, + nvram_ularray, bus->varsz); if (bcmerror) { brcmf_dbg(ERROR, "error %d on reading %d nvram bytes at 0x%08x\n", - bcmerror, varsize, varaddr); + bcmerror, bus->varsz, varaddr); } /* Compare the org NVRAM with the one read from RAM */ - if (memcmp(vbuffer, nvram_ularray, varsize)) + if (memcmp(bus->vars, nvram_ularray, bus->varsz)) brcmf_dbg(ERROR, "Downloaded NVRAM image is corrupted\n"); else brcmf_dbg(ERROR, "Download/Upload/Compare of NVRAM ok\n"); kfree(nvram_ularray); #endif /* DEBUG */ - - kfree(vbuffer); } /* adjust to the user specified RAM */ brcmf_dbg(INFO, "Physical memory size: %d\n", bus->ramsize); brcmf_dbg(INFO, "Vars are at %d, orig varsize is %d\n", - varaddr, varsize); - varsize = ((bus->ramsize - 4) - varaddr); + varaddr, bus->varsz); /* * Determine the length token: @@ -3113,13 +3396,13 @@ static int brcmf_sdbrcm_write_vars(struct brcmf_sdio *bus) varsizew = 0; varsizew_le = cpu_to_le32(0); } else { - varsizew = varsize / 4; + varsizew = bus->varsz / 4; varsizew = (~varsizew << 16) | (varsizew & 0x0000FFFF); varsizew_le = cpu_to_le32(varsizew); } brcmf_dbg(INFO, "New varsize is %d, length token=0x%08x\n", - varsize, varsizew); + bus->varsz, varsizew); /* Write the length token to the last word */ bcmerror = brcmf_sdbrcm_membytes(bus, true, (bus->ramsize - 4), @@ -3243,13 +3526,21 @@ err: * by two NULs. */ -static uint brcmf_process_nvram_vars(char *varbuf, uint len) +static int brcmf_process_nvram_vars(struct brcmf_sdio *bus) { + char *varbuf; char *dp; bool findNewline; int column; - uint buf_len, n; + int ret = 0; + uint buf_len, n, len; + + len = bus->firmware->size; + varbuf = vmalloc(len); + if (!varbuf) + return -ENOMEM; + memcpy(varbuf, bus->firmware->data, len); dp = varbuf; findNewline = false; @@ -3278,56 +3569,44 @@ static uint brcmf_process_nvram_vars(char *varbuf, uint len) column++; } buf_len = dp - varbuf; - while (dp < varbuf + n) *dp++ = 0; - return buf_len; + kfree(bus->vars); + /* roundup needed for download to device */ + bus->varsz = roundup(buf_len + 1, 4); + bus->vars = kmalloc(bus->varsz, GFP_KERNEL); + if (bus->vars == NULL) { + bus->varsz = 0; + ret = -ENOMEM; + goto err; + } + + /* copy the processed variables and add null termination */ + memcpy(bus->vars, varbuf, buf_len); + bus->vars[buf_len] = 0; +err: + vfree(varbuf); + return ret; } static int brcmf_sdbrcm_download_nvram(struct brcmf_sdio *bus) { - uint len; - char *memblock = NULL; - char *bufp; int ret; + if (bus->sdiodev->bus_if->drvr_up) + return -EISCONN; + ret = request_firmware(&bus->firmware, BRCMF_SDIO_NV_NAME, &bus->sdiodev->func[2]->dev); if (ret) { brcmf_dbg(ERROR, "Fail to request nvram %d\n", ret); return ret; } - bus->fw_ptr = 0; - memblock = kmalloc(MEMBLOCK, GFP_ATOMIC); - if (memblock == NULL) { - ret = -ENOMEM; - goto err; - } - - len = brcmf_sdbrcm_get_image(memblock, MEMBLOCK, bus); - - if (len > 0 && len < MEMBLOCK) { - bufp = memblock; - bufp[len] = 0; - len = brcmf_process_nvram_vars(bufp, len); - bufp += len; - *bufp++ = 0; - if (len) - ret = brcmf_sdbrcm_downloadvars(bus, memblock, len + 1); - if (ret) - brcmf_dbg(ERROR, "error downloading vars: %d\n", ret); - } else { - brcmf_dbg(ERROR, "error reading nvram file: %d\n", len); - ret = -EIO; - } - -err: - kfree(memblock); + ret = brcmf_process_nvram_vars(bus); release_firmware(bus->firmware); - bus->fw_ptr = 0; return ret; } @@ -3606,6 +3885,8 @@ static bool brcmf_sdbrcm_chipmatch(u16 chipid) return true; if (chipid == BCM4330_CHIP_ID) return true; + if (chipid == BCM4334_CHIP_ID) + return true; return false; } @@ -3817,6 +4098,7 @@ static void brcmf_sdbrcm_release_dongle(struct brcmf_sdio *bus) static void brcmf_sdbrcm_release(struct brcmf_sdio *bus) { brcmf_dbg(TRACE, "Enter\n"); + if (bus) { /* De-register interrupt handler */ brcmf_sdio_intr_unregister(bus->sdiodev); @@ -3838,6 +4120,10 @@ void *brcmf_sdbrcm_probe(u32 regsva, struct brcmf_sdio_dev *sdiodev) { int ret; struct brcmf_sdio *bus; + struct brcmf_bus_dcmd *dlst; + u32 dngl_txglom; + u32 dngl_txglomalign; + u8 idx; brcmf_dbg(TRACE, "Enter\n"); @@ -3923,6 +4209,26 @@ void *brcmf_sdbrcm_probe(u32 regsva, struct brcmf_sdio_dev *sdiodev) brcmf_sdio_debugfs_create(bus); brcmf_dbg(INFO, "completed!!\n"); + /* sdio bus core specific dcmd */ + idx = brcmf_sdio_chip_getinfidx(bus->ci, BCMA_CORE_SDIO_DEV); + dlst = kzalloc(sizeof(struct brcmf_bus_dcmd), GFP_KERNEL); + if (dlst) { + if (bus->ci->c_inf[idx].rev < 12) { + /* for sdio core rev < 12, disable txgloming */ + dngl_txglom = 0; + dlst->name = "bus:txglom"; + dlst->param = (char *)&dngl_txglom; + dlst->param_len = sizeof(u32); + } else { + /* otherwise, set txglomalign */ + dngl_txglomalign = bus->sdiodev->bus_if->align; + dlst->name = "bus:txglomalign"; + dlst->param = (char *)&dngl_txglomalign; + dlst->param_len = sizeof(u32); + } + list_add(&dlst->list, &bus->sdiodev->bus_if->dcmd_list); + } + /* if firmware path present try to download and bring up bus */ ret = brcmf_bus_start(bus->sdiodev->dev); if (ret != 0) { diff --git a/drivers/net/wireless/brcm80211/brcmfmac/sdio_chip.c b/drivers/net/wireless/brcm80211/brcmfmac/sdio_chip.c index f8e1f1c84d08..58155e23d220 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/sdio_chip.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/sdio_chip.c @@ -403,6 +403,23 @@ static int brcmf_sdio_chip_recognition(struct brcmf_sdio_dev *sdiodev, ci->c_inf[3].cib = 0x03004211; ci->ramsize = 0x48000; break; + case BCM4334_CHIP_ID: + ci->c_inf[0].wrapbase = 0x18100000; + ci->c_inf[0].cib = 0x29004211; + ci->c_inf[1].id = BCMA_CORE_SDIO_DEV; + ci->c_inf[1].base = 0x18002000; + ci->c_inf[1].wrapbase = 0x18102000; + ci->c_inf[1].cib = 0x0d004211; + ci->c_inf[2].id = BCMA_CORE_INTERNAL_MEM; + ci->c_inf[2].base = 0x18004000; + ci->c_inf[2].wrapbase = 0x18104000; + ci->c_inf[2].cib = 0x13080401; + ci->c_inf[3].id = BCMA_CORE_ARM_CM3; + ci->c_inf[3].base = 0x18003000; + ci->c_inf[3].wrapbase = 0x18103000; + ci->c_inf[3].cib = 0x07004211; + ci->ramsize = 0x80000; + break; default: brcmf_dbg(ERROR, "chipid 0x%x is not supported\n", ci->chip); return -ENODEV; diff --git a/drivers/net/wireless/brcm80211/brcmsmac/channel.c b/drivers/net/wireless/brcm80211/brcmsmac/channel.c index eb77ac3cfb6b..2d365d3486df 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/channel.c +++ b/drivers/net/wireless/brcm80211/brcmsmac/channel.c @@ -15,7 +15,9 @@ */ #include <linux/types.h> +#include <net/cfg80211.h> #include <net/mac80211.h> +#include <net/regulatory.h> #include <defs.h> #include "pub.h" @@ -23,73 +25,17 @@ #include "main.h" #include "stf.h" #include "channel.h" +#include "mac80211_if.h" /* 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 #define LOCALE_MIMO_IDX_11n 0 -/* max of BAND_5G_PWR_LVLS and 6 for 2.4 GHz */ -#define BRCMS_MAXPWR_TBL_SIZE 6 /* max of BAND_5G_PWR_LVLS and 14 for 2.4 GHz */ #define BRCMS_MAXPWR_MIMO_TBL_SIZE 14 -/* power level in group of 2.4GHz band channels: - * maxpwr[0] - CCK channels [1] - * maxpwr[1] - CCK channels [2-10] - * maxpwr[2] - CCK channels [11-14] - * maxpwr[3] - OFDM channels [1] - * maxpwr[4] - OFDM channels [2-10] - * maxpwr[5] - OFDM channels [11-14] - */ - /* maxpwr mapping to 5GHz band channels: * maxpwr[0] - channels [34-48] * maxpwr[1] - channels [52-60] @@ -101,16 +47,8 @@ #define LC(id) LOCALE_MIMO_IDX_ ## id -#define LC_2G(id) LOCALE_2G_IDX_ ## id - -#define LC_5G(id) LOCALE_5G_IDX_ ## id - -#define LOCALES(band2, band5, mimo2, mimo5) \ - {LC_2G(band2), LC_5G(band5), LC(mimo2), LC(mimo5)} - -/* macro to get 2.4 GHz channel group index for tx power */ -#define CHANNEL_POWER_IDX_2G_CCK(c) (((c) < 2) ? 0 : (((c) < 11) ? 1 : 2)) -#define CHANNEL_POWER_IDX_2G_OFDM(c) (((c) < 2) ? 3 : (((c) < 11) ? 4 : 5)) +#define LOCALES(mimo2, mimo5) \ + {LC(mimo2), LC(mimo5)} /* macro to get 5 GHz channel group index for tx power */ #define CHANNEL_POWER_IDX_5G(c) (((c) < 52) ? 0 : \ @@ -118,18 +56,37 @@ (((c) < 100) ? 2 : \ (((c) < 149) ? 3 : 4)))) -#define ISDFS_EU(fl) (((fl) & BRCMS_DFS_EU) == BRCMS_DFS_EU) - -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]; +#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_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_5GHZ_5180_5240, + BRCM_5GHZ_5260_5320, + BRCM_5GHZ_5500_5700, + BRCM_5GHZ_5745_5825, + } }; /* locale per-channel tx power limits for MIMO frames @@ -141,337 +98,23 @@ 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]; - u8 flags; }; /* Country names and abbreviations with locale defined from ISO 3166 */ struct country_info { - const u8 locale_2G; /* 2.4G band locale */ - const u8 locale_5G; /* 5G band locale */ const u8 locale_mimo_2G; /* 2.4G mimo info */ const u8 locale_mimo_5G; /* 5G mimo info */ }; +struct brcms_regd { + struct country_info country; + const struct ieee80211_regdomain *regdomain; +}; + struct brcms_cm_info { struct brcms_pub *pub; struct brcms_c_info *wlc; - 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]; - 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) -{ - 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]); - } -} - -/* - * 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 -}; - -/* - * 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 -}; - -static const struct locale_info *g_locale_2g_table[] = { - &locale_i -}; - -static const struct locale_info *g_locale_5g_table[] = { - &locale_11 + const struct brcms_regd *world_regd; }; /* @@ -484,7 +127,6 @@ static const struct locale_mimo_info locale_bn = { {0, 0, QDB(13), QDB(13), QDB(13), QDB(13), QDB(13), QDB(13), QDB(13), QDB(13), QDB(13), 0, 0}, - 0 }; static const struct locale_mimo_info *g_mimo_2g_table[] = { @@ -497,114 +139,20 @@ static const struct locale_mimo_info *g_mimo_2g_table[] = { static const struct locale_mimo_info locale_11n = { { /* 12.5 dBm */ 50, 50, 50, QDB(15), QDB(15)}, {QDB(14), QDB(15), QDB(15), QDB(15), QDB(15)}, - 0 }; 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 */ -}; - -#ifdef SUPPORT_40MHZ -/* 20MHz channel info for 40MHz pairing support */ -struct chan20_info { - u8 sb; - u8 adj_sbs; + .country = LOCALES(bn, 11n), + .regdomain = &brcms_regdom_x2, + }, }; -/* 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 */ - -static const struct locale_info *brcms_c_get_locale_2g(u8 locale_idx) -{ - if (locale_idx >= ARRAY_SIZE(g_locale_2g_table)) - return NULL; /* error condition */ - - return g_locale_2g_table[locale_idx]; -} - -static const struct locale_info *brcms_c_get_locale_5g(u8 locale_idx) -{ - if (locale_idx >= ARRAY_SIZE(g_locale_5g_table)) - return NULL; /* error condition */ - - return g_locale_5g_table[locale_idx]; -} - static const struct locale_mimo_info *brcms_c_get_mimo_2g(u8 locale_idx) { if (locale_idx >= ARRAY_SIZE(g_mimo_2g_table)) @@ -621,13 +169,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; -} - /* * Indicates whether the country provided is valid to pass * to cfg80211 or not. @@ -662,155 +203,24 @@ static bool brcms_c_country_valid(const char *ccode) return true; } -/* 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) +static const struct brcms_regd *brcms_world_regd(const char *regdom, int len) { - 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]; + const struct brcms_regd *regd = NULL; + int i; + for (i = 0; i < ARRAY_SIZE(cntry_locales); i++) { + if (!strncmp(regdom, cntry_locales[i].regdomain->alpha2, len)) { + regd = &cntry_locales[i]; + break; + } } -} - -/* 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)); + return regd; } -/* 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) +static const struct brcms_regd *brcms_default_world_regd(void) { - 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)); + return &cntry_locales[0]; } /* JP, J1 - J10 are Japan ccodes */ @@ -820,12 +230,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, @@ -901,140 +305,16 @@ brcms_c_channel_min_txpower_limits_with_local_constraint( } -/* 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 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); - 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); - } -} - -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; - struct brcms_band *band; - const struct locale_info *li; - struct brcms_chanvec sup_chan; - const struct locale_mimo_info *li_mimo; - - band = wlc->band; - for (i = 0; i < wlc->pub->_nbands; - i++, band = wlc->bandstate[OTHERBANDUNIT(wlc)]) { - - li = (band->bandtype == BRCM_BAND_5G) ? - brcms_c_get_locale_5g(country->locale_5G) : - brcms_c_get_locale_2g(country->locale_2G); - wlc_cm->bandstate[band->bandunit].locale_flags = li->flags; - li_mimo = (band->bandtype == BRCM_BAND_5G) ? - brcms_c_get_mimo_5g(country->locale_mimo_5G) : - brcms_c_get_mimo_2g(country->locale_mimo_2G); - - /* 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); - brcms_c_channels_commit(wlc_cm); - - return 0; -} - /* * set the driver's current country and regulatory information * using a country code as the source. Look up built in country * 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; 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) @@ -1042,75 +322,19 @@ 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_channels_init(wlc_cm, country); + brcms_c_set_gmode(wlc, wlc->protection->gmode_user, false); 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; struct ssb_sprom *sprom = &wlc->hw->d11core->bus->sprom; + const char *ccode = sprom->alpha2; + int ccode_len = sizeof(sprom->alpha2); BCMMSG(wlc->wiphy, "wl%d\n", wlc->pub->unit); @@ -1122,24 +346,27 @@ struct brcms_cm_info *brcms_c_channel_mgr_attach(struct brcms_c_info *wlc) wlc->cmi = wlc_cm; /* store the country code for passing up as a regulatory hint */ - if (sprom->alpha2 && brcms_c_country_valid(sprom->alpha2)) - strncpy(wlc->pub->srom_ccode, sprom->alpha2, sizeof(sprom->alpha2)); + wlc_cm->world_regd = brcms_world_regd(ccode, ccode_len); + if (brcms_c_country_valid(ccode)) + strncpy(wlc->pub->srom_ccode, ccode, ccode_len); /* - * 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) { + wlc_cm->world_regd = brcms_default_world_regd(); + ccode = wlc_cm->world_regd->regdomain->alpha2; + ccode_len = BRCM_CNTRY_BUF_SZ - 1; + } /* save default country for exiting 11d regulatory mode */ - strncpy(wlc->country_default, country_abbrev, BRCM_CNTRY_BUF_SZ - 1); + strncpy(wlc->country_default, ccode, ccode_len); /* initialize autocountry_default to driver default */ - strncpy(wlc->autocountry_default, "X2", BRCM_CNTRY_BUF_SZ - 1); + strncpy(wlc->autocountry_default, ccode, ccode_len); - brcms_c_set_countrycode(wlc_cm, country_abbrev); + brcms_c_set_country(wlc_cm, wlc_cm->world_regd); return wlc_cm; } @@ -1149,31 +376,15 @@ void brcms_c_channel_mgr_detach(struct brcms_cm_info *wlc_cm) kfree(wlc_cm); } -u8 -brcms_c_channel_locale_flags_in_band(struct brcms_cm_info *wlc_cm, - uint bandunit) -{ - 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 brcms_c_info *wlc = wlc_cm->wlc; + struct ieee80211_channel *ch = wlc->pub->ieee_hw->conf.channel; + const struct ieee80211_reg_rule *reg_rule; struct txpwr_limits txpwr; + int ret; brcms_c_channel_reg_limits(wlc_cm, chanspec, &txpwr); @@ -1181,8 +392,15 @@ brcms_c_channel_set_chanspec(struct brcms_cm_info *wlc_cm, u16 chanspec, wlc_cm, &txpwr, local_constraint_qdbm ); + /* set or restore gmode as required by regulatory */ + ret = freq_reg_info(wlc->wiphy, ch->center_freq, 0, ®_rule); + if (!ret && (reg_rule->flags & NL80211_RRF_NO_OFDM)) + brcms_c_set_gmode(wlc, GMODE_LEGACY_B, false); + else + brcms_c_set_gmode(wlc, wlc->protection->gmode_user, false); + brcms_b_set_chanspec(wlc->hw, chanspec, - (brcms_c_quiet_chanspec(wlc_cm, chanspec) != 0), + !!(ch->flags & IEEE80211_CHAN_PASSIVE_SCAN), &txpwr); } @@ -1191,15 +409,14 @@ brcms_c_channel_reg_limits(struct brcms_cm_info *wlc_cm, u16 chanspec, struct txpwr_limits *txpwr) { struct brcms_c_info *wlc = wlc_cm->wlc; + struct ieee80211_channel *ch = wlc->pub->ieee_hw->conf.channel; uint i; uint chan; int maxpwr; int delta; const struct country_info *country; 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; @@ -1207,67 +424,35 @@ 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; - } + if (WARN_ON(!ch)) + return; + + country = &wlc_cm->world_regd->country; chan = CHSPEC_CHANNEL(chanspec); band = wlc->bandstate[chspec_bandunit(chanspec)]; - li = (band->bandtype == BRCM_BAND_5G) ? - brcms_c_get_locale_5g(country->locale_5G) : - brcms_c_get_locale_2g(country->locale_2G); - li_mimo = (band->bandtype == BRCM_BAND_5G) ? brcms_c_get_mimo_5g(country->locale_mimo_5G) : brcms_c_get_mimo_2g(country->locale_mimo_2G); - if (li->flags & BRCMS_EIRP) { - delta = band->antgain; - } else { - delta = 0; - if (band->antgain > QDB(6)) - delta = band->antgain - QDB(6); /* Excess over 6 dB */ - } + delta = band->antgain; - if (li == &locale_i) { + if (band->bandtype == BRCM_BAND_2G) conducted_max = QDB(22); - conducted_ofdm_max = QDB(22); - } + + maxpwr = QDB(ch->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. @@ -1282,14 +467,9 @@ brcms_c_channel_reg_limits(struct brcms_cm_info *wlc_cm, u16 chanspec, txpwr->ofdm_40_cdd[i] = 0; } - /* MIMO/HT specific limits */ - if (li_mimo->flags & BRCMS_EIRP) { - delta = band->antgain; - } else { - delta = 0; - if (band->antgain > QDB(6)) - delta = band->antgain - QDB(6); /* Excess over 6 dB */ - } + delta = 0; + if (band->antgain > QDB(6)) + delta = band->antgain - QDB(6); /* Excess over 6 dB */ if (band->bandtype == BRCM_BAND_2G) maxpwr_idx = (chan - 1); @@ -1431,8 +611,7 @@ static bool brcms_c_chspec_malformed(u16 chanspec) * 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); @@ -1448,59 +627,166 @@ 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); +} + +static 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; +} + +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 *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 (ch->flags & + (IEEE80211_CHAN_DISABLED | IEEE80211_CHAN_RADAR)) + continue; + + if (initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE) { + ret = freq_reg_info(wiphy, ch->center_freq, + 0, &rule); + if (ret) + continue; + + if (!(rule->flags & NL80211_RRF_NO_IBSS)) + ch->flags &= ~IEEE80211_CHAN_NO_IBSS; + if (!(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); + } } + } +} - /* 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 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; + struct ieee80211_supported_band *sband; + struct ieee80211_channel *ch; + int band, i; + bool ch_found = false; + + brcms_reg_apply_radar_flags(wiphy); + + if (request->initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE) + brcms_reg_apply_beaconing_flags(wiphy, request->initiator); + + /* Disable radio if all channels disallowed by regulatory */ + for (band = 0; !ch_found && band < IEEE80211_NUM_BANDS; band++) { + sband = wiphy->bands[band]; + if (!sband) + continue; + + for (i = 0; !ch_found && i < sband->n_channels; i++) { + ch = &sband->channels[i]; + + if (!(ch->flags & IEEE80211_CHAN_DISABLED)) + ch_found = true; } - /* 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; + if (ch_found) { + mboolclr(wlc->pub->radio_disabled, WL_RADIO_COUNTRY_DISABLE); + } else { + mboolset(wlc->pub->radio_disabled, WL_RADIO_COUNTRY_DISABLE); + wiphy_err(wlc->wiphy, "wl%d: %s: no valid channel for \"%s\"\n", + wlc->pub->unit, __func__, request->alpha2); + } + + 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 = wlc->wiphy; + 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]; + + /* skip if band not initialized */ + if (band->pi == NULL) + continue; + + 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_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 808cb4fbfbe7..006483a0abe6 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/channel.h +++ b/drivers/net/wireless/brcm80211/brcmsmac/channel.h @@ -37,9 +37,6 @@ brcms_c_channel_mgr_attach(struct brcms_c_info *wlc); extern void brcms_c_channel_mgr_detach(struct brcms_cm_info *wlc_cm); -extern u8 brcms_c_channel_locale_flags_in_band(struct brcms_cm_info *wlc_cm, - uint bandunit); - extern bool brcms_c_valid_chanspec_db(struct brcms_cm_info *wlc_cm, u16 chspec); @@ -49,5 +46,6 @@ extern void brcms_c_channel_reg_limits(struct brcms_cm_info *wlc_cm, extern void brcms_c_channel_set_chanspec(struct brcms_cm_info *wlc_cm, u16 chanspec, u8 local_constraint_qdbm); +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 341e06a0d6ec..2d5a40412690 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c +++ b/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c @@ -1050,6 +1050,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; diff --git a/drivers/net/wireless/brcm80211/brcmsmac/main.c b/drivers/net/wireless/brcm80211/brcmsmac/main.c index e67556780a31..bb00b6528d8f 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/main.c +++ b/drivers/net/wireless/brcm80211/brcmsmac/main.c @@ -18,6 +18,7 @@ #include <linux/pci_ids.h> #include <linux/if_ether.h> +#include <net/cfg80211.h> #include <net/mac80211.h> #include <brcm_hw_ids.h> #include <aiutils.h> @@ -3139,20 +3140,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; @@ -5129,6 +5116,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 */ @@ -5195,8 +5184,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); } @@ -5397,11 +5387,6 @@ int brcms_c_set_gmode(struct brcms_c_info *wlc, u8 gmode, bool config) else return -EINVAL; - /* Legacy or bust when no OFDM is supported by regulatory */ - if ((brcms_c_channel_locale_flags_in_band(wlc->cmi, band->bandunit) & - BRCMS_NO_OFDM) && (gmode != GMODE_LEGACY_B)) - return -EINVAL; - /* update configuration value */ if (config) brcms_c_protection_upd(wlc, BRCMS_PROT_G_USER, gmode); @@ -8201,19 +8186,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/include/brcm_hw_ids.h b/drivers/net/wireless/brcm80211/include/brcm_hw_ids.h index 333193f20e1c..bcc79b4e3267 100644 --- a/drivers/net/wireless/brcm80211/include/brcm_hw_ids.h +++ b/drivers/net/wireless/brcm80211/include/brcm_hw_ids.h @@ -37,5 +37,6 @@ #define BCM4329_CHIP_ID 0x4329 #define BCM4330_CHIP_ID 0x4330 #define BCM4331_CHIP_ID 0x4331 +#define BCM4334_CHIP_ID 0x4334 #endif /* _BRCM_HW_IDS_H_ */ |