1492 lines
39 KiB
C
1492 lines
39 KiB
C
/**************************************************************************
|
|
* *
|
|
* Copyright (C) 1992, 1994 Silicon Graphics, Inc. *
|
|
* *
|
|
* These coded instructions, statements, and computer programs contain *
|
|
* unpublished proprietary information of Silicon Graphics, Inc., and *
|
|
* are protected by Federal copyright law. They may not be disclosed *
|
|
* to third parties or copied or duplicated in any form, in whole or *
|
|
* in part, without the prior written consent of Silicon Graphics, Inc. *
|
|
* *
|
|
**************************************************************************/
|
|
|
|
#ifdef EVEREST /* whole file */
|
|
|
|
#include <sys/types.h>
|
|
#include <sys/debug.h>
|
|
#include <setjmp.h>
|
|
#include <sys/sbd.h>
|
|
#include <sys/cpu.h>
|
|
#include <sys/immu.h>
|
|
#include <sys/param.h>
|
|
#include <sys/iotlb.h>
|
|
#include "libsk.h"
|
|
#include <everr_hints.h>
|
|
#include <stdarg.h>
|
|
#include <sys/EVEREST/everest.h>
|
|
#include <sys/EVEREST/evintr.h>
|
|
#include <sys/EVEREST/evconfig.h>
|
|
#include <sys/EVEREST/mc3.h>
|
|
#include <sys/EVEREST/io4.h>
|
|
#include <sys/EVEREST/epc.h>
|
|
#include <sys/EVEREST/fchip.h>
|
|
#include <sys/EVEREST/vmecc.h>
|
|
#include <sys/EVEREST/s1chip.h>
|
|
#include <sys/EVEREST/dang.h>
|
|
#include <sys/wd95a.h>
|
|
#include <ide_msg.h>
|
|
#include <ide_s1chip.h>
|
|
#include <fault.h>
|
|
#include <stringlist.h>
|
|
#include <prototypes.h>
|
|
|
|
|
|
#ident "arcs/ide/EVEREST/lib/EVERESTlib.c: $Revision: 1.65 $"
|
|
|
|
/* Additional utilities used by IDE test cases. */
|
|
#define ASSERT_CFG ASSERT(EVCFGINFO->ecfg_magic == EVCFGINFO_MAGIC)
|
|
#define CHECK_SLOT(x) if((x < 0)||(x >=EV_MAX_SLOTS)) return(EVCLASS_NONE)
|
|
#define CHECK_ADAP(x) if((x < 0)||(x >=IO4_MAX_PADAPS)) return(IO4_ADAP_NULL)
|
|
|
|
#define SLOTTYPE(x) (EVCFGINFO->ecfg_board[x].eb_type)
|
|
#define IO4_WINDOW(x) (EVCFGINFO->ecfg_board[x].eb_io.eb_winnum)
|
|
#define IOATYPE(x, y) (EVCFGINFO->ecfg_board[x].eb_io.eb_ioas[y].ioa_type)
|
|
#define IOASTRU(x, y) &(EVCFGINFO->ecfg_board[x].eb_io.eb_ioas[y])
|
|
|
|
#define IDE_ERR_VECTOR 0x3f00 /* Vector 0x3f << 8 */
|
|
|
|
#define DANG_ADAP 1 /* vector all DANG exceptions to same handler */
|
|
|
|
extern int clear_bustags(void);
|
|
extern void ev_perr(int, char *, ...);
|
|
extern void ip_error_clear(int);
|
|
extern void ip_error_log(int);
|
|
extern void ip_error_show(int);
|
|
extern int cc_error_log(void);
|
|
extern int inval_tlbentry(uint);
|
|
|
|
int
|
|
board_type(int slot)
|
|
{
|
|
unsigned stype;
|
|
ASSERT_CFG;
|
|
CHECK_SLOT(slot);
|
|
if ((stype = SLOTTYPE(slot)) && hw_boardfound(slot, stype))
|
|
return(stype);
|
|
|
|
return(EVCLASS_NONE);
|
|
|
|
}
|
|
|
|
int
|
|
adap_type(int slot, int anum)
|
|
{
|
|
int atype;
|
|
ASSERT_CFG;
|
|
CHECK_SLOT(slot);
|
|
CHECK_ADAP(anum);
|
|
|
|
if ((SLOTTYPE(slot) != EVTYPE_IO4) && (SLOTTYPE(slot) != EVTYPE_IO5))
|
|
return(IO4_ADAP_NULL);
|
|
|
|
if ((atype = IOATYPE(slot, anum)) && hw_adapfound(slot, anum, atype))
|
|
return(atype);
|
|
|
|
return(IO4_ADAP_NULL);
|
|
}
|
|
|
|
/* Check if the Hardware config regs have the same idea as the EVCONFIG!! */
|
|
|
|
/* Few macros borrowed from IP19prom/io4_config.c */
|
|
#define EBOARD(_c, _s) ((_c) & (1 << (_s)))
|
|
#define CPUBOARD(_c, _s) ((_c) & (1 << ((_s) + 16)))
|
|
#define MEMBOARD(_c, _s) ((_c) & (1 << (_s)))
|
|
#define IOBOARD(_c, _s) (EBOARD(_c, _s) && !CPUBOARD(_c, _s) && !MEMBOARD(_c, _s))
|
|
|
|
static caddr_t unknown_name = {"UNKNOWN"};
|
|
static caddr_t boardnames[]= {
|
|
"IP19", "IP21", "MC3", "IO4", "IP25"
|
|
};
|
|
static caddr_t adapnames[] = {
|
|
"EPC", "SCSI", "FCHIP", "VMECC", "FCG"
|
|
};
|
|
|
|
|
|
caddr_t
|
|
adap_name(int adap_type)
|
|
{
|
|
switch(adap_type){
|
|
case IO4_ADAP_EPC : return(adapnames[0]); break;
|
|
case IO4_ADAP_SCSI : return(adapnames[1]); break;
|
|
case IO4_ADAP_FCHIP: return(adapnames[2]); break;
|
|
case IO4_ADAP_VMECC: return(adapnames[3]); break;
|
|
case IO4_ADAP_FCG : return(adapnames[4]); break;
|
|
case IO4_ADAP_NULL : return(unknown_name); break;
|
|
}
|
|
|
|
}
|
|
|
|
int
|
|
hw_boardfound(int slot, int boardtype)
|
|
{
|
|
evreg_t config = EV_GET_REG(EV_SYSCONFIG);
|
|
uint confhi, conflo;
|
|
caddr_t btype;
|
|
|
|
conflo = config & 0xffffffff;
|
|
confhi = config >> 32;
|
|
|
|
if(((boardtype == EVTYPE_IP21) && CPUBOARD(conflo, slot)) ||
|
|
((boardtype == EVTYPE_IP25) && CPUBOARD(conflo, slot)) ||
|
|
((boardtype == EVTYPE_IP19) && CPUBOARD(conflo, slot)) ||
|
|
((boardtype == EVTYPE_MC3) && MEMBOARD(confhi, slot)) ||
|
|
((boardtype == EVTYPE_IO4) && !CPUBOARD(conflo, slot) &&
|
|
!MEMBOARD(confhi, slot)))
|
|
return(1);
|
|
|
|
msg_printf(ERR, "Bad data seems to be in EVCONFIG data structure !!\n");
|
|
|
|
if (CPUBOARD(config, slot)){
|
|
#if IP19
|
|
btype = boardnames[0];
|
|
#endif
|
|
#if IP21
|
|
btype = boardnames[1];
|
|
#endif
|
|
#if IP25
|
|
btype = boardnames[4];
|
|
#endif
|
|
}
|
|
else if (MEMBOARD(config, slot))
|
|
btype = boardnames[2];
|
|
else if (EBOARD(config, slot))
|
|
btype = boardnames[3];
|
|
else btype = unknown_name;
|
|
|
|
msg_printf(ERR,"Slot %d has <%s> board instead of <%s> found in EVCONFIG\n",
|
|
slot, btype, board_name(boardtype));
|
|
|
|
msg_printf(ERR,"Inconsistent/Corrupted EVCONFIG.. Please reboot\n");
|
|
return(0);
|
|
|
|
}
|
|
|
|
int
|
|
hw_adapfound(int slot, int padap, int adaptype)
|
|
{
|
|
unsigned iodev;
|
|
|
|
if (!hw_boardfound(slot, EVTYPE_IO4))
|
|
return(0);
|
|
|
|
if (padap & 0x4)
|
|
iodev = IO4_GETCONF_REG(slot, IO4_CONF_IODEV1);
|
|
else
|
|
iodev = IO4_GETCONF_REG(slot, IO4_CONF_IODEV0);
|
|
|
|
iodev = ( iodev >> ((padap & 0x3) * 8)) & 0xff;
|
|
|
|
if (iodev == adaptype)
|
|
return 1;
|
|
|
|
msg_printf(ERR, "Bad data seems to be in EVCONFIG data structure !!\n");
|
|
msg_printf(ERR,"Adapter in IO4 slot %d padap %d is <%s> instead of <%s> found in EVCONFIG\n",
|
|
slot, padap, adap_name(iodev), adap_name(adaptype));
|
|
msg_printf(ERR,"Inconsistent/Corrupted EVCONFIG.. Please reboot\n");
|
|
return(0);
|
|
}
|
|
|
|
int
|
|
io4_window(int slot)
|
|
{
|
|
if (board_type(slot) != EVTYPE_IO4)
|
|
return(-1);
|
|
|
|
return(IO4_WINDOW(slot));
|
|
}
|
|
|
|
int adap_slots(int adap)
|
|
{
|
|
/* returns bit-mapped array of slots with specified io4 adapter */
|
|
register int slot, anum;
|
|
register uint slots = 0x0;
|
|
register uint atype;
|
|
|
|
for (slot = 0; slot < EV_MAX_SLOTS; slot++)
|
|
if (board_type(slot) == EVTYPE_IO4)
|
|
for (anum = 0; anum < IO4_MAX_PADAPS; anum++) {
|
|
atype = adap_type(slot, anum);
|
|
if (atype == adap)
|
|
slots |= (1 << anum);
|
|
}
|
|
return (slots);
|
|
}
|
|
|
|
|
|
int
|
|
fmaster(int slot, int anum)
|
|
/* Return : IO4_ADAP_NULL OR IO4_ADAP_VMECC OR IO4_ADAP_FCG */
|
|
{
|
|
unsigned window;
|
|
__psunsigned_t swin;
|
|
|
|
if (adap_type(slot, anum) != IO4_ADAP_FCHIP)
|
|
return(IO4_ADAP_NULL);
|
|
|
|
window = IO4_WINDOW(slot);
|
|
swin = SWIN_BASE(window, anum);
|
|
return(EV_GET_REG(swin + FCHIP_MASTER_ID));
|
|
}
|
|
|
|
|
|
int
|
|
scsichip(int slot, int anum)
|
|
/* Return Value : S1_H_ADAP_95A, S1_H_ADAP_93B */
|
|
{
|
|
/* TBD */
|
|
}
|
|
|
|
|
|
/* Error Clear Registers */
|
|
|
|
extern void everest_error_clear(); /* Defined in everror.c */
|
|
|
|
void
|
|
cpu_err_clear()
|
|
/* Description : Clear CC and A chip error regs on IP where test is running.*/
|
|
{
|
|
int slot;
|
|
slot = ((unsigned)(EV_GET_REG(EV_SPNUM) & EV_SLOTNUM_MASK)>>EV_SLOTNUM_SHFT);
|
|
|
|
ip_error_clear(slot);
|
|
EV_SET_REG(EV_CERTOIP, 0xffff);
|
|
}
|
|
|
|
int
|
|
mem_err_clear(int slot_arr )
|
|
/* Description : Clear the error registers on the Memory Boards.
|
|
slot_arr : bitmapped array of MC3 slots.
|
|
'i'th bit set for MC3 in slot 'i'
|
|
Clear this CPU's error register.
|
|
*/
|
|
{
|
|
int i, result=0;
|
|
|
|
ASSERT_CFG;
|
|
|
|
for (i=1; i < EV_MAX_SLOTS; i++){
|
|
if ((slot_arr & (1 << i)) == 0)
|
|
continue;
|
|
|
|
if (SLOTTYPE(i) != EVTYPE_MC3){
|
|
result |= i;
|
|
continue;
|
|
}
|
|
mc3_error_clear(i);
|
|
}
|
|
cpu_err_clear();
|
|
|
|
return(result);
|
|
}
|
|
|
|
int
|
|
io_err_clear(int slot, int adap_arr)
|
|
/*
|
|
* Description: Clear error registers for IO4 in 'slot'
|
|
Clear error registers for the adaps specified by adap_arr
|
|
adap_arr : bit 'i' set for adapter no 'i'
|
|
|
|
Clears error registers in ALL Memory boards, and
|
|
Clears error registers on the IP19 where test is running.
|
|
*/
|
|
{
|
|
int i, result=0;
|
|
|
|
ASSERT_CFG;
|
|
CHECK_SLOT(slot);
|
|
|
|
if (SLOTTYPE(slot) != EVTYPE_IO4)
|
|
return(-1);
|
|
|
|
io4_error_clear(slot);
|
|
|
|
for (i=0; i < IO4_MAX_PADAPS; i++){
|
|
if ((adap_arr & (1 << i)) == 0)
|
|
continue;
|
|
|
|
adap_error_clear(slot, i);
|
|
}
|
|
|
|
for (i=0; i < EV_MAX_SLOTS; i++)
|
|
if (SLOTTYPE(slot) == EVTYPE_MC3)
|
|
result != (1 << i);
|
|
|
|
mem_err_clear(result);
|
|
|
|
return(0);
|
|
}
|
|
|
|
|
|
|
|
void
|
|
cpu_err_show()
|
|
/* Description : Display the error registers in the running IP19 board */
|
|
{
|
|
int slot;
|
|
|
|
slot = ((unsigned)(EV_GET_REG(EV_SPNUM) & EV_SLOTNUM_MASK)>>EV_SLOTNUM_SHFT);
|
|
|
|
ASSERT_CFG;
|
|
ip_error_show(slot);
|
|
}
|
|
|
|
|
|
void
|
|
cpu_err_log()
|
|
{
|
|
int slot ;
|
|
|
|
slot = (((unsigned)EV_GET_REG(EV_SPNUM) & EV_SLOTNUM_MASK) >>EV_SLOTNUM_SHFT);
|
|
|
|
ip_error_log(slot);
|
|
cc_error_log();
|
|
}
|
|
|
|
void
|
|
mem_err_show()
|
|
/* Description : Display error registers in all the MC3 boards in system */
|
|
{
|
|
int i;
|
|
ASSERT_CFG;
|
|
|
|
for (i=0; i < EV_MAX_SLOTS; i++)
|
|
if (SLOTTYPE(i) == EVTYPE_MC3)
|
|
mc3_error_show(i);
|
|
|
|
cpu_err_show();
|
|
|
|
}
|
|
|
|
void
|
|
mem_err_log()
|
|
{
|
|
int i;
|
|
|
|
for (i=0; i < EV_MAX_SLOTS; i++)
|
|
if (SLOTTYPE(i) == EVTYPE_MC3){
|
|
mc3_mem_error_log(i);
|
|
mc3_ebus_error_log(i);
|
|
}
|
|
|
|
|
|
cpu_err_log();
|
|
}
|
|
|
|
int
|
|
io_err_show(int slot, int adap_arr)
|
|
/*
|
|
* Description: Display error registers in CPU board where test is running,
|
|
Error registers on all the MC3 boards,
|
|
Error registers on the IO4 board in 'slot', and
|
|
Error registers in the adapters specified by adap_arr
|
|
*/
|
|
{
|
|
int i;
|
|
|
|
ASSERT_CFG;
|
|
CHECK_SLOT(slot);
|
|
|
|
if (SLOTTYPE(slot) != EVTYPE_IO4)
|
|
return(-1);
|
|
|
|
io4_error_show(slot);
|
|
|
|
for (i=0; i < IO4_MAX_PADAPS; i++)
|
|
if( adap_arr & (1 << i))
|
|
adap_error_show(slot, i);
|
|
|
|
mem_err_show();
|
|
}
|
|
|
|
|
|
io_err_log(int slot, int adap_arr)
|
|
{
|
|
int i;
|
|
|
|
CHECK_SLOT(slot);
|
|
|
|
if (SLOTTYPE(slot) != EVTYPE_IO4)
|
|
return(-1);
|
|
|
|
io4_error_log(slot);
|
|
|
|
for(i=0; i < IO4_MAX_PADAPS; i++)
|
|
if (adap_arr & (1 << i))
|
|
adap_error_log(slot, i);
|
|
|
|
mem_err_log();
|
|
}
|
|
/* TLB Entry 0 could be used by the Graphics people. So try leaving
|
|
* entry 0 and 1 free
|
|
*/
|
|
#define FIRST_TLB_ENTRY 2
|
|
void
|
|
ide_init_tlb()
|
|
/* Description: Initialize all the TLB entries. */
|
|
{
|
|
int i;
|
|
|
|
#if !defined(TFP)
|
|
/*
|
|
* added to synch with the private tlb setup stuff in lib/libsk/ml
|
|
*/
|
|
for (i = 0; !inval_tlbentry(i); i++);
|
|
|
|
for(i=FIRST_TLB_ENTRY; i < NTLBENTRIES; i++)
|
|
invaltlb(i);
|
|
#else
|
|
flush_tlb(0);
|
|
#endif
|
|
|
|
}
|
|
|
|
/* returns the s1num (set up by libsk) based on slot, adap */
|
|
int
|
|
s1num_from_slotadap(int slot, int adap)
|
|
{
|
|
int i, j;
|
|
int s1num = 0;
|
|
int atype;
|
|
|
|
msg_printf(DBG,"slot is %d and adap is %d\n", slot, adap);
|
|
for (i = EV_MAX_SLOTS; i > 0; i--) {
|
|
if (board_type(i) == EVTYPE_IO4) {
|
|
for (j = 1; j < IO4_MAX_PADAPS; j++) {
|
|
atype = adap_type(i, j);
|
|
if (atype == IO4_ADAP_SCSI) {
|
|
msg_printf(DBG,"i: %d, j: %d\n", i,j);
|
|
if ((slot == i) && (adap == j)) {
|
|
msg_printf(DBG,
|
|
"s1num_from_slotadap: ");
|
|
msg_printf(DBG,"s1num %d\n",
|
|
s1num);
|
|
return (s1num);
|
|
}
|
|
s1num++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
msg_printf(ERR,"No s1 chips found!\n");
|
|
}
|
|
|
|
|
|
/* from evintr.c, pieces of evintr_connect() */
|
|
int
|
|
s1_intr_setup(__psunsigned_t swin, int my_s1_num)
|
|
{
|
|
int arg, dest, intrdest, level, proc, slot;
|
|
|
|
arg = my_s1_num;
|
|
proc = (EV_GET_LOCAL(EV_SPNUM) & EV_PROCNUM_MASK) >> EV_PROCNUM_SHFT;
|
|
slot = (EV_GET_LOCAL(EV_SPNUM) & EV_SLOTNUM_MASK) >> EV_SLOTNUM_SHFT;
|
|
msg_printf(DBG, "Running CPU %d on IP19 in slot %d\n", proc, slot);
|
|
|
|
intrdest = (slot << 2) | proc;
|
|
msg_printf(DBG,"intrdest is 0x%x\n", intrdest);
|
|
|
|
EV_SET_REG(
|
|
swin + S1_DMA_INTERRUPT,
|
|
EVINTR_VECTOR(
|
|
EVINTR_LEVEL_S1_CHIP(my_s1_num),
|
|
intrdest));
|
|
level = S1_GET_REG(swin, S1_DMA_INTERRUPT);
|
|
S1_PUT_REG(swin, S1_DMA_INTERRUPT + S1_DMA_INT_OFFSET, level);
|
|
S1_PUT_REG(swin,S1_DMA_INTERRUPT + 2*S1_DMA_INT_OFFSET, level);
|
|
S1_PUT_REG(swin, S1_INTERRUPT, level);
|
|
msg_printf(DBG,"level is 0x%x\n", level);
|
|
}
|
|
|
|
void
|
|
setup_err_intr(int slot, int anum)
|
|
/*
|
|
* Description: If the 'slot' has a MC3 board, anum is ignored, and
|
|
the Interrupt vector is setup for MC3. Otherwise
|
|
Setup Intr vector for all memory boards, IO4 board in 'slot'
|
|
and for the defined Adapter,
|
|
The error interrupts are targeted to CPU where test runs
|
|
*/
|
|
{
|
|
int i, ivect, level, my_s1_num, win, btype;
|
|
evioacfg_t *ioa;
|
|
long long pend, cel;
|
|
__psunsigned_t swin;
|
|
volatile long long *adptr;
|
|
|
|
#if defined(TFP)
|
|
/* clear possible bad parity errors */
|
|
tfp_clear_gparity_error();
|
|
#endif
|
|
#if defined(TFP) || defined(IP25)
|
|
/* Disable interrupts on the R8K/R10K processor */
|
|
set_SR(get_SR() & ~(SR_IMASK | SRB_SCHEDCLK | SRB_ERR | SR_IE | SR_EXL));
|
|
#else
|
|
/* Disable interrupts on the R4k processor */
|
|
set_SR(get_SR() & ~SR_IE & ~(SR_EXL | SR_ERL));
|
|
#endif
|
|
|
|
ASSERT_CFG;
|
|
|
|
if ((slot < 0) || (slot >= EV_MAX_SLOTS))
|
|
return;
|
|
|
|
ivect = (EV_GET_REG(EV_SPNUM) & EV_SPNUM_MASK) | IDE_ERR_VECTOR;
|
|
|
|
switch(btype = SLOTTYPE(slot)){
|
|
|
|
case EVTYPE_IP19: break;
|
|
|
|
case EVTYPE_MC3 : MC3_SETREG(slot, MC3_EBUSERRINT, ivect); break;
|
|
|
|
case EVTYPE_IO4 :
|
|
ivect = EVINTR_VECTOR(EVINTR_LEVEL_IO4_ERROR,
|
|
(EV_GET_REG(EV_SPNUM) & EV_SPNUM_MASK));
|
|
IO4_SETCONF_REG(slot, IO4_CONF_INTRVECTOR, ivect);
|
|
IO4_SETCONF_REG(slot, IO4_CONF_INTRMASK, 0x2);
|
|
|
|
/*
|
|
* clear any pending errors
|
|
*/
|
|
i = EV_GET_CONFIG(slot, IO4_CONF_IBUSERRORCLR);
|
|
i = EV_GET_CONFIG(slot, IO4_CONF_EBUSERRORCLR);
|
|
|
|
|
|
win = IO4_WINDOW(slot);
|
|
ioa = IOASTRU(slot, anum);
|
|
swin = (__psunsigned_t)SWIN_BASE(win, anum);
|
|
adptr = (long long *)swin; /* for dang, mostly */
|
|
|
|
/*
|
|
*
|
|
* anum == 0 means set up the io4 ia/id stuff only
|
|
*/
|
|
if (anum) {
|
|
|
|
switch(ioa->ioa_type){
|
|
|
|
case IO4_ADAP_FCHIP:
|
|
EV_SET_REG(swin+FCHIP_INTR_RESET_MASK, 0x1);
|
|
EV_SET_REG(swin+FCHIP_INTR_MAP, ivect);
|
|
|
|
if (EV_GET_REG(swin+FCHIP_MASTER_ID) == IO4_ADAP_VMECC){
|
|
EV_SET_REG(swin+VMECC_INT_ENABLESET, 0x1);
|
|
EV_SET_REG(swin+VMECC_VECTORERROR, ivect);
|
|
}
|
|
/* Need code for FCG case */
|
|
break;
|
|
|
|
case IO4_ADAP_SCSI:
|
|
my_s1_num = s1num_from_slotadap(slot, anum);
|
|
s1_intr_setup(swin, my_s1_num);
|
|
level = S1_GET_REG(swin, S1_DMA_INTERRUPT);
|
|
S1_PUT_REG(swin, S1_DMA_INTERRUPT + S1_DMA_INT_OFFSET, level);
|
|
S1_PUT_REG(swin,S1_DMA_INTERRUPT + 2*S1_DMA_INT_OFFSET, level);
|
|
S1_PUT_REG(swin, S1_INTERRUPT, level);
|
|
break;
|
|
|
|
case IO4_ADAP_EPC :
|
|
/*
|
|
* currently, clears existing errors, initializes the interrupt
|
|
* registers and mask for the duarts and I/O errors
|
|
*/
|
|
EV_SET_REG(swin + EPC_IMRST, 0xFF);
|
|
EV_SET_REG(swin + EPC_IERR, 0x1000000);
|
|
EV_GET_REG(swin + EPC_IERRC);
|
|
|
|
ivect = EVINTR_VECTOR(EVINTR_LEVEL_EPC_DUART0,
|
|
(EV_GET_REG(EV_SPNUM) & EV_SPNUM_MASK));
|
|
|
|
/* msg_printf(DBG, "EPC DUART 0 ivect was %x\n", ivect); */
|
|
EV_SET_REG(swin + EPC_IIDDUART0, ivect);
|
|
|
|
ivect = EVINTR_VECTOR(EVINTR_LEVEL_EPC_DUART1,
|
|
(EV_GET_REG(EV_SPNUM) & EV_SPNUM_MASK));
|
|
/* msg_printf(DBG, "EPC DUART 1/2 ivect was %x\n", ivect); */
|
|
EV_SET_REG(swin + EPC_IIDDUART1, ivect);
|
|
|
|
ivect = EVINTR_VECTOR(EVINTR_LEVEL_EPC_PPORT,
|
|
(EV_GET_REG(EV_SPNUM) & EV_SPNUM_MASK));
|
|
/* msg_printf(DBG, "EPC PPORT ivect was %x\n", ivect); */
|
|
EV_SET_REG(swin + EPC_IIDPPORT, ivect);
|
|
|
|
ivect = EVINTR_VECTOR(EVINTR_LEVEL_EPC_ERROR,
|
|
(EV_GET_REG(EV_SPNUM) & EV_SPNUM_MASK));
|
|
/* msg_printf(DBG, "EPC ERROR ivect was %x\n", ivect); */
|
|
EV_SET_REG(swin + EPC_IIDERROR, ivect);
|
|
|
|
ivect = EVINTR_VECTOR(EVINTR_LEVEL_EPC_PROFTIM,
|
|
(EV_GET_REG(EV_SPNUM) & EV_SPNUM_MASK));
|
|
/* msg_printf(DBG, "EPC PROFTIM ivect was %x\n", ivect); */
|
|
EV_SET_REG(swin + EPC_IIDPROFTIM, ivect);
|
|
|
|
ivect = EVINTR_VECTOR(EVINTR_LEVEL_EPC_ERROR,
|
|
(EV_GET_REG(EV_SPNUM) & EV_SPNUM_MASK));
|
|
/* msg_printf(DBG, "EPC PROFTIM ivect was %x\n", ivect); */
|
|
EV_SET_REG(swin + EPC_IIDSPARE, ivect);
|
|
|
|
i = (int) EV_GET_REG(swin + EPC_ISTAT) |
|
|
EPC_INTR_DUART0 | EPC_INTR_DUART12 |
|
|
EPC_INTR_ERROR | EPC_INTR_PROFTIM |
|
|
EPC_INTR_PPORT | EPC_INTR_SPARE;
|
|
EV_SET_REG(swin + EPC_IMSET, i);
|
|
break;
|
|
|
|
case IO4_ADAP_DANG :
|
|
|
|
/*
|
|
* currently, clears existing errors after disabling all
|
|
* possible DANG interrupt sources. The interrupt vectors
|
|
* all map to the same location, but it is up to the
|
|
* test code to enable an interrupt source and interpret
|
|
* the interrupt cause.
|
|
*/
|
|
|
|
i = (int)load_double((long long*)&adptr[DANG_PIO_ERR_CLR]);
|
|
i = (int)load_double((long long*)&adptr[DANG_DMAM_ERR_CLR]);
|
|
i = (int)load_double((long long*)&adptr[DANG_DMAS_ERR_CLR]);
|
|
i = (int)load_double((long long*)&adptr[DANG_WG_PRIV_ERR_CLR]);
|
|
i = (int)load_double(
|
|
(long long*)&adptr[DANG_DMAM_COMPLETE_CLR]);
|
|
|
|
/*
|
|
* disable all interrupt sources
|
|
*/
|
|
i = (int) DANG_IENA_CLEAR | DANG_ISTAT_DCHIP |
|
|
DANG_ISTAT_DMAM_CMP | DANG_ISTAT_WG_FLOW |
|
|
DANG_ISTAT_WG_FHI | DANG_ISTAT_WG_FULL |
|
|
DANG_ISTAT_WG_PRIV | DANG_ISTAT_GIO0 |
|
|
DANG_ISTAT_GIO1 | DANG_ISTAT_GIO2;
|
|
store_double((long long*)&adptr[DANG_INTR_ENABLE],
|
|
(long long) i);
|
|
|
|
/*
|
|
* DANG interrupts will all use the same handler in the
|
|
* standalones, all the error interrupt vectors point to
|
|
* the same location - kinda kludgy, when you consider the
|
|
* EPC has scads o' vectors, but that is the model found
|
|
* in the kernel and evintr.h
|
|
* GIO has its own vector, and DMA comes in at the calculated
|
|
* vector
|
|
*
|
|
* yes, invects are built funny here - have to reverse for
|
|
* some reason
|
|
*/
|
|
|
|
ivect = EVINTR_VECTOR(EVINTR_LEVEL_DANG_GIO,
|
|
(EV_GET_REG(EV_SPNUM) & EV_SPNUM_MASK));
|
|
store_double((long long*)&adptr[DANG_INTR_GIO_0],
|
|
(long long) ivect);
|
|
ivect = EVINTR_VECTOR(DANG_INTR_LEVEL(1),
|
|
(EV_GET_REG(EV_SPNUM) & EV_SPNUM_MASK));
|
|
store_double((long long*)&adptr[DANG_INTR_DMAM_COMPLETE],
|
|
(long long) ivect);
|
|
ivect = EVINTR_VECTOR(EVINTR_LEVEL_DANG_ERROR,
|
|
(EV_GET_REG(EV_SPNUM) & EV_SPNUM_MASK));
|
|
store_double((long long*)&adptr[DANG_INTR_PRIV_ERR],
|
|
(long long) ivect);
|
|
store_double((long long*)&adptr[DANG_INTR_PAUSE],
|
|
(long long) ivect);
|
|
store_double((long long*)&adptr[DANG_INTR_BREAK],
|
|
(long long) ivect);
|
|
|
|
/* set only dest for these - rest comes in at wg */
|
|
ivect = EVINTR_LEVEL_DANG_ERROR;
|
|
store_double((long long*)&adptr[DANG_INTR_LOWATER],
|
|
(long long) ivect);
|
|
store_double((long long*)&adptr[DANG_INTR_HIWATER],
|
|
(long long) ivect);
|
|
store_double((long long*)&adptr[DANG_INTR_FULL],
|
|
(long long) ivect);
|
|
|
|
i = (int)load_double((long long*)&adptr[DANG_PIO_ERR_CLR]);
|
|
i = (int)load_double((long long*)&adptr[DANG_DMAM_ERR_CLR]);
|
|
i = (int)load_double((long long*)&adptr[DANG_DMAS_ERR_CLR]);
|
|
i = (int)load_double((long long*)&adptr[DANG_WG_PRIV_ERR_CLR]);
|
|
i = (int)load_double(
|
|
(long long*)&adptr[DANG_DMAM_COMPLETE_CLR]);
|
|
|
|
break;
|
|
|
|
default :
|
|
msg_printf(ERR,
|
|
"Invalid adapter type %x at slot %d adap-no %d\n",
|
|
ioa->ioa_type, slot, anum);
|
|
break;
|
|
}
|
|
}
|
|
|
|
for (i=1; i < EV_MAX_SLOTS; i++){
|
|
if (SLOTTYPE(i) != EVTYPE_MC3)
|
|
continue;
|
|
MC3_SETREG(i, MC3_EBUSERRINT, ivect);
|
|
}
|
|
break;
|
|
|
|
default:
|
|
msg_printf(ERR, "Invalid Board type %d in slot %d\n",btype, slot);
|
|
break;
|
|
}
|
|
|
|
/* Some misc stuff */
|
|
/* It is possible that some old interrupts are hanging around.
|
|
* (from initial IP19 PROM launch in particular). Clean them
|
|
* up.
|
|
*/
|
|
for (i = 0; i < EVINTR_MAX_LEVELS; i++)
|
|
EV_SET_LOCAL(EV_CIPL0, i);
|
|
EV_SET_LOCAL(EV_CIPL124, 0x7);
|
|
EV_SET_LOCAL(EV_IP0, 0);
|
|
EV_SET_LOCAL(EV_IP1, 0);
|
|
|
|
/*
|
|
* as long as interrupts still pending, clear them
|
|
*/
|
|
while (pend = EV_GET_REG(EV_HPIL)) {
|
|
msg_printf(DBG, "interrupt level %x still pending\n", (int) pend);
|
|
EV_SET_REG(EV_CIPL0, pend);
|
|
}
|
|
|
|
|
|
#if TFP || IP25
|
|
EV_SET_REG(EV_CERTOIP, 0xffff); /* Clear Bus Error */
|
|
EV_SET_LOCAL(EV_ILE,
|
|
(EV_EBUSINT_MASK|EV_ERTOINT_MASK)); /* re-enable BE */
|
|
#else
|
|
EV_SET_REG(EV_ILE, (EV_GET_REG(EV_ILE) | 0x1)); /* Enable Lev 1 Intr */
|
|
#endif
|
|
|
|
#if TFP || IP25
|
|
/* Disable interrupts on the TFP processor */
|
|
set_SR(get_SR() & ~(SR_IMASK | SRB_SCHEDCLK | SRB_ERR | SR_IE | SR_EXL));
|
|
#else
|
|
/* Disable interrupts on the R4k processor */
|
|
set_SR(get_SR() & ~SR_IE & ~(SR_EXL | SR_ERL));
|
|
#endif
|
|
}
|
|
|
|
cpu_intr_pending()
|
|
{
|
|
#if _MIPS_SIM != _ABI64
|
|
__psunsigned_t t0l, t0h, t1l, t1h;
|
|
int retval;
|
|
|
|
/*
|
|
* This nastiness is required to work around a compiler bug -
|
|
* some logical operations mask off the upper 32 bits of 64 bit
|
|
* values, even when the values being compared are all 64 bit values
|
|
*/
|
|
t0l = load_double_lo(EV_IP0);
|
|
t0h = load_double_hi(EV_IP0);
|
|
t1l = load_double_lo(EV_IP1);
|
|
t1h = load_double_hi(EV_IP1);
|
|
|
|
retval = t0l || t0h || t1l || t1h;
|
|
if (retval)
|
|
msg_printf(DBG,"IP0 lo: 0x%x, IP0 hi: 0x%x, IP1 lo: 0x%x, IP1 hi:0x%x\n",
|
|
t0l, t0h, t1l, t1h);
|
|
#else
|
|
long long t0, t1;
|
|
int retval;
|
|
|
|
t0 = load_double((long long *)EV_IP0);
|
|
t1 = load_double((long long *)EV_IP1);
|
|
|
|
retval = t0 || t1;
|
|
if (retval)
|
|
msg_printf(DBG, "IP0: 0x%llx, IP1: 0x%llx\n",
|
|
(long long) t0, (long long) t1);
|
|
#endif
|
|
return(retval);
|
|
}
|
|
|
|
int
|
|
clear_err_intr(int slot, int anum)
|
|
/* Description: If 'slot' has memory board, ignore anum, clear that vector
|
|
and disable interrupt.
|
|
Otherwise, Clear intr vector in all memory, and IO4 boards in
|
|
'slot' and the adapter defined by <slot, anum>
|
|
*/
|
|
{
|
|
int i, ivect, win, btype;
|
|
__psunsigned_t swin;
|
|
evioacfg_t *ioa;
|
|
long long pend;
|
|
volatile long long * adptr;
|
|
|
|
ASSERT_CFG;
|
|
CHECK_SLOT(slot);
|
|
|
|
#if TFP
|
|
/* clear possible screwed up parity errors */
|
|
tfp_clear_gparity_error();
|
|
#endif
|
|
#if TFP || IP25
|
|
/* Disable interrupts on the R8k/R10k processor */
|
|
set_SR(get_SR() & ~(SR_IMASK | SRB_SCHEDCLK | SRB_ERR | SR_IE | SR_EXL));
|
|
#else
|
|
/* Disable interrupts on the R4k processor */
|
|
set_SR(get_SR() & ~SR_IE & ~(SR_EXL | SR_ERL));
|
|
#endif
|
|
|
|
switch(btype = SLOTTYPE(slot)){
|
|
|
|
case EVTYPE_IP21: break;
|
|
|
|
case EVTYPE_IP19: break;
|
|
|
|
case EVTYPE_MC3 : MC3_SETREG(slot, MC3_EBUSERRINT, 0); break;
|
|
|
|
case EVTYPE_IO4 :
|
|
IO4_SETCONF_REG(slot, IO4_CONF_INTRVECTOR, 0);
|
|
IO4_SETCONF_REG(slot, IO4_CONF_INTRMASK, 0x3);/* Int Disable+Err chk */
|
|
|
|
/*
|
|
* clear any pending errors
|
|
*/
|
|
i = EV_GET_CONFIG(slot, IO4_CONF_IBUSERRORCLR);
|
|
i = EV_GET_CONFIG(slot, IO4_CONF_EBUSERRORCLR);
|
|
|
|
win = IO4_WINDOW(slot);
|
|
ioa = IOASTRU(slot, anum);
|
|
swin = SWIN_BASE(win, anum);
|
|
adptr = (long long *) swin; /* dang, mostly */
|
|
|
|
/*
|
|
*
|
|
* anum == 0 means set up the io4 ia/id stuff only
|
|
*/
|
|
if (anum) {
|
|
|
|
switch(ioa->ioa_type){
|
|
|
|
case IO4_ADAP_FCHIP:
|
|
EV_SET_REG(swin+FCHIP_INTR_SET_MASK, 0x1);
|
|
EV_SET_REG(swin+FCHIP_INTR_MAP, 0);
|
|
|
|
if (EV_GET_REG(swin+FCHIP_MASTER_ID) == IO4_ADAP_VMECC){
|
|
EV_SET_REG(swin+VMECC_INT_ENABLESET, 0);
|
|
EV_SET_REG(swin+VMECC_VECTORERROR, 0);
|
|
}
|
|
/* Need code for FCG case */
|
|
break;
|
|
|
|
case IO4_ADAP_SCSI:
|
|
/*
|
|
* direct steal from setup_err_intr, above
|
|
*/
|
|
i = s1num_from_slotadap(slot, anum);
|
|
s1_intr_setup(swin, i);
|
|
i = S1_GET_REG(swin, S1_DMA_INTERRUPT);
|
|
S1_PUT_REG(swin,
|
|
S1_DMA_INTERRUPT + S1_DMA_INT_OFFSET, i);
|
|
S1_PUT_REG(swin,
|
|
S1_DMA_INTERRUPT + 2*S1_DMA_INT_OFFSET, i);
|
|
S1_PUT_REG(swin, S1_INTERRUPT, i);
|
|
break;
|
|
|
|
case IO4_ADAP_EPC :
|
|
/*
|
|
* need to add code to clear EPC stuff - this just
|
|
* disables the various EPC interupts in
|
|
*/
|
|
i = (int) EV_GET_REG(swin + EPC_ISTAT) |
|
|
EPC_INTR_DUART0 | EPC_INTR_DUART12 |
|
|
EPC_INTR_ERROR | EPC_INTR_PROFTIM |
|
|
EPC_INTR_PPORT | EPC_INTR_SPARE;
|
|
EV_SET_REG(swin + EPC_IMRST, i);
|
|
break;
|
|
|
|
case IO4_ADAP_DANG :
|
|
/*
|
|
* currently, clears existing errors, then disables all
|
|
* possible DANG interrupt sources.
|
|
*/
|
|
i = (int)load_double((long long*)&adptr[DANG_PIO_ERR_CLR]);
|
|
i = (int)load_double((long long*)&adptr[DANG_DMAM_ERR_CLR]);
|
|
i = (int)load_double((long long*)&adptr[DANG_DMAS_ERR_CLR]);
|
|
i = (int)load_double(
|
|
(long long*)&adptr[DANG_WG_PRIV_ERR_CLR]);
|
|
i = (int)load_double(
|
|
(long long*)&adptr[DANG_DMAM_COMPLETE_CLR]);
|
|
|
|
i = DANG_IENA_CLEAR | DANG_ISTAT_DCHIP |
|
|
DANG_ISTAT_DMAM_CMP | DANG_ISTAT_WG_FLOW |
|
|
DANG_ISTAT_WG_FHI | DANG_ISTAT_WG_FULL |
|
|
DANG_ISTAT_WG_PRIV | DANG_ISTAT_GIO0 |
|
|
DANG_ISTAT_GIO1 | DANG_ISTAT_GIO2;
|
|
store_double((long long*)&adptr[DANG_INTR_ENABLE],
|
|
(long long) i);
|
|
|
|
break;
|
|
|
|
default :
|
|
msg_printf(ERR,
|
|
"Invalid adapter type %x at slot %d adap-no %d\n",
|
|
ioa->ioa_type, slot, anum);
|
|
break;
|
|
}
|
|
}
|
|
|
|
for (i=1; i < EV_MAX_SLOTS; i++){
|
|
if (SLOTTYPE(i) != EVTYPE_MC3)
|
|
continue;
|
|
MC3_SETREG(i, MC3_EBUSERRINT, 0);
|
|
}
|
|
break;
|
|
|
|
default:
|
|
msg_printf(ERR, "Invalid Board type %d in slot %d\n",btype, slot);
|
|
break;
|
|
}
|
|
|
|
/* Some misc stuff */
|
|
/* It is possible that some old interrupts are hanging around.
|
|
* (from initial IP19 PROM launch in particular). Clean them
|
|
* up.
|
|
*/
|
|
#if TFP || IP25
|
|
EV_SET_REG(EV_CERTOIP, 0xffff); /* Clear Bus Error */
|
|
#endif
|
|
EV_SET_LOCAL(EV_ILE,
|
|
(EV_EBUSINT_MASK|EV_ERTOINT_MASK)); /* re-enable BE */
|
|
|
|
for (i = 0; i < EVINTR_MAX_LEVELS; i++)
|
|
EV_SET_LOCAL(EV_CIPL0, i);
|
|
EV_SET_LOCAL(EV_CIPL124, 0x7);
|
|
EV_SET_LOCAL(EV_IP0, 0);
|
|
EV_SET_LOCAL(EV_IP1, 0);
|
|
|
|
/*
|
|
* as long as interrupts still pending, clear them
|
|
*/
|
|
while (pend = EV_GET_REG(EV_HPIL)) {
|
|
msg_printf(DBG, "Clearing interrupt vector %x\n", (unsigned)pend);
|
|
EV_SET_REG(EV_CIPL0, pend);
|
|
}
|
|
|
|
return(0);
|
|
}
|
|
|
|
int banks_populated(int slot, int leaf)
|
|
{
|
|
uint leaf0populated = 0x33;
|
|
uint leaf1populated = 0xcc;
|
|
uint populated = 0;
|
|
|
|
if (leaf) {
|
|
populated = leaf1populated & read_reg(slot, MC3_BANKENB);
|
|
}
|
|
else {
|
|
populated = leaf0populated & read_reg(slot, MC3_BANKENB);
|
|
}
|
|
|
|
return(populated);
|
|
|
|
} /* banks_populated */
|
|
|
|
#define CPU_ERROR 1
|
|
#define MEM_ERROR 2
|
|
#define IO_ERROR 4
|
|
|
|
int
|
|
check_cpuereg()
|
|
/* Return Value : 1 if error registers has any bit set, 0 Otherwise. */
|
|
|
|
{
|
|
unsigned a_error, slot;;
|
|
|
|
slot =((EV_GET_REG(EV_SPNUM) & EV_SLOTNUM_MASK)>>EV_SLOTNUM_SHFT);
|
|
a_error = EV_GETCONFIG_REG(slot, 0, EV_A_ERROR);
|
|
if (a_error) {
|
|
msg_printf(ERR, "WARNING: ");
|
|
msg_printf(ERR,"CPU in slot %d, A chip register is non-zero: 0x%x\n",
|
|
slot,a_error);
|
|
}
|
|
msg_printf(DBG,"result is %d at loc 5\n", a_error);
|
|
return((a_error) ? CPU_ERROR : 0);
|
|
}
|
|
|
|
int
|
|
check_memereg(int slot_arr)
|
|
/* slot_arr : 'i'th bit set for MC3 in slot i.
|
|
Return Value : 2 if error register in any of MC3 specified is set |
|
|
1 if the CPU error registers have any bit set.
|
|
0 Otherwise.
|
|
*/
|
|
{
|
|
|
|
int i,j,k, result=0;
|
|
uint reg;
|
|
|
|
for (i=1; i < EV_MAX_SLOTS; i++){
|
|
if ((slot_arr & (1 << i)) == 0)
|
|
continue;
|
|
|
|
reg = MC3_GETREG(i, MC3_EBUSERROR);
|
|
if (reg) {
|
|
msg_printf(ERR, "WARNING: ");
|
|
msg_printf(ERR,
|
|
"slot %d, MC3_EBUSERROR reg is non-zero: 0x%x\n",
|
|
i, reg);
|
|
result |= MEM_ERROR;
|
|
}
|
|
for (j = 0; j < MC3_NUM_LEAVES; j++) {
|
|
reg = MC3_GETLEAFREG(i,j,MC3LF_ERROR);
|
|
if (reg) {
|
|
msg_printf(ERR, "WARNING: ");
|
|
msg_printf(ERR,
|
|
"slot %d, MC3LF_ERROR reg:leaf-%d is non-zero: 0x%x\n",
|
|
i, j, reg);
|
|
result |= MEM_ERROR;
|
|
}
|
|
reg = MC3_GETLEAFREG(i,j,MC3LF_ERRADDRHI);
|
|
if (reg) {
|
|
msg_printf(ERR, "WARNING: ");
|
|
msg_printf(ERR,
|
|
"slot %d, MC3LF_ERRADDRHI reg: leaf-%d is non-zero: 0x%x\n",
|
|
i, j, reg);
|
|
result |= MEM_ERROR;
|
|
}
|
|
reg = MC3_GETLEAFREG(i,j,MC3LF_ERRADDRLO);
|
|
if (reg) {
|
|
msg_printf(ERR, "WARNING: ");
|
|
msg_printf(ERR,
|
|
"slot %d, MC3LF_ERRADDRLO reg: leaf-%d is non-zero: 0x%x\n",
|
|
i, j, reg);
|
|
result |= MEM_ERROR;
|
|
}
|
|
/*
|
|
if (banks_populated(i, j))
|
|
for (k = 0; k < MC3_BANKS_PER_LEAF; k++) {
|
|
reg = MC3_GETLEAFREG(i, j, MC3LF_SYNDROME0 + k);
|
|
if (reg) {
|
|
msg_printf(ERR, "WARNING: ");
|
|
msg_printf(ERR,
|
|
"slot %d, leaf %d, SYNDROME%d is non-zero: 0x%x\n",
|
|
i, j, k, reg);
|
|
result |= MEM_ERROR;
|
|
}
|
|
}
|
|
*/
|
|
}
|
|
if (result)
|
|
break; /* Since there is some error, why continue */
|
|
|
|
}
|
|
msg_printf(DBG,"result is %d at loc 4\n", result);
|
|
result |= check_cpuereg();
|
|
|
|
return(result);
|
|
}
|
|
|
|
int
|
|
check_ioereg(int slot, int adap_arr)
|
|
/* adap_arr : 'i' the bit set for Adapter 'i'
|
|
* Return Value : 4 if error reg in any of adap in IO4 is set | (Bit ORing)
|
|
2 if error register in any of MC3 is set | (Bit ORing)
|
|
1 if the CPU error registers have any bit set.
|
|
0 Otherwise.
|
|
*/
|
|
{
|
|
int i, result=0;
|
|
unsigned win, mem_arr=0, reg;
|
|
__psunsigned_t swin;
|
|
evioacfg_t *ioa;
|
|
|
|
reg = IO4_GETCONF_REG(slot, IO4_CONF_IBUSERROR);
|
|
if (reg) {
|
|
msg_printf(ERR, "WARNING: ");
|
|
msg_printf(ERR,
|
|
"slot %d, IO4_CONF_IBUSERROR Reg is non-zero: 0x%x\n",
|
|
slot, reg);
|
|
result |= IO_ERROR;
|
|
}
|
|
reg = IO4_GETCONF_REG(slot, IO4_CONF_EBUSERROR);
|
|
if (reg) {
|
|
msg_printf(ERR, "WARNING: ");
|
|
msg_printf(ERR,
|
|
"slot %d, IO4_CONF_EBUSERROR Reg is non-zero: 0x%x\n",
|
|
slot, reg);
|
|
result |= IO_ERROR;
|
|
}
|
|
|
|
msg_printf(DBG,"result is %d at loc 1\n", result);
|
|
if (result == 0){
|
|
for (i=1; i < IO4_MAX_PADAPS; i++){
|
|
if ((adap_arr & (1 << i)) == 0)
|
|
continue;
|
|
|
|
win = IO4_WINDOW(slot);
|
|
ioa = IOASTRU(slot, i);
|
|
swin = SWIN_BASE(win, i);
|
|
|
|
switch(ioa->ioa_type){
|
|
case IO4_ADAP_VMECC:
|
|
reg = EV_GET_REG(swin+FCHIP_ERROR);
|
|
if (reg) {
|
|
msg_printf(ERR, "WARNING: ");
|
|
msg_printf(ERR,
|
|
"slot %d, FCHIP_ERROR Reg is non-zero: 0x%x\n",
|
|
slot, reg);
|
|
result |= IO_ERROR;
|
|
}
|
|
reg = EV_GET_REG(swin+ VMECC_ERRORCAUSES);
|
|
if (reg) {
|
|
msg_printf(ERR, "WARNING: ");
|
|
msg_printf(ERR,
|
|
"slot %d, VMECC_ERRORCAUSES Reg is non-zero: 0x%x\n",
|
|
slot, reg);
|
|
result |= IO_ERROR;
|
|
}
|
|
break;
|
|
|
|
case IO4_ADAP_FCG : break;
|
|
case IO4_ADAP_SCSI : break;
|
|
case IO4_ADAP_EPC : break;
|
|
default : break;
|
|
}
|
|
|
|
if (result)
|
|
break;
|
|
}
|
|
}
|
|
msg_printf(DBG,"result is %d at loc 2\n", result);
|
|
|
|
for(i=1; i < EV_MAX_SLOTS; i++)
|
|
if (SLOTTYPE(i) == EVTYPE_MC3)
|
|
mem_arr |= (1 << i);
|
|
|
|
result |= check_memereg(mem_arr);
|
|
|
|
msg_printf(DBG,"result is %d at loc 3\n", result);
|
|
return(result);
|
|
}
|
|
|
|
int report_check_error(int fail)
|
|
{
|
|
msg_printf(INFO,"WARNING: ");
|
|
if (!fail)
|
|
msg_printf(INFO,"Test passed, but got an ");
|
|
msg_printf(INFO,"Unexpected ERROR in a register\n");
|
|
}
|
|
|
|
|
|
/*
|
|
* Routine to facilitate accessing memory beyond 512 MB
|
|
* Assumptions:
|
|
* This is NOT a general purpose TLB mapping routine.
|
|
* This should be used with extreme care.
|
|
* It works as below
|
|
* If the address to be mapped is below 512 Mbytes, then either
|
|
* K0 or K1 address is returned based on the value of 'cached'
|
|
*
|
|
* If the address is above 512 Mbytes, then the routine makes
|
|
* as many TLB entries as needed to map 'size' bytes. Maximum
|
|
* size of memory chunk that can be mapped is 512 Mbytes.
|
|
*
|
|
* Each time the routine is called, it clears all the TLB entries
|
|
*
|
|
* This should be called only when a new chunk of memory needs to
|
|
* be mapped by the memory testing program.
|
|
*
|
|
* FOR ADDRESS > 512MB,
|
|
* THIS SHOULD BE CALLED WITH 'addr' at any 16 Mbyte boundary
|
|
*
|
|
* NOTE: Provides special treatment for uncached memory address space
|
|
* mapping to local resource addresses.
|
|
*/
|
|
#define DIRECT_MAP 0x20000000 /* Address < this Needs no mapping */
|
|
|
|
#define UNCACH_START 0x00010000
|
|
#define UNCACH_END 0x00020000
|
|
#define NEW_MAPADDR 0x00ff0000 /* 0xff0000000 >> 12 */
|
|
|
|
unsigned pfns[64];
|
|
|
|
__psunsigned_t map_addr(__psunsigned_t addr, int size, int cached)
|
|
{
|
|
unsigned paddr, pfaddr, offs, npaddr;
|
|
pde_t pfnevn, pfnodd;
|
|
int tlbindx;
|
|
__psunsigned_t vpn, startaddr;
|
|
unsigned int mypaddr;
|
|
|
|
#ifdef USE_K0ADDR
|
|
if (addr < (long long)DIRECT_MAP){
|
|
paddr = (unsigned)addr;
|
|
msg_printf(DBG,"cached is %d\n", cached);
|
|
|
|
(cached) ? msg_printf(DBG,"cached\n") : msg_printf(DBG,"uncached\n");
|
|
mypaddr = ((cached) ? PHYS_TO_K0(paddr) : PHYS_TO_K1(paddr));
|
|
msg_printf(DBG,"mypaddr is 0x%x and paddr is 0x%x\n", mypaddr, paddr);
|
|
msg_printf(DBG,"k0: 0x%x, k1:0x%x\n",
|
|
PHYS_TO_K0(paddr), PHYS_TO_K1(paddr));
|
|
return((cached) ? PHYS_TO_K0(paddr) : PHYS_TO_K1(paddr));
|
|
}
|
|
#endif
|
|
|
|
offs = (unsigned)(addr & (long long)(IOMAP_VPAGESIZE - 1));
|
|
paddr = (unsigned)(addr & (long long)~(IOMAP_VPAGESIZE - 1)) >> BPCSHIFT;
|
|
tlbindx = FIRST_TLB_ENTRY;
|
|
/*startaddr = vpn = IOMAP_BASE + ( tlbindx * IOMAP_VPAGESIZE * 2); */
|
|
startaddr = vpn = IOMAP_BASE;
|
|
|
|
/* ide_init_tlb(); */
|
|
|
|
/* Truncate Max mapped size to 512 Mbyts */
|
|
if (size > DIRECT_MAP)
|
|
size = DIRECT_MAP;
|
|
|
|
msg_printf(DBG,"addr: 0x%x size = 0x%x cached: %d\n", paddr, size, cached);
|
|
|
|
do{
|
|
invaltlb(tlbindx); /* Invalidate required entry */
|
|
/* If uncached, and falls in the local resource area, map it to
|
|
* the unique address supported by CC Physical 0xff0000000
|
|
*/
|
|
|
|
pfns[tlbindx] = paddr;
|
|
/* Two different checkings for those address range which cross
|
|
* this boundary . npaddr is used so that paddr still tracks the
|
|
* actual physical address, and can be used after crossing 512 MB
|
|
*/
|
|
if (!cached && (paddr >= UNCACH_START) && (paddr < UNCACH_END)){
|
|
npaddr = NEW_MAPADDR + (paddr & 0xffff);
|
|
pfnevn.pgi = npaddr << 6;
|
|
}
|
|
else pfnevn.pgi = paddr << 6;
|
|
|
|
paddr += (IOMAP_VPAGESIZE >> BPCSHIFT);
|
|
|
|
if (!cached && (paddr >= UNCACH_START) && (paddr < UNCACH_END)){
|
|
npaddr = NEW_MAPADDR + (paddr & 0xffff);
|
|
pfnodd.pgi = npaddr << 6;
|
|
}
|
|
else pfnodd.pgi = paddr << 6;
|
|
|
|
if (cached){
|
|
pfnevn.pgi |= 0x1f; pfnodd.pgi |= 0x1f;
|
|
}
|
|
else{
|
|
pfnevn.pgi |= 0x17; pfnodd.pgi |= 0x17;
|
|
}
|
|
|
|
|
|
set_pgmask(IOMAP_TLBPAGEMASK); /* 16 MB pagesize */
|
|
#if !defined(TFP)
|
|
tlbwired(tlbindx++, 0, (caddr_t)vpn, pfnevn.pgi, pfnodd.pgi);
|
|
#else
|
|
tlbwired(tlbindx++, 0, (caddr_t)vpn, pfnevn.pte);
|
|
#endif
|
|
paddr += (IOMAP_VPAGESIZE >> BPCSHIFT);
|
|
size -= (IOMAP_VPAGESIZE * 2);
|
|
vpn += (IOMAP_VPAGESIZE * 2);
|
|
|
|
}while(size > 0);
|
|
|
|
return((unsigned)(startaddr | offs));
|
|
|
|
}
|
|
|
|
long long
|
|
vir2phys(unsigned virtaddr)
|
|
{
|
|
int indx;
|
|
long long pfn;
|
|
|
|
if ((virtaddr < IOMAP_BASE) || (virtaddr > (IOMAP_BASE + DIRECT_MAP)))
|
|
return ( -1);
|
|
|
|
indx = (virtaddr - IOMAP_BASE)/(IOMAP_VPAGESIZE * 2) ;
|
|
pfn = (long long)pfns[indx+FIRST_TLB_ENTRY] << BPCSHIFT;
|
|
|
|
if (virtaddr & IOMAP_VPAGESIZE)
|
|
pfn += IOMAP_VPAGESIZE ;
|
|
|
|
return(pfn + (virtaddr & (IOMAP_VPAGESIZE - 1)));
|
|
}
|
|
|
|
extern catalog_t *Global_Catalog[];
|
|
char hint_buf[256];
|
|
|
|
/*VARARGS2*/
|
|
err_msg(uint hint, void *physloc, ...)
|
|
{
|
|
va_list ap;
|
|
hint_t *h;
|
|
catalog_t **ct;
|
|
uint *subhints, got_boardtype = 0;
|
|
|
|
msg_printf(ERR, "BOARD_HINT_MASK %x SUBSYS_HINT_MASK %x hint %x\n", BOARD_HINT_MASK, SUBSYS_HINT_MASK, hint);
|
|
for (ct=Global_Catalog; *ct; ct++){
|
|
subhints = (*ct)->cat_fntable->subsystem;
|
|
msg_printf(ERR, "*subhints %x\n", *subhints);
|
|
|
|
if (((*subhints)&BOARD_HINT_MASK) != (hint & BOARD_HINT_MASK))
|
|
continue;
|
|
|
|
got_boardtype = 0;
|
|
for(; *subhints; subhints++){
|
|
if (((*subhints)&SUBSYS_HINT_MASK) == (hint & SUBSYS_HINT_MASK))
|
|
break;
|
|
}
|
|
if (*subhints)
|
|
break; /* Got the needed catalog */
|
|
}
|
|
|
|
if (*ct == (catalog_t *)0){
|
|
if (got_boardtype)
|
|
msg_printf(ERR,"err_msg: No valid sybsystem for hint:%07x\n",hint);
|
|
else
|
|
msg_printf(ERR, "err_msg: Bad Board type for Hint: %07x \n", hint);
|
|
return(0);
|
|
}
|
|
h = (*ct)->hints;
|
|
|
|
for(h=(*ct)->hints; h->hint_num; h++){
|
|
if (h->hint_num == hint)
|
|
break;
|
|
}
|
|
|
|
if (h->hint_num == 0){
|
|
msg_printf(ERR, "err_msg: No Hint msg for Hint: %07x \n", hint);
|
|
return(0);
|
|
}
|
|
|
|
|
|
msg_printf(ERR, "ERROR %07x: %s FAILED ", h->hint_num, h->hint_func);
|
|
|
|
/* Subsystem specific physical location description */
|
|
if ((*ct)->cat_fntable->printfn)
|
|
((*ct)->cat_fntable->printfn)(physloc);
|
|
else
|
|
msg_printf(ERR, "\n");
|
|
|
|
if (h->hint_msg){
|
|
hint_buf[0] = '+';
|
|
va_start(ap, physloc);
|
|
vsprintf(&hint_buf[1], h->hint_msg, ap);
|
|
va_end(ap);
|
|
|
|
msg_printf(ERR, "%s\n", hint_buf);
|
|
}
|
|
ev_perr(0, "HARDWARE ERROR STATE:\n");
|
|
r4kregs();
|
|
}
|
|
|
|
|
|
static char *exc_names[] = {
|
|
/*0-3*/ "Interrupt", "Page Modified", "Load TLB Miss", "Store TLB Miss",
|
|
/*4-7*/ "Load Addr Err", "Store Addr Err", "Instr Bus Err", "Data Bus Err",
|
|
/*8-11*/ "System Call", "Breakpoint", "Reserved Instr", "Cop. Unusable",
|
|
/*12-15*/ "Overflow", "Trap", "Instr VCE", "Float pt Exc",
|
|
/*16-23*/ "-", "-", "-", "-","-", "-", "-", "Watchpoint",
|
|
/*24-31*/ "-", "-", "-", "-","-", "-", "-", "Data VCE"
|
|
};
|
|
|
|
|
|
void r4kregs(void)
|
|
{
|
|
int exc_code, int_bits, i;
|
|
|
|
exc_code = (_cause_save & CAUSE_EXCMASK ) >> CAUSE_EXCSHIFT;
|
|
if ((exc_code != EXC_IBE) || (exc_code != EXC_DBE))
|
|
return; /* Not interesting */
|
|
|
|
ev_perr(1, "(INT:");
|
|
|
|
int_bits = (_cause_save & CAUSE_IPMASK) >> CAUSE_IPSHIFT;
|
|
|
|
for(i=8; i > 0; i--){
|
|
if (( 1 << (i - 1)) & int_bits)
|
|
msg_printf(ERR, "%d", i);
|
|
else
|
|
msg_printf(ERR, "-");
|
|
}
|
|
if (exc_code)
|
|
msg_printf(ERR, " <%s> )\n", exc_names[exc_code]);
|
|
else
|
|
msg_printf(ERR, ")\n");
|
|
|
|
ev_perr(1, "EPC: 0x%x\tCause: 0x%x\tStatus: 0x%x\n",
|
|
_epc_save, _cause_save, _sr_save);
|
|
|
|
#if !defined(TFP) && !defined(IP25) /* THIS IS A HACK - must fix */
|
|
ev_perr(1, "ErrEPC: 0x%x\tBadVA: 0x%x\tReturn: 0x%x\n",
|
|
_error_epc_save, _badvaddr_save, _regs[31]);
|
|
#endif
|
|
|
|
_cause_save = 0; /* Reset so that future calls will not be confused */
|
|
}
|
|
|
|
/* Some dummy routines till they get defined in everror.c */
|
|
int sendintr(cpuid_t cpuid, unchar cpuno){}
|
|
|
|
int clear_IP()
|
|
{
|
|
int i;
|
|
long long tmp, tmp1, tmp2;
|
|
|
|
tmp = EV_GET_LOCAL(EV_IP0);
|
|
msg_printf(DBG, "IP0 register before test 0x%llx\n", tmp);
|
|
if (tmp)
|
|
{
|
|
msg_printf(DBG, "Clearing IP0 register\n");
|
|
for (i = 0; i < 64; i++)
|
|
{
|
|
if (tmp & ((long long)0x1))
|
|
{
|
|
msg_printf(DBG,
|
|
"Pending interrupt at priority 0x%x prior to test\n", i);
|
|
|
|
/* Clear pending interrupt. */
|
|
EV_SET_LOCAL(EV_CIPL0, i);
|
|
|
|
/* Wait a cycle (is this necessary?). */
|
|
tmp1 = EV_GET_LOCAL(EV_RO_COMPARE);
|
|
|
|
}
|
|
tmp = tmp >> 1;
|
|
}
|
|
}
|
|
tmp = EV_GET_LOCAL(EV_IP1);
|
|
msg_printf(DBG, "IP1 register before test 0x%llx\n", tmp);
|
|
if (tmp)
|
|
{
|
|
msg_printf(DBG, "Clearing IP1 register\n");
|
|
for (i = 64; i < 127; i++)
|
|
{
|
|
if (tmp & 1)
|
|
{
|
|
msg_printf(DBG,
|
|
"Pending interrupt at priority 0x%x prior to test\n", i);
|
|
|
|
/* Clear pending interrupt. */
|
|
EV_SET_LOCAL(EV_CIPL0, i);
|
|
|
|
/* Wait a cycle (is this necessary?). */
|
|
tmp1 = EV_GET_LOCAL(EV_RO_COMPARE);
|
|
|
|
}
|
|
tmp = tmp >> 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
void ide_invalidate_caches(void)
|
|
{
|
|
clear_bustags();
|
|
invalidate_caches();
|
|
}
|
|
#endif /* EVEREST */
|