545 lines
11 KiB
C
545 lines
11 KiB
C
/* gcache.c - Gcache diagnostics */
|
|
/* :set ts=4 */
|
|
|
|
#ident "$Revision: 1.28 $"
|
|
|
|
#include <sys/sbd.h>
|
|
#include <sys/cpu.h>
|
|
#include <strings.h>
|
|
#include "libsc.h"
|
|
#include "uif.h"
|
|
#include "./cache.h"
|
|
|
|
#define MAX_ERRORS 16
|
|
|
|
extern int _sidcache_size;
|
|
|
|
static int check_error(volatile unsigned long *, const char *);
|
|
static void failed(volatile unsigned long *, unsigned long, int, const char *);
|
|
static int scache1(void), scache3(void), scache4(void);
|
|
static int scache5(void), scache6(void);
|
|
|
|
|
|
/* IDE front end to the GCache tests. Will run all tests with no args,
|
|
* or tests can be picked indivdually.
|
|
*/
|
|
int
|
|
scache(int argc, char *argv[])
|
|
{
|
|
int error = 0, i;
|
|
unsigned long len;
|
|
|
|
msg_printf(VRB, "Scache test\n");
|
|
|
|
/* Make sure that no cache errors already happened. */
|
|
error = check_error(0,"pre-scache check");
|
|
#if 0 /* we really do not want to do this. (jeffs) */
|
|
if (error) {
|
|
msg_printf(VRB, "pre-scache test FAILED(%d)\n", error);
|
|
return error;
|
|
}
|
|
#endif
|
|
|
|
if (argc > 2) {
|
|
msg_printf(DBG, "invalid argument\n");
|
|
return -1;
|
|
} else if (argc == 1) {
|
|
error = scache1();
|
|
error += scache3();
|
|
error += scache4();
|
|
error += scache5();
|
|
error += scache6();
|
|
} else {
|
|
for (len = strlen(argv[1]);len;len--)
|
|
if (argv[1][len-1] < '1' || argv[1][len-1] > '6') {
|
|
msg_printf(DBG, "invalid argument\n");
|
|
return -1;
|
|
}
|
|
msg_printf(VRB, "Scache %d test\n", (i = atoi(argv[1])));
|
|
switch(i) {
|
|
case 1: /* scache 1 and 2 are combined now */
|
|
case 2:
|
|
error = scache1();
|
|
break;
|
|
case 3:
|
|
error = scache3();
|
|
break;
|
|
case 4:
|
|
error = scache4();
|
|
break;
|
|
case 5:
|
|
error = scache5();
|
|
break;
|
|
case 6:
|
|
error = scache6();
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (error)
|
|
msg_printf(VRB, "Scache test FAILED(%d)\n", error);
|
|
else
|
|
msg_printf(VRB, "Scache test passed\n");
|
|
|
|
return error;
|
|
}
|
|
|
|
|
|
/* Runs the tag power on tests, which test both tag ram chips, not the cache
|
|
* itself.
|
|
*/
|
|
static int
|
|
scache1(void)
|
|
{
|
|
volatile long *tcc_gcache = (long *)PHYS_TO_K1(TCC_GCACHE);
|
|
long gcache_orig;
|
|
int error;
|
|
|
|
msg_printf(DBG, " Scache1 (pon) test\n");
|
|
|
|
__dcache_wb_inval_all();
|
|
|
|
gcache_orig = *tcc_gcache;
|
|
|
|
run_chandra();
|
|
|
|
error = scache_tag();
|
|
error |= scache_tag2();
|
|
error |= scache_tag3();
|
|
error |= scache_data();
|
|
error |= scache_data2();
|
|
|
|
*tcc_gcache = gcache_orig;
|
|
inval_gcache_tags();
|
|
|
|
/* check for parity errors after it's all over */
|
|
if (check_error(0,"scache1"))
|
|
error++;
|
|
|
|
return error;
|
|
}
|
|
|
|
/* Runs some simple data through the GCache a set at a time with floating
|
|
* point stores, which go directly from the FPU to the GCache.
|
|
*/
|
|
static int
|
|
scache3(void)
|
|
{
|
|
volatile void *dst = (volatile void *)SCACHE_TESTADDR;
|
|
int error=0;
|
|
ulong oldSR;
|
|
void *baddr;
|
|
|
|
msg_printf(DBG, " Scache3 test\n");
|
|
__dcache_wb_inval_all();
|
|
|
|
/* save status register */
|
|
oldSR = get_SR();
|
|
|
|
/* Enable parity interrupts */
|
|
set_SR(oldSR | SR_IBIT10 | SR_IBIT9);
|
|
|
|
/* Used to implement this test over each set, changing the TCC_GCACHE
|
|
* register to only allow the requested set to be tested. This turns
|
|
* out to cause cases where the tags can get messed-up (usually in
|
|
* set 0) we think. We have seen failures in mfg that could be caused
|
|
* by this behavior.
|
|
*/
|
|
baddr = fp_ls(0x5555555555555555, dst, 0x200000);
|
|
if (baddr) {
|
|
failed(baddr,0x5555555555555555,-1,"scache3");
|
|
error++;
|
|
}
|
|
baddr = fp_ls(0xaaaaaaaaaaaaaaaa, dst, 0x200000);
|
|
if (baddr) {
|
|
failed(baddr,0xaaaaaaaaaaaaaaaa,-1,"scache3");
|
|
error++;
|
|
}
|
|
baddr = fp_ls(0x5555555555555555, dst, 0x200000);
|
|
if (baddr) {
|
|
failed(baddr,0x5555555555555555,-1,"scache3");
|
|
error++;
|
|
}
|
|
baddr = fp_ls(0xaaaaaaaaaaaaaaaa, dst, 0x200000);
|
|
if (baddr) {
|
|
failed(baddr,0xaaaaaaaaaaaaaaaa,-1,"scache3");
|
|
error++;
|
|
}
|
|
|
|
/* check for parity errors after it's all over */
|
|
if (check_error(0,"scache3"))
|
|
error++;
|
|
|
|
flush_cache();
|
|
|
|
/* restore status register */
|
|
set_SR(oldSR);
|
|
|
|
return error;
|
|
}
|
|
|
|
/* This tests writes 2MB of patterns based on the the address pointer to
|
|
* do an approximation of an address test. It's impercise as to if it
|
|
* hits off of the cache, and things may be forced out. It used to be
|
|
* run setting the TCC_GCACHE to disable some sets, but that is risky
|
|
* and seems to cause problems sometimes.
|
|
*/
|
|
static int
|
|
scache4(void)
|
|
{
|
|
register unsigned long *fillptr;
|
|
ulong oldSR;
|
|
int error = 0;
|
|
int i,j;
|
|
|
|
msg_printf(DBG, " Scache4 test\n");
|
|
__dcache_wb_inval_all();
|
|
|
|
/* save status register */
|
|
oldSR = get_SR();
|
|
|
|
/* Enable parity interrupts */
|
|
set_SR(oldSR | SR_IBIT10 | SR_IBIT9);
|
|
|
|
/* fill memory with inverse current address */
|
|
fillptr = (unsigned long *)SCACHE_TESTADDR;
|
|
for (i = _sidcache_size / (int)sizeof(unsigned long); i > 0; --i) {
|
|
*fillptr = ~(long)fillptr;
|
|
if (check_error(fillptr++,"scache4")) {
|
|
error++;
|
|
goto err;
|
|
}
|
|
}
|
|
|
|
__dcache_wb_all();
|
|
|
|
/* now check each entry to valid data */
|
|
fillptr = (unsigned long *)SCACHE_TESTADDR;
|
|
for (i = _sidcache_size / (int)sizeof (unsigned long); i > 0; --i) {
|
|
if (*fillptr != ~(long) fillptr) {
|
|
failed(fillptr, ~(long)fillptr, j, "scache4");
|
|
|
|
if (++error == MAX_ERRORS)
|
|
goto err;
|
|
}
|
|
|
|
/* check for errors */
|
|
if (check_error(fillptr++,"scache4")) {
|
|
error++;
|
|
goto err;
|
|
}
|
|
}
|
|
|
|
|
|
/* fill the cache in with the address */
|
|
fillptr = (unsigned long *)SCACHE_TESTADDR;
|
|
for (i = _sidcache_size / (int)sizeof(unsigned long); i > 0; --i) {
|
|
|
|
*fillptr = (long)fillptr;
|
|
|
|
if (check_error(fillptr++,"scache4")) {
|
|
error++;
|
|
goto err;
|
|
}
|
|
|
|
}
|
|
|
|
/* verify each of the writes */
|
|
fillptr = (unsigned long *)SCACHE_TESTADDR;
|
|
for (i = _sidcache_size / (int)sizeof (unsigned long); i > 0; --i) {
|
|
if (*fillptr != (long) fillptr ) {
|
|
failed(fillptr, (long)fillptr, j, "scache4");
|
|
if (++error == MAX_ERRORS)
|
|
goto err;
|
|
}
|
|
|
|
if (check_error(fillptr++,"scache4")) {
|
|
error++;
|
|
goto err;
|
|
}
|
|
|
|
}
|
|
|
|
err:
|
|
/* restore status register */
|
|
set_SR(oldSR);
|
|
|
|
return error;
|
|
}
|
|
|
|
/* Walks a bit though each double word in the cache (approx -- does not play
|
|
* with TCC_GCACHE since this is dangerous).
|
|
*/
|
|
static int
|
|
scache5(void)
|
|
{
|
|
register unsigned long *fillptr, pattern;
|
|
void *test_base = (void *)(SCACHE_TESTADDR);
|
|
ulong oldSR;
|
|
int i, error=0;
|
|
|
|
msg_printf(DBG, " Scache5 test\n");
|
|
__dcache_wb_inval_all();
|
|
|
|
/* save status register */
|
|
oldSR = get_SR();
|
|
|
|
/* Enable parity interrupts */
|
|
set_SR(oldSR | SR_IBIT10 | SR_IBIT9);
|
|
|
|
pattern = 0x1;
|
|
while ( pattern ) {
|
|
fillptr = test_base;
|
|
|
|
for (i = 0 ; i < (_sidcache_size/8); i += 32){
|
|
|
|
*fillptr = !pattern;
|
|
*(fillptr+8) = !pattern;
|
|
*(fillptr+16) = !pattern;
|
|
*(fillptr+24) = !pattern;
|
|
|
|
*fillptr = pattern;
|
|
*(fillptr+8) = pattern;
|
|
*(fillptr+16) = pattern;
|
|
*(fillptr+24) = pattern;
|
|
|
|
if (check_error(fillptr,"scache5")) {
|
|
error++;
|
|
goto err;
|
|
}
|
|
|
|
fillptr = fillptr + 32;
|
|
}
|
|
|
|
__dcache_wb(test_base,_sidcache_size);
|
|
|
|
/* Read back and check */
|
|
fillptr = test_base;
|
|
for (i = 0 ; i < (_sidcache_size/8); i += 32){
|
|
if (*fillptr != pattern) {
|
|
failed(fillptr, pattern, -1, "scache5");
|
|
if (++error == MAX_ERRORS)
|
|
goto err;
|
|
}
|
|
|
|
if (check_error(fillptr,"scache5")) {
|
|
error++;
|
|
goto err;
|
|
}
|
|
|
|
if (*(fillptr+8) != pattern) {
|
|
failed(fillptr+8, pattern, -1, "scache5");
|
|
if (++error == MAX_ERRORS)
|
|
goto err;
|
|
}
|
|
|
|
if (check_error(fillptr,"scache5")) {
|
|
error++;
|
|
goto err;
|
|
}
|
|
|
|
|
|
if (*(fillptr+16) != pattern) {
|
|
failed(fillptr+16, pattern, -1, "scache5");
|
|
error++;
|
|
}
|
|
|
|
if (check_error(fillptr,"scache5")) {
|
|
error++;
|
|
goto err;
|
|
}
|
|
|
|
if (*(fillptr+24) != pattern) {
|
|
failed(fillptr+24, pattern, -1, "scache5");
|
|
if (++error == MAX_ERRORS)
|
|
goto err;
|
|
}
|
|
|
|
if (check_error(fillptr,"scache5")) {
|
|
error++;
|
|
goto err;
|
|
}
|
|
|
|
fillptr = fillptr + 32;
|
|
}
|
|
|
|
pattern <<=1;
|
|
|
|
}
|
|
|
|
err:
|
|
set_SR(oldSR);
|
|
|
|
return error;
|
|
}
|
|
|
|
/* Writes a number of double word patterns to the cache (approx -- does not
|
|
* play with TCC_GCACHE since this is dangerous).
|
|
*/
|
|
static int
|
|
scache6(void)
|
|
{
|
|
volatile unsigned long pattern;
|
|
volatile unsigned long *fillptr;
|
|
ulong oldSR;
|
|
volatile int i;
|
|
int j,k,error = 0;
|
|
|
|
msg_printf(DBG, " Scache6 test\n");
|
|
__dcache_wb_inval_all();
|
|
|
|
/* save status register */
|
|
oldSR = get_SR();
|
|
|
|
/* Enable parity interrupts */
|
|
set_SR(oldSR | SR_IBIT10 | SR_IBIT9);
|
|
|
|
busy(1);
|
|
|
|
/* run thru with 16 patterns */
|
|
pattern = 0;
|
|
for ( pattern = j = 0; j < 16; j++) {
|
|
|
|
fillptr = (unsigned long *)SCACHE_TESTADDR;
|
|
for (i = _sidcache_size / (int)sizeof(unsigned long); i > 0; --i) {
|
|
*fillptr = pattern;
|
|
|
|
if (check_error(fillptr,"scache6")) {
|
|
error++;
|
|
goto err;
|
|
}
|
|
|
|
fillptr++;
|
|
}
|
|
|
|
busy(1);
|
|
|
|
fillptr = (unsigned long *)SCACHE_TESTADDR;
|
|
for (i = _sidcache_size / (int)sizeof(unsigned long); i > 0; --i) {
|
|
|
|
if ( *fillptr != pattern) {
|
|
failed(fillptr, pattern, k, "scache6");
|
|
if (++error == MAX_ERRORS)
|
|
goto err;
|
|
}
|
|
|
|
if (check_error(fillptr,"scache6")) {
|
|
error++;
|
|
goto err;
|
|
}
|
|
|
|
fillptr++;
|
|
}
|
|
|
|
pattern = pattern + 0x0001000100010001;
|
|
busy(1);
|
|
}
|
|
|
|
err:
|
|
set_SR(oldSR);
|
|
|
|
busy(0);
|
|
|
|
return error;
|
|
}
|
|
|
|
static int
|
|
check_error(volatile unsigned long *fillptr, const char *name)
|
|
{
|
|
volatile long *ptcc_parity = (volatile long *)PHYS_TO_K1(TCC_PARITY);
|
|
long tcc_error = *(volatile long *)PHYS_TO_K1(TCC_ERROR);
|
|
long tcc_parity = *ptcc_parity;
|
|
char *type;
|
|
|
|
if ( tcc_parity & ( PAR_SYSAD_SYND_TCC | PAR_DATA_SYND_DB0 |
|
|
PAR_DATA_SYND_DB1) ) {
|
|
msg_printf(VRB,
|
|
"ERROR(%s): Teton detected GCache parity error!\n",
|
|
name);
|
|
if (fillptr)
|
|
msg_printf(VRB,"Address 0x%x Data 0x%x\n",
|
|
fillptr, *fillptr);
|
|
msg_printf(VRB,"TCC Parity Registor: 0x%08x\n", tcc_parity);
|
|
msg_printf(VRB,"TCC Error Register: 0x%08x\n", tcc_error);
|
|
|
|
type = 0;
|
|
switch ((tcc_error & ERROR_TYPE) >> ERROR_TYPE_SHIFT ) {
|
|
case 0:
|
|
msg_printf(VRB,
|
|
"sysAD data parity error (TDB %s%s)\n",
|
|
(tcc_parity & PAR_DATA_SYND_DB0) ? "[0]" : "",
|
|
(tcc_parity & PAR_DATA_SYND_DB1) ? "[1]" : "");
|
|
break;
|
|
case 1:
|
|
type = "sysAD data parity error (TCC)\n";
|
|
break;
|
|
case 2:
|
|
type = "sysCMD parity error\n";
|
|
break;
|
|
case 3:
|
|
type = "unknown sysAD command\n";
|
|
break;
|
|
case 4:
|
|
type = "GCache data parity error\n";
|
|
break;
|
|
case 5:
|
|
type = "unknown T-Bus command\n";
|
|
break;
|
|
default:
|
|
type = "unknown error\n";
|
|
break;
|
|
}
|
|
if (type) msg_printf(VRB,"Error Type: %s",type);
|
|
|
|
msg_printf(VRB,"Failing word: 0x%x\nIndex: 0x%x\nSet: 0x%x\n",
|
|
(tcc_error & ERROR_OFFSET) >> ERROR_OFFSET_SHIFT,
|
|
(tcc_error & ERROR_INDEX) >> ERROR_INDEX_SHIFT,
|
|
(tcc_error & ERROR_PARITY_SET) >> ERROR_PARITY_SET_SHIFT);
|
|
|
|
/* clear parity information */
|
|
*ptcc_parity = tcc_parity &
|
|
(PAR_TDB_EN|PAR_TCC_EN|PAR_DATA_TDB_EN);
|
|
|
|
return 1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
static void
|
|
failed(volatile unsigned long *ptr, unsigned long expect, int set,
|
|
const char *test)
|
|
{
|
|
unsigned long mask = 0xff;
|
|
unsigned long offset = 0;
|
|
unsigned long actual;
|
|
int *ram;
|
|
char *msg;
|
|
static int even_rams[] = {16,15,11,10,12,6,5,4};
|
|
static int odd_rams[] = {14,13,8,7,9,3,2,1};
|
|
|
|
if ((__psunsigned_t)ptr & 8)
|
|
ram = odd_rams, msg = "[odd]";
|
|
else
|
|
ram = even_rams, msg = "[even]";
|
|
msg_printf(VRB, "%s: secondary cache data error @ 0x%lx %s\n",
|
|
test, ptr, msg);
|
|
actual = *ptr;
|
|
msg_printf(VRB, " Expected: 0x%lx Actual: 0x%lx\n", expect, actual);
|
|
msg_printf(VRB, " index: 0x%x ",
|
|
((__psint_t)ptr&TCC_CACHE_INDEX)>>TCC_CACHE_INDEX_SHIFT);
|
|
if (set != -1)
|
|
msg_printf(VRB, "set: %d", set);
|
|
msg_printf(VRB, "\n");
|
|
do {
|
|
if ((actual & mask) != (expect & mask))
|
|
msg_printf(VRB, " byte: %d SRAM: S%d\n", offset, ram[offset]);
|
|
|
|
mask <<= 8;
|
|
offset++;
|
|
|
|
} while(mask);
|
|
|
|
}
|