diff options
author | ian <ian@FreeBSD.org> | 2015-01-11 21:25:03 +0000 |
---|---|---|
committer | ian <ian@FreeBSD.org> | 2015-01-11 21:25:03 +0000 |
commit | 3dadde38236c8d1c3515accb0f46af07669139e3 (patch) | |
tree | 508b6e43a4cc2b73edfa1a1111990a3b0770d4cc /sys/dev | |
parent | b0834e310346ec43d73c6e2957c9decffa3708b6 (diff) | |
download | FreeBSD-src-3dadde38236c8d1c3515accb0f46af07669139e3.zip FreeBSD-src-3dadde38236c8d1c3515accb0f46af07669139e3.tar.gz |
Handle the possibility that SDHCI_PLATFORM_START_TRANSFER() can fail, by
moving the handling of curcmd->error != 0 to the end of the interrupt
handler. Also make sdhci_finish_data() idempotent by moving the setting
of slot->data_done = 1 down past the point where the busdma buffer is
unmapped. This allows for the possibility that the finish routine can
get called from multiple places when handling errors.
Diffstat (limited to 'sys/dev')
-rw-r--r-- | sys/dev/sdhci/sdhci.c | 20 |
1 files changed, 12 insertions, 8 deletions
diff --git a/sys/dev/sdhci/sdhci.c b/sys/dev/sdhci/sdhci.c index 98861ab6..272a8f4 100644 --- a/sys/dev/sdhci/sdhci.c +++ b/sys/dev/sdhci/sdhci.c @@ -984,7 +984,6 @@ sdhci_finish_data(struct sdhci_slot *slot) { struct mmc_data *data = slot->curcmd->data; - slot->data_done = 1; /* Interrupt aggregation: Restore command interrupt. * Auxiliary restore point for the case when data interrupt * happened first. */ @@ -993,7 +992,7 @@ sdhci_finish_data(struct sdhci_slot *slot) slot->intmask |= SDHCI_INT_RESPONSE); } /* Unload rest of data from DMA buffer. */ - if (slot->flags & SDHCI_USE_DMA) { + if (!slot->data_done && (slot->flags & SDHCI_USE_DMA)) { if (data->flags & MMC_DATA_READ) { size_t left = data->len - slot->offset; bus_dmamap_sync(slot->dmatag, slot->dmamap, @@ -1004,6 +1003,7 @@ sdhci_finish_data(struct sdhci_slot *slot) bus_dmamap_sync(slot->dmatag, slot->dmamap, BUS_DMASYNC_POSTWRITE); } + slot->data_done = 1; /* If there was error - reset the host. */ if (slot->curcmd->error) { sdhci_reset(slot, SDHCI_RESET_CMD); @@ -1171,12 +1171,7 @@ sdhci_data_irq(struct sdhci_slot *slot, uint32_t intmask) } if (slot->curcmd->error) { /* No need to continue after any error. */ - if (slot->flags & PLATFORM_DATA_STARTED) { - slot->flags &= ~PLATFORM_DATA_STARTED; - SDHCI_PLATFORM_FINISH_TRANSFER(slot->bus, slot); - } else - sdhci_finish_data(slot); - return; + goto done; } /* Handle PIO interrupt. */ @@ -1233,6 +1228,15 @@ sdhci_data_irq(struct sdhci_slot *slot, uint32_t intmask) } else sdhci_finish_data(slot); } +done: + if (slot->curcmd != NULL && slot->curcmd->error != 0) { + if (slot->flags & PLATFORM_DATA_STARTED) { + slot->flags &= ~PLATFORM_DATA_STARTED; + SDHCI_PLATFORM_FINISH_TRANSFER(slot->bus, slot); + } else + sdhci_finish_data(slot); + return; + } } static void |