[BACK]Return to mca_machdep.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / sys / arch / i386 / mca

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(&regs, 0, sizeof(regs));
1.7       jdolecek  328:        regs.AH = 0xc0;
1.1       jdolecek  329:        bioscall(0x15, &regs);
                    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>