diff options
Diffstat (limited to 'drivers/net/wireless/bcmdhd/sbutils.c')
-rw-r--r-- | drivers/net/wireless/bcmdhd/sbutils.c | 146 |
1 files changed, 104 insertions, 42 deletions
diff --git a/drivers/net/wireless/bcmdhd/sbutils.c b/drivers/net/wireless/bcmdhd/sbutils.c index 68cfcb2..712f721 100644 --- a/drivers/net/wireless/bcmdhd/sbutils.c +++ b/drivers/net/wireless/bcmdhd/sbutils.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: sbutils.c 310902 2012-01-26 19:45:33Z $ + * $Id: sbutils.c 431423 2013-10-23 16:07:35Z $ */ #include <bcm_cfg.h> @@ -46,7 +46,6 @@ static uint _sb_scan(si_info_t *sii, uint32 sba, void *regs, uint bus, uint32 sb uint ncores); static uint32 _sb_coresba(si_info_t *sii); static void *_sb_setcoreidx(si_info_t *sii, uint coreidx); - #define SET_SBREG(sii, r, mask, val) \ W_SBREG((sii), (r), ((R_SBREG((sii), (r)) & ~(mask)) | (val))) #define REGS2SB(va) (sbconfig_t*) ((int8*)(va) + SBCONFIGOFF) @@ -63,6 +62,7 @@ static void *_sb_setcoreidx(si_info_t *sii, uint coreidx); static uint32 sb_read_sbreg(si_info_t *sii, volatile uint32 *sbr) { + si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; uint8 tmp; uint32 val, intr_val = 0; @@ -94,6 +94,7 @@ sb_read_sbreg(si_info_t *sii, volatile uint32 *sbr) static void sb_write_sbreg(si_info_t *sii, volatile uint32 *sbr, uint32 v) { + si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; uint8 tmp; volatile uint32 dummy; uint32 intr_val = 0; @@ -144,13 +145,12 @@ sb_coreid(si_t *sih) uint sb_intflag(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; void *corereg; sbconfig_t *sb; uint origidx, intflag, intr_val = 0; - sii = SI_INFO(sih); - INTR_OFF(sii, intr_val); origidx = si_coreidx(sih); corereg = si_setcore(sih, CC_CORE_ID, 0); @@ -197,9 +197,10 @@ static uint _sb_coreidx(si_info_t *sii, uint32 sba) { uint i; + si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; for (i = 0; i < sii->numcores; i ++) - if (sba == sii->coresba[i]) + if (sba == cores_info->coresba[i]) return i; return BADIDX; } @@ -374,9 +375,8 @@ sb_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; - - sii = SI_INFO(sih); + 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); @@ -389,16 +389,16 @@ sb_corereg(si_t *sih, uint coreidx, uint regoff, uint mask, uint val) /* If internal bus, we can always get at everything */ fast = TRUE; /* map if does not exist */ - if (!sii->regs[coreidx]) { - sii->regs[coreidx] = REG_MAP(sii->coresba[coreidx], + 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(sii->pub.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; @@ -464,6 +464,69 @@ sb_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 * +sb_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(sii->pub.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(sii->pub.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); +} + /* Scan the enumeration space to find all cores starting from the given * bus 'sbba'. Append coreid and other info to the lists in 'si'. 'sba' * is the default core address at chip POR time and 'regs' is the virtual @@ -478,6 +541,7 @@ _sb_scan(si_info_t *sii, uint32 sba, void *regs, uint bus, uint32 sbba, uint num uint next; uint ncc = 0; uint i; + si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; if (bus >= SB_MAXBUSES) { SI_ERROR(("_sb_scan: bus 0x%08x at level %d is too deep to scan\n", sbba, bus)); @@ -489,31 +553,32 @@ _sb_scan(si_info_t *sii, uint32 sba, void *regs, uint bus, uint32 sbba, uint num * Core addresses must be contiguous on each bus. */ for (i = 0, next = sii->numcores; i < numcores && next < SB_BUS_MAXCORES; i++, next++) { - sii->coresba[next] = sbba + (i * SI_CORE_SIZE); + cores_info->coresba[next] = sbba + (i * SI_CORE_SIZE); /* keep and reuse the initial register mapping */ - if ((BUSTYPE(sii->pub.bustype) == SI_BUS) && (sii->coresba[next] == sba)) { + if ((BUSTYPE(sii->pub.bustype) == SI_BUS) && (cores_info->coresba[next] == sba)) { SI_VMSG(("_sb_scan: reuse mapped regs %p for core %u\n", regs, next)); - sii->regs[next] = regs; + cores_info->regs[next] = regs; } /* change core to 'next' and read its coreid */ sii->curmap = _sb_setcoreidx(sii, next); sii->curidx = next; - sii->coreid[next] = sb_coreid(&sii->pub); + cores_info->coreid[next] = sb_coreid(&sii->pub); /* core specific processing... */ /* chipc provides # cores */ - if (sii->coreid[next] == CC_CORE_ID) { + if (cores_info->coreid[next] == CC_CORE_ID) { chipcregs_t *cc = (chipcregs_t *)sii->curmap; uint32 ccrev = sb_corerev(&sii->pub); /* determine numcores - this is the total # cores in the chip */ - if (((ccrev == 4) || (ccrev >= 6))) + if (((ccrev == 4) || (ccrev >= 6))) { + ASSERT(cc); numcores = (R_REG(sii->osh, &cc->chipid) & CID_CC_MASK) >> CID_CC_SHIFT; - else { + } else { /* Older chips */ uint chip = CHIPID(sii->pub.chip); @@ -534,7 +599,7 @@ _sb_scan(si_info_t *sii, uint32 sba, void *regs, uint bus, uint32 sbba, uint num sii->pub.issim ? "QT" : "")); } /* scan bridged SB(s) and add results to the end of the list */ - else if (sii->coreid[next] == OCP_CORE_ID) { + else if (cores_info->coreid[next] == OCP_CORE_ID) { sbconfig_t *sb = REGS2SB(sii->curmap); uint32 nsbba = R_SBREG(sii, &sb->sbadmatch1); uint nsbcc; @@ -565,11 +630,10 @@ _sb_scan(si_info_t *sii, uint32 sba, void *regs, uint bus, uint32 sbba, uint num void sb_scan(si_t *sih, void *regs, uint devid) { - si_info_t *sii; uint32 origsba; sbconfig_t *sb; + si_info_t *sii = SI_INFO(sih); - sii = SI_INFO(sih); sb = REGS2SB(sii->curmap); sii->pub.socirev = (R_SBREG(sii, &sb->sbidlow) & SBIDL_RV_MASK) >> SBIDL_RV_SHIFT; @@ -591,9 +655,7 @@ sb_scan(si_t *sih, void *regs, uint devid) void * sb_setcoreidx(si_t *sih, uint coreidx) { - si_info_t *sii; - - sii = SI_INFO(sih); + si_info_t *sii = SI_INFO(sih); if (coreidx >= sii->numcores) return (NULL); @@ -616,17 +678,18 @@ sb_setcoreidx(si_t *sih, uint coreidx) static void * _sb_setcoreidx(si_info_t *sii, uint coreidx) { - uint32 sbaddr = sii->coresba[coreidx]; + si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; + uint32 sbaddr = cores_info->coresba[coreidx]; void *regs; switch (BUSTYPE(sii->pub.bustype)) { case SI_BUS: /* map new one */ - if (!sii->regs[coreidx]) { - sii->regs[coreidx] = REG_MAP(sbaddr, SI_CORE_SIZE); - ASSERT(GOODREGS(sii->regs[coreidx])); + if (!cores_info->regs[coreidx]) { + cores_info->regs[coreidx] = REG_MAP(sbaddr, SI_CORE_SIZE); + ASSERT(GOODREGS(cores_info->regs[coreidx])); } - regs = sii->regs[coreidx]; + regs = cores_info->regs[coreidx]; break; case PCI_BUS: @@ -648,11 +711,11 @@ _sb_setcoreidx(si_info_t *sii, uint coreidx) case SPI_BUS: case SDIO_BUS: /* map new one */ - if (!sii->regs[coreidx]) { - sii->regs[coreidx] = (void *)(uintptr)sbaddr; - ASSERT(GOODREGS(sii->regs[coreidx])); + if (!cores_info->regs[coreidx]) { + cores_info->regs[coreidx] = (void *)(uintptr)sbaddr; + ASSERT(GOODREGS(cores_info->regs[coreidx])); } - regs = sii->regs[coreidx]; + regs = cores_info->regs[coreidx]; break; @@ -740,12 +803,11 @@ sb_addrspacesize(si_t *sih, uint asidx) void sb_commit(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; uint origidx; uint intr_val = 0; - sii = SI_INFO(sih); - origidx = sii->curidx; ASSERT(GOODIDX(origidx)); @@ -903,13 +965,13 @@ sb_core_reset(si_t *sih, uint32 bits, uint32 resetbits) uint32 sb_set_initiator_to(si_t *sih, uint32 to, uint idx) { - 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 origidx; uint intr_val = 0; uint32 tmp, ret = 0xffffffff; sbconfig_t *sb; - sii = SI_INFO(sih); if ((to & ~TO_MASK) != 0) return ret; |