431 lines
14 KiB
C
431 lines
14 KiB
C
#ifndef __IDE_MP_H__
|
|
#define __IDE_MP_H__
|
|
|
|
/*
|
|
* ide_mp.h - ide-specific mp definitions
|
|
*
|
|
* $Revision: 1.21 $
|
|
*/
|
|
|
|
#if _LANGUAGE_C
|
|
#include <sys/types.h>
|
|
#include <sys/systm.h>
|
|
#include <stringlist.h>
|
|
#endif /* _LANGUAGE_C */
|
|
|
|
/*
|
|
* genpda.h evaluates MULTIPROCESSOR; ensure it's been included in
|
|
* whatever .c file we're included in.
|
|
*/
|
|
#ifndef __GENPDA_H__
|
|
dontcompile("#include ERROR, ide_mp.h: genpda.h hasn't been included!")
|
|
#endif
|
|
|
|
/*
|
|
* define structs and values to interrelate the following processor terms:
|
|
*
|
|
* virtual ids (vid): [0..ActiveProcessors-1]
|
|
* - contiguous, sequential numbering assigned during system init.
|
|
* physical indices (phys_index): [0..MAXCPUS]
|
|
* - hardware-determined ordering, readable at runtime. Used only
|
|
* as a guaranteed-unique index to fetch assigned vid
|
|
* EVEREST specific:
|
|
* slot - (Everest) [0..EV_BOARD_MAX]:
|
|
* - backplane slot board is occupying (hw-numbered)
|
|
* slice - (Everest) [0..EV_MAX_CPUS_BOARD]:
|
|
* - position on cpu board of specific processor (hw-numbered)
|
|
* physical indices are derived from <slot,slice> pairs
|
|
*
|
|
* In order to allow runtime instead of compile-time decision making
|
|
* (due to architectural differences) set up dummy structs for
|
|
* inapplicable concepts and initialize them with values that make
|
|
* everything work anyway.
|
|
*/
|
|
|
|
#if EVEREST
|
|
#define _SLOTS EV_BOARD_MAX /* slots in Everest backplane */
|
|
#define _SLICES EV_MAX_CPUS_BOARD /* max cpus per processor bd */
|
|
#else /* !EVEREST */
|
|
#define _SLOTS 1
|
|
#define _SLICES 1
|
|
#endif /* EVEREST */
|
|
|
|
/*
|
|
* XXXX For all R4K-based architectures, the master and slave SRs
|
|
* should really have SR_KX & SR_FR set, but one/both of these
|
|
* caused problems (FPE exceptions) before 5.0.1, so I nuked 'em.
|
|
* They'll be required for 6.0.
|
|
*/
|
|
#if _MIPS_SIM == _ABI64
|
|
#define IDE_SLAVE_SR SR_KX
|
|
#else
|
|
#define IDE_SLAVE_SR 0
|
|
#endif
|
|
|
|
/* ide-specific pda */
|
|
#define IDE_PDASIZE 512 /* size in bytes of ide's PDA */
|
|
#define IDE_PDASIZE_2 9 /* log2 of IDE_PDASIZE */
|
|
|
|
/* values of empty slots: SP can't have any bad cpus! */
|
|
#if MULTIPROCESSOR
|
|
#define BAD_CPU 0xDEADBEEF /* disabled cpu: failed power-on diags */
|
|
#endif
|
|
|
|
#define MTY (-1) /* slot or slice has no cpu in it. */
|
|
#define NO_VID (-1) /* potential talking_vid value */
|
|
|
|
#if !defined(LANGUAGE_ASSEMBLY)
|
|
|
|
/*
|
|
* each diagnostic has <passcnt,failcnt,skipcnt> triple per cpu. A back-ptr to
|
|
* the diag's symbol makes flexible log-dumping easy.
|
|
*/
|
|
typedef struct mp_logrec_s {
|
|
sym_t *diagsym;
|
|
unsigned pass_tot;
|
|
unsigned fail_tot;
|
|
unsigned skip_tot;
|
|
unsigned passcnt[MAXCPU];
|
|
unsigned failcnt[MAXCPU];
|
|
unsigned skipcnt[MAXCPU];
|
|
} mp_logrec_t;
|
|
extern mp_logrec_t statlog[MAXDIAG];
|
|
extern int diag_tally;
|
|
|
|
extern void ide_mpsetup(void);
|
|
|
|
extern int dump_cpu_info(void);
|
|
extern int ide_whoisthat(int, char *);
|
|
extern int ide_whoami(char *);
|
|
|
|
/*
|
|
* the following arrays convert between different methods of processor
|
|
* numbering. Some of these are redundant but convenient.
|
|
*/
|
|
extern int vid_to_phys_idx[]; /* vid --> phys_index */
|
|
extern int phys_idx_to_vid[]; /* phys_index --> vid */
|
|
extern int vid_to_slot[]; /* vid --> slot */
|
|
extern int vid_to_slice[]; /* vid --> slice */
|
|
extern cpuid_t ss_to_vid[_SLOTS][_SLICES]; /* slot/slice --> vid */
|
|
|
|
extern struct string_list argv_str_tab[];
|
|
extern struct string_list environ_str_tab[];
|
|
extern void ide_initargv(int *, char ***, struct string_list *);
|
|
|
|
/* <slot,slice> --> phys_index */
|
|
#define SS_TO_PHYS(_slot, _slice) ((_slot << 2) + _slice)
|
|
|
|
typedef volatile unsigned long volul_t;
|
|
typedef volatile long voll_t;
|
|
|
|
/* kludge typedef for fns invoked by launching code */
|
|
typedef volatile void *volvp;
|
|
|
|
|
|
#ifdef USE_THE_LEDS
|
|
> /*
|
|
> * The master issues commands to slaves, and the slaves ACK those
|
|
> * commands with a response. The inconvenient values below were
|
|
> * mandated by the shortage of LEDs on Everests (6).
|
|
> * These bits are split 3 and 3, with the top three encoded to
|
|
> * yield 8 commands from the master to a slave, and the bottom
|
|
> * three bits encoded for 8 slave-responses to those commands.
|
|
> */
|
|
> #define DONT_CARE ((voll_t)0x37) /* 11 1111 */
|
|
> /* ide_master commands to slaves */
|
|
> #define CMD_WAKEUP ((voll_t)0x08) /* 00 1000 */
|
|
> #define CMD_CALL_FN ((voll_t)0x10) /* 01 0000 */
|
|
> #define CMD_GIMME_RES ((voll_t)0x18) /* 01 1000 */
|
|
> #define CMD_GO_HOME ((voll_t)0x20) /* 10 0000 */
|
|
> #define CMD_SWITCH_CPUS ((voll_t)0x28) /* 10 1000 */
|
|
> #define CMD_UNUSED1 ((voll_t)0x30) /* 11 0000 */
|
|
>
|
|
> /* slave responses to ide_master's commands) */
|
|
> #define SLAVE_IDLE ((voll_t)0x00) /* 00 0000 */
|
|
> #define SLAVE_AWAKE ((voll_t)0x01) /* 00 0001 */
|
|
> #define SLAVE_WORKING ((voll_t)0x02) /* 00 0010 */
|
|
> #define SLAVE_GAVE_EM ((voll_t)0x03) /* 00 0011 */
|
|
> #define SLAVE_UNUSED1 ((voll_t)0x04) /* 00 0100 */
|
|
> #define SLAVE_UNUSED2 ((voll_t)0x05) /* 00 0101 */
|
|
> #define SLAVE_UNUSED3 ((voll_t)0x06) /* 00 0110 */
|
|
#endif /* forget about trying to use the LEDs for this */
|
|
|
|
|
|
#define SLAVE_INTER 0x80000000
|
|
|
|
/*
|
|
* values of the slaves' `doit_done' status field:
|
|
* pending, finished, interrupted, or error
|
|
*/
|
|
#define STAT_SDOIT 1
|
|
#define STAT_SDONE 2
|
|
#define STAT_SINTER 3
|
|
#define STAT_SERROR 4
|
|
|
|
/*
|
|
*commands from ide_master to remote slaves
|
|
*/
|
|
#define SLAVE_WAKEUP (0x01) /* 00 0001 */
|
|
#define SLAVE_CALL_FN (0x02) /* 00 0010 */
|
|
#define SLAVE_GO_HOME (0x03) /* 00 0011 */
|
|
#define SLAVE_SWITCH_CPUS (0x04) /* 00 0100 */
|
|
|
|
#define SBADCMD_STR "?"
|
|
#define SWAKE_STR "wake_up"
|
|
#define SCALL_STR "exec_fn"
|
|
#define SGOHOME_STR "go_home"
|
|
#define SSWTCH_STR "swtch_cpus"
|
|
|
|
#define BADSCMD(_CMD) (_CMD < SLAVE_WAKEUP || _CMD > SLAVE_SWITCH_CPUS)
|
|
#define BADSSTAT(S_STAT) (S_STAT < STAT_SDOIT || S_STAT > STAT_SERROR)
|
|
|
|
|
|
#define IDLE_LEDS(_VID_) \
|
|
{ \
|
|
int led5 = ((0x1 << 5) | _VID_); \
|
|
int led4 = ((0x1 << 4) | _VID_); \
|
|
int i; \
|
|
\
|
|
_set_cc_leds(0); \
|
|
for (i = 150000; i > 0; i--); \
|
|
_set_cc_leds(led5); \
|
|
for (i = 150000; i > 0; i--); \
|
|
_set_cc_leds(0); \
|
|
for (i = 150000; i > 0; i--); \
|
|
_set_cc_leds(led4); \
|
|
}
|
|
|
|
|
|
/*
|
|
* - VID_OUTARANGE check vids against highest assigned vid found during
|
|
* traversal of the prom-built config-tree, or 0 if an SP machine.
|
|
* use this check for verifying launch vids, etc.
|
|
* - PLAUSIBLE_VID checks only that the vid is in the range of
|
|
* 0 <= vid < MAXSETSIZE. PLAUSIBLE_VID is used in set operations like
|
|
* set_in and add_cpu, where the target set isn't referring to the
|
|
* active system.
|
|
* - PHYS_IDX_OUTARANGE checks physically-numbered cpunums against the
|
|
* defined system-max `MAXCPU'.
|
|
*/
|
|
#define VID_OUTARANGE(VID) ((VID) < 0 || (VID) > _ide_info.vid_max)
|
|
#define PHYS_IDX_OUTARANGE(PHYS_IDX) ((PHYS_IDX) < 0 || (PHYS_IDX) >= MAXCPU)
|
|
#define PLAUSIBLE_VID(V_ID) ((V_ID) >= 0 && (V_ID) < MAXSETSIZE)
|
|
|
|
typedef struct argdesc_s {
|
|
int argc;
|
|
char **argv;
|
|
} argdesc_t;
|
|
|
|
extern int _get_disopts(argdesc_t *arginfop, optlist_t *optlistp);
|
|
|
|
typedef volatile struct proc_talk_s {
|
|
volvp fnaddr;
|
|
argdesc_t fnargcv; /* contains fn's <argc, argv> combo */
|
|
voll_t fnreturn; /* launched job's return value */
|
|
voll_t state; /* indicates slave's current state */
|
|
voll_t slavecmd; /* command from master: slave spins on this */
|
|
voll_t doitdone; /* */
|
|
} proc_talk_t;
|
|
|
|
|
|
/*
|
|
* IDE-specific Private Data Area
|
|
*
|
|
* The IDE pda contains the IDE-specific globals: not needed or accessed
|
|
* by any other arcs standalones or library routines, but written and
|
|
* read in shared code.
|
|
*/
|
|
#define IDE_PDAMAGIC 0xDBADBD
|
|
|
|
#if (_MIPS_ISA == _MIPS_ISA_MIPS1 || _MIPS_ISA == _MIPS_ISA_MIPS2)
|
|
typedef int jbuf_elem;
|
|
#endif
|
|
#if (_MIPS_ISA == _MIPS_ISA_MIPS3 || _MIPS_ISA == _MIPS_ISA_MIPS4)
|
|
typedef __uint64_t jbuf_elem;
|
|
#endif
|
|
|
|
typedef union ide_pda_u {
|
|
struct ide_pda_s {
|
|
int ide_pdamagic; /* validate each processor's pda */
|
|
int ide_mode; /* IDE_MASTER or IDE_SLAVE */
|
|
proc_talk_t launch_fn; /* requested function to launch */
|
|
proc_talk_t cleanup_fn; /* clean-up routine (optional) */
|
|
struct string_list *argv_str;
|
|
struct string_list *environ_str;
|
|
jbuf_elem *slave_jbuf;
|
|
jbuf_elem *wakeup_jbuf;
|
|
char *putbuf;
|
|
int putbufndx;
|
|
/* int *fault_buf; -- may use for diags later */
|
|
} idata;
|
|
char filler[IDE_PDASIZE]; /* any reasonable power of 2 */
|
|
} ide_pda_t;
|
|
extern ide_pda_t ide_pda_tab[];
|
|
|
|
#define slave_cmd launch_fn.slavecmd
|
|
#define doit_done launch_fn.doitdone
|
|
|
|
#define fn_addr launch_fn.fnaddr
|
|
#define fn_argcv launch_fn.fnargcv
|
|
#define fn_return launch_fn.fnreturn
|
|
|
|
#define cleanup_addr cleanup_fn.fnaddr
|
|
#define cleanup_argcv cleanup_fn.fnargcv
|
|
#define cleanup_return cleanup_fn.fnreturn
|
|
|
|
|
|
/*
|
|
* 'GPRIVATE' is already defined in genpda.h; that'll get us into our
|
|
* generic pda. IDE-specific global variables are stored in another
|
|
* set of pdas: to access values in other processors' pdas (master does
|
|
* this) define 'IDE_PRIVATE(vid,fieldname)'. Transparent access to
|
|
* one's own pda fields is provided by prepending the field names with an
|
|
* underscore. e.g. IDE_PRIVATE(vid,slave_jbuf) and _slave_jbuf both
|
|
* refer to ide_pda_tab[vid].ide_pda.slave_jbuf.
|
|
*/
|
|
#define IDE_PRIVATE(_VID_,_FIELD_) (ide_pda_tab[_VID_].idata._FIELD_)
|
|
#define IDE_ME(_FIELD_) (ide_pda_tab[_cpuid()].idata._FIELD_)
|
|
|
|
#if EVEREST
|
|
/*
|
|
* boardinfo_t tallies the number of each type of legal EVEREST board
|
|
* based on the current configuration, created by the prom during bootup
|
|
*/
|
|
typedef struct boardinfo_s {
|
|
int ip19;
|
|
int ip21;
|
|
int ip25;
|
|
int io4;
|
|
int mc3;
|
|
int mty; /* total number of empty slots */
|
|
int unknown;
|
|
} boardinfo_t;
|
|
extern boardinfo_t evboards;
|
|
extern int dump_ev_bdinfo(boardinfo_t *);
|
|
#endif /* EVEREST */
|
|
|
|
|
|
/*
|
|
* ide_slave() provides the setup and cleanup between libsk's
|
|
* call_coroutine() and the invoked function. It sets up the stack
|
|
* using the specified sp, and--interpretting the single argument provided
|
|
* by the launch facility as a pointer to the necessary args--sets up the
|
|
* normal <int argc, char *argv[]> format and calls the function.
|
|
*/
|
|
extern int ii_spl;
|
|
extern lock_t ide_info_lock;
|
|
|
|
#if defined(MULTIPROCESSOR) && defined(_LOCK_IINFO)
|
|
#define _DO_IILOCK
|
|
#define LOCK_IDE_INFO() ii_spl=splockspl(ide_info_lock, splhi);
|
|
#define UNLOCK_IDE_INFO() spunlockspl(ide_info_lock, ii_spl);
|
|
#else
|
|
#define LOCK_IDE_INFO()
|
|
#define UNLOCK_IDE_INFO()
|
|
#endif /* MULTIPROCESSOR && _LOCK_IINFO */
|
|
|
|
|
|
#define IDE_PMGR "ide_pmgr" /* IDE Process Manager */
|
|
|
|
/*
|
|
* global_info_t contains information of general interest to ide slaves
|
|
* and the ide_master: the tally and set of logical processors in the
|
|
* system, the vid of the processor currently executing as master,
|
|
* status variables used for user-interface arbitration/control, and
|
|
* a set of variables which determine the default environment under which
|
|
* all diagnostics execute. It is initialized during ide startup by the master
|
|
* code, and updated by the new ide_master when the master execution
|
|
* thread migrates to a different processor. The ui data is written
|
|
* by slaves and the master, so it's lock-protected. The remaining
|
|
* fields of the structure are only modified by the processor executing
|
|
* as 'master', so it needn't be locked.
|
|
*/
|
|
typedef struct global_info_s {
|
|
uint g_magic; /* confirms initialization of vp_info struct */
|
|
uint vid_cnt; /* total # of active (==virtual) processors */
|
|
uint vid_max; /* largest allocated virtual id in system */
|
|
uint master_vid; /* current ide-master's virtual processor# */
|
|
uint *saved_normsp; /* master's normal-mode SP when slave */
|
|
uint *saved_faultsp; /* master's fault-mode SP when slave */
|
|
uint talking_vid; /* vid of proc currently controlling duart */
|
|
volul_t c_pending; /* pending state of system */
|
|
volul_t c_state; /* current state of system (coherent/noncoh) */
|
|
uint pad; /* must have dbl-word boundary for long longs */
|
|
set_t waiting_vids; /* bitmask of cpus currently in ide_slave_wait*/
|
|
set_t vid_set; /* bit-vector of virtual processors */
|
|
} global_info_t;
|
|
#define IDE_GMAGIC 0xDEADEDDE
|
|
extern global_info_t _ide_info;
|
|
|
|
extern int dump_global(global_info_t *);
|
|
extern int _do_launch(uint, volvp, argdesc_t *);
|
|
extern int _do_slave_asynch(uint, volvp, argdesc_t *);
|
|
extern int _insert_arg(argdesc_t *, char *, int);
|
|
extern void dump_gpda(int);
|
|
extern void dump_idepda(int);
|
|
extern int setup_idarr(int, int *, int *);
|
|
|
|
#endif /* !_LANGUAGE_ASSEMBLY */
|
|
|
|
/*
|
|
* A non-fault-handling version of _get_gpda macro in genpda.h.
|
|
* This one uses t0 and t1 instead of k0 and k1 to compute
|
|
* a pointer to the processor's correct (generic) pda, as indexed
|
|
* by virtual id. If expanded for Everest systems, it requires
|
|
* that the ss_to_vid array be initialized.
|
|
* Ends up with the running process's pda in t1.
|
|
* It is used by slave startup code in all three csu.s files
|
|
* (libsk, libsc, and ide) to read and write the initial_sp and
|
|
* fault_sp variables (which previously were in BSS).
|
|
*
|
|
* Some of the things buried in this macro:
|
|
* - pda_t is 512 bytes
|
|
* - ss_to_vid is an array of bytes
|
|
* - (EVEREST only): EV_GET_SPNUM returns a "physical cpuid",
|
|
* a number suitable for use as an index into ss_to_vid.
|
|
* - NOTE THE BDSLOT after the branch!
|
|
*/
|
|
#ifdef IP19
|
|
#define _get_spda \
|
|
/*la t0,isaneverest; \
|
|
lw t1,0(t0); \
|
|
li t0, YES_EVEREST; \
|
|
bne t0,t1,4f; \
|
|
move t0, zero;*/ \
|
|
\
|
|
li t0,EV_SPNUM; \
|
|
ld t0,0(t0); \
|
|
la t1,ss_to_vid; \
|
|
and t0,EV_SPNUM_MASK; \
|
|
addu t1,t0; \
|
|
lb t0,0(t1); \
|
|
sll t0,GENERIC_PDASIZE_2; \
|
|
la t1,gen_pda_tab; \
|
|
4: la t1,gen_pda_tab; \
|
|
addu t1,t0
|
|
#elif EVEREST
|
|
|
|
#define _get_spda \
|
|
/*la t0,isaneverest; \
|
|
lw t1,0(t0); \
|
|
dli t0, YES_EVEREST; \
|
|
bne t0,t1,4f; \
|
|
move t0, zero;*/ \
|
|
\
|
|
dli t0,EV_SPNUM; \
|
|
ld t0,0(t0); \
|
|
dla t1,ss_to_vid; \
|
|
and t0,EV_SPNUM_MASK; \
|
|
addu t1,t0; \
|
|
lb t0,0(t1); \
|
|
sll t0,GENERIC_PDASIZE_2; \
|
|
dla t1,gen_pda_tab; \
|
|
4: dla t1,gen_pda_tab; \
|
|
addu t1,t0
|
|
#else
|
|
#define _get_spda \
|
|
_get_gpda(t1,t0)
|
|
#endif
|
|
|
|
#endif /* __IDE_MP_H__ */
|