📄 kn02.c
字号:
* This must be done very early on at boot time and must * be done before any interrupt is allowed. */ bcopy((int *)kn02intr_vec, c0vec_tbl, c0vec_tblsize); bcopy(kn02iplmask, iplmask, IPLSIZE * sizeof(int)); bcopy(kn02splm, 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(KN02CLOCK_ADDR); /* * Clear the memory error counters. */ for (i = 0; i < MEM_MODULES; i++) kn02memerrs[i] = 0; /* Initialize the TURBOchannel */ tc_init(); /* Fill in the TURBOchannel slot addresses */ for (i = 0; i < TC_IOSLOTS; i++) tc_slotaddr[i] = kn02_slotaddr[i]; /* Fill in the TURBOchannel switch table */ tc_sw.enable_option = kn02enable_option; tc_sw.disable_option = kn02disable_option; tc_sw.clear_errors = kn02clear_errors; tc_sw.config_order = kn02config_order; /* * Fixed 3max IO devices (slots 3 & 4 unused) */ tc_slot[3].slot = 3; tc_slot[4].slot = 4; strcpy(tc_slot[5].devname,"asc"); strcpy(tc_slot[5].modulename, "PMAZ-AA "); tc_slot[5].slot = 5; tc_slot[5].module_width = 1; tc_slot[5].physaddr = SLOT_5_ADDR; tc_slot[5].intr_b4_probe = 0; tc_slot[5].intr_aft_attach = 1; tc_slot[5].adpt_config = 0; strcpy(tc_slot[6].devname,"ln"); strcpy(tc_slot[6].modulename, "PMAD-AA "); tc_slot[6].slot = 6; tc_slot[6].module_width = 1; tc_slot[6].physaddr = SLOT_6_ADDR; tc_slot[6].intr_b4_probe = 0; tc_slot[6].intr_aft_attach = 1; tc_slot[6].adpt_config = 0; strcpy(tc_slot[7].devname,"dc"); tc_slot[7].slot = 7; tc_slot[7].module_width = 1; tc_slot[7].physaddr = KN02DC_ADDR; tc_slot[7].intr_b4_probe = 0; tc_slot[7].intr_aft_attach = 1; tc_slot[7].adpt_config = 0; return(0);}/* * Configuration routine for kn02 processor (3max). */kn02conf(){ extern int cold; extern u_int cpu_systype; cold = 1; /* * Initialize PROM environment entries. */ hwconf_init(); /* * Report what system we are on */ printf("KN02 processor - system rev %d\n", (GETHRDREV(cpu_systype))); coproc_find(); /* Turn off all interrupts in the CSR */ *(u_int *)PHYS_TO_K1(KN02CSR_ADDR) &= (~0x00ff0000); wbflush(); /* * Probe the TURBOchannel and find all devices */ tc_find(); timeout (kn02crdenable, (caddr_t) 0, kn02crdintvl * hz); timeout (kn02pscheck, (caddr_t) 0, kn02psintvl * hz); cold = 0; /* * configure nvram option, this enables * Prestoserve if the NVRAM is present. * * This will go out an probe for NVRAM. * */ kn02_config_nvram(); return (0); /* tell configure() we have configured correctly */}/* * kn02clear_errors() * * Clears any pending errors in the error register */kn02clear_errors(){ *(u_int *)PHYS_TO_K1(KN02ERR_ADDR) = 0; wbflush();}/* * kn02enable_option() * * Takes a slot number as an argument. * * This function enables an option's interrupt on the TURBOchannel * to interrupt the system at the I/O interrupt level. * This is done by setting the option's slot number as a valid * interrupt to service. */kn02enable_option(slot) int slot;{ kn02ie_mask |= (1 << slot); *(u_int *)PHYS_TO_K1(KN02CSR_ADDR) |= (1 << slot+KN02IE_OFFSET); wbflush();}/* * kn02disable_option() * * Takes a slot number as an argument. * * This function disables an option's interrupt on the TURBOchannel * to interrupt the system at the I/O interrupt level. * This is done by resetting the option's slot number as a valid * interrupt to service. */ kn02disable_option(slot) int slot;{ kn02ie_mask &= ~(1 << slot); *(u_int *)PHYS_TO_K1(KN02CSR_ADDR) &= ~(1 << slot+KN02IE_OFFSET); wbflush();}/* * 3max halt interrupt routine. * It calls the console PROM halt routine with an address (ep) where it will * start dumping out values & the length to dump (size of exception frame, in * long words). */kn02halt(ep){ extern int rex_base; if(rex_base) rex_halt(ep, EF_SIZE/4); /* TURBOchannel'd 3max ROM callback */ else prom_halt(ep, EF_SIZE/4);}/* * 3max stray interrupt routine. */kn02stray(ep) u_int *ep; /* exception frame ptr */{ printf("Stray interrupt, CAUSE = 0x%x, STATUS = 0x%x\n", ep[EF_CAUSE], ep[EF_SR]);}/* * Check Power Supply over-heat Warning. * If its overheating, warn to shut down the system. * If its gone from overheat to OK, cancel the warning. */kn02pscheck(){ register u_int kn02csr; /* a copy of the real csr */ kn02csr = *(u_int *)PHYS_TO_K1(KN02CSR_ADDR); if (kn02csr & KN02CSR_PSWARN) { printf("System Overheating - suggest immediate shutdown and power-off\n"); kn02pswarn = 1; } else { if (kn02pswarn) { printf("System OK - cancel overheat shutdown\n"); kn02pswarn = 0; } } timeout (kn02pscheck, (caddr_t) 0, kn02psintvl * hz);}/* * Enable CRD (single bit ECC) error logging */kn02crdenable(){ kn02crdlog = 1; timeout (kn02crdenable, (caddr_t) 0, kn02crdintvl * hz);}/* * 3max I/O interrupt routine. * The IOint bits in the CSR tell which slot interrupted. * Look up the slot number in the tc_slot table to determine which * interrupt routine to call. * * Note that more than 1 interrupt bit can be set in the CSR. * Also note that software does not need to clear the IO bits in the CSR, * they are cleared when the Interrupt line is cleared. */kn02iointr(ep) u_int *ep;{ register u_int kn02csr; /* a copy of the real csr */ register int ioint; /* the ioint bits in the CSR */ kn02csr = *(u_int *)PHYS_TO_K1(KN02CSR_ADDR); /* * This is a clever way of making a fast jump table which converts * a bit set in the ioint portion of the kn02 csr to an index into * the tc_slot table. We are handling interrupts, so speed * is of the essence. */ ioint = (kn02csr >> KN02IE_OFFSET) & (kn02csr & 0xff); if (ioint != 0) { /* * Check for bits set in the high nibble */ switch (ioint & 0xf0) { case 0xf0: case 0xe0: case 0xd0: case 0xc0: case 0xb0: case 0xa0: case 0x90: case 0x80: /* * We always handle the serial line ctlr first. * This will give the mouse highest priority. * For debug: pass ep to dcintr() so it can print epc */ (*(tc_slot[7].intr))(tc_slot[7].unit, ep); break; case 0x70: case 0x60: case 0x50: case 0x40: (*(tc_slot[6].intr))(tc_slot[6].unit); break; case 0x30: case 0x20: (*(tc_slot[5].intr))(tc_slot[5].unit); break; /* * slot 4 unused on 3max */ } /* * Check for bits set in the low nibble */ switch (ioint & 0xf) { /* * slot 3 unused on 3max */ case 0x7: case 0x6: case 0x5: case 0x4: (*(tc_slot[2].intr))(tc_slot[2].unit); break; case 0x3: case 0x2: (*(tc_slot[1].intr))(tc_slot[1].unit); break; case 0x1: (*(tc_slot[0].intr))(tc_slot[0].unit); break; } }}/* * 3max delay routine. * Tested from 5 seconds down to 4,000 usecs (4 mSec clock accuracy). */int kn02_delay_mult = 13; /* multiplier for DELAY (optimized) */kn02delay(n) int n;{ register int N = kn02_delay_mult*(n); while (--N > 0); return(0);}/* * Error interrupt. * With buffered writes, these are not reported synchronously, thus * there is no process context to terminate a user process, so we panic. * * Causes: * Memory Errors: * CPU read single bit ECC * DMA read overrun, DMA write overrun * CPU partial memory write ECC, DMA memory read ECC * Timeout Errors: * CPU I/O write timeout */kn02errintr(ep) u_int *ep; /* exception frame ptr */{ register int s; register u_int kn02csr; /* copy of csr reg */ register u_int erradr; /* copy of erradr reg */ register u_int chksyn; /* copy of chksyn reg */ register u_int chksyn_plus; /* valid half of chksyn + errcnt + pc */ int errtype; /* local record of error type */ int pa; /* the physical address of the error */ int module; /* module number with error */ long currtime; /* current time value */ struct kn02consinfo_t *pcons; /* pointer to console info */ struct kn02log_errinfo_t *plog; /* pointer to log info */ kn02csr = *(u_int *)PHYS_TO_K1(KN02CSR_ADDR); erradr = *(u_int *)PHYS_TO_K1(KN02ERR_ADDR); chksyn = *(u_int *)PHYS_TO_K1(KN02CHKSYN_ADDR); if ((erradr & ERR_VALID) && ((erradr & ERR_TYPE) == ERR_RECC) && (((chksyn & CHKSYN_VLDLO) && (chksyn & CHKSYN_SNGLO)) || ((chksyn & CHKSYN_VLDHI) && (chksyn & CHKSYN_SNGHI)))) errtype = ERR_RECC; /* singlebit memory read ECC */ else if ((erradr & ERR_VALID) && ((erradr & ERR_TYPE) == ERR_DMARECC) && ((chksyn & CHKSYN_VLDLO) || (chksyn & CHKSYN_VLDHI))) errtype = ERR_DMARECC; /* DMA memory read ECC */ else if ((erradr & ERR_VALID) && ((erradr & ERR_TYPE) == ERR_WECC) && ((chksyn & CHKSYN_VLDLO) || (chksyn & CHKSYN_VLDHI))) errtype = ERR_WECC; /* CPU partial mem write ECC */ else if ((erradr & ERR_VALID) && ((erradr & ERR_TYPE) == ERR_DMAROVR)) errtype = ERR_DMAROVR; /* DMA read overrun */ else if ((erradr & ERR_VALID) && ((erradr & ERR_TYPE) == ERR_DMAWOVR)) errtype = ERR_DMAWOVR; /* DMA write overrun */ else if ((erradr & ERR_VALID) && ((erradr & ERR_TYPE) == ERR_WTMO)) errtype = ERR_WTMO; /* CPU write timeout */ else errtype = ERR_UKN; switch (errtype) { case ERR_RECC: case ERR_DMARECC: case ERR_WECC: erradr = (erradr & (~ERR_COLADDR)) | (((int)erradr -5) & ERR_COLADDR); pa = (erradr & ERR_ADDR) << 2; if (kn02csr & KN02CSR_BNK32M) module = pa / (32*(1024*1024)); else module = pa / (8*(1024*1024)); if (module >= 0 && module < MEM_MODULES) { kn02memerrs[module]++; if (kn02memerrs[module] > MAXERRCNT) { kn02memerrs[module] = 0; mprintf("Error count on memory module %d reached %d, resetting count to zero.\n", module, MAXERRCNT); } } else module = -1; /* * Build chksyn_plus. */ chksyn_plus = 0; if (chksyn & CHKSYN_VLDLO) { chksyn_plus = (chksyn & CPLUS_CHK); } else chksyn_plus = ((chksyn >> CPLUS_MOFF) & CPLUS_CHK); if (module == -1) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -