📄 kn01.c
字号:
#ifndef lintstatic char *sccsid = "@(#)kn01.c 4.5 (ULTRIX) 1/21/91";#endif lint/************************************************************************ * * * Copyright (c) 1989 by * * Digital Equipment Corporation, Maynard, MA * * All rights reserved. * * * * This software is furnished under a license and may be used and * * copied only in accordance with the terms of such license and * * with the inclusion of the above copyright notice. This * * software or any other copies thereof may not be provided or * * otherwise made available to any other person. No title to and * * ownership of the software is hereby transferred. * * * * This software is derived from software received from the * * University of California, Berkeley, and from Bell * * Laboratories. Use, duplication, or disclosure is subject to * * restrictions under license agreements with University of * * California and with AT&T. * * * * The information in this software is subject to change without * * notice and should not be construed as a commitment by Digital * * Equipment Corporation. * * * * Digital assumes no responsibility for the use or reliability * * of its software on equipment which is not supplied by Digital. * * * ************************************************************************//* * Modification History: kn01.c * * 21-Jan-91 Randall Brown * Modified kn01conf() when probing for the framebuffer device. * The framebuffer address space always responds to a BADADDR(), * therefore the memory needs to be written and then read to * determine if there is a framebuffer present. * * 01-Nov-90 Donald Dutile * Modified isolatepar() to use kseg1 addresses when writing * parity test pattern(s) to suspected bad memory/parity location. * Kseg1 addr used to prevent TLB MOD exception when page being * written to is shared memory (not write enabled in TLB entry). * Using kseg1 works since main memory < 512MB. * * 17-Aug-90 Randall Brown * Changed call to ib_config_dev() to configure "fb" device instead * of "pm" device. * * 30-Apr-90 Randall Brown * Added call to spl_init() to intialize spl function pointers and * the intr() function pointer. * * 29-Mar-90 -- gmm * Removed splhigh() and splx() from kn01memintr(). The routine gets * entered at splmem() anyway. * * 02-Dec-89 -- afd * Set fixtick to the number of microsec's that the clock looses per * second. This is used in hardclock() to fix the time. * * Fix a few bugs in parity error handling. * * 13-Oct-89 gmm * SMP changes - use nofault as a per cpu variable (in cpudata) * * 22-Sept-89 jls * replaced the direct call to siiprobe will a call to ib_config_cont * * 21-Sept-89 burns (merge from ISIS pool) * 12-sep-89 afd * Block network interrupts around lnprobe to avoid a race condition * while we are switching network interrupts from kn01lnstray to netintr. * * Assign clock address in init routine (since 3max shares same clock * routines but at a different address). * * Call cnprobe with the virt address of the dc7085 chip. Again, 3max * shares the same driver but at a different address. * * 14-June-89 afd * Add kn01init routine for splm, intr_vectors, iplmask and hz setup. * Handle Lance "stray" interrupts that occur before lnprobe is done. * (It is a pmax console firmware bug that allows early lance interrupts) * * 27-Apr-89 afd * Change startup msg from "DECStation 3100" to "KN01 processor". * * 18-July-89 afd * Handle Lance "stray" interrupts that occur before lnprobe is done. * (It is a pmax console firmware bug that allows early lance interrupts) * * 14-Jun-89 darrell * Added kn01init() -- called from startup(). * * 27-Apr-89 afd * Change startup msg from "DECStation 3100" to "KN01 processor". * * 07-Apr-89 afd * Created this file which contains routines specific to PMAX * systems (KN01). Much of this code came from autoconf.c & trap.c. */#include "../machine/pte.h"#include "../machine/cpu.h"#include "../h/param.h"#include "../h/systm.h"#include "../h/map.h"#include "../h/buf.h"#include "../h/dk.h"#include "../h/user.h" /* gets time.h and debug.h too */#include "../h/proc.h"#include "../h/vm.h"#include "../h/conf.h"#include "../h/errlog.h"#include "../h/cmap.h"#include "../h/cpudata.h"#include "../machine/fpu.h"#include "../machine/hwconf.h"#include "../machine/reg.h"#include "../machine/mc146818clock.h"#include "../machine/entrypt.h"#include "../../machine/common/cpuconf.h"#define KN01LANCE_ADDR 0x18000000 /* physical addr of lance registers */#define KN01SII_ADDR 0x1a000000 /* physical addr of sii registers */#define KN01CLOCK_ADDR 0x1d000000 /* phys addr of clock chip */#define KN01DC_ADDR 0x1c000000 /* phys addr of dc7085 (dz) */#define KN01FRAME_BUF_ADDR 0x0fc00000 /* phys addr of frame buffer */#define ESRPKT 1#define MEMPKT 2/* * These defines, macros, and variables are for memory parity errors. * Format of "memreg" for logging memory parity errors. */#define SIMMOFF 28#define TYPEOFF 26#define BYTEOFF 25#define DPOFF 24#define TCOUNTOFF 16#define SCOUNTOFF 8#define HCOUNTOFF 0#define MEMREGFMT(simm, type, byte, dp, tcount, scount, hcount) \(simm << SIMMOFF | type << TYPEOFF | byte << BYTEOFF | dp << DPOFF | \tcount << TCOUNTOFF | scount << SCOUNTOFF | hcount << HCOUNTOFF)#define TRANSINTVL (60*15) /* time delta to enable parity log - 15 mins */int kn01transintvl = TRANSINTVL;/* global var so we can change it */int kn01translog = 1; /* is trans logging currently enabled */struct trans_errcnt { /* trans parity errors */ long trans_last; /* time of most recent trans err */ long trans_prev; /* time of previous trans err */} trans_errcnt = { 0, 0 };#define TRANSPAR 0x1#define SOFTPAR 0x2#define HARDPAR 0x3#define MAXSIMM 16int tcount[MAXSIMM]; /* # of transient parity errs per simm*/int scount[MAXSIMM]; /* # of soft errs on each simm */int hcount[MAXSIMM]; /* # of hard errs on each simm */int parityerr = 0; /* flag for parity err isolation */caddr_t vatophys(); /* typedef of functions */unsigned isolatepar();int kn01transenable();extern u_int printstate; /* how to print to the console */extern char *rt_clock_addr; /* addr of the mc146818clock chip */extern struct timeval time; /* the system time */extern int hz;extern int tick;extern int tickadj;extern int fixtick; /* set to the number of microsec's that the clock looses per second *//* * Interrupt handlers for the 6 hardware interrupts and 2 software * interrupts for PMAX. */extern softclock(),softnet(),biointr(),netintr(),Xdcintr0(), hardclock(), fpuintr(),memintr();kn01lnstray();/* The routines that correspond to each of the 8 interrupt lines */int (*kn01intr_vec[IPLSIZE])() = { softclock, /* softint 1 */ softnet, /* softint 2 */ biointr, /* hardint 1 */ kn01lnstray, /* hardint 2 */ Xdcintr0, /* hardint 3 */ hardclock, /* hardint 4 */ memintr, /* hardint 5 */ fpuintr /* hardint 6 */};/* * The masks to use to look at each of the 8 interrupt lines. * * Due to the different priorities of TTY, BIO and IMP on PMAX from * the norm all are effectivly wired into the same level. */int kn01iplmask[IPLSIZE] = { SR_IMASK1|SR_IEC, SR_IMASK2|SR_IEC, SR_IMASK5|SR_IEC, /* wire BIO, IMP and TTY to same level */ SR_IMASK5|SR_IEC, /* wire BIO, IMP and TTY to same level */ SR_IMASK5|SR_IEC, /* wire BIO, IMP and TTY to same level */ SR_IMASK6|SR_IEC, SR_IMASK7|SR_IEC, SR_IMASK8|SR_IEC};/* * The SR reg masks for splxxx usage. See the defines in cpu.h. */int kn01splm[SPLMSIZE] = { SR_IEC | SR_IMASK0, /* 0 SPLNONE */ SR_IEC | SR_IMASK1, /* 1 SPLSOFTC */ SR_IEC | SR_IMASK2, /* 2 SPLNET */ 0, /* 3 NOT_USED */ 0, /* 4 NOT_USED */ SR_IEC | SR_IMASK5, /* 5 SPLBIO, SPLIMP, SPLTTY */ SR_IEC | SR_IMASK6, /* 6 SPLCLOCK */ SR_IEC | SR_IMASK7, /* 7 SPLMEM */ SR_IEC | SR_IMASK8, /* 8 SPLFPU */};/* * Configuration routine for kn01 processor (pmax). */kn01conf(){ extern int cold; extern unsigned cpu_systype; extern int cpu; /* Ultrix internal System type */ cold = 1; /* * Initialize PROM environment entries. */ hwconf_init(); /* * Report what system we are on */ printf("KN01 processor - system rev %d\n", (GETHRDREV(cpu_systype))); coproc_find(); /* * Safe to take interrupts now. */ splnone(); config_delay(); kn01config_devices(); timeout (kn01transenable, (caddr_t) 0, kn01transintvl * hz); cold = 0; return(0);}/* * Initialization routine for kn01 processor (pmax). */kn01init(){ extern int c0vec_tblsize; extern int (*c0vec_tbl[])(); extern int iplmask[]; extern int splm[]; extern struct cpusw *cpup; /* * Initialize the interrupt dispatch table c0vec_tbl. * Initialize the spl table for the system we are running on. * Initialize the interrupt masks for the system we are running on. * This must be done very early on at boot time and must * be done before any interrupt (or spl) is allowed. */ bcopy((int *)kn01intr_vec, c0vec_tbl, c0vec_tblsize); bcopy(kn01iplmask, iplmask, IPLSIZE * sizeof(int)); bcopy(kn01splm, splm, (SPLMSIZE) * sizeof(int)); /* Initialize the spl dispatch table and the intr dispatch routine */ spl_init(); /* * Set up the system specific value for "hz", the number of clock * interrupts per second; and corresponding tick and tickadj values. */ hz = cpup->HZ; tick = 1000000 / hz; tickadj = 240000 / (60 * hz); fixtick = 1000000 - (tick * hz); /* * Assign the rt_clock_addr for this processor */ rt_clock_addr = (char *)PHYS_TO_K1(KN01CLOCK_ADDR); return (0);}/* * Handle stray interrupts that occur before the lance is probed & attached. * This only occurs if the console doesn't initialize the lance properly. the lance properly. */#define LN_CSR0 0x0000 /* CSR 0 */#define LN_STOP 0x0004 /* Reset firmware (stop) */kn01lnstray(){ volatile unsigned short *addr; /* 16 bit lance registers */ addr = (volatile unsigned short *)PHYS_TO_K1(KN01LANCE_ADDR); *addr = LN_CSR0; /* * The lance registers are long word alligned, so increment by 2 shorts */ addr += 2; *addr = LN_STOP; return;}/* * Strategy here is to probe all I/O chips/controllers in one place * and set the appropriate states/flags for further use. */kn01config_devices() { extern int cnprobe(); extern int pmprobe(); extern int lnprobe(); int s; config_set_alive("ibus",0,0,0); /* * Probe the system console subsystem; * set the printstate flag to CONSPRINT if successful. */ if (ib_config_dev(PHYS_TO_K1(KN01DC_ADDR), KN01DC_ADDR, 0, "dc", 0)) { printstate = printstate | CONSPRINT; } /* * Probe the frame buffer graphics driver; * both color and mono bitmaps use the same driver */ if (kn01_fb_probe()) ib_config_dev(PHYS_TO_K1(KN01FRAME_BUF_ADDR), KN01FRAME_BUF_ADDR, 0, "fb", 0); /* * Probe the sii based scsi bus. */ ib_config_cont(PHYS_TO_K1(KN01SII_ADDR),KN01SII_ADDR,0,"sii",0); /* * Config the Lance. * Note: We must block Lance interrupts until after the lnprobe * is done and interrupts are vectored to the "netintr" routine. * Otherwise there is a race condition: when lnprobe turns the * Lance on, the first interrupt could go to kn01lnstray and * turn the lance off! */ s = splimp(); config_set_alive("ibus",0,0,0); if (ib_config_dev(PHYS_TO_K1(KN01LANCE_ADDR),KN01LANCE_ADDR,0,"ln",0)) c0vec_tbl[3] = netintr; else printf("ln0 not probed\n"); splx(s); return(0);}kn01_fb_probe(){ u_char *addr, *addr1; /* if MONO bit is clear a color SIMM is definitely installed */ /* in the slot */ /* if MONO bit is set we need to probe frame buffer to determine */ /* if there is an actual SIMM in the slot */ if ((*((short *) PM_CSR_ADDR) & PM_CSR_MONO) == 0) return (1); /* Use addresses that are not in the visible region of the frame */ /* buffer memory. We need to write and read two addresses so */ /* we are not caught by any logic on the board that may return */ /* the byte just written */ addr = (u_char *)(PHYS_TO_K1(KN01FRAME_BUF_ADDR + 0x36100)); addr1 = (u_char *)((int)addr + 0x88); *addr = 0xaa; *addr1 = 0x55; if ((*addr == 0xaa) && (*addr1 == 0x55)) return (1); return (0);}/* * pmax delay routine. */int delay_mult = 8; /* multiplier for DELAY (optimized) */kn01delay(n) int n;{ register int N = delay_mult*(n); while (--N > 0); return(0);}/* * Enable transient parity memory error logging */kn01transenable(){ kn01translog = 1; timeout (kn01transenable, (caddr_t) 0, kn01transintvl * hz);}/* * Routine to handle trap errors: user-mode ibe & dbe, & all kernel mode traps. * We try to recover from user-mode errors and panic on kernel mode errors. */kn01trap_error(ep, code, sr, cause, signo) register u_int *ep; /* exception frame ptr */ register u_int code; /* trap code (trap type) */ u_int sr, cause; /* status and cause regs */ int *signo; /* set if we want to kill process */{ caddr_t pa; /* the physical addr of the error */ int epc; /* the EPC of the error */ unsigned memreg; /* memory parity error info */ int vaddr; /* virt addr of error */ register struct proc *p; /* ptr to current proc struct */ long currtime; /* current time value */ p = u.u_procp; if (USERMODE(sr)) { /* * If address of bus error is in physical memory, then its * a parity memory error. Gather additional info in "memreg", * for the error log & to determine how to recover. * If its a transient error then continue the user process. * If its a hard or soft parity error: * a) on a private process page, terminate the process * (by setting signo = SIGBUS) * b) on a shared page, crash the system. * TBD: on a non-modified page, re-read the page (page fault), * and continue the process. * TBD: on a shared page terminate all proc's sharing the page, * instead of crash system. * TBD: on hard errors map out the page. */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -