From d2ccde1c8e90d38cee87a1b0309ad2827f3fd30d Mon Sep 17 00:00:00 2001 From: hc <hc@nodka.com> Date: Mon, 11 Dec 2023 02:45:28 +0000 Subject: [PATCH] add boot partition size --- kernel/drivers/net/wireless/rockchip_wlan/cywdhd/bcmdhd/aiutils.c | 1408 +++++++++++++++++++++++++++++++++++++++++++++------------ 1 files changed, 1,103 insertions(+), 305 deletions(-) diff --git a/kernel/drivers/net/wireless/rockchip_wlan/cywdhd/bcmdhd/aiutils.c b/kernel/drivers/net/wireless/rockchip_wlan/cywdhd/bcmdhd/aiutils.c index bcdda3f..328f836 100644 --- a/kernel/drivers/net/wireless/rockchip_wlan/cywdhd/bcmdhd/aiutils.c +++ b/kernel/drivers/net/wireless/rockchip_wlan/cywdhd/bcmdhd/aiutils.c @@ -1,16 +1,17 @@ -/* SPDX-License-Identifier: GPL-2.0 */ /* * Misc utility routines for accessing chip-specific features * of the SiliconBackplane-based Broadcom chips. * - * Copyright (C) 1999-2019, Broadcom Corporation - * + * Portions of this code are copyright (c) 2022 Cypress Semiconductor Corporation + * + * Copyright (C) 1999-2017, Broadcom Corporation + * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you * under the terms of the GNU General Public License version 2 (the "GPL"), * available at http://www.broadcom.com/licenses/GPLv2.php, with the * following added to such license: - * + * * As a special exception, the copyright holders of this software give you * permission to link this software with independent modules, and to copy and * distribute the resulting executable under terms of your choice, provided that @@ -18,7 +19,7 @@ * the license of that module. An independent module is a module which is not * derived from this software. The special exception does not apply to any * modifications of the software. - * + * * Notwithstanding the above, under no circumstances may you combine this * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. @@ -26,7 +27,7 @@ * * <<Broadcom-WL-IPTag/Open:>> * - * $Id: aiutils.c 708487 2018-10-31 05:33:14Z $ + * $Id: aiutils.c 701122 2017-05-23 19:32:45Z $ */ #include <bcm_cfg.h> #include <typedefs.h> @@ -39,23 +40,28 @@ #include <pcicfg.h> #include "siutils_priv.h" - - -#ifdef LOAD_DHD_WITH_FW_ALIVE #include <bcmdevs.h> -#include <dhd_chip_info.h> -#endif -#define BCM47162_DMP() (0) -#define BCM5357_DMP() (0) #define BCM53573_DMP() (0) #define BCM4707_DMP() (0) #define PMU_DMP() (0) #define GCI_DMP() (0) -#define remap_coreid(sih, coreid) (coreid) -#define remap_corerev(sih, corerev) (corerev) + +#if defined(BCM_BACKPLANE_TIMEOUT) +static bool ai_get_apb_bridge(si_t *sih, uint32 coreidx, uint32 *apb_id, uint32 *apb_coreuinit); +#endif /* BCM_BACKPLANE_TIMEOUT */ + +#if defined(AXI_TIMEOUTS) || defined(BCM_BACKPLANE_TIMEOUT) +static void ai_reset_axi_to(si_info_t *sii, aidmp_t *ai); +#endif /* defined (AXI_TIMEOUTS) || defined (BCM_BACKPLANE_TIMEOUT) */ /* EROM parsing */ + +#ifdef BCMQT +#define SPINWAIT_TIME_US 3000 +#else +#define SPINWAIT_TIME_US 300 +#endif /* BCMQT */ static uint32 get_erom_ent(si_t *sih, uint32 **eromptr, uint32 mask, uint32 match) @@ -101,9 +107,11 @@ static uint32 get_asd(si_t *sih, uint32 **eromptr, uint sp, uint ad, uint st, uint32 *addrl, uint32 *addrh, - uint32 *sizel, uint32 *sizeh) + uint32 *sizel, uint32 *sizeh) { uint32 asd, sz, szd; + + BCM_REFERENCE(ad); asd = get_erom_ent(sih, eromptr, ER_VALID, ER_VALID); if (((asd & ER_TAG1) != ER_ADD) || @@ -134,58 +142,19 @@ return asd; } -static void -ai_hwfixup(si_info_t *sii) -{ -} - - -/* parse the enumeration rom to identify all cores */ +/* Parse the enumeration rom to identify all cores + * Erom content format can be found in: + * http://hwnbu-twiki.broadcom.com/twiki/pub/Mwgroup/ArmDocumentation/SystemDiscovery.pdf + */ void -ai_scan(si_t *sih, void *regs, uint devid) +ai_scan(si_t *sih, void *regs, uint32 erombase, 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; + uint32 *eromptr, *eromlim; + axi_wrapper_t * axi_wrapper = sii->axi_wrapper; -#ifdef LOAD_DHD_WITH_FW_ALIVE - if(alive == FW_ALIVE_MAGIC) { - switch(card_dev) { - case BCM43430_CHIP_ID: - sii->numcores = ai_core_43430; - sii->oob_router = oob_router_43430; - memcpy(&cores_info->coreid, &bcm43430_coreid, sii->numcores * 4); - memcpy(&cores_info->coresba, &bcm43430_coresba, sii->numcores * 4); - memcpy(&cores_info->coresba_size, &bcm43430_coresba_size, sii->numcores * 4); - memcpy(&cores_info->wrapba, &bcm43430_wrapba, sii->numcores * 4); - memcpy(&cores_info->cia, &bcm43430_cia, sii->numcores * 4); - if(card_rev == 2) { - memcpy(&cores_info->cib, &bcm43436_cib, sii->numcores * 4); - } else { - memcpy(&cores_info->cib, &bcm43430_cib, sii->numcores * 4); - } - break; - - case BCM43012_CHIP_ID: - sii->numcores = ai_core_43012; - sii->oob_router = oob_router_43012; - memcpy(&cores_info->coreid, &bcm43012_coreid, sii->numcores * 4); - memcpy(&cores_info->coresba, &bcm43012_coresba, sii->numcores * 4); - memcpy(&cores_info->coresba_size, &bcm43012_coresba_size, sii->numcores * 4); - memcpy(&cores_info->wrapba, &bcm43012_wrapba, sii->numcores * 4); - memcpy(&cores_info->cia, &bcm43012_cia, sii->numcores * 4); - memcpy(&cores_info->cib, &bcm43012_cib, sii->numcores * 4); - - default: - break; - } - - return; - } -#endif - - erombase = R_REG(sii->osh, &cc->eromptr); + BCM_REFERENCE(devid); switch (BUSTYPE(sih->bustype)) { case SI_BUS: @@ -215,9 +184,11 @@ return; } eromlim = eromptr + (ER_REMAPCONTROL / sizeof(uint32)); + sii->axi_num_wrappers = 0; SI_VMSG(("ai_scan: regs = 0x%p, erombase = 0x%08x, eromptr = 0x%p, eromlim = 0x%p\n", - regs, erombase, eromptr, eromlim)); + OSL_OBFUSCATE_BUF(regs), erombase, + OSL_OBFUSCATE_BUF(eromptr), OSL_OBFUSATE_BUF(eromlim))); while (eromptr < eromlim) { uint32 cia, cib, cid, mfg, crev, nmw, nsw, nmp, nsp; uint32 mpd, asd, addrl, addrh, sizel, sizeh; @@ -230,7 +201,6 @@ 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)); - ai_hwfixup(sii); return; } @@ -252,24 +222,49 @@ #ifdef BCMDBG_SI SI_VMSG(("Found component 0x%04x/0x%04x rev %d at erom addr 0x%p, with nmw = %d, " "nsw = %d, nmp = %d & nsp = %d\n", - mfg, cid, crev, eromptr - 1, nmw, nsw, nmp, nsp)); + mfg, cid, crev, OSL_OBFUSCATE_BUF(eromptr - 1), nmw, nsw, nmp, nsp)); #else BCM_REFERENCE(crev); -#endif +#endif // endif - if (((mfg == MFGID_ARM) && (cid == DEF_AI_COMP)) || (nsp == 0)) - continue; + if (BCM4347_CHIP(sih->chip)) { + /* 4347 has more entries for ARM core + * This should apply to all chips but crashes on router + * This is a temp fix to be further analyze + */ + if (nsp == 0) + continue; + } else + { + /* Include Default slave wrapper for timeout monitoring */ + if ((nsp == 0) || +#if !defined(AXI_TIMEOUTS) && !defined(BCM_BACKPLANE_TIMEOUT) + ((mfg == MFGID_ARM) && (cid == DEF_AI_COMP)) || +#else + ((CHIPTYPE(sii->pub.socitype) == SOCI_NAI) && + (mfg == MFGID_ARM) && (cid == DEF_AI_COMP)) || +#endif /* !defined(AXI_TIMEOUTS) && !defined(BCM_BACKPLANE_TIMEOUT) */ + FALSE) { + 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); if (asd != 0) { - sii->oob_router = addrl; + if ((sii->oob_router != 0) && (sii->oob_router != addrl)) { + sii->oob_router1 = addrl; + } else { + sii->oob_router = addrl; + } } } - if (cid != GMAC_COMMON_4706_CORE_ID && cid != NS_CCB_CORE_ID && - cid != PMU_CORE_ID && cid != GCI_CORE_ID) + if (cid != NS_CCB_CORE_ID && + cid != PMU_CORE_ID && cid != GCI_CORE_ID && cid != SR_CORE_ID && + cid != HUB_CORE_ID && cid != HND_OOBR_CORE_ID) continue; } @@ -277,7 +272,7 @@ cores_info->cia[idx] = cia; cores_info->cib[idx] = cib; - cores_info->coreid[idx] = remap_coreid(sih, cid); + cores_info->coreid[idx] = cid; for (i = 0; i < nmp; i++) { mpd = get_erom_ent(sih, &eromptr, ER_VALID, ER_VALID); @@ -319,7 +314,7 @@ } cores_info->coresba[idx] = addrl; cores_info->coresba_size[idx] = sizel; - /* Get any more ASDs in port 0 */ + /* Get any more ASDs in first port */ j = 1; do { asd = get_asd(sih, &eromptr, 0, j, AD_ST_SLAVE, &addrl, &addrh, @@ -337,7 +332,11 @@ do { asd = get_asd(sih, &eromptr, i, j, AD_ST_SLAVE, &addrl, &addrh, &sizel, &sizeh); - + /* To get the first base address of second slave port */ + if ((asd != 0) && (i == 1) && (j == 0)) { + cores_info->csp2ba[idx] = addrl; + cores_info->csp2ba_size[idx] = sizel; + } if (asd == 0) break; j++; @@ -360,10 +359,26 @@ SI_ERROR(("Master wrapper %d is not 4KB\n", i)); goto error; } - if (i == 0) + if (i == 0) { cores_info->wrapba[idx] = addrl; - else if (i == 1) + } else if (i == 1) { cores_info->wrapba2[idx] = addrl; + } else if (i == 2) { + cores_info->wrapba3[idx] = addrl; + } + + if (axi_wrapper && + (sii->axi_num_wrappers < SI_MAX_AXI_WRAPPERS)) { + axi_wrapper[sii->axi_num_wrappers].mfg = mfg; + axi_wrapper[sii->axi_num_wrappers].cid = cid; + axi_wrapper[sii->axi_num_wrappers].rev = crev; + axi_wrapper[sii->axi_num_wrappers].wrapper_type = AI_MASTER_WRAPPER; + axi_wrapper[sii->axi_num_wrappers].wrapper_addr = addrl; + sii->axi_num_wrappers++; + SI_VMSG(("MASTER WRAPPER: %d, mfg:%x, cid:%x," + "rev:%x, addr:%x, size:%x\n", + sii->axi_num_wrappers, mfg, cid, crev, addrl, sizel)); + } } /* And finally slave wrappers */ @@ -377,6 +392,7 @@ ASSERT(sii->num_br < SI_MAXBR); sii->br_wrapba[sii->num_br++] = addrl; } + if (asd == 0) { SI_ERROR(("Missing descriptor for SW %d\n", i)); goto error; @@ -385,16 +401,54 @@ SI_ERROR(("Slave wrapper %d is not 4KB\n", i)); goto error; } - if ((nmw == 0) && (i == 0)) + if ((nmw == 0) && (i == 0)) { cores_info->wrapba[idx] = addrl; - else if ((nmw == 0) && (i == 1)) + } else if ((nmw == 0) && (i == 1)) { cores_info->wrapba2[idx] = addrl; + } else if ((nmw == 0) && (i == 2)) { + cores_info->wrapba3[idx] = addrl; + } + + /* Include all slave wrappers to the list to + * enable and monitor watchdog timeouts + */ + + if (axi_wrapper && + (sii->axi_num_wrappers < SI_MAX_AXI_WRAPPERS)) { + axi_wrapper[sii->axi_num_wrappers].mfg = mfg; + axi_wrapper[sii->axi_num_wrappers].cid = cid; + axi_wrapper[sii->axi_num_wrappers].rev = crev; + axi_wrapper[sii->axi_num_wrappers].wrapper_type = AI_SLAVE_WRAPPER; + + /* Software WAR as discussed with hardware team, to ensure proper + * Slave Wrapper Base address is set for 4364 Chip ID. + * Current address is 0x1810c000, Corrected the same to 0x1810e000. + * This ensures AXI default slave wrapper is registered along with + * other slave wrapper cores and is useful while generating trap info + * when write operation is tried on Invalid Core / Wrapper register + */ + + if ((CHIPID(sih->chip) == BCM4364_CHIP_ID) && + (cid == DEF_AI_COMP)) { + axi_wrapper[sii->axi_num_wrappers].wrapper_addr = + 0x1810e000; + } else { + axi_wrapper[sii->axi_num_wrappers].wrapper_addr = addrl; + } + + sii->axi_num_wrappers++; + + SI_VMSG(("SLAVE WRAPPER: %d, mfg:%x, cid:%x," + "rev:%x, addr:%x, size:%x\n", + sii->axi_num_wrappers, mfg, cid, crev, addrl, sizel)); + } } - +#ifndef BCM_BACKPLANE_TIMEOUT /* Don't record bridges */ if (br) continue; +#endif // endif /* Done with core */ sii->numcores++; @@ -413,13 +467,13 @@ /* This function changes the logical "focus" to the indicated core. * Return the current core's virtual address. */ -static void * -_ai_setcoreidx(si_t *sih, uint coreidx, uint use_wrap2) +static volatile void * +_ai_setcoreidx(si_t *sih, uint coreidx, uint use_wrapn) { si_info_t *sii = SI_INFO(sih); si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; - uint32 addr, wrap, wrap2; - void *regs; + uint32 addr, wrap, wrap2, wrap3; + volatile void *regs; if (coreidx >= MIN(sii->numcores, SI_MAXCORES)) return (NULL); @@ -427,12 +481,21 @@ addr = cores_info->coresba[coreidx]; wrap = cores_info->wrapba[coreidx]; wrap2 = cores_info->wrapba2[coreidx]; + wrap3 = cores_info->wrapba3[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)); +#ifdef BCM_BACKPLANE_TIMEOUT + /* No need to disable interrupts while entering/exiting APB bridge core */ + if ((cores_info->coreid[coreidx] != APB_BRIDGE_CORE_ID) && + (cores_info->coreid[sii->curidx] != APB_BRIDGE_CORE_ID)) +#endif /* BCM_BACKPLANE_TIMEOUT */ + { + /* + * 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: @@ -451,18 +514,35 @@ cores_info->wrappers2[coreidx] = REG_MAP(wrap2, SI_CORE_SIZE); ASSERT(GOODREGS(cores_info->wrappers2[coreidx])); } - if (use_wrap2) + if (!cores_info->wrappers3[coreidx] && (wrap3 != 0)) { + cores_info->wrappers3[coreidx] = REG_MAP(wrap3, SI_CORE_SIZE); + ASSERT(GOODREGS(cores_info->wrappers3[coreidx])); + } + + if (use_wrapn == 2) { + sii->curwrap = cores_info->wrappers3[coreidx]; + } else if (use_wrapn == 1) { sii->curwrap = cores_info->wrappers2[coreidx]; - else + } else { sii->curwrap = cores_info->wrappers[coreidx]; + } break; case PCI_BUS: - /* point bar0 window */ - OSL_PCI_WRITE_CONFIG(sii->osh, PCI_BAR0_WIN, 4, addr); +#ifdef BCM_BACKPLANE_TIMEOUT + /* No need to set the BAR0 if core is APB Bridge. + * This is to reduce 2 PCI writes while checkng for errlog + */ + if (cores_info->coreid[coreidx] != APB_BRIDGE_CORE_ID) +#endif /* BCM_BACKPLANE_TIMEOUT */ + { + /* 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 (use_wrap2) + if (use_wrapn) wrap = wrap2; if (PCIE_GEN2(sii)) OSL_PCI_WRITE_CONFIG(sii->osh, PCIE2_BAR0_WIN2, 4, wrap); @@ -474,7 +554,7 @@ case SPI_BUS: case SDIO_BUS: sii->curmap = regs = (void *)((uintptr)addr); - if (use_wrap2) + if (use_wrapn) sii->curwrap = (void *)((uintptr)wrap2); else sii->curwrap = (void *)((uintptr)wrap); @@ -494,16 +574,22 @@ return regs; } -void * +volatile void * ai_setcoreidx(si_t *sih, uint coreidx) { return _ai_setcoreidx(sih, coreidx, 0); } -void * +volatile void * ai_setcoreidx_2ndwrap(si_t *sih, uint coreidx) { return _ai_setcoreidx(sih, coreidx, 1); +} + +volatile void * +ai_setcoreidx_3rdwrap(si_t *sih, uint coreidx) +{ + return _ai_setcoreidx(sih, coreidx, 2); } void @@ -596,12 +682,20 @@ int ai_numaddrspaces(si_t *sih) { + + BCM_REFERENCE(sih); + return 2; } -/* Return the address of the nth address space in the current core */ +/* Return the address of the nth address space in the current core + * Arguments: + * sih : Pointer to struct si_t + * spidx : slave port index + * baidx : base address index + */ uint32 -ai_addrspace(si_t *sih, uint asidx) +ai_addrspace(si_t *sih, uint spidx, uint baidx) { si_info_t *sii = SI_INFO(sih); si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; @@ -609,36 +703,53 @@ cidx = sii->curidx; - if (asidx == 0) - return cores_info->coresba[cidx]; - else if (asidx == 1) - return cores_info->coresba2[cidx]; - else { - SI_ERROR(("%s: Need to parse the erom again to find addr space %d\n", - __FUNCTION__, asidx)); - return 0; + if (spidx == CORE_SLAVE_PORT_0) { + if (baidx == CORE_BASE_ADDR_0) + return cores_info->coresba[cidx]; + else if (baidx == CORE_BASE_ADDR_1) + return cores_info->coresba2[cidx]; } + else if (spidx == CORE_SLAVE_PORT_1) { + if (baidx == CORE_BASE_ADDR_0) + return cores_info->csp2ba[cidx]; + } + + SI_ERROR(("%s: Need to parse the erom again to find %d base addr in %d slave port\n", + __FUNCTION__, baidx, spidx)); + + return 0; + } -/* Return the size of the nth address space in the current core */ +/* Return the size of the nth address space in the current core +* Arguments: +* sih : Pointer to struct si_t +* spidx : slave port index +* baidx : base address index +*/ uint32 -ai_addrspacesize(si_t *sih, uint asidx) +ai_addrspacesize(si_t *sih, uint spidx, uint baidx) { si_info_t *sii = SI_INFO(sih); si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; uint cidx; cidx = sii->curidx; - - if (asidx == 0) - return cores_info->coresba_size[cidx]; - else if (asidx == 1) - return cores_info->coresba2_size[cidx]; - else { - SI_ERROR(("%s: Need to parse the erom again to find addr space %d\n", - __FUNCTION__, asidx)); - return 0; + if (spidx == CORE_SLAVE_PORT_0) { + if (baidx == CORE_BASE_ADDR_0) + return cores_info->coresba_size[cidx]; + else if (baidx == CORE_BASE_ADDR_1) + return cores_info->coresba2_size[cidx]; } + else if (spidx == CORE_SLAVE_PORT_1) { + if (baidx == CORE_BASE_ADDR_0) + return cores_info->csp2ba_size[cidx]; + } + + SI_ERROR(("%s: Need to parse the erom again to find %d base addr in %d slave port\n", + __FUNCTION__, baidx, spidx)); + + return 0; } uint @@ -647,14 +758,6 @@ 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__)); @@ -664,13 +767,6 @@ SI_ERROR(("%s: Attempting to read DMP registers on 53573\n", __FUNCTION__)); return sii->curidx; } -#ifdef REROUTE_OOBINT - if (PMU_DMP()) { - SI_ERROR(("%s: Attempting to read PMU DMP registers\n", - __FUNCTION__)); - return PMU_OOB_BIT; - } -#else if (PMU_DMP()) { uint idx, flag; idx = sii->curidx; @@ -679,7 +775,6 @@ ai_setcoreidx(sih, idx); return flag; } -#endif /* REROUTE_OOBINT */ ai = sii->curwrap; ASSERT(ai != NULL); @@ -693,26 +788,11 @@ 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; } -#ifdef REROUTE_OOBINT - if (PMU_DMP()) { - SI_ERROR(("%s: Attempting to read PMU DMP registers\n", - __FUNCTION__)); - return PMU_OOB_BIT; - } -#endif /* REROUTE_OOBINT */ ai = sii->curwrap; @@ -722,22 +802,24 @@ void ai_setint(si_t *sih, int siflag) { + BCM_REFERENCE(sih); + BCM_REFERENCE(siflag); + } uint ai_wrap_reg(si_t *sih, uint32 offset, uint32 mask, uint32 val) { si_info_t *sii = SI_INFO(sih); - uint32 *map = (uint32 *) sii->curwrap; + uint32 *addr = (uint32 *) ((uchar *)(sii->curwrap) + offset); if (mask || val) { - uint32 w = R_REG(sii->osh, map+(offset/4)); + uint32 w = R_REG(sii->osh, addr); w &= ~mask; w |= val; - W_REG(sii->osh, map+(offset/4), w); + W_REG(sii->osh, addr, w); } - - return (R_REG(sii->osh, map+(offset/4))); + return (R_REG(sii->osh, addr)); } uint @@ -758,9 +840,15 @@ si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; uint32 cib; - cib = cores_info->cib[sii->curidx]; - return remap_corerev(sih, (cib & CIB_REV_MASK) >> CIB_REV_SHIFT); + return ((cib & CIB_REV_MASK) >> CIB_REV_SHIFT); +} + +uint +ai_corerev_minor(si_t *sih) +{ + return (ai_core_sflags(sih, 0, 0) >> SISF_MINORREV_D11_SHIFT) & + SISF_MINORREV_D11_MASK; } bool @@ -788,13 +876,12 @@ ai_corereg(si_t *sih, uint coreidx, uint regoff, uint mask, uint val) { uint origidx = 0; - uint32 *r = NULL; + volatile uint32 *r = NULL; uint w; uint intr_val = 0; 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); @@ -812,7 +899,7 @@ SI_CORE_SIZE); ASSERT(GOODREGS(cores_info->regs[coreidx])); } - r = (uint32 *)((uchar *)cores_info->regs[coreidx] + regoff); + r = (volatile uint32 *)((volatile 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 */ @@ -820,17 +907,18 @@ /* Chipc registers are mapped at 12KB */ fast = TRUE; - r = (uint32 *)((char *)sii->curmap + PCI_16KB0_CCREGS_OFFSET + regoff); + r = (volatile uint32 *)((volatile 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 + + r = (volatile uint32 *)((volatile char *)sii->curmap + PCI_16KB0_PCIREGS_OFFSET + regoff); else - r = (uint32 *)((char *)sii->curmap + + r = (volatile uint32 *)((volatile char *)sii->curmap + ((regoff >= SBCONFIGOFF) ? PCI_BAR0_PCISBR_OFFSET : PCI_BAR0_PCIREGS_OFFSET) + regoff); @@ -844,7 +932,8 @@ origidx = si_coreidx(&sii->pub); /* switch core */ - r = (uint32*) ((uchar*) ai_setcoreidx(&sii->pub, coreidx) + regoff); + r = (volatile uint32*) ((volatile uchar*) ai_setcoreidx(&sii->pub, coreidx) + + regoff); } ASSERT(r != NULL); @@ -869,6 +958,97 @@ } /* + * 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_writeonly(si_t *sih, uint coreidx, uint regoff, uint mask, uint val) +{ + uint origidx = 0; + volatile uint32 *r = NULL; + uint w = 0; + uint intr_val = 0; + 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); + ASSERT((val & ~mask) == 0); + + 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 = (volatile uint32 *)((volatile 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 = (volatile uint32 *)((volatile 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 = (volatile uint32 *)((volatile char *)sii->curmap + + PCI_16KB0_PCIREGS_OFFSET + regoff); + else + r = (volatile uint32 *)((volatile char *)sii->curmap + + ((regoff >= SBCONFIGOFF) ? + PCI_BAR0_PCISBR_OFFSET : PCI_BAR0_PCIREGS_OFFSET) + + regoff); + } + } + + if (!fast) { + INTR_OFF(sii, intr_val); + + /* save current core index */ + origidx = si_coreidx(&sii->pub); + + /* switch core */ + r = (volatile uint32*) ((volatile 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); + } + + if (!fast) { + /* restore core index */ + if (origidx != coreidx) + ai_setcoreidx(&sii->pub, origidx); + + INTR_RESTORE(sii, intr_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 @@ -877,14 +1057,13 @@ * For accessing registers that would need a core switch, this function will return * NULL. */ -uint32 * +volatile uint32 * ai_corereg_addr(si_t *sih, uint coreidx, uint regoff) { - uint32 *r = NULL; + volatile 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); @@ -901,7 +1080,7 @@ SI_CORE_SIZE); ASSERT(GOODREGS(cores_info->regs[coreidx])); } - r = (uint32 *)((uchar *)cores_info->regs[coreidx] + regoff); + r = (volatile uint32 *)((volatile 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 */ @@ -909,17 +1088,18 @@ /* Chipc registers are mapped at 12KB */ fast = TRUE; - r = (uint32 *)((char *)sii->curmap + PCI_16KB0_CCREGS_OFFSET + regoff); + r = (volatile uint32 *)((volatile 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 + + r = (volatile uint32 *)((volatile char *)sii->curmap + PCI_16KB0_PCIREGS_OFFSET + regoff); else - r = (uint32 *)((char *)sii->curmap + + r = (volatile uint32 *)((volatile char *)sii->curmap + ((regoff >= SBCONFIGOFF) ? PCI_BAR0_PCISBR_OFFSET : PCI_BAR0_PCIREGS_OFFSET) + regoff); @@ -928,7 +1108,7 @@ if (!fast) { ASSERT(sii->curidx == coreidx); - r = (uint32*) ((uchar*)sii->curmap + regoff); + r = (volatile uint32*) ((volatile uchar*)sii->curmap + regoff); } return (r); @@ -942,13 +1122,13 @@ uint32 status; aidmp_t *ai; - ASSERT(GOODREGS(sii->curwrap)); ai = sii->curwrap; /* if core is already in reset, just return */ - if (R_REG(sii->osh, &ai->resetctrl) & AIRC_RESET) + 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); @@ -982,6 +1162,9 @@ _ai_core_reset(si_t *sih, uint32 bits, uint32 resetbits) { si_info_t *sii = SI_INFO(sih); +#if defined(UCM_CORRUPTION_WAR) + si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; +#endif // endif aidmp_t *ai; volatile uint32 dummy; uint loop_counter = 10; @@ -990,41 +1173,56 @@ ai = sii->curwrap; /* ensure there are no pending backplane operations */ - SPINWAIT(((dummy = R_REG(sii->osh, &ai->resetstatus)) != 0), 300); - + SPINWAIT(((dummy = R_REG(sii->osh, &ai->resetstatus)) != 0), SPINWAIT_TIME_US); /* 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); + SPINWAIT((R_REG(sii->osh, &ai->resetstatus) != 0), SPINWAIT_TIME_US); W_REG(sii->osh, &ai->ioctrl, (bits | resetbits | SICF_FGC | SICF_CLOCK_EN)); dummy = R_REG(sii->osh, &ai->ioctrl); BCM_REFERENCE(dummy); - +#ifdef UCM_CORRUPTION_WAR + if (cores_info->coreid[sii->curidx] == D11_CORE_ID) { + /* Reset FGC */ + OSL_DELAY(1); + W_REG(sii->osh, &ai->ioctrl, (dummy & (~SICF_FGC))); + } +#endif /* UCM_CORRUPTION_WAR */ /* ensure there are no pending backplane operations */ - SPINWAIT(((dummy = R_REG(sii->osh, &ai->resetstatus)) != 0), 300); - + SPINWAIT(((dummy = R_REG(sii->osh, &ai->resetstatus)) != 0), SPINWAIT_TIME_US); 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); - + SPINWAIT(((dummy = R_REG(sii->osh, &ai->resetstatus)) != 0), SPINWAIT_TIME_US); /* 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); + SPINWAIT((R_REG(sii->osh, &ai->resetstatus) != 0), SPINWAIT_TIME_US); } - +#ifdef UCM_CORRUPTION_WAR + /* Pulse FGC after lifting Reset */ + W_REG(sii->osh, &ai->ioctrl, (bits | SICF_FGC | SICF_CLOCK_EN)); +#else W_REG(sii->osh, &ai->ioctrl, (bits | SICF_CLOCK_EN)); +#endif /* UCM_CORRUPTION_WAR */ dummy = R_REG(sii->osh, &ai->ioctrl); BCM_REFERENCE(dummy); +#ifdef UCM_CORRUPTION_WAR + if (cores_info->coreid[sii->curidx] == D11_CORE_ID) { + /* Reset FGC */ + OSL_DELAY(1); + W_REG(sii->osh, &ai->ioctrl, (dummy & (~SICF_FGC))); + } +#endif /* UCM_CORRUPTION_WAR */ OSL_DELAY(1); + } void @@ -1033,6 +1231,12 @@ si_info_t *sii = SI_INFO(sih); si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; uint idx = sii->curidx; + + if (cores_info->wrapba3[idx] != 0) { + ai_setcoreidx_3rdwrap(sih, idx); + _ai_core_reset(sih, bits, resetbits); + ai_setcoreidx(sih, idx); + } if (cores_info->wrapba2[idx] != 0) { ai_setcoreidx_2ndwrap(sih, idx); @@ -1050,17 +1254,6 @@ aidmp_t *ai; uint32 w; - - if (BCM47162_DMP()) { - SI_ERROR(("%s: Accessing MIPS DMP register (ioctrl) on 47162a0", - __FUNCTION__)); - return; - } - if (BCM5357_DMP()) { - SI_ERROR(("%s: Accessing USB20H DMP register (ioctrl) on 5357\n", - __FUNCTION__)); - return; - } if (BCM4707_DMP()) { SI_ERROR(("%s: Accessing CHIPCOMMONB DMP register (ioctrl) on 4707\n", __FUNCTION__)); @@ -1090,16 +1283,6 @@ aidmp_t *ai; uint32 w; - if (BCM47162_DMP()) { - SI_ERROR(("%s: Accessing MIPS DMP register (ioctrl) on 47162a0", - __FUNCTION__)); - return 0; - } - if (BCM5357_DMP()) { - SI_ERROR(("%s: Accessing USB20H DMP register (ioctrl) on 5357\n", - __FUNCTION__)); - return 0; - } if (BCM4707_DMP()) { SI_ERROR(("%s: Accessing CHIPCOMMONB DMP register (ioctrl) on 4707\n", __FUNCTION__)); @@ -1131,16 +1314,6 @@ aidmp_t *ai; uint32 w; - if (BCM47162_DMP()) { - SI_ERROR(("%s: Accessing MIPS DMP register (iostatus) on 47162a0", - __FUNCTION__)); - return 0; - } - if (BCM5357_DMP()) { - SI_ERROR(("%s: Accessing USB20H DMP register (iostatus) on 5357\n", - __FUNCTION__)); - return 0; - } if (BCM4707_DMP()) { SI_ERROR(("%s: Accessing CHIPCOMMONB DMP register (ioctrl) on 4707\n", __FUNCTION__)); @@ -1172,43 +1345,68 @@ ai_dumpregs(si_t *sih, struct bcmstrbuf *b) { si_info_t *sii = SI_INFO(sih); - si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; osl_t *osh; aidmp_t *ai; uint i; + uint32 prev_value = 0; + axi_wrapper_t * axi_wrapper = sii->axi_wrapper; + uint32 cfg_reg = 0; + uint bar0_win_offset = 0; osh = sii->osh; - for (i = 0; i < sii->numcores; i++) { - si_setcoreidx(&sii->pub, i); - ai = sii->curwrap; + /* Save and restore wrapper access window */ + if (BUSTYPE(sii->pub.bustype) == PCI_BUS) { + if (PCIE_GEN2(sii)) { + cfg_reg = PCIE2_BAR0_CORE2_WIN2; + bar0_win_offset = PCIE2_BAR0_CORE2_WIN2_OFFSET; + } else { + cfg_reg = PCI_BAR0_WIN2; + bar0_win_offset = PCI_BAR0_WIN2_OFFSET; + } - bcm_bprintf(b, "core 0x%x: \n", cores_info->coreid[i]); - if (BCM47162_DMP()) { - bcm_bprintf(b, "Skipping mips74k in 47162a0\n"); - continue; + prev_value = OSL_PCI_READ_CONFIG(osh, cfg_reg, 4); + + if (prev_value == ID32_INVALID) { + SI_PRINT(("%s, PCI_BAR0_WIN2 - %x\n", __FUNCTION__, prev_value)); + return; } - if (BCM5357_DMP()) { - bcm_bprintf(b, "Skipping usb20h in 5357\n"); - continue; + } + + bcm_bprintf(b, "ChipNum:%x, ChipRev;%x, BusType:%x, BoardType:%x, BoardVendor:%x\n\n", + sih->chip, sih->chiprev, sih->bustype, sih->boardtype, sih->boardvendor); + + for (i = 0; i < sii->axi_num_wrappers; i++) { + + if (BUSTYPE(sii->pub.bustype) == PCI_BUS) { + /* Set BAR0 window to bridge wapper base address */ + OSL_PCI_WRITE_CONFIG(osh, + cfg_reg, 4, axi_wrapper[i].wrapper_addr); + + ai = (aidmp_t *) ((volatile uint8*)sii->curmap + bar0_win_offset); + } else { + ai = (aidmp_t *)(uintptr) axi_wrapper[i].wrapper_addr; } - if (BCM4707_DMP()) { + + bcm_bprintf(b, "core 0x%x: core_rev:%d, %s_WR ADDR:%x \n", axi_wrapper[i].cid, + axi_wrapper[i].rev, + axi_wrapper[i].wrapper_type == AI_SLAVE_WRAPPER ? "SLAVE" : "MASTER", + axi_wrapper[i].wrapper_addr); + + /* BCM4707_DMP() */ + if (BCM4707_CHIP(CHIPID(sih->chip)) && + (axi_wrapper[i].cid == NS_CCB_CORE_ID)) { bcm_bprintf(b, "Skipping chipcommonb in 4707\n"); continue; } - if (PMU_DMP()) { - bcm_bprintf(b, "Skipping pmu core\n"); - continue; - } - - bcm_bprintf(b, "ioctrlset 0x%x ioctrlclear 0x%x ioctrl 0x%x iostatus 0x%x" + bcm_bprintf(b, "ioctrlset 0x%x ioctrlclear 0x%x ioctrl 0x%x iostatus 0x%x " "ioctrlwidth 0x%x iostatuswidth 0x%x\n" "resetctrl 0x%x resetstatus 0x%x resetreadid 0x%x resetwriteid 0x%x\n" - "errlogctrl 0x%x errlogdone 0x%x errlogstatus 0x%x" + "errlogctrl 0x%x errlogdone 0x%x errlogstatus 0x%x " "errlogaddrlo 0x%x errlogaddrhi 0x%x\n" "errlogid 0x%x errloguser 0x%x errlogflags 0x%x\n" - "intstatus 0x%x config 0x%x itcr 0x%x\n", + "intstatus 0x%x config 0x%x itcr 0x%x\n\n", R_REG(osh, &ai->ioctrlset), R_REG(osh, &ai->ioctrlclear), R_REG(osh, &ai->ioctrl), @@ -1231,78 +1429,678 @@ R_REG(osh, &ai->config), R_REG(osh, &ai->itcr)); } -} -#endif - -void -ai_enable_backplane_timeouts(si_t *sih) -{ -#ifdef AXI_TIMEOUTS - si_info_t *sii = SI_INFO(sih); - aidmp_t *ai; - int i; - - for (i = 0; i < sii->num_br; ++i) { - ai = (aidmp_t *) sii->br_wrapba[i]; - W_REG(sii->osh, &ai->errlogctrl, (1 << AIELC_TO_ENAB_SHIFT) | - ((AXI_TO_VAL << AIELC_TO_EXP_SHIFT) & AIELC_TO_EXP_MASK)); - } -#endif /* AXI_TIMEOUTS */ -} - -void -ai_clear_backplane_to(si_t *sih) -{ -#ifdef AXI_TIMEOUTS - si_info_t *sii = SI_INFO(sih); - aidmp_t *ai; - int i; - uint32 errlogstatus; - - for (i = 0; i < sii->num_br; ++i) { - ai = (aidmp_t *) sii->br_wrapba[i]; - /* check for backplane timeout & clear backplane hang */ - errlogstatus = R_REG(sii->osh, &ai->errlogstatus); - - if ((errlogstatus & AIELS_TIMEOUT_MASK) != 0) { - /* set ErrDone to clear the condition */ - W_REG(sii->osh, &ai->errlogdone, AIELD_ERRDONE_MASK); - - /* SPINWAIT on errlogstatus timeout status bits */ - while (R_REG(sii->osh, &ai->errlogstatus) & AIELS_TIMEOUT_MASK) - ; - - /* only reset APB Bridge on timeout (not slave error, or dec error) */ - switch (errlogstatus & AIELS_TIMEOUT_MASK) { - case 0x1: - printf("AXI slave error"); - break; - case 0x2: - /* reset APB Bridge */ - OR_REG(sii->osh, &ai->resetctrl, AIRC_RESET); - /* sync write */ - (void)R_REG(sii->osh, &ai->resetctrl); - /* clear Reset bit */ - AND_REG(sii->osh, &ai->resetctrl, ~(AIRC_RESET)); - /* sync write */ - (void)R_REG(sii->osh, &ai->resetctrl); - printf("AXI timeout"); - break; - case 0x3: - printf("AXI decode error"); - break; - default: - ; /* should be impossible */ - } - printf("; APB Bridge %d\n", i); - printf("\t errlog: lo 0x%08x, hi 0x%08x, id 0x%08x, flags 0x%08x", - R_REG(sii->osh, &ai->errlogaddrlo), - R_REG(sii->osh, &ai->errlogaddrhi), - R_REG(sii->osh, &ai->errlogid), - R_REG(sii->osh, &ai->errlogflags)); - printf(", status 0x%08x\n", errlogstatus); + /* Restore the initial wrapper space */ + if (BUSTYPE(sii->pub.bustype) == PCI_BUS) { + if (prev_value && cfg_reg) { + OSL_PCI_WRITE_CONFIG(osh, cfg_reg, 4, prev_value); } } -#endif /* AXI_TIMEOUTS */ +} +#endif // endif + +void +ai_update_backplane_timeouts(si_t *sih, bool enable, uint32 timeout_exp, uint32 cid) +{ +#if defined(AXI_TIMEOUTS) || defined(BCM_BACKPLANE_TIMEOUT) + si_info_t *sii = SI_INFO(sih); + aidmp_t *ai; + uint32 i; + axi_wrapper_t * axi_wrapper = sii->axi_wrapper; + uint32 errlogctrl = (enable << AIELC_TO_ENAB_SHIFT) | + ((timeout_exp << AIELC_TO_EXP_SHIFT) & AIELC_TO_EXP_MASK); + +#ifdef BCM_BACKPLANE_TIMEOUT + uint32 prev_value = 0; + osl_t *osh = sii->osh; + uint32 cfg_reg = 0; + uint32 offset = 0; +#endif /* BCM_BACKPLANE_TIMEOUT */ + + if ((sii->axi_num_wrappers == 0) || +#ifdef BCM_BACKPLANE_TIMEOUT + (!PCIE(sii)) || +#endif /* BCM_BACKPLANE_TIMEOUT */ + FALSE) { + SI_VMSG((" %s, axi_num_wrappers:%d, Is_PCIE:%d, BUS_TYPE:%d, ID:%x\n", + __FUNCTION__, sii->axi_num_wrappers, PCIE(sii), + BUSTYPE(sii->pub.bustype), sii->pub.buscoretype)); + return; + } + +#ifdef BCM_BACKPLANE_TIMEOUT + /* Save and restore the wrapper access window */ + if (BUSTYPE(sii->pub.bustype) == PCI_BUS) { + if (PCIE_GEN1(sii)) { + cfg_reg = PCI_BAR0_WIN2; + offset = PCI_BAR0_WIN2_OFFSET; + } else if (PCIE_GEN2(sii)) { + cfg_reg = PCIE2_BAR0_CORE2_WIN2; + offset = PCIE2_BAR0_CORE2_WIN2_OFFSET; + } + else { + ASSERT(!"!PCIE_GEN1 && !PCIE_GEN2"); + } + + prev_value = OSL_PCI_READ_CONFIG(osh, cfg_reg, 4); + if (prev_value == ID32_INVALID) { + SI_PRINT(("%s, PCI_BAR0_WIN2 - %x\n", __FUNCTION__, prev_value)); + return; + } + } +#endif /* BCM_BACKPLANE_TIMEOUT */ + + for (i = 0; i < sii->axi_num_wrappers; ++i) { + + if (axi_wrapper[i].wrapper_type != AI_SLAVE_WRAPPER) { + SI_VMSG(("SKIP ENABLE BPT: MFG:%x, CID:%x, ADDR:%x\n", + axi_wrapper[i].mfg, + axi_wrapper[i].cid, + axi_wrapper[i].wrapper_addr)); + continue; + } + + /* Update only given core if requested */ + if ((cid != 0) && (axi_wrapper[i].cid != cid)) { + continue; + } + +#ifdef BCM_BACKPLANE_TIMEOUT + if (BUSTYPE(sii->pub.bustype) == PCI_BUS) { + /* Set BAR0_CORE2_WIN2 to bridge wapper base address */ + OSL_PCI_WRITE_CONFIG(osh, + cfg_reg, 4, axi_wrapper[i].wrapper_addr); + + /* set AI to BAR0 + Offset corresponding to Gen1 or gen2 */ + ai = (aidmp_t *) (DISCARD_QUAL(sii->curmap, uint8) + offset); + } + else +#endif /* BCM_BACKPLANE_TIMEOUT */ + { + ai = (aidmp_t *)(uintptr) axi_wrapper[i].wrapper_addr; + } + + W_REG(sii->osh, &ai->errlogctrl, errlogctrl); + + SI_VMSG(("ENABLED BPT: MFG:%x, CID:%x, ADDR:%x, ERR_CTRL:%x\n", + axi_wrapper[i].mfg, + axi_wrapper[i].cid, + axi_wrapper[i].wrapper_addr, + R_REG(sii->osh, &ai->errlogctrl))); + } + +#ifdef BCM_BACKPLANE_TIMEOUT + /* Restore the initial wrapper space */ + if (prev_value) { + OSL_PCI_WRITE_CONFIG(osh, cfg_reg, 4, prev_value); + } +#endif /* BCM_BACKPLANE_TIMEOUT */ + +#endif /* AXI_TIMEOUTS || BCM_BACKPLANE_TIMEOUT */ +} + +#if defined(AXI_TIMEOUTS) || defined(BCM_BACKPLANE_TIMEOUT) + +/* slave error is ignored, so account for those cases */ +static uint32 si_ignore_errlog_cnt = 0; + +static bool +ai_ignore_errlog(si_info_t *sii, aidmp_t *ai, + uint32 lo_addr, uint32 hi_addr, uint32 err_axi_id, uint32 errsts) +{ + uint32 axi_id; +#ifdef BCMPCIE_BTLOG + uint32 axi_id2 = BCM4347_UNUSED_AXI_ID; +#endif /* BCMPCIE_BTLOG */ + uint32 ignore_errsts = AIELS_SLAVE_ERR; + uint32 ignore_hi = BT_CC_SPROM_BADREG_HI; + uint32 ignore_lo = BT_CC_SPROM_BADREG_LO; + uint32 ignore_size = BT_CC_SPROM_BADREG_SIZE; + + /* ignore the BT slave errors if the errlog is to chipcommon addr 0x190 */ + switch (CHIPID(sii->pub.chip)) { + case BCM4350_CHIP_ID: + axi_id = BCM4350_BT_AXI_ID; + break; + case BCM4345_CHIP_ID: + axi_id = BCM4345_BT_AXI_ID; + break; + case BCM4349_CHIP_GRPID: + axi_id = BCM4349_BT_AXI_ID; + break; + case BCM4364_CHIP_ID: + case BCM4373_CHIP_ID: + axi_id = BCM4364_BT_AXI_ID; + break; +#ifdef BCMPCIE_BTLOG + case BCM4347_CHIP_ID: + case BCM4357_CHIP_ID: + axi_id = BCM4347_CC_AXI_ID; + axi_id2 = BCM4347_PCIE_AXI_ID; + ignore_errsts = AIELS_TIMEOUT; + ignore_hi = BCM4347_BT_ADDR_HI; + ignore_lo = BCM4347_BT_ADDR_LO; + ignore_size = BCM4347_BT_SIZE; + break; +#endif /* BCMPCIE_BTLOG */ + + default: + return FALSE; + } + + /* AXI ID check */ + err_axi_id &= AI_ERRLOGID_AXI_ID_MASK; + if (!(err_axi_id == axi_id || +#ifdef BCMPCIE_BTLOG + (axi_id2 != BCM4347_UNUSED_AXI_ID && err_axi_id == axi_id2))) +#else + FALSE)) +#endif /* BCMPCIE_BTLOG */ + return FALSE; + + /* slave errors */ + if ((errsts & AIELS_TIMEOUT_MASK) != ignore_errsts) + return FALSE; + + /* address range check */ + if ((hi_addr != ignore_hi) || + (lo_addr < ignore_lo) || (lo_addr >= (ignore_lo + ignore_size))) + return FALSE; + +#ifdef BCMPCIE_BTLOG + if (ignore_errsts == AIELS_TIMEOUT) { + /* reset AXI timeout */ + ai_reset_axi_to(sii, ai); + } +#endif /* BCMPCIE_BTLOG */ + + return TRUE; +} +#endif /* defined (AXI_TIMEOUTS) || defined (BCM_BACKPLANE_TIMEOUT) */ + +#ifdef BCM_BACKPLANE_TIMEOUT + +/* Function to return the APB bridge details corresponding to the core */ +static bool +ai_get_apb_bridge(si_t * sih, uint32 coreidx, uint32 *apb_id, uint32 * apb_coreuinit) +{ + uint i; + uint32 core_base, core_end; + si_info_t *sii = SI_INFO(sih); + static uint32 coreidx_cached = 0, apb_id_cached = 0, apb_coreunit_cached = 0; + uint32 tmp_coreunit = 0; + si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; + + if (coreidx >= MIN(sii->numcores, SI_MAXCORES)) + return FALSE; + + /* Most of the time apb bridge query will be for d11 core. + * Maintain the last cache and return if found rather than iterating the table + */ + if (coreidx_cached == coreidx) { + *apb_id = apb_id_cached; + *apb_coreuinit = apb_coreunit_cached; + return TRUE; + } + + core_base = cores_info->coresba[coreidx]; + core_end = core_base + cores_info->coresba_size[coreidx]; + + for (i = 0; i < sii->numcores; i++) { + if (cores_info->coreid[i] == APB_BRIDGE_ID) { + uint32 apb_base; + uint32 apb_end; + + apb_base = cores_info->coresba[i]; + apb_end = apb_base + cores_info->coresba_size[i]; + + if ((core_base >= apb_base) && + (core_end <= apb_end)) { + /* Current core is attached to this APB bridge */ + *apb_id = apb_id_cached = APB_BRIDGE_ID; + *apb_coreuinit = apb_coreunit_cached = tmp_coreunit; + coreidx_cached = coreidx; + return TRUE; + } + /* Increment the coreunit */ + tmp_coreunit++; + } + } + + return FALSE; +} + +uint32 +ai_clear_backplane_to_fast(si_t *sih, void *addr) +{ + si_info_t *sii = SI_INFO(sih); + volatile void *curmap = sii->curmap; + bool core_reg = FALSE; + + /* Use fast path only for core register access */ + if (((uintptr)addr >= (uintptr)curmap) && + ((uintptr)addr < ((uintptr)curmap + SI_CORE_SIZE))) { + /* address being accessed is within current core reg map */ + core_reg = TRUE; + } + + if (core_reg) { + uint32 apb_id, apb_coreuinit; + + if (ai_get_apb_bridge(sih, si_coreidx(&sii->pub), + &apb_id, &apb_coreuinit) == TRUE) { + /* Found the APB bridge corresponding to current core, + * Check for bus errors in APB wrapper + */ + return ai_clear_backplane_to_per_core(sih, + apb_id, apb_coreuinit, NULL); + } + } + + /* Default is to poll for errors on all slave wrappers */ + return si_clear_backplane_to(sih); +} +#endif /* BCM_BACKPLANE_TIMEOUT */ + +#if defined(AXI_TIMEOUTS) || defined(BCM_BACKPLANE_TIMEOUT) +static bool g_disable_backplane_logs = FALSE; + +#if defined(ETD) +static uint32 last_axi_error = AXI_WRAP_STS_NONE; +static uint32 last_axi_error_core = 0; +static uint32 last_axi_error_wrap = 0; +#endif /* ETD */ + +/* + * API to clear the back plane timeout per core. + * Caller may passs optional wrapper address. If present this will be used as + * the wrapper base address. If wrapper base address is provided then caller + * must provide the coreid also. + * If both coreid and wrapper is zero, then err status of current bridge + * will be verified. + */ +uint32 +ai_clear_backplane_to_per_core(si_t *sih, uint coreid, uint coreunit, void *wrap) +{ + int ret = AXI_WRAP_STS_NONE; + aidmp_t *ai = NULL; + uint32 errlog_status = 0; + si_info_t *sii = SI_INFO(sih); + uint32 errlog_lo = 0, errlog_hi = 0, errlog_id = 0, errlog_flags = 0; + uint32 current_coreidx = si_coreidx(sih); + uint32 target_coreidx = si_findcoreidx(sih, coreid, coreunit); + +#if defined(BCM_BACKPLANE_TIMEOUT) + si_axi_error_t * axi_error = sih->err_info ? + &sih->err_info->axi_error[sih->err_info->count] : NULL; +#endif /* BCM_BACKPLANE_TIMEOUT */ + bool restore_core = FALSE; + + if ((sii->axi_num_wrappers == 0) || +#ifdef BCM_BACKPLANE_TIMEOUT + (!PCIE(sii)) || +#endif /* BCM_BACKPLANE_TIMEOUT */ + FALSE) { + SI_VMSG((" %s, axi_num_wrappers:%d, Is_PCIE:%d, BUS_TYPE:%d, ID:%x\n", + __FUNCTION__, sii->axi_num_wrappers, PCIE(sii), + BUSTYPE(sii->pub.bustype), sii->pub.buscoretype)); + return AXI_WRAP_STS_NONE; + } + + if (wrap != NULL) { + ai = (aidmp_t *)wrap; + } else if (coreid && (target_coreidx != current_coreidx)) { + + if (ai_setcoreidx(sih, target_coreidx) == NULL) { + /* Unable to set the core */ + SI_PRINT(("Set Code Failed: coreid:%x, unit:%d, target_coreidx:%d\n", + coreid, coreunit, target_coreidx)); + errlog_lo = target_coreidx; + ret = AXI_WRAP_STS_SET_CORE_FAIL; + goto end; + } + + restore_core = TRUE; + ai = (aidmp_t *)si_wrapperregs(sih); + } else { + /* Read error status of current wrapper */ + ai = (aidmp_t *)si_wrapperregs(sih); + + /* Update CoreID to current Code ID */ + coreid = si_coreid(sih); + } + + /* read error log status */ + errlog_status = R_REG(sii->osh, &ai->errlogstatus); + + if (errlog_status == ID32_INVALID) { + /* Do not try to peek further */ + SI_PRINT(("%s, errlogstatus:%x - Slave Wrapper:%x\n", + __FUNCTION__, errlog_status, coreid)); + ret = AXI_WRAP_STS_WRAP_RD_ERR; + errlog_lo = (uint32)(uintptr)&ai->errlogstatus; + goto end; + } + + if ((errlog_status & AIELS_TIMEOUT_MASK) != 0) { + uint32 tmp; + uint32 count = 0; + /* set ErrDone to clear the condition */ + W_REG(sii->osh, &ai->errlogdone, AIELD_ERRDONE_MASK); + + /* SPINWAIT on errlogstatus timeout status bits */ + while ((tmp = R_REG(sii->osh, &ai->errlogstatus)) & AIELS_TIMEOUT_MASK) { + + if (tmp == ID32_INVALID) { + SI_PRINT(("%s: prev errlogstatus:%x, errlogstatus:%x\n", + __FUNCTION__, errlog_status, tmp)); + ret = AXI_WRAP_STS_WRAP_RD_ERR; + errlog_lo = (uint32)(uintptr)&ai->errlogstatus; + goto end; + } + /* + * Clear again, to avoid getting stuck in the loop, if a new error + * is logged after we cleared the first timeout + */ + W_REG(sii->osh, &ai->errlogdone, AIELD_ERRDONE_MASK); + + count++; + OSL_DELAY(10); + if ((10 * count) > AI_REG_READ_TIMEOUT) { + errlog_status = tmp; + break; + } + } + + errlog_lo = R_REG(sii->osh, &ai->errlogaddrlo); + errlog_hi = R_REG(sii->osh, &ai->errlogaddrhi); + errlog_id = R_REG(sii->osh, &ai->errlogid); + errlog_flags = R_REG(sii->osh, &ai->errlogflags); + + /* we are already in the error path, so OK to check for the slave error */ + if (ai_ignore_errlog(sii, ai, errlog_lo, errlog_hi, errlog_id, + errlog_status)) { + si_ignore_errlog_cnt++; + goto end; + } + + /* only reset APB Bridge on timeout (not slave error, or dec error) */ + switch (errlog_status & AIELS_TIMEOUT_MASK) { + case AIELS_SLAVE_ERR: + SI_PRINT(("AXI slave error\n")); + ret = AXI_WRAP_STS_SLAVE_ERR; + break; + + case AIELS_TIMEOUT: + ai_reset_axi_to(sii, ai); + ret = AXI_WRAP_STS_TIMEOUT; + break; + + case AIELS_DECODE: + SI_PRINT(("AXI decode error\n")); + ret = AXI_WRAP_STS_DECODE_ERR; + break; + default: + ASSERT(0); /* should be impossible */ + } + + SI_PRINT(("\tCoreID: %x\n", coreid)); + SI_PRINT(("\t errlog: lo 0x%08x, hi 0x%08x, id 0x%08x, flags 0x%08x" + ", status 0x%08x\n", + errlog_lo, errlog_hi, errlog_id, errlog_flags, + errlog_status)); + } + +end: +#if defined(ETD) + if (ret != AXI_WRAP_STS_NONE) { + last_axi_error = ret; + last_axi_error_core = coreid; + last_axi_error_wrap = (uint32)ai; + } +#endif /* ETD */ + +#if defined(BCM_BACKPLANE_TIMEOUT) + if (axi_error && (ret != AXI_WRAP_STS_NONE)) { + axi_error->error = ret; + axi_error->coreid = coreid; + axi_error->errlog_lo = errlog_lo; + axi_error->errlog_hi = errlog_hi; + axi_error->errlog_id = errlog_id; + axi_error->errlog_flags = errlog_flags; + axi_error->errlog_status = errlog_status; + sih->err_info->count++; + + if (sih->err_info->count == SI_MAX_ERRLOG_SIZE) { + sih->err_info->count = SI_MAX_ERRLOG_SIZE - 1; + SI_PRINT(("AXI Error log overflow\n")); + } + } +#endif /* BCM_BACKPLANE_TIMEOUT */ + + if (restore_core) { + if (ai_setcoreidx(sih, current_coreidx) == NULL) { + /* Unable to set the core */ + return ID32_INVALID; + } + } + + return ret; +} + +/* reset AXI timeout */ +static void +ai_reset_axi_to(si_info_t *sii, aidmp_t *ai) +{ + /* reset APB Bridge */ + OR_REG(sii->osh, &ai->resetctrl, AIRC_RESET); + /* sync write */ + (void)R_REG(sii->osh, &ai->resetctrl); + /* clear Reset bit */ + AND_REG(sii->osh, &ai->resetctrl, ~(AIRC_RESET)); + /* sync write */ + (void)R_REG(sii->osh, &ai->resetctrl); + SI_PRINT(("AXI timeout\n")); + if (R_REG(sii->osh, &ai->resetctrl) & AIRC_RESET) { + SI_PRINT(("reset failed on wrapper %p\n", ai)); + g_disable_backplane_logs = TRUE; + } +} +#endif /* AXI_TIMEOUTS || BCM_BACKPLANE_TIMEOUT */ + +/* + * This API polls all slave wrappers for errors and returns bit map of + * all reported errors. + * return - bit map of + * AXI_WRAP_STS_NONE + * AXI_WRAP_STS_TIMEOUT + * AXI_WRAP_STS_SLAVE_ERR + * AXI_WRAP_STS_DECODE_ERR + * AXI_WRAP_STS_PCI_RD_ERR + * AXI_WRAP_STS_WRAP_RD_ERR + * AXI_WRAP_STS_SET_CORE_FAIL + * On timeout detection, correspondign bridge will be reset to + * unblock the bus. + * Error reported in each wrapper can be retrieved using the API + * si_get_axi_errlog_info() + */ +uint32 +ai_clear_backplane_to(si_t *sih) +{ + uint32 ret = 0; +#if defined(AXI_TIMEOUTS) || defined(BCM_BACKPLANE_TIMEOUT) + + si_info_t *sii = SI_INFO(sih); + aidmp_t *ai; + uint32 i; + axi_wrapper_t * axi_wrapper = sii->axi_wrapper; + +#ifdef BCM_BACKPLANE_TIMEOUT + uint32 prev_value = 0; + osl_t *osh = sii->osh; + uint32 cfg_reg = 0; + uint32 offset = 0; + + if ((sii->axi_num_wrappers == 0) || (!PCIE(sii))) +#else + if (sii->axi_num_wrappers == 0) +#endif // endif + { + SI_VMSG((" %s, axi_num_wrappers:%d, Is_PCIE:%d, BUS_TYPE:%d, ID:%x\n", + __FUNCTION__, sii->axi_num_wrappers, PCIE(sii), + BUSTYPE(sii->pub.bustype), sii->pub.buscoretype)); + return AXI_WRAP_STS_NONE; + } + +#ifdef BCM_BACKPLANE_TIMEOUT + /* Save and restore wrapper access window */ + if (BUSTYPE(sii->pub.bustype) == PCI_BUS) { + if (PCIE_GEN1(sii)) { + cfg_reg = PCI_BAR0_WIN2; + offset = PCI_BAR0_WIN2_OFFSET; + } else if (PCIE_GEN2(sii)) { + cfg_reg = PCIE2_BAR0_CORE2_WIN2; + offset = PCIE2_BAR0_CORE2_WIN2_OFFSET; + } + else { + ASSERT(!"!PCIE_GEN1 && !PCIE_GEN2"); + } + + prev_value = OSL_PCI_READ_CONFIG(osh, cfg_reg, 4); + + if (prev_value == ID32_INVALID) { + si_axi_error_t * axi_error = + sih->err_info ? + &sih->err_info->axi_error[sih->err_info->count] : + NULL; + + SI_PRINT(("%s, PCI_BAR0_WIN2 - %x\n", __FUNCTION__, prev_value)); + if (axi_error) { + axi_error->error = ret = AXI_WRAP_STS_PCI_RD_ERR; + axi_error->errlog_lo = cfg_reg; + sih->err_info->count++; + + if (sih->err_info->count == SI_MAX_ERRLOG_SIZE) { + sih->err_info->count = SI_MAX_ERRLOG_SIZE - 1; + SI_PRINT(("AXI Error log overflow\n")); + } + } + + return ret; + } + } +#endif /* BCM_BACKPLANE_TIMEOUT */ + + for (i = 0; i < sii->axi_num_wrappers; ++i) { + uint32 tmp; + + if (axi_wrapper[i].wrapper_type != AI_SLAVE_WRAPPER) { + continue; + } + +#ifdef BCM_BACKPLANE_TIMEOUT + if (BUSTYPE(sii->pub.bustype) == PCI_BUS) { + /* Set BAR0_CORE2_WIN2 to bridge wapper base address */ + OSL_PCI_WRITE_CONFIG(osh, + cfg_reg, 4, axi_wrapper[i].wrapper_addr); + + /* set AI to BAR0 + Offset corresponding to Gen1 or gen2 */ + ai = (aidmp_t *) (DISCARD_QUAL(sii->curmap, uint8) + offset); + } + else +#endif /* BCM_BACKPLANE_TIMEOUT */ + { + ai = (aidmp_t *)(uintptr) axi_wrapper[i].wrapper_addr; + } + + tmp = ai_clear_backplane_to_per_core(sih, axi_wrapper[i].cid, 0, + DISCARD_QUAL(ai, void)); + + ret |= tmp; + } + +#ifdef BCM_BACKPLANE_TIMEOUT + /* Restore the initial wrapper space */ + if (prev_value) { + OSL_PCI_WRITE_CONFIG(osh, cfg_reg, 4, prev_value); + } +#endif /* BCM_BACKPLANE_TIMEOUT */ + +#endif /* AXI_TIMEOUTS || BCM_BACKPLANE_TIMEOUT */ + + return ret; +} + +uint +ai_num_slaveports(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 cib; + + cib = cores_info->cib[coreidx]; + return ((cib & CIB_NSP_MASK) >> CIB_NSP_SHIFT); +} + +#ifdef UART_TRAP_DBG +void +ai_dump_APB_Bridge_registers(si_t *sih) +{ +aidmp_t *ai; +si_info_t *sii = SI_INFO(sih); + + ai = (aidmp_t *) sii->br_wrapba[0]; + printf("APB Bridge 0\n"); + printf("lo 0x%08x, hi 0x%08x, id 0x%08x, flags 0x%08x", + R_REG(sii->osh, &ai->errlogaddrlo), + R_REG(sii->osh, &ai->errlogaddrhi), + R_REG(sii->osh, &ai->errlogid), + R_REG(sii->osh, &ai->errlogflags)); + printf("\n status 0x%08x\n", R_REG(sii->osh, &ai->errlogstatus)); +} +#endif /* UART_TRAP_DBG */ + +void +ai_force_clocks(si_t *sih, uint clock_state) +{ + + si_info_t *sii = SI_INFO(sih); + aidmp_t *ai, *ai_sec = NULL; + volatile uint32 dummy; + uint32 ioctrl; + si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; + + ASSERT(GOODREGS(sii->curwrap)); + ai = sii->curwrap; + if (cores_info->wrapba2[sii->curidx]) + ai_sec = REG_MAP(cores_info->wrapba2[sii->curidx], SI_CORE_SIZE); + + /* ensure there are no pending backplane operations */ + SPINWAIT((R_REG(sii->osh, &ai->resetstatus) != 0), 300); + + if (clock_state == FORCE_CLK_ON) { + ioctrl = R_REG(sii->osh, &ai->ioctrl); + W_REG(sii->osh, &ai->ioctrl, (ioctrl | SICF_FGC)); + dummy = R_REG(sii->osh, &ai->ioctrl); + BCM_REFERENCE(dummy); + if (ai_sec) { + ioctrl = R_REG(sii->osh, &ai_sec->ioctrl); + W_REG(sii->osh, &ai_sec->ioctrl, (ioctrl | SICF_FGC)); + dummy = R_REG(sii->osh, &ai_sec->ioctrl); + BCM_REFERENCE(dummy); + } + } else { + ioctrl = R_REG(sii->osh, &ai->ioctrl); + W_REG(sii->osh, &ai->ioctrl, (ioctrl & (~SICF_FGC))); + dummy = R_REG(sii->osh, &ai->ioctrl); + BCM_REFERENCE(dummy); + if (ai_sec) { + ioctrl = R_REG(sii->osh, &ai_sec->ioctrl); + W_REG(sii->osh, &ai_sec->ioctrl, (ioctrl & (~SICF_FGC))); + dummy = R_REG(sii->osh, &ai_sec->ioctrl); + BCM_REFERENCE(dummy); + } + } + /* ensure there are no pending backplane operations */ + SPINWAIT((R_REG(sii->osh, &ai->resetstatus) != 0), 300); } -- Gitblit v1.6.2