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);
 }
 
_______________________________________________
svn-src-all@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to