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