/****************************************************************** * Utility function to retrieve full crash log from CP via simple * handshake protocol. * * ********************************************************************/ void DUMP_CP_assert_log(void) { UInt32 t1, i, size, retryCount; UInt8 *p; UInt32 packetCount = 0; void __iomem *AssertLogVAddr = NULL; struct file *sdDumpFile = NULL; int cpReset = SmLocalControl.SmControl->CrashCode == IPC_CP_SILENT_RESET_READY; /* put logging driver into crash dump mode; messages will be sent * straight out to MTT via RNDIS (or dump file) instead of buffering * in RING buffer (flood of crash dump info overloads ring buffer * otherwise,and we lose a lot of crash dump info) * NOTE: crash dump is put into SD by default; if SD file fails to open, * then we'll try sending it out RNDIS */ BCMLOG_StartCpCrashDump(sdDumpFile, cpReset); /* only grab RAM dump for CP reset case */ if (!cpReset) { retryCount = 0; while (1) { t1 = TIMER_GetValue(); /* signal to CP that we're ready to rx crash log... */ SmLocalControl.SmControl->CrashCode = IPC_AP_CLEAR_TO_SEND; /* wait for CP to "dump"; CrashCode field will be * set to physical address of current assert buf */ while (SmLocalControl.SmControl->CrashCode == IPC_AP_CLEAR_TO_SEND) { for (i = 0; i < 256; i++) ; if (TIMER_GetValue() - t1 > TICKS_ONE_SECOND * 20) break; } /* check for time out */ if (SmLocalControl.SmControl->CrashCode == IPC_AP_CLEAR_TO_SEND) { if (retryCount < MAX_CP_DUMP_RETRIES) { retryCount++; IPC_DEBUG( DBG_TRACE, "timeout %d, trying again..\n", (int)retryCount); continue; } else { /* no response from CP, * so get out of here */ IPC_DEBUG( DBG_ERROR, "Abort --- max retries %d reached\n", (int)retryCount); break; } } /* reset retry counter */ retryCount = 0; /* get virtual address of CP assert buffer */ AssertLogVAddr = ioremap_nocache( (UInt32) (SmLocalControl.SmControl->CrashCode), ASSERT_BUF_SIZE); if (NULL == AssertLogVAddr) { IPC_DEBUG(DBG_ERROR, "ioremap_nocache failed in DUMP_CP_assert_log\n"); break; } p = (UInt8 *)AssertLogVAddr; /* number of bytes in assert buffer */ size = (p[0] << 8) + p[1]; /* size of 0 means CP is done dumping assert log */ if (size == 0) { IPC_DEBUG(DBG_ERROR, "assert log size 0, exiting, packetCount:0x%x\n", (int)packetCount); iounmap(AssertLogVAddr); AssertLogVAddr = NULL; break; } /* sanity check for too beaucoup... */ if (size > ASSERT_BUF_SIZE - 2) { IPC_DEBUG(DBG_ERROR, "Abort --- improper size [%08x]=%d\n", SmLocalControl.SmControl->CrashCode, (int)size); iounmap(AssertLogVAddr); AssertLogVAddr = NULL; break; } /* send packet out to log * (MTT via RNDIS or crash dump file) */ BCMLOG_HandleCpCrashDumpData((const char *)(p + 2), size); packetCount++; iounmap(AssertLogVAddr); AssertLogVAddr = NULL; } } RpcDbgDumpHistoryLogging(2, 1); IPC_DEBUG(DBG_ERROR, "Starting CP RAM dump - do not power down...\n"); /* dump all CP memory to log */ DUMP_CPMemoryByList(dumped_crash_summary_ptr->mem_dump); IPC_DEBUG(DBG_ERROR, "CP RAM dump complete\n"); /* resume normal logging activities... */ BCMLOG_EndCpCrashDump(); if (BCMLOG_OUTDEV_SDCARD == BCMLOG_GetCpCrashLogDevice()) sys_sync(); IPC_DEBUG(DBG_ERROR, "CP crash dump complete\n"); if ((BCMLOG_OUTDEV_SDCARD == BCMLOG_GetCpCrashLogDevice()) && cp_crashed == 1 && !cpReset) abort(); }
/** * Utility function to retrieve full crash log from CP via simple handshake * protocol. * * ********************************************************************************/ void DUMP_CP_assert_log(void) { UInt32 t0, t1, i, size, retryCount; UInt8 *p; UInt32 packetCount = 0; void __iomem *AssertLogVAddr = NULL; struct file* sdDumpFile = NULL; mm_segment_t oldfs; struct timespec ts; struct rtc_time tm; char assertFileName[CP_CRASH_DUMP_MAX_LEN]; extern void abort(void); // need to tell kernel that pointers from within the // kernel address space are valid (needed to do // file ops from kernel) oldfs = get_fs(); set_fs (KERNEL_DS); if( BCMLOG_CPCRASH_SDCARD == BCMLOG_GetCpCrashDumpDevice() ) { // get current time getnstimeofday(&ts); rtc_time_to_tm(ts.tv_sec, &tm); snprintf(assertFileName, CP_CRASH_DUMP_MAX_LEN, "%s%s%d_%02d_%02d_%02d_%02d_%02d%s", CP_CRASH_DUMP_DIR, CP_CRASH_DUMP_BASE_FILE_NAME, tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec, CP_CRASH_DUMP_FILE_EXT ); sdDumpFile = filp_open( assertFileName, O_WRONLY|O_TRUNC|O_LARGEFILE|O_CREAT, 666); if ( IS_ERR(sdDumpFile) ) { IPC_DEBUG(DBG_ERROR,"failed to open sdDumpFile %s\n", assertFileName); sdDumpFile = NULL; } else { IPC_DEBUG(DBG_ERROR,"sdDumpFile %s opened OK\n",assertFileName); } } // put logging driver into crash dump mode; messages will be sent straight out to MTT via // RNDIS (or dump file) instead of buffering in RING buffer (flood of crash dump info // overloads ring buffer otherwise, and we lose a lot of crash dump info) // NOTE: crash dump is put into SD by default; if SD file fails to open, then we'll try // sending it out RNDIS BCMLOG_StartCpCrashDump( sdDumpFile ); retryCount = 0; t0 = TIMER_GetValue(); while (1) { t1 = TIMER_GetValue(); // signal to CP that we're ready to receive crash log... SmLocalControl.SmControl->CrashCode = IPC_AP_CLEAR_TO_SEND; // wait for CP to "dump"; CrashCode field will be set to physical address of current assert buf while (SmLocalControl.SmControl->CrashCode == IPC_AP_CLEAR_TO_SEND) { for (i=0; i<256; i++); if (TIMER_GetValue() - t1 > TICKS_ONE_SECOND * 20) break; } // check for time out if (SmLocalControl.SmControl->CrashCode == IPC_AP_CLEAR_TO_SEND) { if ( retryCount < MAX_CP_DUMP_RETRIES ) { retryCount++; IPC_DEBUG(DBG_ERROR,"timeout %d, trying again...\n", (int)retryCount); continue; } else { // no response from CP, so get out of here IPC_DEBUG(DBG_ERROR,"Abort --- max retries %d reached\n", (int)retryCount); break; } } // reset retry counter retryCount = 0; // get virtual address of CP assert buffer AssertLogVAddr = ioremap_nocache((UInt32)(SmLocalControl.SmControl->CrashCode), ASSERT_BUF_SIZE); if(NULL == AssertLogVAddr) { IPC_DEBUG(DBG_ERROR, "ioremap_nocache failed in DUMP_CP_assert_log\n"); break; } p = (UInt8 *)AssertLogVAddr; // number of bytes in assert buffer size = (p[0] << 8) + p[1]; // size of 0 means CP is done dumping assert log if (size == 0) { IPC_DEBUG(DBG_INFO, "assert log size 0, exiting, packetCount:0x%x\n", (int)packetCount); iounmap(AssertLogVAddr); AssertLogVAddr = NULL; break; } // sanity check for too beaucoup... if (size > ASSERT_BUF_SIZE - 2) { IPC_DEBUG(DBG_ERROR, "Abort --- improper size [%08x]=%d\n", SmLocalControl.SmControl->CrashCode, (int)size); iounmap(AssertLogVAddr); AssertLogVAddr = NULL; break; } // send packet out to log (MTT via RNDIS or crash dump file) BCMLOG_HandleCpCrashDumpData( (const char*)(p+2), size ); packetCount++; iounmap(AssertLogVAddr); AssertLogVAddr = NULL; #if 0 // **FIXME** this is Nucleus timeout code - do we want something similar // for Android? Maybe if we get to the point of restarting CP with // restarting AP if (TIMER_GetValue() - t0 > TICKS_ONE_SECOND * 10 * 60) { IPC_DEBUG(DBG_ERROR,"Abort --- CP assertion log too long\n"); break; } #endif } IPC_DEBUG(DBG_ERROR,"Starting CP RAM dump - do not power down...\n"); // dump all CP memory to log DUMP_CPMemoryByList( dumped_crash_summary_ptr->mem_dump ); IPC_DEBUG(DBG_ERROR,"CP RAM dump complete\n"); // resume normal logging activities... BCMLOG_EndCpCrashDump( ); if ( sdDumpFile ) { filp_close( sdDumpFile ,NULL ); } set_fs (oldfs); sys_sync(); IPC_DEBUG(DBG_ERROR,"CP crash dump complete\n"); if (BCMLOG_CPCRASH_MTD != BCMLOG_GetCpCrashDumpDevice()) abort(); #ifdef CONFIG_BRCM_KPANIC_UI_IND else lcdc_disp_img(IMG_INDEX_END_DUMP); //parameter 1: Draw the Kpanic Dump complete picture #endif }