/******************************************************************
*   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

}