Rather than rely on the DMA interrupt to determine that an ESP interrupt has occurred, poll the ESP interrupt register directly. This enables us to poll until one of the specified interrupts occurs.
Since an ESP interrupt can still be in a pending state before issuing an ESP command, read the ESP interrupt register beforehand to clear any pending interrupts.
Signed-off-by: Mark Cave-Ayland mark.cave-ayland@ilande.co.uk --- drivers/esp.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-)
diff --git a/drivers/esp.c b/drivers/esp.c index 95e969f..5c7ddb5 100644 --- a/drivers/esp.c +++ b/drivers/esp.c @@ -99,14 +99,14 @@ do_command(esp_private_t *esp, sd_private_t *sd, int cmdlen, int replylen) esp->espdma.regs->cond_reg = DMA_ENABLE; // Clear FIFO esp->ll->regs[ESP_CMD] = ESP_CMD_FLUSH; + // Clear pending interrupts + (void)esp->ll->regs[ESP_INTRPT]; // Set ATN, issue command esp->ll->regs[ESP_CMD] = ESP_CMD_SELA | ESP_CMD_DMA; - // Wait for DMA to complete. Can this fail? - while ((esp->espdma.regs->cond_reg & DMA_HNDL_INTR) == 0) /* no-op */; + // Wait for ESP to complete + while (!(esp->ll->regs[ESP_INTRPT] & (ESP_INTR_BSERV | ESP_INTR_FDONE | ESP_INTR_DC))); // Check status status = esp->ll->regs[ESP_STATUS]; - // Clear interrupts to avoid guests seeing spurious interrupts - (void)esp->ll->regs[ESP_INTRPT];
DPRINTF("do_command: id %d, cmd[0] 0x%x, status 0x%x\n", sd->id, esp->buffer[1], status);
@@ -130,14 +130,14 @@ do_command(esp_private_t *esp, sd_private_t *sd, int cmdlen, int replylen) esp->ll->regs[ESP_TCMED] = (replylen >> 8) & 0xff; // Set DMA direction esp->espdma.regs->cond_reg = DMA_ST_WRITE | DMA_ENABLE; + // Clear pending interrupts + (void)esp->ll->regs[ESP_INTRPT]; // Transfer esp->ll->regs[ESP_CMD] = ESP_CMD_TI | ESP_CMD_DMA; - // Wait for DMA to complete - while ((esp->espdma.regs->cond_reg & DMA_HNDL_INTR) == 0) /* no-op */; + // Wait for ESP to complete + while (!(esp->ll->regs[ESP_INTRPT] & (ESP_INTR_BSERV | ESP_INTR_FDONE | ESP_INTR_DC))); // Check status status = esp->ll->regs[ESP_STATUS]; - // Clear interrupts to avoid guests seeing spurious interrupts - (void)esp->ll->regs[ESP_INTRPT];
DPRINTF("do_command_reply: status 0x%x\n", status);