| /*-------------------------------------------------------------------------------------------------------------------- |
| (C) Copyright 2006, 2007 Marvell DSPC Ltd. All Rights Reserved. |
| -------------------------------------------------------------------------------------------------------------------*/ |
| |
| /***************************************/ |
| //exception handler |
| /***************************************/ |
| #include <stdio.h> |
| #include <string.h> |
| #include "loadTable.h" |
| #include "pxa_dbg.h" |
| #include "utilities.h" |
| #include "EEHandler.h" |
| #include "EE_Postmortem.h" |
| #include "EEHandler_int.h" |
| |
| |
| #define DBGTRACE(...) |
| //#define DBGTRACE ERRMSG |
| |
| |
| #define Sleep(X) usleep((X) * 1000) |
| |
| extern eehCfg_t eehCfg; |
| extern UINT32 EE_AssistingMaster_ASSERT_found; |
| UINT32 SysEeHandlerEntryCntr; |
| |
| /*----------- Globals --------------------------------------------------------*/ |
| |
| /*----------- Local defines --------------------------------------------------*/ |
| |
| /*----------- Local macro definitions ----------------------------------------*/ |
| |
| /*----------- Local macro definitions ----------------------------------------*/ |
| |
| /*----------- Local type definitions -----------------------------------------*/ |
| // Optional actions that can be disabled or enabled based on configuration and scenario (risk) |
| typedef enum |
| { |
| EE_MODE_NONE, |
| EE_MODE_DEFERRED = 1, |
| EE_MODE_INTERMEDIATE = 2, |
| EE_MODE_LOG = 4, |
| EE_MODE_ALLOW_EXT = 8, |
| EE_MODE_LEDS = 0x10, |
| EE_MODE_DEFERRED_INTERMEDIATE = 0x20 |
| } EE_Mode_t; |
| |
| /*----------- Local variable definitions -------------------------------------*/ |
| #define EELOG_MAX_STREAMS 10 |
| static UINT32 NumLogstreams; |
| |
| //====================== SYSTEM EXCEPTION HANDLER ===================== |
| // Relevant only for system running on APP+COMM processors |
| // and only for APP side |
| #define SYSEE_TASK_PRIORITY 100 |
| #define SYSEE_STACK_SIZE 2048 |
| |
| typedef enum |
| { |
| SYSEE_TASK_ACTION_COMMWDT = 1, // 1<<0 |
| SYSEE_EVENT_MASK = 0x0F |
| } |
| SysEeActionEnum; |
| |
| UINT32 EELOG_shareReadFWrite(void); |
| |
| /*********************************************************************************** |
| * |
| * Logging EE messsage stream into NVRAM file |
| * |
| ************************************************************************************/ |
| |
| #define SYNC_INFO(COND, PTR) syncStateInfo(COND, PTR, __LINE__) |
| |
| #define RECOD_SIZE (1024 * 56) /* 12k */ |
| #define EELOG_NUM_RECORDS 1 /* 2 buffers */ |
| #define STREAM_OPEN_MAGIC (UINT32)(0x50495045) /*0x50495045 mapping to multi-character character constant 'PIPE' */ |
| |
| /**** Stream-Name is 7characters+\0 (e.g. "1234567"). |
| * Resulting File-Name will be "com_1234567.bin". The "com_" and ".bin" added by server |
| * Default names are: |
| * "com_DTCM.bin" |
| * "com_GB_RAM.bin" |
| * "com_RAMLOG.bin" |
| ***/ |
| #define STREAM_NAME_SIZE (7 + 1) |
| #define FILESTREAM_NAME_SIZE (15 + 1) |
| |
| typedef enum |
| { |
| EELOG_NONE = 0x00000000L, |
| EELOG_OPEN, |
| EELOG_RECORD_READY, |
| EELOG_CLOSE |
| } |
| EElogCmdState; |
| |
| //Always use Long to be complient to WIN compiler. Pay attention for ENUM size |
| typedef struct |
| { |
| UINT32 AcStreamOpenedValid; // <--STREAM_OPEN_MAGIC |
| EElogCmdState cmdState; |
| UINT32 putIdx; |
| UINT32 bytesReady [EELOG_NUM_RECORDS]; |
| UINT32 recordBufPtr [EELOG_NUM_RECORDS]; |
| int blockSize; |
| int lastBlockClosed; |
| char streamName[STREAM_NAME_SIZE]; |
| UINT32 ackNo; |
| //---------------------- for backward Client/Server compatibility add new fields belo this line |
| UINT32 NumLogstreams; |
| } |
| EElogStreamHeader; |
| // \\\_____Stream recordBuf-s are placed after EElogStreamHeader but not a part of the EElogStreamHeader |
| |
| //--------------------------------------------------------------- |
| |
| EElogStreamHeader* pEeLogStream; |
| |
| static void EELOG_CloseStream(BOOL isFileServer); |
| |
| //--------------------------------------------------------------- |
| #define EELOG_TIMEOUT_SHORT_MS 3000 |
| #define EELOG_TIMEOUT_MS 6000 |
| #define EELOG_TIMEOUT_BIG_MS 10000 |
| #define EELOG_TIMEOUT_HUGE_MS 100000 |
| |
| #define EELOG_DELAY_MULT_FACTOR 12 |
| #define RATE_64uS_1mS 4 //1mS/64uS = 16 = 2e4 |
| #define DELAY_64uS_SEC EELOG_Delay64uS(1, 0) |
| |
| UINT32 EELOG_Delay64uS(UINT32 numCycles, UINT32 dummyZero) |
| { |
| UINT32 i = (numCycles << EELOG_DELAY_MULT_FACTOR); |
| |
| while (i != dummyZero) |
| i--; |
| return(i); |
| } |
| |
| //--------------------------------------------------------------- |
| BOOL EELOG_WaitForEQ(UINT32* pV1, UINT32* pV2, UINT32 abortDelta, UINT32 timeoutMS) |
| { |
| UINT32 retryCycles64uS = timeoutMS << RATE_64uS_1mS; |
| |
| while (1) |
| { |
| if (*pV1 == *pV2) |
| return(TRUE); //Condition hit |
| if (abortDelta < (*pV1 - *pV2)) |
| break; //Waiting aborted |
| if (retryCycles64uS-- == 0) |
| break; //Time-out |
| DELAY_64uS_SEC; |
| } |
| return(FALSE); |
| } |
| |
| BOOL EELOG_WaitForAck(EElogStreamHeader* p, UINT32 timeoutMS) |
| { |
| return |
| EELOG_WaitForEQ(&(p->putIdx), &(p->ackNo), (EELOG_NUM_RECORDS + 1), timeoutMS); |
| } |
| |
| //--------------------------------------------------------------- |
| BOOL EELOG_WaitForState(EElogStreamHeader* p, EElogCmdState state, UINT32 timeoutMS) |
| { |
| UINT32 retryCycles5mS = timeoutMS / 5; |
| |
| while (1) |
| { |
| if (p->cmdState == state) |
| return(TRUE); //Condition hit |
| |
| if (retryCycles5mS-- == 0) |
| break; //Time-out |
| |
| Sleep(1); |
| } |
| return(FALSE); |
| } |
| |
| //--------------------------------------------------------------- |
| BOOL EELOG_WaitForState2(EElogStreamHeader* p, EElogCmdState state, EElogCmdState state2, UINT32 timeoutMS) |
| { |
| UINT32 retryCycles5mS = timeoutMS / 5; |
| |
| while (1) |
| { |
| if ((p->cmdState == state) || (p->cmdState == state2)) |
| return(TRUE); //Condition hit |
| |
| if (retryCycles5mS-- == 0) |
| break; //Time-out |
| |
| Sleep(1); |
| } |
| return(FALSE); |
| } |
| |
| //--------------------------------------------------------- |
| // Every client should register for the EELOG service |
| // There is a counter of registered clients, |
| // and it is used by server to know |
| // how many times EELOG-stream protocol should be applied |
| static UINT32 EELOG_GetNumLogstreams(EElogStreamHeader* p) |
| { |
| UINT32 l_NumLogstreams; |
| |
| if (p == NULL) |
| return 0; |
| l_NumLogstreams = p->NumLogstreams; |
| if (l_NumLogstreams > EELOG_MAX_STREAMS) |
| l_NumLogstreams = EELOG_MAX_STREAMS; |
| return(l_NumLogstreams); |
| } |
| |
| //--------------------------------------------------------------- |
| static EElogStreamHeader* EELOG_OpenStream(BOOL isFileServer, char* nameBuf) |
| { |
| UINT32 begin; |
| UINT32 end; |
| UINT32 i; |
| |
| getAppComShareMemAddr(&begin, &end); |
| |
| begin = (UINT32)ADDR_CONVERT(begin); |
| end = (UINT32)ADDR_CONVERT(end); //to avoid compile warning only |
| |
| pEeLogStream = (EElogStreamHeader*)MAP_PHYSICAL_TO_VIRTUAL_ADDRESS(begin); |
| |
| if (isFileServer) |
| { |
| UINT32 retryCycles5mS = (EELOG_TIMEOUT_BIG_MS / 5); |
| i = retryCycles5mS; |
| |
| while ( (pEeLogStream->AcStreamOpenedValid != STREAM_OPEN_MAGIC) |
| || (pEeLogStream->streamName[0] == 0) |
| || (pEeLogStream->cmdState != EELOG_NONE) ) |
| { |
| if (i-- == 0) return(NULL); //timeout |
| Sleep(1); |
| } |
| |
| if (pEeLogStream->streamName[STREAM_NAME_SIZE - 1] != 0) |
| return(NULL); |
| |
| sprintf(nameBuf, "com_%s.bin", pEeLogStream->streamName); |
| pEeLogStream->ackNo = 0; |
| } |
| else |
| { |
| memset(pEeLogStream, 0, sizeof(EElogStreamHeader)); |
| pEeLogStream->NumLogstreams = NumLogstreams; |
| pEeLogStream->ackNo = 0xFFFFFFFF; |
| pEeLogStream->cmdState = EELOG_NONE; |
| pEeLogStream->blockSize = RECOD_SIZE; |
| |
| //Stream buffers are placed after EElogStreamHeader, so use (pEeLogStream + 1) |
| for (i = 0; i < EELOG_NUM_RECORDS; i++) |
| pEeLogStream->recordBufPtr[i] = (UINT32)ADDR_CONVERT((UINT32)(pEeLogStream + 1) + (pEeLogStream->blockSize * i)); |
| { |
| char *streamName; |
| UINT32 nameLen; |
| // Copy name but check consistency and skip :\ / and '.' |
| nameLen = strlen(nameBuf); |
| if ((nameLen == 0) || (nameLen > 14)) |
| { |
| EELOG_CloseStream(0); return(0); |
| } |
| streamName = strchr(nameBuf, ':'); |
| if (streamName != NULL) nameBuf = streamName + 1; |
| streamName = strchr(nameBuf, '\\'); |
| if (streamName != NULL) nameBuf = streamName + 1; |
| streamName = strchr(nameBuf, '/'); |
| if (streamName != NULL) nameBuf = streamName + 1; |
| streamName = strchr(nameBuf, '.'); |
| if (streamName != NULL) *streamName = 0; |
| nameLen = strlen(nameBuf); |
| if (nameLen == 0) |
| { |
| EELOG_CloseStream(0); return(0); |
| } |
| |
| for (i = 0; i < (STREAM_NAME_SIZE - 1); i++) |
| pEeLogStream->streamName[i] = nameBuf[i]; |
| pEeLogStream->streamName[i] = 0; |
| } |
| pEeLogStream->AcStreamOpenedValid = STREAM_OPEN_MAGIC; |
| } |
| |
| return(pEeLogStream); |
| } |
| |
| static void EELOG_CloseStream(BOOL isFileServer) |
| { |
| if (isFileServer) |
| pEeLogStream->ackNo = pEeLogStream->putIdx + (0xFFFFFFFF / 2); |
| else |
| { |
| pEeLogStream->putIdx++; |
| EELOG_WaitForAck(pEeLogStream, EELOG_TIMEOUT_MS); |
| //0x53544F50 mapping to multi-character character constant 'STOP' |
| pEeLogStream->AcStreamOpenedValid = (UINT32)(0x53544F50); |
| } |
| } |
| |
| static void syncStateInfo(BOOL cond, EElogStreamHeader* p, int line) |
| { |
| #ifdef NODIAG |
| (void)line; |
| #endif |
| if (cond == TRUE) |
| { |
| switch (p->cmdState) |
| { |
| case EELOG_OPEN: |
| DIAG_FILTER(EE_HANDLER, EE_LOG, logOpen, DIAG_INFORMATION) |
| diagPrintf("Logging %s OPEN\n", p->streamName); |
| break; |
| case EELOG_RECORD_READY: |
| DIAG_FILTER(EE_HANDLER, EE_LOG, logBlock, DIAG_INFORMATION) |
| diagPrintf("Logging into %s block %d\n", p->streamName, p->putIdx); |
| break; |
| case EELOG_CLOSE: |
| DIAG_FILTER(EE_HANDLER, EE_LOG, logClose, DIAG_INFORMATION) |
| diagPrintf("Logging %s CLOSE\n", p->streamName); |
| break; |
| default: |
| break; |
| } |
| } |
| else |
| { |
| switch (p->cmdState) |
| { |
| case EELOG_NONE: |
| DIAG_FILTER(EE_HANDLER, EE_LOG, logDbg0, DIAG_INFORMATION) |
| diagPrintf("Line_%d: cmdState_NONE, %d\n", line, p->putIdx); |
| break; |
| case EELOG_OPEN: |
| DIAG_FILTER(EE_HANDLER, EE_LOG, logDbg1, DIAG_INFORMATION) |
| diagPrintf("Line_%d: cmdState_OPEN, %d\n", line, p->putIdx); |
| break; |
| case EELOG_RECORD_READY: |
| DIAG_FILTER(EE_HANDLER, EE_LOG, logDbg2, DIAG_INFORMATION) |
| diagPrintf("Line_%d: cmdState_RECO, %d\n", line, p->putIdx); |
| break; |
| case EELOG_CLOSE: |
| DIAG_FILTER(EE_HANDLER, EE_LOG, logDbg3, DIAG_INFORMATION) |
| diagPrintf("Line_%d: cmdState_CLOSE, %d\n", line, p->putIdx); |
| break; |
| default: |
| DIAG_FILTER(EE_HANDLER, EE_LOG, logDbg4, DIAG_INFORMATION) |
| diagPrintf("Line_%d: cmdState_UNKN, %d\n", line, p->putIdx); |
| break; |
| } |
| } |
| } |
| |
| static BOOL check_cp_if_old_eeh_ver(void) |
| { |
| int ret = 0; |
| unsigned short eeh_type; |
| |
| ret = get_cp_eeh_type(&eeh_type); |
| if (ret != 0) |
| return TRUE; |
| else |
| return (eeh_type != 0xA5A5); |
| } |
| |
| // This is the SERVER. |
| // All addresses are in "client" format and should be converted before using !!! |
| // |
| UINT32 EELOG_shareReadFWrite(void) |
| { |
| EElogStreamHeader* p; |
| UINT32 getIdx, idx; |
| int bytesOk; |
| UINT8* src; |
| FILE* fHandl; |
| char fileName[FILESTREAM_NAME_SIZE]; |
| |
| UINT32 retryCycles5mS; |
| UINT32 l_NumLogstreams = 0; |
| BOOL newFile, is_old_eeh_process, isNeedMove = TRUE; |
| |
| DBGMSG("EELOG_shareReadFWrite"); |
| |
| p = EELOG_OpenStream(1 /*isFileServer*/, fileName); |
| |
| if (p == NULL) |
| return(0); |
| |
| l_NumLogstreams = EELOG_GetNumLogstreams(p); |
| if (l_NumLogstreams == 0) |
| { |
| DBGTRACE("EElogStreamHeader 1: p->AcStreamOpenedValid = %d, p->cmdState = %d, p->putIdx = %d\n", |
| p->AcStreamOpenedValid, p->cmdState, p->putIdx); |
| DBGTRACE("EElogStreamHeader 1: p->blockSize = %d, p->lastBlockClosed = %d, p->streamName = %s\n", |
| p->blockSize, p->lastBlockClosed, p->streamName); |
| DBGTRACE("EElogStreamHeader 1: p->ackNo = %d, p->NumLogstreams = %d, p->bytesReady = %d\n", |
| p->ackNo, p->NumLogstreams, p->bytesReady[0]); |
| return(0); |
| } |
| |
| // Wait for NONE->to->OPEN |
| |
| //SYNC_INFO(p->cmdState == EELOG_NONE, p); |
| |
| if ( EELOG_WaitForState2(p, EELOG_NONE, EELOG_OPEN, EELOG_TIMEOUT_MS) == FALSE) |
| { |
| DBGTRACE("EElogStreamHeader 2: p->AcStreamOpenedValid = %d, p->cmdState = %d, p->putIdx = %d\n", |
| p->AcStreamOpenedValid, p->cmdState, p->putIdx); |
| DBGTRACE("EElogStreamHeader 2: p->blockSize = %d, p->lastBlockClosed = %d, p->streamName = %s\n", |
| p->blockSize, p->lastBlockClosed, p->streamName); |
| DBGTRACE("EElogStreamHeader 2: p->ackNo = %d, p->NumLogstreams = %d, p->bytesReady = %d\n", |
| p->ackNo, p->NumLogstreams, p->bytesReady[0]); |
| |
| DIAG_FILTER(EE_HANDLER, EE_LOG, NoLog, DIAG_INFORMATION) |
| diagPrintf("%s file NOT requested\n", fileName); |
| return(0); |
| } |
| |
| remove((char *)fileName); |
| |
| is_old_eeh_process = check_if_old_eeh_process(fileName, check_cp_if_old_eeh_ver()); |
| //DBGMSG("fileName %s, is old eeh %d\n", fileName, is_old_eeh_process); |
| |
| if (is_old_eeh_process) { |
| fHandl = fopen(fileName, "wb"); |
| if (fHandl == 0) |
| { |
| EELOG_CloseStream(1 /*isFileServer*/); |
| return(0); |
| } |
| DBGMSG("old eeh process for shareRead"); |
| } else { |
| DBGMSG("new eeh process for shareRead"); |
| } |
| |
| SYNC_INFO((p->cmdState == EELOG_OPEN) || (p->cmdState == EELOG_RECORD_READY), p); |
| |
| // Wait for first Record Ready |
| if ( EELOG_WaitForState(p, EELOG_RECORD_READY, EELOG_TIMEOUT_HUGE_MS) == FALSE) |
| { |
| DBGTRACE("EElogStreamHeader 3: p->AcStreamOpenedValid = %d, p->cmdState = %d, p->putIdx = %d\n", |
| p->AcStreamOpenedValid, p->cmdState, p->putIdx); |
| DBGTRACE("EElogStreamHeader 3: p->blockSize = %d, p->lastBlockClosed = %d, p->streamName = %s\n", |
| p->blockSize, p->lastBlockClosed, p->streamName); |
| DBGTRACE("EElogStreamHeader 3: p->ackNo = %d, p->NumLogstreams = %d, p->bytesReady = %d\n", |
| p->ackNo, p->NumLogstreams, p->bytesReady[0]); |
| DIAG_FILTER(EE_HANDLER, EE_LOG, ABNORMAL, DIAG_INFORMATION) |
| diagPrintf("%s: STATE ABNORMAL: opened, but streaming never started\n", p->streamName); |
| l_NumLogstreams = 0; |
| goto END_CLOSE_FILE_AND_STREAM; |
| } |
| SYNC_INFO( TRUE, p); |
| getIdx = 0; |
| |
| // READ from Stream and |
| // WRITE to File |
| retryCycles5mS = EELOG_TIMEOUT_SHORT_MS; |
| |
| while (p->cmdState == EELOG_RECORD_READY) |
| { |
| if (getIdx == p->putIdx) |
| { |
| DPRINTF("Stream: %s: getIdx %d, putIdx %d, retryCycles5mS %d\n", p->streamName, getIdx, p->putIdx, retryCycles5mS); |
| if (retryCycles5mS--) |
| Sleep(1); |
| else |
| { |
| DBGTRACE("EElogStreamHeader 4: p->AcStreamOpenedValid = %d, p->cmdState = %d, p->putIdx = %d\n", |
| p->AcStreamOpenedValid, p->cmdState, p->putIdx); |
| DBGTRACE("EElogStreamHeader 4: p->blockSize = %d, p->lastBlockClosed = %d, p->streamName = %s\n", |
| p->blockSize, p->lastBlockClosed, p->streamName); |
| DBGTRACE("EElogStreamHeader 4: p->ackNo = %d, p->NumLogstreams = %d, p->bytesReady = %d\n", |
| p->ackNo, p->NumLogstreams, p->bytesReady[0]); |
| DIAG_FILTER(EE_HANDLER, EE_LOG, STALL, DIAG_INFORMATION) |
| diagPrintf("%s: RX streaming stalled. ABORT\n", p->streamName); |
| l_NumLogstreams = 0; |
| break; |
| } |
| } |
| else |
| { |
| SYNC_INFO( (p->putIdx - getIdx) <= EELOG_NUM_RECORDS, p); |
| |
| idx = getIdx & (EELOG_NUM_RECORDS - 1); |
| |
| src = (UINT8*)MAP_PHYSICAL_TO_VIRTUAL_ADDRESS(ADDR_CONVERT(p->recordBufPtr[idx])); |
| |
| if (is_old_eeh_process) { |
| bytesOk = fwrite(src, 1, p->bytesReady[idx], fHandl); |
| } else { |
| newFile = (getIdx == 0); |
| EEH_DUMP_ENHANCE_2CPMEM(fileName, src, p->bytesReady[idx], newFile, isNeedMove); |
| bytesOk = p->bytesReady[idx]; |
| } |
| DPRINTF("Stream: %s: bytes %d of %d are written!\n", p->streamName, bytesOk, p->bytesReady[idx]); |
| |
| getIdx++; |
| p->ackNo = getIdx; |
| retryCycles5mS = EELOG_TIMEOUT_SHORT_MS; |
| } |
| } |
| |
| END_CLOSE_FILE_AND_STREAM: |
| |
| if (is_old_eeh_process) { |
| fsync(fileno(fHandl)); |
| fclose(fHandl); |
| } |
| |
| SYNC_INFO((p->cmdState == EELOG_CLOSE), p); |
| DBGMSG("EELOG_shareReadFWrite: END_CLOSE_FILE_AND_STREAM *p = %p, l_NumLogstreams = %d\n", p, l_NumLogstreams); |
| #ifdef EEH_DUMP_ENHANCE |
| if (is_old_eeh_process) |
| record_archive_files(NULL, fileName); |
| #endif |
| EELOG_CloseStream(1 /*isFileServer*/); |
| return(l_NumLogstreams); |
| } |
| |
| void Linux_EELOG_shareReadFWrite() |
| { |
| if (!eehCfg.ramdump_ena) |
| { |
| DBGMSG("%s: ramdump not enable, do nothing", __FUNCTION__); |
| return; |
| } |
| |
| // Do LOG-Stream for ASSERT-found only, otherwise nobody sends EELOGs |
| if ( EE_AssistingMaster_ASSERT_found ) NumLogstreams = 1; |
| else NumLogstreams = 0; |
| |
| if (NumLogstreams > 0) |
| { |
| UINT32 streamNo; |
| for (streamNo = 0; streamNo < NumLogstreams; streamNo++) |
| NumLogstreams = EELOG_shareReadFWrite(); |
| } |
| } |