summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Shalayeff <mickey@cvs.openbsd.org>2001-09-15 01:51:12 +0000
committerMichael Shalayeff <mickey@cvs.openbsd.org>2001-09-15 01:51:12 +0000
commit30f56e676fcfe49de9e3435f2ddfdf2723c5c03d (patch)
tree6fde76c2e106c044f8bc32d5c2f78215fafe64ff
parent8877bda2bffd55a0089a40ee6f6b9dd149f958ac (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.c222
-rw-r--r--sys/arch/macppc/dev/dbdma.c132
-rw-r--r--sys/arch/macppc/dev/dbdma.h68
-rw-r--r--sys/arch/macppc/dev/if_bm.c25
-rw-r--r--sys/arch/macppc/dev/mesh.c102
-rw-r--r--sys/arch/macppc/dev/wdc_obio.c327
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, &params) != 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