1
0
Files
irix-657m-src/stand/arcs/ide/IP30/cache/cache_par.c
2022-09-29 17:59:04 +03:00

488 lines
10 KiB
C

/*
* cpu/cache_par.c
*
*
* Copyright 1996, Silicon Graphics, Inc.
* All Rights Reserved.
*
* This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics, Inc.;
* the contents of this file may not be disclosed to third parties, copied or
* duplicated in any form, in whole or in part, without the prior written
* permission of Silicon Graphics, Inc.
*
* RESTRICTED RIGHTS LEGEND:
* Use, duplication or disclosure by the Government is subject to restrictions
* as set forth in subdivision (c)(1)(ii) of the Rights in Technical Data
* and Computer Software clause at DFARS 252.227-7013, and/or in similar or
* successor clauses in the FAR, DOD or NASA FAR Supplement. Unpublished -
* rights reserved under the Copyright Laws of the United States.
*/
#ident "$Revision: 1.18 $"
#include <sys/param.h>
#include <sys/sbd.h>
#include <sys/cpu.h>
#include <setjmp.h>
#include <fault.h>
#include <uif.h>
#include <libsc.h>
#include <libsk.h>
#include <pon.h>
#include "cache.h"
static int icache_parity(void);
static int dcache_parity(void);
/*
* patterns to force-load to check parity - currently, all 0's, all 1's, and
* 1 each of even and odd byte parity
*/
#define NUM_PAR_PATS 4
uint parity_pattern[] = { 0x11111111, 0, 0x10101010, 0xffffffff };
uint fail_parity_bits[] = { 0xf, 0xf, 0x0, 0xf };
/* First level data cache data parity test */
int
dcache_par(void)
{
int error = 0;
msg_printf(VRB|PRCPU, "Data cache data parity test\n");
/* flush stack to uncached space */
flush_cache();
/* make sp uncached too */
setstackseg(K1BASE);
run_uncached();
error = dcache_parity();
setstackseg(K0BASE);
run_cached();
flush_cache();
if (error)
sum_error("Data cache data parity");
else
okydoky();
return error;
}
/* First level instruction cache data parity test */
int
icache_par(void)
{
int error = 0;
msg_printf(VRB|PRCPU, "Instruction cache data parity test\n");
flush_cache(); /* flush stack so we can be uncached */
setstackseg(K1BASE); /* make sp uncached too */
run_uncached();
error = icache_parity();
setstackseg(K0BASE);
run_cached();
flush_cache();
if (error)
sum_error("Instruction cache data parity");
else
okydoky();
return error;
}
/*
* write_icache_badtag - simple routine that writes an
* instruction cache entry with a
* bad parity in the address tag
*
*/
static void
write_icache_badtag(ulong addr)
{
tag_regs_t tag;
/* Create address part of tag */
tag.tag_hi = (uint) ((addr & PTAG1) >> TAGHI_PI_PTAG1_SHIFT);
tag.tag_lo = (uint) ((addr & PTAG0) >> TAGLO_PI_PTAG0_SHIFT);
/* force bad tag parity */
if (!calc_r10k_parity(addr & (PTAG0 | PTAG1)))
tag.tag_lo |= TAGLO_PI_TP;
/* rest of tag, parity correct */
tag.tag_lo |= TAGLO_PI_LRU | TAGLO_PI_PSTATE | TAGLO_PI_SP;
_write_tag(CACH_PI, (ulong)addr, (void*)&tag);
}
/*
* icache_parity_test - causes a tag address parity error and makes
* sure that an exception occurs
*
* note: does NOT cause a data error like the
* R4k diags
*/
static int
icache_parity_test(void)
{
register uint i, j;
register volatile uint *fillptr;
volatile uint bucket;
__psunsigned_t cur_err;
uint fail = 0;
int error = 0;
register uint way;
j = PIL_SIZE / sizeof(uint); /* words/ipline */
invalidate_caches(); /* invalidate to force refill */
flushall_tlb();
/*
* force-fill the cache again, but this time we force bad parity, so
* should see parity errors on every cache line. Error set if NO cache
* parity errors seen
*/
fillptr = (uint *) PHYS_TO_K0(PHYS_CHECK_LO);
i = PI_SIZE / PIL_SIZE;
while(i--) {
/* check both ways in cache */
for (way=0 ; way<=1 ; way++) {
if (setjmp(cache_fault_buf)) {
if (_exc_save != EXCEPT_ECC) {
show_fault();
DoEret();
return ++error;
}
/* current error status */
cur_err = get_cache_err();
/*
* If cache error exception, but not ECC_DFIELD,
* set error flag and log it.
*/
if (!(cur_err & CACHERR_DC_TA)) {
msg_printf(ERR|PRCPU,
"Did not get expected cache tag address error exception at 0x%08lx, CO_CACHE_ERR: 0x%08x\n",
(void *) fillptr, cur_err);
fail = 1;
error++;
}
/*
* Force ERET back to next address to clear
* exception.
*/
DoEret();
/* abort test after error */
if (fail)
goto done;
}
else {
nofault = cache_fault_buf;
/* make sure exception is taken on parity
* errors
*/
SetSR(GetSR() & ~SR_DE);
/* set a value */
*fillptr = 0x0;
/* now write data w/bad tag parity into cache */
write_icache_badtag((ulong)fillptr|way);
/* hit invalidate checks tag parity and will
* cause exception
*/
pi_HINV((void*)((ulong)fillptr|way));
/*
* if it won't take parity exception in 5 uS,
* it ain't gonna
*/
DELAY(5);
/* NO CACHE ERROR - PRINT LOG MESSAGE */
msg_printf(ERR|PRCPU,
"Icache Parity - no exception at Addr: 0x%x\n",
(void *) fillptr);
error++;
nofault = 0;
goto done;
}
}
fillptr += j; /* next line in primary cache */
}
invalidate_caches();
flushall_tlb();
done:
return error;
}
/*
* icache_parity - instruction cache block mode parity test
*
* all memory locations in the cache are set to the same values, so it
* will not detect addressing errors well, if at all, but should have
* very good coverage of cache line parity errors
*/
static int
icache_parity(void)
{
k_machreg_t oldsr;
int rc = 0;
oldsr = GetSR();
/* test tag address parity */
rc = icache_parity_test();
SetSR(oldsr);
return rc;
}
/*
* dcache_de_bit_test - checks to see if DE bit in Status Reg works
* - also checks real parity errors ie if
* real parity errors occur during this test
* they will appear here
*/
int dcache_de_bit_test(uint pattern, k_machreg_t cur_stat)
{
register uint i;
register volatile uint *fillptr;
msg_printf (DBG|PRCPU, "testing data pattern 0x%x\n", pattern);
invalidate_caches();
flushall_tlb();
/* Fill main memory with current test pattern */
fillptr = (uint *) PHYS_TO_K1(PHYS_CHECK_LO);
i = PD_SIZE / sizeof(uint);
while (i--) {
*fillptr++ = pattern;
}
invalidate_caches(); /* force a refill */
/*
* fill the cache from the specified block - normal parity calculation
* are enabled, so any parity errors seen should be real
*/
fillptr = (uint *)PHYS_TO_K0(PHYS_CHECK_LO);
i = PD_SIZE / sizeof(uint);
if (setjmp(cache_fault_buf)) {
show_fault();
DoEret();
SetSR(cur_stat);
return 1;
/*NOTREACHED*/
}
nofault = cache_fault_buf; /* enable error handler */
/*
* enable cache interrupts, but not for parity/ecc
*/
SetSR(GetSR() | SR_FORCE_OFF | SR_DE);
while(i--) {
*fillptr++ = pattern; /* force cache load */
}
/*
* clear error handler - delay is necessary do work around
* pipeline delays in interrupt/exception generation
*/
DELAY(2);
nofault = 0;
return 0;
}
/*
* dcache_parity_test - causes a parity error and makes
* sure that an exception occurs
*
*/
static int
dcache_parity_test(uint pattern, uint parity_bits)
{
register uint i;
register uint way;
register volatile uint *fillptr;
__psunsigned_t cur_err;
volatile uint dummy;
uint fail = 0;
int error = 0;
uint data[2];
invalidate_caches();
flushall_tlb();
/* init data */
data[0] = pattern;
data[1] = 0x0;
#define NUM_WORDS_PER_CACHE_LINE 8
/* we fill the cache with bad-parity data via the index store data
* cache-ops. We run in cached space so that later reads catch
* the parity errors
*/
fillptr = (uint *)PHYS_TO_K0(PHYS_CHECK_LO);
i = PD_SIZE / (NUM_WORDS_PER_CACHE_LINE * sizeof(uint));
while(i--) {
for (way=0 ; way<=1 ; way++) {
if (error) {
msg_printf(VRB|PRCPU,
"i = %d error = %d\n",i,error);
}
/* process exception */
if (setjmp(cache_fault_buf)) {
/* get new error error status */
cur_err = get_cache_err();
/* If cache error exception, but not
* ECC_DFIELD, set error flag and log it
*/
if(!(cur_err & CACHERR_DC_D)) {
msg_printf(ERR|PRCPU,"Did not get expected cache datafield error exception at 0x%x, CO_CACHE_ERR: 0x%08x\n",
(ulong)fillptr, cur_err);
fail = 1;
error++;
}
/* clear parity for cache line */
*(fillptr) = pattern;
/* Force ERET back to next address to clear
* exception.
*/
DoEret();
/* abort test after error */
if (fail)
goto done;
}
/* generate parity exception */
else {
nofault = cache_fault_buf;
/* make sure exception is taken on parity
* errors
*/
SetSR(GetSR() & ~SR_DE);
/* write pattern to memory - this will create
* a correct cache entry
*/
*(fillptr) = pattern;
/* now write bad parity into cache */
_write_cache_data(CACH_PD,
(ulong)fillptr|way,
data, parity_bits);
/* now read and see if we get exception */
dummy = *fillptr;
/* if it won't take parity exception in 5 uS,
* it ain't gonna
*/
DELAY(5);
/* NO CACHE ERROR - PRINT LOG MESSAGE */
msg_printf(ERR|PRCPU, "Dcache Parity - no exception at Addr: 0x%x\n",
(void *)fillptr);
error++;
nofault = 0;
goto done;
}
}
/* next line in primary cache */
fillptr += NUM_WORDS_PER_CACHE_LINE;
}
done:
return error;
}
/*
* dcache_parity - data cache block mode parity test
*
* all memory locations in the cache are set to the same values, so it
* will not detect addressing errors well, if at all, but should have
* very good coverage of cache line parity errors
*/
static int
dcache_parity(void)
{
register uint k,pattern;
k_machreg_t cur_stat;
int rc;
cur_stat = GetSR();
for (k = 0; k < NUM_PAR_PATS; k++) {
pattern = parity_pattern[k];
/* test the DE bit */
if (rc = dcache_de_bit_test(pattern,cur_stat)) {
SetSR(cur_stat);
return(rc);
}
#ifdef NEED_REWRITE /* XXX cannot take exception uncached with cached ide */
/* test parity */
if (rc = dcache_parity_test(pattern,fail_parity_bits[k])) {
SetSR(cur_stat);
return(rc);
}
#endif /* NEED_REWRITE */
/*
* restore original diagnostic values for next pass
*/
SetSR (cur_stat);
}
/*
* restore original diagnostic status values in case of error exit
*/
SetSR(cur_stat);
/* no error */
return 0;
}