I have a simple example that is trying to perform a trivial maintenance read from an SRIO switch.
The code I have works intermittently an apparently random number of times.
typedef unsigned int UINT32;
typedef struct {
UINT32 R1;
UINT32 R2;
UINT32 R3;
UINT32 R4;
UINT32 R5;
} LSU_DATA;
SRIO *Srio = (SRIO *)SRIO_REGS;
LSUREG *LSU = &Srio->LSU[0];
// The next line is needed to stop the compiler over-opimising writes to the LSU registers.
#pragma FUNC_CANNOT_INLINE(SetLSU);
void SetLSU(LSU_DATA *D) {
while (LSU->R[6]>>30) {}
LSU->R[0] = 0;
LSU->R[1] = D->R1;
LSU->R[2] = D->R2;
LSU->R[3] = D->R3;
LSU->R[4] = D->R4;
LSU->R[5] = D->R5;
}
UINT32 maint_read(UINT32 addr) {
UINT32 value = byteswop(0xDEFACED);
LSU_DATA D;
FLUSH(&value, 4); // flush cache
D.R1 = addr;
D.R2 = GLOBAL(&value);
D.R3 = 4; // 4 bytes
D.R4 = (SWITCHID<<16)
| R4_IDSIZE16
| R4_PRIORITY2
| R4_INTREQ;
D.R5 = TYPE_MAINT_READ;
SetLSU(&D);
UINT32 timeout = 20;
while ((Srio->LSU_INT[0].ICSR&0x10001)==0) {
if (--timeout==0) {
printf("*** read time-out LSU0_ICSR=%08X LSU1_ICSR=%08X\n",
Srio->LSU_INT[0].ICSR, Srio->LSU_INT[1].ICSR);
break;
}
msDelay(50);
}
Srio->LSU_INT[0].ICCR = 0x10001;
return = byteswop(value);
}
Running this in a loop trying to read with addr=0x6C returns the correct value a few times (1, 2, or 3, randomly)
then times-out for 10 or 20 times, then works, then times out, ... When it fails to work, 'value' is left unchanged
and 0xDEFACED is returned. It seems that the first read after initialising the SRIO ALWAYS works.
The examples I have seen either make no attempt to determine that LSU operations have finished or wait until the
destination has changed (an obviously useless method).
I have the same problem with all LSU transactions - sometimes it works, sometimes it doesn't; the address used seems
to make no difference to this. I have tried many variants of the code, but nothing works reliably.
All the addresses used refer to valid registers in the switch. Very, very rarely, the example runs to completion without error.
What is the correct way to determine that LSU operations have completed? The documentation is far from clear on this.
It seems that obvious way of doing this, looking at LSU R6, will simply lock the LSU and kill the next transaction.
What am I doing wrong?