Index: sys/arch/arm/broadcom/bcm2835_emmc.c =================================================================== RCS file: /cvsroot/src/sys/arch/arm/broadcom/bcm2835_emmc.c,v retrieving revision 1.26 diff -u -r1.26 bcm2835_emmc.c --- sys/arch/arm/broadcom/bcm2835_emmc.c 3 Aug 2015 10:27:32 -0000 1.26 +++ sys/arch/arm/broadcom/bcm2835_emmc.c 9 Aug 2015 11:41:00 -0000 @@ -82,7 +82,7 @@ static void bcmemmc_attach_i(device_t); #if NBCMDMAC > 0 static int bcmemmc_xfer_data_dma(struct sdhc_softc *, struct sdmmc_command *); -static void bcmemmc_dma_done(void *); +static void bcmemmc_dma_done(uint32_t, uint32_t, void *); #endif CFATTACH_DECL_NEW(bcmemmc, sizeof(struct bcmemmc_softc), @@ -309,7 +309,10 @@ sc->sc_state = EMMC_DMA_STATE_BUSY; bcm_dmac_set_conblk_addr(sc->sc_dmac, sc->sc_dmamap->dm_segs[0].ds_addr); - bcm_dmac_transfer(sc->sc_dmac); + error = bcm_dmac_transfer(sc->sc_dmac); + if (error) + return error; + while (sc->sc_state == EMMC_DMA_STATE_BUSY) { error = cv_timedwait(&sc->sc_cv, plock, hz * 10); if (error == EWOULDBLOCK) { @@ -328,14 +331,19 @@ } static void -bcmemmc_dma_done(void *arg) +bcmemmc_dma_done(uint32_t status, uint32_t error, void *arg) { struct bcmemmc_softc * const sc = arg; kmutex_t *plock = sdhc_host_lock(sc->sc_hosts[0]); + if (status != (DMAC_CS_INT|DMAC_CS_END)) + device_printf(sc->sc.sc_dev, "status %#x error %#x\n", + status,error); + mutex_enter(plock); KASSERT(sc->sc_state == EMMC_DMA_STATE_BUSY); - sc->sc_state = EMMC_DMA_STATE_IDLE; + if (status & DMAC_CS_END) + sc->sc_state = EMMC_DMA_STATE_IDLE; cv_broadcast(&sc->sc_cv); mutex_exit(plock); } Index: sys/arch/arm/broadcom/bcm2835_dmac.c =================================================================== RCS file: /cvsroot/src/sys/arch/arm/broadcom/bcm2835_dmac.c,v retrieving revision 1.12 diff -u -r1.12 bcm2835_dmac.c --- sys/arch/arm/broadcom/bcm2835_dmac.c 2 Aug 2015 16:46:12 -0000 1.12 +++ sys/arch/arm/broadcom/bcm2835_dmac.c 9 Aug 2015 11:41:00 -0000 @@ -53,7 +53,7 @@ struct bcm_dmac_softc *ch_sc; void *ch_ih; uint8_t ch_index; - void (*ch_callback)(void *); + void (*ch_callback)(uint32_t, uint32_t, void *); void *ch_callbackarg; uint32_t ch_debug; }; @@ -165,23 +165,26 @@ { struct bcm_dmac_channel *ch = priv; struct bcm_dmac_softc *sc = ch->ch_sc; - uint32_t cs; + uint32_t cs, ce; cs = DMAC_READ(sc, DMAC_CS(ch->ch_index)); - if (!(cs & DMAC_CS_INTMASK)) - return 0; - DMAC_WRITE(sc, DMAC_CS(ch->ch_index), cs); + cs &= DMAC_CS_INT | DMAC_CS_END | DMAC_CS_ERROR; + + ce = DMAC_READ(sc, DMAC_DEBUG(ch->ch_index)); + ce &= DMAC_DEBUG_READ_ERROR | DMAC_DEBUG_FIFO_ERROR + | DMAC_DEBUG_READ_LAST_NOT_SET_ERROR; + DMAC_WRITE(sc, DMAC_DEBUG(ch->ch_index), ce); if (ch->ch_callback) - ch->ch_callback(ch->ch_callbackarg); + ch->ch_callback(cs, ce, ch->ch_callbackarg); return 1; } struct bcm_dmac_channel * -bcm_dmac_alloc(enum bcm_dmac_type type, int ipl, void (*cb)(void *), - void *cbarg) +bcm_dmac_alloc(enum bcm_dmac_type type, int ipl, + void (*cb)(uint32_t, uint32_t, void *), void *cbarg) { struct bcm_dmac_softc *sc; struct bcm_dmac_channel *ch = NULL; @@ -234,9 +237,9 @@ bcm_dmac_halt(ch); + /* reset chip */ val = DMAC_READ(sc, DMAC_CS(ch->ch_index)); val |= DMAC_CS_RESET; - val |= DMAC_CS_ABORT; val &= ~DMAC_CS_ACTIVE; DMAC_WRITE(sc, DMAC_CS(ch->ch_index), val); @@ -276,9 +279,21 @@ bcm_dmac_halt(struct bcm_dmac_channel *ch) { struct bcm_dmac_softc *sc = ch->ch_sc; + uint32_t val; - DMAC_WRITE(sc, DMAC_CS(ch->ch_index), DMAC_CS_RESET|DMAC_CS_ABORT); - bcm_dmac_set_conblk_addr(ch, 0); + /* pause DMA */ + val = DMAC_READ(sc, DMAC_CS(ch->ch_index)); + val &= ~DMAC_CS_ACTIVE; + DMAC_WRITE(sc, DMAC_CS(ch->ch_index), val); + + /* wait for paused state ? */ + + /* end descriptor chain */ + DMAC_WRITE(sc, DMAC_NEXTCONBK(ch->ch_index), 0); + + /* resume DMA that then stops */ + val |= DMAC_CS_ACTIVE | DMAC_CS_ABORT; + DMAC_WRITE(sc, DMAC_CS(ch->ch_index), val); } #if defined(DDB) Index: sys/arch/arm/broadcom/bcm2835_dmac.h =================================================================== RCS file: /cvsroot/src/sys/arch/arm/broadcom/bcm2835_dmac.h,v retrieving revision 1.3 diff -u -r1.3 bcm2835_dmac.h --- sys/arch/arm/broadcom/bcm2835_dmac.h 12 Sep 2014 19:33:45 -0000 1.3 +++ sys/arch/arm/broadcom/bcm2835_dmac.h 9 Aug 2015 11:41:00 -0000 @@ -102,7 +102,7 @@ struct bcm_dmac_channel; struct bcm_dmac_channel *bcm_dmac_alloc(enum bcm_dmac_type, int, - void (*)(void *), void *); + void (*)(uint32_t, uint32_t, void *), void *); void bcm_dmac_free(struct bcm_dmac_channel *); void bcm_dmac_set_conblk_addr(struct bcm_dmac_channel *, bus_addr_t); int bcm_dmac_transfer(struct bcm_dmac_channel *);