From 6bdaa92f00c576cae5e1c3ef2f03e447937c8884 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Imre=20Vad=C3=A1sz?= Date: Sat, 7 Jan 2017 23:53:43 +0100 Subject: [PATCH] sdhci - Handle ADMA error interrupt, similar to ACMD12 error interrupt. * Print the DMA descriptor entry that is likely at fault. --- sys/dev/disk/sdhci/sdhci.c | 60 ++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 58 insertions(+), 2 deletions(-) diff --git a/sys/dev/disk/sdhci/sdhci.c b/sys/dev/disk/sdhci/sdhci.c index cc2da4c870..0d92f8600a 100644 --- a/sys/dev/disk/sdhci/sdhci.c +++ b/sys/dev/disk/sdhci/sdhci.c @@ -228,7 +228,7 @@ sdhci_init(struct sdhci_slot *slot) SDHCI_INT_CARD_REMOVE | SDHCI_INT_CARD_INSERT | SDHCI_INT_DATA_AVAIL | SDHCI_INT_SPACE_AVAIL | SDHCI_INT_DMA_END | SDHCI_INT_DATA_END | SDHCI_INT_RESPONSE | - SDHCI_INT_ACMD12ERR; + SDHCI_INT_ACMD12ERR | SDHCI_INT_ADMAERR; WR4(slot, SDHCI_INT_ENABLE, slot->intmask); WR4(slot, SDHCI_SIGNAL_ENABLE, slot->intmask); } @@ -1478,7 +1478,7 @@ static void sdhci_acmd_irq(struct sdhci_slot *slot) { uint16_t err; - + err = RD4(slot, SDHCI_ACMD12_ERR); if (!slot->curcmd) { slot_printf(slot, "Got AutoCMD12 error 0x%04x, but " @@ -1490,6 +1490,56 @@ sdhci_acmd_irq(struct sdhci_slot *slot) sdhci_reset(slot, SDHCI_RESET_CMD); } +static void +sdhci_adma_irq(struct sdhci_slot *slot) +{ + bus_dmamem_t *descmem = &slot->adma2_descs; + struct sdhci_adma2_desc32 *desc; + bus_addr_t addr = 0; + uint8_t err, adma_state; + + err = RD1(slot, SDHCI_ADMA_ERR); + if (slot->curcmd && (slot->flags & SDHCI_USE_ADMA2)) { + slot_printf(slot, "Got ADMA2 error 0x%02x\n", err); + } else { + slot_printf(slot, "Got ADMA2 error 0x%02x, but " + "there is no active command.\n", err); + sdhci_dumpregs(slot); + } + + /* Try to print the erronous ADMA2 descriptor */ + adma_state = err & SDHCI_ADMA_ERR_STATE_MASK; + if (adma_state == SDHCI_ADMA_ERR_STATE_STOP) { + addr = RD4(slot, SDHCI_ADMA_ADDRESS_LOW); + if (addr > sizeof(*desc)) + addr -= sizeof(*desc); + else + addr = 0; + } else if (adma_state == SDHCI_ADMA_ERR_STATE_FDS) { + addr = RD4(slot, SDHCI_ADMA_ADDRESS_LOW); + } else if (adma_state == SDHCI_ADMA_ERR_STATE_TFR) { + addr = RD4(slot, SDHCI_ADMA_ADDRESS_LOW); + if (addr > sizeof(*desc)) + addr -= sizeof(*desc); + else + addr = 0; + } else { + slot_printf(slot, "Invalid ADMA2 state 0x%02x\n", adma_state); + } + if (addr >= descmem->dmem_busaddr && + addr < descmem->dmem_busaddr + SDHCI_ADMA2_DESCBUF_SIZE) { + desc = (void *) ((char *)descmem->dmem_addr + + (addr - descmem->dmem_busaddr)); + slot_printf(slot, + "Descriptor: Addr=0x%08x Length=0x%04x Attr=0x%04x\n", + desc->address, desc->length, desc->attribute); + } + + if (slot->curcmd && (slot->flags & SDHCI_USE_ADMA2)) { + sdhci_reset(slot, SDHCI_RESET_CMD); + } +} + void sdhci_generic_intr(struct sdhci_slot *slot) { @@ -1541,8 +1591,14 @@ sdhci_generic_intr(struct sdhci_slot *slot) WR4(slot, SDHCI_INT_STATUS, SDHCI_INT_ACMD12ERR); sdhci_acmd_irq(slot); } + /* Handle ADMA2 error interrupt. */ + if (intmask & SDHCI_INT_ADMAERR) { + WR4(slot, SDHCI_INT_STATUS, SDHCI_INT_ADMAERR); + sdhci_adma_irq(slot); + } intmask &= ~(SDHCI_INT_CMD_MASK | SDHCI_INT_DATA_MASK); intmask &= ~SDHCI_INT_ACMD12ERR; + intmask &= ~SDHCI_INT_ADMAERR; intmask &= ~SDHCI_INT_ERROR; /* Handle bus power interrupt. */ if (intmask & SDHCI_INT_BUS_POWER) { -- 2.11.4.GIT