pmcs_fwlog.c revision 2ac4abe882db38ef90020f7c5ca28586e3d57258
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*
*
* Copyright 2010 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/*
* This file contains firmware log routines.
*/
/*
* Dump internal registers. Used after a firmware crash.
* Here dump various registers for firmware forensics,
* including MPI, GSM configuration, firmware log, IO Queues etc.
*/
void
{
int n = 0;
"%s: register dump memory not allocated", __func__);
return;
}
}
__func__);
goto skip_logs;
}
"-----------------\n");
PMCIN_NVMD_AAP1, (j * PMCS_FLASH_CHUNK_SIZE),
if (n == PMCS_FLASH_CHUNK_SIZE) {
} else if ((n < PMCS_FLASH_CHUNK_SIZE) && (n > 0)) {
break;
} else if (n == 0) {
"register dump on flash is NULL\n");
break;
} else {
"AAP1: Unable to obtain internal register dump\n");
break;
}
}
"-----------------\n");
PMCIN_NVMD_IOP, (j * PMCS_FLASH_CHUNK_SIZE),
if (n == PMCS_FLASH_CHUNK_SIZE) {
} else if ((n < PMCS_FLASH_CHUNK_SIZE) && (n > 0)) {
break;
} else if (n == 0) {
"IOP: Content of internal register dump is NULL\n");
break;
} else {
"IOP: Unable to obtain internal register dump\n");
break;
}
}
"-----------------\n");
PMCIN_NVMD_AAP1, (j * PMCS_FLASH_CHUNK_SIZE),
if (n > 0) {
} else {
"AAP1: Unable to obtain event log on flash\n");
break;
}
}
"-----------------\n");
PMCIN_NVMD_IOP, (j * PMCS_FLASH_CHUNK_SIZE),
if (n > 0) {
} else {
"IOP: Unable to obtain event log dump\n");
break;
}
}
"-----------------\n");
"\n------------ Dump internal registers end -------------\n");
}
static int
{
int n = 0, retries = 0;
"not enabled\n");
return (n);
}
/*
* First, check to make sure all entries have been DMAed to the
* log buffer.
*
* We'll wait the required 50ms, but if the latest entry keeps
* changing, we'll only retry twice
*/
} else {
++retries;
"%s: event log is still being updated... waiting",
__func__);
}
}
return (n);
}
/*
* Dump Inbound and Outbound Queues.
*/
static int
{
uint8_t i = 0, k = 0;
int n = 0;
"-----------------\n");
for (i = 0; i < PMCS_NIQ; i++) {
"IQ[%d] Details:\n-----------------\n", i);
" depth = 0x%04x\n", depth);
for (j = 0; j < depth; j++) {
"IOMB[%d]:\n", j);
for (k = 0; k < (PMCS_QENTRY_SIZE / sizeof (uint32_t));
k += 8) {
"0x%08x 0x%08x 0x%08x 0x%08x "
"0x%08x 0x%08x 0x%08x 0x%08x\n",
}
}
}
for (i = 0; i < PMCS_NOQ; i++) {
"OQ[%d] Details:\n", i);
" depth = 0x%04x\n", depth);
for (j = 0; j < depth; j++) {
"IOMB[%d]:\n", j);
for (k = 0; k < (PMCS_QENTRY_SIZE / sizeof (uint32_t));
k += 8) {
"0x%08x 0x%08x 0x%08x 0x%08x "
"0x%08x 0x%08x 0x%08x 0x%08x\n",
}
}
}
"Dump I/O queues end \n");
return (n);
}
/*
* Dump SPC Version.
*/
static int
{
int n = 0;
"-----------------\n");
"Dump SPC version end \n");
return (n);
}
/*
* Dump MPI Table.
*/
static int
{
int n = 0;
"-----------------\n");
"-----------------\n");
"Elements = 0x%08x\n",
"connected to the SPC = 0x%08x\n",
"supported = 0x%08x\n",
"supported = 0x%08x\n",
"Priority Processing Depth = 0x%02x 0x%02x\n",
"Notification Queue = 0x%02x\n",
"Notification Queue - PHY ID %d = 0x%02x\n", i,
& 0xff);
}
"Event Notification Queue - PHY ID %d = 0x%02x\n", i,
& 0xff);
}
"Event Notification Queue - PHY ID %d = 0x%02x\n", i,
}
"Event Notification Queue - PHY ID %d = 0x%02x\n", i,
}
"Customization Setting = 0x%08x\n",
"Fatal Error Register Dump Offset "
"Fatal Error Register Dump Length "
"Fatal Error Register Dump Offset "
"Fatal Error Register Dump Length "
"-----------------\n");
}
"Information %d = 0x%08x\n", i,
}
"-----------------\n");
"Configuration Table - [%d]:\n", i);
"Depth = 0x%08x\n",
"Element Size and Priority = 0x%08x 0x%08x\n",
"Base Address High = 0x%08x\n",
"Base Address Low = 0x%08x\n",
"Consumer Index Base Address High = 0x%08x\n",
"Consumer Index Base Address Low = 0x%08x\n",
"Producer Index PCI BAR = 0x%08x\n",
"Producer Index PCI BAR offset = 0x%08x\n",
}
"-----------------\n");
"Configuration Table - [%d]:\n", i);
"Depth = 0x%08x\n",
"Element Size = 0x%08x\n",
"Base Address High = 0x%08x\n",
"Base Address Low = 0x%08x\n",
"Producer Index Base Address High = 0x%08x\n",
"Producer Index Base Address Low = 0x%08x\n",
"Consumer Index PCI BAR = 0x%08x\n",
"Consumer Index PCI BAR offset = 0x%08x\n",
"Interrupt Coalescing Timeout = 0x%08x\n",
"Interrupt Coalescing Count = 0x%08x\n",
"Interrupt Vector = 0x%08x\n",
"Dynamic Interrupt Coalescing Timeout = 0x%08x\n",
}
"Dump MPI Table end\n");
return (n);
}
/*ARGSUSED*/
int
{
uint32_t i;
int n = 0;
char c = ' ';
for (i = 0, n = 0; i < words_to_read; i++) {
if ((i & 7) == 0) {
}
if ((i + 1) & 7) {
c = ' ';
} else {
c = '\n';
}
}
return (n);
}
/*
* Dump Global Shared Memory Configuration Registers
*/
static int
{
int n = 0;
"registers: \n -----------------\n");
"READ ADR PARITY ERROR INDICATOR = 0x%08x\n",
"WRITE ADR PARITY ERROR INDICATOR = 0x%08x\n",
"WRITE DATA PARITY ERROR INDICATOR = 0x%08x\n",
"Dump GSM configuration registers end \n");
return (n);
}
/*
* Dump PCIe Configuration Registers.
*/
static int
{
int n = 0;
uint32_t i = 0;
"registers: \n -----------------\n");
"0x%08x\n",
"INTLINE = 0x%08x\n",
"MC MSI_NEXT_CAP MSI_CAP_ID = 0x%08x\n",
"PCIE_CAP PCIE_NEXT_CAP PCIE_CAP_ID = 0x%08x\n",
"DEVICE_STAT DEVICE_CTRL = 0x%08x\n",
"LINK_STAT LINK_CTRL = 0x%08x\n",
for (i = 0; i < 4; i++) {
(PMCS_PCI_HD_LOG_DW + i * 4)));
}
"Dump PCIe configuration registers end \n");
return (n);
}
/*
* Called with axil_lock held
*/
static boolean_t
{
drv_usecwait(10);
"AXIL register update failed");
return (B_FALSE);
}
return (B_TRUE);
}
static uint32_t
{
return (regval);
}
static void
{
drv_usecwait(10);
"AXIL register restore failed");
}
}
/*
* Dump Additional GSM Registers.
*/
static int
{
uint32_t i = 0;
int n = 0, j = 0, nums = 0;
"\n-----------------\n");
for (i = 0; i < sizeof (gsm_spregs) / sizeof (pmcs_sparse_regs_t);
i++) {
gsm_addr =
"[MEMBASE-III SHIFT = 0x%08X]\nOffset:\n",
}
if (nums == 0) {
} else if (nums > 0) {
gsm_spregs[i].offset_end);
j = 0;
while (nums > 0) {
j++;
nums -= 4;
}
}
}
"------------ Dump GSM Sparse Registers end ------------\n");
return (n);
}
/*
* Dump GSM Memory Regions.
*/
static int
{
int n = 0;
uint32_t i = 0;
"%s: local_buf memory not allocated", __func__);
return (0);
}
" -----------------\n");
for (i = 0; i < 4; i++) {
}
}
"Dump GSM IO Status Table end \n");
" -----------------\n");
for (i = 0; i < 2; i++) {
}
}
"Dump Ring Buffer Storage end \n");
" -----------------\n");
}
"Dump Ring Buffer Pointers end \n");
" -----------------\n");
}
"Dump Ring Buffer Access end \n");
" -----------------\n");
for (i = 0; i < 16; i++) {
}
}
"Dump GSM SM end \n");
"\n------------ Dump GSM Memory Regions end -------------\n");
if (local_buf) {
}
return (n);
}
/*
* Trace current Inbound Message host sent to SPC.
*/
void
{
uint32_t k = 0;
int n = 0;
"%s: trace buffer is not ready,"
" Inbound Message from host to SPC is not traced",
__func__);
return;
}
(PMCS_QENTRY_SIZE >> 2)];
for (k = 0; k < (PMCS_QENTRY_SIZE / sizeof (uint32_t));
k += 8) {
"0x%08x 0x%08x 0x%08x 0x%08x "
"0x%08x 0x%08x 0x%08x 0x%08x\n",
}
} else {
}
}
/*
* Capture HSST State Registers.
*/
static int
{
int n = 0;
"-----------------\n");
for (i = 0; i < 8; i++) {
hsst_state[i].shift_addr;
for (j = 0; j < 6; j++) {
addr));
addr));
}
}
return (n);
}
/*
* Capture SSPA State Registers.
*/
static int
{
int n = 0;
"-----------------\n");
for (i = 0; i < 8; i++) {
}
}
return (n);
}
/*
* Dump fatal error register content from GSM.
*/
int
{
int i = 0;
return (0);
}
switch (nvmd) {
case PMCIN_NVMD_AAP1:
break;
case PMCIN_NVMD_IOP:
break;
default:
return (0);
}
}
return (i);
}
/*
* Write out either the AAP1 or IOP event log
*/
static void
{
int error;
} else {
}
"%s: Could not create '%s', error %d", __func__,
return;
}
for (;;) {
if (error) {
"%s: could not write %s, error %d", __func__,
break;
}
"%s: Out of space in %s, error %d", __func__,
break;
}
if (resid == 0)
break;
}
if (!error) {
"%s: Error on close %s, error %d", __func__,
}
}
}
/*
* Check the in-memory event log. If it's filled up to or beyond the
* threshold, write it out to the configured filename.
*/
void
{
/*
* Get our copies of the latest indices
*/
/*
* We need entries in the log before we can know how big they are
*/
if ((pwp->fwlog_max_entries_aap1 == 0) &&
}
if ((pwp->fwlog_max_entries_iop == 0) &&
}
/*
* Check if we've reached the threshold in the AAP1 log. We do this
* by comparing the latest index with our copy of the oldest index
* (not the chip's).
*/
/* Log has not wrapped */
} else {
/* Log has wrapped */
}
/*
* Now check the IOP log
*/
/* Log has not wrapped */
} else {
/* Log has wrapped */
}
return;
}
/*
* We also can't write the event log out if it's too early in boot
* (i.e. the root fs isn't mounted yet).
*/
if (!modrootloaded) {
return;
}
/*
* Write out the necessary log file(s), update the "oldest" pointers
* and the suffix to the written filenames.
*/
} else {
}
}
} else {
}
}
}