/****************************************************************** * 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(); }
/************************************************* * * Worker thread to dump CP crash log information. * * *****************************************************/ void ProcessCPCrashedDump(struct work_struct *work) { char crashReason[40] = { 0 }; char crashFile[40] = { 0 }; char crashThread[40] = { 0 }; char outString[512] = { 0 }; IPC_U32 *Dump; void __iomem *DumpVAddr; int cpReset = SmLocalControl.SmControl->CrashCode == IPC_CP_SILENT_RESET_READY; RpcDbgDumpHistoryLogging(0, 0); #ifdef CONFIG_KONA_SECURE_MEMC u32 *memc_handle; /* this is where any type of cp crash gets handled. * there could be a scenerio of silent-reboot of cp. * or there could be abrupt crash of cp. * either ap would be alive or ap will crash itself. * we protect cp area from following masters. * > ap * > mm * > fabric * in the event of ap/cp crash we need to give an ap * access back to the cp area for the dump. * and in the case of silent cp reset, ap will * be alive, in that case we grant an access to ap. * so that ap can load cp images and can take dump * if required. * and when cp comes up successfully and sync up with ap, * we revoke the access for ap somwhere in HandleRestartCP. */ memc_handle = get_secure_memc_handle(); if (!memc_handle) pr_err("Failed to get secure memc handle\n"); if (do_grant_region_access(memc_handle, AP)) pr_err("Failed to grant access for AP\n"); #endif #ifdef CONFIG_FB_BRCM_CP_CRASH_DUMP_IMAGE_SUPPORT if (!crash_dump_ui_on && !cpReset) { if (ramdump_enable) kona_display_crash_image(CP_RAM_DUMP_START); else kona_display_crash_image(CP_CRASH_DUMP_START); crash_dump_ui_on = 1; } #endif #ifndef CONFIG_BCM_AP_PANIC_ON_CPCRASH #ifdef CONFIG_CDEBUGGER if (ramdump_enable #ifdef CONFIG_APANIC_ON_MMC && ap_triggered == 0 #endif && !cpReset ) { /* we kill AP when CP crashes */ IPC_DEBUG(DBG_ERROR, "Crashing AP for Ramdump ...\n\n"); abort(); } #endif if ((BCMLOG_OUTDEV_PANIC == BCMLOG_GetCpCrashLogDevice() || BCMLOG_OUTDEV_NONE == BCMLOG_GetCpCrashLogDevice() || BCMLOG_OUTDEV_STM == BCMLOG_GetCpCrashLogDevice()) && !cpReset #ifdef CONFIG_APANIC_ON_MMC && !ap_triggered #endif ) { /* we kill AP when CP crashes */ IPC_DEBUG(DBG_ERROR, "Crashing AP now ...\n\n"); abort(); } #endif // CONFIG_BCM_AP_PANIC_ON_CPCRASH IPC_Dump(); #if defined(CONFIG_BRCM_CP_CRASH_DUMP_EMMC) \ || defined(CONFIG_BCM_AP_PANIC_ON_CPCRASH) while (SmLocalControl.SmControl->CrashDump == NULL) ; /* No op */ #endif /* **NOTE** for now, continue doing simple dump out IPC_DEBUG so there * is some indication of CP crash in console * (in case user not running MTT) */ Dump = (void *)SmLocalControl.SmControl->CrashDump; IPC_DEBUG(DBG_ERROR, "ioremap\n"); DumpVAddr = plat_ioremap_ns((unsigned long __force) get_vaddr(IPC_CP_CRASH_SUMMARY_AREA), IPC_CP_CRASH_SUMMARY_AREA_SZ, (phys_addr_t)Dump); if (!DumpVAddr) { IPC_DEBUG(DBG_ERROR, "ioremap failed in ProcessCPCrashedDump\n"); goto cleanUp; } IPC_DEBUG(DBG_ERROR, "Crash Summary Virtual Addr: 0x%08X\n", (unsigned int)DumpVAddr); dumped_crash_summary_ptr = (struct T_CRASH_SUMMARY *)DumpVAddr; IPC_DEBUG(DBG_ERROR, "===== COMMS_PROCESSOR crash summary =====\r\n"); if (dumped_crash_summary_ptr->link_signature) { GetStringFromPA((UInt32) dumped_crash_summary_ptr->link_signature, outString, 128); IPC_DEBUG(DBG_ERROR, "%s\r\n", outString); } if (dumped_crash_summary_ptr->project_version) { GetStringFromPA((UInt32) dumped_crash_summary_ptr->project_version, outString, 128); IPC_DEBUG(DBG_ERROR, "%s\r\n", outString); } if (dumped_crash_summary_ptr->DSP_version) { GetStringFromPA((UInt32)dumped_crash_summary_ptr->DSP_version, outString, 128); IPC_DEBUG(DBG_ERROR, "%s\r\n", outString); } if (dumped_crash_summary_ptr->FW_version) { GetStringFromPA((UInt32)dumped_crash_summary_ptr->FW_version, outString, 128); IPC_DEBUG(DBG_ERROR, "%s\r\n", outString); } if (dumped_crash_summary_ptr->decoder_version) { GetStringFromPA((UInt32) dumped_crash_summary_ptr->decoder_version, outString, 128); IPC_DEBUG(DBG_ERROR, "%s\r\n", outString); } GetStringFromPA((UInt32)dumped_crash_summary_ptr->reason, crashReason, 40); GetStringFromPA((UInt32)dumped_crash_summary_ptr->file, crashFile, 40); GetStringFromPA((UInt32)dumped_crash_summary_ptr->thread, crashThread, 40); IPC_DEBUG(DBG_ERROR, "%s f=%s l=%d v=%d/0x%x t=%s TS=%d\r\n", crashReason, crashFile, dumped_crash_summary_ptr->line, dumped_crash_summary_ptr->value, dumped_crash_summary_ptr->value, crashThread, dumped_crash_summary_ptr->time); /* notify clients about CP reset */ if (cpReset #ifdef CONFIG_BRCM_CP_CRASH_DUMP_EMMC && !ap_triggered #endif ) HandleCPResetStart(); #ifndef CONFIG_BCM_AP_PANIC_ON_CPCRASH /* done with "simple" dump, so now pull the full assert * log from CP and dump out to MTT */ DUMP_CP_assert_log(); #endif cleanUp: if (DumpVAddr) plat_iounmap_ns(get_vaddr(IPC_CP_CRASH_SUMMARY_AREA), free_size_ipc(IPC_CP_CRASH_SUMMARY_AREA_SZ)); /* crash dump is done, so trigger CP reset */ if (cpReset #ifdef CONFIG_BRCM_CP_CRASH_DUMP_EMMC && !ap_triggered #endif ) { IPC_DEBUG(DBG_INFO, "waiting for clients to ack...\n"); while (!cp_reset_clients_acked) msleep(300); cp_reset_clients_acked = 0; IPC_DEBUG(DBG_INFO, "starting cp_reset thread\n"); kthread_run(HandleRestartCP, 0, "cp_reset"); } #ifdef CONFIG_HAS_WAKELOCK else wake_unlock(&ipc_wake_lock); #endif #ifdef CONFIG_BCM_AP_PANIC_ON_CPCRASH #ifdef CONFIG_SEC_DEBUG cp_abort(); #endif /* CONFIG_SEC_DEBUG */ #endif /* CONFIG_AP_PANIC_ON_CPCRASH */ }
/************************************************* * * Worker thread to dump CP crash log information. * * *****************************************************/ void ProcessCPCrashedDump(struct work_struct *work) { char crashReason[40] = { 0 }; char crashFile[40] = { 0 }; char crashThread[40] = { 0 }; char outString[512] = { 0 }; IPC_U32 *Dump; void __iomem *DumpVAddr; int cpReset = SmLocalControl.SmControl->CrashCode == IPC_CP_SILENT_RESET_READY; #ifdef CONFIG_CDEBUGGER if (ramdump_enable #ifdef CONFIG_BRCM_CP_CRASH_DUMP_EMMC && ap_triggered == 0 #endif ) { BCMLOG_SetCpCrashLogDevice(BCMLOG_OUTDEV_NONE); /* we kill AP when CP crashes */ IPC_DEBUG(DBG_ERROR, "Crashing AP for ramdump ...\n\n"); abort(); } #endif if ((BCMLOG_OUTDEV_PANIC == BCMLOG_GetCpCrashLogDevice() || (BCMLOG_OUTDEV_RNDIS == BCMLOG_GetCpCrashLogDevice() && !cpReset)) #ifdef CONFIG_BRCM_CP_CRASH_DUMP_EMMC && !ap_triggered #endif ) { #ifdef CONFIG_CRASH_DUMP_START_UI_DISPLAY if (!dump_start_ui_on) { display_crash_dump_start_ui(); dump_start_ui_on = 1; msleep(100); } #endif /* we kill AP when CP crashes */ IPC_DEBUG(DBG_ERROR, "Crashing AP now ...\n\n"); abort(); } #ifdef CONFIG_CRASH_DUMP_START_UI_DISPLAY if ((BCMLOG_OUTDEV_SDCARD == BCMLOG_GetCpCrashLogDevice()) && cp_crashed == 1 && !cpReset) { if (!dump_start_ui_on) { display_crash_dump_start_ui(); dump_start_ui_on = 1; } } #endif IPC_Dump(); RpcDbgDumpHistoryLogging(0, 0); #if defined(CONFIG_BRCM_CP_CRASH_DUMP) \ || defined(CONFIG_BRCM_CP_CRASH_DUMP_EMMC) \ || defined(CONFIG_BCM_AP_PANIC_ON_CPCRASH) while (SmLocalControl.SmControl->CrashDump == NULL) ; /* No op */ #endif /* **NOTE** for now, continue doing simple dump out IPC_DEBUG so there * is some indication of CP crash in console * (in case user not running MTT) */ Dump = (void *)SmLocalControl.SmControl->CrashDump; IPC_DEBUG(DBG_ERROR, "ioremap_nocache\n"); DumpVAddr = ioremap_nocache((UInt32)Dump, sizeof(struct T_CRASH_SUMMARY)); if (NULL == DumpVAddr) { IPC_DEBUG(DBG_ERROR, "VirtualAlloc failed\n"); goto cleanUp; } IPC_DEBUG(DBG_ERROR, "Crash Summary Virtual Addr: 0x%08X\n", (unsigned int)DumpVAddr); dumped_crash_summary_ptr = (struct T_CRASH_SUMMARY *)DumpVAddr; IPC_DEBUG(DBG_ERROR, "===== COMMS_PROCESSOR crash summary =====\r\n"); if (dumped_crash_summary_ptr->link_signature) { GetStringFromPA((UInt32) dumped_crash_summary_ptr->link_signature, outString, 128); IPC_DEBUG(DBG_ERROR, "%s\r\n", outString); } if (dumped_crash_summary_ptr->project_version) { GetStringFromPA((UInt32) dumped_crash_summary_ptr->project_version, outString, 128); IPC_DEBUG(DBG_ERROR, "%s\r\n", outString); } if (dumped_crash_summary_ptr->DSP_version) { GetStringFromPA((UInt32)dumped_crash_summary_ptr->DSP_version, outString, 128); IPC_DEBUG(DBG_ERROR, "%s\r\n", outString); } if (dumped_crash_summary_ptr->FW_version) { GetStringFromPA((UInt32)dumped_crash_summary_ptr->FW_version, outString, 128); IPC_DEBUG(DBG_ERROR, "%s\r\n", outString); } if (dumped_crash_summary_ptr->decoder_version) { GetStringFromPA((UInt32) dumped_crash_summary_ptr->decoder_version, outString, 128); IPC_DEBUG(DBG_ERROR, "%s\r\n", outString); } GetStringFromPA((UInt32)dumped_crash_summary_ptr->reason, crashReason, 40); GetStringFromPA((UInt32)dumped_crash_summary_ptr->file, crashFile, 40); GetStringFromPA((UInt32)dumped_crash_summary_ptr->thread, crashThread, 40); IPC_DEBUG(DBG_ERROR, "%s f=%s l=%d v=%d/0x%x t=%s TS=%d\r\n", crashReason, crashFile, dumped_crash_summary_ptr->line, dumped_crash_summary_ptr->value, dumped_crash_summary_ptr->value, crashThread, dumped_crash_summary_ptr->time); /* notify clients about CP reset */ if (cpReset #ifdef CONFIG_BRCM_CP_CRASH_DUMP_EMMC && !ap_triggered #endif ) HandleCPResetStart(); #ifndef CONFIG_BCM_AP_PANIC_ON_CPCRASH /* done with "simple" dump, so now pull the full assert * log from CP and dump out to MTT */ DUMP_CP_assert_log(); #endif cleanUp: if (NULL != DumpVAddr) iounmap(DumpVAddr); /* crash dump is done, so trigger CP reset */ if (cpReset #ifdef CONFIG_BRCM_CP_CRASH_DUMP_EMMC && !ap_triggered #endif ) { IPC_DEBUG(DBG_INFO, "waiting for clients to ack...\n"); while (!cp_reset_clients_acked) msleep(300); cp_reset_clients_acked = 0; IPC_DEBUG(DBG_INFO, "starting cp_reset thread\n"); kthread_run(HandleRestartCP, 0, "cp_reset"); } #ifdef CONFIG_HAS_WAKELOCK else wake_unlock(&ipc_wake_lock); #endif #ifdef CONFIG_BCM_AP_PANIC_ON_CPCRASH IPC_DEBUG(DBG_ERROR, "CP crashed, crashing AP now..\n"); #ifdef CONFIG_SEC_DEBUG cp_abort(); #else abort(); #endif /* CONFIG_SEC_DEBUG */ #endif /* CONFIG_AP_PANIC_ON_CPCRASH */ }
/************************************************* * * Worker thread to dump CP crash log information. * * *****************************************************/ void ProcessCPCrashedDump(struct work_struct *work) { char crashReason[40] = { 0 }; char crashFile[40] = { 0 }; char crashThread[40] = { 0 }; char outString[512] = { 0 }; IPC_U32 *Dump; void __iomem *DumpVAddr; #ifdef CONFIG_FB_BRCM_CP_CRASH_DUMP_IMAGE_SUPPORT rhea_display_crash_image(CP_CRASH_DUMP_START); #endif #ifdef CONFIG_BCM_AP_PANIC_ON_CPCRASH if (BCMLOG_OUTDEV_SDCARD == BCMLOG_GetCpCrashLogDevice() #ifdef CONFIG_CDEBUGGER && ramdump_enable == 1 #endif #ifdef CONFIG_APANIC_ON_MMC && ap_triggered == 0 #endif ) { /* we kill AP when CP crashes */ IPC_DEBUG(DBG_ERROR, "Crashing AP for Ramdump ...\n\n"); #ifdef CONFIG_SEC_DEBUG cp_abort(); #else abort(); #endif /* CONFIG_SEC_DEBUG */ } if ((BCMLOG_OUTDEV_NONE == BCMLOG_GetCpCrashLogDevice() || BCMLOG_OUTDEV_PANIC == BCMLOG_GetCpCrashLogDevice() || BCMLOG_OUTDEV_STM == BCMLOG_GetCpCrashLogDevice() || BCMLOG_OUTDEV_RNDIS == BCMLOG_GetCpCrashLogDevice()) #ifdef CONFIG_APANIC_ON_MMC && ap_triggered == 0 #endif ) { /* we kill AP when CP crashes */ IPC_DEBUG(DBG_ERROR, "Crashing AP now ...\n\n"); #ifdef CONFIG_SEC_DEBUG cp_abort(); #else abort(); #endif /* CONFIG_SEC_DEBUG */ } #endif /* check for CP Reset here? Assuming CP Reset is just signified by a different crash code */ if (SmLocalControl.SmControl->CrashCode == IPC_CP_SILENT_RESET_READY) { HandleCPResetStart(); return; } IPC_Dump(); RpcDbgDumpHistoryLogging(0, 0); #if defined(CONFIG_BRCM_CP_CRASH_DUMP) \ || defined(CONFIG_BRCM_CP_CRASH_DUMP_EMMC) \ || defined(CONFIG_BCM_AP_PANIC_ON_CPCRASH) while (SmLocalControl.SmControl->CrashDump == NULL) ; /* No op */ #endif /* **NOTE** for now, continue doing simple dump out IPC_DEBUG so there * is some indication of CP crash in console * (in case user not running MTT) */ Dump = (void *)SmLocalControl.SmControl->CrashDump; IPC_DEBUG(DBG_ERROR, "ioremap_nocache\n"); DumpVAddr = ioremap_nocache((UInt32) Dump, sizeof(struct T_CRASH_SUMMARY)); if (NULL == DumpVAddr) { IPC_DEBUG(DBG_ERROR, "VirtualAlloc failed\n"); goto cleanUp; } IPC_DEBUG(DBG_ERROR, "Crash Summary Virtual Addr: 0x%08X\n", (unsigned int)DumpVAddr); dumped_crash_summary_ptr = (struct T_CRASH_SUMMARY *)DumpVAddr; IPC_DEBUG(DBG_ERROR, "===== COMMS_PROCESSOR crash summary =====\r\n"); if (dumped_crash_summary_ptr->link_signature) { GetStringFromPA((UInt32) dumped_crash_summary_ptr-> link_signature, outString, 128); IPC_DEBUG(DBG_ERROR, "%s\r\n", outString); } if (dumped_crash_summary_ptr->project_version) { GetStringFromPA((UInt32) dumped_crash_summary_ptr-> project_version, outString, 128); IPC_DEBUG(DBG_ERROR, "%s\r\n", outString); } if (dumped_crash_summary_ptr->DSP_version) { GetStringFromPA((UInt32) dumped_crash_summary_ptr->DSP_version, outString, 128); IPC_DEBUG(DBG_ERROR, "%s\r\n", outString); } if (dumped_crash_summary_ptr->FW_version) { GetStringFromPA((UInt32) dumped_crash_summary_ptr->FW_version, outString, 128); IPC_DEBUG(DBG_ERROR, "%s\r\n", outString); } if (dumped_crash_summary_ptr->decoder_version) { GetStringFromPA((UInt32) dumped_crash_summary_ptr-> decoder_version, outString, 128); IPC_DEBUG(DBG_ERROR, "%s\r\n", outString); } GetStringFromPA((UInt32) dumped_crash_summary_ptr->reason, crashReason, 40); GetStringFromPA((UInt32) dumped_crash_summary_ptr->file, crashFile, 40); GetStringFromPA((UInt32) dumped_crash_summary_ptr->thread, crashThread, 40); IPC_DEBUG(DBG_ERROR, "%s f=%s l=%d v=%d/0x%x t=%s TS=%d\r\n", crashReason, crashFile, dumped_crash_summary_ptr->line, dumped_crash_summary_ptr->value, dumped_crash_summary_ptr->value, crashThread, dumped_crash_summary_ptr->time); #ifndef CONFIG_BCM_AP_PANIC_ON_CPCRASH /* done with "simple" dump, so now pull the full assert * log from CP and dump out to MTT */ DUMP_CP_assert_log(); #endif cleanUp: if (NULL != DumpVAddr) iounmap(DumpVAddr); #ifdef CONFIG_HAS_WAKELOCK wake_unlock(&ipc_wake_lock); #endif #ifdef CONFIG_BCM_AP_PANIC_ON_CPCRASH #ifdef CONFIG_SEC_DEBUG cp_abort(); #endif /* CONFIG_SEC_DEBUG */ #endif /* CONFIG_AP_PANIC_ON_CPCRASH */ }