Annotation of sys/arch/i386/isa/isa_machdep.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: isa_machdep.c,v 1.60 2007/04/28 03:55:40 jsg Exp $ */
! 2: /* $NetBSD: isa_machdep.c,v 1.22 1997/06/12 23:57:32 thorpej Exp $ */
! 3:
! 4: /*-
! 5: * Copyright (c) 1996, 1997 The NetBSD Foundation, Inc.
! 6: * All rights reserved.
! 7: *
! 8: * This code is derived from software contributed to The NetBSD Foundation
! 9: * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
! 10: * NASA Ames Research Center.
! 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: * Copyright (c) 1993, 1994, 1996, 1997
! 43: * Charles M. Hannum. All rights reserved.
! 44: * Copyright (c) 1991 The Regents of the University of California.
! 45: * All rights reserved.
! 46: *
! 47: * This code is derived from software contributed to Berkeley by
! 48: * William Jolitz.
! 49: *
! 50: * Redistribution and use in source and binary forms, with or without
! 51: * modification, are permitted provided that the following conditions
! 52: * are met:
! 53: * 1. Redistributions of source code must retain the above copyright
! 54: * notice, this list of conditions and the following disclaimer.
! 55: * 2. Redistributions in binary form must reproduce the above copyright
! 56: * notice, this list of conditions and the following disclaimer in the
! 57: * documentation and/or other materials provided with the distribution.
! 58: * 3. Neither the name of the University nor the names of its contributors
! 59: * may be used to endorse or promote products derived from this software
! 60: * without specific prior written permission.
! 61: *
! 62: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
! 63: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
! 64: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
! 65: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
! 66: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
! 67: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
! 68: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
! 69: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
! 70: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
! 71: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
! 72: * SUCH DAMAGE.
! 73: *
! 74: * @(#)isa.c 7.2 (Berkeley) 5/13/91
! 75: */
! 76:
! 77: #include <sys/param.h>
! 78: #include <sys/systm.h>
! 79: #include <sys/syslog.h>
! 80: #include <sys/device.h>
! 81: #include <sys/malloc.h>
! 82: #include <sys/proc.h>
! 83:
! 84: #include <uvm/uvm_extern.h>
! 85:
! 86: #include "ioapic.h"
! 87:
! 88: #if NIOAPIC > 0
! 89: #include <machine/i82093var.h>
! 90: #include <machine/mpbiosvar.h>
! 91: #endif
! 92:
! 93: #define _I386_BUS_DMA_PRIVATE
! 94: #include <machine/bus.h>
! 95:
! 96: #include <machine/intr.h>
! 97: #include <machine/pio.h>
! 98: #include <machine/cpufunc.h>
! 99: #include <machine/i8259.h>
! 100:
! 101: #include <dev/isa/isareg.h>
! 102: #include <dev/isa/isavar.h>
! 103: #include <dev/isa/isadmavar.h>
! 104: #include <i386/isa/isa_machdep.h>
! 105:
! 106: #include "isadma.h"
! 107:
! 108: extern paddr_t avail_end;
! 109:
! 110: #define IDTVEC(name) __CONCAT(X,name)
! 111: /* default interrupt vector table entries */
! 112: typedef int (*vector)(void);
! 113: extern vector IDTVEC(intr)[];
! 114: void isa_strayintr(int);
! 115: void intr_calculatemasks(void);
! 116: int fakeintr(void *);
! 117:
! 118: #if NISADMA > 0
! 119: int _isa_bus_dmamap_create(bus_dma_tag_t, bus_size_t, int,
! 120: bus_size_t, bus_size_t, int, bus_dmamap_t *);
! 121: void _isa_bus_dmamap_destroy(bus_dma_tag_t, bus_dmamap_t);
! 122: int _isa_bus_dmamap_load(bus_dma_tag_t, bus_dmamap_t, void *,
! 123: bus_size_t, struct proc *, int);
! 124: int _isa_bus_dmamap_load_mbuf(bus_dma_tag_t, bus_dmamap_t,
! 125: struct mbuf *, int);
! 126: int _isa_bus_dmamap_load_uio(bus_dma_tag_t, bus_dmamap_t,
! 127: struct uio *, int);
! 128: int _isa_bus_dmamap_load_raw(bus_dma_tag_t, bus_dmamap_t,
! 129: bus_dma_segment_t *, int, bus_size_t, int);
! 130: void _isa_bus_dmamap_unload(bus_dma_tag_t, bus_dmamap_t);
! 131: void _isa_bus_dmamap_sync(bus_dma_tag_t, bus_dmamap_t,
! 132: bus_addr_t, bus_size_t, int);
! 133:
! 134: int _isa_bus_dmamem_alloc(bus_dma_tag_t, bus_size_t, bus_size_t,
! 135: bus_size_t, bus_dma_segment_t *, int, int *, int);
! 136: void _isa_bus_dmamem_free(bus_dma_tag_t,
! 137: bus_dma_segment_t *, int);
! 138: int _isa_bus_dmamem_map(bus_dma_tag_t, bus_dma_segment_t *,
! 139: int, size_t, caddr_t *, int);
! 140: void _isa_bus_dmamem_unmap(bus_dma_tag_t, caddr_t, size_t);
! 141: paddr_t _isa_bus_dmamem_mmap(bus_dma_tag_t, bus_dma_segment_t *,
! 142: int, off_t, int, int);
! 143:
! 144: int _isa_dma_check_buffer(void *, bus_size_t, int, bus_size_t,
! 145: struct proc *);
! 146: int _isa_dma_alloc_bouncebuf(bus_dma_tag_t, bus_dmamap_t,
! 147: bus_size_t, int);
! 148: void _isa_dma_free_bouncebuf(bus_dma_tag_t, bus_dmamap_t);
! 149:
! 150: /*
! 151: * Entry points for ISA DMA. These are mostly wrappers around
! 152: * the generic functions that understand how to deal with bounce
! 153: * buffers, if necessary.
! 154: */
! 155: struct i386_bus_dma_tag isa_bus_dma_tag = {
! 156: NULL, /* _cookie */
! 157: _isa_bus_dmamap_create,
! 158: _isa_bus_dmamap_destroy,
! 159: _isa_bus_dmamap_load,
! 160: _isa_bus_dmamap_load_mbuf,
! 161: _isa_bus_dmamap_load_uio,
! 162: _isa_bus_dmamap_load_raw,
! 163: _isa_bus_dmamap_unload,
! 164: _isa_bus_dmamap_sync,
! 165: _isa_bus_dmamem_alloc,
! 166: _isa_bus_dmamem_free,
! 167: _isa_bus_dmamem_map,
! 168: _isa_bus_dmamem_unmap,
! 169: _isa_bus_dmamem_mmap,
! 170: };
! 171: #endif /* NISADMA > 0 */
! 172:
! 173: /*
! 174: * Fill in default interrupt table (in case of spurious interrupt
! 175: * during configuration of kernel, setup interrupt control unit
! 176: */
! 177: void
! 178: isa_defaultirq(void)
! 179: {
! 180: int i;
! 181:
! 182: /* icu vectors */
! 183: for (i = 0; i < ICU_LEN; i++)
! 184: setgate(&idt[ICU_OFFSET + i], IDTVEC(intr)[i], 0,
! 185: SDT_SYS386IGT, SEL_KPL, GICODE_SEL);
! 186:
! 187: /* initialize 8259's */
! 188: outb(IO_ICU1, 0x11); /* reset; program device, four bytes */
! 189: outb(IO_ICU1+1, ICU_OFFSET); /* starting at this vector index */
! 190: outb(IO_ICU1+1, 1 << IRQ_SLAVE); /* slave on line 2 */
! 191: #ifdef AUTO_EOI_1
! 192: outb(IO_ICU1+1, 2 | 1); /* auto EOI, 8086 mode */
! 193: #else
! 194: outb(IO_ICU1+1, 1); /* 8086 mode */
! 195: #endif
! 196: outb(IO_ICU1+1, 0xff); /* leave interrupts masked */
! 197: outb(IO_ICU1, 0x68); /* special mask mode (if available) */
! 198: outb(IO_ICU1, 0x0a); /* Read IRR by default. */
! 199: #ifdef REORDER_IRQ
! 200: outb(IO_ICU1, 0xc0 | (3 - 1)); /* pri order 3-7, 0-2 (com2 first) */
! 201: #endif
! 202:
! 203: outb(IO_ICU2, 0x11); /* reset; program device, four bytes */
! 204: outb(IO_ICU2+1, ICU_OFFSET+8); /* staring at this vector index */
! 205: outb(IO_ICU2+1, IRQ_SLAVE);
! 206: #ifdef AUTO_EOI_2
! 207: outb(IO_ICU2+1, 2 | 1); /* auto EOI, 8086 mode */
! 208: #else
! 209: outb(IO_ICU2+1, 1); /* 8086 mode */
! 210: #endif
! 211: outb(IO_ICU2+1, 0xff); /* leave interrupts masked */
! 212: outb(IO_ICU2, 0x68); /* special mask mode (if available) */
! 213: outb(IO_ICU2, 0x0a); /* Read IRR by default. */
! 214: }
! 215:
! 216: void
! 217: isa_nodefaultirq(void)
! 218: {
! 219: int i;
! 220:
! 221: /* icu vectors */
! 222: for (i = 0; i < ICU_LEN; i++)
! 223: unsetgate(&idt[ICU_OFFSET + i]);
! 224: }
! 225:
! 226: /*
! 227: * Handle a NMI, possibly a machine check.
! 228: * return true to panic system, false to ignore.
! 229: */
! 230: int
! 231: isa_nmi(void)
! 232: {
! 233: /* This is historic garbage; these ports are not readable */
! 234: log(LOG_CRIT, "No-maskable interrupt, may be parity error\n");
! 235: return(0);
! 236: }
! 237:
! 238: u_long intrstray[ICU_LEN];
! 239:
! 240: /*
! 241: * Caught a stray interrupt, notify
! 242: */
! 243: void
! 244: isa_strayintr(int irq)
! 245: {
! 246: /*
! 247: * Stray interrupts on irq 7 occur when an interrupt line is raised
! 248: * and then lowered before the CPU acknowledges it. This generally
! 249: * means either the device is screwed or something is cli'ing too
! 250: * long and it's timing out.
! 251: */
! 252: if (++intrstray[irq] <= 5)
! 253: log(LOG_ERR, "stray interrupt %d%s\n", irq,
! 254: intrstray[irq] >= 5 ? "; stopped logging" : "");
! 255: }
! 256:
! 257: int intrtype[ICU_LEN], intrmask[ICU_LEN], intrlevel[ICU_LEN];
! 258: int iminlevel[ICU_LEN], imaxlevel[ICU_LEN];
! 259: struct intrhand *intrhand[ICU_LEN];
! 260:
! 261: int imask[NIPL]; /* Bitmask telling what interrupts are blocked. */
! 262: int iunmask[NIPL]; /* Bitmask telling what interrupts are accepted. */
! 263:
! 264: /*
! 265: * Recalculate the interrupt masks from scratch.
! 266: * We could code special registry and deregistry versions of this function that
! 267: * would be faster, but the code would be nastier, and we don't expect this to
! 268: * happen very much anyway.
! 269: */
! 270: void
! 271: intr_calculatemasks(void)
! 272: {
! 273: int irq, level, unusedirqs;
! 274: struct intrhand *q;
! 275:
! 276: /* First, figure out which levels each IRQ uses. */
! 277: unusedirqs = 0xffff;
! 278: for (irq = 0; irq < ICU_LEN; irq++) {
! 279: int levels = 0;
! 280: for (q = intrhand[irq]; q; q = q->ih_next)
! 281: levels |= 1 << IPL(q->ih_level);
! 282: intrlevel[irq] = levels;
! 283: if (levels)
! 284: unusedirqs &= ~(1 << irq);
! 285: }
! 286:
! 287: /* Then figure out which IRQs use each level. */
! 288: for (level = 0; level < NIPL; level++) {
! 289: int irqs = 0;
! 290: for (irq = 0; irq < ICU_LEN; irq++)
! 291: if (intrlevel[irq] & (1 << level))
! 292: irqs |= 1 << irq;
! 293: imask[level] = irqs | unusedirqs;
! 294: }
! 295:
! 296: /*
! 297: * Initialize soft interrupt masks to block themselves.
! 298: */
! 299: IMASK(IPL_SOFTAST) |= 1 << SIR_AST;
! 300: IMASK(IPL_SOFTCLOCK) |= 1 << SIR_CLOCK;
! 301: IMASK(IPL_SOFTNET) |= 1 << SIR_NET;
! 302: IMASK(IPL_SOFTTTY) |= 1 << SIR_TTY;
! 303:
! 304: /*
! 305: * Enforce a hierarchy that gives slow devices a better chance at not
! 306: * dropping data.
! 307: */
! 308: for (level = 0; level < NIPL - 1; level++)
! 309: imask[level + 1] |= imask[level];
! 310:
! 311: /* And eventually calculate the complete masks. */
! 312: for (irq = 0; irq < ICU_LEN; irq++) {
! 313: int irqs = 1 << irq;
! 314: int minlevel = IPL_NONE;
! 315: int maxlevel = IPL_NONE;
! 316:
! 317: if (intrhand[irq] == NULL) {
! 318: maxlevel = IPL_HIGH;
! 319: irqs = IMASK(IPL_HIGH);
! 320: } else {
! 321: for (q = intrhand[irq]; q; q = q->ih_next) {
! 322: irqs |= IMASK(q->ih_level);
! 323: if (minlevel == IPL_NONE ||
! 324: q->ih_level < minlevel)
! 325: minlevel = q->ih_level;
! 326: if (q->ih_level > maxlevel)
! 327: maxlevel = q->ih_level;
! 328: }
! 329: }
! 330: if (irqs != IMASK(maxlevel))
! 331: panic("irq %d level %x mask mismatch: %x vs %x", irq,
! 332: maxlevel, irqs, IMASK(maxlevel));
! 333:
! 334: intrmask[irq] = irqs;
! 335: iminlevel[irq] = minlevel;
! 336: imaxlevel[irq] = maxlevel;
! 337:
! 338: #if 0
! 339: printf("irq %d: level %x, mask 0x%x (%x)\n", irq,
! 340: imaxlevel[irq], intrmask[irq], IMASK(imaxlevel[irq]));
! 341: #endif
! 342: }
! 343:
! 344: /* Lastly, determine which IRQs are actually in use. */
! 345: {
! 346: int irqs = 0;
! 347: for (irq = 0; irq < ICU_LEN; irq++)
! 348: if (intrhand[irq])
! 349: irqs |= 1 << irq;
! 350: if (irqs >= 0x100) /* any IRQs >= 8 in use */
! 351: irqs |= 1 << IRQ_SLAVE;
! 352: imen = ~irqs;
! 353: SET_ICUS();
! 354: }
! 355:
! 356: /* For speed of splx, provide the inverse of the interrupt masks. */
! 357: for (irq = 0; irq < ICU_LEN; irq++)
! 358: iunmask[irq] = ~imask[irq];
! 359: }
! 360:
! 361: int
! 362: fakeintr(arg)
! 363: void *arg;
! 364: {
! 365: return 0;
! 366: }
! 367:
! 368: #define LEGAL_IRQ(x) ((x) >= 0 && (x) < ICU_LEN && (x) != 2)
! 369:
! 370: int
! 371: isa_intr_alloc(isa_chipset_tag_t ic, int mask, int type, int *irq)
! 372: {
! 373: int i, bestirq, count;
! 374: int tmp;
! 375: struct intrhand **p, *q;
! 376:
! 377: if (type == IST_NONE)
! 378: panic("intr_alloc: bogus type");
! 379:
! 380: bestirq = -1;
! 381: count = -1;
! 382:
! 383: /* some interrupts should never be dynamically allocated */
! 384: mask &= 0xdef8;
! 385:
! 386: /*
! 387: * XXX some interrupts will be used later (6 for fdc, 12 for pms).
! 388: * the right answer is to do "breadth-first" searching of devices.
! 389: */
! 390: mask &= 0xefbf;
! 391:
! 392: for (i = 0; i < ICU_LEN; i++) {
! 393: if (LEGAL_IRQ(i) == 0 || (mask & (1<<i)) == 0)
! 394: continue;
! 395:
! 396: switch(intrtype[i]) {
! 397: case IST_NONE:
! 398: /*
! 399: * if nothing's using the irq, just return it
! 400: */
! 401: *irq = i;
! 402: return (0);
! 403:
! 404: case IST_EDGE:
! 405: case IST_LEVEL:
! 406: if (type != intrtype[i])
! 407: continue;
! 408: /*
! 409: * if the irq is shareable, count the number of other
! 410: * handlers, and if it's smaller than the last irq like
! 411: * this, remember it
! 412: *
! 413: * XXX We should probably also consider the
! 414: * interrupt level and stick IPL_TTY with other
! 415: * IPL_TTY, etc.
! 416: */
! 417: for (p = &intrhand[i], tmp = 0; (q = *p) != NULL;
! 418: p = &q->ih_next, tmp++)
! 419: ;
! 420: if ((bestirq == -1) || (count > tmp)) {
! 421: bestirq = i;
! 422: count = tmp;
! 423: }
! 424: break;
! 425:
! 426: case IST_PULSE:
! 427: /* this just isn't shareable */
! 428: continue;
! 429: }
! 430: }
! 431:
! 432: if (bestirq == -1)
! 433: return (1);
! 434:
! 435: *irq = bestirq;
! 436:
! 437: return (0);
! 438: }
! 439:
! 440: /*
! 441: * Just check to see if an IRQ is available/can be shared.
! 442: * 0 = interrupt not available
! 443: * 1 = interrupt shareable
! 444: * 2 = interrupt all to ourself
! 445: */
! 446: int
! 447: isa_intr_check(isa_chipset_tag_t ic, int irq, int type)
! 448: {
! 449: if (!LEGAL_IRQ(irq) || type == IST_NONE)
! 450: return (0);
! 451:
! 452: switch (intrtype[irq]) {
! 453: case IST_NONE:
! 454: return (2);
! 455: break;
! 456: case IST_LEVEL:
! 457: if (type != intrtype[irq])
! 458: return (0);
! 459: return (1);
! 460: break;
! 461: case IST_EDGE:
! 462: case IST_PULSE:
! 463: if (type != IST_NONE)
! 464: return (0);
! 465: }
! 466: return (1);
! 467: }
! 468:
! 469: /*
! 470: * Set up an interrupt handler to start being called.
! 471: * XXX PRONE TO RACE CONDITIONS, UGLY, 'INTERESTING' INSERTION ALGORITHM.
! 472: */
! 473: void *
! 474: isa_intr_establish(isa_chipset_tag_t ic, int irq, int type, int level,
! 475: int (*ih_fun)(void *), void *ih_arg, char *ih_what)
! 476: {
! 477: struct intrhand **p, *q, *ih;
! 478: static struct intrhand fakehand = {fakeintr};
! 479:
! 480: #if NIOAPIC > 0
! 481: struct mp_intr_map *mip;
! 482:
! 483: if (mp_busses != NULL) {
! 484: int mpspec_pin = irq;
! 485: int airq;
! 486:
! 487: if (mp_isa_bus == NULL)
! 488: panic("no isa bus");
! 489:
! 490: for (mip = mp_isa_bus->mb_intrs; mip != NULL;
! 491: mip = mip->next) {
! 492: if (mip->bus_pin == mpspec_pin) {
! 493: airq = mip->ioapic_ih | irq;
! 494: break;
! 495: }
! 496: }
! 497: if (mip == NULL && mp_eisa_bus) {
! 498: for (mip = mp_eisa_bus->mb_intrs; mip != NULL;
! 499: mip = mip->next) {
! 500: if (mip->bus_pin == mpspec_pin) {
! 501: airq = mip->ioapic_ih | irq;
! 502: break;
! 503: }
! 504: }
! 505: }
! 506:
! 507: /* no MP mapping found -- invent! */
! 508: if (mip == NULL)
! 509: airq = mpbios_invent(irq, type, mp_isa_bus->mb_idx);
! 510:
! 511: return (apic_intr_establish(airq, type, level, ih_fun,
! 512: ih_arg, ih_what));
! 513: }
! 514: #endif
! 515: /* no point in sleeping unless someone can free memory. */
! 516: ih = malloc(sizeof *ih, M_DEVBUF, cold ? M_NOWAIT : M_WAITOK);
! 517: if (ih == NULL) {
! 518: printf("%s: isa_intr_establish: can't malloc handler info\n",
! 519: ih_what);
! 520: return (NULL);
! 521: }
! 522:
! 523: if (!LEGAL_IRQ(irq) || type == IST_NONE) {
! 524: printf("%s: isa_intr_establish: bogus irq or type\n", ih_what);
! 525: free(ih, M_DEVBUF);
! 526: return (NULL);
! 527: }
! 528: switch (intrtype[irq]) {
! 529: case IST_NONE:
! 530: intrtype[irq] = type;
! 531: break;
! 532: case IST_EDGE:
! 533: case IST_LEVEL:
! 534: if (type == intrtype[irq])
! 535: break;
! 536: case IST_PULSE:
! 537: if (type != IST_NONE) {
! 538: /*printf("%s: intr_establish: can't share %s with %s, irq %d\n",
! 539: ih_what, isa_intr_typename(intrtype[irq]),
! 540: isa_intr_typename(type), irq);*/
! 541: free(ih, M_DEVBUF);
! 542: return (NULL);
! 543: }
! 544: break;
! 545: }
! 546:
! 547: /*
! 548: * Figure out where to put the handler.
! 549: * This is O(N^2), but we want to preserve the order, and N is
! 550: * generally small.
! 551: */
! 552: for (p = &intrhand[irq]; (q = *p) != NULL; p = &q->ih_next)
! 553: ;
! 554:
! 555: /*
! 556: * Actually install a fake handler momentarily, since we might be doing
! 557: * this with interrupts enabled and don't want the real routine called
! 558: * until masking is set up.
! 559: */
! 560: fakehand.ih_level = level;
! 561: *p = &fakehand;
! 562:
! 563: intr_calculatemasks();
! 564:
! 565: /*
! 566: * Poke the real handler in now.
! 567: */
! 568: ih->ih_fun = ih_fun;
! 569: ih->ih_arg = ih_arg;
! 570: ih->ih_next = NULL;
! 571: ih->ih_level = level;
! 572: ih->ih_irq = irq;
! 573: evcount_attach(&ih->ih_count, ih_what, (void *)&ih->ih_irq,
! 574: &evcount_intr);
! 575: *p = ih;
! 576:
! 577: return (ih);
! 578: }
! 579:
! 580: /*
! 581: * Deregister an interrupt handler.
! 582: */
! 583: void
! 584: isa_intr_disestablish(isa_chipset_tag_t ic, void *arg)
! 585: {
! 586: struct intrhand *ih = arg;
! 587: int irq = ih->ih_irq;
! 588: struct intrhand **p, *q;
! 589:
! 590: #if NIOAPIC > 0
! 591: if (irq & APIC_INT_VIA_APIC) {
! 592: apic_intr_disestablish(arg);
! 593: return;
! 594: }
! 595: #endif
! 596:
! 597: if (!LEGAL_IRQ(irq))
! 598: panic("intr_disestablish: bogus irq %d", irq);
! 599:
! 600: /*
! 601: * Remove the handler from the chain.
! 602: * This is O(n^2), too.
! 603: */
! 604: for (p = &intrhand[irq]; (q = *p) != NULL && q != ih; p = &q->ih_next)
! 605: ;
! 606: if (q)
! 607: *p = q->ih_next;
! 608: else
! 609: panic("intr_disestablish: handler not registered");
! 610: evcount_detach(&ih->ih_count);
! 611: free(ih, M_DEVBUF);
! 612:
! 613: intr_calculatemasks();
! 614:
! 615: if (intrhand[irq] == NULL)
! 616: intrtype[irq] = IST_NONE;
! 617: }
! 618:
! 619: void
! 620: isa_attach_hook(struct device *parent, struct device *self,
! 621: struct isabus_attach_args *iba)
! 622: {
! 623: extern int isa_has_been_seen;
! 624:
! 625: /*
! 626: * Notify others that might need to know that the ISA bus
! 627: * has now been attached.
! 628: */
! 629: if (isa_has_been_seen)
! 630: panic("isaattach: ISA bus already seen!");
! 631: isa_has_been_seen = 1;
! 632: }
! 633:
! 634: #if NISADMA > 0
! 635: /**********************************************************************
! 636: * bus.h dma interface entry points
! 637: **********************************************************************/
! 638:
! 639: #ifdef ISA_DMA_STATS
! 640: #define STAT_INCR(v) (v)++
! 641: #define STAT_DECR(v) do { \
! 642: if ((v) == 0) \
! 643: printf("%s:%d -- Already 0!\n", __FILE__, __LINE__); \
! 644: else \
! 645: (v)--; \
! 646: } while (0)
! 647: u_long isa_dma_stats_loads;
! 648: u_long isa_dma_stats_bounces;
! 649: u_long isa_dma_stats_nbouncebufs;
! 650: #else
! 651: #define STAT_INCR(v)
! 652: #define STAT_DECR(v)
! 653: #endif
! 654:
! 655: /*
! 656: * Create an ISA DMA map.
! 657: */
! 658: int
! 659: _isa_bus_dmamap_create(bus_dma_tag_t t, bus_size_t size, int nsegments,
! 660: bus_size_t maxsegsz, bus_size_t boundary, int flags, bus_dmamap_t *dmamp)
! 661: {
! 662: struct i386_isa_dma_cookie *cookie;
! 663: bus_dmamap_t map;
! 664: int error, cookieflags;
! 665: void *cookiestore;
! 666: size_t cookiesize;
! 667:
! 668: /* Call common function to create the basic map. */
! 669: error = _bus_dmamap_create(t, size, nsegments, maxsegsz, boundary,
! 670: flags, dmamp);
! 671: if (error)
! 672: return (error);
! 673:
! 674: map = *dmamp;
! 675: map->_dm_cookie = NULL;
! 676:
! 677: cookiesize = sizeof(struct i386_isa_dma_cookie);
! 678:
! 679: /*
! 680: * ISA only has 24-bits of address space. This means
! 681: * we can't DMA to pages over 16M. In order to DMA to
! 682: * arbitrary buffers, we use "bounce buffers" - pages
! 683: * in memory below the 16M boundary. On DMA reads,
! 684: * DMA happens to the bounce buffers, and is copied into
! 685: * the caller's buffer. On writes, data is copied into
! 686: * but bounce buffer, and the DMA happens from those
! 687: * pages. To software using the DMA mapping interface,
! 688: * this looks simply like a data cache.
! 689: *
! 690: * If we have more than 16M of RAM in the system, we may
! 691: * need bounce buffers. We check and remember that here.
! 692: *
! 693: * There are exceptions, however. VLB devices can do
! 694: * 32-bit DMA, and indicate that here.
! 695: *
! 696: * ...or, there is an opposite case. The most segments
! 697: * a transfer will require is (maxxfer / NBPG) + 1. If
! 698: * the caller can't handle that many segments (e.g. the
! 699: * ISA DMA controller), we may have to bounce it as well.
! 700: */
! 701: cookieflags = 0;
! 702: if ((avail_end > ISA_DMA_BOUNCE_THRESHOLD &&
! 703: (flags & ISABUS_DMA_32BIT) == 0) ||
! 704: ((map->_dm_size / NBPG) + 1) > map->_dm_segcnt) {
! 705: cookieflags |= ID_MIGHT_NEED_BOUNCE;
! 706: cookiesize += (sizeof(bus_dma_segment_t) * map->_dm_segcnt);
! 707: }
! 708:
! 709: /*
! 710: * Allocate our cookie.
! 711: */
! 712: if ((cookiestore = malloc(cookiesize, M_DEVBUF,
! 713: (flags & BUS_DMA_NOWAIT) ? M_NOWAIT : M_WAITOK)) == NULL) {
! 714: error = ENOMEM;
! 715: goto out;
! 716: }
! 717: bzero(cookiestore, cookiesize);
! 718: cookie = (struct i386_isa_dma_cookie *)cookiestore;
! 719: cookie->id_flags = cookieflags;
! 720: map->_dm_cookie = cookie;
! 721:
! 722: if (cookieflags & ID_MIGHT_NEED_BOUNCE) {
! 723: /*
! 724: * Allocate the bounce pages now if the caller
! 725: * wishes us to do so.
! 726: */
! 727: if ((flags & BUS_DMA_ALLOCNOW) == 0)
! 728: goto out;
! 729:
! 730: error = _isa_dma_alloc_bouncebuf(t, map, size, flags);
! 731: }
! 732:
! 733: out:
! 734: if (error) {
! 735: if (map->_dm_cookie != NULL)
! 736: free(map->_dm_cookie, M_DEVBUF);
! 737: _bus_dmamap_destroy(t, map);
! 738: }
! 739: return (error);
! 740: }
! 741:
! 742: /*
! 743: * Destroy an ISA DMA map.
! 744: */
! 745: void
! 746: _isa_bus_dmamap_destroy(bus_dma_tag_t t, bus_dmamap_t map)
! 747: {
! 748: struct i386_isa_dma_cookie *cookie = map->_dm_cookie;
! 749:
! 750: /*
! 751: * Free any bounce pages this map might hold.
! 752: */
! 753: if (cookie->id_flags & ID_HAS_BOUNCE)
! 754: _isa_dma_free_bouncebuf(t, map);
! 755:
! 756: free(cookie, M_DEVBUF);
! 757: _bus_dmamap_destroy(t, map);
! 758: }
! 759:
! 760: /*
! 761: * Load an ISA DMA map with a linear buffer.
! 762: */
! 763: int
! 764: _isa_bus_dmamap_load(bus_dma_tag_t t, bus_dmamap_t map, void *buf,
! 765: bus_size_t buflen, struct proc *p, int flags)
! 766: {
! 767: struct i386_isa_dma_cookie *cookie = map->_dm_cookie;
! 768: int error;
! 769:
! 770: STAT_INCR(isa_dma_stats_loads);
! 771:
! 772: /*
! 773: * Check to see if we might need to bounce the transfer.
! 774: */
! 775: if (cookie->id_flags & ID_MIGHT_NEED_BOUNCE) {
! 776: /*
! 777: * Check if all pages are below the bounce
! 778: * threshold. If they are, don't bother bouncing.
! 779: */
! 780: if (_isa_dma_check_buffer(buf, buflen,
! 781: map->_dm_segcnt, map->_dm_boundary, p) == 0)
! 782: return (_bus_dmamap_load(t, map, buf, buflen,
! 783: p, flags));
! 784:
! 785: STAT_INCR(isa_dma_stats_bounces);
! 786:
! 787: /*
! 788: * Allocate bounce pages, if necessary.
! 789: */
! 790: if ((cookie->id_flags & ID_HAS_BOUNCE) == 0) {
! 791: error = _isa_dma_alloc_bouncebuf(t, map, buflen,
! 792: flags);
! 793: if (error)
! 794: return (error);
! 795: }
! 796:
! 797: /*
! 798: * Cache a pointer to the caller's buffer and
! 799: * load the DMA map with the bounce buffer.
! 800: */
! 801: cookie->id_origbuf = buf;
! 802: cookie->id_origbuflen = buflen;
! 803: error = _bus_dmamap_load(t, map, cookie->id_bouncebuf,
! 804: buflen, p, flags);
! 805:
! 806: if (error) {
! 807: /*
! 808: * Free the bounce pages, unless our resources
! 809: * are reserved for our exclusive use.
! 810: */
! 811: if ((map->_dm_flags & BUS_DMA_ALLOCNOW) == 0)
! 812: _isa_dma_free_bouncebuf(t, map);
! 813: }
! 814:
! 815: /* ...so _isa_bus_dmamap_sync() knows we're bouncing */
! 816: cookie->id_flags |= ID_IS_BOUNCING;
! 817: } else {
! 818: /*
! 819: * Just use the generic load function.
! 820: */
! 821: error = _bus_dmamap_load(t, map, buf, buflen, p, flags);
! 822: }
! 823:
! 824: return (error);
! 825: }
! 826:
! 827: /*
! 828: * Like _isa_bus_dmamap_load(), but for mbufs.
! 829: */
! 830: int
! 831: _isa_bus_dmamap_load_mbuf(bus_dma_tag_t t, bus_dmamap_t map, struct mbuf *m,
! 832: int flags)
! 833: {
! 834:
! 835: panic("_isa_bus_dmamap_load_mbuf: not implemented");
! 836: }
! 837:
! 838: /*
! 839: * Like _isa_bus_dmamap_load(), but for uios.
! 840: */
! 841: int
! 842: _isa_bus_dmamap_load_uio(bus_dma_tag_t t, bus_dmamap_t map, struct uio *uio,
! 843: int flags)
! 844: {
! 845:
! 846: panic("_isa_bus_dmamap_load_uio: not implemented");
! 847: }
! 848:
! 849: /*
! 850: * Like _isa_bus_dmamap_load(), but for raw memory allocated with
! 851: * bus_dmamem_alloc().
! 852: */
! 853: int
! 854: _isa_bus_dmamap_load_raw(bus_dma_tag_t t, bus_dmamap_t map,
! 855: bus_dma_segment_t *segs, int nsegs, bus_size_t size, int flags)
! 856: {
! 857:
! 858: panic("_isa_bus_dmamap_load_raw: not implemented");
! 859: }
! 860:
! 861: /*
! 862: * Unload an ISA DMA map.
! 863: */
! 864: void
! 865: _isa_bus_dmamap_unload(bus_dma_tag_t t, bus_dmamap_t map)
! 866: {
! 867: struct i386_isa_dma_cookie *cookie = map->_dm_cookie;
! 868:
! 869: /*
! 870: * If we have bounce pages, free them, unless they're
! 871: * reserved for our exclusive use.
! 872: */
! 873: if ((cookie->id_flags & ID_HAS_BOUNCE) &&
! 874: (map->_dm_flags & BUS_DMA_ALLOCNOW) == 0)
! 875: _isa_dma_free_bouncebuf(t, map);
! 876:
! 877: cookie->id_flags &= ~ID_IS_BOUNCING;
! 878:
! 879: /*
! 880: * Do the generic bits of the unload.
! 881: */
! 882: _bus_dmamap_unload(t, map);
! 883: }
! 884:
! 885: /*
! 886: * Synchronize an ISA DMA map.
! 887: */
! 888: void
! 889: _isa_bus_dmamap_sync(bus_dma_tag_t t, bus_dmamap_t map, bus_addr_t offset,
! 890: bus_size_t len, int op)
! 891: {
! 892: struct i386_isa_dma_cookie *cookie = map->_dm_cookie;
! 893:
! 894: #ifdef DEBUG
! 895: if ((op & (BUS_DMASYNC_PREWRITE|BUS_DMASYNC_POSTREAD)) != 0) {
! 896: if (offset >= map->dm_mapsize)
! 897: panic("_isa_bus_dmamap_sync: bad offset");
! 898: if (len == 0 || (offset + len) > map->dm_mapsize)
! 899: panic("_isa_bus_dmamap_sync: bad length");
! 900: }
! 901: #endif
! 902:
! 903: switch (op) {
! 904: case BUS_DMASYNC_PREREAD:
! 905: /*
! 906: * Nothing to do for pre-read.
! 907: */
! 908: break;
! 909:
! 910: case BUS_DMASYNC_PREWRITE:
! 911: /*
! 912: * If we're bouncing this transfer, copy the
! 913: * caller's buffer to the bounce buffer.
! 914: */
! 915: if (cookie->id_flags & ID_IS_BOUNCING)
! 916: bcopy((char *)cookie->id_origbuf + offset,
! 917: cookie->id_bouncebuf + offset,
! 918: len);
! 919: break;
! 920:
! 921: case BUS_DMASYNC_POSTREAD:
! 922: /*
! 923: * If we're bouncing this transfer, copy the
! 924: * bounce buffer to the caller's buffer.
! 925: */
! 926: if (cookie->id_flags & ID_IS_BOUNCING)
! 927: bcopy((char *)cookie->id_bouncebuf + offset,
! 928: cookie->id_origbuf + offset,
! 929: len);
! 930: break;
! 931:
! 932: case BUS_DMASYNC_POSTWRITE:
! 933: /*
! 934: * Nothing to do for post-write.
! 935: */
! 936: break;
! 937: }
! 938:
! 939: #if 0
! 940: /* This is a noop anyhow, so why bother calling it? */
! 941: _bus_dmamap_sync(t, map, op);
! 942: #endif
! 943: }
! 944:
! 945: /*
! 946: * Allocate memory safe for ISA DMA.
! 947: */
! 948: int
! 949: _isa_bus_dmamem_alloc(bus_dma_tag_t t, bus_size_t size, bus_size_t alignment,
! 950: bus_size_t boundary, bus_dma_segment_t *segs, int nsegs, int *rsegs,
! 951: int flags)
! 952: {
! 953: paddr_t high;
! 954:
! 955: if (avail_end > ISA_DMA_BOUNCE_THRESHOLD)
! 956: high = trunc_page(ISA_DMA_BOUNCE_THRESHOLD);
! 957: else
! 958: high = trunc_page(avail_end);
! 959:
! 960: return (_bus_dmamem_alloc_range(t, size, alignment, boundary,
! 961: segs, nsegs, rsegs, flags, 0, high));
! 962: }
! 963:
! 964: /*
! 965: * Free memory safe for ISA DMA.
! 966: */
! 967: void
! 968: _isa_bus_dmamem_free(bus_dma_tag_t t, bus_dma_segment_t *segs, int nsegs)
! 969: {
! 970:
! 971: _bus_dmamem_free(t, segs, nsegs);
! 972: }
! 973:
! 974: /*
! 975: * Map ISA DMA-safe memory into kernel virtual address space.
! 976: */
! 977: int
! 978: _isa_bus_dmamem_map(bus_dma_tag_t t, bus_dma_segment_t *segs, int nsegs,
! 979: size_t size, caddr_t *kvap, int flags)
! 980: {
! 981:
! 982: return (_bus_dmamem_map(t, segs, nsegs, size, kvap, flags));
! 983: }
! 984:
! 985: /*
! 986: * Unmap ISA DMA-safe memory from kernel virtual address space.
! 987: */
! 988: void
! 989: _isa_bus_dmamem_unmap(bus_dma_tag_t t, caddr_t kva, size_t size)
! 990: {
! 991:
! 992: _bus_dmamem_unmap(t, kva, size);
! 993: }
! 994:
! 995: /*
! 996: * mmap(2) ISA DMA-safe memory.
! 997: */
! 998: paddr_t
! 999: _isa_bus_dmamem_mmap(bus_dma_tag_t t, bus_dma_segment_t *segs, int nsegs,
! 1000: off_t off, int prot, int flags)
! 1001: {
! 1002:
! 1003: return (_bus_dmamem_mmap(t, segs, nsegs, off, prot, flags));
! 1004: }
! 1005:
! 1006: /**********************************************************************
! 1007: * ISA DMA utility functions
! 1008: **********************************************************************/
! 1009:
! 1010: /*
! 1011: * Return 0 if all pages in the passed buffer lie within the DMA'able
! 1012: * range RAM.
! 1013: */
! 1014: int
! 1015: _isa_dma_check_buffer(void *buf, bus_size_t buflen, int segcnt,
! 1016: bus_size_t boundary, struct proc *p)
! 1017: {
! 1018: vaddr_t vaddr = (vaddr_t)buf;
! 1019: vaddr_t endva;
! 1020: paddr_t pa, lastpa;
! 1021: u_long pagemask = ~(boundary - 1);
! 1022: pmap_t pmap;
! 1023: int nsegs;
! 1024:
! 1025: endva = round_page(vaddr + buflen);
! 1026:
! 1027: nsegs = 1;
! 1028: lastpa = 0;
! 1029:
! 1030: if (p != NULL)
! 1031: pmap = p->p_vmspace->vm_map.pmap;
! 1032: else
! 1033: pmap = pmap_kernel();
! 1034:
! 1035: for (; vaddr < endva; vaddr += NBPG) {
! 1036: /*
! 1037: * Get physical address for this segment.
! 1038: */
! 1039: pmap_extract(pmap, (vaddr_t)vaddr, &pa);
! 1040: pa = trunc_page(pa);
! 1041:
! 1042: /*
! 1043: * Is it below the DMA'able threshold?
! 1044: */
! 1045: if (pa > ISA_DMA_BOUNCE_THRESHOLD)
! 1046: return (EINVAL);
! 1047:
! 1048: if (lastpa) {
! 1049: /*
! 1050: * Check excessive segment count.
! 1051: */
! 1052: if (lastpa + NBPG != pa) {
! 1053: if (++nsegs > segcnt)
! 1054: return (EFBIG);
! 1055: }
! 1056:
! 1057: /*
! 1058: * Check boundary restriction.
! 1059: */
! 1060: if (boundary) {
! 1061: if ((lastpa ^ pa) & pagemask)
! 1062: return (EINVAL);
! 1063: }
! 1064: }
! 1065: lastpa = pa;
! 1066: }
! 1067:
! 1068: return (0);
! 1069: }
! 1070:
! 1071: int
! 1072: _isa_dma_alloc_bouncebuf(bus_dma_tag_t t, bus_dmamap_t map, bus_size_t size, int flags)
! 1073: {
! 1074: struct i386_isa_dma_cookie *cookie = map->_dm_cookie;
! 1075: int error = 0;
! 1076:
! 1077: cookie->id_bouncebuflen = round_page(size);
! 1078: error = _isa_bus_dmamem_alloc(t, cookie->id_bouncebuflen,
! 1079: NBPG, map->_dm_boundary, cookie->id_bouncesegs,
! 1080: map->_dm_segcnt, &cookie->id_nbouncesegs, flags);
! 1081: if (error)
! 1082: goto out;
! 1083: error = _isa_bus_dmamem_map(t, cookie->id_bouncesegs,
! 1084: cookie->id_nbouncesegs, cookie->id_bouncebuflen,
! 1085: (caddr_t *)&cookie->id_bouncebuf, flags);
! 1086:
! 1087: out:
! 1088: if (error) {
! 1089: _isa_bus_dmamem_free(t, cookie->id_bouncesegs,
! 1090: cookie->id_nbouncesegs);
! 1091: cookie->id_bouncebuflen = 0;
! 1092: cookie->id_nbouncesegs = 0;
! 1093: } else {
! 1094: cookie->id_flags |= ID_HAS_BOUNCE;
! 1095: STAT_INCR(isa_dma_stats_nbouncebufs);
! 1096: }
! 1097:
! 1098: return (error);
! 1099: }
! 1100:
! 1101: void
! 1102: _isa_dma_free_bouncebuf(bus_dma_tag_t t, bus_dmamap_t map)
! 1103: {
! 1104: struct i386_isa_dma_cookie *cookie = map->_dm_cookie;
! 1105:
! 1106: STAT_DECR(isa_dma_stats_nbouncebufs);
! 1107:
! 1108: _isa_bus_dmamem_unmap(t, cookie->id_bouncebuf,
! 1109: cookie->id_bouncebuflen);
! 1110: _isa_bus_dmamem_free(t, cookie->id_bouncesegs,
! 1111: cookie->id_nbouncesegs);
! 1112: cookie->id_bouncebuflen = 0;
! 1113: cookie->id_nbouncesegs = 0;
! 1114: cookie->id_flags &= ~ID_HAS_BOUNCE;
! 1115: }
! 1116: #endif /* NISADMA > 0 */
CVSweb