Hi Mark, On Jul 11, 2011, at 8:00 PM, Mark F. Brown wrote: > Philip, > > 1. The code should revert to ADMA in the case when the offset has > proper alignment and/or transfer size meets requirements. It does this. This was the reason for the introduction of dmaflags so each transfer could be individually checked. > > 2. The code here has four levels of nesting try to simplify that. > @@ -697,34 +702,62 @@ static void sdhci_prepare_data(struct sdhci_host > *host, struct mmc_command *cmd) > @@ -733,39 +766,68 @@ static void sdhci_prepare_data(struct sdhci_host > *host, struct mmc_command *cmd) > > if (unlikely(broken)) { > for_each_sg(data->sg, sg, data->sg_len, i) { > if (sg->length & 0x3) { > - DBG("Reverting to PIO because of " > - "transfer size (%d)\n", > - sg->length); > - host->flags &= ~SDHCI_REQ_USE_DMA; > - break; > + if ((dmaflags & SDHCI_USE_S_ADMA) == > + SDHCI_USE_S_ADMA) { > + if ((broken & > BROKEN_BOTH_DMA) == > + BROKEN_ADMA) { will look into how to do this. Thank You. Philip > > On Mon, Jul 11, 2011 at 3:19 PM, Philip Rakity <prakity@xxxxxxxxxxx> wrote: >> Extend the fallback path for doing DMA by allowing >> SDMA to be used before PIO when doing writes. >> >> New quirk added to indicate ADMA needs 32 bit >> addressing. For compatibility, the existing >> 32 BIT DMA quirk indicated that both ADMA and SDMA >> address are broken. The new quirk allows finer >> control if needed. >> >> When checking if for the broken xDMA quirks special >> case if both SDMA and ADMA are supported. If SDMA is >> not broken then use that rather than PIO. >> >> Signed-off-by: Philip Rakity <prakity@xxxxxxxxxxx> >> --- >> drivers/mmc/host/sdhci.c | 122 ++++++++++++++++++++++++++++++++++---------- >> include/linux/mmc/sdhci.h | 7 ++- >> 2 files changed, 99 insertions(+), 30 deletions(-) >> >> diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c >> index 91d9892..4da6a4d 100644 >> --- a/drivers/mmc/host/sdhci.c >> +++ b/drivers/mmc/host/sdhci.c >> @@ -40,6 +40,10 @@ >> >> #define MAX_TUNING_LOOP 40 >> >> +#define BROKEN_ADMA (1<<0) >> +#define BROKEN_SDMA (1<<1) >> +#define BROKEN_BOTH_DMA (BROKEN_ADMA | BROKEN_SDMA) >> + >> static unsigned int debug_quirks = 0; >> >> static void sdhci_finish_data(struct sdhci_host *); >> @@ -481,7 +485,7 @@ static int sdhci_adma_table_pre(struct sdhci_host *host, >> if (offset) { >> if (data->flags & MMC_DATA_WRITE) { >> buffer = sdhci_kmap_atomic(sg, &flags); >> - WARN_ON(((long)buffer & PAGE_MASK) > (PAGE_SIZE - 3)); >> + WARN_ON(((long)buffer & ~PAGE_MASK) > (PAGE_SIZE - 3)); >> memcpy(align, buffer, offset); >> sdhci_kunmap_atomic(buffer, &flags); >> } >> @@ -589,7 +593,7 @@ static void sdhci_adma_table_post(struct sdhci_host *host, >> size = 4 - (sg_dma_address(sg) & 0x3); >> >> buffer = sdhci_kmap_atomic(sg, &flags); >> - WARN_ON(((long)buffer & PAGE_MASK) > (PAGE_SIZE - 3)); >> + WARN_ON(((long)buffer & ~PAGE_MASK) > (PAGE_SIZE - 3)); >> memcpy(buffer, align, size); >> sdhci_kunmap_atomic(buffer, &flags); >> >> @@ -677,6 +681,7 @@ static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_command *cmd) >> u8 ctrl; >> struct mmc_data *data = cmd->data; >> int ret; >> + int dmaflags = 0; >> >> WARN_ON(host->data); >> >> @@ -697,34 +702,62 @@ static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_command *cmd) >> host->data_early = 0; >> host->data->bytes_xfered = 0; >> >> - if (host->flags & (SDHCI_USE_SDMA | SDHCI_USE_ADMA)) >> + dmaflags = host->flags & SDHCI_USE_S_ADMA; >> + if (dmaflags) >> host->flags |= SDHCI_REQ_USE_DMA; >> >> /* >> * FIXME: This doesn't account for merging when mapping the >> * scatterlist. >> + * if ADMA cannot work --> try SDMA --> else PIO >> */ >> if (host->flags & SDHCI_REQ_USE_DMA) { >> int broken, i; >> struct scatterlist *sg; >> >> broken = 0; >> - if (host->flags & SDHCI_USE_ADMA) { >> + if (dmaflags & SDHCI_USE_ADMA) { >> if (host->quirks & SDHCI_QUIRK_32BIT_ADMA_SIZE) >> - broken = 1; >> - } else { >> + broken |= BROKEN_ADMA; >> + } >> + >> + if (dmaflags & SDHCI_USE_SDMA) { >> if (host->quirks & SDHCI_QUIRK_32BIT_DMA_SIZE) >> - broken = 1; >> + broken |= BROKEN_SDMA; >> } >> >> if (unlikely(broken)) { >> for_each_sg(data->sg, sg, data->sg_len, i) { >> if (sg->length & 0x3) { >> - DBG("Reverting to PIO because of " >> - "transfer size (%d)\n", >> - sg->length); >> - host->flags &= ~SDHCI_REQ_USE_DMA; >> - break; >> + if ((dmaflags & SDHCI_USE_S_ADMA) == >> + SDHCI_USE_S_ADMA) { >> + if ((broken & BROKEN_BOTH_DMA) == >> + BROKEN_ADMA) { >> + DBG("Reverting to SDMA " >> + "because of " >> + "transfer size " >> + "sg_offset = %08X, " >> + "sg->length = %d\n", >> + sg->offset, sg->length); >> + dmaflags &= ~SDHCI_USE_ADMA; >> + } else { >> + DBG("Reverting to PIO " >> + "because of " >> + "transfer size " >> + "sg_offset = %08X, " >> + "sg->length = %d\n", >> + sg->offset, >> + sg->length); >> + host->flags &= ~SDHCI_REQ_USE_DMA; >> + } >> + } else { >> + DBG("Reverting to PIO because of " >> + "transfer size " >> + "sg_offset = %08X, " >> + "sg->length = %d\n", >> + sg->offset, sg->length); >> + host->flags &= ~SDHCI_REQ_USE_DMA; >> + } >> } >> } >> } >> @@ -733,39 +766,68 @@ static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_command *cmd) >> /* >> * The assumption here being that alignment is the same after >> * translation to device address space. >> + * >> + * if ADMA cannot work --> try SDMA --> else PIO >> */ >> if (host->flags & SDHCI_REQ_USE_DMA) { >> int broken, i; >> struct scatterlist *sg; >> >> broken = 0; >> - if (host->flags & SDHCI_USE_ADMA) { >> + if (dmaflags & SDHCI_USE_ADMA) { >> /* >> * As we use 3 byte chunks to work around >> * alignment problems, we need to check this >> * quirk. >> */ >> if (host->quirks & SDHCI_QUIRK_32BIT_ADMA_SIZE) >> - broken = 1; >> - } else { >> - if (host->quirks & SDHCI_QUIRK_32BIT_DMA_ADDR) >> - broken = 1; >> + broken |= BROKEN_ADMA; >> + if (host->quirks & SDHCI_QUIRK_32BIT_ADMA_ADDR) >> + broken |= BROKEN_ADMA; >> + } >> + if (dmaflags & SDHCI_USE_SDMA) { >> + if (host->quirks & SDHCI_QUIRK_32BIT_SDMA_ADDR) >> + broken |= BROKEN_SDMA; >> } >> >> if (unlikely(broken)) { >> for_each_sg(data->sg, sg, data->sg_len, i) { >> if (sg->offset & 0x3) { >> - DBG("Reverting to PIO because of " >> - "bad alignment\n"); >> - host->flags &= ~SDHCI_REQ_USE_DMA; >> - break; >> + if ((dmaflags & SDHCI_USE_S_ADMA) == >> + SDHCI_USE_S_ADMA) { >> + if ((broken & BROKEN_BOTH_DMA) == >> + BROKEN_ADMA) { >> + DBG("Reverting to SDMA " >> + "because of " >> + "bad alignment " >> + "sg_offset = %08X, " >> + "sg->length = %d\n", >> + sg->offset, sg->length); >> + dmaflags &= ~SDHCI_USE_ADMA; >> + } else { >> + DBG("Reverting to PIO " >> + "because of " >> + "bad alignment " >> + "sg_offset = %08X, " >> + "sg->length = %d\n", >> + sg->offset, sg->length); >> + host->flags &= ~SDHCI_REQ_USE_DMA; >> + } >> + } else { >> + DBG("Reverting to PIO because of " >> + "bad alignment " >> + "sg_offset = %08X, " >> + "sg->length = %d\n", >> + sg->offset, sg->length); >> + host->flags &= ~SDHCI_REQ_USE_DMA; >> + } >> } >> } >> } >> } >> >> if (host->flags & SDHCI_REQ_USE_DMA) { >> - if (host->flags & SDHCI_USE_ADMA) { >> + if (dmaflags & SDHCI_USE_ADMA) { >> ret = sdhci_adma_table_pre(host, data); >> if (ret) { >> /* >> @@ -810,7 +872,7 @@ static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_command *cmd) >> ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL); >> ctrl &= ~SDHCI_CTRL_DMA_MASK; >> if ((host->flags & SDHCI_REQ_USE_DMA) && >> - (host->flags & SDHCI_USE_ADMA)) >> + (dmaflags & SDHCI_USE_ADMA)) >> ctrl |= SDHCI_CTRL_ADMA32; >> else >> ctrl |= SDHCI_CTRL_SDMA; >> @@ -2260,7 +2322,7 @@ int sdhci_resume_host(struct sdhci_host *host) >> } >> >> >> - if (host->flags & (SDHCI_USE_SDMA | SDHCI_USE_ADMA)) { >> + if (host->flags & SDHCI_USE_S_ADMA) { >> if (host->ops->enable_dma) >> host->ops->enable_dma(host); >> } >> @@ -2381,14 +2443,13 @@ int sdhci_add_host(struct sdhci_host *host) >> host->flags &= ~SDHCI_USE_ADMA; >> } >> >> - if (host->flags & (SDHCI_USE_SDMA | SDHCI_USE_ADMA)) { >> + if (host->flags & SDHCI_USE_S_ADMA) { >> if (host->ops->enable_dma) { >> if (host->ops->enable_dma(host)) { >> printk(KERN_WARNING "%s: No suitable DMA " >> "available. Falling back to PIO.\n", >> mmc_hostname(mmc)); >> - host->flags &= >> - ~(SDHCI_USE_SDMA | SDHCI_USE_ADMA); >> + host->flags &= ~SDHCI_USE_S_ADMA; >> } >> } >> } >> @@ -2416,7 +2477,7 @@ int sdhci_add_host(struct sdhci_host *host) >> * mask, but PIO does not need the hw shim so we set a new >> * mask here in that case. >> */ >> - if (!(host->flags & (SDHCI_USE_SDMA | SDHCI_USE_ADMA))) { >> + if (!(host->flags & SDHCI_USE_S_ADMA)) { >> host->dma_mask = DMA_BIT_MASK(64); >> mmc_dev(host->mmc)->dma_mask = &host->dma_mask; >> } >> @@ -2758,6 +2819,11 @@ int sdhci_add_host(struct sdhci_host *host) >> (host->flags & SDHCI_USE_ADMA) ? "ADMA" : >> (host->flags & SDHCI_USE_SDMA) ? "DMA" : "PIO"); >> >> + if ((host->flags & SDHCI_USE_S_ADMA) == SDHCI_USE_S_ADMA) >> + printk(KERN_INFO "%s: SDHCI controller on %s [%s] can also" >> + " use SDMA\n", >> + mmc_hostname(mmc), host->hw_name, dev_name(mmc_dev(mmc))); >> + >> sdhci_enable_card_detection(host); >> >> return 0; >> diff --git a/include/linux/mmc/sdhci.h b/include/linux/mmc/sdhci.h >> index 13c13f8..74d8cbd 100644 >> --- a/include/linux/mmc/sdhci.h >> +++ b/include/linux/mmc/sdhci.h >> @@ -38,7 +38,7 @@ struct sdhci_host { >> /* Controller has an unusable ADMA engine */ >> #define SDHCI_QUIRK_BROKEN_ADMA (1<<6) >> /* Controller can only DMA from 32-bit aligned addresses */ >> -#define SDHCI_QUIRK_32BIT_DMA_ADDR (1<<7) >> +#define SDHCI_QUIRK_32BIT_SDMA_ADDR (1<<7) >> /* Controller can only DMA chunk sizes that are a multiple of 32 bits */ >> #define SDHCI_QUIRK_32BIT_DMA_SIZE (1<<8) >> /* Controller can only ADMA chunks that are a multiple of 32 bits */ >> @@ -64,7 +64,7 @@ struct sdhci_host { >> /* Controller losing signal/interrupt enable states after reset */ >> #define SDHCI_QUIRK_RESTORE_IRQS_AFTER_RESET (1<<19) >> /* Reclaimed, available for use */ >> -#define SDHCI_QUIRK_UNUSED_20 (1<<20) >> +#define SDHCI_QUIRK_32BIT_ADMA_ADDR (1<<20) >> /* Reclaimed, available for use */ >> #define SDHCI_QUIRK_UNUSED_21 (1<<21) >> /* Controller can only handle 1-bit data transfers */ >> @@ -87,6 +87,8 @@ struct sdhci_host { >> #define SDHCI_QUIRK_BROKEN_ADMA_ZEROLEN_DESC (1<<30) >> /* The read-only detection via SDHCI_PRESENT_STATE register is unstable */ >> #define SDHCI_QUIRK_UNSTABLE_RO_DETECT (1<<31) >> +#define SDHCI_QUIRK_32BIT_DMA_ADDR (SDHCI_QUIRK_32BIT_SDMA_ADDR | \ >> + SDHCI_QUIRK_32BIT_ADMA_ADDR) >> >> int irq; /* Device IRQ */ >> void __iomem *ioaddr; /* Mapped address */ >> @@ -115,6 +117,7 @@ struct sdhci_host { >> #define SDHCI_NEEDS_RETUNING (1<<5) /* Host needs retuning */ >> #define SDHCI_AUTO_CMD12 (1<<6) /* Auto CMD12 support */ >> #define SDHCI_AUTO_CMD23 (1<<7) /* Auto CMD23 support */ >> +#define SDHCI_USE_S_ADMA (SDHCI_USE_SDMA | SDHCI_USE_ADMA) >> >> unsigned int version; /* SDHCI spec. version */ >> >> -- >> 1.7.0.4 >> >> >> -- >> To unsubscribe from this list: send the line "unsubscribe linux-mmc" in >> the body of a message to majordomo@xxxxxxxxxxxxxxx >> More majordomo info at http://vger.kernel.org/majordomo-info.html >> -- To unsubscribe from this list: send the line "unsubscribe linux-mmc" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html