Annotation of src/sys/arch/i386/mca/mca_machdep.c, Revision 1.19
1.19 ! fvdl 1: /* $NetBSD: mca_machdep.c,v 1.18 2002/11/22 15:23:51 fvdl Exp $ */
1.1 jdolecek 2:
1.3 jdolecek 3: /*-
1.12 jdolecek 4: * Copyright (c) 2000, 2001 The NetBSD Foundation, Inc.
1.3 jdolecek 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
1.12 jdolecek 9: * by Scott Telford <s.telford@ed.ac.uk> and Jaromir Dolecek
10: * <jdolecek@NetBSD.org>.
1.1 jdolecek 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.
1.3 jdolecek 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.
1.1 jdolecek 27: *
1.3 jdolecek 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.
1.1 jdolecek 39: */
40:
41: /*
42: * Machine-specific functions for MCA autoconfiguration.
43: */
1.10 lukem 44:
45: #include <sys/cdefs.h>
1.19 ! fvdl 46: __KERNEL_RCSID(0, "$NetBSD: mca_machdep.c,v 1.18 2002/11/22 15:23:51 fvdl Exp $");
1.1 jdolecek 47:
48: #include <sys/types.h>
49: #include <sys/param.h>
1.11 jdolecek 50: #include <sys/device.h>
51: #include <sys/malloc.h>
1.1 jdolecek 52: #include <sys/systm.h>
53: #include <sys/syslog.h>
1.11 jdolecek 54: #include <sys/time.h>
55: #include <sys/kernel.h>
1.1 jdolecek 56:
57: #include <machine/bioscall.h>
58: #include <machine/psl.h>
59:
1.19 ! fvdl 60: #define _X86_BUS_DMA_PRIVATE
1.1 jdolecek 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:
1.7 jdolecek 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 */
1.11 jdolecek 86: u_int8_t feature2;
87: u_int8_t pad[9];
1.7 jdolecek 88: } __attribute__ ((packed));
89:
1.11 jdolecek 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: */
1.19 ! fvdl 94: struct x86_isa_dma_cookie {
1.11 jdolecek 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)
1.7 jdolecek 126:
1.19 ! fvdl 127: struct x86_bus_dma_tag mca_bus_dma_tag = {
1.11 jdolecek 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,
1.1 jdolecek 138: _bus_dmamem_free,
139: _bus_dmamem_map,
140: _bus_dmamem_unmap,
141: _bus_dmamem_mmap,
142: };
143:
1.11 jdolecek 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;
1.1 jdolecek 151:
1.11 jdolecek 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: */
1.1 jdolecek 177: void
178: mca_attach_hook(parent, self, mba)
179: struct device *parent, *self;
180: struct mcabus_attach_args *mba;
181: {
1.11 jdolecek 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);
1.1 jdolecek 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
1.2 cgd 229:
1.4 jdolecek 230: #if 0
1.2 cgd 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: }
1.4 jdolecek 238: #endif
1.1 jdolecek 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: {
1.18 fvdl 247: if (ih == 0 || ih >= NUM_LEGACY_IRQS || ih == 2)
1.15 provos 248: panic("mca_intr_establish: bogus handle 0x%x", ih);
1.1 jdolecek 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: {
1.17 christos 259: isa_intr_disestablish(NULL, cookie);
1.1 jdolecek 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:
1.19 ! fvdl 277: /* if there is no MCA bus, call x86_nmi() */
1.1 jdolecek 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 */
1.11 jdolecek 285: for(slot=0; slot<MCA_MAX_SLOTS; slot++) {
1.1 jdolecek 286: outb(MCA_ADAP_SETUP_REG, slot | MCA_ADAP_SET);
1.11 jdolecek 287: if ((inb(MCA_POS_REG(5)) & MCA_POS5_CHCK) == 0) {
1.1 jdolecek 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 */
1.19 ! fvdl 303: return (x86_nmi());
1.1 jdolecek 304: } else
305: return(0);
306: }
307:
1.7 jdolecek 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: */
1.1 jdolecek 319: void
320: mca_busprobe()
321: {
322: struct bioscallregs regs;
1.7 jdolecek 323: struct bios_config *scp;
1.1 jdolecek 324: paddr_t paddr;
1.7 jdolecek 325: char buf[50];
1.1 jdolecek 326:
327: memset(®s, 0, sizeof(regs));
1.7 jdolecek 328: regs.AH = 0xc0;
1.1 jdolecek 329: bioscall(0x15, ®s);
330:
1.7 jdolecek 331: if ((regs.EFLAGS & PSL_C) || regs.AH != 0) {
332: #ifdef DEBUG
333: printf("BIOS CFG: Not supported. Not AT-compatible?\n");
1.1 jdolecek 334: #endif
335: return;
336: }
1.7 jdolecek 337:
1.1 jdolecek 338: paddr = (regs.ES << 4) + regs.BX;
1.7 jdolecek 339: scp = (struct bios_config *)ISA_HOLE_VADDR(paddr);
1.1 jdolecek 340:
1.7 jdolecek 341: #if 1 /* MCAVERBOSE */
1.11 jdolecek 342: bitmask_snprintf(((scp->feature2 & 1)<< 8) | scp->feature1,
1.3 jdolecek 343: "\20"
1.9 jdolecek 344: "\01MCA+ISA"
345: "\02MCA"
1.3 jdolecek 346: "\03EBDA"
347: "\04WAITEV"
348: "\05KBDINT"
349: "\06RTC"
1.5 jdolecek 350: "\07IC2"
1.11 jdolecek 351: "\010DMA3B"
352: "\011DMA32\n",
1.3 jdolecek 353: buf, sizeof(buf));
1.9 jdolecek 354:
1.11 jdolecek 355: printf("BIOS CFG: Model-SubM-Rev: %02x-%02x-%02x, 0x%s\n",
1.9 jdolecek 356: scp->model, scp->submodel, scp->bios_rev, buf);
1.1 jdolecek 357: #endif
358:
1.7 jdolecek 359: MCA_system = (scp->feature1 & FEATURE_MCABUS) ? 1 : 0;
1.6 jdolecek 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);
1.11 jdolecek 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: {
1.19 ! fvdl 447: struct x86_isa_dma_cookie *cookie;
1.11 jdolecek 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: */
1.12 jdolecek 457: if ((map->_dm_flags & _MCABUS_DMA_USEDMACTRL) == 0)
1.11 jdolecek 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:
1.19 ! fvdl 467: cookie = (struct x86_isa_dma_cookie *)map->_dm_cookie;
1.11 jdolecek 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;
1.12 jdolecek 476: if (map->_dm_flags & MCABUS_DMA_IOPORT)
477: mode |= DMACMD_MODE_IOPORT;
1.11 jdolecek 478:
1.13 jdolecek 479: /* Use 16bit DMA if requested */
1.12 jdolecek 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
1.11 jdolecek 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. */
1.12 jdolecek 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);
1.11 jdolecek 502:
503: /* Set the address byte pointer. */
1.12 jdolecek 504: bus_space_write_1(dmaiot, dmacmdh, 0, DMACMD_SET_ADDR | dmach);
1.11 jdolecek 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 */
1.12 jdolecek 513: bus_space_write_1(dmaiot, dmacmdh, 0, DMACMD_SET_CNT | dmach);
1.11 jdolecek 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. */
1.12 jdolecek 520: bus_space_write_1(dmaiot, dmacmdh, 0, DMACMD_RESET_MASK | dmach);
1.11 jdolecek 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;
1.19 ! fvdl 535: struct x86_isa_dma_cookie *cookie;
1.11 jdolecek 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",
1.14 sommerfe 547: (long) size);
1.11 jdolecek 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 */
1.19 ! fvdl 559: cookie = (struct x86_isa_dma_cookie *) (*dmamp)->_dm_cookie;
1.11 jdolecek 560: cookie->id_flags &= 0x0f;
561: cookie->id_flags |= dmach << 4;
562:
1.12 jdolecek 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;
1.11 jdolecek 569:
570: return (0);
1.12 jdolecek 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 */
1.13 jdolecek 586: bus_space_write_1(dmaiot, dmacmdh, 0, DMACMD_SET_IO | dma);
1.12 jdolecek 587: bus_space_write_1(dmaiot, dmaexech, 0, port & 0xff);
1.13 jdolecek 588: bus_space_write_1(dmaiot, dmaexech, 0, (port >> 8) & 0xff);
1.12 jdolecek 589:
590: /* Enable access to dma channel. */
591: bus_space_write_1(dmaiot, dmacmdh, 0, DMACMD_RESET_MASK | dma);
1.1 jdolecek 592: }
CVSweb <webmaster@jp.NetBSD.org>