blob: 5307c5c37a9b90164d0b6dfaea9ab3f73a57b66f [file] [log] [blame] [edit]
/*
* DHD Silicon Save Simulation Restore (SSSR)
* dump module for PCIE
*
* Copyright (C) 2024, Broadcom.
*
* 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
* you also meet, for each linked independent module, the terms and conditions of
* 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.
*
*
* <<Broadcom-WL-IPTag/Dual:>>
*/
#ifdef DHD_SSSR_DUMP
/* include files */
#include <typedefs.h>
#include <bcmutils.h>
#include <bcmdevs.h>
#include <bcmdevs_legacy.h> /* need to still support chips no longer in trunk firmware */
#include <siutils.h>
#include <sbgci.h>
#include <hndoobr.h>
#include <hndsoc.h>
#include <hndpmu_dhd.h>
#include <etd.h>
#include <hnd_debug.h>
#include <sbchipc.h>
#include <sbhndarm.h>
#include <sbsysmem.h>
#include <sbsreng.h>
#include <pcie_core.h>
#include <dhd.h>
#include <dhd_bus.h>
#include <dhd_flowring.h>
#include <dhd_proto.h>
#include <dhd_dbg.h>
#include <dhd_debug.h>
#if defined(__linux__)
#include <dhd_plat.h>
#endif /* __linux__ */
#include <dhd_pcie.h>
#include <pcicfg.h>
#include <bcmpcie.h>
#include <bcmutils.h>
#include <bcmendian.h>
#include <bcmstdlib_s.h>
#if defined(__linux__)
#include <dhd_linux.h>
#endif /* __linux__ */
#include <dhd_pcie_sssr_dump.h>
/* This can be overwritten by module parameter defined in dhd_linux.c */
#ifdef GDB_PROXY
/* GDB Proxy can't connect to crashed firmware after SSSR dump is generated.
* SSSR dump generation disabled for GDB Proxy enabled firmware by default.
* Still it can be explicitly enabled by echo 1 > /sys/wifi/sssr_enab or by
* sssr_enab=1 in insmod command line
*/
uint sssr_enab = FALSE;
#else /* GDB_PROXY */
uint sssr_enab = TRUE;
#endif /* else GDB_PROXY */
/* If defined collect FIS dump for all cases */
#ifdef DHD_FIS_DUMP
uint fis_enab = TRUE;
#else
uint fis_enab = FALSE;
#endif /* DHD_FIS_DUMP */
#ifdef DHD_COREDUMP
extern dhd_coredump_t dhd_coredump_types[];
#endif /* DHD_COREDUMP */
static int
dhdpcie_get_sssr_fifo_dump(dhd_pub_t *dhd, uint *buf, uint fifo_size,
uint addr_reg, uint data_reg)
{
uint addr;
uint val = 0;
int i;
DHD_PRINT(("%s addr = 0x%x, data_reg = 0x%x\n", __FUNCTION__, addr_reg, data_reg));
if (!buf) {
DHD_ERROR(("%s: buf is NULL\n", __FUNCTION__));
return BCME_ERROR;
}
if (!fifo_size) {
DHD_ERROR(("%s: fifo_size is 0\n", __FUNCTION__));
return BCME_ERROR;
}
/* Set the base address offset to 0 */
addr = addr_reg;
val = 0;
dhd_sbreg_op(dhd, addr, &val, FALSE);
addr = data_reg;
/* Read 4 bytes at once and loop for fifo_size / 4 */
for (i = 0; i < fifo_size / 4; i++) {
if (serialized_backplane_access(dhd->bus, addr,
sizeof(uint), &val, TRUE) != BCME_OK) {
DHD_ERROR(("%s: error in serialized_backplane_access\n", __FUNCTION__));
return BCME_ERROR;
}
buf[i] = val;
OSL_DELAY(1);
}
return BCME_OK;
}
static int
dhdpcie_get_sssr_dig_dump(dhd_pub_t *dhd, uint *buf, uint fifo_size,
uint addr_reg)
{
uint addr;
uint val = 0;
int i;
si_t *sih = dhd->bus->sih;
bool vasip_enab, dig_mem_check;
uint32 ioctrl_addr = 0;
DHD_PRINT(("%s addr_reg=0x%x size=0x%x\n", __FUNCTION__, addr_reg, fifo_size));
if (!buf) {
DHD_ERROR(("%s: buf is NULL\n", __FUNCTION__));
return BCME_ERROR;
}
if (!fifo_size) {
DHD_ERROR(("%s: fifo_size is 0\n", __FUNCTION__));
return BCME_ERROR;
}
vasip_enab = FALSE;
dig_mem_check = FALSE;
/* SSSR register information structure v0 and v1 shares most except dig_mem */
switch (dhd->sssr_reg_info->rev2.version) {
case SSSR_REG_INFO_VER_6 :
case SSSR_REG_INFO_VER_5 :
if ((dhd->sssr_reg_info->rev5.length > OFFSETOF(sssr_reg_info_v5_t,
dig_mem_info)) && dhd->sssr_reg_info->rev5.dig_mem_info.dig_sssr_size) {
dig_mem_check = TRUE;
}
break;
case SSSR_REG_INFO_VER_4 :
if ((dhd->sssr_reg_info->rev4.length > OFFSETOF(sssr_reg_info_v4_t,
dig_mem_info)) && dhd->sssr_reg_info->rev4.dig_mem_info.dig_sssr_size) {
dig_mem_check = TRUE;
}
break;
case SSSR_REG_INFO_VER_3 :
/* intentional fall through */
case SSSR_REG_INFO_VER_2 :
if ((dhd->sssr_reg_info->rev2.length > OFFSETOF(sssr_reg_info_v2_t,
dig_mem_info)) && dhd->sssr_reg_info->rev2.dig_mem_info.dig_sr_size) {
dig_mem_check = TRUE;
}
break;
case SSSR_REG_INFO_VER_1 :
if (dhd->sssr_reg_info->rev1.vasip_regs.vasip_sr_size) {
vasip_enab = TRUE;
} else if ((dhd->sssr_reg_info->rev1.length > OFFSETOF(sssr_reg_info_v1_t,
dig_mem_info)) && dhd->sssr_reg_info->rev1.
dig_mem_info.dig_sr_size) {
dig_mem_check = TRUE;
}
ioctrl_addr = dhd->sssr_reg_info->rev1.vasip_regs.wrapper_regs.ioctrl;
break;
case SSSR_REG_INFO_VER_0 :
if (dhd->sssr_reg_info->rev0.vasip_regs.vasip_sr_size) {
vasip_enab = TRUE;
}
ioctrl_addr = dhd->sssr_reg_info->rev0.vasip_regs.wrapper_regs.ioctrl;
break;
default :
DHD_ERROR(("invalid sssr_reg_ver"));
return BCME_UNSUPPORTED;
}
if (addr_reg) {
DHD_PRINT(("dig_mem_check=%d vasip_enab=%d\n", dig_mem_check, vasip_enab));
if (!vasip_enab && dig_mem_check) {
int err = dhdpcie_bus_membytes(dhd->bus, FALSE, DHD_PCIE_MEM_BAR1, addr_reg,
(uint8 *)buf, fifo_size);
if (err != BCME_OK) {
DHD_ERROR(("%s: Error reading dig dump from dongle !\n",
__FUNCTION__));
}
} else {
/* Check if vasip clk is disabled, if yes enable it */
addr = ioctrl_addr;
dhd_sbreg_op(dhd, addr, &val, TRUE);
if (!val) {
val = 1;
dhd_sbreg_op(dhd, addr, &val, FALSE);
}
addr = addr_reg;
/* Read 4 bytes at once and loop for fifo_size / 4 */
for (i = 0; i < fifo_size / 4; i++, addr += 4) {
if (serialized_backplane_access(dhd->bus, addr, sizeof(uint),
&val, TRUE) != BCME_OK) {
DHD_ERROR(("%s: Invalid uint addr: 0x%x \n", __FUNCTION__,
addr));
return BCME_ERROR;
}
buf[i] = val;
OSL_DELAY(1);
}
}
} else {
uint cur_coreid;
uint chipc_corerev;
chipcregs_t *chipcregs;
/* Save the current core */
cur_coreid = si_coreid(sih);
/* Switch to ChipC */
chipcregs = (chipcregs_t *)si_setcore(sih, CC_CORE_ID, 0);
if (!chipcregs) {
DHD_ERROR(("%s: si_setcore returns NULL for core id %u \n",
__FUNCTION__, CC_CORE_ID));
return BCME_ERROR;
}
chipc_corerev = si_corerev(sih);
if ((chipc_corerev == 64) || (chipc_corerev == 65)) {
W_REG(si_osh(sih), CC_REG_ADDR(chipcregs, SRMemRWAddr), 0);
/* Read 4 bytes at once and loop for fifo_size / 4 */
for (i = 0; i < fifo_size / 4; i++) {
buf[i] = R_REG(si_osh(sih), CC_REG_ADDR(chipcregs, SRMemRWData));
OSL_DELAY(1);
}
}
/* Switch back to the original core */
si_setcore(sih, cur_coreid, 0);
}
return BCME_OK;
}
static int
dhd_sssr_chk_version_support(int cur_ver, int *supported_vers)
{
int i = 0;
if (cur_ver < (int)SSSR_REG_INFO_VER_0 || cur_ver > SSSR_REG_INFO_VER_MAX) {
return BCME_ERROR;
}
for (i = 0; i < SSSR_REG_INFO_VER_MAX && supported_vers[i] != -1; ++i) {
if (cur_ver == supported_vers[i]) {
return BCME_OK;
}
}
return BCME_UNSUPPORTED;
}
static int
dhdpcie_get_sssr_subtype_dump(dhd_pub_t *dhd, uint *buf, uint fifo_size,
uint addr_reg, sssr_subtype_t subtype, int *supported_vers)
{
bool check = FALSE;
int ret = 0;
DHD_PRINT(("%s: subtype=%u addr_reg=0x%x size=0x%x\n", __FUNCTION__,
subtype, addr_reg, fifo_size));
if (!buf) {
DHD_ERROR(("%s: buf is NULL\n", __FUNCTION__));
return BCME_ERROR;
}
if (!fifo_size) {
DHD_ERROR(("%s: fifo_size is 0\n", __FUNCTION__));
return BCME_ERROR;
}
ret = dhd_sssr_chk_version_support(dhd->sssr_reg_info->rev2.version, supported_vers);
if (ret == BCME_ERROR) {
DHD_ERROR(("%s:invalid sssr_reg_ver (%d) !\n", __FUNCTION__,
dhd->sssr_reg_info->rev2.version));
return BCME_UNSUPPORTED;
} else if (ret == BCME_OK) {
switch (subtype) {
case SSSR_SAQM_DUMP:
if ((dhd->sssr_reg_info->rev5.length > OFFSETOF(sssr_reg_info_v5_t,
saqm_sssr_info)) && dhd->sssr_reg_info->rev5.saqm_sssr_info.
saqm_sssr_size) {
check = TRUE;
}
break;
case SSSR_SRCB_DUMP:
if ((dhd->sssr_reg_info->rev5.length > OFFSETOF(sssr_reg_info_v5_t,
srcb_mem_info)) && dhd->sssr_reg_info->rev5.srcb_mem_info.
srcb_sssr_size) {
check = TRUE;
}
break;
case SSSR_CMN_DUMP:
if ((dhd->sssr_reg_info->rev5.length > OFFSETOF(sssr_reg_info_v5_t,
fis_mem_info)) && dhd->sssr_reg_info->rev5.fis_mem_info.
fis_size) {
check = TRUE;
}
break;
default:
DHD_ERROR(("%s: invalid subtype %u!\n", __FUNCTION__, subtype));
return BCME_UNSUPPORTED;
}
}
if (addr_reg && check) {
int err = dhdpcie_bus_membytes(dhd->bus, FALSE, DHD_PCIE_MEM_BAR1, addr_reg,
(uint8 *)buf, fifo_size);
if (err != BCME_OK) {
DHD_ERROR(("%s: Error reading dump subtype %u from dongle !\n",
__FUNCTION__, subtype));
return BCME_ERROR;
}
} else {
DHD_PRINT(("%s: check fails for subtype %u !\n", __FUNCTION__, subtype));
return BCME_ERROR;
}
return BCME_OK;
}
static uint32
dhdpcie_resume_chipcommon_powerctrl(dhd_pub_t *dhd, uint32 reg_val)
{
uint addr;
uint val = 0;
uint powerctrl_mask;
DHD_PRINT(("%s\n", __FUNCTION__));
/* SSSR register information structure v0 and v1 shares most except dig_mem */
switch (dhd->sssr_reg_info->rev2.version) {
case SSSR_REG_INFO_VER_6 :
case SSSR_REG_INFO_VER_5 :
/* Handled using MaxRsrcMask for rev5 and above */
goto exit;
case SSSR_REG_INFO_VER_4 :
addr = dhd->sssr_reg_info->rev4.chipcommon_regs.base_regs.powerctrl;
powerctrl_mask = dhd->sssr_reg_info->rev4.
chipcommon_regs.base_regs.powerctrl_mask;
break;
case SSSR_REG_INFO_VER_3 :
/* intentional fall through */
case SSSR_REG_INFO_VER_2 :
addr = dhd->sssr_reg_info->rev2.chipcommon_regs.base_regs.powerctrl;
powerctrl_mask = dhd->sssr_reg_info->rev2.
chipcommon_regs.base_regs.powerctrl_mask;
break;
case SSSR_REG_INFO_VER_1 :
case SSSR_REG_INFO_VER_0 :
addr = dhd->sssr_reg_info->rev1.chipcommon_regs.base_regs.powerctrl;
powerctrl_mask = dhd->sssr_reg_info->rev1.
chipcommon_regs.base_regs.powerctrl_mask;
break;
default :
DHD_ERROR(("invalid sssr_reg_ver"));
return BCME_UNSUPPORTED;
}
/* conditionally clear bits [11:8] of PowerCtrl */
dhd_sbreg_op(dhd, addr, &val, TRUE);
if (!(val & powerctrl_mask)) {
dhd_sbreg_op(dhd, addr, &reg_val, FALSE);
}
exit:
return BCME_OK;
}
static uint32
dhdpcie_suspend_chipcommon_powerctrl(dhd_pub_t *dhd)
{
uint addr;
uint val = 0, reg_val = 0;
uint powerctrl_mask;
DHD_PRINT(("%s\n", __FUNCTION__));
/* SSSR register information structure v0 and v1 shares most except dig_mem */
switch (dhd->sssr_reg_info->rev2.version) {
case SSSR_REG_INFO_VER_4 :
addr = dhd->sssr_reg_info->rev4.chipcommon_regs.base_regs.powerctrl;
powerctrl_mask = dhd->sssr_reg_info->rev4.
chipcommon_regs.base_regs.powerctrl_mask;
break;
case SSSR_REG_INFO_VER_3 :
/* intentional fall through */
case SSSR_REG_INFO_VER_2 :
addr = dhd->sssr_reg_info->rev2.chipcommon_regs.base_regs.powerctrl;
powerctrl_mask = dhd->sssr_reg_info->rev2.
chipcommon_regs.base_regs.powerctrl_mask;
break;
case SSSR_REG_INFO_VER_1 :
case SSSR_REG_INFO_VER_0 :
addr = dhd->sssr_reg_info->rev1.chipcommon_regs.base_regs.powerctrl;
powerctrl_mask = dhd->sssr_reg_info->rev1.
chipcommon_regs.base_regs.powerctrl_mask;
break;
default :
DHD_ERROR(("invalid sssr_reg_ver"));
return BCME_UNSUPPORTED;
}
/* conditionally clear bits [11:8] of PowerCtrl */
dhd_sbreg_op(dhd, addr, &reg_val, TRUE);
if (reg_val & powerctrl_mask) {
val = 0;
dhd_sbreg_op(dhd, addr, &val, FALSE);
}
return reg_val;
}
static int
dhdpcie_clear_intmask_and_timer(dhd_pub_t *dhd)
{
uint addr;
uint val;
uint32 cc_intmask, pmuintmask0, pmuintmask1, resreqtimer, macresreqtimer,
macresreqtimer1, vasip_sr_size = 0;
DHD_PRINT(("%s\n", __FUNCTION__));
/* SSSR register information structure v0 and v1 shares most except dig_mem */
switch (dhd->sssr_reg_info->rev2.version) {
case SSSR_REG_INFO_VER_4 :
cc_intmask = dhd->sssr_reg_info->rev4.chipcommon_regs.base_regs.intmask;
pmuintmask0 = dhd->sssr_reg_info->rev4.pmu_regs.base_regs.pmuintmask0;
pmuintmask1 = dhd->sssr_reg_info->rev4.pmu_regs.base_regs.pmuintmask1;
resreqtimer = dhd->sssr_reg_info->rev4.pmu_regs.base_regs.resreqtimer;
macresreqtimer = dhd->sssr_reg_info->rev4.pmu_regs.base_regs.macresreqtimer;
macresreqtimer1 = dhd->sssr_reg_info->rev4.pmu_regs.
base_regs.macresreqtimer1;
break;
case SSSR_REG_INFO_VER_3 :
/* intentional fall through */
case SSSR_REG_INFO_VER_2 :
cc_intmask = dhd->sssr_reg_info->rev2.chipcommon_regs.base_regs.intmask;
pmuintmask0 = dhd->sssr_reg_info->rev2.pmu_regs.base_regs.pmuintmask0;
pmuintmask1 = dhd->sssr_reg_info->rev2.pmu_regs.base_regs.pmuintmask1;
resreqtimer = dhd->sssr_reg_info->rev2.pmu_regs.base_regs.resreqtimer;
macresreqtimer = dhd->sssr_reg_info->rev2.pmu_regs.base_regs.macresreqtimer;
macresreqtimer1 = dhd->sssr_reg_info->rev2.
pmu_regs.base_regs.macresreqtimer1;
break;
case SSSR_REG_INFO_VER_1 :
case SSSR_REG_INFO_VER_0 :
cc_intmask = dhd->sssr_reg_info->rev1.chipcommon_regs.base_regs.intmask;
pmuintmask0 = dhd->sssr_reg_info->rev1.pmu_regs.base_regs.pmuintmask0;
pmuintmask1 = dhd->sssr_reg_info->rev1.pmu_regs.base_regs.pmuintmask1;
resreqtimer = dhd->sssr_reg_info->rev1.pmu_regs.base_regs.resreqtimer;
macresreqtimer = dhd->sssr_reg_info->rev1.pmu_regs.base_regs.macresreqtimer;
macresreqtimer1 = dhd->sssr_reg_info->rev1.
pmu_regs.base_regs.macresreqtimer1;
vasip_sr_size = dhd->sssr_reg_info->rev1.vasip_regs.vasip_sr_size;
break;
default :
DHD_ERROR(("invalid sssr_reg_ver"));
return BCME_UNSUPPORTED;
}
/* clear chipcommon intmask */
val = 0x0;
dhd_sbreg_op(dhd, cc_intmask, &val, FALSE);
/* clear PMUIntMask0 */
val = 0x0;
dhd_sbreg_op(dhd, pmuintmask0, &val, FALSE);
/* clear PMUIntMask1 */
val = 0x0;
dhd_sbreg_op(dhd, pmuintmask1, &val, FALSE);
/* clear res_req_timer */
val = 0x0;
dhd_sbreg_op(dhd, resreqtimer, &val, FALSE);
/* clear macresreqtimer */
val = 0x0;
dhd_sbreg_op(dhd, macresreqtimer, &val, FALSE);
/* clear macresreqtimer1 */
val = 0x0;
dhd_sbreg_op(dhd, macresreqtimer1, &val, FALSE);
/* clear VasipClkEn */
if (vasip_sr_size) {
addr = dhd->sssr_reg_info->rev1.vasip_regs.wrapper_regs.ioctrl;
val = 0x0;
dhd_sbreg_op(dhd, addr, &val, FALSE);
}
return BCME_OK;
}
static void
dhdpcie_update_d11_status_from_trapdata(dhd_pub_t *dhd)
{
#define TRAP_DATA_MAIN_CORE_BIT_MASK (1 << 1)
#define TRAP_DATA_AUX_CORE_BIT_MASK (1 << 4)
uint trap_data_mask[MAX_NUM_D11CORES] =
{TRAP_DATA_MAIN_CORE_BIT_MASK, TRAP_DATA_AUX_CORE_BIT_MASK};
int i;
/* Apply only for 4375 chip */
if (dhd_bus_chip_id(dhd) == BCM4375_CHIP_ID) {
for (i = 0; i < MAX_NUM_D11CORES; i++) {
if (dhd->sssr_d11_outofreset[i] &&
(dhd->dongle_trap_data & trap_data_mask[i])) {
dhd->sssr_d11_outofreset[i] = TRUE;
} else {
dhd->sssr_d11_outofreset[i] = FALSE;
}
DHD_PRINT(("%s: sssr_d11_outofreset[%d] : %d after AND with "
"trap_data:0x%x-0x%x\n",
__FUNCTION__, i, dhd->sssr_d11_outofreset[i],
dhd->dongle_trap_data, trap_data_mask[i]));
}
}
}
static int
dhdpcie_d11_check_outofreset(dhd_pub_t *dhd)
{
int i = 0;
uint8 num_d11cores = 0;
int ret = BCME_OK;
struct dhd_bus *bus = dhd->bus;
uint save_idx = 0;
DHD_PRINT(("%s\n", __FUNCTION__));
num_d11cores = dhd_d11_slices_num_get(dhd);
save_idx = si_coreidx(bus->sih);
for (i = 0; i < num_d11cores; i++) {
if (si_setcore(bus->sih, D11_CORE_ID, i)) {
dhd->sssr_d11_outofreset[i] = si_iscoreup(bus->sih);
} else {
DHD_ERROR(("%s: setcore d11 fails !\n", __FUNCTION__));
ret = BCME_ERROR;
goto exit;
}
}
si_setcoreidx(bus->sih, save_idx);
dhdpcie_update_d11_status_from_trapdata(dhd);
exit:
return ret;
}
#define SAQM_CLK_REQ_CLR_DELAY 1000u
static int
dhdpcie_saqm_clear_clk_req(dhd_pub_t *dhdp)
{
uint32 clockcontrolstatus_val = 0, clockcontrolstatus = 0, saqm_extrsrcreq = 0;
uint32 digsr_srcontrol2_addr = 0, pmuchip_ctl_addr_reg = 0, pmuchip_ctl_data_reg = 0;
uint32 digsr_srcontrol2_setbit_val = 0, pmuchip_ctl_val = 0, pmuchip_ctl_setbit_val = 0;
uint32 digsr_srcontrol1_addr = 0, digsr_srcontrol1_clrbit_val = 0;
uint32 val = 0;
uint save_idx = si_coreidx(dhdp->bus->sih);
if ((si_setcore(dhdp->bus->sih, D11_SAQM_CORE_ID, 0) == NULL) ||
!si_iscoreup(dhdp->bus->sih)) {
goto exit;
}
DHD_PRINT(("%s\n", __FUNCTION__));
switch (dhdp->sssr_reg_info->rev2.version) {
case SSSR_REG_INFO_VER_6 :
case SSSR_REG_INFO_VER_5 :
saqm_extrsrcreq = dhdp->sssr_reg_info->rev5.saqm_sssr_info.
oobr_regs.extrsrcreq;
if (saqm_extrsrcreq) {
/* read is for information purpose only. */
dhd_sbreg_op(dhdp, saqm_extrsrcreq, &clockcontrolstatus_val, TRUE);
clockcontrolstatus = dhdp->sssr_reg_info->rev5.saqm_sssr_info.
base_regs.clockcontrolstatus;
dhd_sbreg_op(dhdp, clockcontrolstatus,
&clockcontrolstatus_val, TRUE);
clockcontrolstatus_val |=
dhdp->sssr_reg_info->rev5.saqm_sssr_info.
base_regs.clockcontrolstatus_val;
dhd_sbreg_op(dhdp, clockcontrolstatus, &clockcontrolstatus_val,
FALSE);
OSL_DELAY(SAQM_CLK_REQ_CLR_DELAY);
}
/* set DIG force_sr_all bit */
digsr_srcontrol2_addr =
dhdp->sssr_reg_info->rev5.saqm_sssr_info.sssr_config_regs.
digsr_srcontrol2_addr;
if (digsr_srcontrol2_addr) {
dhd_sbreg_op(dhdp, digsr_srcontrol2_addr, &val, TRUE);
digsr_srcontrol2_setbit_val =
dhdp->sssr_reg_info->rev5.saqm_sssr_info.sssr_config_regs.
digsr_srcontrol2_setbit_val;
val |= digsr_srcontrol2_setbit_val;
dhd_sbreg_op(dhdp, digsr_srcontrol2_addr, &val, FALSE);
}
/* Disable SR self test */
digsr_srcontrol1_addr =
dhdp->sssr_reg_info->rev5.saqm_sssr_info.sssr_config_regs.
digsr_srcontrol1_addr;
digsr_srcontrol1_clrbit_val =
dhdp->sssr_reg_info->rev5.saqm_sssr_info.sssr_config_regs.
digsr_srcontrol1_clrbit_val;
if (digsr_srcontrol1_addr) {
dhd_sbreg_op(dhdp, digsr_srcontrol1_addr, &val, TRUE);
val &= ~(digsr_srcontrol1_clrbit_val);
dhd_sbreg_op(dhdp, digsr_srcontrol1_addr, &val, FALSE);
}
/* set PMU chip ctrl saqm_sr_enable bit */
pmuchip_ctl_addr_reg = dhdp->sssr_reg_info->rev5.saqm_sssr_info.
sssr_config_regs.pmuchip_ctl_addr_reg;
pmuchip_ctl_val = dhdp->sssr_reg_info->rev5.saqm_sssr_info.
sssr_config_regs.pmuchip_ctl_val;
if (pmuchip_ctl_addr_reg) {
dhd_sbreg_op(dhdp, pmuchip_ctl_addr_reg, &pmuchip_ctl_val, FALSE);
}
pmuchip_ctl_data_reg = dhdp->sssr_reg_info->rev5.saqm_sssr_info.
sssr_config_regs.pmuchip_ctl_data_reg;
pmuchip_ctl_setbit_val =
dhdp->sssr_reg_info->rev5.saqm_sssr_info.sssr_config_regs.
pmuchip_ctl_setbit_val;
if (pmuchip_ctl_data_reg) {
dhd_sbreg_op(dhdp, pmuchip_ctl_data_reg, &val, TRUE);
val |= pmuchip_ctl_setbit_val;
dhd_sbreg_op(dhdp, pmuchip_ctl_data_reg, &val, FALSE);
}
break;
case SSSR_REG_INFO_VER_4 :
saqm_extrsrcreq = dhdp->sssr_reg_info->rev4.saqm_sssr_info.
oobr_regs.extrsrcreq;
if (saqm_extrsrcreq) {
/* read is for information purpose only. */
dhd_sbreg_op(dhdp, saqm_extrsrcreq, &clockcontrolstatus_val, TRUE);
clockcontrolstatus = dhdp->sssr_reg_info->rev4.saqm_sssr_info.
base_regs.clockcontrolstatus;
dhd_sbreg_op(dhdp, clockcontrolstatus, &clockcontrolstatus_val,
TRUE);
clockcontrolstatus_val |=
dhdp->sssr_reg_info->rev4.saqm_sssr_info.
base_regs.clockcontrolstatus_val;
dhd_sbreg_op(dhdp, clockcontrolstatus, &clockcontrolstatus_val,
FALSE);
OSL_DELAY(SAQM_CLK_REQ_CLR_DELAY);
}
/* set DIG force_sr_all bit */
digsr_srcontrol2_addr =
dhdp->sssr_reg_info->rev4.saqm_sssr_info.sssr_config_regs.
digsr_srcontrol2_addr;
if (digsr_srcontrol2_addr) {
dhd_sbreg_op(dhdp, digsr_srcontrol2_addr, &val, TRUE);
digsr_srcontrol2_setbit_val =
dhdp->sssr_reg_info->rev4.saqm_sssr_info.sssr_config_regs.
digsr_srcontrol2_setbit_val;
val |= digsr_srcontrol2_setbit_val;
dhd_sbreg_op(dhdp, digsr_srcontrol2_addr, &val, FALSE);
}
/* Disable SR self test */
digsr_srcontrol1_addr =
dhdp->sssr_reg_info->rev4.saqm_sssr_info.sssr_config_regs.
digsr_srcontrol1_addr;
digsr_srcontrol1_clrbit_val =
dhdp->sssr_reg_info->rev4.saqm_sssr_info.sssr_config_regs.
digsr_srcontrol1_clrbit_val;
if (digsr_srcontrol1_addr) {
dhd_sbreg_op(dhdp, digsr_srcontrol1_addr, &val, TRUE);
val &= ~(digsr_srcontrol1_clrbit_val);
dhd_sbreg_op(dhdp, digsr_srcontrol1_addr, &val, FALSE);
}
/* set PMU chip ctrl saqm_sr_enable bit */
pmuchip_ctl_addr_reg = dhdp->sssr_reg_info->rev4.saqm_sssr_info.
sssr_config_regs.pmuchip_ctl_addr_reg;
pmuchip_ctl_val = dhdp->sssr_reg_info->rev4.saqm_sssr_info.
sssr_config_regs.pmuchip_ctl_val;
if (pmuchip_ctl_addr_reg) {
dhd_sbreg_op(dhdp, pmuchip_ctl_addr_reg, &pmuchip_ctl_val, FALSE);
}
pmuchip_ctl_data_reg = dhdp->sssr_reg_info->rev4.saqm_sssr_info.
sssr_config_regs.pmuchip_ctl_data_reg;
pmuchip_ctl_setbit_val =
dhdp->sssr_reg_info->rev4.saqm_sssr_info.sssr_config_regs.
pmuchip_ctl_setbit_val;
if (pmuchip_ctl_data_reg) {
dhd_sbreg_op(dhdp, pmuchip_ctl_data_reg, &val, TRUE);
val |= pmuchip_ctl_setbit_val;
dhd_sbreg_op(dhdp, pmuchip_ctl_data_reg, &val, FALSE);
}
break;
default :
DHD_ERROR(("invalid sssr_reg_ver"));
return BCME_UNSUPPORTED;
}
exit:
si_setcoreidx(dhdp->bus->sih, save_idx);
return BCME_OK;
}
static int
dhdpcie_saqm_clear_force_sr_all(dhd_pub_t *dhdp)
{
uint32 val = 0, digsr_srcontrol2_addr = 0, digsr_srcontrol2_setbit_val = 0;
uint save_idx = si_coreidx(dhdp->bus->sih);
if ((si_setcore(dhdp->bus->sih, D11_SAQM_CORE_ID, 0) == NULL) ||
!si_iscoreup(dhdp->bus->sih)) {
goto exit;
}
DHD_PRINT(("%s\n", __FUNCTION__));
switch (dhdp->sssr_reg_info->rev2.version) {
case SSSR_REG_INFO_VER_6:
case SSSR_REG_INFO_VER_5:
/* clear DIG force_sr_all bit */
digsr_srcontrol2_addr =
dhdp->sssr_reg_info->rev5.saqm_sssr_info.sssr_config_regs.
digsr_srcontrol2_addr;
if (digsr_srcontrol2_addr) {
dhd_sbreg_op(dhdp, digsr_srcontrol2_addr, &val, TRUE);
digsr_srcontrol2_setbit_val =
dhdp->sssr_reg_info->rev5.saqm_sssr_info.sssr_config_regs.
digsr_srcontrol2_setbit_val;
val &= ~digsr_srcontrol2_setbit_val;
dhd_sbreg_op(dhdp, digsr_srcontrol2_addr, &val, FALSE);
}
break;
case SSSR_REG_INFO_VER_4:
/* clear DIG force_sr_all bit */
digsr_srcontrol2_addr =
dhdp->sssr_reg_info->rev4.saqm_sssr_info.sssr_config_regs.
digsr_srcontrol2_addr;
if (digsr_srcontrol2_addr) {
dhd_sbreg_op(dhdp, digsr_srcontrol2_addr, &val, TRUE);
digsr_srcontrol2_setbit_val =
dhdp->sssr_reg_info->rev4.saqm_sssr_info.sssr_config_regs.
digsr_srcontrol2_setbit_val;
val &= ~digsr_srcontrol2_setbit_val;
dhd_sbreg_op(dhdp, digsr_srcontrol2_addr, &val, FALSE);
}
break;
default:
DHD_ERROR(("invalid sssr_reg_ver"));
return BCME_UNSUPPORTED;
}
exit:
si_setcoreidx(dhdp->bus->sih, save_idx);
return BCME_OK;
}
static int
dhdpcie_d11_clear_clk_req(dhd_pub_t *dhd)
{
int i;
uint val = 0;
uint8 num_d11cores;
uint32 clockrequeststatus, clockcontrolstatus, clockcontrolstatus_val;
DHD_PRINT(("%s\n", __FUNCTION__));
num_d11cores = dhd_d11_slices_num_get(dhd);
for (i = 0; i < num_d11cores; i++) {
if (dhd->sssr_d11_outofreset[i]) {
/* clear request clk only if itopoobb/extrsrcreq is non zero */
/* SSSR register information structure v0 and
* v1 shares most except dig_mem
*/
switch (dhd->sssr_reg_info->rev2.version) {
case SSSR_REG_INFO_VER_4 :
clockrequeststatus = dhd->sssr_reg_info->rev4.
mac_regs[i].oobr_regs.extrsrcreq;
clockcontrolstatus = dhd->sssr_reg_info->rev4.
mac_regs[i].base_regs.clockcontrolstatus;
clockcontrolstatus_val = dhd->sssr_reg_info->rev4.
mac_regs[i].base_regs.clockcontrolstatus_val;
break;
case SSSR_REG_INFO_VER_3 :
/* intentional fall through */
case SSSR_REG_INFO_VER_2 :
clockrequeststatus = dhd->sssr_reg_info->rev2.
mac_regs[i].wrapper_regs.extrsrcreq;
clockcontrolstatus = dhd->sssr_reg_info->rev2.
mac_regs[i].base_regs.clockcontrolstatus;
clockcontrolstatus_val = dhd->sssr_reg_info->rev2.
mac_regs[i].base_regs.clockcontrolstatus_val;
break;
case SSSR_REG_INFO_VER_1 :
case SSSR_REG_INFO_VER_0 :
clockrequeststatus = dhd->sssr_reg_info->rev1.
mac_regs[i].wrapper_regs.itopoobb;
clockcontrolstatus = dhd->sssr_reg_info->rev1.
mac_regs[i].base_regs.clockcontrolstatus;
clockcontrolstatus_val = dhd->sssr_reg_info->rev1.
mac_regs[i].base_regs.clockcontrolstatus_val;
break;
default :
DHD_ERROR(("invalid sssr_reg_ver"));
return BCME_UNSUPPORTED;
}
/* Read is for information purpose only */
dhd_sbreg_op(dhd, clockrequeststatus, &val, TRUE);
/* clear clockcontrolstatus */
dhd_sbreg_op(dhd, clockcontrolstatus, &clockcontrolstatus_val, FALSE);
}
}
return BCME_OK;
}
static int
dhdpcie_arm_clear_clk_req(dhd_pub_t *dhd)
{
struct dhd_bus *bus = dhd->bus;
uint val = 0;
uint32 resetctrl = 0;
uint32 clockrequeststatus, clockcontrolstatus, clockcontrolstatus_val;
uint save_idx = si_coreidx(bus->sih);
DHD_PRINT(("%s\n", __FUNCTION__));
/* SSSR register information structure v0 and v1 shares most except dig_mem */
switch (dhd->sssr_reg_info->rev2.version) {
case SSSR_REG_INFO_VER_6 :
case SSSR_REG_INFO_VER_5 :
clockrequeststatus = dhd->sssr_reg_info->rev5.
arm_regs.oobr_regs.extrsrcreq;
clockcontrolstatus = dhd->sssr_reg_info->rev5.
arm_regs.base_regs.clockcontrolstatus;
clockcontrolstatus_val = dhd->sssr_reg_info->rev5.
arm_regs.base_regs.clockcontrolstatus_val;
break;
case SSSR_REG_INFO_VER_4 :
clockrequeststatus = dhd->sssr_reg_info->rev4.
arm_regs.oobr_regs.extrsrcreq;
clockcontrolstatus = dhd->sssr_reg_info->rev4.
arm_regs.base_regs.clockcontrolstatus;
clockcontrolstatus_val = dhd->sssr_reg_info->rev4.
arm_regs.base_regs.clockcontrolstatus_val;
break;
case SSSR_REG_INFO_VER_3 :
/* intentional fall through */
case SSSR_REG_INFO_VER_2 :
resetctrl = dhd->sssr_reg_info->rev2.
arm_regs.wrapper_regs.resetctrl;
clockrequeststatus = dhd->sssr_reg_info->rev2.
arm_regs.wrapper_regs.extrsrcreq;
clockcontrolstatus = dhd->sssr_reg_info->rev2.
arm_regs.base_regs.clockcontrolstatus;
clockcontrolstatus_val = dhd->sssr_reg_info->rev2.
arm_regs.base_regs.clockcontrolstatus_val;
break;
case SSSR_REG_INFO_VER_1 :
case SSSR_REG_INFO_VER_0 :
resetctrl = dhd->sssr_reg_info->rev1.
arm_regs.wrapper_regs.resetctrl;
clockrequeststatus = dhd->sssr_reg_info->rev1.
arm_regs.wrapper_regs.itopoobb;
clockcontrolstatus = dhd->sssr_reg_info->rev1.
arm_regs.base_regs.clockcontrolstatus;
clockcontrolstatus_val = dhd->sssr_reg_info->rev1.
arm_regs.base_regs.clockcontrolstatus_val;
break;
default :
DHD_ERROR(("invalid sssr_reg_ver"));
return BCME_UNSUPPORTED;
}
/* Check if bit 0 of resetctrl is cleared */
/* for chips having booker interface */
if (CHIPTYPE(bus->sih->socitype) == SOCI_NCI) {
if (si_setcore(bus->sih, ARMCA7_CORE_ID, 0)) {
if (si_iscoreup(bus->sih))
val = 0;
else
val = 1;
} else {
DHD_ERROR(("%s: Failed to set armca7 core !\n", __FUNCTION__));
si_setcoreidx(bus->sih, save_idx);
return BCME_ERROR;
}
} else {
dhd_sbreg_op(dhd, resetctrl, &val, TRUE);
val &= 1u;
}
if (!(val & 1)) {
dhd_sbreg_op(dhd, clockrequeststatus, &val, TRUE);
/* clear clockcontrolstatus */
dhd_sbreg_op(dhd, clockcontrolstatus, &clockcontrolstatus_val, FALSE);
if (MULTIBP_ENAB(bus->sih)) {
uint cfgval = 0;
/* Clear coherent bits for CA7 because CPU is halted */
if (bus->coreid == ARMCA7_CORE_ID) {
cfgval = dhdpcie_bus_cfg_read_dword(bus,
PCIE_CFG_SUBSYSTEM_CONTROL, 4);
dhdpcie_bus_cfg_write_dword(bus, PCIE_CFG_SUBSYSTEM_CONTROL, 4,
(cfgval & ~PCIE_BARCOHERENTACCEN_MASK));
}
}
}
si_setcoreidx(bus->sih, save_idx);
return BCME_OK;
}
static int
dhdpcie_arm_resume_clk_req(dhd_pub_t *dhd)
{
struct dhd_bus *bus = dhd->bus;
uint save_idx = si_coreidx(bus->sih);
int ret = BCME_OK;
if (!si_setcore(bus->sih, ARMCA7_CORE_ID, 0) &&
!(si_setcore(bus->sih, ARMCR4_CORE_ID, 0)) &&
!(si_setcore(bus->sih, ARMCM3_CORE_ID, 0)) &&
!(si_setcore(bus->sih, ARM7S_CORE_ID, 0))) {
DHD_ERROR(("%s: Failed to find ARM core!\n", __FUNCTION__));
ret = BCME_ERROR;
goto fail;
}
fail:
si_setcoreidx(bus->sih, save_idx);
return ret;
}
static int
dhdpcie_pcie_clear_clk_req(dhd_pub_t *dhd)
{
uint val = 0;
uint32 clockrequeststatus, clockcontrolstatus_addr, clockcontrolstatus_val;
DHD_PRINT(("%s\n", __FUNCTION__));
/* SSSR register information structure v0 and v1 shares most except dig_mem */
switch (dhd->sssr_reg_info->rev2.version) {
case SSSR_REG_INFO_VER_4 :
clockrequeststatus = dhd->sssr_reg_info->rev4.
pcie_regs.oobr_regs.extrsrcreq;
clockcontrolstatus_addr = dhd->sssr_reg_info->rev4.
pcie_regs.base_regs.clockcontrolstatus;
clockcontrolstatus_val = dhd->sssr_reg_info->rev4.
pcie_regs.base_regs.clockcontrolstatus_val;
break;
case SSSR_REG_INFO_VER_3 :
/* intentional fall through */
case SSSR_REG_INFO_VER_2 :
clockrequeststatus = dhd->sssr_reg_info->rev2.
pcie_regs.wrapper_regs.extrsrcreq;
clockcontrolstatus_addr = dhd->sssr_reg_info->rev2.
pcie_regs.base_regs.clockcontrolstatus;
clockcontrolstatus_val = dhd->sssr_reg_info->rev2.
pcie_regs.base_regs.clockcontrolstatus_val;
break;
case SSSR_REG_INFO_VER_1 :
case SSSR_REG_INFO_VER_0 :
clockrequeststatus = dhd->sssr_reg_info->rev1.
pcie_regs.wrapper_regs.itopoobb;
clockcontrolstatus_addr = dhd->sssr_reg_info->rev1.
pcie_regs.base_regs.clockcontrolstatus;
clockcontrolstatus_val = dhd->sssr_reg_info->rev1.
pcie_regs.base_regs.clockcontrolstatus_val;
break;
default :
DHD_ERROR(("invalid sssr_reg_ver"));
return BCME_UNSUPPORTED;
}
dhd_sbreg_op(dhd, clockrequeststatus, &val, TRUE);
/* clear clockcontrolstatus */
dhd_sbreg_op(dhd, clockcontrolstatus_addr, &clockcontrolstatus_val, FALSE);
return BCME_OK;
}
static int
dhdpcie_pcie_send_ltrsleep(dhd_pub_t *dhd)
{
uint addr;
uint val = 0;
DHD_PRINT(("%s\n", __FUNCTION__));
/* SSSR register information structure v0 and v1 shares most except dig_mem */
switch (dhd->sssr_reg_info->rev2.version) {
case SSSR_REG_INFO_VER_6 :
case SSSR_REG_INFO_VER_5 :
addr = dhd->sssr_reg_info->rev5.pcie_regs.base_regs.ltrstate;
break;
case SSSR_REG_INFO_VER_4 :
addr = dhd->sssr_reg_info->rev4.pcie_regs.base_regs.ltrstate;
break;
case SSSR_REG_INFO_VER_3 :
/* intentional fall through */
case SSSR_REG_INFO_VER_2 :
addr = dhd->sssr_reg_info->rev2.pcie_regs.base_regs.ltrstate;
break;
case SSSR_REG_INFO_VER_1 :
case SSSR_REG_INFO_VER_0 :
addr = dhd->sssr_reg_info->rev1.pcie_regs.base_regs.ltrstate;
break;
default :
DHD_ERROR(("invalid sssr_reg_ver"));
return BCME_UNSUPPORTED;
}
val = LTR_ACTIVE;
dhd_sbreg_op(dhd, addr, &val, FALSE);
val = LTR_SLEEP;
dhd_sbreg_op(dhd, addr, &val, FALSE);
return BCME_OK;
}
static int
dhdpcie_clear_clk_req(dhd_pub_t *dhd)
{
DHD_PRINT(("%s\n", __FUNCTION__));
dhdpcie_arm_clear_clk_req(dhd);
dhdpcie_d11_clear_clk_req(dhd);
if (dhd->sssr_reg_info->rev2.version >= SSSR_REG_INFO_VER_4) {
dhdpcie_saqm_clear_clk_req(dhd);
}
dhdpcie_pcie_clear_clk_req(dhd);
return BCME_OK;
}
#define SICF_PCLKE 0x0004 /**< PHY clock enable */
#define SICF_PRST 0x0008 /**< PHY reset */
static int
dhdpcie_bring_d11_outofreset(dhd_pub_t *dhd)
{
int i = 0;
uint8 num_d11cores = 0;
uint save_idx = 0;
dhd_bus_t *bus = dhd->bus;
DHD_PRINT(("%s\n", __FUNCTION__));
num_d11cores = dhd_d11_slices_num_get(dhd);
save_idx = si_coreidx(bus->sih);
for (i = 0; i < num_d11cores; i++) {
if (dhd->sssr_d11_outofreset[i]) {
if (si_setcore(bus->sih, D11_CORE_ID, i)) {
si_core_reset(bus->sih, SICF_PRST | SICF_PCLKE,
SICF_PRST | SICF_PCLKE);
DHD_PRINT(("dhdpcie_bring_d11_outofreset mac %d si_isup %d\n",
i, si_iscoreup(bus->sih)));
} else {
DHD_ERROR(("%s: setcore d11 fails !\n",
__FUNCTION__));
return BCME_ERROR;
}
}
}
si_setcoreidx(bus->sih, save_idx);
return BCME_OK;
}
static int
dhdpcie_bring_saqm_updown(dhd_pub_t *dhdp, bool down)
{
dhd_bus_t *bus = dhdp->bus;
uint save_idx, save_unit;
save_idx = si_coreidx(bus->sih);
save_unit = si_coreunit(bus->sih);
if (si_setcore(bus->sih, D11_SAQM_CORE_ID, 0)) {
if (down) {
si_core_disable(bus->sih, SICF_PRST | SICF_PCLKE);
} else {
si_core_reset(bus->sih, SICF_PRST | SICF_PCLKE,
SICF_PRST | SICF_PCLKE);
}
DHD_PRINT(("dhdpcie_bring_saqm_updown si_isup %d down %d\n",
si_iscoreup(bus->sih), down));
si_setcore(bus->sih, save_idx, save_unit);
}
return BCME_OK;
}
static void
dhdpcie_sssr_common_header(dhd_pub_t *dhd, sssr_header_t *sssr_header)
{
int ret = 0;
uint16 sr_asm_version;
sssr_header->magic = SSSR_HEADER_MAGIC;
ret = dhd_sssr_sr_asm_version(dhd, &sr_asm_version);
if (ret == BCME_OK) {
sssr_header->sr_version = sr_asm_version;
}
sssr_header->header_len =
OFFSETOF(sssr_header_t, flags) - OFFSETOF(sssr_header_t, header_len);
sssr_header->chipid = dhd_bus_chip(dhd->bus);
sssr_header->chiprev = dhd_bus_chiprev(dhd->bus);
}
static int
dhdpcie_sssr_d11_header(dhd_pub_t *dhd, uint *buf, uint32 data_len, uint16 coreunit, uint32 *len)
{
int ret = 0;
switch (dhd->sssr_reg_info->rev2.version) {
case SSSR_REG_INFO_VER_6 :
case SSSR_REG_INFO_VER_5 :
{
sssr_header_t sssr_header;
uint32 war_reg = 0;
bzero(&sssr_header, sizeof(sssr_header_t));
dhdpcie_sssr_common_header(dhd, &sssr_header);
sssr_header.data_len = data_len;
sssr_header.coreid = D11_CORE_ID;
sssr_header.coreunit = coreunit;
ret = dhd_sssr_mac_war_reg(dhd, coreunit, &war_reg);
if (ret == BCME_OK) {
sssr_header.war_reg = war_reg;
}
ret = memcpy_s(buf, data_len, &sssr_header, sizeof(sssr_header_t));
if (ret) {
DHD_ERROR(("%s: D11 sssr_header memcpy_s failed: %d\n",
__FUNCTION__, ret));
return ret;
}
*len = sizeof(sssr_header_t);
}
break;
default :
*len = 0;
}
return BCME_OK;
}
static int
dhdpcie_sssr_dig_header(dhd_pub_t *dhd, uint *buf, uint32 data_len, uint32 *len)
{
int ret = 0;
switch (dhd->sssr_reg_info->rev2.version) {
case SSSR_REG_INFO_VER_6 :
case SSSR_REG_INFO_VER_5 :
{
sssr_header_t sssr_header;
uint32 war_reg = 0;
bzero(&sssr_header, sizeof(sssr_header_t));
dhdpcie_sssr_common_header(dhd, &sssr_header);
sssr_header.data_len = data_len;
sssr_header.coreid = dhd->bus->coreid;
ret = dhd_sssr_arm_war_reg(dhd, &war_reg);
if (ret == BCME_OK) {
sssr_header.war_reg = war_reg;
}
ret = memcpy_s(buf, data_len, &sssr_header, sizeof(sssr_header_t));
if (ret) {
DHD_ERROR(("%s: DIG sssr header memcpy_s failed: %d\n",
__FUNCTION__, ret));
return ret;
}
*len = sizeof(sssr_header_t);
}
break;
default :
*len = 0;
}
return BCME_OK;
}
static int
dhdpcie_sssr_saqm_header(dhd_pub_t *dhd, uint *buf, uint32 data_len, uint32 * len)
{
int ret = 0;
switch (dhd->sssr_reg_info->rev2.version) {
case SSSR_REG_INFO_VER_6:
case SSSR_REG_INFO_VER_5:
{
sssr_header_t sssr_header;
uint32 war_reg = 0;
bzero(&sssr_header, sizeof(sssr_header_t));
dhdpcie_sssr_common_header(dhd, &sssr_header);
sssr_header.data_len = data_len;
sssr_header.coreid = D11_SAQM_CORE_ID;
ret = dhd_sssr_saqm_war_reg(dhd, &war_reg);
if (ret == BCME_OK) {
sssr_header.war_reg = war_reg;
}
ret = memcpy_s(buf, data_len, &sssr_header, sizeof(sssr_header_t));
if (ret) {
DHD_ERROR(("%s: SAQM sssr header memcpy_s failed: %d\n",
__FUNCTION__, ret));
return ret;
}
*len = sizeof(sssr_header_t);
}
break;
default:
*len = 0;
}
return BCME_OK;
}
static int
dhdpcie_sssr_srcb_header(dhd_pub_t *dhd, uint *buf, uint32 data_len, uint32 *len)
{
int ret = 0;
switch (dhd->sssr_reg_info->rev2.version) {
case SSSR_REG_INFO_VER_6:
{
sssr_header_t sssr_header;
uint32 war_reg = 0;
bzero(&sssr_header, sizeof(sssr_header_t));
dhdpcie_sssr_common_header(dhd, &sssr_header);
sssr_header.data_len = data_len;
sssr_header.coreid = SRCB_CORE_ID;
ret = dhd_sssr_srcb_war_reg(dhd, &war_reg);
if (ret == BCME_OK) {
sssr_header.war_reg = war_reg;
}
ret = memcpy_s(buf, data_len, &sssr_header, sizeof(sssr_header_t));
if (ret) {
DHD_ERROR(("%s: SRCB sssr header memcpy_s failed: %d\n",
__FUNCTION__, ret));
return ret;
}
*len = sizeof(sssr_header_t);
}
break;
default:
*len = 0;
}
return BCME_OK;
}
static int
dhdpcie_sssr_cmn_header(dhd_pub_t *dhd, uint *buf, uint32 data_len, uint32 *len)
{
int ret = 0;
switch (dhd->sssr_reg_info->rev2.version) {
case SSSR_REG_INFO_VER_6:
case SSSR_REG_INFO_VER_5:
{
sssr_header_t sssr_header = {0};
dhdpcie_sssr_common_header(dhd, &sssr_header);
sssr_header.data_len = data_len;
sssr_header.coreid = CC_CORE_ID;
ret = memcpy_s(buf, data_len, &sssr_header, sizeof(sssr_header_t));
if (ret) {
DHD_ERROR(("%s: CMN sssr header memcpy_s failed: %d\n",
__FUNCTION__, ret));
return ret;
}
*len = sizeof(sssr_header_t);
}
break;
default:
*len = 0;
}
return BCME_OK;
}
static bool
dhdpcie_saqm_check_outofreset(dhd_pub_t *dhdp)
{
dhd_bus_t *bus = dhdp->bus;
uint save_idx, save_unit;
uint saqm_buf_size = 0;
bool ret = FALSE;
save_idx = si_coreidx(bus->sih);
save_unit = si_coreunit(bus->sih);
saqm_buf_size = dhd_sssr_saqm_buf_size(dhdp);
if ((saqm_buf_size > 0) && si_setcore(bus->sih, D11_SAQM_CORE_ID, 0)) {
ret = si_iscoreup(bus->sih);
DHD_PRINT(("dhdpcie_saqm_check_outofreset si_isup %d\n",
si_iscoreup(bus->sih)));
si_setcore(bus->sih, save_idx, save_unit);
}
return ret;
}
#ifdef DHD_SSSR_DUMP_BEFORE_SR
static int
dhdpcie_sssr_dump_get_before_sr(dhd_pub_t *dhd)
{
int i;
uint32 sr_size, xmtaddress, xmtdata, dig_buf_size,
dig_buf_addr, saqm_buf_size, saqm_buf_addr;
uint8 num_d11cores;
uint32 d11_header_len = 0;
uint32 dig_header_len = 0;
uint32 saqm_header_len = 0;
uint *d11_buffer;
uint *dig_buffer;
uint *saqm_buffer;
int sssr_header_populate_state = 0;
DHD_PRINT(("%s\n", __FUNCTION__));
num_d11cores = dhd_d11_slices_num_get(dhd);
for (i = 0; i < num_d11cores; i++) {
if (dhd->sssr_d11_outofreset[i]) {
sr_size = dhd_sssr_mac_buf_size(dhd, i);
xmtaddress = dhd_sssr_mac_xmtaddress(dhd, i);
xmtdata = dhd_sssr_mac_xmtdata(dhd, i);
d11_buffer = dhd->sssr_d11_before[i];
sssr_header_populate_state = dhdpcie_sssr_d11_header(dhd, d11_buffer,
sr_size, i, &d11_header_len);
if (sssr_header_populate_state != BCME_OK) {
DHD_ERROR(("%s: dhdpcie_sssr_d11_header failed\n", __FUNCTION__));
return BCME_ERROR;
}
/* D11 buffer starts right after sssr d11 header */
d11_buffer = (uint *)((char *)d11_buffer + d11_header_len);
if (dhdpcie_get_sssr_fifo_dump(dhd, d11_buffer, sr_size, xmtaddress,
xmtdata) != BCME_OK) {
DHD_ERROR(("%s: dhdpcie_get_sssr_fifo_dump failed\n",
__FUNCTION__));
return BCME_ERROR;
}
}
}
dig_buf_size = dhd_sssr_dig_buf_size(dhd);
dig_buf_addr = dhd_sssr_dig_buf_addr(dhd);
if (dig_buf_size) {
dig_buffer = dhd->sssr_dig_buf_before;
sssr_header_populate_state = dhdpcie_sssr_dig_header(dhd, dig_buffer,
dig_buf_size, &dig_header_len);
if (sssr_header_populate_state != BCME_OK) {
DHD_ERROR(("%s: dhdpcie_sssr_dig_header failed\n", __FUNCTION__));
return BCME_ERROR;
}
/* Dig buffer starts right after sssr dig header */
dig_buffer = (uint *)((char *)dig_buffer + dig_header_len);
if (dhdpcie_get_sssr_dig_dump(dhd, dig_buffer, dig_buf_size, dig_buf_addr) !=
BCME_OK) {
DHD_ERROR(("%s: Failed to get sssr dig dump!\n", __FUNCTION__));
return BCME_ERROR;
}
}
saqm_buf_size = dhd_sssr_saqm_buf_size(dhd);
saqm_buf_addr = dhd_sssr_saqm_buf_addr(dhd);
if (saqm_buf_size) {
int supported_vers[SSSR_REG_INFO_VER_MAX] = {0};
supported_vers[0] = SSSR_REG_INFO_VER_5;
supported_vers[1] = SSSR_REG_INFO_VER_6;
supported_vers[2] = -1;
saqm_buffer = dhd->sssr_saqm_buf_before;
sssr_header_populate_state = dhdpcie_sssr_saqm_header(dhd, saqm_buffer,
saqm_buf_size, &saqm_header_len);
if (sssr_header_populate_state != BCME_OK) {
DHD_ERROR(("%s: dhdpcie_sssr_saqm_header failed\n", __FUNCTION__));
return BCME_ERROR;
}
/* saqm buffer starts right after saqm header */
saqm_buffer = (uint *)((char *)saqm_buffer + saqm_header_len);
if (dhdpcie_get_sssr_subtype_dump(dhd, saqm_buffer, saqm_buf_size,
saqm_buf_addr, SSSR_SAQM_DUMP, supported_vers) != BCME_OK) {
DHD_ERROR(("%s: Failed to get sssr saqm dump!\n", __FUNCTION__));
return BCME_ERROR;
}
}
return BCME_OK;
}
#endif /* DHD_SSSR_DUMP_BEFORE_SR */
static int
dhdpcie_sssr_dump_get_after_sr(dhd_pub_t *dhd)
{
int i;
uint32 sr_size, xmtaddress, xmtdata, dig_buf_size,
dig_buf_addr, saqm_buf_size, saqm_buf_addr,
srcb_buf_size, srcb_buf_addr;
uint32 cmn_buf_size = 0, cmn_buf_addr = 0;
uint8 num_d11cores;
uint32 d11_header_len = 0;
uint32 dig_header_len = 0;
uint32 saqm_header_len = 0;
uint32 srcb_header_len = 0;
uint32 cmn_header_len = 0;
uint *d11_buffer = NULL;
uint *dig_buffer = NULL;
uint *saqm_buffer = NULL;
uint *srcb_buffer = NULL;
uint *cmn_buffer = NULL;
int supported_vers[SSSR_REG_INFO_VER_MAX] = {0};
int sssr_header_populate_state = 0;
DHD_PRINT(("%s\n", __FUNCTION__));
num_d11cores = dhd_d11_slices_num_get(dhd);
for (i = 0; i < num_d11cores; i++) {
if (dhd->sssr_d11_outofreset[i]) {
sr_size = dhd_sssr_mac_buf_size(dhd, i);
xmtaddress = dhd_sssr_mac_xmtaddress(dhd, i);
xmtdata = dhd_sssr_mac_xmtdata(dhd, i);
d11_buffer = dhd->sssr_d11_after[i];
sssr_header_populate_state = dhdpcie_sssr_d11_header(dhd, d11_buffer,
sr_size, i, &d11_header_len);
if (sssr_header_populate_state != BCME_OK) {
DHD_ERROR(("%s: dhdpcie_sssr_d11_header failed\n", __FUNCTION__));
return BCME_ERROR;
}
/* D11 buffer starts right after sssr d11 header */
d11_buffer = (uint *)((char *)d11_buffer + d11_header_len);
if (dhdpcie_get_sssr_fifo_dump(dhd, d11_buffer, sr_size,
xmtaddress, xmtdata) != BCME_OK) {
DHD_ERROR(("%s: dhdpcie_get_sssr_fifo_dump failed\n",
__FUNCTION__));
return BCME_ERROR;
}
}
}
dig_buf_size = dhd_sssr_dig_buf_size(dhd);
dig_buf_addr = dhd_sssr_dig_buf_addr(dhd);
if (dig_buf_size) {
dig_buffer = dhd->sssr_dig_buf_after;
sssr_header_populate_state = dhdpcie_sssr_dig_header(dhd, dig_buffer,
dig_buf_size, &dig_header_len);
if (sssr_header_populate_state != BCME_OK) {
DHD_ERROR(("%s: dhdpcie_sssr_dig_header failed\n", __FUNCTION__));
return BCME_ERROR;
}
/* Dig buffer starts right after sssr dig header */
dig_buffer = (uint *)((char *)dig_buffer + dig_header_len);
if (dhdpcie_get_sssr_dig_dump(dhd, dig_buffer, dig_buf_size, dig_buf_addr) !=
BCME_OK)
{
DHD_ERROR(("%s: dhdpcie_get_sssr_dig_dump failed\n", __FUNCTION__));
return BCME_ERROR;
}
}
supported_vers[0] = SSSR_REG_INFO_VER_5;
supported_vers[1] = SSSR_REG_INFO_VER_6;
supported_vers[2] = -1;
saqm_buf_size = dhd_sssr_saqm_buf_size(dhd);
saqm_buf_addr = dhd_sssr_saqm_buf_addr(dhd);
if (saqm_buf_size) {
saqm_buffer = dhd->sssr_saqm_buf_after;
sssr_header_populate_state = dhdpcie_sssr_saqm_header(dhd, saqm_buffer,
saqm_buf_size, &saqm_header_len);
if (sssr_header_populate_state != BCME_OK) {
DHD_ERROR(("%s: dhdpcie_sssr_saqm_header failed\n", __FUNCTION__));
return BCME_ERROR;
}
/* saqm buffer starts right after saqm header */
saqm_buffer = (uint *)((char *)saqm_buffer + saqm_header_len);
if (dhdpcie_get_sssr_subtype_dump(dhd, saqm_buffer, saqm_buf_size,
saqm_buf_addr, SSSR_SAQM_DUMP, supported_vers) != BCME_OK) {
DHD_ERROR(("%s: Failed to get sssr saqm dump!\n", __FUNCTION__));
return BCME_ERROR;
}
}
if (dhd->sssr_dump_mode == SSSR_DUMP_MODE_FIS) {
supported_vers[0] = SSSR_REG_INFO_VER_6;
supported_vers[1] = -1;
srcb_buf_size = dhd_sssr_srcb_buf_size(dhd);
srcb_buf_addr = dhd_sssr_srcb_buf_addr(dhd);
if (srcb_buf_size > 0) {
srcb_buffer = dhd->sssr_srcb_buf_after;
sssr_header_populate_state = dhdpcie_sssr_srcb_header(dhd, srcb_buffer,
srcb_buf_size, &srcb_header_len);
if (sssr_header_populate_state != BCME_OK) {
DHD_ERROR(("%s: dhdpcie_sssr_srcb_header failed\n", __FUNCTION__));
return BCME_ERROR;
}
/* srcb buffer starts right after srcb header */
srcb_buffer = (uint *)((char *)srcb_buffer + srcb_header_len);
if (dhdpcie_get_sssr_subtype_dump(dhd, srcb_buffer, srcb_buf_size,
srcb_buf_addr, SSSR_SRCB_DUMP, supported_vers) != BCME_OK) {
DHD_ERROR(("%s: Failed to get sssr srcb dump!\n", __FUNCTION__));
return BCME_ERROR;
}
}
supported_vers[0] = SSSR_REG_INFO_VER_5;
supported_vers[1] = SSSR_REG_INFO_VER_6;
supported_vers[2] = -1;
cmn_buf_size = dhd_sssr_cmn_buf_size(dhd);
cmn_buf_addr = dhd_sssr_cmn_buf_addr(dhd);
if (cmn_buf_size && cmn_buf_addr > 0) {
cmn_buffer = dhd->sssr_cmn_buf_after;
/* populate header */
sssr_header_populate_state = dhdpcie_sssr_cmn_header(dhd, cmn_buffer,
cmn_buf_size, &cmn_header_len);
if (sssr_header_populate_state != BCME_OK) {
DHD_ERROR(("%s: dhdpcie_sssr_cmn_header failed\n", __FUNCTION__));
return BCME_ERROR;
}
cmn_buffer = (uint *)((char *)cmn_buffer + cmn_header_len);
if (dhdpcie_get_sssr_subtype_dump(dhd, cmn_buffer, cmn_buf_size,
cmn_buf_addr, SSSR_CMN_DUMP, supported_vers) != BCME_OK) {
DHD_ERROR(("%s: Failed to get sssr cmn dump!\n", __FUNCTION__));
return BCME_ERROR;
}
}
}
return BCME_OK;
}
#define GCI_CHIPSTATUS_AUX GCI_CHIPSTATUS_10
#define GCI_CHIPSTATUS_MAIN GCI_CHIPSTATUS_11
#define GCI_CHIPSTATUS_DIG GCI_CHIPSTATUS_12
#define GCI_CHIPSTATUS_SCAN GCI_CHIPSTATUS_13
#define GCI_CHIPSTATUS_ILLEGAL_INSTR_BITMASK (1u << 3)
int
dhdpcie_validate_gci_chip_intstatus(dhd_pub_t *dhd)
{
int gci_intstatus;
si_t *sih = dhd->bus->sih;
/* For now validate only for 4389 chip */
if (si_chipid(sih) != BCM4389_CHIP_ID) {
DHD_ERROR(("%s: skipping for chipid:0x%x\n", __FUNCTION__, si_chipid(sih)));
return BCME_OK;
}
gci_intstatus = si_gci_chipstatus(sih, GCI_CHIPSTATUS_MAIN);
if (gci_intstatus & GCI_CHIPSTATUS_ILLEGAL_INSTR_BITMASK) {
DHD_ERROR(("%s: Illegal instruction set for MAIN core 0x%x\n",
__FUNCTION__, gci_intstatus));
return BCME_ERROR;
}
gci_intstatus = si_gci_chipstatus(sih, GCI_CHIPSTATUS_AUX);
if (gci_intstatus & GCI_CHIPSTATUS_ILLEGAL_INSTR_BITMASK) {
DHD_ERROR(("%s: Illegal instruction set for AUX core 0x%x\n",
__FUNCTION__, gci_intstatus));
return BCME_ERROR;
}
gci_intstatus = si_gci_chipstatus(sih, GCI_CHIPSTATUS_SCAN);
if (gci_intstatus & GCI_CHIPSTATUS_ILLEGAL_INSTR_BITMASK) {
DHD_ERROR(("%s: Illegal instruction set for SCAN core 0x%x\n",
__FUNCTION__, gci_intstatus));
return BCME_ERROR;
}
gci_intstatus = si_gci_chipstatus(sih, GCI_CHIPSTATUS_DIG);
if (gci_intstatus & GCI_CHIPSTATUS_ILLEGAL_INSTR_BITMASK) {
DHD_ERROR(("%s: Illegal instruction set for DIG core 0x%x\n",
__FUNCTION__, gci_intstatus));
return BCME_ERROR;
}
return BCME_OK;
}
#define OOBR_DMP_FOR_D11 0x1u
#define OOBR_DMP_FOR_SAQM 0x2u
#define OOBR_DMP_D11_MAIN 0x1u
#define OOBR_DMP_D11_AUX 0x2u
#define OOBR_DMP_D11_SCAN 0x4u
#define OOBR_CAP2_NUMTOPEXTRSRC_MASK 0x1Fu
#define OOBR_CAP2_NUMTOPEXTRSRC_SHIFT 4u /* Bits 8:4 */
static int
dhdpcie_dump_oobr(dhd_pub_t *dhd, uint core_bmap, uint coreunit_bmap)
{
si_t *sih = dhd->bus->sih;
uint curcore = 0;
int i = 0;
hndoobr_reg_t *reg = NULL;
uint mask = 0x1;
uint val = 0, idx = 0;
if (CHIPTYPE(sih->socitype) != SOCI_NCI) {
return BCME_UNSUPPORTED;
}
if (dhd->bus->is_linkdown) {
DHD_ERROR(("%s: PCIe link is down\n", __FUNCTION__));
return BCME_NOTUP;
}
if (dhd->bus->link_state == DHD_PCIE_WLAN_BP_DOWN ||
dhd->bus->link_state == DHD_PCIE_COMMON_BP_DOWN) {
DHD_ERROR(("%s : wlan/common backplane is down (link_state=%u), skip.\n",
__FUNCTION__, dhd->bus->link_state));
return BCME_NOTUP;
}
curcore = si_coreid(dhd->bus->sih);
if ((reg = si_setcore(sih, HND_OOBR_CORE_ID, 0)) != NULL) {
uint corecap2 = R_REG(dhd->osh, &reg->capability2);
uint numtopextrsrc = (corecap2 >> OOBR_CAP2_NUMTOPEXTRSRC_SHIFT) &
OOBR_CAP2_NUMTOPEXTRSRC_MASK;
if (corecap2 == (uint)-1) {
DHD_ERROR(("%s:corecap2=0x%x ! Bad value, set linkdown\n",
__FUNCTION__, corecap2));
dhd_bus_set_linkdown(dhd, TRUE);
return BCME_NOTUP;
}
/*
* Convert the value (8:4) to a loop count to dump topextrsrcmap.
* TopRsrcDestSel0 is accessible if NUM_TOP_EXT_RSRC > 0
* TopRsrcDestSel1 is accessible if NUM_TOP_EXT_RSRC > 4
* TopRsrcDestSel2 is accessible if NUM_TOP_EXT_RSRC > 8
* TopRsrcDestSel3 is accessible if NUM_TOP_EXT_RSRC > 12
* 0 --> 0
* 1-3 --> 1 (TopRsrcDestSel0)
* 4-7 --> 2 (TopRsrcDestSel1/0)
* 8 - 11 --> 3 (TopRsrcDestSel2/1/0)
* 12 - 15 --> 4 (TopRsrcDestSel3/2/1/0)
*/
numtopextrsrc = numtopextrsrc ? (numtopextrsrc / 4) + 1 : numtopextrsrc;
DHD_PRINT(("reg: corecap2:0x%x numtopextrsrc: %d\n", corecap2, numtopextrsrc));
for (i = 0; i < numtopextrsrc; ++i) {
val = R_REG(dhd->osh, &reg->topextrsrcmap[i]);
DHD_PRINT(("reg: hndoobr_reg->topextrsrcmap[%d] = 0x%x\n", i, val));
}
for (i = 0; i < 4; ++i) {
val = R_REG(dhd->osh, &reg->intstatus[i]);
DHD_PRINT(("reg: hndoobr_reg->intstatus[%d] = 0x%x\n", i, val));
}
if (core_bmap & OOBR_DMP_FOR_D11) {
for (i = 0; coreunit_bmap != 0; ++i) {
if (coreunit_bmap & mask) {
idx = si_findcoreidx(sih, D11_CORE_ID, i);
val = R_REG(dhd->osh,
&reg->percore_reg[idx].clkpwrreq);
DHD_PRINT(("reg: D11 core, coreunit %d, clkpwrreq=0x%x\n",
i, val));
}
coreunit_bmap >>= 1;
}
}
if (core_bmap & OOBR_DMP_FOR_SAQM) {
idx = si_findcoreidx(sih, D11_SAQM_CORE_ID, 0);
val = R_REG(dhd->osh, &reg->percore_reg[idx].clkpwrreq);
DHD_PRINT(("reg: D11_SAQM core, coreunit 0, clkpwrreq=0x%x\n", val));
}
}
si_setcore(sih, curcore, 0);
return BCME_OK;
}
int
dhdpcie_sssr_dump(dhd_pub_t *dhd)
{
uint32 powerctrl_val = 0, pwrctrl = 0;
uint32 pwrreq_val = 0;
dhd_bus_t *bus = dhd->bus;
si_t *sih = bus->sih;
uint core_bmap = 0, coreunit_bmap = 0;
uint32 old_max_resmask = 0, min_resmask = 0, val = 0;
bool saqm_isup = FALSE;
ulong flags;
int ret = BCME_OK;
DHD_GENERAL_LOCK(bus->dhd, flags);
DHD_BUS_BUSY_SET_IN_SSSR(bus->dhd);
DHD_GENERAL_UNLOCK(bus->dhd, flags);
if (!dhd->sssr_inited) {
DHD_ERROR(("%s: SSSR not inited\n", __FUNCTION__));
ret = BCME_ERROR;
goto exit;
}
if (dhd->bus->is_linkdown) {
DHD_ERROR(("%s: PCIe link is down\n", __FUNCTION__));
ret = BCME_ERROR;
goto exit;
}
if (dhd->bus->cto_triggered) {
DHD_ERROR(("%s: CTO Triggered\n", __FUNCTION__));
ret = BCME_ERROR;
goto exit;
}
if (dhdpcie_validate_gci_chip_intstatus(dhd) != BCME_OK) {
DHD_ERROR(("%s: ## Invalid GCI Chip intstatus, Abort SSSR ##\n",
__FUNCTION__));
ret = BCME_ERROR;
goto exit;
}
bus->link_state = dhdpcie_get_link_state(bus);
if (bus->link_state != DHD_PCIE_ALL_GOOD) {
DHD_ERROR(("%s: PCIe Link is not good! link_state=%u, Abort\n",
__FUNCTION__, bus->link_state));
ret = BCME_ERROR;
goto exit;
}
dhdpcie_print_amni_regs(bus);
DHD_PRINT(("%s: Before WL down (powerctl: pcie:0x%x chipc:0x%x) "
"PMU rctl:0x%x res_state:0x%x\n", __FUNCTION__,
si_corereg(sih, sih->buscoreidx,
CC_REG_OFF(PowerControl), 0, 0),
si_corereg(sih, 0, CC_REG_OFF(PowerControl), 0, 0),
PMU_REG(sih, RetentionControl, 0, 0),
PMU_REG(sih, RsrcState, 0, 0)));
dhdpcie_d11_check_outofreset(dhd);
saqm_isup = dhdpcie_saqm_check_outofreset(dhd);
DHD_PRINT(("%s: Before WL down, SAQM core up state is %d\n", __FUNCTION__, saqm_isup));
dhd->sssr_dump_mode = SSSR_DUMP_MODE_SSSR;
#ifdef DHD_SSSR_DUMP_BEFORE_SR
DHD_PRINT(("%s: Collecting Dump before SR\n", __FUNCTION__));
if (dhdpcie_sssr_dump_get_before_sr(dhd) != BCME_OK) {
DHD_ERROR(("%s: dhdpcie_sssr_dump_get_before_sr failed\n", __FUNCTION__));
ret = BCME_ERROR;
goto exit;
}
#endif /* DHD_SSSR_DUMP_BEFORE_SR */
/* Set the flag to block all membytes or bus dumps */
bus->sssr_in_progress = TRUE;
/* Read Min and Max resource mask */
dhd_sbreg_op(dhd, dhd->sssr_reg_info->rev5.pmu_regs.base_regs.pmu_max_res_mask,
&old_max_resmask, TRUE);
dhd_sbreg_op(dhd, dhd->sssr_reg_info->rev5.pmu_regs.base_regs.pmu_min_res_mask,
&min_resmask, TRUE);
if (dhd->sssr_reg_info->rev2.version >= SSSR_REG_INFO_VER_5) {
dhdpcie_arm_clear_clk_req(dhd);
dhdpcie_saqm_clear_clk_req(dhd);
dhdpcie_pcie_send_ltrsleep(dhd);
/* MaxRsrcMask is updated to bring down the resources for rev5 and above */
val = dhd->sssr_reg_info->rev5.pmu_regs.base_regs.sssr_max_res_mask | min_resmask;
dhd_sbreg_op(dhd, dhd->sssr_reg_info->rev5.pmu_regs.base_regs.pmu_max_res_mask,
&val, FALSE);
/* Wait for some time before Restore */
OSL_DELAY(100 * 1000);
} else {
dhdpcie_clear_intmask_and_timer(dhd);
dhdpcie_clear_clk_req(dhd);
powerctrl_val = dhdpcie_suspend_chipcommon_powerctrl(dhd);
dhdpcie_pcie_send_ltrsleep(dhd);
/* save current pwr req state and clear pwr req for all domains */
pwrreq_val = si_srpwr_request(sih, 0, 0);
pwrreq_val >>= SRPWR_REQON_SHIFT;
pwrreq_val &= SRPWR_DMN_ALL_MASK(sih);
DHD_PRINT(("%s: clear pwr req all domains\n", __FUNCTION__));
si_srpwr_request(sih, SRPWR_DMN_ALL_MASK(sih), 0);
if (MULTIBP_ENAB(sih)) {
dhd_bus_pcie_pwr_req_wl_domain(dhd->bus, CC_REG_OFF(PowerControl), FALSE);
}
/* Wait for some time before Restore */
OSL_DELAY(10000);
}
pwrctrl = si_corereg(sih, 0, CC_REG_OFF(PowerControl), 0, 0);
DHD_PRINT(("%s: After WL down (powerctl: pcie:0x%x chipc:0x%x) "
"PMU rctl:0x%x res_state:0x%x old_max_resmask:0x%x min_resmask:0x%x "
"sssr_max_res_mask:0x%x max_resmask:0x%x\n", __FUNCTION__,
si_corereg(sih, sih->buscoreidx, CC_REG_OFF(PowerControl), 0, 0),
pwrctrl, PMU_REG(sih, RetentionControl, 0, 0),
PMU_REG(sih, RsrcState, 0, 0), old_max_resmask, min_resmask,
dhd->sssr_reg_info->rev5.pmu_regs.base_regs.sssr_max_res_mask,
PMU_REG(sih, MaxResourceMask, 0, 0)));
/* again check if some regs are read as 0xffffs to avoid getting
* sssr from a bad pcie link
*/
if (pwrctrl == (uint32)-1) {
DHD_ERROR(("%s: PCIe Link after WL down is not good! pwrctrl=%x, Abort\n",
__FUNCTION__, pwrctrl));
bus->link_state = DHD_PCIE_COMMON_BP_DOWN;
dhd_bus_set_linkdown(dhd, TRUE);
ret = BCME_ERROR;
goto exit;
}
if (dhd->sssr_reg_info->rev2.version >= SSSR_REG_INFO_VER_5) {
dhd_sbreg_op(dhd, dhd->sssr_reg_info->rev5.pmu_regs.base_regs.pmu_max_res_mask,
&old_max_resmask, FALSE);
}
if (MULTIBP_ENAB(sih)) {
if ((pwrctrl >> SRPWR_STATUS_SHIFT) & SRPWR_DMN1_ARMBPSD_MASK) {
DHD_ERROR(("DIG Domain is not going down. The DIG SSSR is not valid.\n"));
}
if ((pwrctrl >> SRPWR_STATUS_SHIFT) & SRPWR_DMN2_MACAUX_MASK) {
DHD_ERROR(("MAC AUX Domain is not going down.\n"));
core_bmap |= OOBR_DMP_FOR_D11;
coreunit_bmap |= OOBR_DMP_D11_AUX;
}
if ((pwrctrl >> SRPWR_STATUS_SHIFT) & SRPWR_DMN3_MACMAIN_MASK) {
DHD_ERROR(("MAC MAIN Domain is not going down\n"));
core_bmap |= OOBR_DMP_FOR_D11;
coreunit_bmap |= OOBR_DMP_D11_MAIN;
}
if ((pwrctrl >> SRPWR_STATUS_SHIFT) & SRPWR_DMN4_MACSCAN_MASK) {
DHD_ERROR(("MAC SCAN Domain is not going down.\n"));
core_bmap |= OOBR_DMP_FOR_D11;
coreunit_bmap |= OOBR_DMP_D11_SCAN;
}
if ((pwrctrl >> SRPWR_STATUS_SHIFT) & SRPWR_DMN6_SAQM_MASK) {
DHD_ERROR(("SAQM Domain is not going down.\n"));
core_bmap |= OOBR_DMP_FOR_SAQM;
}
if (core_bmap) {
ret = dhdpcie_dump_oobr(dhd, core_bmap, coreunit_bmap);
if (ret == BCME_NOTUP) {
DHD_ERROR(("%s: dhdpcie_dump_oobr fails due to linkdown !\n",
__FUNCTION__));
goto exit;
}
}
dhd_bus_pcie_pwr_req_wl_domain(dhd->bus, CC_REG_OFF(PowerControl), TRUE);
/* Add delay for WL domain to power up */
OSL_DELAY(15000);
DHD_PRINT(("%s: After WL up again (powerctl: pcie:0x%x chipc:0x%x) "
"PMU rctl:0x%x res_state:0x%x old_max_resmask:0x%x "
"min_resmask:0x%x sssr_max_res_mask:0x%x "
"max_resmask:0x%x\n", __FUNCTION__,
si_corereg(sih, sih->buscoreidx,
CC_REG_OFF(PowerControl), 0, 0),
si_corereg(sih, 0, CC_REG_OFF(PowerControl), 0, 0),
PMU_REG(sih, RetentionControl, 0, 0),
PMU_REG(sih, RsrcState, 0, 0), old_max_resmask, min_resmask,
dhd->sssr_reg_info->rev5.pmu_regs.base_regs.sssr_max_res_mask,
PMU_REG(sih, MaxResourceMask, 0, 0)));
}
dhdpcie_resume_chipcommon_powerctrl(dhd, powerctrl_val);
dhdpcie_arm_resume_clk_req(dhd);
if (dhd->sssr_reg_info->rev2.version <= SSSR_REG_INFO_VER_4) {
/* Before collecting SSSR dump explicitly request power
* for main and aux domains as per recommendation
* of ASIC team
*/
si_srpwr_request(sih, SRPWR_DMN_ALL_MASK(sih), SRPWR_DMN_ALL_MASK(sih));
}
if (dhd->sssr_reg_info->rev2.version == SSSR_REG_INFO_VER_4) {
dhdpcie_bring_saqm_updown(dhd, TRUE);
} else if (dhd->sssr_reg_info->rev2.version >= SSSR_REG_INFO_VER_5) {
dhdpcie_bring_saqm_updown(dhd, FALSE);
}
dhdpcie_bring_d11_outofreset(dhd);
if (dhd->sssr_reg_info->rev2.version == SSSR_REG_INFO_VER_4) {
dhdpcie_bring_saqm_updown(dhd, FALSE);
}
/* Add delay for d11 cores out of reset */
OSL_DELAY(6000);
saqm_isup = dhdpcie_saqm_check_outofreset(dhd);
DHD_PRINT(("%s: After WL UP and out of reset, SAQM core up state is %d\n",
__FUNCTION__, saqm_isup));
if (saqm_isup && (dhd->sssr_reg_info->rev2.version >= SSSR_REG_INFO_VER_5)) {
dhdpcie_saqm_clear_force_sr_all(dhd);
}
/* Clear the flag to unblock membytes or bus dumps */
bus->sssr_in_progress = FALSE;
DHD_PRINT(("%s: Collecting Dump after SR\n", __FUNCTION__));
if (dhdpcie_sssr_dump_get_after_sr(dhd) != BCME_OK) {
DHD_ERROR(("%s: dhdpcie_sssr_dump_get_after_sr failed\n", __FUNCTION__));
ret = BCME_ERROR;
goto exit;
}
dhd->sssr_dump_collected = TRUE;
/* restore back previous pwr req values */
DHD_PRINT(("%s: restore pwr req prev state 0x%x\n", __FUNCTION__, pwrreq_val));
si_srpwr_request(sih, pwrreq_val, pwrreq_val);
DHD_PRINT(("%s: restore done\n", __FUNCTION__));
dhd_write_sssr_dump(dhd, SSSR_DUMP_MODE_SSSR);
DHD_PRINT(("%s: sssr dump done\n", __FUNCTION__));
dhdpcie_print_amni_regs(bus);
exit:
DHD_GENERAL_LOCK(bus->dhd, flags);
DHD_BUS_BUSY_CLEAR_IN_SSSR(bus->dhd);
DHD_GENERAL_UNLOCK(bus->dhd, flags);
return ret;
}
static void
dhdpcie_clear_pmu_debug_mode(dhd_pub_t *dhd)
{
uint32 vreg_ctrl_addr, vreg_ctrl_data_addr, vreg_num, vreg_offset;
sssr_reg_info_cmn_t *sssr_reg_info_cmn = dhd->sssr_reg_info;
sssr_reg_info_v6_t *sssr_reg_info = (sssr_reg_info_v6_t *)&sssr_reg_info_cmn->rev3;
uint32 val = 0;
if (sssr_reg_info->version < SSSR_REG_INFO_VER_6) {
DHD_ERROR(("%s: not supported for version:%d\n",
__FUNCTION__, sssr_reg_info->version));
return;
}
vreg_ctrl_addr = sssr_reg_info->pmu_dbug_rst_regs.vreg_addr;
vreg_ctrl_data_addr = sssr_reg_info->pmu_dbug_rst_regs.vreg_data_addr;
vreg_num = sssr_reg_info->pmu_dbug_rst_regs.vreg_num;
vreg_offset = sssr_reg_info->pmu_dbug_rst_regs.vreg_offset;
if (IS_HWADDR_INVALID(vreg_ctrl_addr) || IS_HWADDR_INVALID(vreg_ctrl_data_addr)) {
DHD_ERROR(("%s: Bad values ! vreg_ctrl_addr=0x%x; vreg_ctrl_data_addr=0x%x;\n",
__FUNCTION__, vreg_ctrl_addr, vreg_ctrl_data_addr));
return;
}
dhd_sbreg_op(dhd, vreg_ctrl_addr, &vreg_num, FALSE);
dhd_sbreg_op(dhd, vreg_ctrl_data_addr, &val, TRUE);
val |= 1 << vreg_offset;
dhd_sbreg_op(dhd, vreg_ctrl_data_addr, &val, FALSE);
OSL_DELAY(100);
val &= ~(1 << vreg_offset);
dhd_sbreg_op(dhd, vreg_ctrl_data_addr, &val, FALSE);
}
#define PCIE_CFG_DSTATE_MASK 0x11u
#define CHIPCOMMON_WAR_SIGNATURE 0xabcdu
#define FIS_DONE_DELAY (100 * 1000) /* 100ms */
int
dhdpcie_fis_recover(dhd_pub_t *dhd)
{
uint32 FISCtrlStatus = 0;
uint32 FISTrigRsrcState, RsrcState, MinResourceMask;
#ifdef FIS_WITH_CMN
uint32 cfg_status_cmd;
uint32 cfg_pmcsr;
/*
* For android built-in platforms need to perform REG ON/OFF
* to restore pcie link.
* dhd_download_fw_on_driverload will be FALSE for built-in.
*/
if (!dhd_download_fw_on_driverload) {
DHD_PRINT(("%s: Toggle REG_ON and restore config space\n", __FUNCTION__));
dhdpcie_bus_stop_host_dev(dhd->bus);
dhd_wifi_platform_set_power(dhd, FALSE);
dhd_wifi_platform_set_power(dhd, TRUE);
dhd_bus_reset_link_state(dhd);
dhdpcie_bus_start_host_dev(dhd->bus);
/* Restore inited pcie cfg from pci_load_saved_state */
dhdpcie_bus_enable_device(dhd->bus);
}
/* Use dhd restore function instead of kernel api */
dhdpcie_config_restore(dhd->bus, TRUE);
cfg_status_cmd = dhd_pcie_config_read(dhd->bus, PCIECFGREG_STATUS_CMD, sizeof(uint32));
cfg_pmcsr = dhd_pcie_config_read(dhd->bus, PCIE_CFG_PMCSR, sizeof(uint32));
DHD_PRINT(("after restore: Status Command(0x%x)=0x%x PCIE_CFG_PMCSR(0x%x)=0x%x\n",
PCIECFGREG_STATUS_CMD, cfg_status_cmd, PCIE_CFG_PMCSR, cfg_pmcsr));
DHD_PRINT(("after restore: PCI_BAR0_WIN(0x%x)=0x%x PCI_BAR1_WIN(0x%x)=0x%x\n",
PCI_BAR0_WIN, dhd_pcie_config_read(dhd->bus, PCI_BAR0_WIN, sizeof(uint32)),
PCI_BAR1_WIN, dhd_pcie_config_read(dhd->bus, PCI_BAR1_WIN, sizeof(uint32))));
DHD_PRINT(("after restore: PCIE2_BAR0_WIN2(0x%x)=0x%x"
" PCIE2_BAR0_CORE2_WIN(0x%x)=0x%x PCIE2_BAR0_CORE2_WIN2(0x%x)=0x%x\n",
PCIE2_BAR0_WIN2, dhd_pcie_config_read(dhd->bus, PCIE2_BAR0_WIN2, sizeof(uint32)),
PCIE2_BAR0_CORE2_WIN,
dhd_pcie_config_read(dhd->bus, PCIE2_BAR0_CORE2_WIN, sizeof(uint32)),
PCIE2_BAR0_CORE2_WIN2,
dhd_pcie_config_read(dhd->bus, PCIE2_BAR0_CORE2_WIN2, sizeof(uint32))));
/*
* To-Do: below is debug code, remove this if EP is in D0 after REG-ON restore
* in both MSM and LSI RCs
*/
if ((cfg_pmcsr & PCIE_CFG_DSTATE_MASK) != 0) {
int ret = dhdpcie_set_master_and_d0_pwrstate(dhd->bus);
if (ret != BCME_OK) {
DHD_ERROR(("%s: Setting D0 failed, ABORT FIS collection\n", __FUNCTION__));
return ret;
}
cfg_status_cmd =
dhd_pcie_config_read(dhd->bus, PCIECFGREG_STATUS_CMD, sizeof(uint32));
cfg_pmcsr = dhd_pcie_config_read(dhd->bus, PCIE_CFG_PMCSR, sizeof(uint32));
DHD_PRINT(("after force-d0: Status Command(0x%x)=0x%x PCIE_CFG_PMCSR(0x%x)=0x%x\n",
PCIECFGREG_STATUS_CMD, cfg_status_cmd, PCIE_CFG_PMCSR, cfg_pmcsr));
}
FISCtrlStatus = PMU_REG(dhd->bus->sih, FISCtrlStatus, 0, 0);
FISTrigRsrcState = PMU_REG(dhd->bus->sih, FISTrigRsrcState, 0, 0);
RsrcState = PMU_REG(dhd->bus->sih, RsrcState, 0, 0);
MinResourceMask = PMU_REG(dhd->bus->sih, MinResourceMask, 0, 0);
DHD_PRINT(("%s: After trigger & %u us delay: FISCtrlStatus=0x%x, FISTrigRsrcState=0x%x,"
" RsrcState=0x%x MinResourceMask=0x%x\n",
__FUNCTION__, FIS_DONE_DELAY, FISCtrlStatus, FISTrigRsrcState,
RsrcState, MinResourceMask));
#endif /* FIS_WITH_CMN */
#ifdef FIS_WITHOUT_CMN
FISCtrlStatus = PMU_REG(dhd->bus->sih, FISCtrlStatus, 0, 0);
FISTrigRsrcState = PMU_REG(dhd->bus->sih, FISTrigRsrcState, 0, 0);
RsrcState = PMU_REG(dhd->bus->sih, RsrcState, 0, 0);
MinResourceMask = PMU_REG(dhd->bus->sih, MinResourceMask, 0, 0);
DHD_PRINT(("%s: After trigger & %u us delay: FISCtrlStatus=0x%x, FISTrigRsrcState=0x%x,"
" RsrcState=0x%x MinResourceMask=0x%x\n",
__FUNCTION__, FIS_DONE_DELAY, FISCtrlStatus, FISTrigRsrcState,
RsrcState, MinResourceMask));
#endif /* FIS_WITHOUT_CMN */
if ((FISCtrlStatus & PMU_CLEAR_FIS_DONE_MASK) == 0) {
DHD_ERROR(("%s: FIS Done bit not set. exit\n", __FUNCTION__));
return BCME_ERROR;
}
dhdpcie_clear_pmu_debug_mode(dhd);
/* Clear fis_triggered as REG OFF/ON recovered link */
dhd->fis_triggered = FALSE;
return BCME_OK;
}
static int
dhdpcie_fis_trigger(dhd_pub_t *dhd)
{
uint32 cfg_status_cmd;
uint32 cfg_pmcsr;
BCM_REFERENCE(cfg_status_cmd);
BCM_REFERENCE(cfg_pmcsr);
if (!dhd->sssr_inited) {
DHD_ERROR(("%s: SSSR not inited\n", __FUNCTION__));
return BCME_ERROR;
}
if (dhd->bus->is_linkdown) {
DHD_ERROR(("%s: PCIe link is down\n", __FUNCTION__));
return BCME_ERROR;
}
#ifdef DHD_PCIE_RUNTIMEPM
/* Bring back to D0 */
dhdpcie_runtime_bus_wake(dhd, CAN_SLEEP(), __builtin_return_address(0));
/* Stop RPM timer so that even INB DW DEASSERT should not happen */
DHD_STOP_RPM_TIMER(dhd);
#endif /* DHD_PCIE_RUNTIMEPM */
/* Set fis_triggered flag to ignore link down callback from RC */
dhd->fis_triggered = TRUE;
#ifdef FIS_WITH_CMN
/* for android platforms, since they support WL_REG_ON toggle,
* trigger FIS with common subcore - which involves saving pcie
* config space, toggle REG_ON and restoring pcie config space
*/
cfg_status_cmd = dhd_pcie_config_read(dhd->bus, PCIECFGREG_STATUS_CMD, sizeof(uint32));
cfg_pmcsr = dhd_pcie_config_read(dhd->bus, PCIE_CFG_PMCSR, sizeof(uint32));
DHD_PRINT(("before save: Status Command(0x%x)=0x%x PCIE_CFG_PMCSR(0x%x)=0x%x\n",
PCIECFGREG_STATUS_CMD, cfg_status_cmd, PCIE_CFG_PMCSR, cfg_pmcsr));
DHD_PRINT(("before save: PCI_BAR0_WIN(0x%x)=0x%x PCI_BAR1_WIN(0x%x)=0x%x\n",
PCI_BAR0_WIN, dhd_pcie_config_read(dhd->bus, PCI_BAR0_WIN, sizeof(uint32)),
PCI_BAR1_WIN, dhd_pcie_config_read(dhd->bus, PCI_BAR1_WIN, sizeof(uint32))));
DHD_PRINT(("before save: PCIE2_BAR0_WIN2(0x%x)=0x%x"
" PCIE2_BAR0_CORE2_WIN(0x%x)=0x%x PCIE2_BAR0_CORE2_WIN2(0x%x)=0x%x\n",
PCIE2_BAR0_WIN2, dhd_pcie_config_read(dhd->bus, PCIE2_BAR0_WIN2, sizeof(uint32)),
PCIE2_BAR0_CORE2_WIN,
dhd_pcie_config_read(dhd->bus, PCIE2_BAR0_CORE2_WIN, sizeof(uint32)),
PCIE2_BAR0_CORE2_WIN2,
dhd_pcie_config_read(dhd->bus, PCIE2_BAR0_CORE2_WIN2, sizeof(uint32))));
/* Use dhd save function instead of kernel api */
dhdpcie_config_save(dhd->bus);
/* Trigger FIS */
si_corereg(dhd->bus->sih, dhd->bus->sih->buscoreidx,
DAR_FIS_CTRL(dhd->bus->sih->buscorerev), ~0, DAR_FIS_START_MASK);
OSL_DELAY(FIS_DONE_DELAY);
#endif /* FIS_WITH_CMN */
#ifdef FIS_WITHOUT_CMN
/* for non-android platforms, since they do not support
* WL_REG_ON toggle, trigger FIS without common subcore
* the PcieSaveEn bit in PMU FISCtrlStatus reg would be
* set to 0 during init time
*/
si_corereg(dhd->bus->sih, dhd->bus->sih->buscoreidx,
DAR_FIS_CTRL(dhd->bus->sih->buscorerev), DAR_FIS_START_MASK, DAR_FIS_START_MASK);
/* wait for FIS done */
OSL_DELAY(FIS_DONE_DELAY);
/* clear the timeout interrupt in PCIE errlog register
* before reading any register on backplane
*/
si_corereg(dhd->bus->sih, dhd->bus->sih->buscoreidx,
PCIE_REG_OFF(dar_errorlog), DAR_ERRLOG_MASK, DAR_ERRLOG_MASK);
#endif /* FIS_WITHOUT_CMN */
return dhdpcie_fis_recover(dhd);
}
int
dhd_bus_fis_trigger(dhd_pub_t *dhd)
{
return dhdpcie_fis_trigger(dhd);
}
bool
dhdpcie_set_collect_fis(dhd_bus_t *bus)
{
#if defined(DHD_FIS_DUMP) && (defined(FIS_WITH_CMN) || defined(FIS_WITHOUT_CMN))
if (CHIPTYPE(bus->sih->socitype) == SOCI_NCI) {
DHD_PRINT(("%s : Collect FIS dumps\n", __FUNCTION__));
bus->dhd->collect_fis = TRUE;
return TRUE;
}
#endif /* DHD_FIS_DUMP */
return FALSE;
}
static int
dhdpcie_reset_hwa(dhd_pub_t *dhd)
{
int ret;
sssr_reg_info_cmn_t *sssr_reg_info_cmn = dhd->sssr_reg_info;
sssr_reg_info_v3_t *sssr_reg_info = (sssr_reg_info_v3_t *)&sssr_reg_info_cmn->rev3;
/* HWA wrapper registers */
uint32 ioctrl, resetctrl;
/* HWA base registers */
uint32 clkenable, clkgatingenable, clkext, clkctlstatus;
uint32 hwa_resetseq_val[SSSR_HWA_RESET_SEQ_STEPS];
int i = 0;
if (sssr_reg_info->version < SSSR_REG_INFO_VER_3) {
DHD_ERROR(("%s: not supported for version:%d\n",
__FUNCTION__, sssr_reg_info->version));
return BCME_UNSUPPORTED;
}
if (sssr_reg_info->hwa_regs.base_regs.clkenable == 0) {
DHD_ERROR(("%s: hwa regs are not set\n", __FUNCTION__));
return BCME_UNSUPPORTED;
}
DHD_PRINT(("%s: version:%d\n", __FUNCTION__, sssr_reg_info->version));
ioctrl = sssr_reg_info->hwa_regs.wrapper_regs.ioctrl;
resetctrl = sssr_reg_info->hwa_regs.wrapper_regs.resetctrl;
clkenable = sssr_reg_info->hwa_regs.base_regs.clkenable;
clkgatingenable = sssr_reg_info->hwa_regs.base_regs.clkgatingenable;
clkext = sssr_reg_info->hwa_regs.base_regs.clkext;
clkctlstatus = sssr_reg_info->hwa_regs.base_regs.clkctlstatus;
ret = memcpy_s(hwa_resetseq_val, sizeof(hwa_resetseq_val),
sssr_reg_info->hwa_regs.hwa_resetseq_val,
sizeof(sssr_reg_info->hwa_regs.hwa_resetseq_val));
if (ret) {
DHD_ERROR(("%s: hwa_resetseq_val memcpy_s failed: %d\n",
__FUNCTION__, ret));
return ret;
}
dhd_sbreg_op(dhd, ioctrl, &hwa_resetseq_val[i++], FALSE);
dhd_sbreg_op(dhd, resetctrl, &hwa_resetseq_val[i++], FALSE);
dhd_sbreg_op(dhd, resetctrl, &hwa_resetseq_val[i++], FALSE);
dhd_sbreg_op(dhd, ioctrl, &hwa_resetseq_val[i++], FALSE);
dhd_sbreg_op(dhd, clkenable, &hwa_resetseq_val[i++], FALSE);
dhd_sbreg_op(dhd, clkgatingenable, &hwa_resetseq_val[i++], FALSE);
dhd_sbreg_op(dhd, clkext, &hwa_resetseq_val[i++], FALSE);
dhd_sbreg_op(dhd, clkctlstatus, &hwa_resetseq_val[i++], FALSE);
return BCME_OK;
}
static bool
dhdpcie_fis_fw_triggered_check(struct dhd_bus *bus)
{
uint32 FISCtrlStatus;
if (bus->link_state == DHD_PCIE_WLAN_BP_DOWN ||
bus->link_state == DHD_PCIE_COMMON_BP_DOWN) {
DHD_ERROR(("%s : wlan/common backplane is down (link_state=%u).\n",
__FUNCTION__, bus->link_state));
return FALSE;
}
FISCtrlStatus = PMU_REG(bus->sih, FISCtrlStatus, 0, 0);
if (FISCtrlStatus == (uint32)-1) {
DHD_ERROR(("%s: WARNING! invalid value of FISCtrlStatus(0x%x)\n", __FUNCTION__,
FISCtrlStatus));
return FALSE;
}
if ((FISCtrlStatus & PMU_CLEAR_FIS_DONE_MASK) == 0) {
DHD_PRINT(("%s: FIS trigger done bit not set. FIS control status=0x%x\n",
__FUNCTION__, FISCtrlStatus));
return FALSE;
} else {
DHD_PRINT(("%s: FIS trigger done bit set. FIS control status=0x%x\n",
__FUNCTION__, FISCtrlStatus));
return TRUE;
}
}
static int
dhdpcie_fis_dump(dhd_pub_t *dhd)
{
int i;
uint32 FISCtrlStatus, FISTrigRsrcState, RsrcState;
uint8 num_d11cores;
struct dhd_bus *bus = dhd->bus;
uint32 save_idx = 0;
int hwa_reset_state;
uint curcore = 0;
uint val = 0;
chipcregs_t *chipcregs = NULL;
curcore = si_coreid(bus->sih);
DHD_PRINT(("%s\n", __FUNCTION__));
if (!dhd->sssr_inited) {
DHD_ERROR(("%s: SSSR not inited\n", __FUNCTION__));
return BCME_ERROR;
}
dhd->busstate = DHD_BUS_LOAD;
FISCtrlStatus = PMU_REG(dhd->bus->sih, FISCtrlStatus, 0, 0);
if ((FISCtrlStatus & PMU_CLEAR_FIS_DONE_MASK) == 0) {
DHD_ERROR(("%s: FIS Done bit not set. exit\n", __FUNCTION__));
return BCME_ERROR;
}
/* bring up all pmu resources */
PMU_REG(dhd->bus->sih, MinResourceMask, ~0,
PMU_REG(dhd->bus->sih, MaxResourceMask, 0, 0));
OSL_DELAY(10 * 1000);
num_d11cores = dhd_d11_slices_num_get(dhd);
for (i = 0; i < num_d11cores; i++) {
dhd->sssr_d11_outofreset[i] = TRUE;
}
if (dhd->sssr_reg_info->rev2.version >= SSSR_REG_INFO_VER_4) {
dhdpcie_bring_saqm_updown(dhd, TRUE);
}
dhdpcie_bring_d11_outofreset(dhd);
if (dhd->sssr_reg_info->rev2.version >= SSSR_REG_INFO_VER_4) {
dhdpcie_bring_saqm_updown(dhd, FALSE);
}
/* Take DAP core out of reset so that ETB is readable again */
chipcregs = (chipcregs_t *)si_setcore(bus->sih, CC_CORE_ID, 0);
if (chipcregs != NULL) {
val = R_REG(bus->osh, CC_REG_ADDR(chipcregs, JtagMasterCtrl));
W_REG(bus->osh, CC_REG_ADDR(chipcregs, JtagMasterCtrl),
val & ~(1 << 9));
}
si_setcore(bus->sih, curcore, 0);
OSL_DELAY(6000);
FISCtrlStatus = PMU_REG(dhd->bus->sih, FISCtrlStatus, 0, 0);
FISTrigRsrcState = PMU_REG(dhd->bus->sih, FISTrigRsrcState, 0, 0);
RsrcState = PMU_REG(dhd->bus->sih, RsrcState, 0, 0);
DHD_PRINT(("%s: 0 ms before FIS_DONE clear: FISCtrlStatus=0x%x,"
" FISTrigRsrcState=0x%x, RsrcState=0x%x\n",
__FUNCTION__, FISCtrlStatus, FISTrigRsrcState, RsrcState));
/* clear FIS Done */
PMU_REG(dhd->bus->sih, FISCtrlStatus, PMU_CLEAR_FIS_DONE_MASK, PMU_CLEAR_FIS_DONE_MASK);
FISCtrlStatus = PMU_REG(dhd->bus->sih, FISCtrlStatus, 0, 0);
FISTrigRsrcState = PMU_REG(dhd->bus->sih, FISTrigRsrcState, 0, 0);
RsrcState = PMU_REG(dhd->bus->sih, RsrcState, 0, 0);
DHD_PRINT(("%s: 0 ms after FIS_DONE clear: FISCtrlStatus=0x%x,"
" FISTrigRsrcState=0x%x, RsrcState=0x%x\n",
__FUNCTION__, FISCtrlStatus, FISTrigRsrcState, RsrcState));
hwa_reset_state = dhdpcie_reset_hwa(dhd);
if (hwa_reset_state != BCME_OK && hwa_reset_state != BCME_UNSUPPORTED) {
DHD_ERROR(("%s: dhdpcie_reset_hwa failed\n", __FUNCTION__));
return BCME_ERROR;
}
dhdpcie_d11_check_outofreset(dhd);
/* take sysmem out of reset - otherwise
* socram collected again will read only
* 0xffff
*/
save_idx = si_coreidx(bus->sih);
if (si_setcore(bus->sih, SYSMEM_CORE_ID, 0)) {
si_core_reset(bus->sih, 0, 0);
si_setcoreidx(bus->sih, save_idx);
}
/* FIS trigger puts cores into reset including aximem
* so take out of reset again to dump content;
* otherwise, AERs with FFs
*/
save_idx = si_coreidx(bus->sih);
if (si_setcore(bus->sih, AXIMEM_CORE_ID, 0)) {
si_core_reset(bus->sih, 0, 0);
si_setcoreidx(bus->sih, save_idx);
}
DHD_PRINT(("%s: Collecting Dump after SR\n", __FUNCTION__));
dhd->sssr_dump_mode = SSSR_DUMP_MODE_FIS;
if (dhdpcie_sssr_dump_get_after_sr(dhd) != BCME_OK) {
DHD_ERROR(("%s: dhdpcie_sssr_dump_get_after_sr failed\n", __FUNCTION__));
return BCME_ERROR;
}
dhd->sssr_dump_collected = TRUE;
dhd_write_sssr_dump(dhd, SSSR_DUMP_MODE_FIS);
if (dhd->bus->link_state != DHD_PCIE_ALL_GOOD) {
/* reset link state and collect socram */
dhd->bus->link_state = DHD_PCIE_ALL_GOOD;
DHD_PRINT(("%s: recollect socram\n", __FUNCTION__));
/* re-read socram into buffer */
dhdpcie_get_mem_dump(bus);
}
return BCME_OK;
}
int
dhd_bus_fis_dump(dhd_pub_t *dhd)
{
return dhdpcie_fis_dump(dhd);
}
bool
dhd_bus_fis_fw_triggered_check(dhd_pub_t *dhd)
{
return dhdpcie_fis_fw_triggered_check(dhd->bus);
}
void
dhd_fill_sssr_reg_info_4389(dhd_pub_t *dhd)
{
sssr_reg_info_cmn_t *sssr_reg_info_cmn = dhd->sssr_reg_info;
sssr_reg_info_v3_t *sssr_reg_info;
sssr_reg_info = (sssr_reg_info_v3_t *)&sssr_reg_info_cmn->rev3;
DHD_PRINT(("%s:\n", __FUNCTION__));
sssr_reg_info->version = SSSR_REG_INFO_VER_3;
sssr_reg_info->length = sizeof(sssr_reg_info_v3_t);
sssr_reg_info->pmu_regs.base_regs.pmuintmask0 = 0x18012700;
sssr_reg_info->pmu_regs.base_regs.pmuintmask1 = 0x18012704;
sssr_reg_info->pmu_regs.base_regs.resreqtimer = 0x18012644;
sssr_reg_info->pmu_regs.base_regs.macresreqtimer = 0x18012688;
sssr_reg_info->pmu_regs.base_regs.macresreqtimer1 = 0x180126f0;
sssr_reg_info->pmu_regs.base_regs.macresreqtimer2 = 0x18012738;
sssr_reg_info->chipcommon_regs.base_regs.intmask = 0x18000024;
sssr_reg_info->chipcommon_regs.base_regs.powerctrl = 0x180001e8;
sssr_reg_info->chipcommon_regs.base_regs.clockcontrolstatus = 0x180001e0;
sssr_reg_info->chipcommon_regs.base_regs.powerctrl_mask = 0x1f00;
sssr_reg_info->arm_regs.base_regs.clockcontrolstatus = 0x180201e0;
sssr_reg_info->arm_regs.base_regs.clockcontrolstatus_val = 0x20;
sssr_reg_info->arm_regs.wrapper_regs.resetctrl = 0x18120800;
sssr_reg_info->arm_regs.wrapper_regs.extrsrcreq = 0x18006234;
sssr_reg_info->pcie_regs.base_regs.ltrstate = 0x18001c38;
sssr_reg_info->pcie_regs.base_regs.clockcontrolstatus = 0x180011e0;
sssr_reg_info->pcie_regs.base_regs.clockcontrolstatus_val = 0x0;
sssr_reg_info->pcie_regs.wrapper_regs.extrsrcreq = 0x180061b4;
sssr_reg_info->mac_regs[0].base_regs.xmtaddress = 0x18021130;
sssr_reg_info->mac_regs[0].base_regs.xmtdata = 0x18021134;
sssr_reg_info->mac_regs[0].base_regs.clockcontrolstatus = 0x180211e0;
sssr_reg_info->mac_regs[0].base_regs.clockcontrolstatus_val = 0x20;
sssr_reg_info->mac_regs[0].wrapper_regs.resetctrl = 0x18121800;
sssr_reg_info->mac_regs[0].wrapper_regs.extrsrcreq = 0x180062b4;
sssr_reg_info->mac_regs[0].wrapper_regs.ioctrl = 0x18121408;
sssr_reg_info->mac_regs[0].wrapper_regs.ioctrl_resetseq_val[0] = 0xc7;
sssr_reg_info->mac_regs[0].wrapper_regs.ioctrl_resetseq_val[1] = 0x15f;
sssr_reg_info->mac_regs[0].wrapper_regs.ioctrl_resetseq_val[2] = 0x151;
sssr_reg_info->mac_regs[0].wrapper_regs.ioctrl_resetseq_val[3] = 0x155;
sssr_reg_info->mac_regs[0].wrapper_regs.ioctrl_resetseq_val[4] = 0xc5;
sssr_reg_info->mac_regs[0].sr_size = 0x40000;
sssr_reg_info->mac_regs[1].base_regs.xmtaddress = 0x18022130;
sssr_reg_info->mac_regs[1].base_regs.xmtdata = 0x18022134;
sssr_reg_info->mac_regs[1].base_regs.clockcontrolstatus = 0x180221e0;
sssr_reg_info->mac_regs[1].base_regs.clockcontrolstatus_val = 0x20;
sssr_reg_info->mac_regs[1].wrapper_regs.resetctrl = 0x18122800;
sssr_reg_info->mac_regs[1].wrapper_regs.extrsrcreq = 0x18006334;
sssr_reg_info->mac_regs[1].wrapper_regs.ioctrl = 0x18122408;
sssr_reg_info->mac_regs[1].wrapper_regs.ioctrl_resetseq_val[0] = 0xc7;
sssr_reg_info->mac_regs[1].wrapper_regs.ioctrl_resetseq_val[1] = 0x15f;
sssr_reg_info->mac_regs[1].wrapper_regs.ioctrl_resetseq_val[2] = 0x151;
sssr_reg_info->mac_regs[1].wrapper_regs.ioctrl_resetseq_val[3] = 0x155;
sssr_reg_info->mac_regs[1].wrapper_regs.ioctrl_resetseq_val[4] = 0xc5;
sssr_reg_info->mac_regs[1].sr_size = 0x30000;
sssr_reg_info->mac_regs[2].base_regs.xmtaddress = 0x18023130;
sssr_reg_info->mac_regs[2].base_regs.xmtdata = 0x18023134;
sssr_reg_info->mac_regs[2].base_regs.clockcontrolstatus = 0x180231e0;
sssr_reg_info->mac_regs[2].base_regs.clockcontrolstatus_val = 0x20;
sssr_reg_info->mac_regs[2].wrapper_regs.resetctrl = 0x18123800;
sssr_reg_info->mac_regs[2].wrapper_regs.extrsrcreq = 0x180063b4;
sssr_reg_info->mac_regs[2].wrapper_regs.ioctrl = 0x18123408;
sssr_reg_info->mac_regs[2].wrapper_regs.ioctrl_resetseq_val[0] = 0xc7;
sssr_reg_info->mac_regs[2].wrapper_regs.ioctrl_resetseq_val[1] = 0x15f;
sssr_reg_info->mac_regs[2].wrapper_regs.ioctrl_resetseq_val[2] = 0x151;
sssr_reg_info->mac_regs[2].wrapper_regs.ioctrl_resetseq_val[3] = 0x155;
sssr_reg_info->mac_regs[2].wrapper_regs.ioctrl_resetseq_val[4] = 0xc5;
sssr_reg_info->mac_regs[2].sr_size = 0x30000;
sssr_reg_info->dig_mem_info.dig_sr_addr = 0x18520000;
sssr_reg_info->dig_mem_info.dig_sr_size = 0x10000;
sssr_reg_info->fis_enab = 1;
sssr_reg_info->hwa_regs.base_regs.clkenable = 0x180242d0;
sssr_reg_info->hwa_regs.base_regs.clkgatingenable = 0x180242d4;
sssr_reg_info->hwa_regs.base_regs.clkext = 0x180242e0;
sssr_reg_info->hwa_regs.base_regs.clkctlstatus = 0x180241e0;
sssr_reg_info->hwa_regs.wrapper_regs.ioctrl = 0x18124408;
sssr_reg_info->hwa_regs.wrapper_regs.resetctrl = 0x18124800;
sssr_reg_info->hwa_regs.hwa_resetseq_val[0] = 0x3;
sssr_reg_info->hwa_regs.hwa_resetseq_val[1] = 0x1;
sssr_reg_info->hwa_regs.hwa_resetseq_val[2] = 0x0;
sssr_reg_info->hwa_regs.hwa_resetseq_val[3] = 0x1;
sssr_reg_info->hwa_regs.hwa_resetseq_val[4] = 0x1ff;
sssr_reg_info->hwa_regs.hwa_resetseq_val[5] = 0x1ff;
sssr_reg_info->hwa_regs.hwa_resetseq_val[6] = 0x3;
sssr_reg_info->hwa_regs.hwa_resetseq_val[7] = 0x20;
dhd->sssr_inited = TRUE;
}
void
dhdpcie_fill_sssr_reg_info(dhd_pub_t *dhd)
{
if (dhd_get_chipid(dhd->bus) == BCM4389_CHIP_ID) {
dhd_fill_sssr_reg_info_4389(dhd);
}
}
void
dhdpcie_set_pmu_fisctrlsts(struct dhd_bus *bus)
{
uint32 FISCtrlStatus = 0;
bool fis_fw_triggered = FALSE;
if (CHIPTYPE(bus->sih->socitype) != SOCI_NCI) {
return;
}
/* FIS might be triggered in firmware, so FIS collection
* should be done and fis control status reg should not be
* touched before FIS collection.
*/
fis_fw_triggered = dhdpcie_fis_fw_triggered_check(bus);
if (fis_fw_triggered) {
return;
}
#ifdef FIS_WITH_CMN
/* for platforms where reg on toggle support is present
* FIS with common subcore is collected, so set PcieSaveEn bit in
* PMU FISCtrlStatus reg
*/
FISCtrlStatus = PMU_REG(bus->sih, FISCtrlStatus, PMU_FIS_PCIE_SAVE_EN_VALUE,
PMU_FIS_PCIE_SAVE_EN_VALUE);
FISCtrlStatus = PMU_REG(bus->sih, FISCtrlStatus, 0, 0);
DHD_PRINT(("%s: reg on support present, set PMU FISCtrlStatus=0x%x \n",
__FUNCTION__, FISCtrlStatus));
#endif /* FIS_WITH_CMN */
#ifdef FIS_WITHOUT_CMN
/* for platforms where reg on toggle support is absent
* FIS without common subcore is collected, so reset PcieSaveEn bit in
* PMU FISCtrlStatus reg
*/
FISCtrlStatus = PMU_REG(bus->sih, FISCtrlStatus, PMU_FIS_PCIE_SAVE_EN_VALUE, 0x0);
FISCtrlStatus = PMU_REG(bus->sih, FISCtrlStatus, 0, 0);
DHD_PRINT(("%s: reg on not supported, set PMU FISCtrlStatus=0x%x \n",
__FUNCTION__, FISCtrlStatus));
#endif /* FIS_WITHOUT_CMN */
}
int
dhd_sssr_mempool_init(dhd_pub_t *dhd)
{
#ifdef CONFIG_BCMDHD_PCIE
dhd->sssr_mempool = (uint8 *) VMALLOCZ(dhd->osh, DHD_SSSR_MEMPOOL_SIZE);
#else
dhd->sssr_mempool = (uint8 *) MALLOCZ(dhd->osh, DHD_SSSR_MEMPOOL_SIZE);
#endif /* CONFIG_BCMDHD_PCIE */
if (dhd->sssr_mempool == NULL) {
DHD_ERROR(("%s: MALLOC of sssr_mempool failed\n",
__FUNCTION__));
return BCME_ERROR;
}
return BCME_OK;
}
void
dhd_sssr_mempool_deinit(dhd_pub_t *dhd)
{
if (dhd->sssr_mempool) {
#ifdef CONFIG_BCMDHD_PCIE
VMFREE(dhd->osh, dhd->sssr_mempool, DHD_SSSR_MEMPOOL_SIZE);
#else
MFREE(dhd->osh, dhd->sssr_mempool, DHD_SSSR_MEMPOOL_SIZE);
#endif /* CONFIG_BCMDHD_PCIE */
dhd->sssr_mempool = NULL;
}
}
int
dhd_sssr_reg_info_init(dhd_pub_t *dhd)
{
dhd->sssr_reg_info = (sssr_reg_info_cmn_t *) MALLOCZ(dhd->osh, sizeof(sssr_reg_info_cmn_t));
if (dhd->sssr_reg_info == NULL) {
DHD_ERROR(("%s: MALLOC of sssr_reg_info failed\n",
__FUNCTION__));
return BCME_ERROR;
}
return BCME_OK;
}
void
dhd_sssr_reg_info_deinit(dhd_pub_t *dhd)
{
if (dhd->sssr_reg_info) {
MFREE(dhd->osh, dhd->sssr_reg_info, sizeof(sssr_reg_info_cmn_t));
dhd->sssr_reg_info = NULL;
}
}
#ifdef DHD_PCIE_REG_ACCESS
static void
dhd_dump_sssr_reg_info_v2(dhd_pub_t *dhd)
{
sssr_reg_info_cmn_t *sssr_reg_info_cmn = dhd->sssr_reg_info;
sssr_reg_info_v2_t *sssr_reg_info = (sssr_reg_info_v2_t *)&sssr_reg_info_cmn->rev2;
int i, j;
uint8 num_d11cores = dhd_d11_slices_num_get(dhd);
DHD_PRINT(("pmu_regs\n"));
DHD_PRINT(("pmuintmask0=0x%x pmuintmask1=0x%x resreqtimer=0x%x "
"macresreqtimer=0x%x macresreqtimer1=0x%x\n",
sssr_reg_info->pmu_regs.base_regs.pmuintmask0,
sssr_reg_info->pmu_regs.base_regs.pmuintmask1,
sssr_reg_info->pmu_regs.base_regs.resreqtimer,
sssr_reg_info->pmu_regs.base_regs.macresreqtimer,
sssr_reg_info->pmu_regs.base_regs.macresreqtimer1));
DHD_PRINT(("chipcommon_regs\n"));
DHD_PRINT(("intmask=0x%x powerctrl=0x%x clockcontrolstatus=0x%x powerctrl_mask=0x%x\n",
sssr_reg_info->chipcommon_regs.base_regs.intmask,
sssr_reg_info->chipcommon_regs.base_regs.powerctrl,
sssr_reg_info->chipcommon_regs.base_regs.clockcontrolstatus,
sssr_reg_info->chipcommon_regs.base_regs.powerctrl_mask));
DHD_PRINT(("arm_regs\n"));
DHD_PRINT(("clockcontrolstatus=0x%x clockcontrolstatus_val=0x%x"
" resetctrl=0x%x extrsrcreq=0x%x\n",
sssr_reg_info->arm_regs.base_regs.clockcontrolstatus,
sssr_reg_info->arm_regs.base_regs.clockcontrolstatus_val,
sssr_reg_info->arm_regs.wrapper_regs.resetctrl,
sssr_reg_info->arm_regs.wrapper_regs.extrsrcreq));
DHD_PRINT(("pcie_regs\n"));
DHD_PRINT(("ltrstate=0x%x clockcontrolstatus=0x%x "
"clockcontrolstatus_val=0x%x extrsrcreq=0x%x\n",
sssr_reg_info->pcie_regs.base_regs.ltrstate,
sssr_reg_info->pcie_regs.base_regs.clockcontrolstatus,
sssr_reg_info->pcie_regs.base_regs.clockcontrolstatus_val,
sssr_reg_info->pcie_regs.wrapper_regs.extrsrcreq));
for (i = 0; i < num_d11cores; i++) {
DHD_PRINT(("mac_regs core[%d]\n", i));
DHD_PRINT(("xmtaddress=0x%x xmtdata=0x%x clockcontrolstatus=0x%x "
"clockcontrolstatus_val=0x%x\n",
sssr_reg_info->mac_regs[i].base_regs.xmtaddress,
sssr_reg_info->mac_regs[i].base_regs.xmtdata,
sssr_reg_info->mac_regs[i].base_regs.clockcontrolstatus,
sssr_reg_info->mac_regs[i].base_regs.clockcontrolstatus_val));
DHD_PRINT(("resetctrl=0x%x extrsrcreq=0x%x ioctrl=0x%x\n",
sssr_reg_info->mac_regs[i].wrapper_regs.resetctrl,
sssr_reg_info->mac_regs[i].wrapper_regs.extrsrcreq,
sssr_reg_info->mac_regs[i].wrapper_regs.ioctrl));
for (j = 0; j < SSSR_D11_RESET_SEQ_STEPS; j++) {
DHD_PRINT(("ioctrl_resetseq_val[%d] 0x%x\n", j,
sssr_reg_info->mac_regs[i].wrapper_regs.ioctrl_resetseq_val[j]));
}
DHD_PRINT(("sr_size=0x%x\n", sssr_reg_info->mac_regs[i].sr_size));
}
DHD_PRINT(("dig_regs\n"));
DHD_PRINT(("dig_sr_addr=0x%x dig_sr_size=0x%x\n",
sssr_reg_info->dig_mem_info.dig_sr_addr,
sssr_reg_info->dig_mem_info.dig_sr_size));
}
static void
dhd_dump_sssr_reg_info_v3(dhd_pub_t *dhd)
{
sssr_reg_info_cmn_t *sssr_reg_info_cmn = dhd->sssr_reg_info;
sssr_reg_info_v3_t *sssr_reg_info = (sssr_reg_info_v3_t *)&sssr_reg_info_cmn->rev3;
int i;
dhd_dump_sssr_reg_info_v2(dhd);
DHD_PRINT(("FIS Enab in fw : %d\n", sssr_reg_info->fis_enab));
DHD_PRINT(("HWA regs for reset \n"));
DHD_PRINT(("clkenable 0x%x, clkgatingenable 0x%x, clkext 0x%x, "
"clkctlstatus 0x%x, ioctrl 0x%x, resetctrl 0x%x\n",
sssr_reg_info->hwa_regs.base_regs.clkenable,
sssr_reg_info->hwa_regs.base_regs.clkgatingenable,
sssr_reg_info->hwa_regs.base_regs.clkext,
sssr_reg_info->hwa_regs.base_regs.clkctlstatus,
sssr_reg_info->hwa_regs.wrapper_regs.ioctrl,
sssr_reg_info->hwa_regs.wrapper_regs.resetctrl));
DHD_PRINT(("HWA regs value seq for reset \n"));
for (i = 0; i < SSSR_HWA_RESET_SEQ_STEPS; i++) {
DHD_PRINT(("hwa_resetseq_val[%d] 0x%x\n", i,
sssr_reg_info->hwa_regs.hwa_resetseq_val[i]));
}
}
static void
dhd_dump_sssr_reg_info_v6(dhd_pub_t *dhd)
{
sssr_reg_info_cmn_t *sssr_reg_info_cmn = dhd->sssr_reg_info;
sssr_reg_info_v6_t *sssr_reg_info = (sssr_reg_info_v6_t *)&sssr_reg_info_cmn->rev6;
int i;
uint8 num_d11cores = dhd_d11_slices_num_get(dhd);
DHD_PRINT(("pmu_regs\n"));
DHD_PRINT(("pmuintmask0=0x%x pmuintmask1=0x%x resreqtimer=0x%x "
"macresreqtimer=0x%x macresreqtimer1=0x%x macresreqtimer2=0x%x"
"pmu_min_res_mask=0x%x pmu_max_res_mask=0x%x sssr_max_res_mask=0x%x\n",
sssr_reg_info->pmu_regs.base_regs.pmuintmask0,
sssr_reg_info->pmu_regs.base_regs.pmuintmask1,
sssr_reg_info->pmu_regs.base_regs.resreqtimer,
sssr_reg_info->pmu_regs.base_regs.macresreqtimer,
sssr_reg_info->pmu_regs.base_regs.macresreqtimer1,
sssr_reg_info->pmu_regs.base_regs.macresreqtimer2,
sssr_reg_info->pmu_regs.base_regs.pmu_min_res_mask,
sssr_reg_info->pmu_regs.base_regs.pmu_max_res_mask,
sssr_reg_info->pmu_regs.base_regs.sssr_max_res_mask));
DHD_PRINT(("chipcommon_regs\n"));
DHD_PRINT(("intmask=0x%x powerctrl=0x%x clockcontrolstatus=0x%x powerctrl_mask=0x%x\n",
sssr_reg_info->chipcommon_regs.base_regs.intmask,
sssr_reg_info->chipcommon_regs.base_regs.powerctrl,
sssr_reg_info->chipcommon_regs.base_regs.clockcontrolstatus,
sssr_reg_info->chipcommon_regs.base_regs.powerctrl_mask));
DHD_PRINT(("arm_regs\n"));
DHD_PRINT(("clockcontrolstatus=0x%x clockcontrolstatus_val=0x%x"
" extrsrcreq=0x%x war_reg=0x%x\n",
sssr_reg_info->arm_regs.base_regs.clockcontrolstatus,
sssr_reg_info->arm_regs.base_regs.clockcontrolstatus_val,
sssr_reg_info->arm_regs.oobr_regs.extrsrcreq,
sssr_reg_info->arm_regs.war_reg));
DHD_PRINT(("pcie_regs\n"));
DHD_PRINT(("ltrstate=0x%x clockcontrolstatus=0x%x "
"clockcontrolstatus_val=0x%x extrsrcreq=0x%x\n",
sssr_reg_info->pcie_regs.base_regs.ltrstate,
sssr_reg_info->pcie_regs.base_regs.clockcontrolstatus,
sssr_reg_info->pcie_regs.base_regs.clockcontrolstatus_val,
sssr_reg_info->pcie_regs.oobr_regs.extrsrcreq));
for (i = 0; i < num_d11cores; i++) {
DHD_PRINT(("mac_regs core[%d]\n", i));
DHD_PRINT(("xmtaddress=0x%x xmtdata=0x%x clockcontrolstatus=0x%x "
"clockcontrolstatus_val=0x%x extrsrcreq=0x%x war_reg=0x%x\n",
sssr_reg_info->mac_regs[i].base_regs.xmtaddress,
sssr_reg_info->mac_regs[i].base_regs.xmtdata,
sssr_reg_info->mac_regs[i].base_regs.clockcontrolstatus,
sssr_reg_info->mac_regs[i].base_regs.clockcontrolstatus_val,
sssr_reg_info->mac_regs[i].oobr_regs.extrsrcreq,
sssr_reg_info->mac_regs[i].war_reg));
DHD_PRINT(("sr_size=0x%x\n", sssr_reg_info->mac_regs[i].sr_size));
}
DHD_PRINT(("saqm_sssr_info base_regs\n"));
DHD_PRINT(("clockcontrolstatus=0x%x clockcontrolstatus_val=0x%x "
"extrsrcreq=0x%x war_reg=0x%x\n",
sssr_reg_info->saqm_sssr_info.base_regs.clockcontrolstatus,
sssr_reg_info->saqm_sssr_info.base_regs.clockcontrolstatus_val,
sssr_reg_info->saqm_sssr_info.oobr_regs.extrsrcreq,
sssr_reg_info->saqm_sssr_info.war_reg));
DHD_PRINT(("saqm_sssr_info saqm_sssr_addr=0x%x saqm_sssr_size=0x%x\n",
sssr_reg_info->saqm_sssr_info.saqm_sssr_addr,
sssr_reg_info->saqm_sssr_info.saqm_sssr_size));
DHD_PRINT(("saqm_sssr_info config_regs\n"));
DHD_PRINT(("digsr_srcontrol1_addr=0x%x digsr_srcontrol1_clrbit_val=0x%x"
" digsr_srcontrol2_addr=0x%x digsr_srcontrol2_setbit_val=0x%x"
" pmuchip_ctl_addr_reg=0x%x, pmuchip_ctl_val=0x%x"
" pmuchip_ctl_data_reg=0x%x pmuchip_ctl_setbit_val=0x%x\n",
sssr_reg_info->saqm_sssr_info.sssr_config_regs.digsr_srcontrol1_addr,
sssr_reg_info->saqm_sssr_info.sssr_config_regs.digsr_srcontrol1_clrbit_val,
sssr_reg_info->saqm_sssr_info.sssr_config_regs.digsr_srcontrol2_addr,
sssr_reg_info->saqm_sssr_info.sssr_config_regs.digsr_srcontrol2_setbit_val,
sssr_reg_info->saqm_sssr_info.sssr_config_regs.pmuchip_ctl_addr_reg,
sssr_reg_info->saqm_sssr_info.sssr_config_regs.pmuchip_ctl_val,
sssr_reg_info->saqm_sssr_info.sssr_config_regs.pmuchip_ctl_data_reg,
sssr_reg_info->saqm_sssr_info.sssr_config_regs.pmuchip_ctl_setbit_val));
DHD_PRINT(("dig_mem_info\n"));
DHD_PRINT(("dig_sssr_addr=0x%x dig_sssr_size=0x%x\n",
sssr_reg_info->dig_mem_info.dig_sssr_addr,
sssr_reg_info->dig_mem_info.dig_sssr_size));
DHD_PRINT(("fis_mem_info\n"));
DHD_PRINT(("fis_addr=0x%x fis_size=0x%x fis_enab=0x%x\n",
sssr_reg_info->fis_mem_info.fis_addr,
sssr_reg_info->fis_mem_info.fis_size,
sssr_reg_info->fis_enab));
DHD_PRINT(("sssr_all_mem_info\n"));
DHD_PRINT(("sysmem_sssr_addr=0x%x sysmem_sssr_size=0x%x\n",
sssr_reg_info->sssr_all_mem_info.sysmem_sssr_addr,
sssr_reg_info->sssr_all_mem_info.sysmem_sssr_size));
DHD_PRINT(("sr_asm_version=0x%xn", sssr_reg_info->sr_asm_version));
DHD_PRINT(("srcb_mem_info\n"));
DHD_PRINT(("war_reg=0x%x srcb_sssr_addr=0x%x srcb_sssr_size=0x%x\n",
sssr_reg_info->srcb_mem_info.war_reg,
sssr_reg_info->srcb_mem_info.srcb_sssr_addr,
sssr_reg_info->srcb_mem_info.srcb_sssr_size));
DHD_PRINT(("pmu debug rst regs\n"));
DHD_PRINT(("vreg_addr=0x%x vreg_data_addr=0x%x vreg_num=0x%x vreg_offset=0x%x\n",
sssr_reg_info->pmu_dbug_rst_regs.vreg_addr,
sssr_reg_info->pmu_dbug_rst_regs.vreg_data_addr,
sssr_reg_info->pmu_dbug_rst_regs.vreg_num,
sssr_reg_info->pmu_dbug_rst_regs.vreg_offset));
}
static void
dhd_dump_sssr_reg_info_v5(dhd_pub_t *dhd)
{
sssr_reg_info_cmn_t *sssr_reg_info_cmn = dhd->sssr_reg_info;
sssr_reg_info_v5_t *sssr_reg_info = (sssr_reg_info_v5_t *)&sssr_reg_info_cmn->rev5;
int i;
uint8 num_d11cores = dhd_d11_slices_num_get(dhd);
DHD_PRINT(("pmu_regs\n"));
DHD_PRINT(("pmuintmask0=0x%x pmuintmask1=0x%x resreqtimer=0x%x "
"macresreqtimer=0x%x macresreqtimer1=0x%x macresreqtimer2=0x%x"
"pmu_min_res_mask=0x%x pmu_max_res_mask=0x%x sssr_max_res_mask=0x%x\n",
sssr_reg_info->pmu_regs.base_regs.pmuintmask0,
sssr_reg_info->pmu_regs.base_regs.pmuintmask1,
sssr_reg_info->pmu_regs.base_regs.resreqtimer,
sssr_reg_info->pmu_regs.base_regs.macresreqtimer,
sssr_reg_info->pmu_regs.base_regs.macresreqtimer1,
sssr_reg_info->pmu_regs.base_regs.macresreqtimer2,
sssr_reg_info->pmu_regs.base_regs.pmu_min_res_mask,
sssr_reg_info->pmu_regs.base_regs.pmu_max_res_mask,
sssr_reg_info->pmu_regs.base_regs.sssr_max_res_mask));
DHD_PRINT(("chipcommon_regs\n"));
DHD_PRINT(("intmask=0x%x powerctrl=0x%x clockcontrolstatus=0x%x powerctrl_mask=0x%x\n",
sssr_reg_info->chipcommon_regs.base_regs.intmask,
sssr_reg_info->chipcommon_regs.base_regs.powerctrl,
sssr_reg_info->chipcommon_regs.base_regs.clockcontrolstatus,
sssr_reg_info->chipcommon_regs.base_regs.powerctrl_mask));
DHD_PRINT(("arm_regs\n"));
DHD_PRINT(("clockcontrolstatus=0x%x clockcontrolstatus_val=0x%x"
" extrsrcreq=0x%x war_reg=0x%x\n",
sssr_reg_info->arm_regs.base_regs.clockcontrolstatus,
sssr_reg_info->arm_regs.base_regs.clockcontrolstatus_val,
sssr_reg_info->arm_regs.oobr_regs.extrsrcreq,
sssr_reg_info->arm_regs.war_reg));
DHD_PRINT(("pcie_regs\n"));
DHD_PRINT(("ltrstate=0x%x clockcontrolstatus=0x%x "
"clockcontrolstatus_val=0x%x extrsrcreq=0x%x\n",
sssr_reg_info->pcie_regs.base_regs.ltrstate,
sssr_reg_info->pcie_regs.base_regs.clockcontrolstatus,
sssr_reg_info->pcie_regs.base_regs.clockcontrolstatus_val,
sssr_reg_info->pcie_regs.oobr_regs.extrsrcreq));
for (i = 0; i < num_d11cores; i++) {
DHD_PRINT(("mac_regs core[%d]\n", i));
DHD_PRINT(("xmtaddress=0x%x xmtdata=0x%x clockcontrolstatus=0x%x "
"clockcontrolstatus_val=0x%x extrsrcreq=0x%x war_reg=0x%x\n",
sssr_reg_info->mac_regs[i].base_regs.xmtaddress,
sssr_reg_info->mac_regs[i].base_regs.xmtdata,
sssr_reg_info->mac_regs[i].base_regs.clockcontrolstatus,
sssr_reg_info->mac_regs[i].base_regs.clockcontrolstatus_val,
sssr_reg_info->mac_regs[i].oobr_regs.extrsrcreq,
sssr_reg_info->mac_regs[i].war_reg));
DHD_PRINT(("sr_size=0x%x\n", sssr_reg_info->mac_regs[i].sr_size));
}
DHD_PRINT(("saqm_sssr_info base_regs\n"));
DHD_PRINT(("clockcontrolstatus=0x%x clockcontrolstatus_val=0x%x "
"extrsrcreq=0x%x war_reg=0x%x\n",
sssr_reg_info->saqm_sssr_info.base_regs.clockcontrolstatus,
sssr_reg_info->saqm_sssr_info.base_regs.clockcontrolstatus_val,
sssr_reg_info->saqm_sssr_info.oobr_regs.extrsrcreq,
sssr_reg_info->saqm_sssr_info.war_reg));
DHD_PRINT(("saqm_sssr_info saqm_sssr_addr=0x%x saqm_sssr_size=0x%x\n",
sssr_reg_info->saqm_sssr_info.saqm_sssr_addr,
sssr_reg_info->saqm_sssr_info.saqm_sssr_size));
DHD_PRINT(("saqm_sssr_info config_regs\n"));
DHD_PRINT(("digsr_srcontrol1_addr=0x%x digsr_srcontrol1_clrbit_val=0x%x"
" digsr_srcontrol2_addr=0x%x digsr_srcontrol2_setbit_val=0x%x"
" pmuchip_ctl_addr_reg=0x%x, pmuchip_ctl_val=0x%x"
" pmuchip_ctl_data_reg=0x%x pmuchip_ctl_setbit_val=0x%x\n",
sssr_reg_info->saqm_sssr_info.sssr_config_regs.digsr_srcontrol1_addr,
sssr_reg_info->saqm_sssr_info.sssr_config_regs.digsr_srcontrol1_clrbit_val,
sssr_reg_info->saqm_sssr_info.sssr_config_regs.digsr_srcontrol2_addr,
sssr_reg_info->saqm_sssr_info.sssr_config_regs.digsr_srcontrol2_setbit_val,
sssr_reg_info->saqm_sssr_info.sssr_config_regs.pmuchip_ctl_addr_reg,
sssr_reg_info->saqm_sssr_info.sssr_config_regs.pmuchip_ctl_val,
sssr_reg_info->saqm_sssr_info.sssr_config_regs.pmuchip_ctl_data_reg,
sssr_reg_info->saqm_sssr_info.sssr_config_regs.pmuchip_ctl_setbit_val));
DHD_PRINT(("dig_mem_info\n"));
DHD_PRINT(("dig_sssr_addr=0x%x dig_sssr_size=0x%x\n",
sssr_reg_info->dig_mem_info.dig_sssr_addr,
sssr_reg_info->dig_mem_info.dig_sssr_size));
DHD_PRINT(("fis_mem_info\n"));
DHD_PRINT(("fis_addr=0x%x fis_size=0x%x fis_enab=0x%x\n",
sssr_reg_info->fis_mem_info.fis_addr,
sssr_reg_info->fis_mem_info.fis_size,
sssr_reg_info->fis_enab));
DHD_PRINT(("sssr_all_mem_info\n"));
DHD_PRINT(("sysmem_sssr_addr=0x%x sysmem_sssr_size=0x%x\n",
sssr_reg_info->sssr_all_mem_info.sysmem_sssr_addr,
sssr_reg_info->sssr_all_mem_info.sysmem_sssr_size));
}
static void
dhd_dump_sssr_reg_info_v4(dhd_pub_t *dhd)
{
sssr_reg_info_cmn_t *sssr_reg_info_cmn = dhd->sssr_reg_info;
sssr_reg_info_v4_t *sssr_reg_info = (sssr_reg_info_v4_t *)&sssr_reg_info_cmn->rev4;
int i;
uint8 num_d11cores = dhd_d11_slices_num_get(dhd);
DHD_PRINT(("pmu_regs\n"));
DHD_PRINT(("pmuintmask0=0x%x pmuintmask1=0x%x resreqtimer=0x%x "
"macresreqtimer=0x%x macresreqtimer1=0x%x macresreqtimer2=0x%x\n",
sssr_reg_info->pmu_regs.base_regs.pmuintmask0,
sssr_reg_info->pmu_regs.base_regs.pmuintmask1,
sssr_reg_info->pmu_regs.base_regs.resreqtimer,
sssr_reg_info->pmu_regs.base_regs.macresreqtimer,
sssr_reg_info->pmu_regs.base_regs.macresreqtimer1,
sssr_reg_info->pmu_regs.base_regs.macresreqtimer2));
DHD_PRINT(("chipcommon_regs\n"));
DHD_PRINT(("intmask=0x%x powerctrl=0x%x clockcontrolstatus=0x%x powerctrl_mask=0x%x\n",
sssr_reg_info->chipcommon_regs.base_regs.intmask,
sssr_reg_info->chipcommon_regs.base_regs.powerctrl,
sssr_reg_info->chipcommon_regs.base_regs.clockcontrolstatus,
sssr_reg_info->chipcommon_regs.base_regs.powerctrl_mask));
DHD_PRINT(("arm_regs\n"));
DHD_PRINT(("clockcontrolstatus=0x%x clockcontrolstatus_val=0x%x"
" extrsrcreq=0x%x\n",
sssr_reg_info->arm_regs.base_regs.clockcontrolstatus,
sssr_reg_info->arm_regs.base_regs.clockcontrolstatus_val,
sssr_reg_info->arm_regs.oobr_regs.extrsrcreq));
DHD_PRINT(("pcie_regs\n"));
DHD_PRINT(("ltrstate=0x%x clockcontrolstatus=0x%x "
"clockcontrolstatus_val=0x%x extrsrcreq=0x%x\n",
sssr_reg_info->pcie_regs.base_regs.ltrstate,
sssr_reg_info->pcie_regs.base_regs.clockcontrolstatus,
sssr_reg_info->pcie_regs.base_regs.clockcontrolstatus_val,
sssr_reg_info->pcie_regs.oobr_regs.extrsrcreq));
for (i = 0; i < num_d11cores; i++) {
DHD_PRINT(("mac_regs core[%d]\n", i));
DHD_PRINT(("xmtaddress=0x%x xmtdata=0x%x clockcontrolstatus=0x%x "
"clockcontrolstatus_val=0x%x extrsrcreq=0x%x\n",
sssr_reg_info->mac_regs[i].base_regs.xmtaddress,
sssr_reg_info->mac_regs[i].base_regs.xmtdata,
sssr_reg_info->mac_regs[i].base_regs.clockcontrolstatus,
sssr_reg_info->mac_regs[i].base_regs.clockcontrolstatus_val,
sssr_reg_info->mac_regs[i].oobr_regs.extrsrcreq));
DHD_PRINT(("sr_size=0x%x\n", sssr_reg_info->mac_regs[i].sr_size));
}
DHD_PRINT(("saqm_sssr_info base_regs\n"));
DHD_PRINT(("clockcontrolstatus=0x%x clockcontrolstatus_val=0x%x extrsrcreq=0x%x\n",
sssr_reg_info->saqm_sssr_info.base_regs.clockcontrolstatus,
sssr_reg_info->saqm_sssr_info.base_regs.clockcontrolstatus_val,
sssr_reg_info->saqm_sssr_info.oobr_regs.extrsrcreq));
DHD_PRINT(("saqm_sssr_info saqm_sssr_addr=0x%x saqm_sssr_size=0x%x\n",
sssr_reg_info->saqm_sssr_info.saqm_sssr_addr,
sssr_reg_info->saqm_sssr_info.saqm_sssr_size));
DHD_PRINT(("saqm_sssr_info config_regs\n"));
DHD_PRINT(("digsr_srcontrol1_addr=0x%x digsr_srcontrol1_clrbit_val=0x%x"
" digsr_srcontrol2_addr=0x%x digsr_srcontrol2_setbit_val=0x%x"
" pmuchip_ctl_addr_reg=0x%x, pmuchip_ctl_val=0x%x"
" pmuchip_ctl_data_reg=0x%x pmuchip_ctl_setbit_val=0x%x\n",
sssr_reg_info->saqm_sssr_info.sssr_config_regs.digsr_srcontrol1_addr,
sssr_reg_info->saqm_sssr_info.sssr_config_regs.digsr_srcontrol1_clrbit_val,
sssr_reg_info->saqm_sssr_info.sssr_config_regs.digsr_srcontrol2_addr,
sssr_reg_info->saqm_sssr_info.sssr_config_regs.digsr_srcontrol2_setbit_val,
sssr_reg_info->saqm_sssr_info.sssr_config_regs.pmuchip_ctl_addr_reg,
sssr_reg_info->saqm_sssr_info.sssr_config_regs.pmuchip_ctl_val,
sssr_reg_info->saqm_sssr_info.sssr_config_regs.pmuchip_ctl_data_reg,
sssr_reg_info->saqm_sssr_info.sssr_config_regs.pmuchip_ctl_setbit_val));
DHD_PRINT(("dig_mem_info\n"));
DHD_PRINT(("dig_sssr_addr=0x%x dig_sssr_size=0x%x\n",
sssr_reg_info->dig_mem_info.dig_sssr_addr,
sssr_reg_info->dig_mem_info.dig_sssr_size));
DHD_PRINT(("fis_mem_info\n"));
DHD_PRINT(("fis_addr=0x%x fis_size=0x%x fis_enab=0x%x\n",
sssr_reg_info->fis_mem_info.fis_addr,
sssr_reg_info->fis_mem_info.fis_size,
sssr_reg_info->fis_enab));
DHD_PRINT(("sssr_all_mem_info\n"));
DHD_PRINT(("sysmem_sssr_addr=0x%x sysmem_sssr_size=0x%x\n",
sssr_reg_info->sssr_all_mem_info.sysmem_sssr_addr,
sssr_reg_info->sssr_all_mem_info.sysmem_sssr_size));
}
static void
dhd_dump_sssr_reg_info_v1(dhd_pub_t *dhd)
{
sssr_reg_info_cmn_t *sssr_reg_info_cmn = dhd->sssr_reg_info;
sssr_reg_info_v1_t *sssr_reg_info = (sssr_reg_info_v1_t *)&sssr_reg_info_cmn->rev1;
int i, j;
uint8 num_d11cores = dhd_d11_slices_num_get(dhd);
DHD_PRINT(("pmu_regs\n"));
DHD_PRINT(("pmuintmask0=0x%x pmuintmask1=0x%x resreqtimer=0x%x "
"macresreqtimer=0x%x macresreqtimer1=0x%x\n",
sssr_reg_info->pmu_regs.base_regs.pmuintmask0,
sssr_reg_info->pmu_regs.base_regs.pmuintmask1,
sssr_reg_info->pmu_regs.base_regs.resreqtimer,
sssr_reg_info->pmu_regs.base_regs.macresreqtimer,
sssr_reg_info->pmu_regs.base_regs.macresreqtimer1));
DHD_PRINT(("chipcommon_regs\n"));
DHD_PRINT(("intmask=0x%x powerctrl=0x%x clockcontrolstatus=0x%x powerctrl_mask=0x%x\n",
sssr_reg_info->chipcommon_regs.base_regs.intmask,
sssr_reg_info->chipcommon_regs.base_regs.powerctrl,
sssr_reg_info->chipcommon_regs.base_regs.clockcontrolstatus,
sssr_reg_info->chipcommon_regs.base_regs.powerctrl_mask));
DHD_PRINT(("arm_regs\n"));
DHD_PRINT(("clockcontrolstatus=0x%x clockcontrolstatus_val=0x%x"
" resetctrl=0x%x itopoobb=0x%x\n",
sssr_reg_info->arm_regs.base_regs.clockcontrolstatus,
sssr_reg_info->arm_regs.base_regs.clockcontrolstatus_val,
sssr_reg_info->arm_regs.wrapper_regs.resetctrl,
sssr_reg_info->arm_regs.wrapper_regs.itopoobb));
DHD_PRINT(("pcie_regs\n"));
DHD_PRINT(("ltrstate=0x%x clockcontrolstatus=0x%x "
"clockcontrolstatus_val=0x%x itopoobb=0x%x\n",
sssr_reg_info->pcie_regs.base_regs.ltrstate,
sssr_reg_info->pcie_regs.base_regs.clockcontrolstatus,
sssr_reg_info->pcie_regs.base_regs.clockcontrolstatus_val,
sssr_reg_info->pcie_regs.wrapper_regs.itopoobb));
DHD_PRINT(("vasip_regs\n"));
DHD_PRINT(("ioctrl=0x%x vasip_sr_addr=0x%x vasip_sr_size=0x%x\n",
sssr_reg_info->vasip_regs.wrapper_regs.ioctrl,
sssr_reg_info->vasip_regs.vasip_sr_addr,
sssr_reg_info->vasip_regs.vasip_sr_size));
for (i = 0; i < num_d11cores; i++) {
DHD_PRINT(("mac_regs core[%d]\n", i));
DHD_PRINT(("xmtaddress=0x%x xmtdata=0x%x clockcontrolstatus=0x%x "
"clockcontrolstatus_val=0x%x\n",
sssr_reg_info->mac_regs[i].base_regs.xmtaddress,
sssr_reg_info->mac_regs[i].base_regs.xmtdata,
sssr_reg_info->mac_regs[i].base_regs.clockcontrolstatus,
sssr_reg_info->mac_regs[i].base_regs.clockcontrolstatus_val));
DHD_PRINT(("resetctrl=0x%x itopoobb=0x%x ioctrl=0x%x\n",
sssr_reg_info->mac_regs[i].wrapper_regs.resetctrl,
sssr_reg_info->mac_regs[i].wrapper_regs.itopoobb,
sssr_reg_info->mac_regs[i].wrapper_regs.ioctrl));
for (j = 0; j < SSSR_D11_RESET_SEQ_STEPS; j++) {
DHD_PRINT(("ioctrl_resetseq_val[%d] 0x%x\n", j,
sssr_reg_info->mac_regs[i].wrapper_regs.ioctrl_resetseq_val[j]));
}
DHD_PRINT(("sr_size=0x%x\n", sssr_reg_info->mac_regs[i].sr_size));
}
}
#endif /* DHD_PCIE_REG_ACCESS */
void
dhd_dump_sssr_reg_info(dhd_pub_t *dhd)
{
#ifdef DHD_PCIE_REG_ACCESS
sssr_reg_info_cmn_t *sssr_reg_info_cmn = dhd->sssr_reg_info;
sssr_reg_info_v1_t *sssr_reg_info = (sssr_reg_info_v1_t *)&sssr_reg_info_cmn->rev1;
DHD_PRINT(("************** SSSR REG INFO start version:%d ****************\n",
sssr_reg_info->version));
switch (sssr_reg_info->version) {
case SSSR_REG_INFO_VER_6 :
dhd_dump_sssr_reg_info_v6(dhd);
break;
case SSSR_REG_INFO_VER_5 :
dhd_dump_sssr_reg_info_v5(dhd);
break;
case SSSR_REG_INFO_VER_4 :
dhd_dump_sssr_reg_info_v4(dhd);
break;
case SSSR_REG_INFO_VER_3 :
dhd_dump_sssr_reg_info_v3(dhd);
break;
case SSSR_REG_INFO_VER_2 :
dhd_dump_sssr_reg_info_v2(dhd);
break;
default:
dhd_dump_sssr_reg_info_v1(dhd);
break;
}
DHD_PRINT(("************** SSSR REG INFO end ****************\n"));
#endif /* DHD_PCIE_REG_ACCESS */
}
void dhdpcie_fill_sssr_reg_info(dhd_pub_t *dhd);
int
dhd_get_sssr_reg_info(dhd_pub_t *dhd)
{
int ret;
char *filepath_sssr = "/root/sssr_reginfo.dat";
if (dhd->force_sssr_init) {
dhdpcie_fill_sssr_reg_info(dhd);
dhd->force_sssr_init = FALSE;
goto done;
}
/* get sssr_reg_info from firmware */
ret = dhd_iovar(dhd, 0, "sssr_reg_info", NULL, 0, (char *)dhd->sssr_reg_info,
sizeof(sssr_reg_info_cmn_t), FALSE);
if (ret < 0) {
DHD_ERROR(("%s: sssr_reg_info failed (error=%d)\n",
__FUNCTION__, ret));
return BCME_ERROR;
}
/* Write sssr reg info to output file */
switch (dhd->sssr_reg_info->rev2.version) {
case SSSR_REG_INFO_VER_6 :
ret = dhd_write_file_and_check(filepath_sssr,
(char*)(&dhd->sssr_reg_info->rev6),
sizeof(sssr_reg_info_v6_t));
break;
case SSSR_REG_INFO_VER_5 :
ret = dhd_write_file_and_check(filepath_sssr,
(char*)(&dhd->sssr_reg_info->rev5),
sizeof(sssr_reg_info_v5_t));
break;
case SSSR_REG_INFO_VER_4 :
ret = dhd_write_file_and_check(filepath_sssr,
(char*)(&dhd->sssr_reg_info->rev4),
sizeof(sssr_reg_info_v4_t));
break;
case SSSR_REG_INFO_VER_3 :
ret = dhd_write_file_and_check(filepath_sssr,
(char*)(&dhd->sssr_reg_info->rev3),
sizeof(sssr_reg_info_v3_t));
break;
case SSSR_REG_INFO_VER_2 :
ret = dhd_write_file_and_check(filepath_sssr,
(char*)(&dhd->sssr_reg_info->rev2),
sizeof(sssr_reg_info_v2_t));
break;
case SSSR_REG_INFO_VER_1 :
ret = dhd_write_file_and_check(filepath_sssr,
(char*)(&dhd->sssr_reg_info->rev1),
sizeof(sssr_reg_info_v1_t));
break;
case SSSR_REG_INFO_VER_0 :
ret = dhd_write_file_and_check(filepath_sssr,
(char*)(&dhd->sssr_reg_info->rev0),
sizeof(sssr_reg_info_v0_t));
break;
}
if (ret < 0) {
DHD_ERROR(("%s: SSSR REG INFO [%s] Failed to write into"
" File: %s\n", __FUNCTION__, (char*)(&dhd->sssr_reg_info->rev0), filepath_sssr));
}
done:
dhd_dump_sssr_reg_info(dhd);
return BCME_OK;
}
uint32
dhd_get_sssr_bufsize(dhd_pub_t *dhd)
{
int i;
uint32 sssr_bufsize = 0;
uint8 num_d11cores;
num_d11cores = dhd_d11_slices_num_get(dhd);
switch (dhd->sssr_reg_info->rev2.version) {
case SSSR_REG_INFO_VER_6 :
case SSSR_REG_INFO_VER_5 :
sssr_bufsize += dhd->sssr_reg_info->rev5.sssr_all_mem_info.sysmem_sssr_size;
break;
case SSSR_REG_INFO_VER_4 :
sssr_bufsize += dhd->sssr_reg_info->rev4.sssr_all_mem_info.sysmem_sssr_size;
break;
case SSSR_REG_INFO_VER_3 :
for (i = 0; i < num_d11cores; i++) {
sssr_bufsize += dhd->sssr_reg_info->rev3.mac_regs[i].sr_size;
}
if ((dhd->sssr_reg_info->rev3.length >
OFFSETOF(sssr_reg_info_v3_t, dig_mem_info)) &&
dhd->sssr_reg_info->rev3.dig_mem_info.dig_sr_addr) {
sssr_bufsize += dhd->sssr_reg_info->rev3.dig_mem_info.dig_sr_size;
}
break;
case SSSR_REG_INFO_VER_2 :
for (i = 0; i < num_d11cores; i++) {
sssr_bufsize += dhd->sssr_reg_info->rev2.mac_regs[i].sr_size;
}
if ((dhd->sssr_reg_info->rev2.length >
OFFSETOF(sssr_reg_info_v2_t, dig_mem_info)) &&
dhd->sssr_reg_info->rev2.dig_mem_info.dig_sr_addr) {
sssr_bufsize += dhd->sssr_reg_info->rev2.dig_mem_info.dig_sr_size;
}
break;
case SSSR_REG_INFO_VER_1 :
for (i = 0; i < num_d11cores; i++) {
sssr_bufsize += dhd->sssr_reg_info->rev1.mac_regs[i].sr_size;
}
if (dhd->sssr_reg_info->rev1.vasip_regs.vasip_sr_size) {
sssr_bufsize += dhd->sssr_reg_info->rev1.vasip_regs.vasip_sr_size;
} else if ((dhd->sssr_reg_info->rev1.length > OFFSETOF(sssr_reg_info_v1_t,
dig_mem_info)) && dhd->sssr_reg_info->rev1.
dig_mem_info.dig_sr_addr) {
sssr_bufsize += dhd->sssr_reg_info->rev1.dig_mem_info.dig_sr_size;
}
break;
case SSSR_REG_INFO_VER_0 :
for (i = 0; i < num_d11cores; i++) {
sssr_bufsize += dhd->sssr_reg_info->rev0.mac_regs[i].sr_size;
}
if (dhd->sssr_reg_info->rev0.vasip_regs.vasip_sr_size) {
sssr_bufsize += dhd->sssr_reg_info->rev0.vasip_regs.vasip_sr_size;
}
break;
default :
DHD_ERROR(("invalid sssr_reg_ver"));
return BCME_UNSUPPORTED;
}
#ifdef DHD_SSSR_DUMP_BEFORE_SR
/* Double the size as different dumps will be saved before and after SR */
sssr_bufsize = 2 * sssr_bufsize;
#endif /* DHD_SSSR_DUMP_BEFORE_SR */
return sssr_bufsize;
}
int
dhd_sssr_dump_init(dhd_pub_t *dhd, bool fis_dump)
{
int i;
uint32 sssr_bufsize = 0;
uint32 mempool_used = 0;
uint8 num_d11cores = 0;
bool alloc_sssr = FALSE;
uint32 sr_size = 0;
int supported_vers[SSSR_REG_INFO_VER_MAX] = {0};
int ret = 0;
dhd->sssr_inited = FALSE;
if (!sssr_enab) {
DHD_ERROR(("%s: sssr dump not inited as instructed by mod param\n", __FUNCTION__));
return BCME_OK;
}
/* check if sssr mempool is allocated */
if (dhd->sssr_mempool == NULL) {
DHD_ERROR(("%s: sssr_mempool is not allocated\n",
__FUNCTION__));
return BCME_ERROR;
}
/* check if sssr mempool is allocated */
if (dhd->sssr_reg_info == NULL) {
DHD_ERROR(("%s: sssr_reg_info is not allocated\n",
__FUNCTION__));
return BCME_ERROR;
}
/* Get SSSR reg info */
if (dhd_get_sssr_reg_info(dhd) != BCME_OK) {
if (fis_dump) {
int err = -1;
char *filepath_sssr = "/root/sssr_reginfo.dat";
err = dhd_read_file(filepath_sssr, (char*)(&dhd->sssr_reg_info->rev0),
sizeof(sssr_reg_info_v0_t));
switch (dhd->sssr_reg_info->rev2.version) {
case SSSR_REG_INFO_VER_6 :
err = dhd_read_file(filepath_sssr,
(char*)(&dhd->sssr_reg_info->rev6),
sizeof(sssr_reg_info_v6_t));
break;
case SSSR_REG_INFO_VER_5 :
err = dhd_read_file(filepath_sssr,
(char*)(&dhd->sssr_reg_info->rev5),
sizeof(sssr_reg_info_v5_t));
break;
case SSSR_REG_INFO_VER_4 :
err = dhd_read_file(filepath_sssr,
(char*)(&dhd->sssr_reg_info->rev4),
sizeof(sssr_reg_info_v4_t));
break;
case SSSR_REG_INFO_VER_3 :
err = dhd_read_file(filepath_sssr,
(char*)(&dhd->sssr_reg_info->rev3),
sizeof(sssr_reg_info_v3_t));
break;
case SSSR_REG_INFO_VER_2 :
err = dhd_read_file(filepath_sssr,
(char*)(&dhd->sssr_reg_info->rev2),
sizeof(sssr_reg_info_v2_t));
break;
case SSSR_REG_INFO_VER_1 :
err = dhd_read_file(filepath_sssr,
(char*)(&dhd->sssr_reg_info->rev1),
sizeof(sssr_reg_info_v1_t));
break;
}
if (err < 0) {
DHD_ERROR(("%s: dhd_get_sssr_reg_info failed and there"
" is no FIS cache\n", __FUNCTION__));
return BCME_ERROR;
} else {
DHD_INFO(("%s: dhd_get_sssr_reg_info succeeds"
"with FIS cache\n", __FUNCTION__));
}
} else {
DHD_ERROR(("%s: dhd_get_sssr_reg_info failed\n", __FUNCTION__));
DHD_CONS_ONLY(("DEBUG_SSSr: %s: dhd_get_sssr_reg_info failed\n",
__FUNCTION__));
return BCME_ERROR;
}
}
num_d11cores = dhd_d11_slices_num_get(dhd);
/* Validate structure version and length */
switch (dhd->sssr_reg_info->rev2.version) {
case SSSR_REG_INFO_VER_6 :
if (dhd->sssr_reg_info->rev6.length != sizeof(sssr_reg_info_v6_t)) {
DHD_ERROR(("%s: dhd->sssr_reg_info->rev6.length (%d : %d)"
"mismatch on rev6\n", __FUNCTION__,
(int)dhd->sssr_reg_info->rev6.length,
(int)sizeof(sssr_reg_info_v6_t)));
return BCME_ERROR;
}
break;
case SSSR_REG_INFO_VER_5 :
if ((dhd->sssr_reg_info->rev5.length != sizeof(sssr_reg_info_v5_t)) &&
(dhd->sssr_reg_info->rev5.length <
OFFSETOF(sssr_reg_info_v5_t, srcb_mem_info))) {
DHD_ERROR(("%s: dhd->sssr_reg_info->rev5.length (%d : %d)"
"mismatch on rev5\n", __FUNCTION__,
(int)dhd->sssr_reg_info->rev5.length,
(int)sizeof(sssr_reg_info_v5_t)));
return BCME_ERROR;
}
break;
case SSSR_REG_INFO_VER_4 :
if (dhd->sssr_reg_info->rev4.length != sizeof(sssr_reg_info_v4_t)) {
DHD_ERROR(("%s: dhd->sssr_reg_info->rev4.length (%d : %d)"
"mismatch on rev4\n", __FUNCTION__,
(int)dhd->sssr_reg_info->rev4.length,
(int)sizeof(sssr_reg_info_v4_t)));
return BCME_ERROR;
}
break;
case SSSR_REG_INFO_VER_3 :
if (dhd->sssr_reg_info->rev3.length != sizeof(sssr_reg_info_v3_t)) {
DHD_ERROR(("%s: dhd->sssr_reg_info->rev3.length (%d : %d)"
"mismatch on rev3\n", __FUNCTION__,
(int)dhd->sssr_reg_info->rev3.length,
(int)sizeof(sssr_reg_info_v3_t)));
return BCME_ERROR;
}
break;
case SSSR_REG_INFO_VER_2 :
if (dhd->sssr_reg_info->rev2.length != sizeof(sssr_reg_info_v2_t)) {
DHD_ERROR(("%s: dhd->sssr_reg_info->rev2.length (%d : %d)"
"mismatch on rev2\n", __FUNCTION__,
(int)dhd->sssr_reg_info->rev2.length,
(int)sizeof(sssr_reg_info_v2_t)));
return BCME_ERROR;
}
break;
case SSSR_REG_INFO_VER_1 :
if (dhd->sssr_reg_info->rev1.length != sizeof(sssr_reg_info_v1_t)) {
DHD_ERROR(("%s: dhd->sssr_reg_info->rev1.length (%d : %d)"
"mismatch on rev1\n", __FUNCTION__,
(int)dhd->sssr_reg_info->rev1.length,
(int)sizeof(sssr_reg_info_v1_t)));
return BCME_ERROR;
}
break;
case SSSR_REG_INFO_VER_0 :
if (dhd->sssr_reg_info->rev0.length != sizeof(sssr_reg_info_v0_t)) {
DHD_ERROR(("%s: dhd->sssr_reg_info->rev0.length (%d : %d)"
"mismatch on rev0\n", __FUNCTION__,
(int)dhd->sssr_reg_info->rev0.length,
(int)sizeof(sssr_reg_info_v0_t)));
return BCME_ERROR;
}
break;
default :
DHD_ERROR(("invalid sssr_reg_ver\n"));
return BCME_UNSUPPORTED;
}
/* validate fifo size */
sssr_bufsize = dhd_get_sssr_bufsize(dhd);
if (sssr_bufsize > DHD_SSSR_MEMPOOL_SIZE) {
DHD_ERROR(("%s: sssr_bufsize(%d) is greater than sssr_mempool(%d)\n",
__FUNCTION__, (int)sssr_bufsize, DHD_SSSR_MEMPOOL_SIZE));
return BCME_ERROR;
}
/* init all pointers to NULL */
for (i = 0; i < num_d11cores; i++) {
#ifdef DHD_SSSR_DUMP_BEFORE_SR
dhd->sssr_d11_before[i] = NULL;
#endif /* DHD_SSSR_DUMP_BEFORE_SR */
dhd->sssr_d11_after[i] = NULL;
}
#ifdef DHD_SSSR_DUMP_BEFORE_SR
dhd->sssr_dig_buf_before = NULL;
#endif /* DHD_SSSR_DUMP_BEFORE_SR */
dhd->sssr_dig_buf_after = NULL;
#ifdef DHD_SSSR_DUMP_BEFORE_SR
dhd->sssr_saqm_buf_before = NULL;
#endif /* DHD_SSSR_DUMP_BEFORE_SR */
dhd->sssr_saqm_buf_after = NULL;
dhd->sssr_srcb_buf_after = NULL;
dhd->sssr_cmn_buf_after = NULL;
/* Allocate memory */
for (i = 0; i < num_d11cores; i++) {
alloc_sssr = FALSE;
sr_size = 0;
switch (dhd->sssr_reg_info->rev2.version) {
case SSSR_REG_INFO_VER_6 :
/* intentional fall through */
case SSSR_REG_INFO_VER_5 :
if (dhd->sssr_reg_info->rev5.mac_regs[i].sr_size) {
alloc_sssr = TRUE;
sr_size = dhd->sssr_reg_info->rev5.mac_regs[i].sr_size;
sr_size += sizeof(sssr_header_t);
}
break;
case SSSR_REG_INFO_VER_4 :
if (dhd->sssr_reg_info->rev4.mac_regs[i].sr_size) {
alloc_sssr = TRUE;
sr_size = dhd->sssr_reg_info->rev4.mac_regs[i].sr_size;
}
break;
case SSSR_REG_INFO_VER_3 :
/* intentional fall through */
case SSSR_REG_INFO_VER_2 :
if (dhd->sssr_reg_info->rev2.mac_regs[i].sr_size) {
alloc_sssr = TRUE;
sr_size = dhd->sssr_reg_info->rev2.mac_regs[i].sr_size;
}
break;
case SSSR_REG_INFO_VER_1 :
if (dhd->sssr_reg_info->rev1.mac_regs[i].sr_size) {
alloc_sssr = TRUE;
sr_size = dhd->sssr_reg_info->rev1.mac_regs[i].sr_size;
}
break;
case SSSR_REG_INFO_VER_0 :
if (dhd->sssr_reg_info->rev0.mac_regs[i].sr_size) {
alloc_sssr = TRUE;
sr_size = dhd->sssr_reg_info->rev0.mac_regs[i].sr_size;
}
break;
default :
DHD_ERROR(("invalid sssr_reg_ver"));
return BCME_UNSUPPORTED;
}
if (alloc_sssr) {
#ifdef DHD_SSSR_DUMP_BEFORE_SR
dhd->sssr_d11_before[i] = (uint32 *)(dhd->sssr_mempool + mempool_used);
mempool_used += sr_size;
#endif /* DHD_SSSR_DUMP_BEFORE_SR */
dhd->sssr_d11_after[i] = (uint32 *)(dhd->sssr_mempool + mempool_used);
mempool_used += sr_size;
}
}
/* Allocate dump memory for VASIP (version 0 or 1) or digital core (version 0, 1, or 2) */
alloc_sssr = FALSE;
sr_size = 0;
switch (dhd->sssr_reg_info->rev2.version) {
case SSSR_REG_INFO_VER_6 :
if ((dhd->sssr_reg_info->rev6.length >
OFFSETOF(sssr_reg_info_v6_t, sssr_all_mem_info)) &&
dhd->sssr_reg_info->rev6.sssr_all_mem_info.sysmem_sssr_addr) {
alloc_sssr = TRUE;
sr_size =
dhd->sssr_reg_info->rev6.sssr_all_mem_info.sysmem_sssr_size;
sr_size += sizeof(sssr_header_t);
}
break;
case SSSR_REG_INFO_VER_5 :
if ((dhd->sssr_reg_info->rev5.length >
OFFSETOF(sssr_reg_info_v5_t, sssr_all_mem_info)) &&
dhd->sssr_reg_info->rev5.sssr_all_mem_info.sysmem_sssr_addr) {
alloc_sssr = TRUE;
sr_size =
dhd->sssr_reg_info->rev5.sssr_all_mem_info.sysmem_sssr_size;
sr_size += sizeof(sssr_header_t);
}
break;
case SSSR_REG_INFO_VER_4 :
/* for v4 need to use sssr_all_mem_info instead of dig_mem_info */
if ((dhd->sssr_reg_info->rev4.length >
OFFSETOF(sssr_reg_info_v4_t, sssr_all_mem_info)) &&
dhd->sssr_reg_info->rev4.sssr_all_mem_info.sysmem_sssr_addr) {
alloc_sssr = TRUE;
sr_size =
dhd->sssr_reg_info->rev4.sssr_all_mem_info.sysmem_sssr_size;
}
break;
case SSSR_REG_INFO_VER_3 :
/* intentional fall through */
case SSSR_REG_INFO_VER_2 :
if ((dhd->sssr_reg_info->rev2.length >
OFFSETOF(sssr_reg_info_v2_t, dig_mem_info)) &&
dhd->sssr_reg_info->rev2.dig_mem_info.dig_sr_addr) {
alloc_sssr = TRUE;
sr_size = dhd->sssr_reg_info->rev2.dig_mem_info.dig_sr_size;
}
break;
case SSSR_REG_INFO_VER_1 :
if (dhd->sssr_reg_info->rev1.vasip_regs.vasip_sr_size) {
alloc_sssr = TRUE;
sr_size = dhd->sssr_reg_info->rev1.vasip_regs.vasip_sr_size;
} else if ((dhd->sssr_reg_info->rev1.length > OFFSETOF(sssr_reg_info_v1_t,
dig_mem_info)) && dhd->sssr_reg_info->rev1.
dig_mem_info.dig_sr_addr) {
alloc_sssr = TRUE;
sr_size = dhd->sssr_reg_info->rev1.dig_mem_info.dig_sr_size;
}
break;
case SSSR_REG_INFO_VER_0 :
if (dhd->sssr_reg_info->rev0.vasip_regs.vasip_sr_size) {
alloc_sssr = TRUE;
sr_size = dhd->sssr_reg_info->rev0.vasip_regs.vasip_sr_size;
}
break;
default :
DHD_ERROR(("invalid sssr_reg_ver"));
return BCME_UNSUPPORTED;
}
if (alloc_sssr) {
dhd->sssr_dig_buf_after = (uint32 *)(dhd->sssr_mempool + mempool_used);
mempool_used += sr_size;
#ifdef DHD_SSSR_DUMP_BEFORE_SR
/* DIG dump before suspend is not applicable. */
dhd->sssr_dig_buf_before = (uint32 *)(dhd->sssr_mempool + mempool_used);
mempool_used += sr_size;
#endif /* DHD_SSSR_DUMP_BEFORE_SR */
}
/* Allocate dump memory for SAQM */
sr_size = 0;
supported_vers[0] = SSSR_REG_INFO_VER_5;
supported_vers[1] = SSSR_REG_INFO_VER_6;
supported_vers[2] = -1;
ret = dhd_sssr_chk_version_support(dhd->sssr_reg_info->rev2.version, supported_vers);
if (ret == BCME_ERROR) {
DHD_ERROR(("%s:invalid sssr_reg_ver (%d), during saqm mem init\n", __FUNCTION__,
dhd->sssr_reg_info->rev2.version));
return BCME_UNSUPPORTED;
} else if (ret == BCME_OK &&
dhd->sssr_reg_info->rev5.saqm_sssr_info.saqm_sssr_size > 0) {
dhd->sssr_saqm_buf_after = (uint32 *)(dhd->sssr_mempool + mempool_used);
sr_size =
dhd->sssr_reg_info->rev5.saqm_sssr_info.saqm_sssr_size;
mempool_used += sr_size;
DHD_PRINT(("%s: saqm mem init size=%u\n", __func__, sr_size));
#ifdef DHD_SSSR_DUMP_BEFORE_SR
/* DIG dump before suspend is not applicable. */
dhd->sssr_saqm_buf_before = (uint32 *)(dhd->sssr_mempool + mempool_used);
mempool_used += sr_size;
#endif /* DHD_SSSR_DUMP_BEFORE_SR */
}
/* Allocate dump memory for SRCB */
sr_size = 0;
supported_vers[0] = SSSR_REG_INFO_VER_6;
supported_vers[1] = -1;
ret = dhd_sssr_chk_version_support(dhd->sssr_reg_info->rev2.version, supported_vers);
if (ret == BCME_ERROR) {
DHD_ERROR(("%s: sssr_reg_ver (%d) does not suppport SRCB FIS dump,"
" during srcb mem init\n", __FUNCTION__,
dhd->sssr_reg_info->rev2.version));
} else if (ret == BCME_OK &&
dhd->sssr_reg_info->rev6.srcb_mem_info.srcb_sssr_size > 0) {
dhd->sssr_srcb_buf_after = (uint32 *)(dhd->sssr_mempool + mempool_used);
sr_size =
dhd->sssr_reg_info->rev6.srcb_mem_info.srcb_sssr_size;
mempool_used += sr_size;
DHD_PRINT(("%s: srcb mem init size=%u\n", __func__, sr_size));
}
/* Allocate dump memory for CMN */
sr_size = 0;
supported_vers[0] = SSSR_REG_INFO_VER_5;
supported_vers[1] = SSSR_REG_INFO_VER_6;
supported_vers[2] = -1;
ret = dhd_sssr_chk_version_support(dhd->sssr_reg_info->rev2.version, supported_vers);
if (ret == BCME_ERROR) {
DHD_ERROR(("%s: sssr_reg_ver (%d) does not support cmn FIS dump,"
" during cmn mem init\n", __FUNCTION__,
dhd->sssr_reg_info->rev2.version));
} else if (ret == BCME_OK &&
dhd->sssr_reg_info->rev5.fis_mem_info.fis_size > 0) {
dhd->sssr_cmn_buf_after = (uint32 *)(dhd->sssr_mempool + mempool_used);
sr_size =
dhd->sssr_reg_info->rev5.fis_mem_info.fis_size;
mempool_used += sr_size;
DHD_PRINT(("%s: cmn mem init size=%u\n", __func__, sr_size));
}
dhd->sssr_inited = TRUE;
DHD_PRINT(("%s mempool_used:%d size:%d\n",
__FUNCTION__, mempool_used, DHD_SSSR_MEMPOOL_SIZE));
ASSERT(mempool_used <= DHD_SSSR_MEMPOOL_SIZE);
return BCME_OK;
}
void
dhd_sssr_dump_deinit(dhd_pub_t *dhd)
{
int i;
dhd->sssr_inited = FALSE;
/* init all pointers to NULL */
for (i = 0; i < MAX_NUM_D11_CORES_WITH_SCAN; i++) {
#ifdef DHD_SSSR_DUMP_BEFORE_SR
dhd->sssr_d11_before[i] = NULL;
#endif /* DHD_SSSR_DUMP_BEFORE_SR */
dhd->sssr_d11_after[i] = NULL;
}
#ifdef DHD_SSSR_DUMP_BEFORE_SR
dhd->sssr_dig_buf_before = NULL;
#endif /* DHD_SSSR_DUMP_BEFORE_SR */
dhd->sssr_dig_buf_after = NULL;
return;
}
void
dhd_sssr_print_filepath(dhd_pub_t *dhd, char *path)
{
bool print_info = FALSE;
int dump_mode;
if (!dhd || !path) {
DHD_ERROR(("%s: dhd or memdump_path is NULL\n",
__FUNCTION__));
return;
}
if (!dhd->sssr_dump_collected) {
/* SSSR dump is not collected */
return;
}
dump_mode = dhd->sssr_dump_mode;
if (bcmstrstr(path, "core_0_before")) {
if (dhd->sssr_d11_outofreset[0] &&
dump_mode == SSSR_DUMP_MODE_SSSR) {
print_info = TRUE;
}
} else if (bcmstrstr(path, "core_0_after")) {
if (dhd->sssr_d11_outofreset[0]) {
print_info = TRUE;
}
} else if (bcmstrstr(path, "core_1_before")) {
if (dhd->sssr_d11_outofreset[1] &&
dump_mode == SSSR_DUMP_MODE_SSSR) {
print_info = TRUE;
}
} else if (bcmstrstr(path, "core_1_after")) {
if (dhd->sssr_d11_outofreset[1]) {
print_info = TRUE;
}
} else if (bcmstrstr(path, "core_2_before")) {
if (dhd->sssr_d11_outofreset[2] &&
dump_mode == SSSR_DUMP_MODE_SSSR) {
print_info = TRUE;
}
} else if (bcmstrstr(path, "core_2_after")) {
if (dhd->sssr_d11_outofreset[2]) {
print_info = TRUE;
}
} else {
print_info = TRUE;
}
if (print_info) {
DHD_ERROR(("%s: file_path = %s%s\n", __FUNCTION__,
path, FILE_NAME_HAL_TAG));
}
}
#ifdef DHD_COREDUMP
int dhd_append_sssr_tlv(uint8 *buf_dst, int type_idx, int buf_remain)
{
uint32 type_val, length_val;
uint32 *type, *length;
void *buf_src;
int total_size = 0, ret = 0;
/* DHD_COREDUMP_TYPE_SSSRDUMP_[CORE[0|1|2]|DIG]_[BEFORE|AFTER] */
type_val = dhd_coredump_types[type_idx].type;
length_val = dhd_coredump_types[type_idx].length;
if (length_val == 0) {
return 0;
}
type = (uint32*)buf_dst;
*type = type_val;
length = (uint32*)(buf_dst + sizeof(*type));
*length = length_val;
buf_dst += TLV_TYPE_LENGTH_SIZE;
total_size += TLV_TYPE_LENGTH_SIZE;
buf_src = dhd_coredump_types[type_idx].bufptr;
ret = memcpy_s(buf_dst, buf_remain, buf_src, *length);
if (ret) {
DHD_ERROR(("Failed to memcpy_s() for coredump.\n"));
return BCME_ERROR;
}
DHD_INFO(("%s: type: %u, length: %u\n", __FUNCTION__, *type, *length));
total_size += *length;
return total_size;
}
#endif /* DHD_COREDUMP */
uint
dhd_sssr_dig_buf_size(dhd_pub_t *dhdp)
{
uint dig_buf_size = 0;
/* SSSR register information structure v0 and v1 shares most except dig_mem */
switch (dhdp->sssr_reg_info->rev2.version) {
case SSSR_REG_INFO_VER_6:
if ((dhdp->sssr_reg_info->rev6.length >
OFFSETOF(sssr_reg_info_v6_t, sssr_all_mem_info)) &&
dhdp->sssr_reg_info->rev6.sssr_all_mem_info.sysmem_sssr_size) {
dig_buf_size =
dhdp->sssr_reg_info->rev6.sssr_all_mem_info.sysmem_sssr_size;
}
break;
case SSSR_REG_INFO_VER_5:
if ((dhdp->sssr_reg_info->rev5.length >
OFFSETOF(sssr_reg_info_v5_t, sssr_all_mem_info)) &&
dhdp->sssr_reg_info->rev5.sssr_all_mem_info.sysmem_sssr_size) {
dig_buf_size =
dhdp->sssr_reg_info->rev5.sssr_all_mem_info.sysmem_sssr_size;
}
break;
case SSSR_REG_INFO_VER_4:
/* for v4 need to use sssr_all_mem_info instead of dig_mem_info */
if ((dhdp->sssr_reg_info->rev4.length >
OFFSETOF(sssr_reg_info_v4_t, sssr_all_mem_info)) &&
dhdp->sssr_reg_info->rev4.sssr_all_mem_info.sysmem_sssr_size) {
dig_buf_size =
dhdp->sssr_reg_info->rev4.sssr_all_mem_info.sysmem_sssr_size;
}
break;
case SSSR_REG_INFO_VER_3:
/* intentional fall through */
case SSSR_REG_INFO_VER_2 :
if ((dhdp->sssr_reg_info->rev2.length >
OFFSETOF(sssr_reg_info_v2_t, dig_mem_info)) &&
dhdp->sssr_reg_info->rev2.dig_mem_info.dig_sr_size) {
dig_buf_size = dhdp->sssr_reg_info->rev2.dig_mem_info.dig_sr_size;
}
break;
case SSSR_REG_INFO_VER_1 :
if (dhdp->sssr_reg_info->rev1.vasip_regs.vasip_sr_size) {
dig_buf_size = dhdp->sssr_reg_info->rev1.vasip_regs.vasip_sr_size;
} else if ((dhdp->sssr_reg_info->rev1.length >
OFFSETOF(sssr_reg_info_v1_t, dig_mem_info)) &&
dhdp->sssr_reg_info->rev1.dig_mem_info.dig_sr_size) {
dig_buf_size = dhdp->sssr_reg_info->rev1.dig_mem_info.dig_sr_size;
}
break;
case SSSR_REG_INFO_VER_0 :
if (dhdp->sssr_reg_info->rev0.vasip_regs.vasip_sr_size) {
dig_buf_size = dhdp->sssr_reg_info->rev0.vasip_regs.vasip_sr_size;
}
break;
default :
DHD_ERROR(("invalid sssr_reg_ver"));
return BCME_UNSUPPORTED;
}
return dig_buf_size;
}
uint
dhd_sssr_dig_buf_addr(dhd_pub_t *dhdp)
{
uint dig_buf_addr = 0;
/* SSSR register information structure v0 and v1 shares most except dig_mem */
switch (dhdp->sssr_reg_info->rev2.version) {
case SSSR_REG_INFO_VER_6 :
if ((dhdp->sssr_reg_info->rev6.length >
OFFSETOF(sssr_reg_info_v6_t, sssr_all_mem_info)) &&
dhdp->sssr_reg_info->rev6.sssr_all_mem_info.sysmem_sssr_size) {
dig_buf_addr =
dhdp->sssr_reg_info->rev6.sssr_all_mem_info.sysmem_sssr_addr;
}
break;
case SSSR_REG_INFO_VER_5 :
if ((dhdp->sssr_reg_info->rev5.length >
OFFSETOF(sssr_reg_info_v5_t, sssr_all_mem_info)) &&
dhdp->sssr_reg_info->rev5.sssr_all_mem_info.sysmem_sssr_size) {
dig_buf_addr =
dhdp->sssr_reg_info->rev5.sssr_all_mem_info.sysmem_sssr_addr;
}
break;
case SSSR_REG_INFO_VER_4 :
/* for v4 need to use sssr_all_mem_info instead of dig_mem_info */
if ((dhdp->sssr_reg_info->rev4.length >
OFFSETOF(sssr_reg_info_v4_t, sssr_all_mem_info)) &&
dhdp->sssr_reg_info->rev4.sssr_all_mem_info.sysmem_sssr_size) {
dig_buf_addr =
dhdp->sssr_reg_info->rev4.sssr_all_mem_info.sysmem_sssr_addr;
}
break;
case SSSR_REG_INFO_VER_3 :
/* intentional fall through */
case SSSR_REG_INFO_VER_2 :
if ((dhdp->sssr_reg_info->rev2.length >
OFFSETOF(sssr_reg_info_v2_t, dig_mem_info)) &&
dhdp->sssr_reg_info->rev2.dig_mem_info.dig_sr_size) {
dig_buf_addr = dhdp->sssr_reg_info->rev2.dig_mem_info.dig_sr_addr;
}
break;
case SSSR_REG_INFO_VER_1 :
if (dhdp->sssr_reg_info->rev1.vasip_regs.vasip_sr_size) {
dig_buf_addr = dhdp->sssr_reg_info->rev1.vasip_regs.vasip_sr_addr;
} else if ((dhdp->sssr_reg_info->rev1.length >
OFFSETOF(sssr_reg_info_v1_t, dig_mem_info)) &&
dhdp->sssr_reg_info->rev1.dig_mem_info.dig_sr_size) {
dig_buf_addr = dhdp->sssr_reg_info->rev1.dig_mem_info.dig_sr_addr;
}
break;
case SSSR_REG_INFO_VER_0 :
if (dhdp->sssr_reg_info->rev0.vasip_regs.vasip_sr_size) {
dig_buf_addr = dhdp->sssr_reg_info->rev0.vasip_regs.vasip_sr_addr;
}
break;
default :
DHD_ERROR(("invalid sssr_reg_ver"));
return BCME_UNSUPPORTED;
}
return dig_buf_addr;
}
uint
dhd_sssr_mac_buf_size(dhd_pub_t *dhdp, uint8 core_idx)
{
uint mac_buf_size = 0;
uint8 num_d11cores;
num_d11cores = dhd_d11_slices_num_get(dhdp);
/* SSSR register information structure v0 and v1 shares most except dig_mem */
if (core_idx < num_d11cores) {
switch (dhdp->sssr_reg_info->rev2.version) {
case SSSR_REG_INFO_VER_6 :
case SSSR_REG_INFO_VER_5 :
mac_buf_size = dhdp->sssr_reg_info->rev5.mac_regs[core_idx].sr_size;
break;
case SSSR_REG_INFO_VER_4 :
mac_buf_size = dhdp->sssr_reg_info->rev4.mac_regs[core_idx].sr_size;
break;
case SSSR_REG_INFO_VER_3 :
/* intentional fall through */
case SSSR_REG_INFO_VER_2 :
mac_buf_size = dhdp->sssr_reg_info->rev2.mac_regs[core_idx].sr_size;
break;
case SSSR_REG_INFO_VER_1 :
mac_buf_size = dhdp->sssr_reg_info->rev1.mac_regs[core_idx].sr_size;
break;
case SSSR_REG_INFO_VER_0 :
mac_buf_size = dhdp->sssr_reg_info->rev0.mac_regs[core_idx].sr_size;
break;
default :
DHD_ERROR(("invalid sssr_reg_ver"));
return BCME_UNSUPPORTED;
}
}
return mac_buf_size;
}
uint
dhd_sssr_mac_xmtaddress(dhd_pub_t *dhdp, uint8 core_idx)
{
uint xmtaddress = 0;
uint8 num_d11cores;
num_d11cores = dhd_d11_slices_num_get(dhdp);
/* SSSR register information structure v0 and v1 shares most except dig_mem */
if (core_idx < num_d11cores) {
switch (dhdp->sssr_reg_info->rev2.version) {
case SSSR_REG_INFO_VER_6 :
case SSSR_REG_INFO_VER_5 :
xmtaddress = dhdp->sssr_reg_info->rev5.
mac_regs[core_idx].base_regs.xmtaddress;
break;
case SSSR_REG_INFO_VER_4 :
xmtaddress = dhdp->sssr_reg_info->rev4.
mac_regs[core_idx].base_regs.xmtaddress;
break;
case SSSR_REG_INFO_VER_3 :
/* intentional fall through */
case SSSR_REG_INFO_VER_2 :
xmtaddress = dhdp->sssr_reg_info->rev2.
mac_regs[core_idx].base_regs.xmtaddress;
break;
case SSSR_REG_INFO_VER_1 :
xmtaddress = dhdp->sssr_reg_info->rev1.
mac_regs[core_idx].base_regs.xmtaddress;
break;
case SSSR_REG_INFO_VER_0 :
xmtaddress = dhdp->sssr_reg_info->rev0.
mac_regs[core_idx].base_regs.xmtaddress;
break;
default :
DHD_ERROR(("invalid sssr_reg_ver"));
return BCME_UNSUPPORTED;
}
}
return xmtaddress;
}
uint
dhd_sssr_mac_xmtdata(dhd_pub_t *dhdp, uint8 core_idx)
{
uint xmtdata = 0;
uint8 num_d11cores;
num_d11cores = dhd_d11_slices_num_get(dhdp);
/* SSSR register information structure v0 and v1 shares most except dig_mem */
if (core_idx < num_d11cores) {
switch (dhdp->sssr_reg_info->rev2.version) {
case SSSR_REG_INFO_VER_6 :
case SSSR_REG_INFO_VER_5 :
xmtdata = dhdp->sssr_reg_info->rev5.
mac_regs[core_idx].base_regs.xmtdata;
break;
case SSSR_REG_INFO_VER_4 :
xmtdata = dhdp->sssr_reg_info->rev4.
mac_regs[core_idx].base_regs.xmtdata;
break;
case SSSR_REG_INFO_VER_3 :
/* intentional fall through */
case SSSR_REG_INFO_VER_2 :
xmtdata = dhdp->sssr_reg_info->rev2.
mac_regs[core_idx].base_regs.xmtdata;
break;
case SSSR_REG_INFO_VER_1 :
xmtdata = dhdp->sssr_reg_info->rev1.
mac_regs[core_idx].base_regs.xmtdata;
break;
case SSSR_REG_INFO_VER_0 :
xmtdata = dhdp->sssr_reg_info->rev0.
mac_regs[core_idx].base_regs.xmtdata;
break;
default :
DHD_ERROR(("invalid sssr_reg_ver"));
return BCME_UNSUPPORTED;
}
}
return xmtdata;
}
int
dhd_sssr_sr_asm_version(dhd_pub_t *dhdp, uint16 *sr_asm_version)
{
int supported_vers[SSSR_REG_INFO_VER_MAX] = {0};
int ret = 0;
supported_vers[0] = SSSR_REG_INFO_VER_5;
supported_vers[1] = SSSR_REG_INFO_VER_6;
supported_vers[2] = -1;
ret = dhd_sssr_chk_version_support(dhdp->sssr_reg_info->rev2.version, supported_vers);
if (ret == BCME_ERROR) {
DHD_ERROR(("%s:invalid sssr_reg_ver (%d)\n", __FUNCTION__,
dhdp->sssr_reg_info->rev2.version));
return BCME_UNSUPPORTED;
} else if (ret == BCME_OK) {
*sr_asm_version = dhdp->sssr_reg_info->rev5.sr_asm_version;
}
return BCME_OK;
}
int
dhd_sssr_mac_war_reg(dhd_pub_t *dhdp, uint8 core_idx, uint32 *war_reg)
{
uint8 num_d11cores;
int supported_vers[SSSR_REG_INFO_VER_MAX] = {0};
int ret = 0;
num_d11cores = dhd_d11_slices_num_get(dhdp);
supported_vers[0] = SSSR_REG_INFO_VER_5;
supported_vers[1] = SSSR_REG_INFO_VER_6;
supported_vers[2] = -1;
if (core_idx < num_d11cores) {
ret = dhd_sssr_chk_version_support(dhdp->sssr_reg_info->rev2.version,
supported_vers);
if (ret == BCME_ERROR) {
DHD_ERROR(("%s:invalid sssr_reg_ver (%d)\n", __FUNCTION__,
dhdp->sssr_reg_info->rev2.version));
return BCME_UNSUPPORTED;
} else if (ret == BCME_OK) {
*war_reg = dhdp->sssr_reg_info->rev5.mac_regs[core_idx].war_reg;
}
}
return BCME_OK;
}
int
dhd_sssr_arm_war_reg(dhd_pub_t *dhdp, uint32 *war_reg)
{
int supported_vers[SSSR_REG_INFO_VER_MAX] = {0};
int ret = 0;
supported_vers[0] = SSSR_REG_INFO_VER_5;
supported_vers[1] = SSSR_REG_INFO_VER_6;
supported_vers[2] = -1;
ret = dhd_sssr_chk_version_support(dhdp->sssr_reg_info->rev2.version, supported_vers);
if (ret == BCME_ERROR) {
DHD_ERROR(("%s:invalid sssr_reg_ver (%d)\n", __FUNCTION__,
dhdp->sssr_reg_info->rev2.version));
return BCME_UNSUPPORTED;
} else if (ret == BCME_OK) {
*war_reg = dhdp->sssr_reg_info->rev5.arm_regs.war_reg;
}
return BCME_OK;
}
int
dhd_sssr_saqm_war_reg(dhd_pub_t *dhdp, uint32 *war_reg)
{
int supported_vers[SSSR_REG_INFO_VER_MAX] = {0};
int ret = 0;
supported_vers[0] = SSSR_REG_INFO_VER_5;
supported_vers[1] = SSSR_REG_INFO_VER_6;
supported_vers[2] = -1;
ret = dhd_sssr_chk_version_support(dhdp->sssr_reg_info->rev2.version, supported_vers);
if (ret == BCME_ERROR) {
DHD_ERROR(("%s:invalid sssr_reg_ver (%d)\n", __FUNCTION__,
dhdp->sssr_reg_info->rev2.version));
return BCME_UNSUPPORTED;
} else if (ret == BCME_OK) {
*war_reg = dhdp->sssr_reg_info->rev5.saqm_sssr_info.war_reg;
}
return BCME_OK;
}
int
dhd_sssr_srcb_war_reg(dhd_pub_t *dhdp, uint32 *war_reg)
{
int supported_vers[SSSR_REG_INFO_VER_MAX] = {0};
int ret = 0;
supported_vers[0] = SSSR_REG_INFO_VER_6;
supported_vers[1] = -1;
ret = dhd_sssr_chk_version_support(dhdp->sssr_reg_info->rev2.version, supported_vers);
if (ret == BCME_ERROR) {
DHD_ERROR(("%s:invalid sssr_reg_ver (%d)\n", __FUNCTION__,
dhdp->sssr_reg_info->rev2.version));
return BCME_UNSUPPORTED;
} else if (ret == BCME_OK) {
if (dhdp->sssr_reg_info->rev6.srcb_mem_info.srcb_sssr_size > 0) {
*war_reg = dhdp->sssr_reg_info->rev6.srcb_mem_info.war_reg;
}
}
return BCME_OK;
}
uint
dhd_sssr_saqm_buf_size(dhd_pub_t *dhdp)
{
uint saqm_buf_size = 0;
int supported_vers[SSSR_REG_INFO_VER_MAX] = {0};
int ret = 0;
supported_vers[0] = SSSR_REG_INFO_VER_5;
supported_vers[1] = SSSR_REG_INFO_VER_6;
supported_vers[2] = -1;
ret = dhd_sssr_chk_version_support(dhdp->sssr_reg_info->rev2.version, supported_vers);
if (ret == BCME_ERROR) {
DHD_ERROR(("%s:invalid sssr_reg_ver (%d)\n", __FUNCTION__,
dhdp->sssr_reg_info->rev2.version));
return 0;
} else if (ret == BCME_OK) {
if (dhdp->sssr_reg_info->rev5.saqm_sssr_info.saqm_sssr_size > 0) {
saqm_buf_size =
dhdp->sssr_reg_info->rev5.saqm_sssr_info.saqm_sssr_size;
}
}
return saqm_buf_size;
}
uint
dhd_sssr_saqm_buf_addr(dhd_pub_t *dhdp)
{
uint saqm_buf_addr = 0;
int supported_vers[SSSR_REG_INFO_VER_MAX] = {0};
int ret = 0;
supported_vers[0] = SSSR_REG_INFO_VER_5;
supported_vers[1] = SSSR_REG_INFO_VER_6;
supported_vers[2] = -1;
ret = dhd_sssr_chk_version_support(dhdp->sssr_reg_info->rev2.version, supported_vers);
if (ret == BCME_ERROR) {
DHD_ERROR(("%s:invalid sssr_reg_ver (%d)\n", __FUNCTION__,
dhdp->sssr_reg_info->rev2.version));
return 0;
} else if (ret == BCME_OK) {
if (dhdp->sssr_reg_info->rev5.saqm_sssr_info.saqm_sssr_size > 0) {
saqm_buf_addr =
dhdp->sssr_reg_info->rev5.saqm_sssr_info.saqm_sssr_addr;
}
}
return saqm_buf_addr;
}
uint
dhd_sssr_srcb_buf_size(dhd_pub_t *dhdp)
{
uint srcb_buf_size = 0;
int supported_vers[SSSR_REG_INFO_VER_MAX] = {0};
int ret = 0;
supported_vers[0] = SSSR_REG_INFO_VER_6;
supported_vers[1] = -1;
ret = dhd_sssr_chk_version_support(dhdp->sssr_reg_info->rev2.version, supported_vers);
if (ret == BCME_ERROR) {
DHD_ERROR(("%s:sssr_reg_ver (%d) does not support SRCB FIS dump\n", __FUNCTION__,
dhdp->sssr_reg_info->rev2.version));
return 0;
} else if (ret == BCME_OK) {
if (dhdp->sssr_reg_info->rev6.srcb_mem_info.srcb_sssr_size > 0) {
srcb_buf_size =
dhdp->sssr_reg_info->rev6.srcb_mem_info.srcb_sssr_size;
}
}
return srcb_buf_size;
}
uint
dhd_sssr_srcb_buf_addr(dhd_pub_t *dhdp)
{
uint srcb_buf_addr = 0;
int supported_vers[SSSR_REG_INFO_VER_MAX] = {0};
int ret = 0;
supported_vers[0] = SSSR_REG_INFO_VER_6;
supported_vers[1] = -1;
ret = dhd_sssr_chk_version_support(dhdp->sssr_reg_info->rev2.version, supported_vers);
if (ret == BCME_ERROR) {
DHD_ERROR(("%s: sssr_reg_ver (%d) does not support SRCB FIS \n", __FUNCTION__,
dhdp->sssr_reg_info->rev2.version));
return 0;
} else if (ret == BCME_OK) {
if (dhdp->sssr_reg_info->rev6.srcb_mem_info.srcb_sssr_size > 0) {
srcb_buf_addr =
dhdp->sssr_reg_info->rev6.srcb_mem_info.srcb_sssr_addr;
}
}
return srcb_buf_addr;
}
uint
dhd_sssr_cmn_buf_size(dhd_pub_t *dhdp)
{
uint cmn_buf_size = 0;
int supported_vers[SSSR_REG_INFO_VER_MAX] = {0};
int ret = 0;
supported_vers[0] = SSSR_REG_INFO_VER_5;
supported_vers[1] = SSSR_REG_INFO_VER_6;
supported_vers[2] = -1;
ret = dhd_sssr_chk_version_support(dhdp->sssr_reg_info->rev2.version, supported_vers);
if (ret == BCME_ERROR) {
DHD_ERROR(("%s:invalid sssr_reg_ver (%d)\n", __FUNCTION__,
dhdp->sssr_reg_info->rev2.version));
return 0;
} else if (ret == BCME_OK) {
if (dhdp->sssr_reg_info->rev5.fis_mem_info.fis_size > 0 &&
dhdp->sssr_reg_info->rev5.fis_mem_info.fis_size != (uint32)-1) {
cmn_buf_size =
dhdp->sssr_reg_info->rev5.fis_mem_info.fis_size;
} else {
DHD_ERROR(("%s:invalid cmn buf size %u !\n", __FUNCTION__,
dhdp->sssr_reg_info->rev5.fis_mem_info.fis_size));
}
}
return cmn_buf_size;
}
uint
dhd_sssr_cmn_buf_addr(dhd_pub_t *dhdp)
{
uint cmn_buf_addr = 0;
int supported_vers[SSSR_REG_INFO_VER_MAX] = {0};
int ret = 0;
supported_vers[0] = SSSR_REG_INFO_VER_5;
supported_vers[1] = SSSR_REG_INFO_VER_6;
supported_vers[2] = -1;
ret = dhd_sssr_chk_version_support(dhdp->sssr_reg_info->rev2.version, supported_vers);
if (ret == BCME_ERROR) {
DHD_ERROR(("%s:invalid sssr_reg_ver (%d)\n", __FUNCTION__,
dhdp->sssr_reg_info->rev2.version));
return 0;
} else if (ret == BCME_OK) {
if (dhdp->sssr_reg_info->rev5.fis_mem_info.fis_size > 0 &&
dhdp->sssr_reg_info->rev5.fis_mem_info.fis_addr &&
dhdp->sssr_reg_info->rev5.fis_mem_info.fis_addr != (uint32)-1) {
cmn_buf_addr =
dhdp->sssr_reg_info->rev5.fis_mem_info.fis_addr;
} else {
DHD_ERROR(("%s:invalid cmn buf addr %x !\n", __FUNCTION__,
dhdp->sssr_reg_info->rev5.fis_mem_info.fis_addr));
}
}
return cmn_buf_addr;
}
#ifdef DHD_SSSR_DUMP_BEFORE_SR
int
dhd_sssr_dump_dig_buf_before(void *dhd_pub, const void *user_buf, uint32 len)
{
dhd_pub_t *dhdp = (dhd_pub_t *)dhd_pub;
int pos = 0, ret = BCME_ERROR;
uint dig_buf_size = 0;
dig_buf_size = dhd_sssr_dig_buf_size(dhdp);
if (dhdp->sssr_dig_buf_before && (dhdp->sssr_dump_mode == SSSR_DUMP_MODE_SSSR)) {
ret = dhd_export_debug_data((char *)dhdp->sssr_dig_buf_before,
NULL, user_buf, dig_buf_size, &pos);
}
return ret;
}
int
dhd_sssr_dump_d11_buf_before(void *dhd_pub, const void *user_buf, uint32 len, int core)
{
dhd_pub_t *dhdp = (dhd_pub_t *)dhd_pub;
int pos = 0, ret = BCME_ERROR;
if (dhdp->sssr_d11_before[core] &&
dhdp->sssr_d11_outofreset[core] &&
(dhdp->sssr_dump_mode == SSSR_DUMP_MODE_SSSR)) {
ret = dhd_export_debug_data((char *)dhdp->sssr_d11_before[core],
NULL, user_buf, len, &pos);
}
return ret;
}
#endif /* DHD_SSSR_DUMP_BEFORE_SR */
int
dhd_sssr_dump_dig_buf_after(void *dhd_pub, const void *user_buf, uint32 len)
{
dhd_pub_t *dhdp = (dhd_pub_t *)dhd_pub;
int pos = 0, ret = BCME_ERROR;
uint dig_buf_size = 0;
dig_buf_size = dhd_sssr_dig_buf_size(dhdp);
if (dhdp->sssr_dig_buf_after) {
ret = dhd_export_debug_data((char *)dhdp->sssr_dig_buf_after,
NULL, user_buf, dig_buf_size, &pos);
}
return ret;
}
int
dhd_sssr_dump_d11_buf_after(void *dhd_pub, const void *user_buf, uint32 len, int core)
{
dhd_pub_t *dhdp = (dhd_pub_t *)dhd_pub;
int pos = 0, ret = BCME_ERROR;
if (dhdp->sssr_d11_after[core] &&
dhdp->sssr_d11_outofreset[core]) {
ret = dhd_export_debug_data((char *)dhdp->sssr_d11_after[core],
NULL, user_buf, len, &pos);
}
return ret;
}
#if defined(DHD_DUMP_FILE_WRITE_FROM_KERNEL)
static void
dhd_sssr_dump_to_file(dhd_pub_t *dhdp)
{
int i;
#ifdef DHD_SSSR_DUMP_BEFORE_SR
char before_sr_dump[128];
#endif /* DHD_SSSR_DUMP_BEFORE_SR */
char after_sr_dump[128];
unsigned long flags = 0;
uint dig_buf_size = 0;
uint8 num_d11cores = 0;
uint d11_buf_size = 0;
uint saqm_buf_size = 0;
uint srcb_buf_size = 0;
uint cmn_buf_size = 0;
DHD_PRINT(("%s: ENTER \n", __FUNCTION__));
if (!dhdp) {
DHD_ERROR(("%s: dhdp is NULL\n", __FUNCTION__));
return;
}
DHD_GENERAL_LOCK(dhdp, flags);
DHD_BUS_BUSY_SET_IN_SSSRDUMP(dhdp);
if (DHD_BUS_CHECK_DOWN_OR_DOWN_IN_PROGRESS(dhdp)) {
DHD_GENERAL_UNLOCK(dhdp, flags);
DHD_ERROR(("%s: bus is down! can't collect sssr dump. \n", __FUNCTION__));
goto exit;
}
DHD_GENERAL_UNLOCK(dhdp, flags);
num_d11cores = dhd_d11_slices_num_get(dhdp);
for (i = 0; i < num_d11cores; i++) {
/* Init file name */
#ifdef DHD_SSSR_DUMP_BEFORE_SR
bzero(before_sr_dump, sizeof(before_sr_dump));
#endif /* DHD_SSSR_DUMP_BEFORE_SR */
bzero(after_sr_dump, sizeof(after_sr_dump));
#ifdef DHD_SSSR_DUMP_BEFORE_SR
snprintf(before_sr_dump, sizeof(before_sr_dump), "%s_%d_%s",
"sssr_dump_core", i, "before_SR");
#endif /* DHD_SSSR_DUMP_BEFORE_SR */
if (dhdp->sssr_dump_mode == SSSR_DUMP_MODE_FIS) {
snprintf(after_sr_dump, sizeof(after_sr_dump), "%s_%d_%s",
"sssr_dump_fis_core", i, "after_SR");
} else {
snprintf(after_sr_dump, sizeof(after_sr_dump), "%s_%d_%s",
"sssr_dump_core", i, "after_SR");
}
d11_buf_size = dhd_sssr_mac_buf_size(dhdp, i);
#ifdef DHD_SSSR_DUMP_BEFORE_SR
if (dhdp->sssr_d11_before[i] && dhdp->sssr_d11_outofreset[i] &&
(dhdp->sssr_dump_mode == SSSR_DUMP_MODE_SSSR)) {
if (write_dump_to_file(dhdp, (uint8 *)dhdp->sssr_d11_before[i],
d11_buf_size, before_sr_dump)) {
DHD_ERROR(("%s: writing SSSR MAIN dump before to the file failed\n",
__FUNCTION__));
}
}
#endif /* DHD_SSSR_DUMP_BEFORE_SR */
if (dhdp->sssr_d11_after[i] && dhdp->sssr_d11_outofreset[i]) {
if (write_dump_to_file(dhdp, (uint8 *)dhdp->sssr_d11_after[i],
d11_buf_size, after_sr_dump)) {
DHD_ERROR(("%s: writing SSSR AUX dump after to the file failed\n",
__FUNCTION__));
}
}
}
dig_buf_size = dhd_sssr_dig_buf_size(dhdp);
#ifdef DHD_SSSR_DUMP_BEFORE_SR
if (dhdp->sssr_dig_buf_before && (dhdp->sssr_dump_mode == SSSR_DUMP_MODE_SSSR)) {
if (write_dump_to_file(dhdp, (uint8 *)dhdp->sssr_dig_buf_before,
dig_buf_size, "sssr_dump_dig_before_SR")) {
DHD_ERROR(("%s: writing SSSR Dig dump before to the file failed\n",
__FUNCTION__));
}
}
#endif /* DHD_SSSR_DUMP_BEFORE_SR */
bzero(after_sr_dump, sizeof(after_sr_dump));
if (dhdp->sssr_dump_mode == SSSR_DUMP_MODE_FIS) {
snprintf(after_sr_dump, sizeof(after_sr_dump), "%s_%s",
"sssr_dump_fis_dig", "after_SR");
} else {
snprintf(after_sr_dump, sizeof(after_sr_dump), "%s_%s",
"sssr_dump_dig", "after_SR");
}
if (dhdp->sssr_dig_buf_after) {
if (write_dump_to_file(dhdp, (uint8 *)dhdp->sssr_dig_buf_after,
dig_buf_size, after_sr_dump)) {
DHD_ERROR(("%s: writing SSSR Dig VASIP dump after to the file failed\n",
__FUNCTION__));
}
}
saqm_buf_size = dhd_sssr_saqm_buf_size(dhdp);
#ifdef DHD_SSSR_DUMP_BEFORE_SR
if ((saqm_buf_size > 0) && dhdp->sssr_saqm_buf_before &&
(dhdp->sssr_dump_mode == SSSR_DUMP_MODE_SSSR)) {
if (write_dump_to_file(dhdp, (uint8 *)dhdp->sssr_saqm_buf_before,
saqm_buf_size, "sssr_dump_saqm_before_SR")) {
DHD_ERROR(("%s: writing SSSR SAQM dump before to the file failed\n",
__FUNCTION__));
}
}
#endif /* DHD_SSSR_DUMP_BEFORE_SR */
bzero(after_sr_dump, sizeof(after_sr_dump));
if (dhdp->sssr_dump_mode == SSSR_DUMP_MODE_FIS) {
snprintf(after_sr_dump, sizeof(after_sr_dump), "%s_%s",
"sssr_dump_fis_saqm", "after_SR");
} else {
snprintf(after_sr_dump, sizeof(after_sr_dump), "%s_%s",
"sssr_dump_saqm", "after_SR");
}
if ((saqm_buf_size > 0) && dhdp->sssr_saqm_buf_after) {
if (write_dump_to_file(dhdp, (uint8 *)dhdp->sssr_saqm_buf_after,
saqm_buf_size, after_sr_dump)) {
DHD_ERROR(("%s: writing SSSR SAQM dump after to the file failed\n",
__FUNCTION__));
}
}
if (dhdp->sssr_dump_mode == SSSR_DUMP_MODE_FIS) {
srcb_buf_size = dhd_sssr_srcb_buf_size(dhdp);
if ((srcb_buf_size > 0) && dhdp->sssr_srcb_buf_after) {
bzero(after_sr_dump, sizeof(after_sr_dump));
snprintf(after_sr_dump, sizeof(after_sr_dump), "%s_%s",
"sssr_dump_fis_srcb", "after_SR");
if (write_dump_to_file(dhdp, (uint8 *)dhdp->sssr_srcb_buf_after,
srcb_buf_size, after_sr_dump)) {
DHD_ERROR(("%s: writing FIS SRCB dump after to the file failed\n",
__FUNCTION__));
}
}
cmn_buf_size = dhd_sssr_cmn_buf_size(dhdp);
if ((cmn_buf_size > 0) && dhdp->sssr_cmn_buf_after) {
bzero(after_sr_dump, sizeof(after_sr_dump));
snprintf(after_sr_dump, sizeof(after_sr_dump), "%s_%s",
"sssr_dump_fis_cmn", "after_SR");
if (write_dump_to_file(dhdp, (uint8 *)dhdp->sssr_cmn_buf_after,
cmn_buf_size, after_sr_dump)) {
DHD_ERROR(("%s: writing FIS CMN dump after to the file failed\n",
__FUNCTION__));
}
}
}
exit:
DHD_GENERAL_LOCK(dhdp, flags);
DHD_BUS_BUSY_CLEAR_IN_SSSRDUMP(dhdp);
dhd_os_busbusy_wake(dhdp);
DHD_GENERAL_UNLOCK(dhdp, flags);
}
#endif /* DHD_DUMP_FILE_WRITE_FROM_KERNEL */
void
dhd_write_sssr_dump(dhd_pub_t *dhdp, uint32 dump_mode)
{
#if defined(DHD_DUMP_FILE_WRITE_FROM_KERNEL)
#endif
dhdp->sssr_dump_mode = dump_mode;
/*
* If kernel does not have file write access enabled
* then skip writing dumps to files.
* The dumps will be pushed to HAL layer which will
* write into files
*/
#if !defined(DHD_DUMP_FILE_WRITE_FROM_KERNEL)
return;
#else
/*
* dhd_mem_dump -> dhd_sssr_dump -> dhd_write_sssr_dump
* Without workqueue -
* DUMP_TYPE_DONGLE_INIT_FAILURE/DUMP_TYPE_DUE_TO_BT/DUMP_TYPE_SMMU_FAULT
* : These are called in own handler, not in the interrupt context
* With workqueue - all other DUMP_TYPEs : dhd_mem_dump is called in workqueue
* Thus, it doesn't neeed to dump SSSR in workqueue
*/
DHD_PRINT(("%s: writing sssr dump to file... \n", __FUNCTION__));
dhd_sssr_dump_to_file(dhdp);
#endif /* !DHD_DUMP_FILE_WRITE_FROM_KERNEL */
}
bool
dhd_is_fis_enabled(void)
{
return fis_enab;
}
#endif /* DHD_SSSR_DUMP */