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

449 lines
13 KiB
C

/***********************************************************************\
* File: pod_master.c *
* *
\***********************************************************************/
#include <sys/types.h>
#include <sys/cpu.h>
#include <sys/EVEREST/evconfig.h>
#include <sys/EVEREST/evmp.h>
#include <sys/EVEREST/sysctlr.h>
#include <sys/EVEREST/nvram.h>
#include <sys/EVEREST/IP21addrs.h>
#include "ip21prom.h"
#include "prom_leds.h"
#include "pod_failure.h"
#include "prom_intr.h"
#include "prom_externs.h"
#include "pod.h"
#define SLAVE_TOUT 0x1000000 /* Somewhere around 1 minutes */
#define DISABLE_TOUT 0x100000
#define MYDIAGVAL (EVCFGINFO->ecfg_board[slot].eb_cpuarr[slice].cpu_diagval)
#define INV_READ(_b, _f) \
get_nvreg(NVOFF_INVENTORY + ((_b) * INV_SIZE) + (_f))
#define INV_READU(_b, _u, _f) \
get_nvreg(NVOFF_INVENTORY + ((_b) * INV_SIZE) + \
INV_UNITOFF + ((_u) * INV_UNITSIZE) + (_f))
#define ABS_VAL(_x) (((_x) < 0) ? -(_x) : (_x))
int load_io4prom(void);
void xlate_ertoip(__uint64_t);
void set_ertoip_at_reset(void);
extern unsigned long MemSizes[];
void update_boot_stat(int io4_err, int slot, int slice) {
uint nv_valid;
evbrdinfo_t *brd;
uint i, c;
char cpuinfo[EV_MAX_CPUS+1];
char *currcpu = cpuinfo;
nv_valid = (nvram_okay() && !io4_err);
/* Switch off nv_valid if it the valid inventory flag isn't set */
if (nv_valid)
if (get_nvreg(NVOFF_INVENT_VALID) != INVENT_VALID)
nv_valid = 0;
/* Clear out the cpuinfo character array */
for (i = 0; i < EV_MAX_CPUS; i++)
cpuinfo[i] = ' ';
cpuinfo[i] = '\0'; /* Null terminate */
for (i = 1; i < EV_MAX_SLOTS; i++) {
brd = &(EVCFGINFO->ecfg_board[i]);
/* Skip non-IP21 boards */
if ((brd->eb_type & EVCLASS_MASK) != EVCLASS_CPU)
continue;
for (c = 0; c < EV_CPU_PER_BOARD; c++) {
/* Special case the behaviour for the boot master */
if ((i == slot) && (c == slice)) {
*currcpu++ = SCSTAT_BOOTMASTER;
continue;
}
/* Check to see whether processor is alive */
if ( brd->eb_cpuarr[c].cpu_vpid != CPUST_NORESP ) {
/* See if processor is enabled */
if (nv_valid && !INV_READU(i, c, INVU_ENABLE)) {
*currcpu++ = SCSTAT_DISABLED;
} else if ( brd->eb_cpuarr[c].cpu_diagval ) {
*currcpu++ = SCSTAT_BROKEN;
} else {
*currcpu++ = SCSTAT_WORKING;
}
} else {
/* Processor didn't respond - either it isn't there
or it is seriously hosed */
if (nv_valid && !INV_READU(i, c, INVU_ENABLE))
*currcpu++ = SCSTAT_DISABLED;
else
*currcpu++ = SCSTAT_UNKNOWN;
}
}
}
/* Fire the CPU status string off to the system controller */
sysctlr_bootstat(cpuinfo, 0);
}
void check_slaves(int slot, int slice) {
int i, j, vpid;
int done;
int slave_errs = 0;
unsigned int time, timeout, last_print, tout;
unsigned int cur_time;
int max_promrev = 0; /* Highest PROM rev on the system */
evbrdinfo_t *brdinfo;
volatile unsigned char *stat;
time = load_double_bloc((long long *)EV_RTC);
timeout = time + SLAVE_TOUT;
last_print = 0;
tout = 0;
for (i = 0; i < EV_MAX_SLOTS; i ++) {
brdinfo = &(EVCFGINFO->ecfg_board[i]);
if ((brdinfo->eb_type & EVCLASS_MASK) == EVCLASS_CPU) {
/* Print the slot we're looking at */
DPRINTF(" %a", i);
for (j = 0; j < EV_CPU_PER_BOARD; j++) {
if ((brdinfo->eb_cpuarr[j].cpu_vpid == CPUST_NORESP) ||
(brdinfo->eb_cpuarr[j].cpu_vpid == 0))
done = 1;
else
done = 0;
stat = &(brdinfo->eb_cpuarr[j].cpu_diagval);
/* Keep track of the highest prom revisions on the
* machine.
* Can't tell the difference between 0 and CANTSEEMEM...
* Bummer.
*/
if ((brdinfo->eb_cpuarr[j].cpu_promrev > max_promrev) &&
brdinfo->eb_cpuarr[j].cpu_promrev)
max_promrev = brdinfo->eb_cpuarr[j].cpu_promrev;
do {
if (*stat == EVDIAG_NOT_SET) {
*stat = EVDIAG_CANTSEEMEM;
}
switch (*stat) {
case EVDIAG_TESTING_DCACHE:
case EVDIAG_TESTING_ICACHE:
case EVDIAG_TESTING_SCACHE:
case EVDIAG_INITING_CACHES:
case EVDIAG_WRCPUINFO:
case EVDIAG_TESTING_CCJOIN:
case EVDIAG_TESTING_CCWG:
break;
default:
done = 1;
} /* switch */
cur_time = load_double_bloc((long long *)EV_RTC);
if (cur_time - last_print > 0x40000) {
last_print = cur_time;
loprintf(".");
}
} while (!done && !(tout += timed_out(time, timeout)));
} /* for j */
} /* if CPU class */
} /* for i */
loprintf("\n");
if (tout)
loprintf("*** Timed out waiting for slaves\n");
for (i = 0; i < EV_MAX_SLOTS; i ++) {
brdinfo = &(EVCFGINFO->ecfg_board[i]);
if ((brdinfo->eb_type & EVCLASS_MASK) == EVCLASS_CPU) {
for (j = 0; j < EV_CPU_PER_BOARD; j++) {
vpid = brdinfo->eb_cpuarr[j].cpu_vpid;
stat = &(brdinfo->eb_cpuarr[j].cpu_diagval);
switch (*stat) {
case EVDIAG_TESTING_DCACHE:
*stat = EVDIAG_DCACHE_HANG;
break;
case EVDIAG_TESTING_SCACHE:
*stat = EVDIAG_SCACHE_HANG;
break;
case EVDIAG_TESTING_ICACHE:
*stat = EVDIAG_ICACHE_HANG;
break;
case EVDIAG_INITING_CACHES:
*stat = EVDIAG_CACHE_INIT_HANG;
break;
case EVDIAG_WRCPUINFO:
*stat = EVDIAG_WRCFG_HANG;
break;
}
}
} /* if EVCLASS_CPU */
} /* for i */
for (i = 0; i < EV_MAX_SLOTS; i ++) {
brdinfo = &(EVCFGINFO->ecfg_board[i]);
if ((brdinfo->eb_type & EVCLASS_MASK) == EVCLASS_CPU) {
for (j = 0; j < EV_CPU_PER_BOARD; j++) {
stat = &(brdinfo->eb_cpuarr[j].cpu_diagval);
if (brdinfo->eb_cpuarr[j].cpu_vpid != CPUST_NORESP) {
/* Can't tell the difference between a rev. 0 prom and
* a CPU that can't see memory.
* Bummer.
*/
if((brdinfo->eb_cpuarr[j].cpu_promrev < max_promrev)
&& brdinfo->eb_cpuarr[j].cpu_promrev)
loprintf("*** CPU %a/%a has a downrev PROM!\n", i, j);
if ((i != slot) || (j != slice)) {
/* Not the CPU we're running on */
if(*stat != EVDIAG_PASSED) {
if(*stat != EVDIAG_WG) {
loprintf("*** Disabling slave CPU %d/%d, First diag Error(%d): %s\n", i, j, *stat, get_diag_string(*stat));
brdinfo->eb_cpuarr[j].cpu_enable = 0;
slave_errs++;
} else {
loprintf("*** Slave CPU %d/%d failed write gatherer diag but will not be disabled.\n", i, j);
*stat = EVDIAG_PASSED;
}
}
} else {
/* Master CPU */
if(*stat != EVDIAG_PASSED)
loprintf("*** Master CPU %a/%a Error: %s\n", i, j, get_diag_string(*stat));
}
}
}
} /* if EVCLASS_CPU */
} /* for i */
}
void query_evcfg(uint *enabled_mem, uint *disabled_mem, int *enabled_cpus,
int *disabled_cpus) {
evbrdinfo_t *brdinfo;
int i;
int j;
*enabled_mem = *disabled_mem = *enabled_cpus = *disabled_cpus = 0;
for (i = 0; i < EV_MAX_SLOTS; i++) {
brdinfo = &(EVCFGINFO->ecfg_board[i]);
if ((brdinfo->eb_type & EVCLASS_MASK) == EVCLASS_CPU) {
for (j = 0; j < EV_CPU_PER_BOARD; j++) {
DPRINTF("CPU %d/%d: diagval %x, enable %x\n", i, j,
brdinfo->eb_cpuarr[j].cpu_diagval,
brdinfo->eb_cpuarr[j].cpu_enable);
if (brdinfo->eb_cpuarr[j].cpu_diagval != CPUST_NORESP) {
if (brdinfo->eb_cpuarr[j].cpu_enable)
(*enabled_cpus)++;
else
(*disabled_cpus)++;
}
} /* for j */
} else if ((brdinfo->eb_type & EVCLASS_MASK) == EVCLASS_MEM) {
#ifdef SABLE
*(enabled_mem) = 8 << 12; /* 8 mb */
#else
for (j = 0; j < MC3_NUM_BANKS; j++) {
if (brdinfo->eb_banks[j].bnk_size != MC3_NOBANK)
if (brdinfo->eb_banks[j].bnk_enable)
(*enabled_mem) += MemSizes[brdinfo->eb_banks[j].bnk_size];
else
(*disabled_mem) += MemSizes[brdinfo->eb_banks[j].bnk_size];
} /* for j */
#endif
}
} /* for i */
}
int cpu_masks[] = {
0x3, /* cpu 0: channels 0 and 1 */
0xc /* cpu 1: channels 2 and 3 */
};
void hard_disable_cpus(int slot, int slice)
{
evbrdinfo_t *brdinfo;
int i, j;
int mask;
unsigned timeout, time;
for (i = 0; i < EV_MAX_SLOTS; i++) {
brdinfo = &(EVCFGINFO->ecfg_board[i]);
if ((brdinfo->eb_type & EVCLASS_MASK) == EVCLASS_CPU) {
mask = 0;
for (j = 0; j < EV_CPU_PER_BOARD; j++) {
if ((i == slot) && (j == slice)) {
mask |= cpu_masks[j];
continue;
}
if (brdinfo->eb_cpuarr[j].cpu_diagval != CPUST_NORESP) {
if (brdinfo->eb_cpuarr[j].cpu_enable) {
mask |= cpu_masks[j];
continue;
}
}
/* If we get here, we're disabled */
/* Go flash our LEDs -
* Since the PROM's in "uncached" space, use the K1
* macro.
*/
brdinfo->eb_cpuarr[j].cpu_launch =
KPHYSTO32K1(IP21PROM_FLASHLEDS);
/* Actually launch the slave */
send_int(i, j, LAUNCH_LEVEL);
} /* for j */
/* Give CPUs a chance to jump. */
if (mask != EV_GET_CONFIG(i, EV_A_ENABLE)) {
time = load_double_bloc((long long *)EV_RTC);
timeout = time + DISABLE_TOUT;
while (!timed_out(time, timeout));
/* Actually disable CPUs */
EV_SET_CONFIG(i, EV_A_ENABLE, mask);
}
}
} /* for i */
}
char plural(int number)
{
if (number != 1)
return 's';
else
return ' ';
}
void test_master(int io4_err)
{
int failure_code = 0;
int slot, slice; /* Our position on the midplane */
uint enabled_mem, disabled_mem;
int enabled_cpus, disabled_cpus;
slot = (load_double_lo((long long *)EV_SPNUM)
& EV_SLOTNUM_MASK) >> EV_SLOTNUM_SHFT;
slice = (load_double_lo((long long *)EV_SPNUM)
& EV_PROCNUM_MASK) >> EV_PROCNUM_SHFT;
if (get_BSR() & BS_MANUMODE) {
int i, first;
for (i = 0, first = 1; i < EV_MAX_CPUS; i++) {
if (MPCONF[i].bevecc) {
/*
* Don't print anything if we only got DB chip parity
* errors. These happen all the time.
*/
if (MPCONF[i].bevecc <= 3)
continue;
if (first) {
loprintf("*** Contents of ERTOIP Registers Before Reset:\n");
first = 0;
}
loprintf("*** CPU %d:\n", i);
xlate_ertoip((__uint64_t)MPCONF[i].bevecc);
}
}
loprintf("\n");
}
/* Check on the slaves. */
if (!(EVCFGINFO->ecfg_debugsw & VDS_NO_DIAGS))
loprintf("Checking slave processor diag results..");
else
loprintf("Checking slave processor status..");
sysctlr_message("Checking slaves...");
check_slaves(slot, slice);
update_boot_stat(io4_err, slot, slice);
set_ertoip_at_reset();
if (!(EVCFGINFO->ecfg_debugsw & VDS_NO_DIAGS)) {
sysctlr_message("Checking FPU...");
fputest();
};
query_evcfg(&enabled_mem, &disabled_mem, &enabled_cpus, &disabled_cpus);
loprintf(" Enabled %d Megabytes of main memory\n",
enabled_mem >> 12);
if (disabled_mem)
loprintf(" (Disabled %d Megabytes of main memory)\n",
disabled_mem >> 12);
loprintf(" Enabled %d processor%c\n", enabled_cpus,
plural(enabled_cpus));
if (disabled_cpus)
loprintf(" (Disabled %d processor%c)\n", disabled_cpus,
plural(disabled_cpus));
#if SABLE
io4_err = 0; /* error? what error? */
EVCFGINFO->ecfg_debugsw |= VDS_PODMODE; /* drop into pod mode */
EVCFGINFO->ecfg_memsize = enabled_mem; /* kludge memory size */
#endif
if (enabled_mem != (EVCFGINFO->ecfg_memsize)) {
loprintf("*** Memory size in evconfig structure was corrupted. Updating.\n");
EVCFGINFO->ecfg_memsize = enabled_mem;
}
if (io4_err) {
sc_disp(io4_err);
pod_handler("\r\nIO4 board failed.\r\n", io4_err);
}
/* Clean stuff up. */
pod_clear_ints();
store_double_lo((long long *)EV_CIPL124, 0x6);
store_double_lo((long long *)EV_CERTOIP, 0xffff);
store_double_lo((long long *)EV_ERTOIP, 0);
if (EVCFGINFO->ecfg_debugsw & VDS_PODMODE) {
sysctlr_message("Entering POD mode.");
pod_handler("\r\nEntering POD mode.\r\n", EVDIAG_DEBUG);
}
/* If NO_DIAGS isn't set and PODMODE isn't set, hard disable CPUs */
if (!(EVCFGINFO->ecfg_debugsw & VDS_NO_DIAGS)) {
hard_disable_cpus(slot, slice);
} else if (disabled_cpus) {
loprintf("NOTE: Soft-disabling CPUs.\n");
}
if ((EVCFGINFO->ecfg_memsize >> 12) < 32) {
loprintf("*** Can't load IO prom with < 32 Megabytes of working memory.\n");
sc_disp(EVDIAG_MC3NOTENOUGH);
pod_handler("Insufficient memory.\r\n", EVDIAG_MC3NOTENOUGH);
}
/*
* Download the IO4 PROM
*/
if (!io4_err) {
failure_code = load_io4prom();
sc_disp(failure_code);
pod_handler("IO4 prom failed.\r\n", failure_code);
} else {
sc_disp(io4_err);
pod_handler("Cannot run without working IO4\r\n", io4_err);
}
}