diff options
author | Miod Vallat <miod@cvs.openbsd.org> | 2006-01-13 19:25:46 +0000 |
---|---|---|
committer | Miod Vallat <miod@cvs.openbsd.org> | 2006-01-13 19:25:46 +0000 |
commit | 03959db78243c44e5fb94b00244e5466c025c0af (patch) | |
tree | cf363aa2652deca96e666555598c48f6c15ef5f0 /sys | |
parent | 9b3ea61729df8fb14778b06dbbf377e15cf2f55e (diff) |
Allow proper detaching of wdc, so that detaching a mediabay device properly
releases resources and works as expected.
Thanks to Thomas Maschutznig for testing.
Diffstat (limited to 'sys')
-rw-r--r-- | sys/arch/macppc/dev/dbdma.c | 28 | ||||
-rw-r--r-- | sys/arch/macppc/dev/dbdma.h | 4 | ||||
-rw-r--r-- | sys/arch/macppc/dev/wdc_obio.c | 57 |
3 files changed, 64 insertions, 25 deletions
diff --git a/sys/arch/macppc/dev/dbdma.c b/sys/arch/macppc/dev/dbdma.c index c1142127299..d6622654072 100644 --- a/sys/arch/macppc/dev/dbdma.c +++ b/sys/arch/macppc/dev/dbdma.c @@ -1,4 +1,4 @@ -/* $OpenBSD: dbdma.c,v 1.7 2003/10/16 03:31:25 drahn Exp $ */ +/* $OpenBSD: dbdma.c,v 1.8 2006/01/13 19:25:44 miod Exp $ */ /* $NetBSD: dbdma.c,v 1.2 1998/08/21 16:13:28 tsubai Exp $ */ /* @@ -117,7 +117,7 @@ dbdma_t dbdma_alloc(bus_dma_tag_t dmat, int size) { dbdma_t dt; - int error, nsegs = 0; + int error; dt = malloc(sizeof *dt, M_DEVBUF, M_NOWAIT); if (!dt) @@ -125,28 +125,34 @@ dbdma_alloc(bus_dma_tag_t dmat, int size) bzero(dt, sizeof *dt); dt->d_size = size *= sizeof(dbdma_command_t); + dt->d_dmat = dmat; if ((error = bus_dmamem_alloc(dmat, size, NBPG, 0, dt->d_segs, - 1, &nsegs, BUS_DMA_NOWAIT)) != 0) { + 1, &dt->d_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, + } else if ((error = bus_dmamem_map(dmat, dt->d_segs, dt->d_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) { + dt->d_segs, dt->d_nsegs, size, BUS_DMA_NOWAIT)) != 0) { printf("dbdma: unable to load dma map, error = %d\n", error); } else return dt; + dbdma_free(dt); + return (NULL); +} + +void +dbdma_free(dbdma_t dt) +{ if (dt->d_map) - bus_dmamap_destroy(dmat, dt->d_map); + bus_dmamap_destroy(dt->d_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); + bus_dmamem_unmap(dt->d_dmat, (caddr_t)dt->d_addr, dt->d_size); + if (dt->d_nsegs) + bus_dmamem_free(dt->d_dmat, dt->d_segs, dt->d_nsegs); free(dt, M_DEVBUF); - - return (NULL); } diff --git a/sys/arch/macppc/dev/dbdma.h b/sys/arch/macppc/dev/dbdma.h index dad8dda54a4..922533017bc 100644 --- a/sys/arch/macppc/dev/dbdma.h +++ b/sys/arch/macppc/dev/dbdma.h @@ -1,4 +1,4 @@ -/* $OpenBSD: dbdma.h,v 1.3 2002/09/06 13:35:00 drahn Exp $ */ +/* $OpenBSD: dbdma.h,v 1.4 2006/01/13 19:25:44 miod Exp $ */ /* $NetBSD: dbdma.h,v 1.2 1998/08/21 16:13:28 tsubai Exp $ */ /* @@ -221,10 +221,12 @@ typedef volatile struct dbdma_regmap dbdma_regmap_t; /* DBDMA routines */ typedef struct dbdma_desc { + bus_dma_tag_t d_dmat; bus_dmamap_t d_map; dbdma_command_t *d_addr; #define d_paddr d_segs->ds_addr bus_dma_segment_t d_segs[1]; + int d_nsegs; size_t d_size; } *dbdma_t; diff --git a/sys/arch/macppc/dev/wdc_obio.c b/sys/arch/macppc/dev/wdc_obio.c index b96184253fd..0c7d9ab3af4 100644 --- a/sys/arch/macppc/dev/wdc_obio.c +++ b/sys/arch/macppc/dev/wdc_obio.c @@ -1,4 +1,4 @@ -/* $OpenBSD: wdc_obio.c,v 1.23 2004/10/17 08:58:56 grange Exp $ */ +/* $OpenBSD: wdc_obio.c,v 1.24 2006/01/13 19:25:45 miod Exp $ */ /* $NetBSD: wdc_obio.c,v 1.15 2001/07/25 20:26:33 bouyer Exp $ */ /*- @@ -73,6 +73,11 @@ struct wdc_obio_softc { dbdma_regmap_t *sc_dmareg; dbdma_command_t *sc_dmacmd; dbdma_t sc_dbdma; + + void *sc_ih; + int sc_use_dma; + bus_size_t sc_cmdsize; + size_t sc_dmasize; }; u_int8_t wdc_obio_read_reg(struct channel_softc *, enum wdc_regs); @@ -89,9 +94,11 @@ struct channel_softc_vtbl wdc_obio_vtbl = { int wdc_obio_probe(struct device *, void *, void *); void wdc_obio_attach(struct device *, struct device *, void *); +int wdc_obio_detach(struct device *, int); struct cfattach wdc_obio_ca = { - sizeof(struct wdc_obio_softc), wdc_obio_probe, wdc_obio_attach + sizeof(struct wdc_obio_softc), wdc_obio_probe, wdc_obio_attach, + wdc_obio_detach, wdcactivate }; int wdc_obio_dma_init(void *, int, int, void *, size_t, int); @@ -128,12 +135,12 @@ wdc_obio_attach(struct device *parent, struct device *self, void *aux) struct wdc_obio_softc *sc = (void *)self; struct confargs *ca = aux; struct channel_softc *chp = &sc->wdc_channel; - int intr, error, use_dma = 0; + int intr, error; bus_addr_t cmdbase; - bus_size_t cmdsize; + sc->sc_use_dma = 0; if (ca->ca_nreg >= 16 || ca->ca_nintr == -1) - use_dma = 1; /* Enable dma */ + sc->sc_use_dma = 1; /* Enable dma */ sc->sc_dmat = ca->ca_dmat; if ((error = bus_dmamap_create(sc->sc_dmat, @@ -154,7 +161,7 @@ wdc_obio_attach(struct device *parent, struct device *self, void *aux) return; } - if (use_dma) + if (sc->sc_use_dma) printf(": DMA"); printf("\n"); @@ -163,10 +170,10 @@ wdc_obio_attach(struct device *parent, struct device *self, void *aux) chp->_vtbl = &wdc_obio_vtbl; cmdbase = ca->ca_reg[0]; - cmdsize = ca->ca_reg[1]; + sc->sc_cmdsize = ca->ca_reg[1]; - if (bus_space_map(chp->cmd_iot, cmdbase, cmdsize, 0, &chp->cmd_ioh) || - bus_space_subregion(chp->cmd_iot, chp->cmd_ioh, + if (bus_space_map(chp->cmd_iot, cmdbase, sc->sc_cmdsize, 0, + &chp->cmd_ioh) || bus_space_subregion(chp->cmd_iot, chp->cmd_ioh, /* WDC_AUXREG_OFFSET<<4 */ 0x160, 1, &chp->ctl_ioh)) { printf("%s: couldn't map registers\n", sc->sc_wdcdev.sc_dev.dv_xname); @@ -175,16 +182,16 @@ wdc_obio_attach(struct device *parent, struct device *self, void *aux) chp->data32iot = chp->cmd_iot; chp->data32ioh = chp->cmd_ioh; - mac_intr_establish(parent, intr, IST_LEVEL, IPL_BIO, wdcintr, chp, - sc->sc_wdcdev.sc_dev.dv_xname); + sc->sc_ih = mac_intr_establish(parent, intr, IST_LEVEL, IPL_BIO, + wdcintr, chp, sc->sc_wdcdev.sc_dev.dv_xname); sc->sc_wdcdev.set_modes = wdc_obio_adjust_timing; - if (use_dma) { + if (sc->sc_use_dma) { 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_dmasize = ca->ca_reg[3]); sc->sc_wdcdev.cap |= WDC_CAPABILITY_DMA; sc->sc_wdcdev.DMA_cap = 2; @@ -226,6 +233,30 @@ wdc_obio_attach(struct device *parent, struct device *self, void *aux) wdc_print_current_modes(chp); } +int +wdc_obio_detach(struct device *self, int flags) +{ + struct wdc_obio_softc *sc = (struct wdc_obio_softc *)self; + struct channel_softc *chp = &sc->wdc_channel; + int error; + + if ((error = wdcdetach(chp, flags)) != 0) + return (error); + + free(chp->ch_queue, M_DEVBUF); + + if (sc->sc_use_dma) { + unmapiodev((void *)sc->sc_dmareg, sc->sc_dmasize); + dbdma_free(sc->sc_dbdma); + } + mac_intr_disestablish(NULL, sc->sc_ih); + + bus_space_unmap(chp->cmd_iot, chp->cmd_ioh, sc->sc_cmdsize); + bus_dmamap_destroy(sc->sc_dmat, sc->sc_dmamap); + + return (0); +} + /* Multiword DMA transfer timings */ struct ide_timings { int cycle; /* minimum cycle time [ns] */ |