1
0
Files
irix-657m-src/stand/arcs/IP27prom/prom_error.c
2022-09-29 17:59:04 +03:00

467 lines
12 KiB
C

/**************************************************************************
* *
* Copyright (C) 1992-1996, 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. *
* *
**************************************************************************/
/*
* File: prom_error.c
* save/restore of error registers. Other miscellaneous functionality
* for error reporting.
*/
#include <sys/types.h>
#include <sys/sbd.h>
#include <libkl.h>
#include <sys/SN/SN0/IP27.h>
#include "ip27prom.h"
#include "libasm.h"
#include "mdir.h"
extern int kl_error_check_power_on(void);
int
error_check_reset(void)
{
int errors = 0;
int crb;
hubreg_t err;
err = LOCAL_HUB_L(PI_ERR_INT_PEND);
while (err) {
errors++;
err &= (err - 1);
}
err = LOCAL_HUB_L(NI_PORT_ERROR);
err &= 0x3fff000000;
while (err) {
errors++;
err &= (err - 1);
}
if (LOCAL_HUB_L(MD_PROTOCOL_ERROR) & PROTO_ERROR_VALID_MASK)
errors++;
if (LOCAL_HUB_L(MD_MISC_ERROR) & MISC_ERROR_VALID_MASK)
errors++;
if (LOCAL_HUB_L(MD_MEM_ERROR) & MEM_ERROR_VALID_UCE)
errors++;
if (LOCAL_HUB_L(MD_DIR_ERROR) & (DIR_ERROR_VALID_UCE |
DIR_ERROR_VALID_AE))
errors++;
for (crb = 0; crb < IIO_NUM_CRBS; crb++) {
icrba_t crba;
crba.reg_value = LOCAL_HUB_L(IIO_ICRB_A(crb));
if (crba.icrba_fields_s.error)
errors++;
}
if (errors > 15)
return 0;
return 1;
}
/*
* Function : error_save_reset
* Parameters : none
* Purpose : to save the reset values of hardware error registers for
* later perusal.
* Assumptions : none
* Returns : none
* NOTE : This routine saves the error registers in a special area
* in the cache, since memory has not yet been initialized.
* This will be copied out to memory soon after it gets
* initialized.
*/
void
error_save_reset(void)
{
__psunsigned_t pod_error = POD_ERRORVADDR;
*(__uint64_t *)pod_error = error_check_reset();
pod_error += 8;
/*
* Link reset, spurious message and crazy bit are turned on at system
* reset?
*/
{
hubreg_t nierr_mask;
LOCAL_HUB_S(PI_ERR_INT_PEND, (PI_ERR_SPUR_MSG_A | PI_ERR_SPUR_MSG_B));
nierr_mask =
(NPE_LINKRESET | NPE_INTERNALERROR | NPE_BADMESSAGE | NPE_BADDEST
| NPE_FIFOOVERFLOW | NPE_CREDITTO_MASK | NPE_TAILTO_MASK);
if ((LOCAL_HUB_L(NI_PORT_ERROR) & nierr_mask) == NPE_LINKRESET)
LOCAL_HUB_L(NI_PORT_ERROR_CLEAR);
LOCAL_HUB_S(IIO_IECLR, IECLR_CRAZY);
}
save_hub_pi_error((__psunsigned_t)LOCAL_HUB(0), (hub_pierr_t *)pod_error);
pod_error += sizeof(hub_pierr_t);
save_hub_md_error((__psunsigned_t)LOCAL_HUB(0), (hub_mderr_t *)pod_error);
pod_error += sizeof(hub_mderr_t);
save_hub_io_error((__psunsigned_t)LOCAL_HUB(0), (hub_ioerr_t *)pod_error);
pod_error += sizeof(hub_ioerr_t);
save_hub_ni_error((__psunsigned_t)LOCAL_HUB(0), (hub_nierr_t *)pod_error);
pod_error += sizeof(hub_nierr_t);
save_hub_err_ext((__psunsigned_t)LOCAL_HUB(0), (klhub_err_ext_t *) pod_error);
pod_error += sizeof(klhub_err_ext_t);
}
/*
* Function : error_clear_hub_regs
* Parameters : none
* Purpose : clear the error registers in the hub
* Assumptions : none
* Returns : none
*/
void
error_clear_hub_regs(void)
{
SD(LOCAL_HUB(PI_ERR_INT_PEND), -1);
LD(LOCAL_HUB(PI_ERR_STATUS1_A_RCLR));
LD(LOCAL_HUB(PI_ERR_STATUS1_B_RCLR));
LD(LOCAL_HUB(MD_DIR_ERROR_CLR));
LD(LOCAL_HUB(MD_MEM_ERROR_CLR));
LD(LOCAL_HUB(MD_MISC_ERROR_CLR));
LD(LOCAL_HUB(MD_PROTOCOL_ERROR_CLR));
SD(LOCAL_HUB(IIO_IO_ERR_CLR), -1);
LD(LOCAL_HUB(NI_PORT_ERROR_CLEAR));
}
/*
* Function : error_move_reset
* Parameters : none
* Purpose : move the reset error registers from cache to initialized
* memory.
* Assumptions : none
* Returns : none.
*/
void
error_move_reset(void)
{
char *err_dump = (char *) TO_NODE(get_nasid(), IP27PROM_ERRDMP);
memcpy(err_dump, (char *) POD_ERRORVADDR, POD_ERRORSIZE);
}
/*
* Function : error_log_reset
* Parameters : board pointer (klconfig)
* Purpose : to save the reset error state from early memory into klconfig
* Assumptions : none
* Returns : none
*/
void
error_log_reset(lboard_t *brd)
{
klinfo_t *klhubp;
klhub_err_t *klhub_err;
hub_error_t *hub_err;
hub_pierr_t *pi_err;
hub_mderr_t *md_err;
hub_ioerr_t *io_err;
hub_nierr_t *ni_err;
klhub_err_ext_t *klhub_err_ext;
__psunsigned_t err_dump;
__psunsigned_t poweron;
int rc = 0;
err_dump = TO_NODE(get_nasid(), IP27PROM_ERRDMP);
poweron = err_dump;
if (*(__uint64_t *)poweron == 0) {
rc = 1;
}
err_dump += 8;
if (klhubp = find_component(brd, NULL, KLSTRUCT_HUB)) {
klhub_err = HUB_COMP_ERROR(brd, klhubp);
hub_err = HUB_ERROR_STRUCT(klhub_err, KL_ERROR_LOG);
}
else {
printf("error_log_reset: cant find hub component\n");
return;
}
hub_err->reset_flag = rc;
pi_err = &hub_err->hb_pi;
memcpy((char *) pi_err, (char *) err_dump, sizeof(hub_pierr_t));
err_dump += sizeof(hub_pierr_t);
md_err = &hub_err->hb_md;
memcpy((char *) md_err, (char *) err_dump, sizeof(hub_mderr_t));
err_dump += sizeof(hub_mderr_t);
io_err = &hub_err->hb_io;
memcpy((char *) io_err, (char *) err_dump, sizeof(hub_ioerr_t));
err_dump += sizeof(hub_ioerr_t);
ni_err = &hub_err->hb_ni;
memcpy((char *) ni_err, (char *) err_dump, sizeof(hub_nierr_t));
err_dump += sizeof(hub_nierr_t);
klhub_err_ext = (klhub_err_ext_t *) NODE_OFFSET_TO_K1(NASID_GET(brd),
klhub_err->he_extension);
memcpy((char *) klhub_err_ext, (char *) err_dump, sizeof(klhub_err_ext_t));
err_dump += sizeof(klhub_err_ext_t);
return;
}
void
error_show_reset(void)
{
kl_error_show_log("Hardware Error State at System Reset\n",
"End Hardware Error State (at System Reset)\n");
}
/*
* Function : hubpi_stack_params
* Parameters : nasid -> nasid
* : off_p -> pointer to memory offset, start of stack.
* : size_p-> pointer to size of stack (as specified by the
* the hub pi)
* Purpose : none
* Assumptions : none
* Returns : none
*/
static void
hubpi_stack_params(nasid_t nasid, unsigned int *off_p, unsigned int *size_p)
{
unsigned int offset;
size_t size, size_per_cpu;
unsigned int size_bytes;
offset = PI_ERROR_OFFSET(nasid);
size_per_cpu = PI_ERROR_SIZE(nasid) >> 1;
size_per_cpu >>= PI_STACK_SIZE_SHFT;
size = 0;
while (size_per_cpu) {
size++;
size_per_cpu >>= 1;
}
/*
* get the size in bytes. If the offset is not on the size boundary,
* switch to the next lower acceptable size AND set the offset to
* the next higher boundary based on size. This ensures that we
* always have the sufficient space available.
*/
size_bytes = ERR_STACK_SIZE_BYTES(size);
if (offset & (size_bytes - 1)) {
if (size) size--;
size_bytes >>= 1;
offset = ((offset + (size_bytes - 1)) & ~(size_bytes - 1));
}
*size_p = size;
*off_p = offset;
}
/*
* Function : error_setup_pi_stack
* Parameters : nasid -> node id on which to program the pi stack values.
* Purpose : to setup the hubpi spooling so that we capture error info.
* This is a requirement for HUB1 as well.
* Assumptions : none
* Returns : none
*/
void
error_setup_pi_stack(nasid_t nasid)
{
unsigned int offset;
unsigned int size;
hubpi_stack_params(nasid, &offset, &size);
if (*LOCAL_HUB(PI_CPU_PRESENT_A))
*LOCAL_HUB(PI_ERR_STACK_ADDR_A) = (hubreg_t)offset;
offset += ERR_STACK_SIZE_BYTES(size);
if (*LOCAL_HUB(PI_CPU_PRESENT_B))
*LOCAL_HUB(PI_ERR_STACK_ADDR_B) = (hubreg_t)offset;
*LOCAL_HUB(PI_ERR_STACK_SIZE) = (hubreg_t)size;
}
void
error_clear_io6(void)
{
#if 0
printf("fixme: error_clear_io6\n");
#endif
}
void
error_disable_checking(int sysad_chk, int dis_eintr, int master)
{
hubreg_t sysad_reg;
if (master) {
sysad_reg = LD(LOCAL_HUB(PI_SYSAD_ERRCHK_EN));
sysad_reg &= ~sysad_chk;
SD(LOCAL_HUB(PI_SYSAD_ERRCHK_EN), sysad_reg);
}
#if 0
if (dis_eintr)
disable_cpu_intrs();
#endif
}
void
error_enable_checking(int sysad_chk, int en_eintr, int master)
{
int en_sys_state;
hubreg_t rev;
if (master) {
/*
* Enable sys_state only if both cpus are present.
*/
en_sys_state = sysad_chk & PI_SYSAD_ERRCHK_STATE;
sysad_chk &= ~PI_SYSAD_ERRCHK_STATE;
SD(LOCAL_HUB(PI_SYSAD_ERRCHK_EN), sysad_chk);
/*
* The sysstate parity checking cannot be enabled if either
* cpu is not present.
*/
if (en_sys_state && LD(LOCAL_HUB(PI_CPU_PRESENT_A))
&& LD(LOCAL_HUB(PI_CPU_PRESENT_B)))
SD(LOCAL_HUB(PI_SYSAD_ERRCHK_EN),
LD(LOCAL_HUB(PI_SYSAD_ERRCHK_EN)) | PI_SYSAD_ERRCHK_STATE);
/*
* Now setup the NACK_CNT registers so that we dont get into an
* infinite nack situation.
*/
SD(LOCAL_HUB(PI_NACK_CMP), PI_NACK_CNT_MAX);
#ifdef HUB2_NACK_WAR
rev = LD(LOCAL_HUB(NI_STATUS_REV_ID));
if (((rev & NSRI_REV_MASK) >> NSRI_REV_SHFT) == 2) {
printf("HUB2: PI_NACK_CNT set to 0\n");
SD(LOCAL_HUB(PI_NACK_CNT_A), 0);
SD(LOCAL_HUB(PI_NACK_CNT_B), 0);
}
else
#endif
{
if (LD(LOCAL_HUB(PI_CPU_PRESENT_A)))
SD(LOCAL_HUB(PI_NACK_CNT_A), (1L << PI_NACK_CNT_EN_SHFT));
if (LD(LOCAL_HUB(PI_CPU_PRESENT_B)))
SD(LOCAL_HUB(PI_NACK_CNT_B), (1L << PI_NACK_CNT_EN_SHFT));
}
if (en_eintr) {
/*
* Setup error intr masks.
*/
if (LD(LOCAL_HUB(PI_CPU_PRESENT_B)) == 0) /* only A present */
SD(LOCAL_HUB(PI_ERR_INT_MASK_A),
PI_FATAL_ERR_CPU_A | PI_MISC_ERR_CPU_A | PI_ERR_GENERIC);
else if (LD(LOCAL_HUB(PI_CPU_PRESENT_A)) == 0)
/* only B present */
SD(LOCAL_HUB(PI_ERR_INT_MASK_B),
PI_FATAL_ERR_CPU_B | PI_MISC_ERR_CPU_B | PI_ERR_GENERIC);
else { /* Both A and B present */
SD(LOCAL_HUB(PI_ERR_INT_MASK_A),
PI_FATAL_ERR_CPU_B | PI_MISC_ERR_CPU_A | PI_ERR_GENERIC);
SD(LOCAL_HUB(PI_ERR_INT_MASK_B),
PI_FATAL_ERR_CPU_A | PI_MISC_ERR_CPU_B);
}
}
}
#if 0
if (en_eintr) {
enable_cpu_intrs();
}
#endif
}
void
error_clear_hub_erreg(nasid_t nasid)
{
SD(REMOTE_HUB(nasid, PI_ERR_INT_PEND), -1);
LD(REMOTE_HUB(nasid, PI_ERR_STATUS1_A_RCLR));
LD(REMOTE_HUB(nasid, PI_ERR_STATUS1_B_RCLR));
LD(REMOTE_HUB(nasid, MD_DIR_ERROR_CLR));
LD(REMOTE_HUB(nasid, MD_MEM_ERROR_CLR));
LD(REMOTE_HUB(nasid, MD_PROTOCOL_ERROR_CLR));
LD(REMOTE_HUB(nasid, MD_MISC_ERROR_CLR));
/*
* XXX FIXME: Take care of local hub ii and bridge etc.
*/
LD(REMOTE_HUB(nasid, NI_PORT_ERROR_CLEAR));
}
void
error_clear_exception()
{
pcfg_hub_t *hub_cf;
int i;
printf("Clearing hub registers\n");
error_clear_hub_erreg(get_nasid());
printf("done Clearing hub registers\n");
for (i = 0; i < PCFG(get_nasid())->count; i++) {
hub_cf = &PCFG_PTR(get_nasid(), i)->hub;
if (hub_cf->type != PCFG_TYPE_HUB) continue;
printf("Clearing node %lx hub registers\n", hub_cf->nasid);
if ((hub_cf->nasid != get_nasid()) &&
(hub_cf->nasid != INVALID_NASID))
error_clear_hub_erreg(hub_cf->nasid);
}
set_cop0(C0_SR, (get_cop0(C0_SR) & ~SR_EXL));
}