blob: 837eec4a01c191e91be8cbb16e8d09cf70498edf [file] [log] [blame]
/*--------------------------------------------------------------------------------------------------------------------
(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();
}
}