summaryrefslogtreecommitdiffstats
path: root/sys/dev/sdhci
diff options
context:
space:
mode:
authorian <ian@FreeBSD.org>2015-01-11 21:25:03 +0000
committerian <ian@FreeBSD.org>2015-01-11 21:25:03 +0000
commit3dadde38236c8d1c3515accb0f46af07669139e3 (patch)
tree508b6e43a4cc2b73edfa1a1111990a3b0770d4cc /sys/dev/sdhci
parentb0834e310346ec43d73c6e2957c9decffa3708b6 (diff)
downloadFreeBSD-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/sdhci')
-rw-r--r--sys/dev/sdhci/sdhci.c20
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
OpenPOWER on IntegriCloud