1 /* $NetBSD: mca_machdep.c,v 1.14 2001/12/04 20:00:16 sommerfeld Exp $ */ 2 3 /*- 4 * Copyright (c) 2000, 2001 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> and Jaromir Dolecek 10 * <jdolecek@NetBSD.org>. 11 * 12 * Redistribution and use in source and binary forms, with or without 13 * modification, are permitted provided that the following conditions 14 * are met: 15 * 1. Redistributions of source code must retain the above copyright 16 * notice, this list of conditions and the following disclaimer. 17 * 2. Redistributions in binary form must reproduce the above copyright 18 * notice, this list of conditions and the following disclaimer in the 19 * documentation and/or other materials provided with the distribution. 20 * 3. All advertising materials mentioning features or use of this software 21 * must display the following acknowledgement: 22 * This product includes software developed by the NetBSD 23 * Foundation, Inc. and its contributors. 24 * 4. Neither the name of The NetBSD Foundation nor the names of its 25 * contributors may be used to endorse or promote products derived 26 * from this software without specific prior written permission. 27 * 28 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 29 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 30 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 31 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 32 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 33 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 34 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 35 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 36 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 37 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 38 * POSSIBILITY OF SUCH DAMAGE. 39 */ 40 41 /* 42 * Machine-specific functions for MCA autoconfiguration. 43 */ 44 45 #include <sys/cdefs.h> 46 __KERNEL_RCSID(0, "$NetBSD: mca_machdep.c,v 1.14 2001/12/04 20:00:16 sommerfeld Exp $"); 47 48 #include <sys/types.h> 49 #include <sys/param.h> 50 #include <sys/device.h> 51 #include <sys/malloc.h> 52 #include <sys/systm.h> 53 #include <sys/syslog.h> 54 #include <sys/time.h> 55 #include <sys/kernel.h> 56 57 #include <machine/bioscall.h> 58 #include <machine/psl.h> 59 60 #define _I386_BUS_DMA_PRIVATE 61 #include <machine/bus.h> 62 63 #include <i386/isa/icu.h> 64 #include <dev/isa/isavar.h> 65 #include <dev/isa/isareg.h> 66 #include <dev/mca/mcavar.h> 67 #include <dev/mca/mcareg.h> 68 69 #include "isa.h" 70 #include "opt_mcaverbose.h" 71 72 /* System Configuration Block - this info is returned by the BIOS call */ 73 struct bios_config { 74 u_int16_t count; 75 u_int8_t model; 76 u_int8_t submodel; 77 u_int8_t bios_rev; 78 u_int8_t feature1; 79 #define FEATURE_MCAISA 0x01 /* Machine contains both MCA and ISA bus */ 80 #define FEATURE_MCABUS 0x02 /* Machine has MCA bus instead of ISA */ 81 #define FEATURE_EBDA 0x04 /* Extended BIOS data area allocated */ 82 #define FEATURE_WAITEV 0x08 /* Wait for external event is supported */ 83 #define FEATURE_KBDINT 0x10 /* Keyboard intercept called by Int 09h */ 84 #define FEATURE_RTC 0x20 /* Real-time clock present */ 85 #define FEATURE_IC2 0x40 /* Second interrupt chip present */ 86 #define FEATURE_DMA3 0x80 /* DMA channel 3 used by hard disk BIOS */ 87 u_int8_t feature2; 88 u_int8_t pad[9]; 89 } __attribute__ ((packed)); 90 91 /* 92 * Used to encode DMA channel into ISA DMA cookie. We use upper 4 bits of 93 * ISA DMA cookie id_flags, it's unused. 94 */ 95 struct i386_isa_dma_cookie { 96 int id_flags; 97 /* We don't care about rest */ 98 }; 99 100 /* ISA DMA stuff - see i386/isa/isa_machdep.c */ 101 int _isa_bus_dmamap_create __P((bus_dma_tag_t, bus_size_t, int, 102 bus_size_t, bus_size_t, int, bus_dmamap_t *)); 103 void _isa_bus_dmamap_destroy __P((bus_dma_tag_t, bus_dmamap_t)); 104 int _isa_bus_dmamap_load __P((bus_dma_tag_t, bus_dmamap_t, void *, 105 bus_size_t, struct proc *, int)); 106 void _isa_bus_dmamap_unload __P((bus_dma_tag_t, bus_dmamap_t)); 107 void _isa_bus_dmamap_sync __P((bus_dma_tag_t, bus_dmamap_t, 108 bus_addr_t, bus_size_t, int)); 109 110 int _isa_bus_dmamem_alloc __P((bus_dma_tag_t, bus_size_t, bus_size_t, 111 bus_size_t, bus_dma_segment_t *, int, int *, int)); 112 113 static void _mca_bus_dmamap_sync __P((bus_dma_tag_t, bus_dmamap_t, 114 bus_addr_t, bus_size_t, int)); 115 static int _mca_bus_dmamap_load_mbuf __P((bus_dma_tag_t, bus_dmamap_t, 116 struct mbuf *, int)); 117 static int _mca_bus_dmamap_load_uio __P((bus_dma_tag_t, bus_dmamap_t, 118 struct uio *, int)); 119 static int _mca_bus_dmamap_load_raw __P((bus_dma_tag_t, bus_dmamap_t, 120 bus_dma_segment_t *, int, bus_size_t, int)); 121 122 /* 123 * For now, we use MCA DMA to 0-16M always. Some IBM PS/2 have 32bit MCA bus, 124 * but majority of them have 24bit only. 125 */ 126 #define MCA_DMA_BOUNCE_THRESHOLD (16 * 1024 * 1024) 127 128 struct i386_bus_dma_tag mca_bus_dma_tag = { 129 MCA_DMA_BOUNCE_THRESHOLD, /* _bounce_thresh */ 130 _isa_bus_dmamap_create, 131 _isa_bus_dmamap_destroy, 132 _isa_bus_dmamap_load, 133 _mca_bus_dmamap_load_mbuf, 134 _mca_bus_dmamap_load_uio, 135 _mca_bus_dmamap_load_raw, 136 _isa_bus_dmamap_unload, 137 _mca_bus_dmamap_sync, 138 _isa_bus_dmamem_alloc, 139 _bus_dmamem_free, 140 _bus_dmamem_map, 141 _bus_dmamem_unmap, 142 _bus_dmamem_mmap, 143 }; 144 145 /* Updated in mca_busprobe() if appropriate. */ 146 int MCA_system = 0; 147 148 /* Used to kick MCA DMA controller */ 149 #define DMA_CMD 0x18 /* command the controller */ 150 #define DMA_EXEC 0x1A /* tell controller how to do things */ 151 static bus_space_handle_t dmaiot, dmacmdh, dmaexech; 152 153 /* 154 * MCA DMA controller commands. The exact sense of individual bits 155 * are from Tymm Twillman <tymm@computer.org>, who worked on Linux MCA DMA 156 * support. 157 */ 158 #define DMACMD_SET_IO 0x00 /* set port (16bit) for i/o transfer */ 159 #define DMACMD_SET_ADDR 0x20 /* set addr (24bit) for i/o transfer */ 160 #define DMACMD_GET_ADDR 0x30 /* get addr (24bit) for i/o transfer */ 161 #define DMACMD_SET_CNT 0x40 /* set memory size for DMA (16b) */ 162 #define DMACMD_GET_CNT 0x50 /* get count of remaining bytes in DMA*/ 163 #define DMACMD_GET_STATUS 0x60 /* ?? */ 164 #define DMACMD_SET_MODE 0x70 /* set DMA mode */ 165 # define DMACMD_MODE_XFER 0x04 /* do transfer, read by default */ 166 # define DMACMD_MODE_READ 0x08 /* read transfer */ 167 # define DMACMD_MODE_WRITE 0x00 /* write transfer */ 168 # define DMACMD_MODE_IOPORT 0x01 /* DMA from/to IO register */ 169 # define DMACMD_MODE_16BIT 0x40 /* 16bit transfers (default 8bit) */ 170 #define DMACMD_SET_ARBUS 0x80 /* ?? */ 171 #define DMACMD_MASK 0x90 /* command mask */ 172 #define DMACMD_RESET_MASK 0xA0 /* reset */ 173 #define DMACMD_MASTER_CLEAR 0xD0 /* ?? */ 174 175 /* 176 * Map the MCA DMA controller registers. 177 */ 178 void 179 mca_attach_hook(parent, self, mba) 180 struct device *parent, *self; 181 struct mcabus_attach_args *mba; 182 { 183 dmaiot = mba->mba_iot; 184 185 if (bus_space_map(dmaiot, DMA_CMD, 1, 0, &dmacmdh) 186 || bus_space_map(dmaiot, DMA_EXEC, 1, 0, &dmaexech)) 187 panic("%s: couldn't map DMA registers", 188 mba->mba_busname); 189 } 190 191 /* 192 * Read value of MCA POS register "reg" in slot "slot". 193 */ 194 195 int 196 mca_conf_read(mc, slot, reg) 197 mca_chipset_tag_t mc; 198 int slot, reg; 199 { 200 int data; 201 202 slot &= 7; /* slot must be in range 0-7 */ 203 outb(MCA_MB_SETUP_REG, 0xff); /* ensure m/board setup is disabled */ 204 outb(MCA_ADAP_SETUP_REG, slot | MCA_ADAP_SET); 205 data = inb(MCA_POS_REG(reg)); 206 outb(MCA_ADAP_SETUP_REG, 0); 207 return data; 208 } 209 210 211 /* 212 * Write "data" to MCA POS register "reg" in slot "slot". 213 */ 214 215 void 216 mca_conf_write(mc, slot, reg, data) 217 mca_chipset_tag_t mc; 218 int slot, reg, data; 219 { 220 slot&=7; /* slot must be in range 0-7 */ 221 outb(MCA_MB_SETUP_REG, 0xff); /* ensure m/board setup is disabled */ 222 outb(MCA_ADAP_SETUP_REG, slot | MCA_ADAP_SET); 223 outb(MCA_POS_REG(reg), data); 224 outb(MCA_ADAP_SETUP_REG, 0); 225 } 226 227 #if NISA <= 0 228 #error mca_intr_(dis)establish: needs ISA to be configured into kernel 229 #endif 230 231 #if 0 232 const struct evcnt * 233 mca_intr_establish(mca_chipset_tag_t mc, mca_intr_handle_t ih) 234 { 235 236 /* XXX for now, no evcnt parent reported */ 237 return NULL; 238 } 239 #endif 240 241 void * 242 mca_intr_establish(mc, ih, level, func, arg) 243 mca_chipset_tag_t mc; 244 mca_intr_handle_t ih; 245 int level, (*func) __P((void *)); 246 void *arg; 247 { 248 if (ih == 0 || ih >= ICU_LEN || ih == 2) 249 panic("mca_intr_establish: bogus handle 0x%x\n", ih); 250 251 /* MCA interrupts are always level-triggered */ 252 return isa_intr_establish(NULL, ih, IST_LEVEL, level, func, arg); 253 } 254 255 void 256 mca_intr_disestablish(mc, cookie) 257 mca_chipset_tag_t mc; 258 void *cookie; 259 { 260 return isa_intr_disestablish(NULL, cookie); 261 } 262 263 264 /* 265 * Handle a NMI. 266 * return true to panic system, false to ignore. 267 */ 268 int 269 mca_nmi() 270 { 271 /* 272 * PS/2 MCA devices can generate NMIs - we can find out which 273 * slot generated it from the POS registers. 274 */ 275 276 int slot, mcanmi=0; 277 278 /* if there is no MCA bus, call isa_nmi() */ 279 if (!MCA_system) 280 goto out; 281 282 /* ensure motherboard setup is disabled */ 283 outb(MCA_MB_SETUP_REG, 0xff); 284 285 /* find if an MCA slot has the CHCK bit asserted (low) in POS 5 */ 286 for(slot=0; slot<MCA_MAX_SLOTS; slot++) { 287 outb(MCA_ADAP_SETUP_REG, slot | MCA_ADAP_SET); 288 if ((inb(MCA_POS_REG(5)) & MCA_POS5_CHCK) == 0) { 289 mcanmi = 1; 290 /* find if CHCK status is available in POS 6/7 */ 291 if((inb(MCA_POS_REG(5)) & MCA_POS5_CHCK_STAT) == 0) 292 log(LOG_CRIT, "MCA NMI: slot %d, POS6=0x%02x, POS7=0x%02x\n", 293 slot+1, inb(MCA_POS_REG(6)), 294 inb(MCA_POS_REG(7))); 295 else 296 log(LOG_CRIT, "MCA NMI: slot %d\n", slot+1); 297 } 298 } 299 outb(MCA_ADAP_SETUP_REG, 0); 300 301 out: 302 if (!mcanmi) { 303 /* no CHCK bits asserted, assume ISA NMI */ 304 return (isa_nmi()); 305 } else 306 return(0); 307 } 308 309 /* 310 * We can obtain the information about MCA bus presence via 311 * GET CONFIGURATION BIOS call - int 0x15, function 0xc0. 312 * The call returns a pointer to memory place with the configuration block 313 * in es:bx (on AT-compatible, e.g. all we care about, computers). 314 * 315 * Configuration block contains block length (2 bytes), model 316 * number (1 byte), submodel number (1 byte), BIOS revision 317 * (1 byte) and up to 5 feature bytes. We only care about 318 * first feature byte. 319 */ 320 void 321 mca_busprobe() 322 { 323 struct bioscallregs regs; 324 struct bios_config *scp; 325 paddr_t paddr; 326 char buf[50]; 327 328 memset(®s, 0, sizeof(regs)); 329 regs.AH = 0xc0; 330 bioscall(0x15, ®s); 331 332 if ((regs.EFLAGS & PSL_C) || regs.AH != 0) { 333 #ifdef DEBUG 334 printf("BIOS CFG: Not supported. Not AT-compatible?\n"); 335 #endif 336 return; 337 } 338 339 paddr = (regs.ES << 4) + regs.BX; 340 scp = (struct bios_config *)ISA_HOLE_VADDR(paddr); 341 342 #if 1 /* MCAVERBOSE */ 343 bitmask_snprintf(((scp->feature2 & 1)<< 8) | scp->feature1, 344 "\20" 345 "\01MCA+ISA" 346 "\02MCA" 347 "\03EBDA" 348 "\04WAITEV" 349 "\05KBDINT" 350 "\06RTC" 351 "\07IC2" 352 "\010DMA3B" 353 "\011DMA32\n", 354 buf, sizeof(buf)); 355 356 printf("BIOS CFG: Model-SubM-Rev: %02x-%02x-%02x, 0x%s\n", 357 scp->model, scp->submodel, scp->bios_rev, buf); 358 #endif 359 360 MCA_system = (scp->feature1 & FEATURE_MCABUS) ? 1 : 0; 361 } 362 363 #define PORT_DISKLED 0x92 364 #define DISKLED_ON 0x40 365 366 /* 367 * Light disk busy LED on IBM PS/2. 368 */ 369 void 370 mca_disk_busy(void) 371 { 372 outb(PORT_DISKLED, inb(PORT_DISKLED) | DISKLED_ON); 373 } 374 375 /* 376 * Turn off disk LED on IBM PS/2. 377 */ 378 void 379 mca_disk_unbusy(void) 380 { 381 outb(PORT_DISKLED, inb(PORT_DISKLED) & ~DISKLED_ON); 382 } 383 384 /* 385 * -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- 386 * MCA DMA specific stuff. We use ISA routines for bulk of the work, 387 * since MCA shares much of the charasteristics with it. We just hook 388 * the DMA channel initialization and kick MCA DMA controller appropriately. 389 * -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- 390 */ 391 392 /* 393 * Like _mca_bus_dmamap_load(), but for mbufs. 394 */ 395 static int 396 _mca_bus_dmamap_load_mbuf(t, map, m0, flags) 397 bus_dma_tag_t t; 398 bus_dmamap_t map; 399 struct mbuf *m0; 400 int flags; 401 { 402 403 panic("_mca_bus_dmamap_load_mbuf: not implemented"); 404 } 405 406 /* 407 * Like _mca_bus_dmamap_load(), but for uios. 408 */ 409 static int 410 _mca_bus_dmamap_load_uio(t, map, uio, flags) 411 bus_dma_tag_t t; 412 bus_dmamap_t map; 413 struct uio *uio; 414 int flags; 415 { 416 417 panic("_mca_bus_dmamap_load_uio: not implemented"); 418 } 419 420 /* 421 * Like _mca_bus_dmamap_load(), but for raw memory allocated with 422 * bus_dmamem_alloc(). 423 */ 424 static int 425 _mca_bus_dmamap_load_raw(t, map, segs, nsegs, size, flags) 426 bus_dma_tag_t t; 427 bus_dmamap_t map; 428 bus_dma_segment_t *segs; 429 int nsegs; 430 bus_size_t size; 431 int flags; 432 { 433 434 panic("_mca_bus_dmamap_load_raw: not implemented"); 435 } 436 437 /* 438 * Synchronize a MCA DMA map. 439 */ 440 static void 441 _mca_bus_dmamap_sync(t, map, offset, len, ops) 442 bus_dma_tag_t t; 443 bus_dmamap_t map; 444 bus_addr_t offset; 445 bus_size_t len; 446 int ops; 447 { 448 struct i386_isa_dma_cookie *cookie; 449 bus_addr_t phys; 450 bus_size_t cnt; 451 int dmach, mode; 452 453 _isa_bus_dmamap_sync(t, map, offset, len, ops); 454 455 /* 456 * Don't do anything if not using the DMA controller. 457 */ 458 if ((map->_dm_flags & _MCABUS_DMA_USEDMACTRL) == 0) 459 return; 460 461 /* 462 * Don't do anything if not PRE* operation, allow only 463 * one of PREREAD and PREWRITE. 464 */ 465 if (ops != BUS_DMASYNC_PREREAD && ops != BUS_DMASYNC_PREWRITE) 466 return; 467 468 cookie = (struct i386_isa_dma_cookie *)map->_dm_cookie; 469 dmach = (cookie->id_flags & 0xf0) >> 4; 470 471 phys = map->dm_segs[0].ds_addr; 472 cnt = map->dm_segs[0].ds_len; 473 474 mode = DMACMD_MODE_XFER; 475 mode |= (ops == BUS_DMASYNC_PREREAD) 476 ? DMACMD_MODE_READ : DMACMD_MODE_WRITE; 477 if (map->_dm_flags & MCABUS_DMA_IOPORT) 478 mode |= DMACMD_MODE_IOPORT; 479 480 /* Use 16bit DMA if requested */ 481 if (map->_dm_flags & MCABUS_DMA_16BIT) { 482 #ifdef DIAGNOSTIC 483 if ((cnt % 2) != 0) { 484 panic("_mca_bus_dmamap_sync: 16bit DMA and cnt %lu odd", 485 cnt); 486 } 487 #endif 488 mode |= DMACMD_MODE_16BIT; 489 cnt /= 2; 490 } 491 492 /* 493 * Initialize the MCA DMA controller appropriately. The exact 494 * sequence to setup the controller is taken from Minix. 495 */ 496 497 /* Disable access to dma channel. */ 498 bus_space_write_1(dmaiot, dmacmdh, 0, DMACMD_MASK | dmach); 499 500 /* Set the transfer mode. */ 501 bus_space_write_1(dmaiot, dmacmdh, 0, DMACMD_SET_MODE | dmach); 502 bus_space_write_1(dmaiot, dmaexech, 0, mode); 503 504 /* Set the address byte pointer. */ 505 bus_space_write_1(dmaiot, dmacmdh, 0, DMACMD_SET_ADDR | dmach); 506 /* address bits 0..7 */ 507 bus_space_write_1(dmaiot, dmaexech, 0, (phys >> 0) & 0xff); 508 /* address bits 8..15 */ 509 bus_space_write_1(dmaiot, dmaexech, 0, (phys >> 8) & 0xff); 510 /* address bits 16..23 */ 511 bus_space_write_1(dmaiot, dmaexech, 0, (phys >> 16) & 0xff); 512 513 /* Set the count byte pointer */ 514 bus_space_write_1(dmaiot, dmacmdh, 0, DMACMD_SET_CNT | dmach); 515 /* count bits 0..7 */ 516 bus_space_write_1(dmaiot, dmaexech, 0, ((cnt - 1) >> 0) & 0xff); 517 /* count bits 8..15 */ 518 bus_space_write_1(dmaiot, dmaexech, 0, ((cnt - 1) >> 8) & 0xff); 519 520 /* Enable access to dma channel. */ 521 bus_space_write_1(dmaiot, dmacmdh, 0, DMACMD_RESET_MASK | dmach); 522 } 523 524 /* 525 * Allocate a dma map, and set up dma channel. 526 */ 527 int 528 mca_dmamap_create(t, size, flags, dmamp, dmach) 529 bus_dma_tag_t t; 530 bus_size_t size; 531 int flags; 532 bus_dmamap_t *dmamp; 533 int dmach; 534 { 535 int error; 536 struct i386_isa_dma_cookie *cookie; 537 538 #ifdef DEBUG 539 /* Sanity check */ 540 if (dmach < 0 || dmach >= 16) { 541 printf("mcadma_create: invalid DMA channel %d\n", 542 dmach); 543 return (EINVAL); 544 } 545 546 if (size > 65536) { 547 panic("mca_dmamap_create: dmamap sz %ld > 65536", 548 (long) size); 549 } 550 #endif 551 552 /* 553 * MCA DMA transfer can be maximum 65536 bytes long and must 554 * be in one chunk. No specific boundary constraints are present. 555 */ 556 if ((error = bus_dmamap_create(t, size, 1, 65536, 0, flags, dmamp))) 557 return (error); 558 559 /* Encode DMA channel */ 560 cookie = (struct i386_isa_dma_cookie *) (*dmamp)->_dm_cookie; 561 cookie->id_flags &= 0x0f; 562 cookie->id_flags |= dmach << 4; 563 564 /* Mark the dmamap as using DMA controller. Some devices 565 * drive DMA themselves, and don't need the MCA DMA controller. 566 * To distinguish the two, use a flag for dmamaps which use the DMA 567 * controller. 568 */ 569 (*dmamp)->_dm_flags |= _MCABUS_DMA_USEDMACTRL; 570 571 return (0); 572 } 573 574 /* 575 * Set I/O port for DMA. Implemented separately from _mca_bus_dmamap_sync() 576 * so that it's available for one-shot setup. 577 */ 578 void 579 mca_dma_set_ioport(dma, port) 580 int dma; 581 u_int16_t port; 582 { 583 /* Disable access to dma channel. */ 584 bus_space_write_1(dmaiot, dmacmdh, 0, DMACMD_MASK | dma); 585 586 /* Set I/O port to use for DMA */ 587 bus_space_write_1(dmaiot, dmacmdh, 0, DMACMD_SET_IO | dma); 588 bus_space_write_1(dmaiot, dmaexech, 0, port & 0xff); 589 bus_space_write_1(dmaiot, dmaexech, 0, (port >> 8) & 0xff); 590 591 /* Enable access to dma channel. */ 592 bus_space_write_1(dmaiot, dmacmdh, 0, DMACMD_RESET_MASK | dma); 593 } 594