/* * Copyright (c) 1988 University of Utah. * Copyright (c) 1992, 1993 * The Regents of the University of California. All rights reserved. * * This code is derived from software contributed to Berkeley by * the Systems Programming Group of the University of Utah Computer * Science Department, The Mach Operating System project at * Carnegie-Mellon University and Ralph Campbell. * * %sccs.include.redist.c% * * @(#)machdep.c 8.1 (Berkeley) 06/16/93 */ /* from: Utah $Hdr: machdep.c 1.63 91/04/24$ */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef SYSVSHM #include #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #if NDC > 0 extern int dcGetc(), dcparam(); extern void dcPutc(); #endif #if NDTOP > 0 extern int dtopKBDGetc(); #endif #if NSCC > 0 extern int sccGetc(), sccparam(); extern void sccPutc(); #endif extern int KBDGetc(); extern void fbPutc(); extern struct consdev cn_tab; /* Will scan from max to min, inclusive */ static int tc_max_slot = KN02_TC_MAX; static int tc_min_slot = KN02_TC_MIN; static u_int tc_slot_phys_base [TC_MAX_SLOTS] = { /* use 3max for default values */ KN02_PHYS_TC_0_START, KN02_PHYS_TC_1_START, KN02_PHYS_TC_2_START, KN02_PHYS_TC_3_START, KN02_PHYS_TC_4_START, KN02_PHYS_TC_5_START, KN02_PHYS_TC_6_START, KN02_PHYS_TC_7_START }; /* the following is used externally (sysctl_hw) */ char machine[] = "DEC"; /* cpu "architecture" */ char cpu_model[30]; vm_map_t buffer_map; /* * Declare these as initialized data so we can patch them. */ int nswbuf = 0; #ifdef NBUF int nbuf = NBUF; #else int nbuf = 0; #endif #ifdef BUFPAGES int bufpages = BUFPAGES; #else int bufpages = 0; #endif int msgbufmapped = 0; /* set when safe to use msgbuf */ int maxmem; /* max memory per process */ int physmem; /* max supported memory, changes to actual */ int pmax_boardtype; /* Mother board type */ u_long le_iomem; /* 128K for lance chip via. ASIC */ u_long asc_iomem; /* and 7 * 8K buffers for the scsi */ u_long asic_base; /* Base address of I/O asic */ const struct callback *callv; /* pointer to PROM entry points */ void (*tc_enable_interrupt)(); extern int (*pmax_hardware_intr)(); void pmax_slot_hand_fill(); int kn02_intr(), kmin_intr(), xine_intr(), pmax_intr(); #ifdef DS5000_240 int kn03_intr(); #endif extern int Mach_spl0(), Mach_spl1(), Mach_spl2(), Mach_spl3(), splhigh(); int (*Mach_splnet)() = splhigh; int (*Mach_splbio)() = splhigh; int (*Mach_splimp)() = splhigh; int (*Mach_spltty)() = splhigh; int (*Mach_splclock)() = splhigh; int (*Mach_splstatclock)() = splhigh; void (*tc_slot_hand_fill)(); extern volatile struct chiptime *Mach_clock_addr; u_long kmin_tc3_imask, xine_tc3_imask; #ifdef DS5000_240 u_long kn03_tc3_imask; #endif tc_option_t tc_slot_info[TC_MAX_LOGICAL_SLOTS]; static void asic_init(); extern void RemconsInit(); #ifdef DS5000 void kn02_enable_intr(), kn02_slot_hand_fill(), kmin_enable_intr(), kmin_slot_hand_fill(), xine_enable_intr(), xine_slot_hand_fill(), tc_find_all_options(); #ifdef DS5000_240 void kn03_enable_intr(), kn03_slot_hand_fill(); #endif #endif /* DS5000 */ /* * safepri is a safe priority for sleep to set for a spin-wait * during autoconfiguration or after a panic. */ int safepri = PSL_LOWIPL; struct user *proc0paddr; struct proc nullproc; /* for use by swtch_exit() */ /* * Do all the stuff that locore normally does before calling main(). * Process arguments passed to us by the prom monitor. * Return the first page address following the system. */ mach_init(argc, argv, code, cv) int argc; char *argv[]; u_int code; const struct callback *cv; { register char *cp; register int i; register unsigned firstaddr; register caddr_t v; caddr_t start; extern char edata[], end[]; extern char MachUTLBMiss[], MachUTLBMissEnd[]; extern char MachException[], MachExceptionEnd[]; /* clear the BSS segment */ v = (caddr_t)pmax_round_page(end); bzero(edata, v - edata); /* check for direct boot from DS5000 PROM */ if (argc > 0 && strcmp(argv[0], "boot") == 0) { argc--; argv++; } /* look at argv[0] and compute bootdev */ makebootdev(argv[0]); /* * Look at arguments passed to us and compute boothowto. */ #ifdef GENERIC boothowto = RB_SINGLE | RB_ASKNAME; #else boothowto = RB_SINGLE; #endif #ifdef KADB boothowto |= RB_KDB; #endif if (argc > 1) { for (i = 1; i < argc; i++) { for (cp = argv[i]; *cp; cp++) { switch (*cp) { case 'a': /* autoboot */ boothowto &= ~RB_SINGLE; break; case 'd': /* use compiled in default root */ boothowto |= RB_DFLTROOT; break; case 'm': /* mini root present in memory */ boothowto |= RB_MINIROOT; break; case 'n': /* ask for names */ boothowto |= RB_ASKNAME; break; case 'N': /* don't ask for names */ boothowto &= ~RB_ASKNAME; } } } } #ifdef MFS /* * Check to see if a mini-root was loaded into memory. It resides * at the start of the next page just after the end of BSS. */ if (boothowto & RB_MINIROOT) { boothowto |= RB_DFLTROOT; v += mfs_initminiroot(v); } #endif /* * Init mapping for u page(s) for proc[0], pm_tlbpid 1. */ start = v; curproc->p_addr = proc0paddr = (struct user *)v; curproc->p_md.md_regs = proc0paddr->u_pcb.pcb_regs; firstaddr = MACH_CACHED_TO_PHYS(v); for (i = 0; i < UPAGES; i++) { MachTLBWriteIndexed(i, (UADDR + (i << PGSHIFT)) | (1 << VMMACH_TLB_PID_SHIFT), curproc->p_md.md_upte[i] = firstaddr | PG_V | PG_M); firstaddr += NBPG; } v += UPAGES * NBPG; MachSetPID(1); /* * init nullproc for swtch_exit(). * init mapping for u page(s), pm_tlbpid 0 * This could be used for an idle process. */ nullproc.p_addr = (struct user *)v; nullproc.p_md.md_regs = nullproc.p_addr->u_pcb.pcb_regs; bcopy("nullproc", nullproc.p_comm, sizeof("nullproc")); for (i = 0; i < UPAGES; i++) { nullproc.p_md.md_upte[i] = firstaddr | PG_V | PG_M; firstaddr += NBPG; } v += UPAGES * NBPG; /* clear pages for u areas */ bzero(start, v - start); /* * Copy down exception vector code. */ if (MachUTLBMissEnd - MachUTLBMiss > 0x80) panic("startup: UTLB code too large"); bcopy(MachUTLBMiss, (char *)MACH_UTLB_MISS_EXC_VEC, MachUTLBMissEnd - MachUTLBMiss); bcopy(MachException, (char *)MACH_GEN_EXC_VEC, MachExceptionEnd - MachException); /* * Clear out the I and D caches. */ MachConfigCache(); MachFlushCache(); /* * Determine what model of computer we are running on. */ if (code == DEC_PROM_MAGIC) { callv = cv; i = (*cv->getsysid)(); cp = ""; } else { callv = &callvec; if (cp = (*callv->getenv)("systype")) i = atoi(cp); else { cp = ""; i = 0; } } /* check for MIPS based platform */ if (((i >> 24) & 0xFF) != 0x82) { printf("Unknown System type '%s' 0x%x\n", cp, i); boot(RB_HALT | RB_NOSYNC); } /* check what model platform we are running on */ pmax_boardtype = ((i >> 16) & 0xff); switch (pmax_boardtype) { case DS_PMAX: /* DS3100 Pmax */ /* * Set up interrupt handling and I/O addresses. */ pmax_hardware_intr = pmax_intr; Mach_splnet = Mach_spl1; Mach_splbio = Mach_spl0; Mach_splimp = Mach_spl1; Mach_spltty = Mach_spl2; Mach_splclock = Mach_spl3; Mach_splstatclock = Mach_spl3; Mach_clock_addr = (volatile struct chiptime *) MACH_PHYS_TO_UNCACHED(KN01_SYS_CLOCK); pmax_slot_hand_fill(); strcpy(cpu_model, "3100"); break; #ifdef DS5000 case DS_3MAX: /* DS5000/200 3max */ { volatile int *csr_addr = (volatile int *)MACH_PHYS_TO_UNCACHED(KN02_SYS_CSR); /* disable all TURBOchannel interrupts */ i = *csr_addr; *csr_addr = i & ~(KN02_CSR_WRESERVED | 0xFF); tc_slot_hand_fill = kn02_slot_hand_fill; pmax_hardware_intr = kn02_intr; tc_enable_interrupt = kn02_enable_intr; Mach_splnet = Mach_spl0; Mach_splbio = Mach_spl0; Mach_splimp = Mach_spl0; Mach_spltty = Mach_spl0; Mach_splclock = Mach_spl1; Mach_splstatclock = Mach_spl1; Mach_clock_addr = (volatile struct chiptime *) MACH_PHYS_TO_UNCACHED(KN02_SYS_CLOCK); /* * Probe the TURBOchannel to see what controllers are present. */ tc_find_all_options(); /* clear any memory errors from probes */ *(unsigned *)MACH_PHYS_TO_UNCACHED(KN02_SYS_ERRADR) = 0; } strcpy(cpu_model, "5000/200"); break; case DS_3MIN: /* DS5000/1xx 3min */ tc_max_slot = KMIN_TC_MAX; tc_min_slot = KMIN_TC_MIN; tc_slot_phys_base[0] = KMIN_PHYS_TC_0_START; tc_slot_phys_base[1] = KMIN_PHYS_TC_1_START; tc_slot_phys_base[2] = KMIN_PHYS_TC_2_START; asic_base = MACH_PHYS_TO_UNCACHED(KMIN_SYS_ASIC); tc_slot_hand_fill = kmin_slot_hand_fill; pmax_hardware_intr = kmin_intr; tc_enable_interrupt = kmin_enable_intr; kmin_tc3_imask = (KMIN_INTR_CLOCK | KMIN_INTR_PSWARN | KMIN_INTR_TIMEOUT); /* * Since all the motherboard interrupts come through the * I/O ASIC, it has to be turned off for all the spls and * since we don't know what kinds of devices are in the * turbochannel option slots, just splhigh(). */ Mach_splnet = splhigh; Mach_splbio = splhigh; Mach_splimp = splhigh; Mach_spltty = splhigh; Mach_splclock = splhigh; Mach_splstatclock = splhigh; Mach_clock_addr = (volatile struct chiptime *) MACH_PHYS_TO_UNCACHED(KMIN_SYS_CLOCK); /* * Probe the TURBOchannel to see what controllers are present. */ tc_find_all_options(); /* * Initialize interrupts. */ *(u_int *)ASIC_REG_IMSK(asic_base) = KMIN_IM0; *(u_int *)ASIC_REG_INTR(asic_base) = 0; /* clear any memory errors from probes */ *(unsigned *)MACH_PHYS_TO_UNCACHED(KMIN_REG_TIMEOUT) = 0; strcpy(cpu_model, "5000/1xx"); break; case DS_MAXINE: /* DS5000/xx maxine */ tc_max_slot = XINE_TC_MAX; tc_min_slot = XINE_TC_MIN; tc_slot_phys_base[0] = XINE_PHYS_TC_0_START; tc_slot_phys_base[1] = XINE_PHYS_TC_1_START; asic_base = MACH_PHYS_TO_UNCACHED(XINE_SYS_ASIC); tc_slot_hand_fill = xine_slot_hand_fill; pmax_hardware_intr = xine_intr; tc_enable_interrupt = xine_enable_intr; Mach_splnet = Mach_spl3; Mach_splbio = Mach_spl3; Mach_splimp = Mach_spl3; Mach_spltty = Mach_spl3; Mach_splclock = Mach_spl1; Mach_splstatclock = Mach_spl1; Mach_clock_addr = (volatile struct chiptime *) MACH_PHYS_TO_UNCACHED(XINE_SYS_CLOCK); /* * Probe the TURBOchannel to see what controllers are present. */ tc_find_all_options(); /* * Initialize interrupts. */ *(u_int *)ASIC_REG_IMSK(asic_base) = XINE_IM0; *(u_int *)ASIC_REG_INTR(asic_base) = 0; /* clear any memory errors from probes */ *(unsigned *)MACH_PHYS_TO_UNCACHED(XINE_REG_TIMEOUT) = 0; strcpy(cpu_model, "5000/25"); break; #ifdef DS5000_240 case DS_3MAXPLUS: /* DS5000/240 3max+ UNTESTED!! */ tc_max_slot = KN03_TC_MAX; tc_min_slot = KN03_TC_MIN; tc_slot_phys_base[0] = KN03_PHYS_TC_0_START; tc_slot_phys_base[1] = KN03_PHYS_TC_1_START; tc_slot_phys_base[2] = KN03_PHYS_TC_2_START; asic_base = MACH_PHYS_TO_UNCACHED(KN03_SYS_ASIC); tc_slot_hand_fill = kn03_slot_hand_fill; pmax_hardware_intr = kn03_intr; tc_enable_interrupt = kn03_enable_intr; kn03_tc3_imask = KN03_INTR_PSWARN; Mach_splnet = Mach_spl0; Mach_splbio = Mach_spl0; Mach_splimp = Mach_spl0; Mach_spltty = Mach_spl0; Mach_splclock = Mach_spl1; Mach_splstatclock = Mach_spl1; Mach_clock_addr = (volatile struct chiptime *) MACH_PHYS_TO_UNCACHED(KN03_SYS_CLOCK); /* * Probe the TURBOchannel to see what controllers are present. */ tc_find_all_options(); /* * Initialize interrupts. */ *(u_int *)ASIC_REG_IMSK(asic_base) = KN03_IM0; *(u_int *)ASIC_REG_INTR(asic_base) = 0; /* clear any memory errors from probes */ *(unsigned *)MACH_PHYS_TO_UNCACHED(KN03_SYS_ERRADR) = 0; strcpy(cpu_model, "5000/240"); break; #endif /* DS5000_240 */ #endif /* DS5000 */ default: printf("kernel not configured for systype 0x%x\n", i); boot(RB_HALT | RB_NOSYNC); } /* * Find out how much memory is available. */ physmem = btoc(v - KERNBASE); cp = (char *)MACH_PHYS_TO_UNCACHED(physmem << PGSHIFT); while (cp < (char *)MACH_MAX_MEM_ADDR) { if (badaddr(cp, 4)) break; *(int *)cp = 0xa5a5a5a5; /* * Data will persist on the bus if we read it right * away. Have to be tricky here. */ ((int *)cp)[4] = 0x5a5a5a5a; MachEmptyWriteBuffer(); if (*(int *)cp != 0xa5a5a5a5) break; cp += NBPG; physmem++; } maxmem = physmem; #if NLE > 0 /* * Grab 128K at the top of physical memory for the lance chip * on machines where it does dma through the I/O ASIC. * It must be physically contiguous and aligned on a 128K boundary. */ if (pmax_boardtype == DS_3MIN || pmax_boardtype == DS_MAXINE || pmax_boardtype == DS_3MAXPLUS) { maxmem -= btoc(128 * 1024); le_iomem = (maxmem << PGSHIFT); } #endif /* NLE */ #if NASC > 0 /* * Ditto for the scsi chip. There is probably a way to make asc.c * do dma without these buffers, but it would require major * re-engineering of the asc driver. * They must be 8K in size and page aligned. */ if (pmax_boardtype == DS_3MIN || pmax_boardtype == DS_MAXINE || pmax_boardtype == DS_3MAXPLUS) { maxmem -= btoc(ASC_NCMD * 8192); asc_iomem = (maxmem << PGSHIFT); } #endif /* NASC */ /* * Initialize error message buffer (at end of core). */ maxmem -= btoc(sizeof (struct msgbuf)); msgbufp = (struct msgbuf *)(MACH_PHYS_TO_CACHED(maxmem << PGSHIFT)); msgbufmapped = 1; /* * Allocate space for system data structures. * The first available kernel virtual address is in "v". * As pages of kernel virtual memory are allocated, "v" is incremented. * * These data structures are allocated here instead of cpu_startup() * because physical memory is directly addressable. We don't have * to map these into virtual address space. */ start = v; #define valloc(name, type, num) \ (name) = (type *)v; v = (caddr_t)((name)+(num)) #define valloclim(name, type, num, lim) \ (name) = (type *)v; v = (caddr_t)((lim) = ((name)+(num))) valloc(cfree, struct cblock, nclist); valloc(callout, struct callout, ncallout); valloc(swapmap, struct map, nswapmap = maxproc * 2); #ifdef SYSVSHM valloc(shmsegs, struct shmid_ds, shminfo.shmmni); #endif /* * Determine how many buffers to allocate. * We allocate more buffer space than the BSD standard of * using 10% of memory for the first 2 Meg, 5% of remaining. * We just allocate a flat 10%. Insure a minimum of 16 buffers. * We allocate 1/2 as many swap buffer headers as file i/o buffers. */ if (bufpages == 0) bufpages = physmem / 10 / CLSIZE; if (nbuf == 0) { nbuf = bufpages; if (nbuf < 16) nbuf = 16; } if (nswbuf == 0) { nswbuf = (nbuf / 2) &~ 1; /* force even */ if (nswbuf > 256) nswbuf = 256; /* sanity */ } valloc(swbuf, struct buf, nswbuf); valloc(buf, struct buf, nbuf); /* * Clear allocated memory. */ bzero(start, v - start); /* * Initialize the virtual memory system. */ pmap_bootstrap((vm_offset_t)v); } /* * Console initialization: called early on from main, * before vm init or startup. Do enough configuration * to choose and initialize a console. */ consinit() { register int kbd, crt; register char *oscon; /* * First get the "osconsole" environment variable. */ oscon = (*callv->getenv)("osconsole"); crt = kbd = -1; if (oscon && *oscon >= '0' && *oscon <= '9') { kbd = *oscon - '0'; cn_tab.cn_screen = 0; while (*++oscon) { if (*oscon == ',') cn_tab.cn_screen = 1; else if (cn_tab.cn_screen && *oscon >= '0' && *oscon <= '9') { crt = kbd; kbd = *oscon - '0'; break; } } } if (pmax_boardtype == DS_PMAX && kbd == 1) cn_tab.cn_screen = 1; /* * The boot program uses PMAX ROM entrypoints so the ROM sets * osconsole to '1' like the PMAX. */ if (pmax_boardtype == DS_3MAX && crt == -1 && kbd == 1) { cn_tab.cn_screen = 1; crt = 0; kbd = 7; } /* * First try the keyboard/crt cases then fall through to the * remote serial lines. */ if (cn_tab.cn_screen) { switch (pmax_boardtype) { case DS_PMAX: #if NDC > 0 && NPM > 0 if (pminit()) { cn_tab.cn_dev = makedev(DCDEV, DCKBD_PORT); cn_tab.cn_getc = KBDGetc; cn_tab.cn_kbdgetc = dcGetc; cn_tab.cn_putc = fbPutc; cn_tab.cn_disabled = 0; return; } #endif /* NDC and NPM */ goto remcons; case DS_MAXINE: #if NDTOP > 0 if (kbd == 3) { cn_tab.cn_dev = makedev(DTOPDEV, 0); cn_tab.cn_getc = dtopKBDGetc; cn_tab.cn_putc = fbPutc; } else #endif /* NDTOP */ goto remcons; #if NXCFB > 0 if (crt == 3 && xcfbinit()) { cn_tab.cn_disabled = 0; return; } #endif /* XCFB */ break; case DS_3MAX: #if NDC > 0 if (kbd == 7) { cn_tab.cn_dev = makedev(DCDEV, DCKBD_PORT); cn_tab.cn_getc = KBDGetc; cn_tab.cn_kbdgetc = dcGetc; cn_tab.cn_putc = fbPutc; } else #endif /* NDC */ goto remcons; break; case DS_3MIN: case DS_3MAXPLUS: #if NSCC > 0 if (kbd == 3) { cn_tab.cn_dev = makedev(SCCDEV, SCCKBD_PORT); cn_tab.cn_getc = KBDGetc; cn_tab.cn_kbdgetc = sccGetc; cn_tab.cn_putc = fbPutc; } else #endif /* NSCC */ goto remcons; break; default: goto remcons; }; /* * Check for a suitable turbochannel frame buffer. */ if (tc_slot_info[crt].driver_name) { #if NMFB > 0 if (strcmp(tc_slot_info[crt].driver_name, "mfb") == 0 && mfbinit(tc_slot_info[crt].k1seg_address)) { cn_tab.cn_disabled = 0; return; } #endif /* NMFB */ #if NCFB > 0 if (strcmp(tc_slot_info[crt].driver_name, "cfb") == 0 && cfbinit(tc_slot_info[crt].k1seg_address)) { cn_tab.cn_disabled = 0; return; } #endif /* NCFB */ printf("crt: %s not supported as console device\n", tc_slot_info[crt].driver_name); } else printf("No crt console device in slot %d\n", crt); } remcons: /* * Configure a serial port as a remote console. */ cn_tab.cn_screen = 0; switch (pmax_boardtype) { case DS_PMAX: #if NDC > 0 if (kbd == 4) cn_tab.cn_dev = makedev(DCDEV, DCCOMM_PORT); else cn_tab.cn_dev = makedev(DCDEV, DCPRINTER_PORT); cn_tab.cn_getc = dcGetc; cn_tab.cn_putc = dcPutc; #endif /* NDC */ break; case DS_3MAX: #if NDC > 0 cn_tab.cn_dev = makedev(DCDEV, DCPRINTER_PORT); cn_tab.cn_getc = dcGetc; cn_tab.cn_putc = dcPutc; #endif /* NDC */ break; case DS_3MIN: case DS_3MAXPLUS: #if NSCC > 0 cn_tab.cn_dev = makedev(SCCDEV, SCCCOMM3_PORT); cn_tab.cn_getc = sccGetc; cn_tab.cn_putc = sccPutc; #endif /* NSCC */ break; case DS_MAXINE: #if NSCC > 0 cn_tab.cn_dev = makedev(SCCDEV, SCCCOMM2_PORT); cn_tab.cn_getc = sccGetc; cn_tab.cn_putc = sccPutc; #endif /* NSCC */ break; }; if (cn_tab.cn_dev == NODEV) printf("Can't configure console!\n"); } /* * cpu_startup: allocate memory for variable-sized tables, * initialize cpu, and do autoconfiguration. */ cpu_startup() { register unsigned i; register caddr_t v; int base, residual; vm_offset_t minaddr, maxaddr; vm_size_t size; #ifdef DEBUG extern int pmapdebug; int opmapdebug = pmapdebug; pmapdebug = 0; #endif /* * Good {morning,afternoon,evening,night}. */ printf(version); printf("real mem = %d\n", ctob(physmem)); /* * Allocate virtual address space for file I/O buffers. * Note they are different than the array of headers, 'buf', * and usually occupy more virtual memory than physical. */ size = MAXBSIZE * nbuf; buffer_map = kmem_suballoc(kernel_map, (vm_offset_t *)&buffers, &maxaddr, size, FALSE); minaddr = (vm_offset_t)buffers; if (vm_map_find(buffer_map, vm_object_allocate(size), (vm_offset_t)0, &minaddr, size, FALSE) != KERN_SUCCESS) panic("startup: cannot allocate buffers"); base = bufpages / nbuf; residual = bufpages % nbuf; for (i = 0; i < nbuf; i++) { vm_size_t curbufsize; vm_offset_t curbuf; /* * First buffers get (base+1) physical pages * allocated for them. The rest get (base) physical pages. * * The rest of each buffer occupies virtual space, * but has no physical memory allocated for it. */ curbuf = (vm_offset_t)buffers + i * MAXBSIZE; curbufsize = CLBYTES * (i < residual ? base+1 : base); vm_map_pageable(buffer_map, curbuf, curbuf+curbufsize, FALSE); vm_map_simplify(buffer_map, curbuf); } /* * Allocate a submap for exec arguments. This map effectively * limits the number of processes exec'ing at any time. */ exec_map = kmem_suballoc(kernel_map, &minaddr, &maxaddr, 16 * NCARGS, TRUE); /* * Allocate a submap for physio */ phys_map = kmem_suballoc(kernel_map, &minaddr, &maxaddr, VM_PHYS_SIZE, TRUE); /* * Finally, allocate mbuf pool. Since mclrefcnt is an off-size * we use the more space efficient malloc in place of kmem_alloc. */ mclrefcnt = (char *)malloc(NMBCLUSTERS+CLBYTES/MCLBYTES, M_MBUF, M_NOWAIT); bzero(mclrefcnt, NMBCLUSTERS+CLBYTES/MCLBYTES); mb_map = kmem_suballoc(kernel_map, (vm_offset_t *)&mbutl, &maxaddr, VM_MBUF_SIZE, FALSE); /* * Initialize callouts */ callfree = callout; for (i = 1; i < ncallout; i++) callout[i-1].c_next = &callout[i]; callout[i-1].c_next = NULL; #ifdef DEBUG pmapdebug = opmapdebug; #endif printf("avail mem = %d\n", ptoa(cnt.v_free_count)); printf("using %d buffers containing %d bytes of memory\n", nbuf, bufpages * CLBYTES); /* * Set up CPU-specific registers, cache, etc. */ initcpu(); /* * Set up buffers, so they can be used to read disk labels. */ bufinit(); /* * Configure the system. */ configure(); } /* * machine dependent system variables. */ cpu_sysctl(name, namelen, oldp, oldlenp, newp, newlen, p) int *name; u_int namelen; void *oldp; size_t *oldlenp; void *newp; size_t newlen; struct proc *p; { /* all sysctl names at this level are terminal */ if (namelen != 1) return (ENOTDIR); /* overloaded */ switch (name[0]) { case CPU_CONSDEV: return (sysctl_rdstruct(oldp, oldlenp, newp, &cn_tab.cn_dev, sizeof cn_tab.cn_dev)); default: return (EOPNOTSUPP); } /* NOTREACHED */ } /* * Set registers on exec. * Clear all registers except sp, pc. */ setregs(p, entry, retval) register struct proc *p; u_long entry; int retval[2]; { int sp = p->p_md.md_regs[SP]; extern struct proc *machFPCurProcPtr; bzero((caddr_t)p->p_md.md_regs, (FSR + 1) * sizeof(int)); p->p_md.md_regs[SP] = sp; p->p_md.md_regs[PC] = entry & ~3; p->p_md.md_regs[PS] = PSL_USERSET; p->p_md.md_flags & ~MDP_FPUSED; if (machFPCurProcPtr == p) machFPCurProcPtr = (struct proc *)0; } /* * WARNING: code in locore.s assumes the layout shown for sf_signum * thru sf_handler so... don't screw with them! */ struct sigframe { int sf_signum; /* signo for handler */ int sf_code; /* additional info for handler */ struct sigcontext *sf_scp; /* context ptr for handler */ sig_t sf_handler; /* handler addr for u_sigc */ struct sigcontext sf_sc; /* actual context */ }; #ifdef DEBUG int sigdebug = 0; int sigpid = 0; #define SDB_FOLLOW 0x01 #define SDB_KSTACK 0x02 #define SDB_FPSTATE 0x04 #endif /* * Send an interrupt to process. */ void sendsig(catcher, sig, mask, code) sig_t catcher; int sig, mask; unsigned code; { register struct proc *p = curproc; register struct sigframe *fp; register int *regs; register struct sigacts *psp = p->p_sigacts; int oonstack, fsize; struct sigcontext ksc; extern char sigcode[], esigcode[]; regs = p->p_md.md_regs; oonstack = psp->ps_sigstk.ss_flags & SA_ONSTACK; /* * Allocate and validate space for the signal handler * context. Note that if the stack is in data space, the * call to grow() is a nop, and the copyout() * will fail if the process has not already allocated * the space with a `brk'. */ fsize = sizeof(struct sigframe); if ((psp->ps_flags & SAS_ALTSTACK) && (psp->ps_sigstk.ss_flags & SA_ONSTACK) == 0 && (psp->ps_sigonstack & sigmask(sig))) { fp = (struct sigframe *)(psp->ps_sigstk.ss_base + psp->ps_sigstk.ss_size - fsize); psp->ps_sigstk.ss_flags |= SA_ONSTACK; } else fp = (struct sigframe *)(regs[SP] - fsize); if ((unsigned)fp <= USRSTACK - ctob(p->p_vmspace->vm_ssize)) (void)grow(p, (unsigned)fp); #ifdef DEBUG if ((sigdebug & SDB_FOLLOW) || (sigdebug & SDB_KSTACK) && p->p_pid == sigpid) printf("sendsig(%d): sig %d ssp %x usp %x scp %x\n", p->p_pid, sig, &oonstack, fp, &fp->sf_sc); #endif /* * Build the signal context to be used by sigreturn. */ ksc.sc_onstack = oonstack; ksc.sc_mask = mask; ksc.sc_pc = regs[PC]; ksc.sc_regs[ZERO] = 0xACEDBADE; /* magic number */ bcopy((caddr_t)®s[1], (caddr_t)&ksc.sc_regs[1], sizeof(ksc.sc_regs) - sizeof(int)); ksc.sc_fpused = p->p_md.md_flags & MDP_FPUSED; if (ksc.sc_fpused) { extern struct proc *machFPCurProcPtr; /* if FPU has current state, save it first */ if (p == machFPCurProcPtr) MachSaveCurFPState(p); bcopy((caddr_t)&p->p_md.md_regs[F0], (caddr_t)ksc.sc_fpregs, sizeof(ksc.sc_fpregs)); } if (copyout((caddr_t)&ksc, (caddr_t)&fp->sf_sc, sizeof(ksc))) { /* * Process has trashed its stack; give it an illegal * instruction to halt it in its tracks. */ SIGACTION(p, SIGILL) = SIG_DFL; sig = sigmask(SIGILL); p->p_sigignore &= ~sig; p->p_sigcatch &= ~sig; p->p_sigmask &= ~sig; psignal(p, SIGILL); return; } /* * Build the argument list for the signal handler. */ regs[A0] = sig; regs[A1] = code; regs[A2] = (int)&fp->sf_sc; regs[A3] = (int)catcher; regs[PC] = (int)catcher; regs[SP] = (int)fp; /* * Signal trampoline code is at base of user stack. */ regs[RA] = (int)PS_STRINGS - (esigcode - sigcode); #ifdef DEBUG if ((sigdebug & SDB_FOLLOW) || (sigdebug & SDB_KSTACK) && p->p_pid == sigpid) printf("sendsig(%d): sig %d returns\n", p->p_pid, sig); #endif } /* * System call to cleanup state after a signal * has been taken. Reset signal mask and * stack state from context left by sendsig (above). * Return to previous pc and psl as specified by * context left by sendsig. Check carefully to * make sure that the user has not modified the * psl to gain improper priviledges or to cause * a machine fault. */ struct sigreturn_args { struct sigcontext *sigcntxp; }; /* ARGSUSED */ sigreturn(p, uap, retval) struct proc *p; struct sigreturn_args *uap; int *retval; { register struct sigcontext *scp; register int *regs; struct sigcontext ksc; int error; scp = uap->sigcntxp; #ifdef DEBUG if (sigdebug & SDB_FOLLOW) printf("sigreturn: pid %d, scp %x\n", p->p_pid, scp); #endif regs = p->p_md.md_regs; /* * Test and fetch the context structure. * We grab it all at once for speed. */ error = copyin((caddr_t)scp, (caddr_t)&ksc, sizeof(ksc)); if (error || ksc.sc_regs[ZERO] != 0xACEDBADE) { #ifdef DEBUG if (!(sigdebug & SDB_FOLLOW)) printf("sigreturn: pid %d, scp %x\n", p->p_pid, scp); printf(" old sp %x ra %x pc %x\n", regs[SP], regs[RA], regs[PC]); printf(" new sp %x ra %x pc %x err %d z %x\n", ksc.sc_regs[SP], ksc.sc_regs[RA], ksc.sc_regs[PC], error, ksc.sc_regs[ZERO]); #endif return (EINVAL); } scp = &ksc; /* * Restore the user supplied information */ if (scp->sc_onstack & 01) p->p_sigacts->ps_sigstk.ss_flags |= SA_ONSTACK; else p->p_sigacts->ps_sigstk.ss_flags &= ~SA_ONSTACK; p->p_sigmask = scp->sc_mask &~ sigcantmask; regs[PC] = scp->sc_pc; bcopy((caddr_t)&scp->sc_regs[1], (caddr_t)®s[1], sizeof(scp->sc_regs) - sizeof(int)); if (scp->sc_fpused) bcopy((caddr_t)scp->sc_fpregs, (caddr_t)&p->p_md.md_regs[F0], sizeof(scp->sc_fpregs)); return (EJUSTRETURN); } int waittime = -1; boot(howto) register int howto; { /* take a snap shot before clobbering any registers */ if (curproc) savectx(curproc->p_addr, 0); #ifdef DEBUG if (panicstr) stacktrace(); #endif boothowto = howto; if ((howto & RB_NOSYNC) == 0 && waittime < 0) { register struct buf *bp; int iter, nbusy; waittime = 0; (void) spl0(); printf("syncing disks... "); /* * Release vnodes held by texts before sync. */ if (panicstr == 0) vnode_pager_umount(NULL); #ifdef notdef #include "fd.h" #if NFD > 0 fdshutdown(); #endif #endif sync(&proc0, (void *)NULL, (int *)NULL); for (iter = 0; iter < 20; iter++) { nbusy = 0; for (bp = &buf[nbuf]; --bp >= buf; ) if ((bp->b_flags & (B_BUSY|B_INVAL)) == B_BUSY) nbusy++; if (nbusy == 0) break; printf("%d ", nbusy); DELAY(40000 * iter); } if (nbusy) printf("giving up\n"); else printf("done\n"); /* * If we've been adjusting the clock, the todr * will be out of synch; adjust it now. */ resettodr(); } (void) splhigh(); /* extreme priority */ if (callv != &callvec) { if (howto & RB_HALT) (*callv->rex)('h'); else { if (howto & RB_DUMP) dumpsys(); (*callv->rex)('b'); } } else if (howto & RB_HALT) { volatile void (*f)() = (volatile void (*)())DEC_PROM_REINIT; (*f)(); /* jump back to prom monitor */ } else { volatile void (*f)() = (volatile void (*)())DEC_PROM_AUTOBOOT; if (howto & RB_DUMP) dumpsys(); (*f)(); /* jump back to prom monitor and do 'auto' cmd */ } /*NOTREACHED*/ } int dumpmag = (int)0x8fca0101; /* magic number for savecore */ int dumpsize = 0; /* also for savecore */ long dumplo = 0; dumpconf() { int nblks; dumpsize = physmem; if (dumpdev != NODEV && bdevsw[major(dumpdev)].d_psize) { nblks = (*bdevsw[major(dumpdev)].d_psize)(dumpdev); if (dumpsize > btoc(dbtob(nblks - dumplo))) dumpsize = btoc(dbtob(nblks - dumplo)); else if (dumplo == 0) dumplo = nblks - btodb(ctob(physmem)); } /* * Don't dump on the first CLBYTES (why CLBYTES?) * in case the dump device includes a disk label. */ if (dumplo < btodb(CLBYTES)) dumplo = btodb(CLBYTES); } /* * Doadump comes here after turning off memory management and * getting on the dump stack, either when called above, or by * the auto-restart code. */ dumpsys() { int error; msgbufmapped = 0; if (dumpdev == NODEV) return; /* * For dumps during autoconfiguration, * if dump device has already configured... */ if (dumpsize == 0) dumpconf(); if (dumplo < 0) return; printf("\ndumping to dev %x, offset %d\n", dumpdev, dumplo); printf("dump "); switch (error = (*bdevsw[major(dumpdev)].d_dump)(dumpdev)) { case ENXIO: printf("device bad\n"); break; case EFAULT: printf("device not ready\n"); break; case EINVAL: printf("area improper\n"); break; case EIO: printf("i/o error\n"); break; default: printf("error %d\n", error); break; case 0: printf("succeeded\n"); } } /* * Return the best possible estimate of the time in the timeval * to which tvp points. Unfortunately, we can't read the hardware registers. * We guarantee that the time will be greater than the value obtained by a * previous call. */ microtime(tvp) register struct timeval *tvp; { int s = splclock(); static struct timeval lasttime; *tvp = time; #ifdef notdef tvp->tv_usec += clkread(); while (tvp->tv_usec > 1000000) { tvp->tv_sec++; tvp->tv_usec -= 1000000; } #endif if (tvp->tv_sec == lasttime.tv_sec && tvp->tv_usec <= lasttime.tv_usec && (tvp->tv_usec = lasttime.tv_usec + 1) > 1000000) { tvp->tv_sec++; tvp->tv_usec -= 1000000; } lasttime = *tvp; splx(s); } initcpu() { register volatile struct chiptime *c; int i; /* disable clock interrupts (until startrtclock()) */ c = Mach_clock_addr; c->regb = REGB_DATA_MODE | REGB_HOURS_FORMAT; i = c->regc; spl0(); /* safe to turn interrupts on now */ return (i); } /* * Convert an ASCII string into an integer. */ int atoi(s) char *s; { int c; unsigned base = 10, d; int neg = 0, val = 0; if (s == 0 || (c = *s++) == 0) goto out; /* skip spaces if any */ while (c == ' ' || c == '\t') c = *s++; /* parse sign, allow more than one (compat) */ while (c == '-') { neg = !neg; c = *s++; } /* parse base specification, if any */ if (c == '0') { c = *s++; switch (c) { case 'X': case 'x': base = 16; break; case 'B': case 'b': base = 2; break; default: base = 8; } } /* parse number proper */ for (;;) { if (c >= '0' && c <= '9') d = c - '0'; else if (c >= 'a' && c <= 'z') d = c - 'a' + 10; else if (c >= 'A' && c <= 'Z') d = c - 'A' + 10; else break; val *= base; val += d; c = *s++; } if (neg) val = -val; out: return val; } /* * Fill in the pmax addresses by hand. */ static struct pmax_address { char *pmax_name; char *pmax_addr; int pmax_pri; } pmax_addresses[] = { { "pm", (char *)MACH_PHYS_TO_CACHED(KN01_PHYS_FBUF_START), 3 }, { "dc", (char *)MACH_PHYS_TO_UNCACHED(KN01_SYS_DZ), 2 }, { "le", (char *)MACH_PHYS_TO_UNCACHED(KN01_SYS_LANCE), 1 }, { "sii",(char *)MACH_PHYS_TO_UNCACHED(KN01_SYS_SII), 0 }, { (char *)0, }, }; void pmax_slot_hand_fill() { register struct pmax_ctlr *cp; register struct driver *drp; register struct pmax_address *pmap; /* * Find the device driver entry and fill in the address. */ for (cp = pmax_cinit; drp = cp->pmax_driver; cp++) { for (pmap = pmax_addresses; pmap->pmax_name; pmap++) { if (strcmp(drp->d_name, pmap->pmax_name)) continue; if (cp->pmax_addr == (char *)QUES) { cp->pmax_addr = pmap->pmax_addr; cp->pmax_pri = pmap->pmax_pri; continue; } } } } #ifdef DS5000 /* * Mach Operating System * Copyright (c) 1991,1990,1989 Carnegie Mellon University * All Rights Reserved. * * Permission to use, copy, modify and distribute this software and its * documentation is hereby granted, provided that both the copyright * notice and this permission notice appear in all copies of the * software, derivative works or modified versions, and any portions * thereof, and that both notices appear in supporting documentation. * * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. * * Carnegie Mellon requests users of this software to return to * * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU * School of Computer Science * Carnegie Mellon University * Pittsburgh PA 15213-3890 * * any improvements or extensions that they make and grant Carnegie the * rights to redistribute these changes. */ /* * Driver map: associates a device driver to an option type. * Drivers name are (arbitrarily) defined in each driver and * used in the various config tables. */ struct drivers_map { char module_name[TC_ROM_LLEN]; /* from ROM, literally! */ char *driver_name; /* in bus_??_init[] tables */ } tc_drivers_map[] = { { "KN02 ", "dc"}, /* (*) 3max system board (with DC) */ { "PMAD-AA ", "le"}, /* Ether */ { "PMAZ-AA ", "asc"}, /* SCSI */ { "PMAG-AA ", "mfb"}, /* Mono Frame Buffer */ { "PMAG-BA ", "cfb"}, /* Color Frame Buffer */ { "PMAG-CA ", "ga"}, /* 2D graphic board */ { "PMAG-DA ", "gq"}, /* 3D graphic board (LM) */ { "PMAG-FA ", "gq"}, /* 3D graphic board (HE) */ { "PMAG-DV ", "xcfb"}, /* (*) maxine Color Frame Buffer */ { "Z8530 ", "scc"}, /* (*) 3min/maxine serial lines */ { "ASIC ", "asic"}, /* (*) 3min/maxine DMA controller */ { "XINE-FDC", "fdc"}, /* (*) maxine floppy controller */ { "DTOP ", "dtop"}, /* (*) maxine desktop bus */ { "AMD79c30", "isdn"}, /* (*) maxine ISDN chip */ { "XINE-FRC", "frc"}, /* (*) maxine free-running counter */ { "", 0} /* list end */ }; /* * Identify an option on the TC. Looks at the mandatory * info in the option's ROM and checks it. */ #ifdef DEBUG int tc_verbose = 0; #endif static int tc_identify_option(addr, slot, complain) tc_rommap_t *addr; tc_option_t *slot; int complain; { register int i; unsigned char width; char firmwr[TC_ROM_LLEN+1], vendor[TC_ROM_LLEN+1], module[TC_ROM_LLEN+1], host_type[TC_ROM_SLEN+1]; /* * We do not really use the 'width' info, but take advantage * of the restriction that the spec impose on the portion * of the ROM that maps between +0x3e0 and +0x470, which * is the only piece we need to look at. */ width = addr->rom_width.value; switch (width) { case 1: case 2: case 4: break; default: #ifdef DEBUG if (tc_verbose && complain) printf("%s (x%x) at x%x\n", "Invalid ROM width", width, addr); #endif return (0); } if (addr->rom_stride.value != 4) { #ifdef DEBUG if (tc_verbose && complain) printf("%s (x%x) at x%x\n", "Invalid ROM stride", addr->rom_stride.value, addr); #endif return (0); } if ((addr->test_data[0] != 0x55) || (addr->test_data[4] != 0x00) || (addr->test_data[8] != 0xaa) || (addr->test_data[12] != 0xff)) { #ifdef DEBUG if (tc_verbose && complain) printf("%s x%x\n", "Test pattern failed, option at", addr); #endif return (0); } for (i = 0; i < TC_ROM_LLEN; i++) { firmwr[i] = addr->firmware_rev[i].value; vendor[i] = addr->vendor_name[i].value; module[i] = addr->module_name[i].value; if (i >= TC_ROM_SLEN) continue; host_type[i] = addr->host_firmware_type[i].value; } firmwr[TC_ROM_LLEN] = vendor[TC_ROM_LLEN] = module[TC_ROM_LLEN] = host_type[TC_ROM_SLEN] = '\0'; #ifdef DEBUG if (tc_verbose) printf("%s %s '%s' at 0x%x\n %s %s %s '%s'\n %s %d %s %d %s\n", "Found a", vendor, module, addr, "Firmware rev.", firmwr, "diagnostics for a", host_type, "ROM size is", addr->rom_size.value << 3, "Kbytes, uses", addr->slot_size.value, "TC slot(s)"); #endif bcopy(module, slot->module_name, TC_ROM_LLEN); bcopy(vendor, slot->module_id, TC_ROM_LLEN); bcopy(firmwr, &slot->module_id[TC_ROM_LLEN], TC_ROM_LLEN); slot->slot_size = addr->slot_size.value; slot->rom_width = width; return (1); } /* * TURBOchannel autoconf procedure. Finds in one sweep what is * hanging on the bus and fills in the tc_slot_info array. * This is only the first part of the autoconf scheme, at this * time we are basically only looking for a graphics board to * use as system console (all workstations). */ void tc_find_all_options() { register int i; u_long addr; int found; register tc_option_t *sl; struct drivers_map *map; register struct pmax_ctlr *cp; register struct driver *drp; /* * Take a look at the bus */ bzero(tc_slot_info, sizeof(tc_slot_info)); for (i = tc_max_slot; i >= tc_min_slot;) { addr = MACH_PHYS_TO_UNCACHED(tc_slot_phys_base[i]); found = tc_probe_slot(addr, &tc_slot_info[i]); if (found) { /* * Found a slot, make a note of it */ tc_slot_info[i].present = 1; tc_slot_info[i].k1seg_address = addr; } i -= tc_slot_info[i].slot_size; } /* * Some slots (e.g. the system slot on 3max) might require * hand-filling. If so, do it now. */ if (tc_slot_hand_fill) (*tc_slot_hand_fill) (tc_slot_info); /* * Now for each alive slot see if we have a device driver that * handles it. This is done in "priority order", meaning that * always present devices are at higher slot numbers on all * current TC machines, and option slots are at lowest numbers. */ for (i = TC_MAX_LOGICAL_SLOTS - 1; i >= 0; i--) { sl = &tc_slot_info[i]; if (!sl->present) continue; found = FALSE; for (map = tc_drivers_map; map->driver_name; map++) { if (bcmp(sl->module_name, map->module_name, TC_ROM_LLEN)) continue; sl->driver_name = map->driver_name; found = TRUE; break; } if (!found) { printf("%s %s %s\n", "Cannot associate a device driver to", sl->module_name, ". Will (try to) ignore it."); sl->present = 0; continue; } /* * Find the device driver entry and fill in the address. */ for (cp = pmax_cinit; drp = cp->pmax_driver; cp++) { if (strcmp(drp->d_name, map->driver_name)) continue; if (cp->pmax_alive) continue; if (cp->pmax_addr == (char *)QUES) { cp->pmax_addr = (char *)sl->k1seg_address; cp->pmax_pri = i; /* * Only enable interrupts if there is an * interrupt handler for it. (e.g., PMAG-BA * can't disable the vertical retrace interrupt * and we might want to ignore it). */ if (drp->d_intr) (*tc_enable_interrupt)(i, 1); cp->pmax_alive = 1; break; } if (cp->pmax_addr != (char *)sl->k1seg_address) { cp->pmax_addr = (char *)QUES; printf("%s: device not at configued address (expected at %x, found at %x)\n", drp->d_name, cp->pmax_addr, sl->k1seg_address); } } } } /* * Probe a slot in the TURBOchannel. Return TRUE if a valid option * is present, FALSE otherwise. A side-effect is to fill the slot * descriptor with the size of the option, whether it is * recognized or not. */ int tc_probe_slot(addr, slot) caddr_t addr; tc_option_t *slot; { int i; static unsigned tc_offset_rom[] = { TC_OFF_PROTO_ROM, TC_OFF_ROM }; #define TC_N_OFFSETS sizeof(tc_offset_rom)/sizeof(unsigned) slot->slot_size = 1; for (i = 0; i < TC_N_OFFSETS; i++) { if (badaddr(addr + tc_offset_rom[i], 4)) continue; /* complain only on last chance */ if (tc_identify_option((tc_rommap_t *)(addr + tc_offset_rom[i]), slot, i == (TC_N_OFFSETS-1))) return (1); } return (0); #undef TC_N_OFFSETS } /* * Enable/Disable interrupts for a TURBOchannel slot. */ void kn02_enable_intr(slotno, on) register int slotno; int on; { register volatile int *p_csr = (volatile int *)MACH_PHYS_TO_UNCACHED(KN02_SYS_CSR); int csr; int s; slotno = 1 << (slotno + KN02_CSR_IOINTEN_SHIFT); s = Mach_spl0(); csr = *p_csr & ~(KN02_CSR_WRESERVED | 0xFF); if (on) *p_csr = csr | slotno; else *p_csr = csr & ~slotno; splx(s); } /* * Object: * kmin_enable_intr EXPORTED function * * Enable/Disable interrupts from a TURBOchannel slot. * * We pretend we actually have 8 slots even if we really have * only 4: TCslots 0-2 maps to slots 0-2, TCslot3 maps to * slots 3-7 (see kmin_slot_hand_fill). */ void kmin_enable_intr(slotno, on) register unsigned int slotno; int on; { register unsigned mask; switch (slotno) { case 0: case 1: case 2: return; case KMIN_SCSI_SLOT: mask = (KMIN_INTR_SCSI | KMIN_INTR_SCSI_PTR_LOAD | KMIN_INTR_SCSI_OVRUN | KMIN_INTR_SCSI_READ_E); break; case KMIN_LANCE_SLOT: mask = KMIN_INTR_LANCE; break; case KMIN_SCC0_SLOT: mask = KMIN_INTR_SCC_0; break; case KMIN_SCC1_SLOT: mask = KMIN_INTR_SCC_1; break; case KMIN_ASIC_SLOT: mask = KMIN_INTR_ASIC; break; default: return; } if (on) kmin_tc3_imask |= mask; else kmin_tc3_imask &= ~mask; } /* * Object: * xine_enable_intr EXPORTED function * * Enable/Disable interrupts from a TURBOchannel slot. * * We pretend we actually have 11 slots even if we really have * only 3: TCslots 0-1 maps to slots 0-1, TCslot 2 is used for * the system (TCslot3), TCslot3 maps to slots 3-10 * (see xine_slot_hand_fill). * Note that all these interrupts come in via the IMR. */ void xine_enable_intr(slotno, on) register unsigned int slotno; int on; { register unsigned mask; switch (slotno) { case 0: /* a real slot, but */ mask = XINE_INTR_TC_0; break; case 1: /* a real slot, but */ mask = XINE_INTR_TC_1; break; case XINE_FLOPPY_SLOT: mask = XINE_INTR_FLOPPY; break; case XINE_SCSI_SLOT: mask = (XINE_INTR_SCSI | XINE_INTR_SCSI_PTR_LOAD | XINE_INTR_SCSI_OVRUN | XINE_INTR_SCSI_READ_E); break; case XINE_LANCE_SLOT: mask = XINE_INTR_LANCE; break; case XINE_SCC0_SLOT: mask = XINE_INTR_SCC_0; break; case XINE_DTOP_SLOT: mask = XINE_INTR_DTOP_RX; break; case XINE_ISDN_SLOT: mask = XINE_INTR_ISDN; break; case XINE_ASIC_SLOT: mask = XINE_INTR_ASIC; break; default: return;/* ignore */ } if (on) xine_tc3_imask |= mask; else xine_tc3_imask &= ~mask; } #ifdef DS5000_240 /* * UNTESTED!! * Object: * kn03_enable_intr EXPORTED function * * Enable/Disable interrupts from a TURBOchannel slot. * * We pretend we actually have 8 slots even if we really have * only 4: TCslots 0-2 maps to slots 0-2, TCslot3 maps to * slots 3-7 (see kn03_slot_hand_fill). */ void kn03_enable_intr(slotno, on) register unsigned int slotno; int on; { register unsigned mask; switch (slotno) { case 0: mask = KN03_INTR_TC_0; break; case 1: mask = KN03_INTR_TC_1; break; case 2: mask = KN03_INTR_TC_2; break; case KN03_SCSI_SLOT: mask = (KN03_INTR_SCSI | KN03_INTR_SCSI_PTR_LOAD | KN03_INTR_SCSI_OVRUN | KN03_INTR_SCSI_READ_E); break; case KN03_LANCE_SLOT: mask = KN03_INTR_LANCE; break; case KN03_SCC0_SLOT: mask = KN03_INTR_SCC_0; break; case KN03_SCC1_SLOT: mask = KN03_INTR_SCC_1; break; case KN03_ASIC_SLOT: mask = KN03_INTR_ASIC; break; default: return; } if (on) kn03_tc3_imask |= mask; else kn03_tc3_imask &= ~mask; } #endif /* DS5000_240 */ /* * Object: * kn02_slot_hand_fill EXPORTED function * * Fill in by hand the info for TC slots that are non-standard. * This is basically just the system slot on a 3max, it does not * look to me like it follows the TC rules although some of the * required info is indeed there. * */ void kn02_slot_hand_fill(slot) tc_option_t *slot; { slot[7].present = 1; slot[7].slot_size = 1; slot[7].rom_width = 1; #if unsafe bcopy(0xbffc0410, slot[7].module_name, TC_ROM_LLEN+1); #endif bcopy("KN02 ", slot[7].module_name, TC_ROM_LLEN+1); bcopy("DEC xxxx", slot[7].module_id, TC_ROM_LLEN+1); slot[7].k1seg_address = MACH_PHYS_TO_UNCACHED(KN02_SYS_DZ); } /* * Object: * kmin_slot_hand_fill EXPORTED function * * Fill in by hand the info for TC slots that are non-standard. * This is the system slot on a 3min, which we think of as a * set of non-regular size TC slots. * */ void kmin_slot_hand_fill(slot) tc_option_t *slot; { register int i; for (i = KMIN_SCSI_SLOT; i < KMIN_ASIC_SLOT+1; i++) { slot[i].present = 1; slot[i].slot_size = 1; slot[i].rom_width = 1; slot[i].unit = 0; bcopy("DEC KMIN", slot[i].module_id, TC_ROM_LLEN+1); } /* scsi */ bcopy("PMAZ-AA ", slot[KMIN_SCSI_SLOT].module_name, TC_ROM_LLEN+1); slot[KMIN_SCSI_SLOT].k1seg_address = MACH_PHYS_TO_UNCACHED(KMIN_SYS_SCSI); /* lance */ bcopy("PMAD-AA ", slot[KMIN_LANCE_SLOT].module_name, TC_ROM_LLEN+1); slot[KMIN_LANCE_SLOT].k1seg_address = 0; /* scc */ bcopy("Z8530 ", slot[KMIN_SCC0_SLOT].module_name, TC_ROM_LLEN+1); slot[KMIN_SCC0_SLOT].k1seg_address = MACH_PHYS_TO_UNCACHED(KMIN_SYS_SCC_0); slot[KMIN_SCC1_SLOT].unit = 1; bcopy("Z8530 ", slot[KMIN_SCC1_SLOT].module_name, TC_ROM_LLEN+1); slot[KMIN_SCC1_SLOT].k1seg_address = MACH_PHYS_TO_UNCACHED(KMIN_SYS_SCC_1); /* asic */ bcopy("ASIC ", slot[KMIN_ASIC_SLOT].module_name, TC_ROM_LLEN+1); slot[KMIN_ASIC_SLOT].k1seg_address = MACH_PHYS_TO_UNCACHED(KMIN_SYS_ASIC); asic_init(0); } /* * Object: * xine_slot_hand_fill EXPORTED function * * Fill in by hand the info for TC slots that are non-standard. * This is the system slot on a 3min, which we think of as a * set of non-regular size TC slots. * */ void xine_slot_hand_fill(slot) tc_option_t *slot; { register int i; for (i = XINE_FLOPPY_SLOT; i < XINE_FRC_SLOT+1; i++) { slot[i].present = 1; slot[i].slot_size = 1; slot[i].rom_width = 1; slot[i].unit = 0; bcopy("DEC XINE", slot[i].module_id, TC_ROM_LLEN+1); } /* floppy */ bcopy("XINE-FDC", slot[XINE_FLOPPY_SLOT].module_name, TC_ROM_LLEN+1); slot[XINE_FLOPPY_SLOT].k1seg_address = MACH_PHYS_TO_UNCACHED(XINE_SYS_FLOPPY); /* scsi */ bcopy("PMAZ-AA ", slot[XINE_SCSI_SLOT].module_name, TC_ROM_LLEN+1); slot[XINE_SCSI_SLOT].k1seg_address = MACH_PHYS_TO_UNCACHED(XINE_SYS_SCSI); /* lance */ bcopy("PMAD-AA ", slot[XINE_LANCE_SLOT].module_name, TC_ROM_LLEN+1); slot[XINE_LANCE_SLOT].k1seg_address = MACH_PHYS_TO_UNCACHED(XINE_SYS_LANCE); /* scc */ bcopy("Z8530 ", slot[XINE_SCC0_SLOT].module_name, TC_ROM_LLEN+1); slot[XINE_SCC0_SLOT].k1seg_address = MACH_PHYS_TO_UNCACHED(XINE_SYS_SCC_0); /* Desktop */ bcopy("DTOP ", slot[XINE_DTOP_SLOT].module_name, TC_ROM_LLEN+1); slot[XINE_DTOP_SLOT].k1seg_address = MACH_PHYS_TO_UNCACHED(XINE_SYS_DTOP+0x20000); /* why? */ /* ISDN */ bcopy("AMD79c30", slot[XINE_ISDN_SLOT].module_name, TC_ROM_LLEN+1); slot[XINE_ISDN_SLOT].k1seg_address = MACH_PHYS_TO_UNCACHED(XINE_SYS_ISDN); /* Video */ bcopy("PMAG-DV ", slot[XINE_CFB_SLOT].module_name, TC_ROM_LLEN+1); slot[XINE_CFB_SLOT].k1seg_address = MACH_PHYS_TO_CACHED(XINE_PHYS_CFB_START); /* asic */ bcopy("ASIC ", slot[XINE_ASIC_SLOT].module_name, TC_ROM_LLEN+1); slot[XINE_ASIC_SLOT].k1seg_address = MACH_PHYS_TO_UNCACHED(XINE_SYS_ASIC); /* free-running counter (high resolution mapped time) */ bcopy("XINE-FRC", slot[XINE_FRC_SLOT].module_name, TC_ROM_LLEN+1); slot[XINE_FRC_SLOT].k1seg_address = MACH_PHYS_TO_UNCACHED(XINE_REG_FCTR); asic_init(1); } #ifdef DS5000_240 /* * UNTESTED!! * Object: * kn03_slot_hand_fill EXPORTED function * * Fill in by hand the info for TC slots that are non-standard. * This is the system slot on a 3max+, which we think of as a * set of non-regular size TC slots. * */ void kn03_slot_hand_fill(slot) tc_option_t *slot; { register int i; for (i = KN03_SCSI_SLOT; i < KN03_ASIC_SLOT+1; i++) { slot[i].present = 1; slot[i].slot_size = 1; slot[i].rom_width = 1; slot[i].unit = 0; bcopy("DEC KN03", slot[i].module_id, TC_ROM_LLEN+1); } /* scsi */ bcopy("PMAZ-AA ", slot[KN03_SCSI_SLOT].module_name, TC_ROM_LLEN+1); slot[KN03_SCSI_SLOT].k1seg_address = MACH_PHYS_TO_UNCACHED(KN03_SYS_SCSI); /* lance */ bcopy("PMAD-AA ", slot[KN03_LANCE_SLOT].module_name, TC_ROM_LLEN+1); slot[KN03_LANCE_SLOT].k1seg_address = 0; /* scc */ bcopy("Z8530 ", slot[KN03_SCC0_SLOT].module_name, TC_ROM_LLEN+1); slot[KN03_SCC0_SLOT].k1seg_address = MACH_PHYS_TO_UNCACHED(KN03_SYS_SCC_0); slot[KN03_SCC1_SLOT].unit = 1; bcopy("Z8530 ", slot[KN03_SCC1_SLOT].module_name, TC_ROM_LLEN+1); slot[KN03_SCC1_SLOT].k1seg_address = MACH_PHYS_TO_UNCACHED(KN03_SYS_SCC_1); /* asic */ bcopy("ASIC ", slot[KN03_ASIC_SLOT].module_name, TC_ROM_LLEN+1); slot[KN03_ASIC_SLOT].k1seg_address = MACH_PHYS_TO_UNCACHED(KN03_SYS_ASIC); asic_init(0); } #endif /* DS5000_240 */ /* * Initialize the I/O asic */ static void asic_init(isa_maxine) int isa_maxine; { volatile u_int *decoder; /* These are common between 3min and maxine */ decoder = (volatile u_int *)ASIC_REG_LANCE_DECODE(asic_base); *decoder = KMIN_LANCE_CONFIG; } #endif /* DS5000 */