1 /* $NetBSD: mca_machdep.c,v 1.3 2000/07/09 10:35:12 jdolecek Exp $ */ 2 3 /*- 4 * Copyright (c) 2000 The NetBSD Foundation, Inc. 5 * Copyright (c) 1996-1999 Scott D. Telford. 6 * All rights reserved. 7 * 8 * This code is derived from software contributed to The NetBSD Foundation 9 * by Scott Telford <s.telford@ed.ac.uk>. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 3. All advertising materials mentioning features or use of this software 20 * must display the following acknowledgement: 21 * This product includes software developed by the NetBSD 22 * Foundation, Inc. and its contributors. 23 * 4. Neither the name of The NetBSD Foundation nor the names of its 24 * contributors may be used to endorse or promote products derived 25 * from this software without specific prior written permission. 26 * 27 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 28 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 29 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 30 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 31 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 32 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 33 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 34 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 35 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 36 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 37 * POSSIBILITY OF SUCH DAMAGE. 38 */ 39 40 /* 41 * Machine-specific functions for MCA autoconfiguration. 42 */ 43 44 #include <sys/types.h> 45 #include <sys/param.h> 46 #include <sys/time.h> 47 #include <sys/systm.h> 48 #include <sys/device.h> 49 #include <sys/syslog.h> 50 51 #include <machine/bioscall.h> 52 #include <machine/psl.h> 53 54 #define _I386_BUS_DMA_PRIVATE 55 #include <machine/bus.h> 56 57 #include <i386/isa/icu.h> 58 #include <dev/isa/isavar.h> 59 #include <dev/isa/isareg.h> 60 #include <dev/mca/mcavar.h> 61 #include <dev/mca/mcareg.h> 62 63 #include "isa.h" 64 #include "opt_mcaverbose.h" 65 66 struct i386_bus_dma_tag mca_bus_dma_tag = { 67 NULL, /* _cookie */ 68 _bus_dmamap_create, 69 _bus_dmamap_destroy, 70 _bus_dmamap_load, 71 _bus_dmamap_load_mbuf, 72 _bus_dmamap_load_uio, 73 _bus_dmamap_load_raw, 74 _bus_dmamap_unload, 75 NULL, /* _dmamap_sync */ 76 _bus_dmamem_alloc, 77 _bus_dmamem_free, 78 _bus_dmamem_map, 79 _bus_dmamem_unmap, 80 _bus_dmamem_mmap, 81 }; 82 83 /* setup by mca_busprobe() */ 84 int MCA_system = 1; /* XXX force MCA for now */ 85 int bios_features = 1; 86 87 void 88 mca_attach_hook(parent, self, mba) 89 struct device *parent, *self; 90 struct mcabus_attach_args *mba; 91 { 92 /* Nothing */ 93 } 94 95 /* 96 * Read value of MCA POS register "reg" in slot "slot". 97 */ 98 99 int 100 mca_conf_read(mc, slot, reg) 101 mca_chipset_tag_t mc; 102 int slot, reg; 103 { 104 int data; 105 106 slot &= 7; /* slot must be in range 0-7 */ 107 outb(MCA_MB_SETUP_REG, 0xff); /* ensure m/board setup is disabled */ 108 outb(MCA_ADAP_SETUP_REG, slot | MCA_ADAP_SET); 109 data = inb(MCA_POS_REG(reg)); 110 outb(MCA_ADAP_SETUP_REG, 0); 111 return data; 112 } 113 114 115 /* 116 * Write "data" to MCA POS register "reg" in slot "slot". 117 */ 118 119 void 120 mca_conf_write(mc, slot, reg, data) 121 mca_chipset_tag_t mc; 122 int slot, reg, data; 123 { 124 slot&=7; /* slot must be in range 0-7 */ 125 outb(MCA_MB_SETUP_REG, 0xff); /* ensure m/board setup is disabled */ 126 outb(MCA_ADAP_SETUP_REG, slot | MCA_ADAP_SET); 127 outb(MCA_POS_REG(reg), data); 128 outb(MCA_ADAP_SETUP_REG, 0); 129 } 130 131 #if NISA <= 0 132 #error mca_intr_(dis)establish: needs ISA to be configured into kernel 133 #endif 134 135 const struct evcnt * 136 mca_intr_establish(mca_chipset_tag_t mc, mca_intr_handle_t ih) 137 { 138 139 /* XXX for now, no evcnt parent reported */ 140 return NULL; 141 } 142 143 void * 144 mca_intr_establish(mc, ih, level, func, arg) 145 mca_chipset_tag_t mc; 146 mca_intr_handle_t ih; 147 int level, (*func) __P((void *)); 148 void *arg; 149 { 150 if (ih == 0 || ih >= ICU_LEN || ih == 2) 151 panic("mca_intr_establish: bogus handle 0x%x\n", ih); 152 153 /* MCA interrupts are always level-triggered */ 154 return isa_intr_establish(NULL, ih, IST_LEVEL, level, func, arg); 155 } 156 157 void 158 mca_intr_disestablish(mc, cookie) 159 mca_chipset_tag_t mc; 160 void *cookie; 161 { 162 return isa_intr_disestablish(NULL, cookie); 163 } 164 165 166 /* 167 * Handle a NMI. 168 * return true to panic system, false to ignore. 169 */ 170 int 171 mca_nmi() 172 { 173 /* 174 * PS/2 MCA devices can generate NMIs - we can find out which 175 * slot generated it from the POS registers. 176 */ 177 178 int slot, mcanmi=0; 179 180 /* if there is no MCA bus, call isa_nmi() */ 181 if (!MCA_system) 182 goto out; 183 184 /* ensure motherboard setup is disabled */ 185 outb(MCA_MB_SETUP_REG, 0xff); 186 187 /* find if an MCA slot has the CHCK bit asserted (low) in POS 5 */ 188 for(slot=0; slot<MCA_MAX_SLOTS; slot++) 189 { 190 outb(MCA_ADAP_SETUP_REG, slot | MCA_ADAP_SET); 191 if ((inb(MCA_POS_REG(5)) & MCA_POS5_CHCK) == 0) 192 { 193 mcanmi = 1; 194 /* find if CHCK status is available in POS 6/7 */ 195 if((inb(MCA_POS_REG(5)) & MCA_POS5_CHCK_STAT) == 0) 196 log(LOG_CRIT, "MCA NMI: slot %d, POS6=0x%02x, POS7=0x%02x\n", 197 slot+1, inb(MCA_POS_REG(6)), 198 inb(MCA_POS_REG(7))); 199 else 200 log(LOG_CRIT, "MCA NMI: slot %d\n", slot+1); 201 } 202 } 203 outb(MCA_ADAP_SETUP_REG, 0); 204 205 out: 206 #if NISA > 0 207 if (!mcanmi) { 208 /* no CHCK bits asserted, assume ISA NMI */ 209 return (isa_nmi()); 210 } else 211 #endif 212 return(0); 213 } 214 215 void 216 mca_busprobe() 217 { 218 /* According to Linux's linux/arch/i386/boot/setup.S, 219 * we can get the extra BIOS information via int 0x15, 220 * ah == 0xc0. The extra information is stored on 221 * es:bx; it contains two bytes of length, then byte 222 * of machine id, byte of machine submodel, byte of BIOS 223 * revision number and byte of feature info. 224 */ 225 /* 226 * Scott Telford's code used 227 * ((inb(MCA_ADAP_SETUP_REG) & (MCA_ADAP_SET | MCA_ADAP_CHR)) == 0) 228 * - somewhat dubious, but good enough. 229 */ 230 231 #if notyet 232 char buf[10]; 233 234 /* 235 * Following has been taken from FreeBSD, for now just for 236 * documentation purposes 237 */ 238 struct bioscallregs regs; 239 struct sys_config *scp; 240 paddr_t paddr; 241 242 memset(®s, 0, sizeof(regs)); 243 regs.AX_HI = 0xc0; 244 bioscall(0x15, ®s); 245 246 if ((regs.EFLAGS & PSL_C) 247 || (regs.AX_HI != 0 && (regs.FLAGS & PSL_AC))) 248 { 249 #ifdef MCAVERBOSE 250 printf("BIOS SDT: Not supported. Not PS/2?\n"); 251 #endif 252 return; 253 } 254 255 paddr = (regs.ES << 4) + regs.BX; 256 scp = (struct sys_config *)ISA_HOLE_VADDR(paddr); 257 258 printf("BIOS SDT: model 0x%x, submodel 0x%x, BIOS rev. 0x%x\n", 259 scp->model, scp->submodel, scp->bios_rev); 260 261 #ifdef MCAVERBOSE 262 bitmask_snprintf(scp->feature, 263 "\20" 264 "\01RESV" 265 "\02MCABUS" 266 "\03EBDA" 267 "\04WAITEV" 268 "\05KBDINT" 269 "\06RTC" 270 "\07IC2", 271 "\08DMA3\n", 272 buf, sizeof(buf)); 273 printf("BIOS SDT: features 0x%s\n", buf); 274 #endif 275 276 bios_features = scp->feature; 277 MCA_system = (bios_features & FEATURE_MCABUS) ? 1 : 0; 278 #endif /* 0 */ 279 } 280