diff options
author | Michael Shalayeff <mickey@cvs.openbsd.org> | 2001-09-15 01:51:12 +0000 |
---|---|---|
committer | Michael Shalayeff <mickey@cvs.openbsd.org> | 2001-09-15 01:51:12 +0000 |
commit | 30f56e676fcfe49de9e3435f2ddfdf2723c5c03d (patch) | |
tree | 6fde76c2e106c044f8bc32d5c2f78215fafe64ff | |
parent | 8877bda2bffd55a0089a40ee6f6b9dd149f958ac (diff) |
reimplement dbdma such that it does memory allocations
w/ bus_dma(9) and rework drivers accordingly.
make drivers use bus_dma as well, except for if_bm (later ;) .
additionally, sync wdc_obio w/ netbsd.
drahn@ ok, tested by miod@, pval@, brad@, mickey@
-rw-r--r-- | sys/arch/macppc/dev/awacs.c | 222 | ||||
-rw-r--r-- | sys/arch/macppc/dev/dbdma.c | 132 | ||||
-rw-r--r-- | sys/arch/macppc/dev/dbdma.h | 68 | ||||
-rw-r--r-- | sys/arch/macppc/dev/if_bm.c | 25 | ||||
-rw-r--r-- | sys/arch/macppc/dev/mesh.c | 102 | ||||
-rw-r--r-- | sys/arch/macppc/dev/wdc_obio.c | 327 |
6 files changed, 550 insertions, 326 deletions
diff --git a/sys/arch/macppc/dev/awacs.c b/sys/arch/macppc/dev/awacs.c index 2aafa374511..22fe2927aff 100644 --- a/sys/arch/macppc/dev/awacs.c +++ b/sys/arch/macppc/dev/awacs.c @@ -1,4 +1,4 @@ -/* $OpenBSD: awacs.c,v 1.3 2001/09/11 20:05:24 miod Exp $ */ +/* $OpenBSD: awacs.c,v 1.4 2001/09/15 01:51:11 mickey Exp $ */ /* $NetBSD: awacs.c,v 1.4 2001/02/26 21:07:51 wiz Exp $ */ /*- @@ -32,17 +32,13 @@ #include <sys/device.h> #include <sys/malloc.h> #include <sys/systm.h> -#include <sys/types.h> #include <dev/auconv.h> #include <dev/audio_if.h> #include <dev/mulaw.h> -#include <vm/vm.h> -#include <uvm/uvm.h> - +#include <machine/bus.h> #include <machine/autoconf.h> -#include <machine/pio.h> #include <macppc/dev/dbdma.h> #ifdef AWACS_DEBUG @@ -51,12 +47,24 @@ # define DPRINTF while (0) printf #endif +#define AWACS_DMALIST_MAX 32 +#define AWACS_DMASEG_MAX NBPG + +struct awacs_dma { + bus_dmamap_t map; + caddr_t addr; + bus_dma_segment_t segs[AWACS_DMALIST_MAX]; + int nsegs; + size_t size; + struct awacs_dma *next; +}; + + struct awacs_softc { struct device sc_dev; void (*sc_ointr)(void *); /* dma completion intr handler */ void *sc_oarg; /* arg for sc_ointr() */ - int sc_opages; /* # of output pages */ void (*sc_iintr)(void *); /* dma completion intr handler */ void *sc_iarg; /* arg for sc_iintr() */ @@ -71,10 +79,14 @@ struct awacs_softc { u_int sc_codecctl4; u_int sc_soundctl; + bus_dma_tag_t sc_dmat; struct dbdma_regmap *sc_odma; struct dbdma_regmap *sc_idma; - struct dbdma_command *sc_odmacmd; - struct dbdma_command *sc_idmacmd; + struct dbdma_command *sc_odmacmd, *sc_odmap; + struct dbdma_command *sc_idmacmd, *sc_idmap; + dbdma_t sc_odbdma, sc_idbdma; + + struct awacs_dma *sc_dmas; }; int awacs_match(struct device *, void *, void *); @@ -102,6 +114,7 @@ int awacs_query_devinfo(void *, mixer_devinfo_t *); size_t awacs_round_buffersize(void *, int, size_t); int awacs_mappage(void *, void *, int, int); int awacs_get_props(void *); +void *awacs_allocm __P((void *, int, size_t, int, int)); static inline u_int awacs_read_reg(struct awacs_softc *, int); static inline void awacs_write_reg(struct awacs_softc *, int, int); @@ -122,31 +135,31 @@ struct cfdriver awacs_cd = { struct audio_hw_if awacs_hw_if = { awacs_open, awacs_close, - NULL, + NULL, /* drain */ awacs_query_encoding, awacs_set_params, awacs_round_blocksize, - NULL, - NULL, - NULL, - NULL, - NULL, + NULL, /* commit_setting */ + NULL, /* init_output */ + NULL, /* init_input */ + NULL, /* start_output */ + NULL, /* start_input */ awacs_halt_output, awacs_halt_input, - NULL, + NULL, /* speaker_ctl */ awacs_getdev, - NULL, + NULL, /* getfd */ awacs_set_port, awacs_get_port, awacs_query_devinfo, - NULL, - NULL, - NULL, + NULL, /* allocm_old */ + NULL, /* freem */ + NULL, /* round_buffersize_old */ awacs_mappage, awacs_get_props, awacs_trigger_output, awacs_trigger_input, - NULL, + awacs_allocm, awacs_round_buffersize, }; @@ -255,10 +268,13 @@ awacs_attach(parent, self, aux) sc->sc_reg = mapiodev(ca->ca_reg[0], ca->ca_reg[1]); + sc->sc_dmat = ca->ca_dmat; sc->sc_odma = mapiodev(ca->ca_reg[2], ca->ca_reg[3]); /* out */ sc->sc_idma = mapiodev(ca->ca_reg[4], ca->ca_reg[5]); /* in */ - sc->sc_odmacmd = dbdma_alloc(20 * sizeof(struct dbdma_command)); - sc->sc_idmacmd = dbdma_alloc(20 * sizeof(struct dbdma_command)); + sc->sc_odbdma = dbdma_alloc(sc->sc_dmat, AWACS_DMALIST_MAX); + sc->sc_odmacmd = sc->sc_odbdma->d_addr; + sc->sc_idbdma = dbdma_alloc(sc->sc_dmat, AWACS_DMALIST_MAX); + sc->sc_idmacmd = sc->sc_idbdma->d_addr; if (ca->ca_nintr == 24) { cirq = ca->ca_intr[0]; @@ -406,29 +422,35 @@ awacs_intr(v) awacs_write_reg(sc, AWACS_SOUND_CTRL, reason); /* clear interrupt */ return 1; } + int awacs_tx_intr(v) void *v; { struct awacs_softc *sc = v; - struct dbdma_command *cmd = sc->sc_odmacmd; - int count = sc->sc_opages; - int status; - - /* Fill used buffer(s). */ - while (count-- > 0) { - /* if DBDMA_INT_ALWAYS */ - if (in16rb(&cmd->d_command) & 0x30) { /* XXX */ - status = in16rb(&cmd->d_status); - cmd->d_status = 0; - if (status) /* status == 0x8400 */ - if (sc->sc_ointr) - (*sc->sc_ointr)(sc->sc_oarg); - } - cmd++; + struct dbdma_command *cmd = sc->sc_odmap; + u_int16_t c, status; + + /* if not set we are not running */ + if (!cmd) + return (0); + + c = in16rb(&cmd->d_command); + status = in16rb(&cmd->d_status); + + if (c >> 12 == DBDMA_CMD_OUT_LAST) + sc->sc_odmap = sc->sc_odmacmd; + else + sc->sc_odmap++; + + if (c & (DBDMA_INT_ALWAYS << 4)) { + cmd->d_status = 0; + if (status) /* status == 0x8400 */ + if (sc->sc_ointr) + (*sc->sc_ointr)(sc->sc_oarg); } - return 1; + return (1); } int @@ -614,9 +636,9 @@ awacs_round_blocksize(h, size) void *h; int size; { - if (size < NBPG) - size = NBPG; - return size & ~PGOFSET; + if (size < PAGE_SIZE) + size = PAGE_SIZE; + return (size + PAGE_SIZE / 2) & ~(PGOFSET); } int @@ -628,6 +650,7 @@ awacs_halt_output(h) dbdma_stop(sc->sc_odma); dbdma_reset(sc->sc_odma); dbdma_stop(sc->sc_odma); + sc->sc_odmap = NULL; return 0; } @@ -900,9 +923,77 @@ awacs_round_buffersize(h, dir, size) int dir; size_t size; { - if (size > 65536) - size = 65536; - return size; + size = (size + PGOFSET) & ~(PGOFSET); + if (size > AWACS_DMALIST_MAX * AWACS_DMASEG_MAX) + size = AWACS_DMALIST_MAX * AWACS_DMASEG_MAX; + return (size); +} + +void * +awacs_allocm(h, dir, size, type, flags) + void *h; + int dir, type, flags; + size_t size; +{ + struct awacs_softc *sc = h; + struct awacs_dma *p; + int error; + + if (size > AWACS_DMALIST_MAX * AWACS_DMASEG_MAX) + return (NULL); + + p = malloc(sizeof(*p), type, flags); + if (!p) + return (NULL); + bzero(p, sizeof(*p)); + + /* convert to the bus.h style, not used otherwise */ + if (flags & M_NOWAIT) + flags = BUS_DMA_NOWAIT; + + p->size = size; + if ((error = bus_dmamem_alloc(sc->sc_dmat, p->size, NBPG, 0, p->segs, + 1, &p->nsegs, flags)) != 0) { + printf("%s: unable to allocate dma, error = %d\n", + sc->sc_dev.dv_xname, error); + free(p, type); + return NULL; + } + + if ((error = bus_dmamem_map(sc->sc_dmat, p->segs, p->nsegs, p->size, + &p->addr, flags | BUS_DMA_COHERENT)) != 0) { + printf("%s: unable to map dma, error = %d\n", + sc->sc_dev.dv_xname, error); + bus_dmamem_free(sc->sc_dmat, p->segs, p->nsegs); + free(p, type); + return NULL; + } + + if ((error = bus_dmamap_create(sc->sc_dmat, p->size, 1, + p->size, 0, flags, &p->map)) != 0) { + printf("%s: unable to create dma map, error = %d\n", + sc->sc_dev.dv_xname, error); + bus_dmamem_unmap(sc->sc_dmat, p->addr, size); + bus_dmamem_free(sc->sc_dmat, p->segs, p->nsegs); + free(p, type); + return NULL; + } + + if ((error = bus_dmamap_load(sc->sc_dmat, p->map, p->addr, p->size, + NULL, flags)) != 0) { + printf("%s: unable to load dma map, error = %d\n", + sc->sc_dev.dv_xname, error); + bus_dmamap_destroy(sc->sc_dmat, p->map); + bus_dmamem_unmap(sc->sc_dmat, p->addr, size); + bus_dmamem_free(sc->sc_dmat, p->segs, p->nsegs); + free(p, type); + return NULL; + } + + p->next = sc->sc_dmas; + sc->sc_dmas = p; + + return p->addr; } int @@ -934,43 +1025,38 @@ awacs_trigger_output(h, start, end, bsize, intr, arg, param) struct audio_params *param; { struct awacs_softc *sc = h; + struct awacs_dma *p; struct dbdma_command *cmd = sc->sc_odmacmd; - vaddr_t va; - int i, len, intmode; + vaddr_t spa, pa, epa; + int c; DPRINTF("trigger_output %p %p 0x%x\n", start, end, bsize); + for (p = sc->sc_dmas; p && p->addr != start; p = p->next); + if (!p) + return -1; + sc->sc_ointr = intr; sc->sc_oarg = arg; - sc->sc_opages = ((char *)end - (char *)start) / NBPG; + sc->sc_odmap = sc->sc_odmacmd; -#ifdef DIAGNOSTIC - if (sc->sc_opages > 16) - panic("awacs_trigger_output"); -#endif + spa = p->segs[0].ds_addr; + c = DBDMA_CMD_OUT_MORE; + for (pa = spa, epa = spa + (end - start); + pa < epa; pa += bsize, cmd++) { - va = (vaddr_t)start; - len = 0; - for (i = sc->sc_opages; i > 0; i--) { - len += NBPG; - if (len < bsize) - intmode = DBDMA_INT_NEVER; - else { - len = 0; - intmode = DBDMA_INT_ALWAYS; - } + if (pa + bsize == epa) + c = DBDMA_CMD_OUT_LAST; - DBDMA_BUILD(cmd, DBDMA_CMD_OUT_MORE, 0, NBPG, vtophys(va), - intmode, DBDMA_WAIT_NEVER, DBDMA_BRANCH_NEVER); - va += NBPG; - cmd++; + DBDMA_BUILD(cmd, c, 0, bsize, pa, DBDMA_INT_ALWAYS, + DBDMA_WAIT_NEVER, DBDMA_BRANCH_NEVER); } DBDMA_BUILD(cmd, DBDMA_CMD_NOP, 0, 0, 0, DBDMA_INT_NEVER, DBDMA_WAIT_NEVER, DBDMA_BRANCH_ALWAYS); - dbdma_st32(&cmd->d_cmddep, vtophys((vaddr_t)sc->sc_odmacmd)); + dbdma_st32(&cmd->d_cmddep, sc->sc_odbdma->d_paddr); - dbdma_start(sc->sc_odma, sc->sc_odmacmd); + dbdma_start(sc->sc_odma, sc->sc_odbdma); return 0; } diff --git a/sys/arch/macppc/dev/dbdma.c b/sys/arch/macppc/dev/dbdma.c index 388e834082e..e936ad7a2e1 100644 --- a/sys/arch/macppc/dev/dbdma.c +++ b/sys/arch/macppc/dev/dbdma.c @@ -1,26 +1,26 @@ -/* $OpenBSD: dbdma.c,v 1.2 2001/09/01 17:43:09 drahn Exp $ */ +/* $OpenBSD: dbdma.c,v 1.3 2001/09/15 01:51:11 mickey Exp $ */ /* $NetBSD: dbdma.c,v 1.2 1998/08/21 16:13:28 tsubai Exp $ */ /* - * Copyright 1991-1998 by Open Software Foundation, Inc. - * All Rights Reserved - * - * Permission to use, copy, modify, and distribute this software and - * its documentation for any purpose and without fee is hereby granted, - * provided that the above copyright notice appears in all copies and - * that both the copyright notice and this permission notice appear in - * supporting documentation. - * - * OSF DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE - * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE. - * - * IN NO EVENT SHALL OSF BE LIABLE FOR ANY SPECIAL, INDIRECT, OR - * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM - * LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT, - * NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION - * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - * + * Copyright 1991-1998 by Open Software Foundation, Inc. + * All Rights Reserved + * + * Permission to use, copy, modify, and distribute this software and + * its documentation for any purpose and without fee is hereby granted, + * provided that the above copyright notice appears in all copies and + * that both the copyright notice and this permission notice appear in + * supporting documentation. + * + * OSF DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL OSF BE LIABLE FOR ANY SPECIAL, INDIRECT, OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT, + * NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION + * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * */ #include <sys/param.h> @@ -29,39 +29,35 @@ #include <vm/vm.h> -#include <machine/pio.h> +#include <machine/bus.h> #include <macppc/dev/dbdma.h> - - dbdma_command_t *dbdma_alloc_commands = NULL; void -dbdma_start(dmap, commands) +dbdma_start(dmap, dt) dbdma_regmap_t *dmap; - dbdma_command_t *commands; + dbdma_t dt; { - u_int32_t addr = vtophys((vaddr_t)commands); - - if (addr & 0xf) - panic("dbdma_start command structure not 16-byte aligned"); - - DBDMA_ST4_ENDIAN(&dmap->d_intselect, DBDMA_CLEAR_CNTRL( (0xffff))); - DBDMA_ST4_ENDIAN(&dmap->d_control, - DBDMA_CLEAR_CNTRL( (DBDMA_CNTRL_ACTIVE | - DBDMA_CNTRL_DEAD | - DBDMA_CNTRL_WAKE | - DBDMA_CNTRL_FLUSH | - DBDMA_CNTRL_PAUSE | - DBDMA_CNTRL_RUN ))); - + u_int32_t addr = dt->d_paddr; + + DBDMA_ST4_ENDIAN(&dmap->d_intselect, DBDMA_CLEAR_CNTRL((0xffff))); + DBDMA_ST4_ENDIAN(&dmap->d_control, DBDMA_CLEAR_CNTRL(( + DBDMA_CNTRL_ACTIVE | + DBDMA_CNTRL_DEAD | + DBDMA_CNTRL_WAKE | + DBDMA_CNTRL_FLUSH | + DBDMA_CNTRL_PAUSE | + DBDMA_CNTRL_RUN))); + + /* XXX time-bind it? */ do { delay(10); } while (DBDMA_LD4_ENDIAN(&dmap->d_status) & DBDMA_CNTRL_ACTIVE); - + DBDMA_ST4_ENDIAN(&dmap->d_cmdptrhi, 0); /* 64-bit not yet */ - DBDMA_ST4_ENDIAN(&dmap->d_cmdptrlo, addr); + DBDMA_ST4_ENDIAN(&dmap->d_cmdptrlo, addr); DBDMA_ST4_ENDIAN(&dmap->d_control, DBDMA_SET_CNTRL(DBDMA_CNTRL_RUN|DBDMA_CNTRL_WAKE)| @@ -85,6 +81,7 @@ dbdma_flush(dmap) { DBDMA_ST4_ENDIAN(&dmap->d_control, DBDMA_SET_CNTRL(DBDMA_CNTRL_FLUSH)); + /* XXX time-bind it? */ while (DBDMA_LD4_ENDIAN(&dmap->d_status) & (DBDMA_CNTRL_FLUSH)); } @@ -92,14 +89,15 @@ void dbdma_reset(dmap) dbdma_regmap_t *dmap; { - DBDMA_ST4_ENDIAN(&dmap->d_control, + DBDMA_ST4_ENDIAN(&dmap->d_control, DBDMA_CLEAR_CNTRL( (DBDMA_CNTRL_ACTIVE | DBDMA_CNTRL_DEAD | DBDMA_CNTRL_WAKE | DBDMA_CNTRL_FLUSH | DBDMA_CNTRL_PAUSE | - DBDMA_CNTRL_RUN ))); + DBDMA_CNTRL_RUN ))); + /* XXX time-bind it? */ while (DBDMA_LD4_ENDIAN(&dmap->d_status) & DBDMA_CNTRL_RUN); } @@ -118,18 +116,46 @@ dbdma_pause(dmap) { DBDMA_ST4_ENDIAN(&dmap->d_control,DBDMA_SET_CNTRL(DBDMA_CNTRL_PAUSE)); - while (DBDMA_LD4_ENDIAN(&dmap->d_status) & DBDMA_CNTRL_ACTIVE) - ; + /* XXX time-bind it? */ + while (DBDMA_LD4_ENDIAN(&dmap->d_status) & DBDMA_CNTRL_ACTIVE); } -dbdma_command_t * -dbdma_alloc(size) +dbdma_t +dbdma_alloc(dmat, size) + bus_dma_tag_t dmat; int size; { - u_int buf; - - buf = (u_int)malloc(size + 0x0f, M_DEVBUF, M_WAITOK); - buf = (buf + 0x0f) & ~0x0f; - - return (dbdma_command_t *)buf; + dbdma_t dt; + int error, nsegs = 0; + + dt = malloc(sizeof *dt, M_DEVBUF, M_NOWAIT); + if (!dt) + return (dt); + bzero(dt, sizeof *dt); + + dt->d_size = size *= sizeof(dbdma_command_t); + if ((error = bus_dmamem_alloc(dmat, size, NBPG, 0, dt->d_segs, + 1, &nsegs, BUS_DMA_NOWAIT)) != 0) { + printf("dbdma: unable to allocate dma, error = %d\n", error); + } else if ((error = bus_dmamem_map(dmat, dt->d_segs, nsegs, size, + (caddr_t *)&dt->d_addr, BUS_DMA_NOWAIT | BUS_DMA_COHERENT)) != 0) { + printf("dbdma: unable to map dma, error = %d\n", error); + } else if ((error = bus_dmamap_create(dmat, dt->d_size, 1, + dt->d_size, 0, BUS_DMA_NOWAIT, &dt->d_map)) != 0) { + printf("dbdma: unable to create dma map, error = %d\n", error); + } else if ((error = bus_dmamap_load_raw(dmat, dt->d_map, + dt->d_segs, nsegs, size, BUS_DMA_NOWAIT)) != 0) { + printf("dbdma: unable to load dma map, error = %d\n", error); + } else + return dt; + + if (dt->d_map) + bus_dmamap_destroy(dmat, dt->d_map); + if (dt->d_addr) + bus_dmamem_unmap(dmat, (caddr_t)dt->d_addr, size); + if (nsegs) + bus_dmamem_free(dmat, dt->d_segs, nsegs); + free(dt, M_DEVBUF); + + return (NULL); } diff --git a/sys/arch/macppc/dev/dbdma.h b/sys/arch/macppc/dev/dbdma.h index eb386cd1a82..ca1bd8b9ec7 100644 --- a/sys/arch/macppc/dev/dbdma.h +++ b/sys/arch/macppc/dev/dbdma.h @@ -1,26 +1,26 @@ -/* $OpenBSD: dbdma.h,v 1.1 2001/09/01 15:50:00 drahn Exp $ */ +/* $OpenBSD: dbdma.h,v 1.2 2001/09/15 01:51:11 mickey Exp $ */ /* $NetBSD: dbdma.h,v 1.2 1998/08/21 16:13:28 tsubai Exp $ */ /* - * Copyright 1991-1998 by Open Software Foundation, Inc. - * All Rights Reserved - * - * Permission to use, copy, modify, and distribute this software and - * its documentation for any purpose and without fee is hereby granted, - * provided that the above copyright notice appears in all copies and - * that both the copyright notice and this permission notice appear in - * supporting documentation. - * - * OSF DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE - * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE. - * - * IN NO EVENT SHALL OSF BE LIABLE FOR ANY SPECIAL, INDIRECT, OR - * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM - * LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT, - * NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION - * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - * + * Copyright 1991-1998 by Open Software Foundation, Inc. + * All Rights Reserved + * + * Permission to use, copy, modify, and distribute this software and + * its documentation for any purpose and without fee is hereby granted, + * provided that the above copyright notice appears in all copies and + * that both the copyright notice and this permission notice appear in + * supporting documentation. + * + * OSF DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL OSF BE LIABLE FOR ANY SPECIAL, INDIRECT, OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT, + * NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION + * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * */ #include "machine/pio.h" @@ -95,6 +95,7 @@ #define DBDMA_SET_CNTRL(x) ( ((x) | (x) << 16) ) #define DBDMA_CLEAR_CNTRL(x) ( (x) << 16) +#define DBDMA_COUNT_MAX 0x8000 #define DBDMA_REGMAP(channel) \ (dbdma_regmap_t *)((v_u_char *) POWERMAC_IO(PCI_DMA_BASE_PHYS) \ @@ -179,11 +180,11 @@ dbdma_ld16(a) return swap; } -#define DBDMA_LD4_ENDIAN(a) dbdma_ld32(a) -#define DBDMA_ST4_ENDIAN(a, x) dbdma_st32(a, x) +#define DBDMA_LD4_ENDIAN(a) dbdma_ld32(a) +#define DBDMA_ST4_ENDIAN(a, x) dbdma_st32(a, x) #else -#define DBDMA_LD4_ENDIAN(a) in32rb(a) -#define DBDMA_ST4_ENDIAN(a, x) out32rb(a, x) +#define DBDMA_LD4_ENDIAN(a) in32rb(a) +#define DBDMA_ST4_ENDIAN(a, x) out32rb(a, x) #define dbdma_st16(a,x) out16rb((a),(x)) #define dbdma_ld16(a) in16rb(a) #define dbdma_st32(a,x) out32rb((a),(x)) @@ -194,7 +195,7 @@ dbdma_ld16(a) /* * DBDMA Channel layout * - * NOTE - This structure is in little-endian format. + * NOTE - This structure is in little-endian format. */ struct dbdma_regmap { @@ -217,14 +218,23 @@ struct dbdma_regmap { typedef volatile struct dbdma_regmap dbdma_regmap_t; /* DBDMA routines */ - -void dbdma_start(dbdma_regmap_t *channel, dbdma_command_t *commands); -void dbdma_stop(dbdma_regmap_t *channel); +typedef +struct dbdma_desc { + bus_dmamap_t d_map; + dbdma_command_t *d_addr; +#define d_paddr d_segs->ds_addr + bus_dma_segment_t d_segs[1]; + size_t d_size; +} *dbdma_t; + +dbdma_t dbdma_alloc(bus_dma_tag_t, int); /* Allocate command structures */ +void dbdma_free(dbdma_t); /* Dispose command structures */ +void dbdma_start(dbdma_regmap_t *channel, dbdma_t dt); +void dbdma_stop(dbdma_regmap_t *channel); void dbdma_flush(dbdma_regmap_t *channel); void dbdma_reset(dbdma_regmap_t *channel); void dbdma_continue(dbdma_regmap_t *channel); void dbdma_pause(dbdma_regmap_t *channel); -dbdma_command_t *dbdma_alloc(int); /* Allocate command structures */ #endif /* !defined(_POWERMAC_DBDMA_H_) */ diff --git a/sys/arch/macppc/dev/if_bm.c b/sys/arch/macppc/dev/if_bm.c index 2e89ebb790e..640047ab794 100644 --- a/sys/arch/macppc/dev/if_bm.c +++ b/sys/arch/macppc/dev/if_bm.c @@ -1,4 +1,4 @@ -/* $OpenBSD: if_bm.c,v 1.2 2001/09/01 17:43:09 drahn Exp $ */ +/* $OpenBSD: if_bm.c,v 1.3 2001/09/15 01:51:11 mickey Exp $ */ /* $NetBSD: if_bm.c,v 1.1 1999/01/01 01:27:52 tsubai Exp $ */ /*- @@ -54,8 +54,8 @@ #include <dev/ofw/openfirm.h> +#include <machine/bus.h> #include <machine/autoconf.h> -#include <machine/pio.h> #include <macppc/dev/dbdma.h> #include <macppc/dev/if_bmreg.h> @@ -77,10 +77,10 @@ struct bmac_softc { #endif struct ifmedia sc_media; vaddr_t sc_regs; - dbdma_regmap_t *sc_txdma; - dbdma_regmap_t *sc_rxdma; - dbdma_command_t *sc_txcmd; - dbdma_command_t *sc_rxcmd; + bus_dma_tag_t sc_dmat; + dbdma_regmap_t *sc_txdma, *sc_rxdma; + dbdma_command_t *sc_txcmd, *sc_rxcmd; + dbdma_t sc_rxdbdma, sc_txdbdma; caddr_t sc_txbuf; caddr_t sc_rxbuf; int sc_rxlast; @@ -215,10 +215,13 @@ bmac_attach(parent, self, aux) } bcopy(laddr, sc->arpcom.ac_enaddr, 6); + sc->sc_dmat = ca->ca_dmat; sc->sc_txdma = mapiodev(ca->ca_reg[2], 0x100); sc->sc_rxdma = mapiodev(ca->ca_reg[4], 0x100); - sc->sc_txcmd = dbdma_alloc(BMAC_TXBUFS * sizeof(dbdma_command_t)); - sc->sc_rxcmd = dbdma_alloc((BMAC_RXBUFS + 1) * sizeof(dbdma_command_t)); + sc->sc_txdbdma = dbdma_alloc(sc->sc_dmat, BMAC_TXBUFS); + sc->sc_txcmd = sc->sc_txdbdma->d_addr; + sc->sc_rxdbdma = dbdma_alloc(sc->sc_dmat, BMAC_RXBUFS + 1); + sc->sc_rxcmd = sc->sc_rxdbdma->d_addr; sc->sc_txbuf = malloc(BMAC_BUFLEN * BMAC_TXBUFS, M_DEVBUF, M_NOWAIT); sc->sc_rxbuf = malloc(BMAC_BUFLEN * BMAC_RXBUFS, M_DEVBUF, M_NOWAIT); if (sc->sc_txbuf == NULL || sc->sc_rxbuf == NULL || @@ -411,11 +414,11 @@ bmac_init_dma(sc) } DBDMA_BUILD(cmd, DBDMA_CMD_NOP, 0, 0, 0, DBDMA_INT_NEVER, DBDMA_WAIT_NEVER, DBDMA_BRANCH_ALWAYS); - dbdma_st32(&cmd->d_cmddep, vtophys((vaddr_t)sc->sc_rxcmd)); + dbdma_st32(&cmd->d_cmddep, sc->sc_rxdbdma->d_paddr); sc->sc_rxlast = 0; - dbdma_start(sc->sc_rxdma, sc->sc_rxcmd); + dbdma_start(sc->sc_rxdma, sc->sc_rxdbdma); } #ifdef WHY_IS_THIS_XXXX @@ -650,7 +653,7 @@ bmac_transmit_packet(sc, buff, len) DBDMA_BUILD(cmd, DBDMA_CMD_STOP, 0, 0, 0, DBDMA_INT_ALWAYS, DBDMA_WAIT_NEVER, DBDMA_BRANCH_NEVER); - dbdma_start(sc->sc_txdma, sc->sc_txcmd); + dbdma_start(sc->sc_txdma, sc->sc_txdbdma); } int diff --git a/sys/arch/macppc/dev/mesh.c b/sys/arch/macppc/dev/mesh.c index 3b08fdde4e0..f5437892893 100644 --- a/sys/arch/macppc/dev/mesh.c +++ b/sys/arch/macppc/dev/mesh.c @@ -1,4 +1,4 @@ -/* $OpenBSD: mesh.c,v 1.1 2001/09/01 15:50:00 drahn Exp $ */ +/* $OpenBSD: mesh.c,v 1.2 2001/09/15 01:51:11 mickey Exp $ */ /* $NetBSD: mesh.c,v 1.1 1999/02/19 13:06:03 tsubai Exp $ */ /*- @@ -53,13 +53,11 @@ #include "scsipi/scsiconf.h" #include "scsipi/scsi_message.h"*/ - - #include <dev/ofw/openfirm.h> +#include <machine/bus.h> #include <machine/autoconf.h> #include <machine/cpu.h> -#include <machine/pio.h> #include "dbdma.h" #include "meshreg.h" @@ -67,8 +65,6 @@ #define T_SYNCMODE 0x01 /* target uses sync mode */ #define T_SYNCNEGO 0x02 /* sync negotiation done */ - - struct mesh_tinfo { int flags; int period; @@ -97,14 +93,18 @@ struct mesh_scb { /* sc_flags value */ #define MESH_DMA_ACTIVE 0x01 +#define MESH_DMALIST_MAX 32 + struct mesh_softc { struct device sc_dev; /* us as a device */ struct scsi_link sc_link; struct scsi_adapter sc_adapter; u_char *sc_reg; /* MESH base address */ + bus_dma_tag_t sc_dmat; dbdma_regmap_t *sc_dmareg; /* DMA register address */ dbdma_command_t *sc_dmacmd; /* DMA command area */ + dbdma_t sc_dbdma; int sc_flags; int sc_cfflags; /* copy of config flags */ @@ -154,8 +154,8 @@ void mesh_error __P((struct mesh_softc *, struct mesh_scb *, int, int)); void mesh_select __P((struct mesh_softc *, struct mesh_scb *)); void mesh_identify __P((struct mesh_softc *, struct mesh_scb *)); void mesh_command __P((struct mesh_softc *, struct mesh_scb *)); -void mesh_dma_setup __P((struct mesh_softc *, struct mesh_scb *)); -void mesh_dataio __P((struct mesh_softc *, struct mesh_scb *)); +int mesh_dma_setup __P((struct mesh_softc *, struct mesh_scb *)); +int mesh_dataio __P((struct mesh_softc *, struct mesh_scb *)); void mesh_status __P((struct mesh_softc *, struct mesh_scb *)); void mesh_msgin __P((struct mesh_softc *, struct mesh_scb *)); void mesh_msgout __P((struct mesh_softc *, int)); @@ -228,7 +228,7 @@ mesh_attach(parent, self, aux) { struct mesh_softc *sc = (void *)self; struct confargs *ca = aux; - int i; + int i, error; u_int *reg; printf("MESH_ATTACH called\n"); @@ -252,6 +252,15 @@ mesh_attach(parent, self, aux) printf(": cannot get clock-frequency\n"); return; } + + sc->sc_dmat = ca->ca_dmat; + if ((error = bus_dmamap_create(sc->sc_dmat, + MESH_DMALIST_MAX * DBDMA_COUNT_MAX, MESH_DMALIST_MAX, + DBDMA_COUNT_MAX, NBPG, BUS_DMA_NOWAIT, &sc->sc_dmamap)) != 0) { + printf(": cannot create dma map, error = %d\n", error); + return; + } + sc->sc_freq /= 1000000; /* in MHz */ sc->sc_minsync = 25; /* maximum sync rate = 10MB/sec */ sc->sc_id = 7; @@ -261,7 +270,8 @@ mesh_attach(parent, self, aux) for (i = 0; i < sizeof(sc->sc_scb)/sizeof(sc->sc_scb[0]); i++) TAILQ_INSERT_TAIL(&sc->free_scb, &sc->sc_scb[i], chain); - sc->sc_dmacmd = dbdma_alloc(sizeof(dbdma_command_t) * 20); + sc->sc_dbdma = dbdma_alloc(sc->sc_dmat, MESH_DMALIST_MAX); + sc->sc_dmacmd = sc->sc_dbdma->d_addr; timeout_set(&sc->sc_tmo, mesh_timeout, scb); mesh_reset(sc); @@ -363,6 +373,7 @@ mesh_intr(arg) if (sc->sc_flags & MESH_DMA_ACTIVE) { dbdma_stop(sc->sc_dmareg); + bus_dmamap_unload(sc->sc_dmat, sc->sc_dmamap); sc->sc_flags &= ~MESH_DMA_ACTIVE; scb->resid = MESH_GET_XFER(sc); @@ -411,7 +422,8 @@ mesh_intr(arg) break; case MESH_DATAIN: case MESH_DATAOUT: - mesh_dataio(sc, scb); + if (mesh_dataio(sc, scb)) + return (1); printf("mesh_intr:case MESH_DATAIN or MESH_DATAOUT\n"); break; case MESH_STATUS: @@ -548,7 +560,7 @@ mesh_command(sc, scb) sc->sc_nextstate = MESH_DATAIN; } -void +int mesh_dma_setup(sc, scb) struct mesh_softc *sc; struct mesh_scb *scb; @@ -557,72 +569,52 @@ mesh_dma_setup(sc, scb) int datain = scb->flags & MESH_READ; dbdma_command_t *cmdp; u_int cmd; - vaddr_t va; - int count, offset; + int i, error; + + if ((error = bus_dmamap_load(sc->dmat, sc->sc_dmamap, scb->daddr, + scb->dlen, NULL, BUS_DMA_NOWAIT)) != 0) + return (error); cmdp = sc->sc_dmacmd; cmd = datain ? DBDMA_CMD_IN_MORE : DBDMA_CMD_OUT_MORE; - count = scb->dlen; - - if (count / NBPG > 32) - panic("mesh: transfer size >= 128k"); - - va = scb->daddr; - offset = va & PGOFSET; - - /* if va is not page-aligned, setup the first page */ - if (offset != 0) { - int rest = NBPG - offset; /* the rest in the page */ - - if (count > rest) { /* if continues to next page */ - DBDMA_BUILD(cmdp, cmd, 0, rest, vtophys(va), - DBDMA_INT_NEVER, DBDMA_WAIT_NEVER, - DBDMA_BRANCH_NEVER); - count -= rest; - va += rest; - cmdp++; - } - } - - /* now va is page-aligned */ - while (count > NBPG) { - DBDMA_BUILD(cmdp, cmd, 0, NBPG, vtophys(va), + for (i = 0; i < sc->sc_dmamap->dm_nsegs; i++, cmdp++) { + if (i + 1 == sc->sc_dmamap->dm_nsegs) + cmd = read ? DBDMA_CMD_IN_LAST : DBDMA_CMD_OUT_LAST; + DBDMA_BUILD(cmdp, cmd, 0, sc->sc_dmamap->dm_segs[i].ds_len, + sc->sc_dmamap->dm_segs[i].ds_addr, DBDMA_INT_NEVER, DBDMA_WAIT_NEVER, DBDMA_BRANCH_NEVER); - count -= NBPG; - va += NBPG; - cmdp++; } - /* the last page (count <= NBPG here) */ - cmd = datain ? DBDMA_CMD_IN_LAST : DBDMA_CMD_OUT_LAST; - DBDMA_BUILD(cmdp, cmd , 0, count, vtophys(va), - DBDMA_INT_NEVER, DBDMA_WAIT_NEVER, DBDMA_BRANCH_NEVER); - cmdp++; - DBDMA_BUILD(cmdp, DBDMA_CMD_STOP, 0, 0, 0, DBDMA_INT_NEVER, DBDMA_WAIT_NEVER, DBDMA_BRANCH_NEVER); + + return (0); } -void +int mesh_dataio(sc, scb) struct mesh_softc *sc; struct mesh_scb *scb; { - mesh_dma_setup(sc, scb); + int error; + + if ((error = mesh_dma_setup(sc, scb))) + return (error); if (scb->dlen == 65536) MESH_SET_XFER(sc, 0); /* TC = 0 means 64KB transfer */ else MESH_SET_XFER(sc, scb->dlen); - if (scb->flags & MESH_READ) - mesh_set_reg(sc, MESH_SEQUENCE, MESH_CMD_DATAIN | MESH_SEQ_DMA); - else - mesh_set_reg(sc, MESH_SEQUENCE, MESH_CMD_DATAOUT | MESH_SEQ_DMA); - dbdma_start(sc->sc_dmareg, sc->sc_dmacmd); + mesh_set_reg(sc, MESH_SEQUENCE, MESH_SEQ_DMA | + (scb->flags & MESH_READ)? MESH_CMD_DATAIN : MESH_CMD_DATAOUT); + + dbdma_start(sc->sc_dmareg, sc->sc_dbdma); sc->sc_flags |= MESH_DMA_ACTIVE; sc->sc_nextstate = MESH_STATUS; + + return (0); } void diff --git a/sys/arch/macppc/dev/wdc_obio.c b/sys/arch/macppc/dev/wdc_obio.c index 58abac913d9..b7d81a99518 100644 --- a/sys/arch/macppc/dev/wdc_obio.c +++ b/sys/arch/macppc/dev/wdc_obio.c @@ -1,5 +1,5 @@ -/* $OpenBSD: wdc_obio.c,v 1.2 2001/09/01 17:43:09 drahn Exp $ */ -/* $NetBSD: wdc_obio.c,v 1.4 1999/06/14 08:53:06 tsubai Exp $ */ +/* $OpenBSD: wdc_obio.c,v 1.3 2001/09/15 01:51:11 mickey Exp $ */ +/* $NetBSD: wdc_obio.c,v 1.15 2001/07/25 20:26:33 bouyer Exp $ */ /*- * Copyright (c) 1998 The NetBSD Foundation, Inc. @@ -61,27 +61,29 @@ #define WDC_OPTIONS_DMA 0x01 -/* - * XXX This code currently doesn't even try to allow 32-bit data port use. - */ +#define WDC_DMALIST_MAX 32 struct wdc_obio_softc { struct wdc_softc sc_wdcdev; struct channel_softc *wdc_chanptr; struct channel_softc wdc_channel; + + bus_dma_tag_t sc_dmat; + bus_dmamap_t sc_dmamap; dbdma_regmap_t *sc_dmareg; dbdma_command_t *sc_dmacmd; + dbdma_t sc_dbdma; }; u_int8_t wdc_obio_read_reg __P((struct channel_softc *, enum wdc_regs)); void wdc_obio_write_reg __P((struct channel_softc *, enum wdc_regs, u_int8_t)); -void wdc_default_read_raw_multi_2 __P((struct channel_softc *, +void wdc_default_read_raw_multi_2 __P((struct channel_softc *, void *, unsigned int)); -void wdc_default_write_raw_multi_2 __P((struct channel_softc *, +void wdc_default_write_raw_multi_2 __P((struct channel_softc *, void *, unsigned int)); -void wdc_default_read_raw_multi_4 __P((struct channel_softc *, +void wdc_default_read_raw_multi_4 __P((struct channel_softc *, void *, unsigned int)); -void wdc_default_write_raw_multi_4 __P((struct channel_softc *, +void wdc_default_write_raw_multi_4 __P((struct channel_softc *, void *, unsigned int)); struct channel_softc_vtbl wdc_obio_vtbl = { wdc_obio_read_reg, @@ -99,17 +101,11 @@ struct cfattach wdc_obio_ca = { sizeof(struct wdc_obio_softc), wdc_obio_probe, wdc_obio_attach }; -#if 0 -struct cfdriver wdc_cd = { - NULL, "wdc", DV_DULL -}; -#endif - - -static int wdc_obio_dma_init __P((void *, int, int, void *, size_t, int)); -static void wdc_obio_dma_start __P((void *, int, int)); -static int wdc_obio_dma_finish __P((void *, int, int)); -static void adjust_timing __P((struct channel_softc *)); +int wdc_obio_dma_init __P((void *, int, int, void *, size_t, int)); +void wdc_obio_dma_start __P((void *, int, int)); +int wdc_obio_dma_finish __P((void *, int, int)); +void wdc_obio_adjust_timing __P((struct channel_softc *)); +void wdc_obio_ata4_adjust_timing __P((struct channel_softc *)); int wdc_obio_probe(parent, match, aux) @@ -143,8 +139,7 @@ wdc_obio_attach(parent, self, aux) struct wdc_obio_softc *sc = (void *)self; struct confargs *ca = aux; struct channel_softc *chp = &sc->wdc_channel; - int intr; - int use_dma = 1; + int intr, error, use_dma = 0; bus_addr_t cmdbase; bus_size_t cmdsize; @@ -153,6 +148,14 @@ wdc_obio_attach(parent, self, aux) use_dma = 1; /* XXX Don't work yet. */ } + sc->sc_dmat = ca->ca_dmat; + if ((error = bus_dmamap_create(sc->sc_dmat, + WDC_DMALIST_MAX * DBDMA_COUNT_MAX, WDC_DMALIST_MAX, + DBDMA_COUNT_MAX, NBPG, BUS_DMA_NOWAIT, &sc->sc_dmamap)) != 0) { + printf(": cannot create dma map, error = %d\n", error); + return; + } + if (ca->ca_nintr >= 4 && ca->ca_nreg >= 8) { intr = ca->ca_intr[0]; printf(" irq %d", intr); @@ -189,14 +192,23 @@ wdc_obio_attach(parent, self, aux) mac_intr_establish(parent, intr, IST_LEVEL, IPL_BIO, wdcintr, chp, "wdc_obio"); + sc->sc_wdcdev.set_modes = wdc_obio_adjust_timing; if (use_dma) { - sc->sc_dmacmd = dbdma_alloc(sizeof(dbdma_command_t) * 20); + sc->sc_dbdma = dbdma_alloc(sc->sc_dmat, WDC_DMALIST_MAX + 1); + sc->sc_dmacmd = sc->sc_dbdma->d_addr; sc->sc_dmareg = mapiodev(ca->ca_baseaddr + ca->ca_reg[2], ca->ca_reg[3]); - sc->sc_wdcdev.cap |= WDC_CAPABILITY_DMA|WDC_CAPABILITY_UDMA; + sc->sc_wdcdev.cap |= WDC_CAPABILITY_DMA; + sc->sc_wdcdev.DMA_cap = 2; + if (strcmp(ca->ca_name, "ata-4") == 0) { + sc->sc_wdcdev.cap |= WDC_CAPABILITY_UDMA | + WDC_CAPABILITY_MODE; + sc->sc_wdcdev.UDMA_cap = 4; + sc->sc_wdcdev.set_modes = wdc_obio_ata4_adjust_timing; + } } sc->sc_wdcdev.cap |= WDC_CAPABILITY_DATA16; - sc->sc_wdcdev.PIO_cap = 0; + sc->sc_wdcdev.PIO_cap = 4; sc->wdc_chanptr = chp; sc->sc_wdcdev.channels = &sc->wdc_chanptr; sc->sc_wdcdev.nchannels = 1; @@ -215,81 +227,194 @@ wdc_obio_attach(parent, self, aux) } wdcattach(chp); - - /* modify DMA access timings */ - if (use_dma) - adjust_timing(chp); - + sc->sc_wdcdev.set_modes(chp); wdc_print_current_modes(chp); } /* Multiword DMA transfer timings */ -static struct { +struct ide_timings { int cycle; /* minimum cycle time [ns] */ int active; /* minimum command active time [ns] */ -} dma_timing[3] = { +}; + +static const struct ide_timings pio_timing[] = { + { 600, 165 }, /* Mode 0 */ + { 383, 125 }, /* 1 */ + { 240, 100 }, /* 2 */ + { 180, 80 }, /* 3 */ + { 120, 70 } /* 4 */ +}; + +static const struct ide_timings dma_timing[] = { { 480, 215 }, /* Mode 0 */ { 150, 80 }, /* Mode 1 */ { 120, 70 }, /* Mode 2 */ }; -#define TIME_TO_TICK(time) howmany((time), 30) +static const struct ide_timings udma_timing[] = { + {114, 0}, /* Mode 0 */ + { 75, 0}, /* Mode 1 */ + { 55, 0}, /* Mode 2 */ + { 45, 100}, /* Mode 3 */ + { 25, 100} /* Mode 4 */ +}; + +#define TIME_TO_TICK(time) howmany((time), 30) +#define PIO_REC_OFFSET 4 +#define PIO_REC_MIN 1 +#define PIO_ACT_MIN 1 +#define DMA_REC_OFFSET 1 +#define DMA_REC_MIN 1 +#define DMA_ACT_MIN 1 + +#define ATA4_TIME_TO_TICK(time) howmany((time) * 1000, 7500) #define CONFIG_REG (0x200) /* IDE access timing register */ void -adjust_timing(chp) +wdc_obio_adjust_timing(chp) struct channel_softc *chp; { - struct ataparams params; - struct ata_drive_datas *drvp = &chp->ch_drive[0]; /* XXX */ + struct ata_drive_datas *drvp; u_int conf; - int mode; - int cycle, active, min_cycle, min_active; + int drive; + int piomode = -1, dmamode = -1; + int min_cycle, min_active; int cycle_tick, act_tick, inact_tick, half_tick; - if (ata_get_params(drvp, AT_POLL, ¶ms) != CMD_OK) - return; - - for (mode = 2; mode >= 0; mode--) - if (params.atap_dmamode_act & (1 << mode)) - goto found; - /* No active DMA mode is found... Do nothing. */ - return; - -found: - min_cycle = dma_timing[mode].cycle; - min_active = dma_timing[mode].active; - -#ifdef notyet - /* Minimum cycle time is 150ns on ohare. */ - if (ohare && params.atap_dmatiming_recom < 150) - params.atap_dmatiming_recom = 150; -#endif - cycle = max(min_cycle, params.atap_dmatiming_recom); - active = min_active + (cycle - min_cycle); /* XXX */ - - cycle_tick = TIME_TO_TICK(cycle); - act_tick = TIME_TO_TICK(active); - inact_tick = cycle_tick - act_tick - 1; - if (inact_tick < 1) - inact_tick = 1; - half_tick = 0; /* XXX */ + for (drive = 0; drive < 2; drive++) { + drvp = &chp->ch_drive[drive]; + if ((drvp->drive_flags & DRIVE) == 0) + continue; + if (piomode == -1 || piomode > drvp->PIO_mode) + piomode = drvp->PIO_mode; + if (drvp->drive_flags & DRIVE_DMA) { + if (dmamode == -1 || dmamode > drvp->DMA_mode) + dmamode = drvp->DMA_mode; + } + } + if (piomode == -1) + return; /* No drive */ + for (drive = 0; drive < 2; drive++) { + drvp = &chp->ch_drive[drive]; + if (drvp->drive_flags & DRIVE) { + drvp->PIO_mode = piomode; + if (drvp->drive_flags & DRIVE_DMA) + drvp->DMA_mode = dmamode; + } + } + min_cycle = pio_timing[piomode].cycle; + min_active = pio_timing[piomode].active; + + cycle_tick = TIME_TO_TICK(min_cycle); + act_tick = TIME_TO_TICK(min_active); + if (act_tick < PIO_ACT_MIN) + act_tick = PIO_ACT_MIN; + inact_tick = cycle_tick - act_tick - PIO_REC_OFFSET; + if (inact_tick < PIO_REC_MIN) + inact_tick = PIO_REC_MIN; + /* mask: 0x000007ff */ + conf = (inact_tick << 5) | act_tick; + if (dmamode != -1) { + /* there are active DMA mode */ + + min_cycle = dma_timing[dmamode].cycle; + min_active = dma_timing[dmamode].active; + cycle_tick = TIME_TO_TICK(min_cycle); + act_tick = TIME_TO_TICK(min_active); + inact_tick = cycle_tick - act_tick - DMA_REC_OFFSET; + if (inact_tick < DMA_REC_MIN) + inact_tick = DMA_REC_MIN; + half_tick = 0; /* XXX */ + /* mask: 0xfffff800 */ + conf |= + (half_tick << 21) | + (inact_tick << 16) | (act_tick << 11); + } + bus_space_write_4(chp->cmd_iot, chp->cmd_ioh, CONFIG_REG, conf); #if 0 - conf = bus_space_read_4(chp->cmd_iot, chp->cmd_ioh, CONFIG_REG); printf("conf = 0x%x, cyc = %d (%d ns), act = %d (%d ns), inact = %d\n", - conf, 0, 0, ((conf >> 11) & 0x1f), 0, ((conf >> 16) & 0x1f)); + conf, cycle_tick, min_cycle, act_tick, min_active, inact_tick); #endif - conf = (half_tick << 21) | (inact_tick << 16) | (act_tick << 11); +} + +void +wdc_obio_ata4_adjust_timing(chp) + struct channel_softc *chp; +{ + struct ata_drive_datas *drvp; + u_int conf; + int drive; + int piomode = -1, dmamode = -1; + int min_cycle, min_active; + int cycle_tick, act_tick, inact_tick; + int udmamode = -1; + + + for (drive = 0; drive < 2; drive++) { + drvp = &chp->ch_drive[drive]; + if ((drvp->drive_flags & DRIVE) == 0) + continue; + if (piomode == -1 || piomode > drvp->PIO_mode) + piomode = drvp->PIO_mode; + if (drvp->drive_flags & DRIVE_DMA) { + if (dmamode == -1 || dmamode > drvp->DMA_mode) + dmamode = drvp->DMA_mode; + } + if (drvp->drive_flags & DRIVE_UDMA) { + if (udmamode == -1 || udmamode > drvp->UDMA_mode) + udmamode = drvp->UDMA_mode; + } + } + if (piomode == -1) + return; /* No drive */ + for (drive = 0; drive < 2; drive++) { + drvp = &chp->ch_drive[drive]; + if (drvp->drive_flags & DRIVE) { + drvp->PIO_mode = piomode; + if (drvp->drive_flags & DRIVE_DMA) + drvp->DMA_mode = dmamode; + if (drvp->drive_flags & DRIVE_UDMA) + drvp->UDMA_mode = udmamode; + } + } + min_cycle = pio_timing[piomode].cycle; + min_active = pio_timing[piomode].active; + + cycle_tick = ATA4_TIME_TO_TICK(min_cycle); + act_tick = ATA4_TIME_TO_TICK(min_active); + inact_tick = cycle_tick - act_tick; + /* mask: 0x000003ff */ + conf = (inact_tick << 5) | act_tick; + if (dmamode != -1) { + /* there are active DMA mode */ + + min_cycle = dma_timing[dmamode].cycle; + min_active = dma_timing[dmamode].active; + cycle_tick = ATA4_TIME_TO_TICK(min_cycle); + act_tick = ATA4_TIME_TO_TICK(min_active); + inact_tick = cycle_tick - act_tick; + /* mask: 0x001ffc00 */ + conf |= (act_tick << 10) | (inact_tick << 15); + } + if (udmamode != -1) { + min_cycle = udma_timing[udmamode].cycle; + min_active = udma_timing[udmamode].active; + act_tick = ATA4_TIME_TO_TICK(min_active); + cycle_tick = ATA4_TIME_TO_TICK(min_cycle); + /* mask: 0x1ff00000 */ + conf |= (cycle_tick << 21) | (act_tick << 25) | 0x100000; + } + bus_space_write_4(chp->cmd_iot, chp->cmd_ioh, CONFIG_REG, conf); #if 0 - printf("conf = 0x%x, cyc = %d (%d ns), act = %d (%d ns), inact = %d\n", - conf, cycle_tick, cycle, act_tick, active, inact_tick); + printf("ata4 conf = 0x%x, cyc = %d (%d ns), act = %d (%d ns), inact = %d\n", + conf, cycle_tick, min_cycle, act_tick, min_active, inact_tick); #endif } -static int +int wdc_obio_dma_init(v, channel, drive, databuf, datalen, read) void *v; void *databuf; @@ -297,61 +422,42 @@ wdc_obio_dma_init(v, channel, drive, databuf, datalen, read) int read; { struct wdc_obio_softc *sc = v; - vaddr_t va = (vaddr_t)databuf; dbdma_command_t *cmdp; - u_int cmd, offset; + u_int cmd; + int i, error; + + if ((error = bus_dmamap_load(sc->sc_dmat, sc->sc_dmamap, databuf, + datalen, NULL, BUS_DMA_NOWAIT)) != 0) + return (error); cmdp = sc->sc_dmacmd; cmd = read ? DBDMA_CMD_IN_MORE : DBDMA_CMD_OUT_MORE; - offset = va & PGOFSET; - - /* if va is not page-aligned, setup the first page */ - if (offset != 0) { - int rest = NBPG - offset; /* the rest of the page */ - - if (datalen > rest) { /* if continues to next page */ - DBDMA_BUILD(cmdp, cmd, 0, rest, vtophys(va), - DBDMA_INT_NEVER, DBDMA_WAIT_NEVER, - DBDMA_BRANCH_NEVER); - datalen -= rest; - va += rest; - cmdp++; - } - } - - /* now va is page-aligned */ - while (datalen > NBPG) { - DBDMA_BUILD(cmdp, cmd, 0, NBPG, vtophys(va), - DBDMA_INT_NEVER, DBDMA_WAIT_NEVER, DBDMA_BRANCH_NEVER); - datalen -= NBPG; - va += NBPG; - cmdp++; + for (i = 0; i < sc->sc_dmamap->dm_nsegs; i++, cmdp++) { + if (i + 1 == sc->sc_dmamap->dm_nsegs) + cmd = read ? DBDMA_CMD_IN_LAST : DBDMA_CMD_OUT_LAST; + DBDMA_BUILD(cmdp, cmd, 0, sc->sc_dmamap->dm_segs[i].ds_len, + sc->sc_dmamap->dm_segs[i].ds_addr, + DBDMA_INT_NEVER, DBDMA_WAIT_NEVER, DBDMA_BRANCH_NEVER); } - /* the last page (datalen <= NBPG here) */ - cmd = read ? DBDMA_CMD_IN_LAST : DBDMA_CMD_OUT_LAST; - DBDMA_BUILD(cmdp, cmd, 0, datalen, vtophys(va), - DBDMA_INT_NEVER, DBDMA_WAIT_NEVER, DBDMA_BRANCH_NEVER); - cmdp++; - DBDMA_BUILD(cmdp, DBDMA_CMD_STOP, 0, 0, 0, DBDMA_INT_NEVER, DBDMA_WAIT_NEVER, DBDMA_BRANCH_NEVER); return 0; } -static void +void wdc_obio_dma_start(v, channel, drive) void *v; int channel, drive; { struct wdc_obio_softc *sc = v; - dbdma_start(sc->sc_dmareg, sc->sc_dmacmd); + dbdma_start(sc->sc_dmareg, sc->sc_dbdma); } -static int +int wdc_obio_dma_finish(v, channel, drive) void *v; int channel, drive; @@ -359,26 +465,27 @@ wdc_obio_dma_finish(v, channel, drive) struct wdc_obio_softc *sc = v; dbdma_stop(sc->sc_dmareg); + bus_dmamap_unload(sc->sc_dmat, sc->sc_dmamap); return 0; } /* read register code * this allows the registers to be spaced by 0x10, instead of 0x1. * mac hardware (obio) requires this. - */ + */ u_int8_t wdc_obio_read_reg(chp, reg) struct channel_softc *chp; enum wdc_regs reg; { -#ifdef DIAGNOSTIC +#ifdef DIAGNOSTIC if (reg & _WDC_WRONLY) { printf ("wdc_obio_read_reg: reading from a write-only register %d\n", reg); } #endif - if (reg & _WDC_AUX) + if (reg & _WDC_AUX) return (bus_space_read_1(chp->ctl_iot, chp->ctl_ioh, (reg & _WDC_REGMASK) << 4)); else @@ -393,13 +500,13 @@ wdc_obio_write_reg(chp, reg, val) enum wdc_regs reg; u_int8_t val; { -#ifdef DIAGNOSTIC +#ifdef DIAGNOSTIC if (reg & _WDC_RDONLY) { printf ("wdc_obio_write_reg: writing to a read-only register %d\n", reg); } #endif - if (reg & _WDC_AUX) + if (reg & _WDC_AUX) bus_space_write_1(chp->ctl_iot, chp->ctl_ioh, (reg & _WDC_REGMASK) << 4, val); else |