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.
This commit is contained in:
Ian Lepore 2015-01-11 21:25:03 +00:00
parent 5e3dbf8b9f
commit a98788edff
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=277027

View File

@ -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