int cpStart(int isReset) { void __iomem *apcp_shmem; void __iomem *cp_boot_base; u32 reg_val; IPC_DEBUG(DBG_TRACE, "enter\n"); #ifdef CONFIG_BCM_MODEM_DEFER_CP_START CP_Boot(); #else if (isReset) { IPC_DEBUG(DBG_INFO, "call CP_Boot\n"); CP_Boot(); } #endif apcp_shmem = ioremap_nocache(IPC_BASE, IPC_SIZE); if (!apcp_shmem) { IPC_DEBUG(DBG_ERROR, "IPC_BASE=0x%x, IPC_SIZE=0x%x\n", IPC_BASE, IPC_SIZE); IPC_DEBUG(DBG_ERROR, "ioremap shmem failed\n"); return -1; } /* clear first (9) 32-bit words in shared memory */ memset(apcp_shmem, 0, IPC_SIZE); iounmap(apcp_shmem); IPC_DEBUG(DBG_TRACE, "cleared sh mem\n"); cp_boot_base = ioremap_nocache(MODEM_DTCM_ADDRESS, INIT_ADDRESS_OFFSET + RESERVED_HEADER); if (!cp_boot_base) { IPC_DEBUG(DBG_ERROR, "DTCM Addr=0x%x, length=0x%x", MODEM_DTCM_ADDRESS, INIT_ADDRESS_OFFSET + RESERVED_HEADER); IPC_DEBUG(DBG_ERROR, "ioremap cp_boot_base error\n"); return -1; } /* Start the CP: * - read main address * - write to init address */ reg_val = readl(cp_boot_base+MAIN_ADDRESS_OFFSET+RESERVED_HEADER); IPC_DEBUG(DBG_TRACE, "main addr 0x%x\n", reg_val); writel(reg_val, cp_boot_base+INIT_ADDRESS_OFFSET+RESERVED_HEADER); iounmap(cp_boot_base); IPC_DEBUG(DBG_TRACE, "modem (R4 COMMS) started ...\n"); return 0; }
/* registers client callback to be used for passing silent CP reset events */ int IPCAP_RegisterCPResetHandler(IPCAP_CPResetHandler_T inResetHandler) { /* **FIXME** need to support multiple clients, or just RPC? */ sCPResetHandler = inResetHandler; IPC_DEBUG(DBG_INFO, "cp reset handler registered\n"); return 1; }
/** @fn void ipcs_ipc_initialised(void); */ void ipcs_ipc_initialised(void) { IPC_DEBUG(DBG_INFO,"IPC Initialization completed\n"); g_ipc_info.ipc_state = 1; return; }
// Send 'val' (and 'pg' with 'perm', if 'pg' is nonnull) to 'toenv'. // This function keeps trying until it succeeds. // It should panic() on any error other than -E_IPC_NOT_RECV. // // Hint: // Use sys_yield() to be CPU-friendly. // If 'pg' is null, pass sys_ipc_try_send a value that it will understand // as meaning "no page". (Zero is not the right value.) void ipc_send(envid_t to_env, uint32_t val, void *pg, int perm) { // LAB 4: Your code here. struct Env *env; int r; void *srcva; if (pg == NULL) { srcva = (void *)~0; } else { srcva = pg; } IPC_DEBUG("ipc_send: perm = %d\n", perm); while ((r = sys_ipc_try_send(to_env, val, srcva, perm)) != 0) { if (r != -E_IPC_NOT_RECV) { panic("ipc_send: sys_ipc_try_send erro %e\n", r); } } // I tested and found out a sys_yield() here actually made things slower! // sys_yield(); return; }
void ResetCP(void) { void __iomem *cp_root_reset_base; void __iomem *cp_bmdm_reset_base; IPC_DEBUG(DBG_INFO, "resetting CP\n"); /* reset CP - copy from cp_reset.cmm rxd from CP team */ /*;CP reset, from AP * * D.S ZSD:0x35001F00 %LE %LONG 0xa5a501 * D.S ZSD:0x35001F08 %LE %LONG 0x3bd ;reset * D.S ZSD:0x35001F08 %LE %LONG 0x3fd ;clear */ cp_root_reset_base = ioremap(ROOT_RST_BASE_ADDR, ROOT_RST_MGR_REG_PD_SOFT_RSTN_OFFSET+4); if (!cp_root_reset_base) { IPC_DEBUG(DBG_ERROR, "failed to remap ROOT_RST_BASE_ADDR, crashing\n"); BUG(); } writel(0xa5a501, cp_root_reset_base+ROOT_RST_MGR_REG_WR_ACCESS_OFFSET); writel(0x3bd, cp_root_reset_base+ROOT_RST_MGR_REG_PD_SOFT_RSTN_OFFSET); writel(0x3fd, cp_root_reset_base+ROOT_RST_MGR_REG_PD_SOFT_RSTN_OFFSET); /* reset R4 - copy from cp_reset.cmm rxd from CP team */ /*;R4 reset * * D.S ZSD:0x3a055f00 %LE %LONG 0xa5a501 * D.S ZSD:0x3a055f18 %LE %LONG 0x2 ;reset * D.S ZSD:0x3a055f18 %LE %LONG 0x3 ;clear */ cp_bmdm_reset_base = ioremap(BMDM_RST_BASE_ADDR, BMDM_RST_MGR_REG_CP_RSTN_OFFSET+4); if (!cp_bmdm_reset_base) { IPC_DEBUG(DBG_ERROR, "failed to remap BMDM_RST_BASE_ADDR, crashing\n"); BUG(); } writel(0xa5a501, cp_bmdm_reset_base+BMDM_RST_MGR_REG_WR_ACCESS_OFFSET); writel(0x2, cp_bmdm_reset_base+BMDM_RST_MGR_REG_CP_RSTN_OFFSET); writel(0x3, cp_bmdm_reset_base+BMDM_RST_MGR_REG_CP_RSTN_OFFSET); iounmap(cp_root_reset_base); iounmap(cp_bmdm_reset_base); }
void ipcs_intr_workqueue_process(struct work_struct *work) { static int first = 1; if (first) { first = 0; set_user_nice(current, -16); } if(IpcCPCrashCheck()) { cp_crashed = 1; //patch-s from Broadcom for csp#529767 reason:FALSE file=ripisr_cp.c line=342 code=-1/0xffffffff tastk=RIP_H TS=48744870/FN=4873 //reviewed by yuan /* Dumping Camera registers. MobC00180667 */ { int i = 0; unsigned int camera_addr_base = 0x08440000; // Receiver Status reg set printk("\n Dumping Camera registers\n"); for(i = 0; i < 8; i ++) { printk("Addr: 0x%x Value: 0x%x\n", camera_addr_base, readl(io_p2v(camera_addr_base))); camera_addr_base += 4; } camera_addr_base = 0x08440080; // Debug register set for(i = 0; i < 9; i ++) { printk("Addr: 0x%x Value: 0x%x\n", camera_addr_base, readl(io_p2v(camera_addr_base))); camera_addr_base += 4; } camera_addr_base = 0x08440100; // Channel information set for(i = 0; i < 12; i ++) { printk("Addr: 0x%x Value: 0x%x\n", camera_addr_base, readl(io_p2v(camera_addr_base))); camera_addr_base += 4; } camera_addr_base = 0x08440400; // Ping pong buffer management printk("Addr: 0x%x Value: 0x%x\n", camera_addr_base, readl(io_p2v(camera_addr_base))); } /* End of Camera register dump */ //patch-e from Broadcom for csp#529767 reason:FALSE file=ripisr_cp.c line=342 code=-1/0xffffffff tastk=RIP_H TS=48744870/FN=4873 if( BCMLOG_CPCRASH_MTD == BCMLOG_GetCpCrashDumpDevice() ) { /* we kill AP when CP crashes */ IPC_DEBUG(DBG_INFO, "Crashing AP now...\n\n"); abort(); } else { ProcessCPCrashedDump(work); } IPC_ProcessEvents(); }else { IPC_ProcessEvents(); #ifdef CONFIG_HAS_WAKELOCK wake_unlock(&ipc_wake_lock); #endif // CONFIG_HAS_WAKELOCK } }
/** unsigned int bcm_map_virt_to_phys(void *virt_addr); */ unsigned int bcm_map_virt_to_phys(void *virt_addr) { //Note: since shared-mem is io-mem, these kernel call to map virt to phys does not work //return((unsigned int)virt_to_phys(virt_addr)); IPC_DEBUG(DBG_ERROR, "%s: should not be used on this address\n", __FUNCTION__); return(0); }
/** void *bcm_map_phys_to_virt(unsigned int physical_addr); */ void *bcm_map_phys_to_virt(unsigned int physical_addr) { //Note: since shared-mem is io-mem, these kernel call to map phys to virt does not work //return((void *)phys_to_virt((unsigned long)physical_addr)); IPC_DEBUG(DBG_ERROR, "%s: should not be used on this address\n", __FUNCTION__); return(NULL); }
/* callback from client indicating it is ready for CP reset */ void IPCAP_ReadyForReset(int inClientID) { IPC_DEBUG(DBG_INFO, "ready for reset\n"); /* get rid of the ack timeout timer */ del_timer(&cp_reset_timer); cp_reset_clients_acked = 1; }
/************************************************* * Reloads the CP images. * *****************************************************/ static void ReloadCP(void) { int ret; int index; for (index = 0; (g_cp_imgs[index].img_name != NULL); index++) { IPC_DEBUG(DBG_INFO, "LoadFirmware for %s @ %p, size %d\n", g_cp_imgs[index].img_name, (void *)g_cp_imgs[index].ram_addr, g_cp_imgs[index].img_size); ret = LoadFirmware(ipcs_get_drvdata(), g_cp_imgs[index].img_name, g_cp_imgs[index].ram_addr, g_cp_imgs[index].img_size); IPC_DEBUG(DBG_INFO, "LoadFirmware for %s returned %d\n", g_cp_imgs[index].img_name, ret); } }
static IPC_ReturnCode_T EventDelete(void *Event) { struct IPC_Evt_t *ipcEvt = (struct IPC_Evt_t *)Event; if (ipcEvt) { IPC_DEBUG(DBG_TRACE, "EventDelete: %p\n", ipcEvt); kfree(ipcEvt); } return IPC_OK; }
int HandleRestartCP(void *data) { IPC_DEBUG(DBG_INFO, "enter\n"); IPC_DEBUG(DBG_INFO, "call local_irq_disable()\n"); local_irq_disable(); IPC_DEBUG(DBG_INFO, "resetting CP\n"); ResetCP(); /* reload CP */ IPC_DEBUG(DBG_INFO, "reloading CP\n"); ReloadCP(); IPC_DEBUG(DBG_INFO, "rebooting CP\n"); /* reboot CP; this will also wipe IPC shared memory */ Comms_Start(1); IPC_DEBUG(DBG_INFO, "call local_irq_enable()\n"); local_irq_enable(); enable_irq(IRQ_IPC_C2A); IPC_DEBUG(DBG_INFO, "re-init IPC\n"); /* reinitialize IPC, and wait for IPC sync with CP */ if (ipcs_reinitialize_ipc()) { IPC_DEBUG(DBG_ERROR, "ipcs_reinitialize_ipc failed\n"); /* CP didn't re-sync, so crash AP here */ BUG(); } /* give CP some time to boot; without this delay, we hang * on the CAPI2_PhoneCtrlApi_ProcessPowerUpReq() from RIL */ msleep(2000); /* notify clients that we're back in business... */ IPC_DEBUG(DBG_INFO, "notifying clients CP reset is complete\n"); HandleCPResetDone(); IPC_DEBUG(DBG_INFO, "notification done, exiting reset thread\n"); /* done with thread */ do_exit(0); }
/** static int ipcs_init(void *smbase, unsigned int size) */ static int ipcs_init(void *smbase, unsigned int size, int isReset) { int rc = 0; IPC_DEBUG(DBG_TRACE, "WaitForCpIpc\n"); /* Wait for CP to initialize */ WaitForCpIpc(smbase); IPC_DEBUG(DBG_TRACE, "Calling ipc_set_interrupt_mask()\n"); ipc_set_interrupt_mask(); IPC_DEBUG(DBG_TRACE, "Done ipc_set_interrupt_mask()\n"); IPC_DEBUG(DBG_TRACE, "Calling ipc_set_interrupt_mask()\n"); ipc_set_interrupt_mask(); IPC_DEBUG(DBG_TRACE, "Done ipc_set_interrupt_mask()\n"); /* Initialize OS specific callbacks with the IPC lib */ rc = ipc_ipc_init(smbase, size); if (rc) { IPC_DEBUG(DBG_ERROR, "ipc_ipc_init() failed, ret[%d]\n", rc); return rc; } IPC_DEBUG(DBG_TRACE, "ipc_ipc_init done\n"); /* Register Endpoints */ rc = ipcs_ccb_init(isReset); if (rc) { IPC_DEBUG(DBG_ERROR, "ipcs_ccb_init() failed, ret[%d]\n", rc); return rc; } IPC_DEBUG(DBG_TRACE, "ipcs_ccb_init done\n"); /* Let CP know that we are done registering endpoints */ IPC_Configured(); /* Wait for IPC initialized */ IPC_DEBUG(DBG_TRACE, "IPC_Configured() invoked\n"); return 0; }
/************************************************* * Loads the image into RAM. * * @param len (in) The size of the image. * @param p_data (in) Pointer to the image data. * @param addr (in) The RAM address to load the image into. * * @return Returns 0 on success, non-zero otherwise. * *****************************************************/ static int DownloadFirmware(uint32_t len, const uint8_t *p_data, uint32_t addr) { void __iomem *virtAddr; int ret = 0; IPC_DEBUG(DBG_INFO, "Downloading %d bytes from %p to address %p\n", len, (void *)p_data, (void *)addr); virtAddr = ioremap_nocache(addr, len); if (NULL == virtAddr) { IPC_DEBUG(DBG_ERROR, "*** ERROR: ioremap_nocache failed\n"); ret = -1; } else { IPC_DEBUG(DBG_INFO, "copying to virtual addr %p\n", (void *)virtAddr); memcpy(virtAddr, p_data, len); iounmap(virtAddr); } return ret; }
/** * unsigned int bcm_map_virt_to_phys(void *virt_addr); */ unsigned int bcm_map_virt_to_phys(void *virt_addr) { /** * Note: since shared-mem is io-mem, these kernel call to map * virt to phys does not work * * return((unsigned int)virt_to_phys(virt_addr)); */ IPC_DEBUG(DBG_TRACE, "should not be used on this address\n"); return 0; }
/** * void *bcm_map_phys_to_virt(unsigned int physical_addr); */ void *bcm_map_phys_to_virt(unsigned int physical_addr) { /** * Note: since shared-mem is io-mem, these kernel call to map * phys to virt does not work * * return((void *)phys_to_virt((unsigned long)physical_addr)); */ IPC_DEBUG(DBG_TRACE, "should not be used on this address\n"); return NULL; }
/************************************************* * Loads the image into RAM. * * @param len (in) The size of the image. * @param p_data (in) Pointer to the image data. * @param addr (in) The RAM address to load the image into. * * @return Returns 0 on success, non-zero otherwise. * *****************************************************/ static int DownloadFirmware(uint32_t len, const uint8_t *p_data, uint32_t addr) { void __iomem *virtAddr; int ret = 0; int count; int chunk_size; IPC_DEBUG(DBG_INFO, "Downloading %d bytes from %p to address %p\n", len, (void *)p_data, (void *)addr); chunk_size = (VIRTUAL_MEM_CHUNK_SIZE > len) ? len : VIRTUAL_MEM_CHUNK_SIZE; for (count = 0; count < len; count += chunk_size) { if (count + chunk_size > len) { /* chunk size is too large for last segment */ chunk_size = len - count; IPC_DEBUG(DBG_INFO, "*** chunk_size: truncated to %d\n", chunk_size); } virtAddr = ioremap_nocache(addr + count, chunk_size); if (NULL == virtAddr) { IPC_DEBUG(DBG_ERROR, "*** ERROR: ioremap_nocache failed\n"); ret = -1; break; } else { IPC_DEBUG(DBG_INFO, "[%d] copying to virtual addr %p\n", count, (void *)virtAddr); memcpy(virtAddr, p_data + count, chunk_size); iounmap(virtAddr); } } return ret; }
static void *EventCreate(void) { struct IPC_Evt_t *ipcEvt; ipcEvt = kmalloc(sizeof(struct IPC_Evt_t), GFP_ATOMIC); if (!ipcEvt) { IPC_DEBUG(DBG_ERROR, "IPC event create fail\n"); return NULL; } init_waitqueue_head(&(ipcEvt->evt_wait)); ipcEvt->evt = 0; return ipcEvt; }
/********************************************************************* * * Retrieve string from physical address * * @param inPhysAddr (in) Physical address of string. * @param inStrBuf (in) Pointer to buffer to copy string into. * @param inStrBufLen (in) Size of inStrBuf in bytes. * @return Null terminated string from physical address is * copied in to buffer pointed to by inStrBuf. * ***********************************************************************/ void GetStringFromPA(UInt32 inPhysAddr, char *inStrBuf, UInt32 inStrBufLen) { void __iomem *virtAddr; virtAddr = plat_ioremap_ns((unsigned long __force) get_vaddr(IPC_CP_STRING_MAP_AREA), IPC_CP_STRING_MAP_AREA_SZ, (phys_addr_t)inPhysAddr); if (!virtAddr) { IPC_DEBUG(DBG_ERROR, "ioremap failed in GetStringFromPA\n"); return; } strncpy(inStrBuf, (char *)virtAddr, inStrBufLen); /* pad NULL in the end of the string */ inStrBuf[inStrBufLen - 1] = '\0'; plat_iounmap_ns(get_vaddr(IPC_CP_STRING_MAP_AREA), free_size_ipc(IPC_CP_STRING_MAP_AREA_SZ)); }
static irqreturn_t ipcs_interrupt(int irq, void *dev_id) { //IPC_DEBUG(DBG_INFO, "[ipc]: ipcs_interrupt\n"); // check for early CP interrupt if( 1 == g_ipc_info.ap_ipc_init_done ) { #ifdef CONFIG_HAS_WAKELOCK wake_lock(&ipc_wake_lock); #endif queue_work(g_ipc_info.intr_workqueue, &g_ipc_info.intr_work); } else { // if we're interrupted before IPC is setup, that // means CP has had an early crash.... IPC_DEBUG(DBG_INFO, "[ipc]: abnormal CP interrupt\n"); sEarlyCPInterrupt = 1; } return IRQ_HANDLED; }
// Receive a value via IPC and return it. // If 'pg' is nonnull, then any page sent by the sender will be mapped at // that address. // If 'from_env_store' is nonnull, then store the IPC sender's envid in // *from_env_store. // If 'perm_store' is nonnull, then store the IPC sender's page permission // in *perm_store (this is nonzero iff a page was successfully // transferred to 'pg'). // If the system call fails, then store 0 in *fromenv and *perm (if // they're nonnull) and return the error. // Otherwise, return the value sent by the sender // // Hint: // Use 'thisenv' to discover the value and who sent it. // If 'pg' is null, pass sys_ipc_recv a value that it will understand // as meaning "no page". (Zero is not the right value, since that's // a perfectly valid place to map a page.) int32_t ipc_recv(envid_t *from_env_store, void *pg, int *perm_store) { // LAB 4: Your code here. void *dstva; int r; if (pg == NULL) { dstva = (void *)~0; } else { dstva = pg; } IPC_DEBUG("ipc_recv: dstva = %p\n", dstva); r = sys_ipc_recv(dstva); if (r < 0) { if (from_env_store) { *from_env_store = 0; } if (perm_store) { *perm_store = 0; } return r; } if (from_env_store) { *from_env_store = thisenv->env_ipc_from; } if (perm_store) { *perm_store = thisenv->env_ipc_perm; } return thisenv->env_ipc_value; }
void ipcs_intr_workqueue_process(struct work_struct *work) { static int first = 1; if (first) { first = 0; set_user_nice(current, -16); } if(IpcCPCrashCheck()) { cp_crashed = 1; if( BCMLOG_CPCRASH_MTD == BCMLOG_GetCpCrashDumpDevice() ) { /* we kill AP when CP crashes */ IPC_DEBUG(DBG_INFO, "Crashing AP now...\n\n"); #if defined(CONFIG_SEC_DEBUG) cp_abort(); #else abort(); #endif } else { schedule_work(&g_ipc_info.cp_crash_dump_wq); } IPC_ProcessEvents(); }else { IPC_ProcessEvents(); #ifdef CONFIG_HAS_WAKELOCK wake_unlock(&ipc_wake_lock); #endif // CONFIG_HAS_WAKELOCK } }
static int CP_Boot(void) { int started = 0; void __iomem *cp_boot_itcm; void __iomem *cp_bmodem_r4cfg; unsigned int r4init; unsigned int jump_instruction = 0xEA000000; #define BMODEM_SYSCFG_R4_CFG0 0x3a004000 #define CP_SYSCFG_BASE_SIZE 0x8 #define CP_ITCM_BASE_SIZE 0x1000 /* 1 4k page */ IPC_DEBUG(DBG_TRACE, "enter\n"); cp_bmodem_r4cfg = ioremap(BMODEM_SYSCFG_R4_CFG0, CP_SYSCFG_BASE_SIZE); if (!cp_bmodem_r4cfg) { IPC_DEBUG(DBG_ERROR, "BMODEM_SYSCFG_R4_CFG0=0x%x, CP_SYSCFG_BASE_SIZE=0x%x\n", BMODEM_SYSCFG_R4_CFG0, CP_SYSCFG_BASE_SIZE); IPC_DEBUG(DBG_ERROR, "ioremap cp_bmodem_r4cfg failed\n"); return started; } r4init = *(unsigned int *)(cp_bmodem_r4cfg); /* check if the CP is already booted, and if not, then boot it */ if ((0x5 != (r4init & 0x5))) { IPC_DEBUG(DBG_TRACE, "boot (R4 COMMS) - init code 0x%x ...\n", r4init); /* Set the CP jump to address. CP must jump to DTCM offset 0x400 */ cp_boot_itcm = ioremap(MODEM_ITCM_ADDRESS, CP_ITCM_BASE_SIZE); if (!cp_boot_itcm) { IPC_DEBUG(DBG_ERROR, "MODEM_ITCM_ADDRESS=0x%x, CP_ITCM_BASE_SIZE=0x%x\n", MODEM_ITCM_ADDRESS, CP_ITCM_BASE_SIZE); IPC_DEBUG(DBG_ERROR, "ioremap cp_boot_itcm failed\n"); return 0; } /* generate instruction for reset vector that jumps to start of * cp_boot.img at 0x20400 */ jump_instruction |= (0x00FFFFFFUL & (((0x10000 + RESERVED_HEADER) / 4) - 2)); IPC_DEBUG(DBG_TRACE, "cp_boot_itcm 0x%x jump_instruction 0x%x\n", (unsigned int)cp_boot_itcm, jump_instruction); /* write jump instruction to cp reset vector */ *(unsigned int *)(cp_boot_itcm) = jump_instruction; iounmap(cp_boot_itcm); /* start CP - should jump to 0x20400 and spin there */ *(unsigned int *)(cp_bmodem_r4cfg) = 0x5; } else { IPC_DEBUG(DBG_TRACE, "(R4 COMMS) already started - init code 0x%x ...\n", r4init); } iounmap(cp_bmodem_r4cfg); IPC_DEBUG(DBG_TRACE, "exit\n"); return started; }
void CPReset_Timer_Callback(unsigned long data) { /* not all IPC/RPC clients ackd the reset in time, so crash AP */ IPC_DEBUG(DBG_INFO, "cp reset timeout %ld jiffies\n", jiffies); BUG(); }
/**************************************************************** ** * Utility function to retrieve full CP RAM dump log for crash log * * *******************************************************************/ void DUMP_CPMemoryByList(struct T_RAMDUMP_BLOCK *mem_dump) { UInt32 i, offset; void __iomem *RamDumpBlockVAddr = NULL; struct T_RAMDUMP_BLOCK *pBlockVAddr = NULL; RamDumpBlockVAddr = ioremap_nocache((UInt32)(mem_dump), (MAX_RAMDUMP_BLOCKS * sizeof(struct T_RAMDUMP_BLOCK))); if (NULL == RamDumpBlockVAddr) { IPC_DEBUG(DBG_ERROR, "failed to remap RAM dump block addr\n"); return; } pBlockVAddr = (struct T_RAMDUMP_BLOCK *)RamDumpBlockVAddr; BCMLOG_LogCPCrashDumpString("===== COMMS PROCESSOR memory dump ====="); i = 0; while (i < MAX_RAMDUMP_BLOCKS && pBlockVAddr[i].name[0] != '\0' && pBlockVAddr[i].mem_size != 0) { if (pBlockVAddr[i].mem_start == SIM_DEBUG_DATA) { offset = (pBlockVAddr[i].name[4] << 24) + (pBlockVAddr[i].name[5] << 16) + (pBlockVAddr[i].name[6] << 8) + pBlockVAddr[i].name[7]; snprintf(assert_buf, ASSERT_BUF_SIZE, "FLASH DUMP: %8s, start=0x%08x, size=0x%08x, image_start=0x%08x, offset_in_image=0x%08x", pBlockVAddr[i].name, pBlockVAddr[i].mem_start, pBlockVAddr[i].mem_size, 0, /* MSP_IMAGE_ADDR, */ (int)offset); } else if (pBlockVAddr[i].mem_start == SIM_AP_DEBUG_DATA) { offset = (pBlockVAddr[i].name[4] << 24) + (pBlockVAddr[i].name[5] << 16) + (pBlockVAddr[i].name[6] << 8) + pBlockVAddr[i].name[7]; snprintf(assert_buf, ASSERT_BUF_SIZE, "FLASH DUMP: %8s, start=0x%08x, size=0x%08x, image_start=0x%08x, offset_in_image=0x%08x", pBlockVAddr[i].name, pBlockVAddr[i].mem_start, pBlockVAddr[i].mem_size, 0, /* AP_IMAGE_ADDR, */ (int)offset); } else { snprintf(assert_buf, ASSERT_BUF_SIZE, "RAM DUMP: %8s, start=0x%08x, size=0x%08x, buffer_in_main=0x%08x", pBlockVAddr[i].name, pBlockVAddr[i].mem_start, pBlockVAddr[i].mem_size, pBlockVAddr[i].buffer_in_main); } BCMLOG_LogCPCrashDumpString(assert_buf); i++; } i = 0; while (i < MAX_RAMDUMP_BLOCKS && pBlockVAddr[i].name[0] != '\0' && pBlockVAddr[i].mem_size != 0) { if (pBlockVAddr[i].mem_start == SIM_DEBUG_DATA) { offset = (pBlockVAddr[i].name[4] << 24) + (pBlockVAddr[i].name[5] << 16) + (pBlockVAddr[i].name[6] << 8) + pBlockVAddr[i].name[7]; BCMLOG_LogCPCrashDumpString(pBlockVAddr[i].name); snprintf(assert_buf, ASSERT_BUF_SIZE, "FLASH DUMP Begin: 0x%08x, 0x%08x", pBlockVAddr[i].mem_start, pBlockVAddr[i].mem_size); BCMLOG_LogCPCrashDumpString(assert_buf); /* **FIXME** MAG - flash dump not supported yet... */ /* DUMP_CompressedFlash(cpu, pBlockVAddr[i].mem_start, pBlockVAddr[i].mem_size, MSP_IMAGE_ADDR, offset); */ BCMLOG_LogCPCrashDumpString ("*** FLASH DUMP NOT SUPPORTED YET ***"); snprintf(assert_buf, ASSERT_BUF_SIZE, "FLASH DUMP End: 0x%08x, 0x%08x", pBlockVAddr[i].mem_start, pBlockVAddr[i].mem_size); BCMLOG_LogCPCrashDumpString(assert_buf); } else if (pBlockVAddr[i].mem_start == SIM_AP_DEBUG_DATA) { offset = (pBlockVAddr[i].name[4] << 24) + (pBlockVAddr[i].name[5] << 16) + (pBlockVAddr[i].name[6] << 8) + pBlockVAddr[i].name[7]; BCMLOG_LogCPCrashDumpString(pBlockVAddr[i].name); snprintf(assert_buf, ASSERT_BUF_SIZE, "FLASH DUMP Begin: 0x%08x, 0x%08x", pBlockVAddr[i].mem_start, pBlockVAddr[i].mem_size); BCMLOG_LogCPCrashDumpString(assert_buf); /* **FIXME** MAG - flash dump not supported yet... */ BCMLOG_LogCPCrashDumpString ("*** FLASH DUMP NOT SUPPORTED YET ***"); /* DUMP_CompressedFlash(cpu, pBlockVAddr[i].mem_start, pBlockVAddr[i].mem_size, AP_IMAGE_ADDR, offset); */ snprintf(assert_buf, ASSERT_BUF_SIZE, "FLASH DUMP End: 0x%08x, 0x%08x", pBlockVAddr[i].mem_start, pBlockVAddr[i].mem_size); BCMLOG_LogCPCrashDumpString(assert_buf); } else if (pBlockVAddr[i].buffer_in_main == 0xFFFFFFFF) { BCMLOG_LogCPCrashDumpString(pBlockVAddr[i].name); snprintf(assert_buf, ASSERT_BUF_SIZE, "RAM DUMP Begin: 0x%08x, 0x%08x", pBlockVAddr[i].mem_start, pBlockVAddr[i].mem_size); BCMLOG_LogCPCrashDumpString(assert_buf); /* BCMLOG_HandleCpCrashMemDumpData takes physical address... */ BCMLOG_HandleCpCrashMemDumpData((const char *) pBlockVAddr [i].mem_start, pBlockVAddr [i].mem_size); snprintf(assert_buf, ASSERT_BUF_SIZE, "RAM DUMP End: 0x%08x, 0x%08x", pBlockVAddr[i].mem_start, pBlockVAddr[i].mem_size); BCMLOG_LogCPCrashDumpString(assert_buf); } i++; } iounmap(RamDumpBlockVAddr); }
/****************************************************************** * 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; #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 */ }
/************************************************* * Loads the image with the given name into RAM. * * @param p_device (in) The kernel device. * @param p_name (in) The image name. This image file must be located * in /vendor/firmware. * @param addr (in) The RAM address to load the image into. * @param expectedSize (in) The expected size of the image file, or 0 * if the size is to be calculated. * *****************************************************/ static int32_t LoadFirmware(struct device *p_device, const char *p_name, int addr, int expectedSize) { const struct firmware *fw; int32_t err; int imgSize; IPC_DEBUG(DBG_INFO, "calling request_firmware for %s, device=%p\n", p_name, p_device); /** call kernel to start firmware load **/ /* request_firmware(const struct firmware **fw, * const char *name, * struct device *device); */ err = request_firmware(&fw, p_name, p_device); if (err) { IPC_DEBUG(DBG_ERROR, "firmware request failed (%d)\n", err); return err; } if (fw) IPC_DEBUG(DBG_INFO, "fw->size=%d\n", fw->size); else { /*Coverity Complaint: FORWARD_NULL */ IPC_DEBUG(DBG_INFO, "fw = NULL!\n"); return err; } imgSize = fw->size; if (expectedSize == 0) { UInt8 *ptr; /* This is the main CP image */ if (IsCommsImageValid(fw->data)) IPC_DEBUG(DBG_INFO, "verified CP image\n"); else IPC_DEBUG(DBG_ERROR, "failed to verify main image\n"); ptr = ((UInt8 *)fw->data) + CP_IMAGE_SIZE_OFFSET; imgSize = (ptr[3] << 24) | (ptr[2] << 16) | (ptr[1] << 8) | ptr[0]; IPC_DEBUG(DBG_INFO, "calculated CP image size = 0x%x\n", imgSize); } else if (expectedSize != imgSize) { if (imgSize > expectedSize) { IPC_DEBUG(DBG_ERROR, "ERROR: fw->size > expected (0x%x > 0x%x)\n", fw->size, expectedSize); imgSize = expectedSize; } else IPC_DEBUG(DBG_ERROR, "ERROR: fw->size < expected (0x%x < 0x%x)\n", fw->size, expectedSize); } /** download to chip **/ err = DownloadFirmware(imgSize, fw->data, addr); /* Verify CP image @ RAM addr */ if (expectedSize == 0) { void __iomem *virtAddr; virtAddr = ioremap_nocache(addr, fw->size); if (virtAddr) { int retval; /* This is the main CP image */ if (IsCommsImageValid(virtAddr)) IPC_DEBUG(DBG_INFO, "verified CP image @ %p\n", (void *)addr); else IPC_DEBUG(DBG_ERROR, "failed to verify main image @ %p\n", (void *)addr); retval = memcmp(fw->data, virtAddr, imgSize); IPC_DEBUG(DBG_INFO, "memcmp(%p, %p, 0x%x) = %d\n", (void *)fw->data, virtAddr, imgSize, retval); iounmap(virtAddr); } else { IPC_DEBUG(DBG_ERROR, "*** ERROR: ioremap_nocache FAILED for addr %p\n", (void *)addr); } } /** free kernel structure */ release_firmware(fw); return err; }
static int __init ipcs_module_init(void) { int rc = 0; int readyChkCnt = 0; struct timespec startTime, endTime; IPC_DEBUG(DBG_INFO,"[ipc]: ipcs_module_init start..\n"); init_MUTEX_LOCKED(&g_ipc_info.ipc_sem); g_ipc_info.ipc_state = 0; g_ipc_info.devnum = MKDEV(IPC_MAJOR, 0); rc = register_chrdev_region(g_ipc_info.devnum, 1, "bcm_fuse_ipc"); if (rc < 0) { IPC_DEBUG(DBG_ERROR,"Error registering the IPC device\n"); goto out; } cdev_init(&g_ipc_info.cdev, &ipc_ops); g_ipc_info.cdev.owner = THIS_MODULE; rc = cdev_add(&g_ipc_info.cdev, g_ipc_info.devnum, 1); if (rc) { IPC_DEBUG(DBG_ERROR,"[ipc]: cdev_add errpr\n"); goto out_unregister; } IPC_DEBUG(DBG_INFO, "[ipc]: create_workqueue\n"); INIT_WORK(&g_ipc_info.cp_crash_dump_wq, ProcessCPCrashedDump); INIT_WORK(&g_ipc_info.intr_work, ipcs_intr_workqueue_process); g_ipc_info.intr_workqueue = create_workqueue("ipc-wq"); if (!g_ipc_info.intr_workqueue) { IPC_DEBUG(DBG_ERROR,"[ipc]: cannot create workqueue\n"); goto out_unregister; } IPC_DEBUG(DBG_INFO, "[ipc]: request_irq\n"); rc = request_irq(IRQ_IPC_C2A, ipcs_interrupt, IRQF_NO_SUSPEND, "ipc-intr", &g_ipc_info); if (rc) { IPC_DEBUG(DBG_ERROR,"[ipc]: request_irq error\n"); goto out_del; } /** Make sure this is not cache'd because CP has to know about any changes we write to this memory immediately. */ IPC_DEBUG(DBG_INFO, "[ipc]: ioremap_nocache IPC_BASE\n"); g_ipc_info.apcp_shmem = ioremap_nocache(IPC_BASE, IPC_SIZE); if (!g_ipc_info.apcp_shmem) { rc = -ENOMEM; IPC_DEBUG(DBG_ERROR,"[ipc]: Could not map shmem\n"); goto out_del; } #ifdef CONFIG_HAS_WAKELOCK wake_lock_init(&ipc_wake_lock, WAKE_LOCK_SUSPEND, "ipc_wake_lock"); #endif IPC_DEBUG(DBG_INFO, "[ipc]: ipcs_init\n"); if (ipcs_init((void *)g_ipc_info.apcp_shmem, IPC_SIZE)) { rc = -1; IPC_DEBUG(DBG_ERROR,"[ipc]: ipcs_init() failed\n"); goto out_del; } if ( sEarlyCPInterrupt ) { IPC_DEBUG(DBG_INFO,"[ipc]: early CP interrupt - doing crash dump...\n"); #ifdef CONFIG_HAS_WAKELOCK wake_lock(&ipc_wake_lock); #endif schedule_work(&g_ipc_info.cp_crash_dump_wq); } // check for AP only boot mode if ( AP_ONLY_BOOT == get_ap_boot_mode() ) { IPC_DEBUG(DBG_INFO,"[ipc]: AP only boot - not waiting for CP\n"); } else { // wait for CP to have IPC setup as well; if we exit module init // before IPC is ready, RPC module will likely crash during its // own init startTime = current_kernel_time(); while ( !g_ipc_info.ipc_state ) { IPC_DEBUG(DBG_INFO, "[ipc]: CP IPC not ready, sleeping...\n"); msleep(20); readyChkCnt++; if ( readyChkCnt > 100 ) { IPC_DEBUG(DBG_ERROR, "[ipc]: IPC init timeout - no response from CP\n"); rc = -1; goto out_del; } } endTime = current_kernel_time(); IPC_DEBUG(DBG_INFO,"readyChkCnt=%d time=%ldus\n", readyChkCnt, ((endTime.tv_sec - startTime.tv_sec)*1000000L+(endTime.tv_nsec - startTime.tv_nsec)/1000L)); IPC_DEBUG(DBG_INFO,"[ipc]: ipcs_module_init ok\n"); } return 0; out_del: cdev_del(&g_ipc_info.cdev); out_unregister: unregister_chrdev_region(g_ipc_info.devnum, 1); out: IPC_DEBUG(DBG_ERROR,"IPC Driver Failed to initialise!\n"); return rc; }
static int __init ipcs_module_init(void) { int rc = -1; struct proc_dir_entry *dir; dir = create_proc_read_entry("driver/bcmipc", 0, NULL, ipcs_read_proc, NULL); if (dir == NULL) { IPC_DEBUG(DBG_ERROR, "ipcs_module_init: can't create /proc/driver/bcmipc\n"); //return -1; } IPC_DEBUG(DBG_TRACE, "start ...\n"); g_ipc_info.ipc_state = 0; g_ipc_info.mDriverClass = class_create(THIS_MODULE, BCM_KERNEL_IPC_NAME); if (IS_ERR(g_ipc_info.mDriverClass)) { IPC_DEBUG(DBG_ERROR, "driver class_create failed\n"); goto out; } g_ipc_info.drvdata = device_create(g_ipc_info.mDriverClass, NULL, MKDEV(IPC_MAJOR, 0), NULL, BCM_KERNEL_IPC_NAME); if (IS_ERR(g_ipc_info.drvdata)) { IPC_DEBUG(DBG_ERROR, "device_create drvdata failed\n"); goto out; } IPC_DEBUG(DBG_TRACE, "Allocate CP crash dump workqueue\n"); g_ipc_info.crash_dump_workqueue = alloc_workqueue("dump-wq", WQ_FREEZABLE | WQ_MEM_RECLAIM, 0); if (!g_ipc_info.crash_dump_workqueue) { IPC_DEBUG(DBG_ERROR, "Cannot allocate CP crash dump workqueue\n"); goto out; } INIT_WORK(&g_ipc_info.cp_crash_dump_wq, ProcessCPCrashedDump); tasklet_init(&g_ipc_info.intr_tasklet, ipcs_intr_tasklet_handler, 0); /** Make sure this is not cache'd because CP has to know about any changes we write to this memory immediately. */ IPC_DEBUG(DBG_TRACE, "ioremap_nocache IPC_BASE\n"); g_ipc_info.apcp_shmem = ioremap_nocache(IPC_BASE, IPC_SIZE); if (!g_ipc_info.apcp_shmem) { rc = -ENOMEM; IPC_DEBUG(DBG_ERROR, "Could not map shmem\n"); goto out_shared_mem_fail; } IPC_DEBUG(DBG_TRACE, "ipcs_init\n"); if (ipcs_init((void *)g_ipc_info.apcp_shmem, IPC_SIZE, 0)) { rc = -1; IPC_DEBUG(DBG_ERROR, "ipcs_init() failed\n"); goto out_ipc_init_fail; } IPC_DEBUG(DBG_TRACE, "ok\n"); #ifdef CONFIG_HAS_WAKELOCK wake_lock_init(&ipc_wake_lock, WAKE_LOCK_SUSPEND, "ipc_wake_lock"); #endif IPC_DEBUG(DBG_TRACE, "request_irq\n"); rc = request_irq(IRQ_IPC_C2A, ipcs_interrupt, IRQF_NO_SUSPEND, "ipc-intr", &g_ipc_info); if (rc) { IPC_DEBUG(DBG_ERROR, "request_irq error\n"); goto out_irq_req_fail; } IPC_DEBUG(DBG_TRACE, "IRQ Clear and Enable\n"); return 0; out_irq_req_fail: wake_lock_destroy(&ipc_wake_lock); out_ipc_init_fail: iounmap(g_ipc_info.apcp_shmem); out_shared_mem_fail: flush_workqueue(g_ipc_info.crash_dump_workqueue); destroy_workqueue(g_ipc_info.crash_dump_workqueue); out: IPC_DEBUG(DBG_ERROR, "IPC Driver Failed to initialise!\n"); return rc; }