From e7773db7a70b5cb47e48e0c50a10bb8f05e9832d Mon Sep 17 00:00:00 2001 From: Jim Kowalkowski Date: Tue, 13 May 1997 14:34:40 +0000 Subject: [PATCH] special bus error recovery code for recovery from bus error due to bus extenders --- src/libvxWorks/bus_error_recovery.c | 381 ++++++++++++++++++++++++++++ 1 file changed, 381 insertions(+) create mode 100644 src/libvxWorks/bus_error_recovery.c diff --git a/src/libvxWorks/bus_error_recovery.c b/src/libvxWorks/bus_error_recovery.c new file mode 100644 index 000000000..bb9429a46 --- /dev/null +++ b/src/libvxWorks/bus_error_recovery.c @@ -0,0 +1,381 @@ + +/* + Special case bus error recovery code. + + The code in this file will attempt to retry instructions which caused + bus errors up to 10 times before invoking the standard vxWorks bus + error handler. The code also records the last 20 bus errors so they + can be reported using a utility run from the vxWorks console. Database + records can be used to monitor when bus errors occur - See support + below. + + The bus error handler only processes bus errors outside the processor's + local memory which are normal user/supervisor data accesses. + + ------------------ + epicsBusErrorPrint - Print the last 20 bus errors that occurred. The + report includes: + 1) The bus error number + 2) FA - The fault address + 3) PC - The program counter when the fault occurred + 4) SR - Status register + 5) SSW - Special status word + + ------------- + devAiBusError - Simple EPICS ai record device support. Create an + ai record with DTYP="Bus Error" and SCAN="I/O Intr" to get + informed when a bus error occurs. You may not get informed if the + bus error is handled by vxWorks and an important EPICS task is + suspended as a result. You will always be notified of a bus + error that has been corrected by retries. The ai record will + count up every time if is processed. The bus error handler triggers + processing of the record if the SCAN type is "I/O Intr". + + If a bus error is handled by vxWorks and you do not get notified via + the ai record, you can sign on the console and run epicsBusErrorPrint + and see the last 20 bus errors that occurred. + + Add the following line to the cat_ascii/devSup.ascii file: + "ai" VME_IO "devAiBusError" "Bus Error" + + ---------------------- + epicsBusErrorInit68040 + Initialize the bus error handling system. ONLY needs to be run if + a bus error monitoring record is NOT present in the database. The + ai record device support above runs with function automatically. You + need to run this function before iocInit in your vxWorks startup + script if you do not use the ai record support described above and + have a record for it in the database. + +*/ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +struct accessFault +{ + unsigned short sr; /* status reg */ + unsigned short* pc; /* program counter */ + unsigned short vo; /* vector offset */ + unsigned long ea; /* effective address */ + unsigned short ssw; /* special status word */ + unsigned short wb3s; /* write-back 3 status */ + unsigned short wb2s; /* write-back 2 status */ + unsigned short wb1s; /* write-back 1 status */ + unsigned char * fa; /* fault address */ + union { + unsigned long* l; unsigned short* s; unsigned char * c; + } wb3a; /* write-back 3 address */ + union { + unsigned long l; unsigned short s; unsigned char c; + } wb3d; /* write-back 3 */ + union { + unsigned long* l; unsigned short* s; unsigned char * c; + } wb2a; /* write-back 2 address */ + union { + unsigned long l; unsigned short s; unsigned char c; + } wb2d; /* write-back 2 */ + union { + unsigned long* l; unsigned short* s; unsigned char * c; + } wb1a; /* write-back 1 address */ + union { + unsigned long l; unsigned short s; unsigned char c; + } wb1d; /* write-back 1 / push data LW0 */ + unsigned long pd1; /* push data LW1 */ + unsigned long pd2; /* push data LW2 */ + unsigned long pd3; /* push data LW3 */ +}; +typedef struct accessFault accessFault; + +struct faultData +{ + unsigned short* pc; + unsigned char * fa; + unsigned short sr; + unsigned short ssw; + unsigned char flags; /* 0x01:write back incompleted, >0: valid bus error */ + long cnt; +}; +typedef struct faultData faultData; + +#define TOTAL_FAULTS 20 +#define ACCESS_FAULT 2 +#define BS_PRI 199 +#define NUM_RETRIES 10 + +long epicsBusErrorInit68040(void); +long epicsBusErrorHandler(void* v); +void epicsBusErrorPrint(void); +void epicsBusError(void); + +volatile long epicsBusErrorTotal=0; +volatile long epicsBusErrorLastRC=0; +static volatile faultData* fault_table=NULL; +static volatile int pos_handler=0; +static unsigned char * be_mem_top=NULL; +static unsigned char * be_mem_bottom=0; +static FUNCPTR* vbr; +static FUNCPTR vx_access_fault; +static IOSCANPVT ioscan; +static unsigned short* curr_pc=NULL; +static unsigned short* last_pc=NULL; +static unsigned short count=0; +static unsigned long regs[64]; +static unsigned long* regs_addr=regs; +static int init_run=0; + +FUNCPTR* epicsGetVBR() +{ + unsigned long x; + asm ("movec vbr,%0" : "=g" (x) ); + return (FUNCPTR*)x; +} + +/* ------------------- ai record to monitor bus errors -------------------- */ +struct aStats +{ + long number; + DEVSUPFUN report; + DEVSUPFUN init; + DEVSUPFUN init_record; + DEVSUPFUN get_ioint_info; + DEVSUPFUN read_write; + DEVSUPFUN special_linconv; +}; +typedef struct aStats aStats; + +static long aiInit(int pass) +{ + if(pass) return 0; + if(init_run==0) + { + epicsBusErrorInit68040(); + init_run=1; + } + return 0; +} + +static long aiInitRecord(aiRecord* pr) +{ + unsigned long* x = (unsigned long*)&pr->dpvt; + x=0; + pr->linr=0; + return 0; +} + +static long aiIointInfo(int cmd,aiRecord* pr,IOSCANPVT* iopvt) +{ + *iopvt=ioscan; + return 0; +} + +static long aiRead(aiRecord* pr) +{ + unsigned long* x = (unsigned long*)&pr->dpvt; + pr->val=++(*x); + pr->udf=0; + return 2; +} + +aStats devAiBusError= + { 6,NULL,aiInit,aiInitRecord,aiIointInfo,aiRead,NULL }; + +/* ------------------- ai record to monitor bus errors -------------------- */ + +long epicsBusErrorInit68040(void) +{ + long rc=0; + int i; + + if(init_run) + return 0; + else + init_run=1; + + vbr=epicsGetVBR(); /* vbr=intVecBaseGet(); */ + be_mem_top=(unsigned char *)sysMemTop(); + vx_access_fault=vbr[ACCESS_FAULT]; + scanIoInit(&ioscan); + +/* + printf("VBR=0x%8.8x\n",vbr); + printf("MemTop=0x%8.8x\n",be_mem_top); + printf("vxWorks Access Fault Handler=0x%8.8x\n",vx_access_fault); +*/ + + /* up to TOTAL_FAULTS number of interrupts can occur before printing */ + fault_table=(volatile faultData*)malloc(sizeof(faultData)*TOTAL_FAULTS); + for(i=0;i 60+60 */ + +asm(" .text"); +asm(" .even"); +asm(" .globl _epicsBusError"); +asm("_epicsBusError:"); +asm(" moveml #0xfffe,sp@-"); /* save the registers */ +asm(" pea sp@(60)"); /* get address of access error stack frame */ +asm(" jbsr _epicsBusErrorHandler"); /* call my bus error handler */ +asm(" addql #4,sp"); +asm(" tstl d0"); /* check return code from bus error handler */ +asm(" jeq L1"); /* exit OK if zero return code */ +asm(" moveml sp@+,#0x7fff"); /* restore regs */ +asm(" movel _vx_access_fault,sp@-"); /* put vxWorks handler addr on stack */ +asm(" rts "); /* load PC from stack (vxWorks handler) */ +asm("L1:"); +asm(" moveml sp@+,#0x7fff"); /* restore regs */ +asm(" rte"); + +/* + see section 8.4.6 of M68040 user's manual, page 8-24 + see section 5.3, page 5-5 for Transfer attribute signals (TT/TM) + SIZ: 00=long word, 01=byte, 10=word + TT: 00=normal, 01=move16, 10=alternate, 11=ack cycle + TM: 001=user data, 010=user code, 101=sup data, 110=sup code + R/W: set indicates a read access +*/ + +long epicsBusErrorHandler(void* v) +{ + long rc; + unsigned char f; + volatile int pos,posp; + volatile accessFault* af = (volatile accessFault*)v; + unsigned short size,op_code; + unsigned short* ppc; + int len; + + curr_pc=af->pc; + if(curr_pc==last_pc) ++count; + + if( countssw & 0x0018) == 0) && ((af->ssw & 0xfc00) == 0) && + ((af->ssw & 0x0001) || (af->ssw & 0x0005)) && + (af->fa >= be_mem_top) ) + { + /* TT=normal TM=user/sup data access bus-errors */ + rc=0; + f=0x02; + + /* + Don't force PC to next instruction, just retry several times + Note: the current instruction may not have caused the fault + */ + + /* correct bus error here */ + if(af->wb1s & 0x0080) + { + /* this is where the fault occured if write */ + if(af->wb1a.c < be_mem_top) + { + size=(af->wb1s & 0060)>>5; + if(size==0x0000) *(af->wb1a.l)=af->wb1d.l; + else if(size==0x0001) *(af->wb1a.c)=af->wb1d.c; + else if(size==0x0010) *(af->wb1a.s)=af->wb1d.s; + } + } + if(af->wb2s & 0x0080) + { + if(af->wb2a.c < be_mem_top) + { + size=(af->wb2s & 0060)>>5; + if(size==0x0000) *(af->wb2a.l)=af->wb2d.l; + else if(size==0x0001) *(af->wb2a.c)=af->wb2d.c; + else if(size==0x0010) *(af->wb2a.s)=af->wb2d.s; + } + else + f|=0x01; + } + if(af->wb3s & 0x0080) + { + if(af->wb3a.c < be_mem_top) + { + size=(af->wb3s & 0060)>>5; + if(size==0x0000) *(af->wb3a.l)=af->wb3d.l; + else if(size==0x0001) *(af->wb3a.c)=af->wb3d.c; + else if(size==0x0010) *(af->wb3a.s)=af->wb3d.s; + } + else + f|=0x01; + } + } + else + { + f=0x04; + rc=-1; /* let vxWorks handle it */ + } + + if(count==0 || count>=NUM_RETRIES) + { + if((++pos_handler)>=TOTAL_FAULTS) pos_handler=0; + fault_table[pos_handler].pc=af->pc; + fault_table[pos_handler].fa=af->fa; + fault_table[pos_handler].sr=af->sr; + fault_table[pos_handler].ssw=af->ssw; + fault_table[pos_handler].cnt=epicsBusErrorTotal; + fault_table[pos_handler].flags=f; + + if(count>=NUM_RETRIES) + { + count=0; + curr_pc=NULL; + } + else + scanIoRequest(ioscan); + + ++epicsBusErrorTotal; + } + + epicsBusErrorLastRC=rc; + last_pc=curr_pc; + return rc; +} +