diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
index 0ee421f30aa24..8f7db434de111 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
@@ -5136,8 +5136,13 @@ brcmf_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
ie_offset = DOT11_MGMT_HDR_LEN +
DOT11_BCN_PRB_FIXED_LEN;
ie_len = len - ie_offset;
- if (vif == cfg->p2p.bss_idx[P2PAPI_BSSCFG_PRIMARY].vif)
+ if (vif == cfg->p2p.bss_idx[P2PAPI_BSSCFG_PRIMARY].vif) {
vif = cfg->p2p.bss_idx[P2PAPI_BSSCFG_DEVICE].vif;
+ if (vif == NULL) {
+ bphy_err(drvr, "No p2p device available for probe response\n");
+ return -ENODEV;
+ }
+ }
-static char brcmf_firmware_path[BRCMF_FW_ALTPATH_LEN];
+char brcmf_firmware_path[BRCMF_FW_ALTPATH_LEN];
module_param_string(alternative_fw_path, brcmf_firmware_path,
- BRCMF_FW_ALTPATH_LEN, 0400);
+ BRCMF_FW_ALTPATH_LEN, 0600);
MODULE_PARM_DESC(alternative_fw_path, "Alternative firmware path");
+char brcmf_mac_addr[18];
+module_param_string(nvram_mac_addr, brcmf_mac_addr,
+ 18, 0600);
+MODULE_PARM_DESC(nvram_mac_addr, "Set MAC address in NVRAM");
+
+char brcmf_otp_chip_id[BRCMF_OTP_VERSION_MAX];
+module_param_string(otp_chip_id, brcmf_otp_chip_id, BRCMF_OTP_VERSION_MAX, 0400);
+MODULE_PARM_DESC(otp_chip_id, "Chip ID and revision from OTP");
+
+char brcmf_otp_nvram_id[BRCMF_OTP_VERSION_MAX];
+module_param_string(otp_nvram_id, brcmf_otp_nvram_id, BRCMF_OTP_VERSION_MAX, 0400);
+MODULE_PARM_DESC(otp_chip_id, "NVRAM variant from OTP");
+
static int brcmf_fcmode;
module_param_named(fcmode, brcmf_fcmode, int, 0);
MODULE_PARM_DESC(fcmode, "Mode of firmware signalled flow control");
@@ -75,7 +88,6 @@ MODULE_PARM_DESC(ignore_probe_fail, "always succeed probe for debugging");
#endif
static struct brcmfmac_platform_data *brcmfmac_pdata;
-struct brcmf_mp_global_t brcmf_mp_global;
void brcmf_c_set_joinpref_default(struct brcmf_if *ifp)
{
@@ -376,22 +388,6 @@ void __brcmf_dbg(u32 level, const char *func, const char *fmt, ...)
}
#endif
-static void brcmf_mp_attach(void)
-{
- /* If module param firmware path is set then this will always be used,
- * if not set then if available use the platform data version. To make
- * sure it gets initialized at all, always copy the module param version
- */
- strlcpy(brcmf_mp_global.firmware_path, brcmf_firmware_path,
- BRCMF_FW_ALTPATH_LEN);
- if ((brcmfmac_pdata) && (brcmfmac_pdata->fw_alternative_path) &&
- (brcmf_mp_global.firmware_path[0] == '\0')) {
- strlcpy(brcmf_mp_global.firmware_path,
- brcmfmac_pdata->fw_alternative_path,
- BRCMF_FW_ALTPATH_LEN);
- }
-}
+static void brcmf_fw_set_macaddr(struct nvram_parser *nvp, const char *mac_addr)
+{
+ uint8_t mac[6] = { 0 };
+ size_t len = strlen("macaddr=") + 17 + 1; /* 17 = "aa:bb:cc:dd:ee:ff" */
+ unsigned i = 0;
+ unsigned long res = 0;
+ char tmp[3];
+
+ while(mac_addr[0] && mac_addr[1] && i < 6) {
+ tmp[0] = mac_addr[0];
+ tmp[1] = mac_addr[1];
+ tmp[2] = 0;
+ if(kstrtoul(tmp, 16, &res))
+ break;
+ mac[i] = res;
+ mac_addr += 2;
+ i ++;
+ while(*mac_addr == ':' || *mac_addr == ' ' || *mac_addr == '-')
+ mac_addr ++;
+ }
+ if(i < 6)
+ pr_warn("invalid MAC address supplied for brcmfmac!\n");
+
+ memmove(&nvp->nvram[len], &nvp->nvram[0], nvp->nvram_len);
+ nvp->nvram_len += len;
+ sprintf(&nvp->nvram[0], "macaddr=%02x:%02x:%02x:%02x:%02x:%02x",
+ mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
+}
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c
index ec6fc7a150a6a..1c1d5131c3f36 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c
@@ -565,7 +565,8 @@ static s32 brcmf_p2p_deinit_discovery(struct brcmf_p2p_info *p2p)
/* Set the discovery state to SCAN */
vif = p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif;
- (void)brcmf_p2p_set_discover_state(vif->ifp, WL_P2P_DISC_ST_SCAN, 0, 0);
+ if (vif != NULL)
+ (void)brcmf_p2p_set_discover_state(vif->ifp, WL_P2P_DISC_ST_SCAN, 0, 0);
/* Disable P2P discovery in the firmware */
vif = p2p->bss_idx[P2PAPI_BSSCFG_PRIMARY].vif;
@@ -1351,6 +1352,8 @@ brcmf_p2p_gon_req_collision(struct brcmf_p2p_info *p2p, u8 *mac)
* if not (sa addr > da addr),
* this device will process gon request and drop gon req of peer.
*/
+ if(p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif == NULL)
+ return false;
ifp = p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif->ifp;
if (memcmp(mac, ifp->mac_addr, ETH_ALEN) < 0) {
brcmf_dbg(INFO, "Block transmit gon req !!!\n");
@@ -1559,6 +1562,10 @@ static s32 brcmf_p2p_tx_action_frame(struct brcmf_p2p_info *p2p,
else
vif = p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif;
+ if (vif == NULL) {
+ bphy_err(drvr, " no P2P interface available\n");
+ goto exit;
+ }
err = brcmf_fil_bsscfg_data_set(vif->ifp, "actframe", af_params,
sizeof(*af_params));
if (err) {
+static u32
+brcmf_pcie_reg_map(struct brcmf_pciedev_info *devinfo, u32 reg)
+{
+ switch(reg) {
+ case BRCMF_PCIE_PCIE2REG_INTMASK:
+ if(devinfo->ci->chip == BRCM_CC_4378_CHIP_ID)
+ return BRCMF_PCIE_64_PCIE2REG_INTMASK;
+ return reg;
+ case BRCMF_PCIE_PCIE2REG_MAILBOXINT:
+ if(devinfo->ci->chip == BRCM_CC_4378_CHIP_ID)
+ return BRCMF_PCIE_64_PCIE2REG_MAILBOXINT;
+ return reg;
+ case BRCMF_PCIE_PCIE2REG_MAILBOXMASK:
+ if(devinfo->ci->chip == BRCM_CC_4378_CHIP_ID)
+ return BRCMF_PCIE_64_PCIE2REG_MAILBOXMASK;
+ return reg;
+ case BRCMF_PCIE_PCIE2REG_H2D_MAILBOX_0:
+ if(devinfo->ci->chip == BRCM_CC_4378_CHIP_ID)
+ return BRCMF_PCIE_64_PCIE2REG_H2D_MAILBOX_0;
+ return reg;
+ case BRCMF_PCIE_PCIE2REG_H2D_MAILBOX_1:
+ if(devinfo->ci->chip == BRCM_CC_4378_CHIP_ID)
+ return BRCMF_PCIE_64_PCIE2REG_H2D_MAILBOX_1;
+ return reg;
+ default:
+ return reg;
+ }
+}
+
+
+
#define WRITECC32(devinfo, reg, value) brcmf_pcie_write_reg32(devinfo, \
CHIPCREGOFFS(reg), value)
@@ -543,6 +626,7 @@ brcmf_pcie_select_core(struct brcmf_pciedev_info *devinfo, u16 coreid)
core = brcmf_chip_get_core(devinfo->ci, coreid);
if (core) {
bar0_win = core->base;
+
pci_write_config_dword(pdev, BRCMF_PCIE_BAR0_WINDOW, bar0_win);
if (pci_read_config_dword(pdev, BRCMF_PCIE_BAR0_WINDOW,
&bar0_win) == 0) {
@@ -615,11 +699,129 @@ static void brcmf_pcie_reset_device(struct brcmf_pciedev_info *devinfo)
}
}
+#define OTP_SIZE 64
+#define OTP_CORE_ID BCMA_CORE_GCI
+#define OTP_CC_ADDR_4378 0x1120
+
+static void brcmf_pcie_process_otp_tuple(struct brcmf_pciedev_info *devinfo, u8 type, u8 size, u8 *data)
+{
+ char tmp[OTP_SIZE], t_chiprev[8] = "", t_module[8] = "", t_modrev[8] = "", t_vendor[8] = "", t_chip[8] = "";
+ unsigned i, len;
+
+ switch(type) {
+ case 0x15: /* system vendor OTP */
+ if(size < 4)
+ return;
+ if(*(u32 *)data != 8)
+ dev_warn(&devinfo->pdev->dev, "system vendor OTP header unexpected: %d\n", *(u32 *)data);
+ size -= 4;
+ data += 4;
+ while(size) {
+ if(data[0] == 0xFF)
+ break;
+ for(len=0; len<size; len++)
+ if(data[len] == 0x00 || data[len] == ' ' || data[len] == 0xFF)
+ break;
+ memcpy(tmp, data, len);
+ tmp[len] = 0;
+ data += len;
+ size -= len;
+ if(size) {
+ data ++;
+ size --;
+ }
+ brcmf_dbg(PCIE, "system vendor OTP element '%s'\n", tmp);
+
+ if(len < 2)
+ continue;
+ if(tmp[1] == '=' && len < 8)
+ switch(tmp[0]) {
+ case 's':
+ strcpy(t_chiprev, tmp + 2);
+ break;
+ case 'M':
+ strcpy(t_module, tmp + 2);
+ break;
+ case 'm':
+ strcpy(t_modrev, tmp + 2);
+ break;
+ case 'V':
+ strcpy(t_vendor, tmp + 2);
+ break;
+ }
+ }
+
+ sprintf(t_chip, (devinfo->ci->chip > 40000) ? "%05d" : "%04x", devinfo->ci->chip);
+ dev_info(&devinfo->pdev->dev, "module revision data: chip %s, chip rev %s, module %s, module rev %s, vendor %s\n", t_chip, t_chiprev, t_module, t_modrev, t_vendor);
+
+ if(t_chiprev[0])
+ sprintf(brcmf_otp_chip_id, "C-%s__s-%s", t_chip, t_chiprev);
+ else
+ sprintf(brcmf_otp_chip_id, "C-%s", t_chip);
+ sprintf(brcmf_otp_nvram_id, "M-%s_V-%s__m-%s", t_module, t_vendor, t_modrev);
+
+ break;
+ case 0x80: /* Broadcom CIS */
+ if(size < 1)
+ return;
+ switch(data[0]) {
+ case 0x83: /* serial number */
+ for(i=0; i<16 && i<size-1; i++)
+ sprintf(tmp + 2 * i, "%02x", data[i+1]);
+ dev_info(&devinfo->pdev->dev, "module serial number: %s\n", tmp);
+ break;
+ }
+ break;
+ }
+}
+
+static u32 brcmf_pcie_buscore_prep_addr(const struct pci_dev *pdev, u32 addr);
+
+static void brcmf_pcie_read_otp(struct brcmf_pciedev_info *devinfo)
+{
+ u8 otp[OTP_SIZE], type, size;
+ unsigned i;
+ struct brcmf_core *core;
+ u32 base;
+
+ if (devinfo->ci->chip == BRCM_CC_4378_CHIP_ID) {
+ /* for whatever reason, reading OTP works only once after reset */
+ if(brcmf_otp_chip_id[0])
+ return;
+
+ core = brcmf_chip_get_core(devinfo->ci, OTP_CORE_ID);
+ if(!core) {
+ dev_err(&devinfo->pdev->dev, "can't find core for OTP\n");
+ return;
+ }
+ base = brcmf_pcie_buscore_prep_addr(devinfo->pdev, core->base + OTP_CC_ADDR_4378);
+
+ for(i=0; i<OTP_SIZE; i+=2)
+ ((u16 *)otp)[i/2] = brcmf_pcie_read_reg16(devinfo, base + i);
+
+ i = 0;
+ while(i < OTP_SIZE - 1) {
+ type = otp[i];
+ if(!type) { /* null tuple */
+ i ++;
+ continue;
+ }
+ size = otp[i + 1];
+ i += 2;
+ if(i + size <= OTP_SIZE)
+ brcmf_pcie_process_otp_tuple(devinfo, type, size, otp + i);
+ i += size;
+ }
+ }
+}
+
static void brcmf_pcie_attach(struct brcmf_pciedev_info *devinfo)
{
u32 config;
+ brcmf_pcie_read_otp(devinfo);
+
/* BAR1 window may not be sized properly */
brcmf_pcie_select_core(devinfo, BCMA_CORE_PCIE2);
brcmf_pcie_write_reg32(devinfo, BRCMF_PCIE_PCIE2REG_CONFIGADDR, 0x4e0);
@@ -809,30 +1011,34 @@ static void brcmf_pcie_bus_console_read(struct brcmf_pciedev_info *devinfo,
static void brcmf_pcie_intr_disable(struct brcmf_pciedev_info *devinfo)
{
- brcmf_pcie_write_reg32(devinfo, BRCMF_PCIE_PCIE2REG_MAILBOXMASK, 0);
+ brcmf_pcie_write_reg32(devinfo, brcmf_pcie_reg_map(devinfo, BRCMF_PCIE_PCIE2REG_MAILBOXMASK), 0);
}
@@ -1543,6 +1754,8 @@ brcmf_pcie_init_share_ram_info(struct brcmf_pciedev_info *devinfo,
return 0;
}
+#define RANDOMBYTES_SIZE 264
+#define CLEAR_SIZE 256
static int brcmf_pcie_download_fw_nvram(struct brcmf_pciedev_info *devinfo,
const struct firmware *fw, void *nvram,
@@ -1553,15 +1766,16 @@ static int brcmf_pcie_download_fw_nvram(struct brcmf_pciedev_info *devinfo,
u32 sharedram_addr_written;
u32 loop_counter;
int err;
- u32 address;
+ u32 address, clraddr;
u32 resetintr;
+ uint8_t randb[RANDOMBYTES_SIZE];
brcmf_dbg(PCIE, "Halt ARM.\n");
err = brcmf_pcie_enter_download_state(devinfo);
if (err)
return err;
- brcmf_dbg(PCIE, "Download FW %s\n", devinfo->fw_name);
+ brcmf_dbg(PCIE, "Download FW %s 0x%x 0x%x\n", devinfo->fw_name, (unsigned)devinfo->ci->rambase, (unsigned)fw->size);
brcmf_pcie_copy_mem_todev(devinfo, devinfo->ci->rambase,
(void *)fw->data, fw->size);
@@ -1574,20 +1788,38 @@ static int brcmf_pcie_download_fw_nvram(struct brcmf_pciedev_info *devinfo,
brcmf_pcie_write_ram32(devinfo, devinfo->ci->ramsize - 4, 0);
if (nvram) {
- brcmf_dbg(PCIE, "Download NVRAM %s\n", devinfo->nvram_name);
address = devinfo->ci->rambase + devinfo->ci->ramsize -
nvram_len;
+ brcmf_dbg(PCIE, "Download NVRAM %s 0x%x 0x%x\n", devinfo->nvram_name, address, nvram_len);
brcmf_pcie_copy_mem_todev(devinfo, address, nvram, nvram_len);
brcmf_fw_nvram_free(nvram);
+
+ address -= RANDOMBYTES_SIZE;
+ get_random_bytes(randb, RANDOMBYTES_SIZE - 8);
+ memcpy(randb + RANDOMBYTES_SIZE - 8, "\x00\x01\x00\x00\xde\xc0\xed\xfe", 8);
+ brcmf_pcie_copy_mem_todev(devinfo, address, randb, RANDOMBYTES_SIZE);
} else {
brcmf_dbg(PCIE, "No matching NVRAM file found %s\n",
devinfo->nvram_name);
+ address = devinfo->ci->rambase + devinfo->ci->ramsize;
+ }
+
+ memset(randb, 0, CLEAR_SIZE);
+ clraddr = devinfo->ci->rambase + fw->size;
+ while(clraddr < address) {
+ u32 block = address - clraddr;
+ if(block > CLEAR_SIZE)
+ block = CLEAR_SIZE;
+ if(((clraddr + block - 1) ^ clraddr) & -CLEAR_SIZE)
+ block = (CLEAR_SIZE - clraddr) & (CLEAR_SIZE - 1);
+ brcmf_pcie_copy_mem_todev(devinfo, clraddr, randb, block);
+ clraddr += block;
}
sharedram_addr_written = brcmf_pcie_read_ram32(devinfo,
devinfo->ci->ramsize -
4);
- brcmf_dbg(PCIE, "Bring ARM in running state\n");
+ brcmf_dbg(PCIE, "Bring ARM in running state (RAM sign: 0x%08x)\n", sharedram_addr_written);
err = brcmf_pcie_exit_download_state(devinfo, resetintr);
if (err)
return err;
+ if(devinfo->ci->chip == BRCM_CC_4378_CHIP_ID) {
+ brcmf_pcie_read_otp(devinfo);
+
+ if(!brcmf_mac_addr[0]) {
+ dev_info(&pdev->dev, "hardware discovery complete, not starting driver\n");
+ ret = -ENODEV;
+ goto exit;
+ }
+ }