1 /* $NetBSD: mca_machdep.c,v 1.9 2001/05/14 14:14:09 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 /* System Configuration Block - this info is returned by the BIOS call */ 67 struct bios_config { 68 u_int16_t count; 69 u_int8_t model; 70 u_int8_t submodel; 71 u_int8_t bios_rev; 72 u_int8_t feature1; 73 #define FEATURE_MCAISA 0x01 /* Machine contains both MCA and ISA bus */ 74 #define FEATURE_MCABUS 0x02 /* Machine has MCA bus instead of ISA */ 75 #define FEATURE_EBDA 0x04 /* Extended BIOS data area allocated */ 76 #define FEATURE_WAITEV 0x08 /* Wait for external event is supported */ 77 #define FEATURE_KBDINT 0x10 /* Keyboard intercept called by Int 09h */ 78 #define FEATURE_RTC 0x20 /* Real-time clock present */ 79 #define FEATURE_IC2 0x40 /* Second interrupt chip present */ 80 #define FEATURE_DMA3 0x80 /* DMA channel 3 used by hard disk BIOS */ 81 u_int8_t pad[10]; 82 } __attribute__ ((packed)); 83 84 85 struct i386_bus_dma_tag mca_bus_dma_tag = { 86 NULL, /* _cookie */ 87 _bus_dmamap_create, 88 _bus_dmamap_destroy, 89 _bus_dmamap_load, 90 _bus_dmamap_load_mbuf, 91 _bus_dmamap_load_uio, 92 _bus_dmamap_load_raw, 93 _bus_dmamap_unload, 94 NULL, /* _dmamap_sync */ 95 _bus_dmamem_alloc, 96 _bus_dmamem_free, 97 _bus_dmamem_map, 98 _bus_dmamem_unmap, 99 _bus_dmamem_mmap, 100 }; 101 102 /* setup by mca_busprobe() */ 103 int MCA_system = 0; /* Updated in mca_busprobe() if appropriate. */ 104 105 void 106 mca_attach_hook(parent, self, mba) 107 struct device *parent, *self; 108 struct mcabus_attach_args *mba; 109 { 110 /* Nothing */ 111 } 112 113 /* 114 * Read value of MCA POS register "reg" in slot "slot". 115 */ 116 117 int 118 mca_conf_read(mc, slot, reg) 119 mca_chipset_tag_t mc; 120 int slot, reg; 121 { 122 int 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 data = inb(MCA_POS_REG(reg)); 128 outb(MCA_ADAP_SETUP_REG, 0); 129 return data; 130 } 131 132 133 /* 134 * Write "data" to MCA POS register "reg" in slot "slot". 135 */ 136 137 void 138 mca_conf_write(mc, slot, reg, data) 139 mca_chipset_tag_t mc; 140 int slot, reg, data; 141 { 142 slot&=7; /* slot must be in range 0-7 */ 143 outb(MCA_MB_SETUP_REG, 0xff); /* ensure m/board setup is disabled */ 144 outb(MCA_ADAP_SETUP_REG, slot | MCA_ADAP_SET); 145 outb(MCA_POS_REG(reg), data); 146 outb(MCA_ADAP_SETUP_REG, 0); 147 } 148 149 #if NISA <= 0 150 #error mca_intr_(dis)establish: needs ISA to be configured into kernel 151 #endif 152 153 #if 0 154 const struct evcnt * 155 mca_intr_establish(mca_chipset_tag_t mc, mca_intr_handle_t ih) 156 { 157 158 /* XXX for now, no evcnt parent reported */ 159 return NULL; 160 } 161 #endif 162 163 void * 164 mca_intr_establish(mc, ih, level, func, arg) 165 mca_chipset_tag_t mc; 166 mca_intr_handle_t ih; 167 int level, (*func) __P((void *)); 168 void *arg; 169 { 170 if (ih == 0 || ih >= ICU_LEN || ih == 2) 171 panic("mca_intr_establish: bogus handle 0x%x\n", ih); 172 173 /* MCA interrupts are always level-triggered */ 174 return isa_intr_establish(NULL, ih, IST_LEVEL, level, func, arg); 175 } 176 177 void 178 mca_intr_disestablish(mc, cookie) 179 mca_chipset_tag_t mc; 180 void *cookie; 181 { 182 return isa_intr_disestablish(NULL, cookie); 183 } 184 185 186 /* 187 * Handle a NMI. 188 * return true to panic system, false to ignore. 189 */ 190 int 191 mca_nmi() 192 { 193 /* 194 * PS/2 MCA devices can generate NMIs - we can find out which 195 * slot generated it from the POS registers. 196 */ 197 198 int slot, mcanmi=0; 199 200 /* if there is no MCA bus, call isa_nmi() */ 201 if (!MCA_system) 202 goto out; 203 204 /* ensure motherboard setup is disabled */ 205 outb(MCA_MB_SETUP_REG, 0xff); 206 207 /* find if an MCA slot has the CHCK bit asserted (low) in POS 5 */ 208 for(slot=0; slot<MCA_MAX_SLOTS; slot++) 209 { 210 outb(MCA_ADAP_SETUP_REG, slot | MCA_ADAP_SET); 211 if ((inb(MCA_POS_REG(5)) & MCA_POS5_CHCK) == 0) 212 { 213 mcanmi = 1; 214 /* find if CHCK status is available in POS 6/7 */ 215 if((inb(MCA_POS_REG(5)) & MCA_POS5_CHCK_STAT) == 0) 216 log(LOG_CRIT, "MCA NMI: slot %d, POS6=0x%02x, POS7=0x%02x\n", 217 slot+1, inb(MCA_POS_REG(6)), 218 inb(MCA_POS_REG(7))); 219 else 220 log(LOG_CRIT, "MCA NMI: slot %d\n", slot+1); 221 } 222 } 223 outb(MCA_ADAP_SETUP_REG, 0); 224 225 out: 226 #if NISA > 0 227 if (!mcanmi) { 228 /* no CHCK bits asserted, assume ISA NMI */ 229 return (isa_nmi()); 230 } else 231 #endif 232 return(0); 233 } 234 235 /* 236 * We can obtain the information about MCA bus presence via 237 * GET CONFIGURATION BIOS call - int 0x15, function 0xc0. 238 * The call returns a pointer to memory place with the configuration block 239 * in es:bx (on AT-compatible, e.g. all we care about, computers). 240 * 241 * Configuration block contains block length (2 bytes), model 242 * number (1 byte), submodel number (1 byte), BIOS revision 243 * (1 byte) and up to 5 feature bytes. We only care about 244 * first feature byte. 245 */ 246 void 247 mca_busprobe() 248 { 249 struct bioscallregs regs; 250 struct bios_config *scp; 251 paddr_t paddr; 252 char buf[50]; 253 254 memset(®s, 0, sizeof(regs)); 255 regs.AH = 0xc0; 256 bioscall(0x15, ®s); 257 258 if ((regs.EFLAGS & PSL_C) || regs.AH != 0) { 259 #ifdef DEBUG 260 printf("BIOS CFG: Not supported. Not AT-compatible?\n"); 261 #endif 262 return; 263 } 264 265 paddr = (regs.ES << 4) + regs.BX; 266 scp = (struct bios_config *)ISA_HOLE_VADDR(paddr); 267 268 #if 1 /* MCAVERBOSE */ 269 bitmask_snprintf(scp->feature1, 270 "\20" 271 "\01MCA+ISA" 272 "\02MCA" 273 "\03EBDA" 274 "\04WAITEV" 275 "\05KBDINT" 276 "\06RTC" 277 "\07IC2" 278 "\010DMA3B\n", 279 buf, sizeof(buf)); 280 281 printf("BIOS CFG: Model-SubMod-Rev: %02x-%02x-%02x, 0x%s\n", 282 scp->model, scp->submodel, scp->bios_rev, buf); 283 #endif 284 285 MCA_system = (scp->feature1 & FEATURE_MCABUS) ? 1 : 0; 286 } 287 288 #define PORT_DISKLED 0x92 289 #define DISKLED_ON 0x40 290 291 /* 292 * Light disk busy LED on IBM PS/2. 293 */ 294 void 295 mca_disk_busy(void) 296 { 297 outb(PORT_DISKLED, inb(PORT_DISKLED) | DISKLED_ON); 298 } 299 300 /* 301 * Turn off disk LED on IBM PS/2. 302 */ 303 void 304 mca_disk_unbusy(void) 305 { 306 outb(PORT_DISKLED, inb(PORT_DISKLED) & ~DISKLED_ON); 307 } 308