1
0
Files
2022-09-29 17:59:04 +03:00

1319 lines
31 KiB
C

#ident "IP30prom/IP30.c: $Revision: 1.111 $"
/*
* IP30.c -- machine dependent prom routines
*/
#include <sys/types.h>
#include <setjmp.h>
#include <sys/cpu.h>
#include <sys/RACER/racermp.h>
#include <sys/RACER/IP30nvram.h>
#include <sys/RACER/IP30addrs.h>
#include <sys/sbd.h>
#include <sys/RACER/gda.h>
#include <sys/nic.h>
#include <pon.h>
#include <arcs/errno.h>
#include <arcs/io.h>
#include <arcs/hinv.h>
#include <gfxgui.h>
#include <style.h>
#include <alocks.h>
#include <libsc.h>
#include <libsk.h>
#include <sys/RACER/sflash.h>
#include <sys/mgrashw.h> /* for system command */
#include <sys/xtalk/hq4.h>
lock_t arcs_ui_lock; /* in bss! */
extern jmp_buf restart_buf;
extern int Verbose, Debug;
extern __uint64_t memsize;
extern void cache_K0(void);
extern void config_cache(void);
extern void hmclear(__psunsigned_t, __psunsigned_t);
extern void init_dcache(void);
extern void init_icache(void);
extern void init_scache(void);
extern void init_tlb(void);
extern void main(void);
extern void setstackseg(__psunsigned_t);
extern void startup(void);
extern void ip30_init_cpu_disable(void);
#ifndef IP30_RPROM
extern int pon_scache(void);
extern int pon_caches(void);
extern int pon_morediags(void);
extern int pon_audio_wait(void);
#else
#define pon_scache() 0
#define pon_caches() 0
#define pon_morediags() 0
#define play_hello_tune(x)
#define wait_hello_tune()
#define pon_audio_wait() 0
#endif
static int cachepromtext(void);
void init_caches(void);
void init_prom_soft(int);
static void alloc_memdesc(void);
#ifdef ENETBOOT
static void clear_memory(int);
#endif
static void domfgstartup(char *);
static void init_gda(void);
static int slave_processor_spin(int);
static int wakeup_slave_processors(uint_t, int);
static volatile unsigned short cpumask;
extern int master_cpuid;
int cache0_diag_failed[MAXCPU];
int cache1_diag_failed[MAXCPU];
static int cache_diags_done[MAXCPU];
static int cache_diags_started[MAXCPU];
#define CACHE_DIAG_IN_PROGRESS -1
#define CACHE_DIAG_DONE 1
#define CACHE_DIAG_DONE 1
#ifdef VERBOSE
#define VPRINTF(arg) printf arg
#define VPUTS(str) pon_puts(str)
#define VCPUPUTS(cpu,str) \
pon_puts("CPU "); \
pon_putc(cpu + '0'); \
pon_puts(str)
#
#else
#define VPRINTF(arg)
#define VPUTS(str)
#define VCPUPUTS(cpu,str)
#endif
#define CPUBOARD "IP30"
#ifdef ENETBOOT
#define ENET_SR_BEV 0
#else
#define ENET_SR_BEV SR_BEV
#endif
#define PROCESSOR_IS_INSTALLED(x) (heart_piu->h_status & \
HEART_STAT_PROC_ACTIVE(x))
#define PROCESSOR_IS_DISABLED(x) (heart_piu->h_mode & \
HM_PROC_DISABLE(x))
#define PROCESSOR_IS_ACTIVE(x) (PROCESSOR_IS_INSTALLED(x) && \
!PROCESSOR_IS_DISABLED(x))
#define PROCESSOR_IS_BAD(x) (k1_cache0_diag_failed[x] || \
k1_cache1_diag_failed[x])
libsc_private_t *_libsc_private;
libsc_private_t ip30_tmp_libsc_private;
/*
* sysinit - finish system initialization and run diags
*/
void
sysinit(void)
{
int diagsfailed;
u_char fan_setting;
register heart_piu_t *heart_piu = HEART_PIU_K1PTR;
int i;
int id = cpuid();
volatile int *k1_cache_diags_done =
(int *)K0_TO_K1(cache_diags_done);
volatile int *k1_cache0_diag_failed =
(int *)K0_TO_K1(cache0_diag_failed);
volatile int *k1_cache1_diag_failed =
(int *)K0_TO_K1(cache1_diag_failed);
volatile int *k1_cache_diags_started =
(int *)K0_TO_K1(cache_diags_started);
int *k1_master_cpuid =
(int *)K0_TO_K1(&master_cpuid);
volatile mpconf_t *mpconf_ptr;
char *ptr;
int running_cached = 0;
#ifdef IP30_RPROM
volatile __psunsigned_t *rprom_slave =
(volatile __psunsigned_t *)PHYS_TO_K1(IP30_RPROM_SLAVE);
#endif
#ifdef ENETBOOT
extern int start();
run_uncached(); /* needed for the cache diags */
#endif
/*
* initially, processor with the smallest id is the master processor
*/
if (!(heart_piu->h_status & HEART_STAT_PROC_ACTIVE_MSK &
(HEART_STAT_PROC_ACTIVE(id) - 1))) {
*k1_master_cpuid = id;
VCPUPUTS(id," is the bootmaster.\r\n");
#ifdef IP30_RPROM
*rprom_slave = 0;
if (flash_fprom_reloc_chk()) {
extern void reloc_to_fprom(void);
#ifndef ENETBOOT
/* relaunch all slaves to fprom */
*rprom_slave = (__psunsigned_t)reloc_to_fprom;
heart_piu->h_mode &= ~HM_PROC_DISABLE_MSK;
wakeup_slave_processors(0xf, 0);
VPUTS("RPROM relocating to FPROM\r\n");
reloc_to_fprom();
#else
VPUTS("DRPROM, Not relocating to FPROM\r\n");
#endif
} else
pon_puts("FPROM Invalid, Starting Recovery\r\n");
#endif /* IP30_RPROM */
init_caches();
k1_cache1_diag_failed[id] = pon_scache();
k1_cache0_diag_failed[id] = pon_caches();
for (i = 0; i < MAXCPU; i++) {
heartreg_t timeout;
if (i == id || !PROCESSOR_IS_INSTALLED(i))
continue;
heart_piu->h_mode &= ~HM_PROC_DISABLE(i);
flushbus();
wakeup_slave_processors(0x1 << i, 0);
/* 1 second to timeout, 12.5MHz clock */
timeout = heart_piu->h_count + 12500000;
while (!k1_cache_diags_started[i] &&
heart_piu->h_count < timeout)
;
if (!k1_cache_diags_started[i]) {
heart_piu->h_mode |= HM_PROC_DISABLE(i);
VCPUPUTS(i," timed out waiting to start the "
"cache diagnostic.\r\n");
continue;
}
/*
* wait for cache diagnostics to finish, no
* timeout here since the slave processor may
* output lot of error message
*/
while (!k1_cache_diags_done[i])
;
#if MAXCPU > 2
/*
* disable slave processor to save some bus
* bandwidth
*/
heart_piu->h_mode |= HM_PROC_DISABLE(i);
#endif
/*
* switch master processor if the current master
* processor failed the cache diagnostics
*/
if (PROCESSOR_IS_BAD(*k1_master_cpuid) &&
!PROCESSOR_IS_BAD(i)) {
VCPUPUTS(i," is now the bootmaster due to a "
"cache diagnostic failure.\r\n");
*k1_master_cpuid = i;
}
}
#if MAXCPU > 2
heart_piu->h_mode &= ~HM_PROC_DISABLE_MSK;
#endif
wakeup_slave_processors(0xf, 0);
}
else {
/* clear own inter-processor interrupt */
heart_piu->h_clr_isr = HEART_ISR_IPI;
init_caches();
k1_cache_diags_started[id] = 1;
k1_cache1_diag_failed[id] = pon_scache();
k1_cache0_diag_failed[id] = pon_caches();
k1_cache_diags_done[id] = 1;
(void)slave_processor_spin(0);
}
/* possible new bootmaster */
if (id != *k1_master_cpuid) {
(void)slave_processor_spin(0);
}
else {
/* XXX may want to do more sensible thing */
if (PROCESSOR_IS_BAD(id)) {
void pon_flash_led(void);
pon_puts("PANIC: None of the processor(s) passed "
"the cache diagnostics.\r\n");
pon_flash_led();
/*NOTREACHED*/
}
/* disable slave processors to stop bus contention */
heart_piu->h_mode |=
HM_PROC_DISABLE_MSK ^ HM_PROC_DISABLE(id);
VPUTS("Caching the rest of the PROM [");
VPUTS(IS_KSEG1(sysinit) || IS_COMPATK1(sysinit) ?
"uncached" : "cached");
VPUTS(" prom].\r\n");
heart_piu->h_mode |= HM_CACHED_PROM_EN;
if (cachepromtext()) {
cache_K0();
#ifdef ENETBOOT
run_cached();
#endif
}
setstackseg(K0BASE);
running_cached = 1;
/* since we want to use printf early */
_libsc_private = &ip30_tmp_libsc_private;
initsplocks();
initlock(&arcs_ui_lock);
/* set cache related global variables */
config_cache();
/* Enable power switch before memory clear, which is slow.
* Need to make sure h_imrs are cleared before initial call
* as it does enable heart interrupts.
*/
VPRINTF(("Enabling power switch.\r\n"));
#ifndef ENETBOOT
/* Initialize heart/bridge base interrupt stuff just enough */
heart_piu->h_imr[0] = 0;
heart_piu->h_imr[1] = 0;
heart_piu->h_imr[2] = 0;
heart_piu->h_imr[3] = 0;
heart_piu->h_mode |= HM_INT_EN;
BRIDGE_K1PTR->b_wid_int_upper = INT_DEST_UPPER(9); /*bogus vec*/
BRIDGE_K1PTR->b_wid_int_lower = INT_DEST_LOWER;
#endif
ip30_setup_power();
set_SR(get_SR() | SR_IE);
VPRINTF(("Initializing the rest of memory.\r\n"));
#define PHYS_TO_UNCACHED_ACC(x) ((__psunsigned_t)(x)|0xb800000000000000)
#if ENETBOOT
#ifdef SYMMON
#define ZERO_BASE (PHYS_RAMBASE+0x180000) /* 1.5MB for symmon */
#else
#define ZERO_BASE (PHYS_RAMBASE+SYSTEM_MEMORY_ALIAS_SIZE)
#endif /* SYMMON */
bzero((void *)PHYS_TO_K1(ZERO_BASE),
(int)(KDM_TO_PHYS(start) - ZERO_BASE));
#endif /* ENETBOOT */
#if !ENETBOOT
hmclear(PHYS_TO_UNCACHED_ACC(0x0),
PHYS_TO_UNCACHED_ACC(SYSTEM_MEMORY_ALIAS_SIZE));
hmclear(PHYS_TO_UNCACHED_ACC(PHYS_RAMBASE+SYSTEM_MEMORY_ALIAS_SIZE),
PHYS_TO_UNCACHED_ACC(KDM_TO_PHYS(PROM_BSS)));
hmclear(PHYS_TO_UNCACHED_ACC(KDM_TO_PHYS(PROM_STACK)),
PHYS_TO_UNCACHED_ACC(PHYS_RAMBASE+memsize));
#endif /* !ENETBOOT */
init_gda();
VPRINTF(("Initializing exception handlers.\r\n"));
_hook_exceptions(); /* setup exception vectors */
set_SR(get_SR() & ~SR_BEV); /* use our vectors now */
VPRINTF(("Initializing IP30 ASICs.\r\n"));
MPCONF->fanloads = 0; /* for ENETBOOT */
init_ip30_chips();
VPRINTF(("Initializing Status Register.\r\n"));
set_SR(SR_PROMBASE | SR_IE | SR_IBIT_BERR | SR_POWER);
/*
* nvram variable override our own selection only if it
* select a good processor
*/
VPRINTF(("Initializing environment.\r\n"));
init_env();
ptr = getenv("bootmaster");
if (ptr) {
i = *ptr - '0';
if (i >= 0 && i < MAXCPU && PROCESSOR_IS_INSTALLED(i) &&
!PROCESSOR_IS_BAD(i))
master_cpuid = i;
}
GDA->g_masterspnum = master_cpuid; /* reset master CPU */
/* Read cpumask while code is single threaded */
ptr = cpu_get_nvram_offset(NVOFF_CPUDISABLE,NVLEN_CPUDISABLE);
cpumask = (*ptr << 8) | *(ptr+1);
if ((cpumask & CPU_DISABLE_MAGIC_MASK) != CPU_DISABLE_MAGIC)
cpumask = 0; /* ignore bogus magic */
if (id != master_cpuid) {
VPRINTF(("CPU %d is the new bootmaster.\r\n",
master_cpuid));
/* Need to flush master CPUs .bss, and stop running
* cached if we are going to switch. We will be
* cached again shortly.
*/
running_cached = 0;
uncache_K0();
#ifdef ENETBOOT
run_uncached();
#endif
flush_cache();
}
for (i = 0; i < MAXCPU; i++) {
if (!PROCESSOR_IS_INSTALLED(i) || PROCESSOR_IS_BAD(i))
continue;
heart_piu->h_mode &= ~HM_PROC_DISABLE(i);
wakeup_slave_processors(0x1 << i, 0);
}
}
if (!running_cached) { /* really means bootmaster switched */
if (cachepromtext()) {
cache_K0();
#ifdef ENETBOOT
run_cached();
#endif
}
setstackseg(K0BASE);
/* this assumes we can have a maximum of 2 processors */
if (id == master_cpuid) {
heartreg_t master_imr;
int old_master = id ^ 0x1;
master_imr = heart_piu->h_imr[old_master];
master_imr ^= HEART_IMR_BERR_(old_master);
heart_piu->h_imr[id] = master_imr |
HEART_IMR_BERR_(id);
heart_piu->h_imr[old_master] =
HEART_IMR_BERR_(old_master);
}
}
if (id == master_cpuid)
set_SR(SR_PROMBASE | SR_IE | SR_IBIT_BERR | SR_POWER);
else
set_SR(SR_PROMBASE | SR_IE | SR_IBIT_BERR);
init_tlb();
/* set up the MPCONF block */
mpconf_ptr = (volatile mpconf_t *)
(MPCONF_ADDR + MPCONF_SIZE * id);
mpconf_ptr->pr_id = get_prid();
mpconf_ptr->phys_id = mpconf_ptr->virt_id = id;
mpconf_ptr->scache_size = ((r4k_getconfig() & CONFIG_SS) >>
CONFIG_SS_SHFT) + CONFIG_SCACHE_POW2_BASE;
mpconf_ptr->mpconf_magic = MPCONF_MAGIC;
/* slave goes into slave idle loop or are disabled */
if (id == master_cpuid) {
/* check if any slaves should be disabled */
for (i = 0; i < MAXCPU; i++) {
if ((i != id) && cpumask & (1<<i)) {
VCPUPUTS(i," disabled by disable cmd.\r\n");
heart_piu->h_mode |= HM_PROC_DISABLE(i);
}
}
}
else
slave_loop();
VPRINTF(("Playing startup tune.\r\n"));
play_hello_tune(0); /* boot tune */
VPRINTF(("Executing remainder of diagnostic.\r\n"));
diagsfailed = pon_morediags(); /* run more diags */
#ifndef IP30_RPROM
/* Fan control stuff, done after pon_morediags() as that is where
* gfx is counted.
*/
ptr = getenv("fastfan");
if (ptr && (*ptr == '1' || *ptr == 'y')) {
VPRINTF(("Enabling fast fan via environment.\r\n"));
MPCONF->fanloads += 1000;
fan_setting = FAN_SPEED_HI;
}
else if (MPCONF->fanloads <= 1) {
/* single headed SI/SE gfx with no additional XIO device */
VPRINTF(("Lowering fan speed via config.\r\n"));
fan_setting = FAN_SPEED_LO;
}
else if (!badaddr((volatile void *)(K1_MAIN_WIDGET(9)+WIDGET_ID), 4)) {
/* quadrant D is occupied, enable fast fan */
VPRINTF(("Enabling fast fan via config.\r\n"));
MPCONF->fanloads += 1000;
fan_setting = FAN_SPEED_HI;
}
else
fan_setting = 0x0;
*IP30_VOLTAGE_CTRL = fan_setting |
PWR_SUPPLY_MARGIN_LO_NORMAL | PWR_SUPPLY_MARGIN_HI_NORMAL;
#endif /* IP30_RPROM */
VPRINTF(("Wait for tune.\r\n"));
if (pon_audio_wait())
diagsfailed |= FAIL_AUDIO;
/* clear memory cached unless diag fails */
#ifdef ENETBOOT
VPRINTF(("Clearing memory.\r\n"));
clear_memory(diagsfailed & FAIL_CACHES);
#endif
VPRINTF(("Initializing software and devices.\r\n"));
init_prom_soft(1);
VPRINTF(("All initialization and diagnostic completed.\r\n"));
#ifndef IP30_RPROM
if (diagsfailed) {
/* Continue the Hook for GE Medical we did for I2
* This lets the system not stop for user intervention
* when power-on diags fail
*
* diagmode=dc (diags continue) triggers this
*/
char *dm = getenv("diagmode");
if (dm && (strstr(dm,"dc"))) {
printf("\nDiagnostics failed.\nContinuing with diagmode=dc.");
startup(); /* no need to check diagmode=mfg */
} else {
setTpButtonAction(main, TPBCONTINUE, WBNOW);
printf("\nDiagnostics failed.\n[Press any key to continue.]");
getchar();
main();
}
}
else {
char *dm = getenv("diagmode");
if (dm && (strstr(dm,"mfg"))) {
domfgstartup(dm);
main();
} else {
startup();
}
}
#else /* IP30_RPROM */
main();
#endif /* !IP30_RPROM */
}
#ifndef IP30_RPROM
static void
domfgstartup(char *mode)
{
char *p = getenv("idebinary");
char bootfile[128];
char *cmdv[4];
int cmdc;
int i;
if (!p) return;
strcpy(bootfile,"bootp()");
strcat(bootfile,p);
cmdc = 3;
cmdv[0] = "boot";
cmdv[1] = "-f";
cmdv[2] = bootfile;
cmdv[3] = 0;
printf("mfg startup: ");
for (i = 0; i < cmdc; i++) {
puts(cmdv[i]);
putchar(' ');
}
putchar('\n');
p_curson();
for (i = 0; i < 500; i++)
if (GetReadStatus(0) == ESUCCESS)
return;
else
us_delay(1000);
Verbose = 1;
boot(cmdc, cmdv, 0, 0);
setTpButtonAction(main, TPBCONTINUE, WBNOW);
printf("\nMfg auto boot failed.\n[Press any key to continue.]");
getchar();
return;
}
#endif /* !IP30_RPROM */
/*
* init_prom_soft - configure prom software, only master processor should
* call this routine
*/
void
init_prom_soft(int no_init_env)
{
/* slave processor only */
if (cpuid() != GDA->g_masterspnum) {
HEART_PIU_K1PTR->h_clr_isr = HEART_ISR_IPI;
flush_cache();
init_tlb();
/* enable bus error interrupt */
set_SR(SR_PROMBASE | SR_IE | SR_IBIT_BERR);
slave_loop();
/* NOTREACHED */
}
/*
* except sysinit(), all routines calling init_prom_soft() should
* set no_init_env to zero
*/
if (!no_init_env) {
master_cpuid = cpuid();
/*
* do this to get debug printf working before _init_saio()
* is called since the calling routine probably just clears
* the PROM bss
*/
_libsc_private = &ip30_tmp_libsc_private;
initsplocks();
initlock(&arcs_ui_lock);
/*
* initialize cache related global variables and the tlb
* cache has already been flushed by the calling routine
*/
config_cache();
init_tlb();
/* set to use memory based exception handlers */
VPRINTF(("_hook_exceptions()\r\n"));
_hook_exceptions();
set_SR(get_SR() & ~SR_BEV);
VPRINTF(("Re-Initializing IP30 ASICs.\r\n"));
init_ip30_chips();
/* enable bus/widget error and softpower interrupt */
set_SR(SR_PROMBASE | SR_IE | SR_IBIT_BERR | SR_POWER);
/* initialize environment variables */
VPRINTF(("Re-initializing environment.\r\n"));
init_env();
if (!wakeup_slave_processors((0x1 << MAXCPU) - 1, 10)) {
VPRINTF(("Slaves did not wakeup, resetting\r\n"));
cpu_hardreset();
}
}
#if DEBUG
atob(getenv("DEBUG"), &Debug); /* initialize debugging flags */
atob(getenv("VERBOSE"), &Verbose);
#endif
VPRINTF(("_init_saio()\r\n"));
_init_saio(); /* initialize saio library */
VPRINTF(("alloc_memdesc()\r\n"));
alloc_memdesc(); /* allocate memory descriptors for prom */
}
#ifndef IP30_RPROM
/*
* halt - bring the system to a quiescent state
*/
void
halt(void)
{
play_hello_tune(1); /* shutdown tune */
if (doGui())
setGuiMode(1, GUI_NOLOGO);
popupDialog("\n\nOkay to power off the system now.\n\n"
"Press RESET button to restart.",
0, DIALOGINFO, DIALOGCENTER | DIALOGBIGFONT);
/* do not need to wait for power down tune since we spin here */
}
/*
* restart - attempt to restart
*/
void
restart(void)
{
static int restart_buttons[] = {
DIALOGRESTART, -1 };
play_hello_tune(1); /* shutdown tune */
if (doGui())
setGuiMode(1, GUI_NOLOGO);
popupDialog("\n\nOkay to power off the system now.\n\n"
"Press any key to restart.",
restart_buttons, DIALOGINFO,
DIALOGCENTER | DIALOGBIGFONT);
wait_hello_tune();
if (doGui())
setGuiMode(0, GUI_RESET);
/* Set-up for AC fails -- need to wait until continue so user can
* power off system and keep setting of alarm for iauto power on.
*/
ip30_power_switch_on(); /* set-up for AC fails */
startup();
}
/*
* reboot - attempt a reboot
*/
void
reboot(void)
{
if (!Verbose && doGui()) {
setGuiMode(1, 0);
}
else {
p_panelmode();
p_cursoff();
}
if (ESUCCESS != autoboot(0, 0, 0)) {
play_hello_tune(1); /* shutdown tune */
putchar('\n');
setTpButtonAction(EnterInteractiveMode, TPBCONTINUE, WBNOW);
p_curson();
p_printf("Unable to boot; press any key to continue: ");
getchar();
putchar('\n');
wait_hello_tune();
}
/*
* If reboot fails, reinitialize software in case a partially
* booted program has messed up the prom state.
*/
EnterInteractiveMode(); /* should not get here */
}
void
enter_imode(void)
{
set_SR(SR_PROMBASE | ENET_SR_BEV | SR_IE); /* for power */
_hook_exceptions();
_init_saio(); /* initialize saio library */
alloc_memdesc(); /* allocate memory descriptors for prom */
wbflush();
set_SR(SR_PROMBASE | SR_IE | SR_IBIT_BERR | SR_POWER);
main();
EnterInteractiveMode(); /* shouldn't get here */
}
#endif /*!IP30_RPROM */
static void
alloc_memdesc(void)
{
#define STKSZ 16384 /* 16K stack (bigger than 32 bit prom) */
#ifdef ENETBOOT
/*
* Add what we know to be the dprom's text, data as FirmwarePermanent,
* and bss (rounded up from data page) + stack as Firmware as
* FirmwareTemporary.
*/
extern int start();
md_alloc(KDM_TO_PHYS(start),
arcs_btop(DBSSADDR - (__psunsigned_t)start),
FirmwarePermanent);
md_alloc(KDM_TO_PHYS(DBSSADDR),
arcs_btop(0x100000), FirmwareTemporary);
md_alloc(KDM_TO_PHYS(PROM_STACK - STKSZ), arcs_btop(STKSZ),
FirmwareTemporary);
#else
/*
* add what we know to be the prom's stack and bss. Text and
* data are safe in prom in I/O space.
*/
md_alloc(KDM_TO_PHYS(PROM_BSS),
arcs_btop(KDM_TO_PHYS(PROM_STACK) - KDM_TO_PHYS(PROM_BSS)),
FirmwareTemporary);
#endif
}
#ifdef ENETBOOT
/* clear_memory - clear memory from PROM_STACK up */
static void
clear_memory(int uncached)
{
int (*clrfunc)(__psunsigned_t, __psunsigned_t);
if (uncached)
clrfunc = (int (*)())hmclear;
else
clrfunc = (int (*)())K1_TO_K0(hmclear);
/* clear from PROM_STACK to top of memory */
(*clrfunc)(PHYS_TO_UNCACHED_ACC(KDM_TO_PHYS(PROM_STACK)),
PHYS_TO_UNCACHED_ACC(PHYS_RAMBASE + memsize));
}
#endif /* ENETBOOT */
/*
* Called when the caches are in the random power-up state.
* Tags are random, as are the data arrays and check bits
* associated with the cache. The data arrays have to be
* initialized with the SR DE bit on, so not to cause ECC
* or parity errors.
*
* Initialize all caches. All lines are initialized, setting the ECC or
* parity, and each line is set to 'invalid'.
*/
void
init_caches(void)
{
extern unsigned int _sidcache_size;
/* set all tags of each cache to be invalid. */
invalidate_caches();
/*
* now go through each cache, and execute a load (or 'fill'
* for the icache), to cause the data for that cache line
* to be initialized with consistent ECC/parity.
*/
init_scache();
init_dcache();
init_icache();
}
static void
init_gda(void)
{
/* Setup the GDA */
GDA->g_promop = 0;
GDA->g_nmivec = 0;
GDA->g_masterspnum = master_cpuid;
GDA->g_count = 0;
GDA->g_magic = GDA_MAGIC; /* needs to be last */
}
/*
* slave processor spins until it receives an inter-processor interrupt
* from the master processor, or until timeout is reached if it is set.
* it returns a 0 if no interrupt from the master processor is received, a 1
* otherwise. timeout is in unit of millisecond
*/
static int
slave_processor_spin(int timeout)
{
register heart_piu_t *heart_piu = HEART_PIU_K1PTR;
register heartreg_t terminal_count;
if (timeout)
terminal_count = heart_piu->h_count +
timeout * (1000000 / HEART_COUNT_NSECS);
else
terminal_count = 0xfffffffffffff;
while (!(heart_piu->h_isr & HEART_ISR_IPI) &&
heart_piu->h_count < terminal_count)
;
if (heart_piu->h_isr & HEART_ISR_IPI) {
heart_piu->h_clr_isr = HEART_ISR_IPI;
return 1;
}
else
return 0;
}
#define IPI_SHIFT(x) (HEART_INT_L2SHIFT + HEART_INT_IPISHFT + (x))
/*
* master processor wakes up all specified slave processors by sending them
* an inter-processor interrupt, then wait for response from them or until
* timeout is reached if it is set. it returns a 0 if it fails to wake up
* one of the processors before timing out, a 1 otherwise. timeout is in
* unit of millisecond
*/
static int
wakeup_slave_processors(uint_t cpu_mask, int timeout)
{
int error = 0;
register heart_piu_t *heart_piu = HEART_PIU_K1PTR;
int i;
register heartreg_t terminal_count;
/* make sure all specified slave processors get the interrupt */
for (i = 0; i < MAXCPU; i++) {
if (i == cpuid() || !(cpu_mask & (0x1 << i)) ||
!PROCESSOR_IS_ACTIVE(i))
continue;
if (timeout)
terminal_count = heart_piu->h_count +
timeout * (1000000 / HEART_COUNT_NSECS);
else
terminal_count = 0xfffffffffffff;
heart_piu->h_set_isr = 0x1L << IPI_SHIFT(i);
while (heart_piu->h_isr & (0x1L << IPI_SHIFT(i)) &&
heart_piu->h_count < terminal_count)
;
if (heart_piu->h_isr & (0x1L << IPI_SHIFT(i)))
error = 1;
}
return error == 0;
}
#ifndef IP30_RPROM
static void
dump_nic_info(char *buf,int dumpflag)
{
int n = 0;
if (dumpflag) {
printf("%s\n",buf);
return;
}
while (*buf != '\0') {
switch (*buf) {
case ':':
printf(": ");
buf++;
while (*buf != '\0' && *buf != ';') {
putchar(*buf);
buf++;
}
printf(" ");
n++;
break;
default:
if (strncmp(buf, "Part:", 5) == 0 ||
strncmp(buf, "NIC:", 4) == 0) {
puts("\n ");
n = 0;
}
else if (n == 3) {
puts("\n ");
n = 0;
}
putchar(*buf);
break;
}
buf++;
}
putchar('\n');
}
#define MB (1024 * 1024)
int
system_cmd(int argc, char **argv)
{
volatile struct mpconf_blk *mpconf = MPCONF;
unsigned int config = r4k_getconfig();
static char *div[] = { "?", "1", "1.5", "2", "2.5", "3", "3.5", "4",
"4.5", "5", "5.5", "6", "6.5" };
int dumpflag = 0;
nic_data_t mcr;
char *buf;
int loads;
int port;
int xrev;
if (argc == 2 && !strcmp(argv[1],"-d"))
dumpflag = 1;
printf("IP30 system:\n");
printf(" CPU speed ~%sMhz\n",cpu_get_freq_str(0));
printf(" Cache speed divisor %s\n",
div[(config & CONFIG_SC) >> CONFIG_SC_SHFT]);
printf(" SysAD speed divisor %s\n",
div[(config & CONFIG_EC) >> CONFIG_EC_SHFT]);
printf(" %d outstanding read(s)\n",
((config & CONFIG_PM) >> CONFIG_PM_SHFT) + 1);
/*
* This will have to be revisited when R14000 etc come out.
*/
if (!IS_R12000())
printf(" R10K Revision: %d.%d",
(mpconf[0].pr_id&C0_MAJREVMASK)>>C0_MAJREVSHIFT,
mpconf[0].pr_id&C0_MINREVMASK);
if (IS_R12000())
printf(" R12K Revision: %d.%d",
(mpconf[0].pr_id&C0_MAJREVMASK)>>C0_MAJREVSHIFT,
mpconf[0].pr_id&C0_MINREVMASK);
if (mpconf[1].mpconf_magic == MPCONF_MAGIC)
printf(", CPU 1 %d.%d",
(mpconf[1].pr_id&C0_MAJREVMASK)>>C0_MAJREVSHIFT,
mpconf[1].pr_id&C0_MINREVMASK);
printf("\n");
printf(" Password jumper %s\n", jumper_off() ? "missing" : "on");
buf = getenv("fastfan");
loads = mpconf[0].fanloads;
if (loads < 0)
loads = -loads;
else if (loads > 1000)
loads -= 1000;
printf(" Number of XIO fan loads %d (%d,env=%s)\n",
loads, mpconf[0].fanloads, buf ? buf : "unset");
printf("Chips/NICs:\n");
buf = malloc(1024);
if (buf != 0) {
printf(" heart(rev %c): ", 'A' + heart_rev() - 1);
mcr = (nic_data_t)&HEART_PIU_K1PTR->h_mlan_ctl + 0x4;
cfg_get_nic_info(mcr, buf);
dump_nic_info(buf,dumpflag);
xrev = XWIDGET_REV_NUM(XBOW_K1PTR->xb_wid_id);
if (xrev <= XBOW_REV_2_0)
printf(" xbow(rev 1.%d):\n", xrev - 1);
else
printf(" xbow(rev 2.%d):\n", xrev - XBOW_REV_2_0);
printf(" bridge(rev %c): ",
'A' + XWIDGET_REV_NUM(BRIDGE_K1PTR->b_wid_id) - 1);
mcr = (nic_data_t)&BRIDGE_K1PTR->b_nic;
cfg_get_nic_info(mcr, buf);
dump_nic_info(buf,dumpflag);
printf(" ioc3(rev %d): eaddr %s ",
*(ioc3reg_t *)(IOC3_PCI_DEVIO_K1PTR+IOC3_PCI_REV)&0xf,
getenv("eaddr"));
mcr = (nic_data_t)IOC3_PCI_DEVIO_K1PTR + IOC3_MCR;
cfg_get_nic_info(mcr, buf);
dump_nic_info(buf,dumpflag);
/* look for other bridge/HQ4 NICs on xtalk */
for (port = BRIDGE_ID-1; port > HEART_ID; port--) {
widget_cfg_t *widget;
int id;
if (!xtalk_probe(XBOW_K1PTR, port))
continue;
widget = (widget_cfg_t *)K1_MAIN_WIDGET(port);
id = ((widget->w_id) & WIDGET_PART_NUM) >>
WIDGET_PART_NUM_SHFT;
printf(" xtalk 0x%x ",port);
if (id == BRIDGE_WIDGET_PART_NUM) {
bridge_t *bridge = (bridge_t *)widget;
printf("bridge(rev %c): ",
'A' + XWIDGET_REV_NUM(bridge->b_wid_id) - 1);
mcr = (nic_data_t)&bridge->b_nic;
cfg_get_nic_info(mcr, buf);
dump_nic_info(buf,dumpflag);
}
else if (id == HQ4_WIDGET_PART_NUM) {
mgras_hw *hq4 = (mgras_hw *)widget;
printf("HQ4: ");
mcr = (nic_data_t)&hq4->microlan_access;
cfg_get_nic_info(mcr, buf);
dump_nic_info(buf,dumpflag);
}
else
printf("unknown widget partno=0x%x\n",id);
}
free(buf);
}
return(0);
}
static void
able_stat(void)
{
heart_piu_t *heart_piu = HEART_PIU_K1PTR;
extern int master_cpuid;
unsigned short cpumask;
int env_bootmaster;
char *p;
int i;
p = cpu_get_nvram_offset(NVOFF_CPUDISABLE,NVLEN_CPUDISABLE);
cpumask = (*p << 8) | *(p+1);
printf("Processor status:\n");
if (p = getenv("bootmaster")) {
env_bootmaster = atoi(p);
if (env_bootmaster < 0 || env_bootmaster >= MAXCPU)
env_bootmaster = 0;
}
if (master_cpuid == env_bootmaster)
env_bootmaster = MAXCPU; /* same as current */
for (i=0; i < MAXCPU; i++) {
if (!PROCESSOR_IS_INSTALLED(i)) continue;
printf(" CPU %d is marked %sabled, is currently %sabled. %s%s\n",
i,
cpumask & (1<<i) ? "dis" : "en",
PROCESSOR_IS_DISABLED(i) ? "dis" : "en",
i == master_cpuid ? "[current bootmaster]" : "",
i == env_bootmaster ? "[next bootmaster]" : "");
}
}
/*ARGSUSED*/
int
disable_cmd(int argc, char **argv, char **argp, struct cmd_table *xxx)
{
heart_piu_t *heart_piu = HEART_PIU_K1PTR;
unsigned short cpumask;
char *p;
int cpu;
int i;
if (argc == 1) {
able_stat();
return 0;
}
if (argc != 2)
return 1;
cpu = atoi(argv[1]);
if ((cpu >= MAXCPU) || !PROCESSOR_IS_INSTALLED(cpu)) {
printf("CPU %d does not exist.\n",cpu);
return 0;
}
if (cpu_probe_all() == 1) {
printf("Only one CPU is present, please do not disable it.\n");
return 0;
}
p = cpu_get_nvram_offset(NVOFF_CPUDISABLE,NVLEN_CPUDISABLE);
cpumask = (*p << 8) | *(p+1);
if ((cpumask & CPU_DISABLE_MAGIC_MASK) != CPU_DISABLE_MAGIC) {
printf("warning: cpumask had invalid magic.\n");
ip30_init_cpu_disable();
cpumask = CPU_DISABLE_MAGIC;
}
/* If trying to disable the current CPU, we have to do some extra
* work with the bootmaster and require a reboot.
*/
if (cpu == cpuid()) {
int env_bootmaster = 0;
int new_bootmaster;
char buf[2];
char *ptr;
if (ptr = getenv("bootmaster")) {
env_bootmaster = atoi(ptr);
if (env_bootmaster < 0 || env_bootmaster >= MAXCPU)
env_bootmaster = 0;
}
if (env_bootmaster == cpu) {
new_bootmaster = MAXCPU;
for (i = 0 ; i < MAXCPU; i++) {
if (i == env_bootmaster) continue;
if (PROCESSOR_IS_INSTALLED(i) &&
!(cpumask & (1<<i)))
new_bootmaster = i;
}
if (new_bootmaster < MAXCPU) {
printf("Setting bootmaster to CPU %d to allow "
"CPU %d (current bootmaster) to be "
"disabled.\n",new_bootmaster,cpu);
buf[0] = '0' + new_bootmaster;
buf[1] = '\0';
_setenv("bootmaster",buf,0);
}
else {
printf("Cannot disable the bootmaster. "
"There are no other enabled CPUs.\n");
able_stat();
return 0;
}
}
}
/* ensure at least one other processor is enabled in mask */
for (i = 0; i < MAXCPU; i++) {
if (i == cpu) continue;
if (PROCESSOR_IS_INSTALLED(i) && !(cpumask & (1<<i)))
break;
}
if (i == MAXCPU) {
printf("Cannot disable CPU %d, "
"it is the only CPU marked active.\n",cpu);
able_stat();
return 0;
}
if (PROCESSOR_IS_DISABLED(cpu)) {
if ((cpumask & (1<<cpu)) != 0) {
printf("CPU %d is already disabled.\n",cpu);
able_stat();
return 0;
}
else
printf("CPU %d is already disabled. "
"Note that it may have failed diagnostics.\n",
cpu);
}
cpumask |= (1<<cpu);
*(p+1) = cpumask & 0xff;
cpu_set_nvram_offset(NVOFF_CPUDISABLE,NVLEN_CPUDISABLE,p);
if (cpu != cpuid()) {
printf("Disabling slave CPU %d now.\n",cpu);
heart_piu->h_mode |= HM_PROC_DISABLE(cpu);
}
else {
printf("Disabling CPU %d. "
"The machine must be reset for this to take effect.\n",
cpu);
}
return 0;
}
/*ARGSUSED*/
int
enable_cmd(int argc, char **argv, char **argp, struct cmd_table *xxx)
{
heart_piu_t *heart_piu = HEART_PIU_K1PTR;
unsigned short cpumask;
int cpu;
char *p;
if (argc == 1) {
able_stat();
return 0;
}
if (argc != 2)
return 1;
cpu = atoi(argv[1]);
if ((cpu >= MAXCPU) || !PROCESSOR_IS_INSTALLED(cpu)) {
printf("CPU %d does not exist.\n",cpu);
return 0;
}
p = cpu_get_nvram_offset(NVOFF_CPUDISABLE,NVLEN_CPUDISABLE);
cpumask = (*p << 8) | *(p+1);
if ((cpumask & CPU_DISABLE_MAGIC_MASK) != CPU_DISABLE_MAGIC) {
printf("warning: cpumask had invalid magic.\n");
ip30_init_cpu_disable();
cpumask = CPU_DISABLE_MAGIC;
}
/* if we are enabling the current CPU, perhaps reset bootmaster */
if (cpu == cpuid()) {
int env_bootmaster = 0;
int new_bootmaster;
char buf[2];
char *ptr;
if (ptr = getenv("bootmaster")) {
env_bootmaster = atoi(ptr);
if (env_bootmaster < 0 || env_bootmaster >= MAXCPU)
env_bootmaster = 0;
}
if (env_bootmaster != cpu) {
printf("Resetting bootmaster to CPU %d, the current "
"bootmaster.\n",cpu);
buf[0] = '0' + cpu;
buf[1] = '\0';
_setenv("bootmaster",buf,0);
}
}
if ((cpumask & (1<<cpu)) == 0) {
if (PROCESSOR_IS_DISABLED(cpu))
printf("CPU %d is marked enabled but is disabled.\n"
"Ensure that it has passed diagnostics.\n",cpu);
else
printf("CPU %d is already enabled.\n",cpu);
able_stat();
return 0;
}
cpumask &= cpumask & ~(1<<cpu);
*(p+1) = cpumask & 0xff;
cpu_set_nvram_offset(NVOFF_CPUDISABLE,NVLEN_CPUDISABLE,p);
printf("Enabling CPU %d.",cpu);
if (PROCESSOR_IS_DISABLED(cpu))
printf(" The machine must be reset for this to take effect.");
printf("\n");
return 0;
}
#endif /* !IP30_RPROM */
/* Check nvram to see if prom text should be cached or not, This
* is mostly for LA debugging odd prom failures.
*/
static int
cachepromtext(void)
{
char *p;
p = cpu_get_nvram_offset(NVOFF_UNCACHEDPROM,NVLEN_UNCACHEDPROM);
return (p && (*p == '1' || *p == 'y')) == 0;
}