diff options
Diffstat (limited to 'drivers/net/wireless/bcmdhd/aiutils.c')
-rw-r--r-- | drivers/net/wireless/bcmdhd/aiutils.c | 365 |
1 files changed, 251 insertions, 114 deletions
diff --git a/drivers/net/wireless/bcmdhd/aiutils.c b/drivers/net/wireless/bcmdhd/aiutils.c index ea94da5..6292396 100644 --- a/drivers/net/wireless/bcmdhd/aiutils.c +++ b/drivers/net/wireless/bcmdhd/aiutils.c @@ -2,7 +2,7 @@ * Misc utility routines for accessing chip-specific features * of the SiliconBackplane-based Broadcom chips. * - * Copyright (C) 1999-2012, Broadcom Corporation + * Copyright (C) 1999-2014, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -22,7 +22,7 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: aiutils.c 363711 2012-10-19 01:36:13Z $ + * $Id: aiutils.c 432226 2013-10-26 04:34:36Z $ */ #include <bcm_cfg.h> #include <typedefs.h> @@ -42,7 +42,7 @@ #define remap_coreid(sih, coreid) (coreid) #define remap_corerev(sih, corerev) (corerev) - +/* EROM parsing */ static uint32 get_erom_ent(si_t *sih, uint32 **eromptr, uint32 mask, uint32 match) @@ -88,7 +88,7 @@ get_asd(si_t *sih, uint32 **eromptr, uint sp, uint ad, uint st, uint32 *addrl, u if (((asd & ER_TAG1) != ER_ADD) || (((asd & AD_SP_MASK) >> AD_SP_SHIFT) != sp) || ((asd & AD_ST_MASK) != st)) { - + /* This is not what we want, "push" it back */ (*eromptr)--; return 0; } @@ -119,11 +119,12 @@ ai_hwfixup(si_info_t *sii) } - +/* parse the enumeration rom to identify all cores */ void ai_scan(si_t *sih, void *regs, uint devid) { si_info_t *sii = SI_INFO(sih); + si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; chipcregs_t *cc = (chipcregs_t *)regs; uint32 erombase, *eromptr, *eromlim; @@ -135,10 +136,10 @@ ai_scan(si_t *sih, void *regs, uint devid) break; case PCI_BUS: - + /* Set wrappers address */ sii->curwrap = (void *)((uintptr)regs + SI_CORE_SIZE); - + /* Now point the window at the erom */ OSL_PCI_WRITE_CONFIG(sii->osh, PCI_BAR0_WIN, 4, erombase); eromptr = regs; break; @@ -166,7 +167,7 @@ ai_scan(si_t *sih, void *regs, uint devid) br = FALSE; - + /* Grok a component */ cia = get_erom_ent(sih, &eromptr, ER_TAG, ER_CI); if (cia == (ER_END | ER_VALID)) { SI_VMSG(("Found END of erom after %d cores\n", sii->numcores)); @@ -200,7 +201,7 @@ ai_scan(si_t *sih, void *regs, uint devid) if (((mfg == MFGID_ARM) && (cid == DEF_AI_COMP)) || (nsp == 0)) continue; if ((nmw + nsw == 0)) { - + /* A component which is not a core */ if (cid == OOB_ROUTER_CORE_ID) { asd = get_asd(sih, &eromptr, 0, 0, AD_ST_SLAVE, &addrl, &addrh, &sizel, &sizeh); @@ -214,9 +215,9 @@ ai_scan(si_t *sih, void *regs, uint devid) idx = sii->numcores; - sii->cia[idx] = cia; - sii->cib[idx] = cib; - sii->coreid[idx] = remap_coreid(sih, cid); + cores_info->cia[idx] = cia; + cores_info->cib[idx] = cib; + cores_info->coreid[idx] = remap_coreid(sih, cid); for (i = 0; i < nmp; i++) { mpd = get_erom_ent(sih, &eromptr, ER_VALID, ER_VALID); @@ -229,11 +230,13 @@ ai_scan(si_t *sih, void *regs, uint devid) (mpd & MPD_MUI_MASK) >> MPD_MUI_SHIFT)); } - + /* First Slave Address Descriptor should be port 0: + * the main register space for the core + */ asd = get_asd(sih, &eromptr, 0, 0, AD_ST_SLAVE, &addrl, &addrh, &sizel, &sizeh); if (asd == 0) { do { - + /* Try again to see if it is a bridge */ asd = get_asd(sih, &eromptr, 0, 0, AD_ST_BRIDGE, &addrl, &addrh, &sizel, &sizeh); if (asd != 0) @@ -254,21 +257,21 @@ ai_scan(si_t *sih, void *regs, uint devid) } } while (1); } - sii->coresba[idx] = addrl; - sii->coresba_size[idx] = sizel; - + cores_info->coresba[idx] = addrl; + cores_info->coresba_size[idx] = sizel; + /* Get any more ASDs in port 0 */ j = 1; do { asd = get_asd(sih, &eromptr, 0, j, AD_ST_SLAVE, &addrl, &addrh, &sizel, &sizeh); if ((asd != 0) && (j == 1) && (sizel == SI_CORE_SIZE)) { - sii->coresba2[idx] = addrl; - sii->coresba2_size[idx] = sizel; + cores_info->coresba2[idx] = addrl; + cores_info->coresba2_size[idx] = sizel; } j++; } while (asd != 0); - + /* Go through the ASDs for other slave ports */ for (i = 1; i < nsp; i++) { j = 0; do { @@ -285,7 +288,7 @@ ai_scan(si_t *sih, void *regs, uint devid) } } - + /* Now get master wrappers */ for (i = 0; i < nmw; i++) { asd = get_asd(sih, &eromptr, i, 0, AD_ST_MWRAP, &addrl, &addrh, &sizel, &sizeh); @@ -298,10 +301,10 @@ ai_scan(si_t *sih, void *regs, uint devid) goto error; } if (i == 0) - sii->wrapba[idx] = addrl; + cores_info->wrapba[idx] = addrl; } - + /* And finally slave wrappers */ for (i = 0; i < nsw; i++) { uint fwp = (nsp == 1) ? 0 : 1; asd = get_asd(sih, &eromptr, fwp + i, 0, AD_ST_SWRAP, &addrl, &addrh, @@ -315,15 +318,15 @@ ai_scan(si_t *sih, void *regs, uint devid) goto error; } if ((nmw == 0) && (i == 0)) - sii->wrapba[idx] = addrl; + cores_info->wrapba[idx] = addrl; } - + /* Don't record bridges */ if (br) continue; - + /* Done with core */ sii->numcores++; } @@ -334,38 +337,54 @@ error: return; } - +/* This function changes the logical "focus" to the indicated core. + * Return the current core's virtual address. + */ void * ai_setcoreidx(si_t *sih, uint coreidx) { si_info_t *sii = SI_INFO(sih); + si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; uint32 addr, wrap; void *regs; if (coreidx >= MIN(sii->numcores, SI_MAXCORES)) return (NULL); - addr = sii->coresba[coreidx]; - wrap = sii->wrapba[coreidx]; + addr = cores_info->coresba[coreidx]; + wrap = cores_info->wrapba[coreidx]; - + /* + * If the user has provided an interrupt mask enabled function, + * then assert interrupts are disabled before switching the core. + */ ASSERT((sii->intrsenabled_fn == NULL) || !(*(sii)->intrsenabled_fn)((sii)->intr_arg)); switch (BUSTYPE(sih->bustype)) { case SI_BUS: - - if (!sii->regs[coreidx]) { - sii->regs[coreidx] = REG_MAP(addr, SI_CORE_SIZE); - ASSERT(GOODREGS(sii->regs[coreidx])); + /* map new one */ + if (!cores_info->regs[coreidx]) { + cores_info->regs[coreidx] = REG_MAP(addr, SI_CORE_SIZE); + ASSERT(GOODREGS(cores_info->regs[coreidx])); } - sii->curmap = regs = sii->regs[coreidx]; - if (!sii->wrappers[coreidx] && (wrap != 0)) { - sii->wrappers[coreidx] = REG_MAP(wrap, SI_CORE_SIZE); - ASSERT(GOODREGS(sii->wrappers[coreidx])); + sii->curmap = regs = cores_info->regs[coreidx]; + if (!cores_info->wrappers[coreidx] && (wrap != 0)) { + cores_info->wrappers[coreidx] = REG_MAP(wrap, SI_CORE_SIZE); + ASSERT(GOODREGS(cores_info->wrappers[coreidx])); } - sii->curwrap = sii->wrappers[coreidx]; + sii->curwrap = cores_info->wrappers[coreidx]; break; + case PCI_BUS: + /* point bar0 window */ + OSL_PCI_WRITE_CONFIG(sii->osh, PCI_BAR0_WIN, 4, addr); + regs = sii->curmap; + /* point bar0 2nd 4KB window to the primary wrapper */ + if (PCIE_GEN2(sii)) + OSL_PCI_WRITE_CONFIG(sii->osh, PCIE2_BAR0_WIN2, 4, wrap); + else + OSL_PCI_WRITE_CONFIG(sii->osh, PCI_BAR0_WIN2, 4, wrap); + break; case SPI_BUS: case SDIO_BUS: @@ -386,10 +405,12 @@ ai_setcoreidx(si_t *sih, uint coreidx) return regs; } + void ai_coreaddrspaceX(si_t *sih, uint asidx, uint32 *addr, uint32 *size) { si_info_t *sii = SI_INFO(sih); + si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; chipcregs_t *cc = NULL; uint32 erombase, *eromptr, *eromlim; uint i, j, cidx; @@ -397,8 +418,8 @@ ai_coreaddrspaceX(si_t *sih, uint asidx, uint32 *addr, uint32 *size) uint32 asd, addrl, addrh, sizel, sizeh; for (i = 0; i < sii->numcores; i++) { - if (sii->coreid[i] == CC_CORE_ID) { - cc = (chipcregs_t *)sii->regs[i]; + if (cores_info->coreid[i] == CC_CORE_ID) { + cc = (chipcregs_t *)cores_info->regs[i]; break; } } @@ -410,13 +431,13 @@ ai_coreaddrspaceX(si_t *sih, uint asidx, uint32 *addr, uint32 *size) eromlim = eromptr + (ER_REMAPCONTROL / sizeof(uint32)); cidx = sii->curidx; - cia = sii->cia[cidx]; - cib = sii->cib[cidx]; + cia = cores_info->cia[cidx]; + cib = cores_info->cib[cidx]; nmp = (cib & CIB_NMP_MASK) >> CIB_NMP_SHIFT; nsp = (cib & CIB_NSP_MASK) >> CIB_NSP_SHIFT; - + /* scan for cores */ while (eromptr < eromlim) { if ((get_erom_ent(sih, &eromptr, ER_TAG, ER_CI) == cia) && (get_erom_ent(sih, &eromptr, 0, 0) == cib)) { @@ -424,14 +445,14 @@ ai_coreaddrspaceX(si_t *sih, uint asidx, uint32 *addr, uint32 *size) } } - + /* skip master ports */ for (i = 0; i < nmp; i++) get_erom_ent(sih, &eromptr, ER_VALID, ER_VALID); - + /* Skip ASDs in port 0 */ asd = get_asd(sih, &eromptr, 0, 0, AD_ST_SLAVE, &addrl, &addrh, &sizel, &sizeh); if (asd == 0) { - + /* Try again to see if it is a bridge */ asd = get_asd(sih, &eromptr, 0, 0, AD_ST_BRIDGE, &addrl, &addrh, &sizel, &sizeh); } @@ -443,7 +464,7 @@ ai_coreaddrspaceX(si_t *sih, uint asidx, uint32 *addr, uint32 *size) j++; } while (asd != 0); - + /* Go through the ASDs for other slave ports */ for (i = 1; i < nsp; i++) { j = 0; do { @@ -471,27 +492,27 @@ error: return; } - +/* Return the number of address spaces in current core */ int ai_numaddrspaces(si_t *sih) { return 2; } - +/* Return the address of the nth address space in the current core */ uint32 ai_addrspace(si_t *sih, uint asidx) { - si_info_t *sii; + si_info_t *sii = SI_INFO(sih); + si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; uint cidx; - sii = SI_INFO(sih); cidx = sii->curidx; if (asidx == 0) - return sii->coresba[cidx]; + return cores_info->coresba[cidx]; else if (asidx == 1) - return sii->coresba2[cidx]; + return cores_info->coresba2[cidx]; else { SI_ERROR(("%s: Need to parse the erom again to find addr space %d\n", __FUNCTION__, asidx)); @@ -499,20 +520,20 @@ ai_addrspace(si_t *sih, uint asidx) } } - +/* Return the size of the nth address space in the current core */ uint32 ai_addrspacesize(si_t *sih, uint asidx) { - si_info_t *sii; + si_info_t *sii = SI_INFO(sih); + si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; uint cidx; - sii = SI_INFO(sih); cidx = sii->curidx; if (asidx == 0) - return sii->coresba_size[cidx]; + return cores_info->coresba_size[cidx]; else if (asidx == 1) - return sii->coresba2_size[cidx]; + return cores_info->coresba2_size[cidx]; else { SI_ERROR(("%s: Need to parse the erom again to find addr space %d\n", __FUNCTION__, asidx)); @@ -523,10 +544,9 @@ ai_addrspacesize(si_t *sih, uint asidx) uint ai_flag(si_t *sih) { - si_info_t *sii; + si_info_t *sii = SI_INFO(sih); aidmp_t *ai; - sii = SI_INFO(sih); if (BCM47162_DMP()) { SI_ERROR(("%s: Attempting to read MIPS DMP registers on 47162a0", __FUNCTION__)); return sii->curidx; @@ -545,6 +565,30 @@ ai_flag(si_t *sih) return (R_REG(sii->osh, &ai->oobselouta30) & 0x1f); } +uint +ai_flag_alt(si_t *sih) +{ + si_info_t *sii = SI_INFO(sih); + aidmp_t *ai; + + if (BCM47162_DMP()) { + SI_ERROR(("%s: Attempting to read MIPS DMP registers on 47162a0", __FUNCTION__)); + return sii->curidx; + } + if (BCM5357_DMP()) { + SI_ERROR(("%s: Attempting to read USB20H DMP registers on 5357b0\n", __FUNCTION__)); + return sii->curidx; + } + if (BCM4707_DMP()) { + SI_ERROR(("%s: Attempting to read CHIPCOMMONB DMP registers on 4707\n", + __FUNCTION__)); + return sii->curidx; + } + ai = sii->curwrap; + + return ((R_REG(sii->osh, &ai->oobselouta30) >> AI_OOBSEL_1_SHIFT) & AI_OOBSEL_MASK); +} + void ai_setint(si_t *sih, int siflag) { @@ -560,7 +604,7 @@ ai_wrap_reg(si_t *sih, uint32 offset, uint32 mask, uint32 val) uint32 w = R_REG(sii->osh, map+(offset/4)); w &= ~mask; w |= val; - W_REG(sii->osh, map+(offset/4), val); + W_REG(sii->osh, map+(offset/4), w); } return (R_REG(sii->osh, map+(offset/4))); @@ -569,39 +613,47 @@ ai_wrap_reg(si_t *sih, uint32 offset, uint32 mask, uint32 val) uint ai_corevendor(si_t *sih) { - si_info_t *sii; + si_info_t *sii = SI_INFO(sih); + si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; uint32 cia; - sii = SI_INFO(sih); - cia = sii->cia[sii->curidx]; + cia = cores_info->cia[sii->curidx]; return ((cia & CIA_MFG_MASK) >> CIA_MFG_SHIFT); } uint ai_corerev(si_t *sih) { - si_info_t *sii; + si_info_t *sii = SI_INFO(sih); + si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; uint32 cib; - sii = SI_INFO(sih); - cib = sii->cib[sii->curidx]; + + cib = cores_info->cib[sii->curidx]; return remap_corerev(sih, (cib & CIB_REV_MASK) >> CIB_REV_SHIFT); } bool ai_iscoreup(si_t *sih) { - si_info_t *sii; + si_info_t *sii = SI_INFO(sih); aidmp_t *ai; - sii = SI_INFO(sih); ai = sii->curwrap; return (((R_REG(sii->osh, &ai->ioctrl) & (SICF_FGC | SICF_CLOCK_EN)) == SICF_CLOCK_EN) && ((R_REG(sii->osh, &ai->resetctrl) & AIRC_RESET) == 0)); } - +/* + * Switch to 'coreidx', issue a single arbitrary 32bit register mask&set operation, + * switch back to the original core, and return the new value. + * + * When using the silicon backplane, no fiddling with interrupts or core switches is needed. + * + * Also, when using pci/pcie, we can optimize away the core switching for pci registers + * and (on newer pci cores) chipcommon registers. + */ uint ai_corereg(si_t *sih, uint coreidx, uint regoff, uint mask, uint val) { @@ -610,9 +662,9 @@ ai_corereg(si_t *sih, uint coreidx, uint regoff, uint mask, uint val) uint w; uint intr_val = 0; bool fast = FALSE; - si_info_t *sii; + si_info_t *sii = SI_INFO(sih); + si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; - sii = SI_INFO(sih); ASSERT(GOODIDX(coreidx)); ASSERT(regoff < SI_CORE_SIZE); @@ -622,25 +674,27 @@ ai_corereg(si_t *sih, uint coreidx, uint regoff, uint mask, uint val) return 0; if (BUSTYPE(sih->bustype) == SI_BUS) { - + /* If internal bus, we can always get at everything */ fast = TRUE; - - if (!sii->regs[coreidx]) { - sii->regs[coreidx] = REG_MAP(sii->coresba[coreidx], + /* map if does not exist */ + if (!cores_info->regs[coreidx]) { + cores_info->regs[coreidx] = REG_MAP(cores_info->coresba[coreidx], SI_CORE_SIZE); - ASSERT(GOODREGS(sii->regs[coreidx])); + ASSERT(GOODREGS(cores_info->regs[coreidx])); } - r = (uint32 *)((uchar *)sii->regs[coreidx] + regoff); + r = (uint32 *)((uchar *)cores_info->regs[coreidx] + regoff); } else if (BUSTYPE(sih->bustype) == PCI_BUS) { - + /* If pci/pcie, we can get at pci/pcie regs and on newer cores to chipc */ - if ((sii->coreid[coreidx] == CC_CORE_ID) && SI_FAST(sii)) { - + if ((cores_info->coreid[coreidx] == CC_CORE_ID) && SI_FAST(sii)) { + /* Chipc registers are mapped at 12KB */ fast = TRUE; r = (uint32 *)((char *)sii->curmap + PCI_16KB0_CCREGS_OFFSET + regoff); } else if (sii->pub.buscoreidx == coreidx) { - + /* pci registers are at either in the last 2KB of an 8KB window + * or, in pcie and pci rev 13 at 8KB + */ fast = TRUE; if (SI_FAST(sii)) r = (uint32 *)((char *)sii->curmap + @@ -656,25 +710,25 @@ ai_corereg(si_t *sih, uint coreidx, uint regoff, uint mask, uint val) if (!fast) { INTR_OFF(sii, intr_val); - + /* save current core index */ origidx = si_coreidx(&sii->pub); - + /* switch core */ r = (uint32*) ((uchar*) ai_setcoreidx(&sii->pub, coreidx) + regoff); } ASSERT(r != NULL); - + /* mask and set */ if (mask || val) { w = (R_REG(sii->osh, r) & ~mask) | val; W_REG(sii->osh, r, w); } - + /* readback */ w = R_REG(sii->osh, r); if (!fast) { - + /* restore core index */ if (origidx != coreidx) ai_setcoreidx(&sii->pub, origidx); @@ -684,33 +738,96 @@ ai_corereg(si_t *sih, uint coreidx, uint regoff, uint mask, uint val) return (w); } +/* + * If there is no need for fiddling with interrupts or core switches (typically silicon + * back plane registers, pci registers and chipcommon registers), this function + * returns the register offset on this core to a mapped address. This address can + * be used for W_REG/R_REG directly. + * + * For accessing registers that would need a core switch, this function will return + * NULL. + */ +uint32 * +ai_corereg_addr(si_t *sih, uint coreidx, uint regoff) +{ + uint32 *r = NULL; + bool fast = FALSE; + si_info_t *sii = SI_INFO(sih); + si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; + + + ASSERT(GOODIDX(coreidx)); + ASSERT(regoff < SI_CORE_SIZE); + + if (coreidx >= SI_MAXCORES) + return 0; + + if (BUSTYPE(sih->bustype) == SI_BUS) { + /* If internal bus, we can always get at everything */ + fast = TRUE; + /* map if does not exist */ + if (!cores_info->regs[coreidx]) { + cores_info->regs[coreidx] = REG_MAP(cores_info->coresba[coreidx], + SI_CORE_SIZE); + ASSERT(GOODREGS(cores_info->regs[coreidx])); + } + r = (uint32 *)((uchar *)cores_info->regs[coreidx] + regoff); + } else if (BUSTYPE(sih->bustype) == PCI_BUS) { + /* If pci/pcie, we can get at pci/pcie regs and on newer cores to chipc */ + + if ((cores_info->coreid[coreidx] == CC_CORE_ID) && SI_FAST(sii)) { + /* Chipc registers are mapped at 12KB */ + + fast = TRUE; + r = (uint32 *)((char *)sii->curmap + PCI_16KB0_CCREGS_OFFSET + regoff); + } else if (sii->pub.buscoreidx == coreidx) { + /* pci registers are at either in the last 2KB of an 8KB window + * or, in pcie and pci rev 13 at 8KB + */ + fast = TRUE; + if (SI_FAST(sii)) + r = (uint32 *)((char *)sii->curmap + + PCI_16KB0_PCIREGS_OFFSET + regoff); + else + r = (uint32 *)((char *)sii->curmap + + ((regoff >= SBCONFIGOFF) ? + PCI_BAR0_PCISBR_OFFSET : PCI_BAR0_PCIREGS_OFFSET) + + regoff); + } + } + + if (!fast) + return 0; + + return (r); +} + void ai_core_disable(si_t *sih, uint32 bits) { - si_info_t *sii; + si_info_t *sii = SI_INFO(sih); volatile uint32 dummy; uint32 status; aidmp_t *ai; - sii = SI_INFO(sih); ASSERT(GOODREGS(sii->curwrap)); ai = sii->curwrap; - + /* if core is already in reset, just return */ if (R_REG(sii->osh, &ai->resetctrl) & AIRC_RESET) return; - + /* ensure there are no pending backplane operations */ SPINWAIT(((status = R_REG(sii->osh, &ai->resetstatus)) != 0), 300); - + /* if pending backplane ops still, try waiting longer */ if (status != 0) { - - + /* 300usecs was sufficient to allow backplane ops to clear for big hammer */ + /* during driver load we may need more time */ SPINWAIT(((status = R_REG(sii->osh, &ai->resetstatus)) != 0), 10000); - - + /* if still pending ops, continue on and try disable anyway */ + /* this is in big hammer path, so don't call wl_reinit in this case... */ } W_REG(sii->osh, &ai->resetctrl, AIRC_RESET); @@ -724,30 +841,53 @@ ai_core_disable(si_t *sih, uint32 bits) OSL_DELAY(10); } - +/* reset and re-enable a core + * inputs: + * bits - core specific bits that are set during and after reset sequence + * resetbits - core specific bits that are set only during reset sequence + */ void ai_core_reset(si_t *sih, uint32 bits, uint32 resetbits) { - si_info_t *sii; + si_info_t *sii = SI_INFO(sih); aidmp_t *ai; volatile uint32 dummy; + uint loop_counter = 10; - sii = SI_INFO(sih); ASSERT(GOODREGS(sii->curwrap)); ai = sii->curwrap; - - ai_core_disable(sih, (bits | resetbits)); + /* ensure there are no pending backplane operations */ + SPINWAIT(((dummy = R_REG(sii->osh, &ai->resetstatus)) != 0), 300); + + + /* put core into reset state */ + W_REG(sii->osh, &ai->resetctrl, AIRC_RESET); + OSL_DELAY(10); + + /* ensure there are no pending backplane operations */ + SPINWAIT((R_REG(sii->osh, &ai->resetstatus) != 0), 300); - - W_REG(sii->osh, &ai->ioctrl, (bits | SICF_FGC | SICF_CLOCK_EN)); + W_REG(sii->osh, &ai->ioctrl, (bits | resetbits | SICF_FGC | SICF_CLOCK_EN)); dummy = R_REG(sii->osh, &ai->ioctrl); BCM_REFERENCE(dummy); - W_REG(sii->osh, &ai->resetctrl, 0); - dummy = R_REG(sii->osh, &ai->resetctrl); - BCM_REFERENCE(dummy); - OSL_DELAY(1); + /* ensure there are no pending backplane operations */ + SPINWAIT(((dummy = R_REG(sii->osh, &ai->resetstatus)) != 0), 300); + + + while (R_REG(sii->osh, &ai->resetctrl) != 0 && --loop_counter != 0) { + /* ensure there are no pending backplane operations */ + SPINWAIT(((dummy = R_REG(sii->osh, &ai->resetstatus)) != 0), 300); + + + /* take core out of reset */ + W_REG(sii->osh, &ai->resetctrl, 0); + + /* ensure there are no pending backplane operations */ + SPINWAIT((R_REG(sii->osh, &ai->resetstatus) != 0), 300); + } + W_REG(sii->osh, &ai->ioctrl, (bits | SICF_CLOCK_EN)); dummy = R_REG(sii->osh, &ai->ioctrl); @@ -758,11 +898,10 @@ ai_core_reset(si_t *sih, uint32 bits, uint32 resetbits) void ai_core_cflags_wo(si_t *sih, uint32 mask, uint32 val) { - si_info_t *sii; + si_info_t *sii = SI_INFO(sih); aidmp_t *ai; uint32 w; - sii = SI_INFO(sih); if (BCM47162_DMP()) { SI_ERROR(("%s: Accessing MIPS DMP register (ioctrl) on 47162a0", @@ -794,11 +933,10 @@ ai_core_cflags_wo(si_t *sih, uint32 mask, uint32 val) uint32 ai_core_cflags(si_t *sih, uint32 mask, uint32 val) { - si_info_t *sii; + si_info_t *sii = SI_INFO(sih); aidmp_t *ai; uint32 w; - sii = SI_INFO(sih); if (BCM47162_DMP()) { SI_ERROR(("%s: Accessing MIPS DMP register (ioctrl) on 47162a0", __FUNCTION__)); @@ -831,11 +969,10 @@ ai_core_cflags(si_t *sih, uint32 mask, uint32 val) uint32 ai_core_sflags(si_t *sih, uint32 mask, uint32 val) { - si_info_t *sii; + si_info_t *sii = SI_INFO(sih); aidmp_t *ai; uint32 w; - sii = SI_INFO(sih); if (BCM47162_DMP()) { SI_ERROR(("%s: Accessing MIPS DMP register (iostatus) on 47162a0", __FUNCTION__)); |