Date: Mon, 18 Nov 2019 18:40:36 +0000 (UTC) From: Kyle Evans <kevans@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r354823 - head/sys/arm/broadcom/bcm2835 Message-ID: <201911181840.xAIIeaTe050946@repo.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: kevans Date: Mon Nov 18 18:40:35 2019 New Revision: 354823 URL: https://svnweb.freebsd.org/changeset/base/354823 Log: bcm2835_sdhci: push DATA_END handling out of DMA interrupt path This simplifies the DMA interrupt handler quite a bit. The sdhci framework will call platform_finish_transfer() if it's received SDHCI_INT_DATA_END, so we can take care of any final cleanup there and simply not worry about the possibility of it ending in the DMA interrupt path. Modified: head/sys/arm/broadcom/bcm2835/bcm2835_sdhci.c Modified: head/sys/arm/broadcom/bcm2835/bcm2835_sdhci.c ============================================================================== --- head/sys/arm/broadcom/bcm2835/bcm2835_sdhci.c Mon Nov 18 18:34:23 2019 (r354822) +++ head/sys/arm/broadcom/bcm2835/bcm2835_sdhci.c Mon Nov 18 18:40:35 2019 (r354823) @@ -167,6 +167,8 @@ bcm_sdhci_dmacb(void *arg, bus_dma_segment_t *segs, in struct bcm_sdhci_softc *sc = arg; int i; + /* Sanity check: we can only ever have one mapping at a time. */ + KASSERT(sc->dmamap_seg_count == 0, ("leaked DMA segment")); sc->dmamap_status = err; sc->dmamap_seg_count = nseg; @@ -546,8 +548,8 @@ bcm_sdhci_start_dma_seg(struct bcm_sdhci_softc *sc) */ if (idx == 0) { bus_dmamap_sync(sc->sc_dma_tag, sc->sc_dma_map, sync_op); - slot->intmask &= ~(SDHCI_INT_DATA_AVAIL | - SDHCI_INT_SPACE_AVAIL | SDHCI_INT_DATA_END); + slot->intmask &= ~(SDHCI_INT_DATA_AVAIL | + SDHCI_INT_SPACE_AVAIL); bcm_sdhci_write_4(sc->sc_dev, &sc->sc_slot, SDHCI_SIGNAL_ENABLE, slot->intmask); } @@ -572,8 +574,6 @@ bcm_sdhci_dma_intr(int ch, void *arg) if (slot->curcmd == NULL) { mtx_unlock(&slot->mtx); - device_printf(sc->sc_dev, - "command aborted in the middle of DMA\n"); return; } @@ -595,12 +595,15 @@ bcm_sdhci_dma_intr(int ch, void *arg) sync_op = BUS_DMASYNC_POSTWRITE; mask = SDHCI_INT_SPACE_AVAIL; } - bus_dmamap_sync(sc->sc_dma_tag, sc->sc_dma_map, sync_op); - bus_dmamap_unload(sc->sc_dma_tag, sc->sc_dma_map); - sc->dmamap_seg_count = 0; - sc->dmamap_seg_index = 0; + if (sc->dmamap_seg_count != 0) { + bus_dmamap_sync(sc->sc_dma_tag, sc->sc_dma_map, sync_op); + bus_dmamap_unload(sc->sc_dma_tag, sc->sc_dma_map); + sc->dmamap_seg_count = 0; + sc->dmamap_seg_index = 0; + } + left = min(BCM_SDHCI_BUFFER_SIZE, slot->curcmd->data->len - slot->offset); @@ -612,57 +615,40 @@ bcm_sdhci_dma_intr(int ch, void *arg) */ if (left < BCM_SDHCI_BUFFER_SIZE) { /* Re-enable data interrupts. */ - slot->intmask |= SDHCI_INT_DATA_AVAIL | SDHCI_INT_SPACE_AVAIL | - SDHCI_INT_DATA_END; + slot->intmask |= SDHCI_INT_DATA_AVAIL | SDHCI_INT_SPACE_AVAIL; bcm_sdhci_write_4(slot->bus, slot, SDHCI_SIGNAL_ENABLE, slot->intmask); mtx_unlock(&slot->mtx); return; } - /* DATA END? */ reg = bcm_sdhci_read_4(slot->bus, slot, SDHCI_INT_STATUS); - if (reg & SDHCI_INT_DATA_END) { - /* ACK for all outstanding interrupts */ - bcm_sdhci_write_4(slot->bus, slot, SDHCI_INT_STATUS, reg); + /* already available? */ + if (reg & mask) { - /* enable INT */ - slot->intmask |= SDHCI_INT_DATA_AVAIL | SDHCI_INT_SPACE_AVAIL - | SDHCI_INT_DATA_END; - bcm_sdhci_write_4(slot->bus, slot, SDHCI_SIGNAL_ENABLE, - slot->intmask); + /* ACK for DATA_AVAIL or SPACE_AVAIL */ + bcm_sdhci_write_4(slot->bus, slot, + SDHCI_INT_STATUS, mask); - /* finish this data */ - sdhci_finish_data(slot); - } - else { - /* already available? */ - if (reg & mask) { - - /* ACK for DATA_AVAIL or SPACE_AVAIL */ - bcm_sdhci_write_4(slot->bus, slot, - SDHCI_INT_STATUS, mask); - - /* continue next DMA transfer */ - if (bus_dmamap_load(sc->sc_dma_tag, sc->sc_dma_map, - (uint8_t *)slot->curcmd->data->data + - slot->offset, left, bcm_sdhci_dmacb, sc, - BUS_DMA_NOWAIT) != 0 || sc->dmamap_status != 0) { - slot->curcmd->error = MMC_ERR_NO_MEMORY; - sdhci_finish_data(slot); - } else { - bcm_sdhci_start_dma_seg(sc); - } + /* continue next DMA transfer */ + if (bus_dmamap_load(sc->sc_dma_tag, sc->sc_dma_map, + (uint8_t *)slot->curcmd->data->data + + slot->offset, left, bcm_sdhci_dmacb, sc, + BUS_DMA_NOWAIT) != 0 || sc->dmamap_status != 0) { + slot->curcmd->error = MMC_ERR_NO_MEMORY; + sdhci_finish_data(slot); } else { - /* wait for next data by INT */ - - /* enable INT */ - slot->intmask |= SDHCI_INT_DATA_AVAIL | - SDHCI_INT_SPACE_AVAIL | SDHCI_INT_DATA_END; - bcm_sdhci_write_4(slot->bus, slot, SDHCI_SIGNAL_ENABLE, - slot->intmask); + bcm_sdhci_start_dma_seg(sc); } + } else { + /* wait for next data by INT */ + + /* enable INT */ + slot->intmask |= SDHCI_INT_DATA_AVAIL | + SDHCI_INT_SPACE_AVAIL; + bcm_sdhci_write_4(slot->bus, slot, SDHCI_SIGNAL_ENABLE, + slot->intmask); } mtx_unlock(&slot->mtx); @@ -674,6 +660,7 @@ bcm_sdhci_read_dma(device_t dev, struct sdhci_slot *sl struct bcm_sdhci_softc *sc = device_get_softc(slot->bus); size_t left; + /* XXX TODO: Not many-segment safe */ if (sc->dmamap_seg_count != 0) { device_printf(sc->sc_dev, "DMA in use\n"); return; @@ -703,6 +690,7 @@ bcm_sdhci_write_dma(device_t dev, struct sdhci_slot *s struct bcm_sdhci_softc *sc = device_get_softc(slot->bus); size_t left; + /* XXX TODO: Not many-segment safe */ if (sc->dmamap_seg_count != 0) { device_printf(sc->sc_dev, "DMA in use\n"); return; @@ -764,7 +752,30 @@ bcm_sdhci_start_transfer(device_t dev, struct sdhci_sl static void bcm_sdhci_finish_transfer(device_t dev, struct sdhci_slot *slot) { + struct bcm_sdhci_softc *sc = device_get_softc(slot->bus); + /* Clean up */ + if (sc->dmamap_seg_count != 0) { + if (slot->curcmd->data->flags & MMC_DATA_READ) + bus_dmamap_sync(sc->sc_dma_tag, sc->sc_dma_map, + BUS_DMASYNC_POSTREAD); + else + bus_dmamap_sync(sc->sc_dma_tag, sc->sc_dma_map, + BUS_DMASYNC_POSTWRITE); + bus_dmamap_unload(sc->sc_dma_tag, sc->sc_dma_map); + + sc->dmamap_seg_count = 0; + sc->dmamap_seg_index = 0; + + slot->intmask |= SDHCI_INT_DATA_AVAIL | + SDHCI_INT_SPACE_AVAIL; + bcm_sdhci_write_4(slot->bus, slot, SDHCI_SIGNAL_ENABLE, + slot->intmask); + } else { + KASSERT((slot->intmask & SDHCI_INT_DATA_AVAIL) != 0 && + (slot->intmask & SDHCI_INT_SPACE_AVAIL) != 0, + ("%s: interrupt mask not restored", __func__)); + } sdhci_finish_data(slot); }
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201911181840.xAIIeaTe050946>