Some hosts (that is, FSL eSDHC) throw PIO interrupts during DMA transfers, this causes tons of unneeded interrupts, and thus highly degraded speed.
This patch adds SDHCI_QUIRK_PIO_IRQS_DURING_DMA quirk. When specified, the sdhci driver will disable PIO interrupts during DMA transfers. Signed-off-by: Anton Vorontsov <avoront...@ru.mvista.com> --- drivers/mmc/host/sdhci.c | 32 ++++++++++++++++++++++++++++++++ drivers/mmc/host/sdhci.h | 3 +++ 2 files changed, 35 insertions(+), 0 deletions(-) diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 9b43588..ede3790 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -167,6 +167,8 @@ static void sdhci_init(struct sdhci_host *host) sdhci_writel(host, intmask, SDHCI_INT_ENABLE); sdhci_writel(host, intmask, SDHCI_SIGNAL_ENABLE); + + host->flags &= ~SDHCI_PIO_DISABLED; } static void sdhci_activate_led(struct sdhci_host *host) @@ -594,6 +596,33 @@ static u8 sdhci_calc_timeout(struct sdhci_host *host, struct mmc_data *data) return count; } +static void sdhci_set_pio_irqs(struct sdhci_host *host, bool state) +{ + bool current_state = !(host->flags & SDHCI_PIO_DISABLED); + u32 ier; + + /* + * We only care about PIO IRQs if the host issues PIO IRQs during + * DMA transfers. Otherwise we can keep the irqs always enabled. + */ + if (!(host->quirks & SDHCI_QUIRK_PIO_IRQS_DURING_DMA)) + return; + + if (current_state == state) + return; + + ier = sdhci_readl(host, SDHCI_INT_ENABLE); + if (state) { + ier |= SDHCI_INT_DATA_AVAIL | SDHCI_INT_SPACE_AVAIL; + host->flags &= ~SDHCI_PIO_DISABLED; + } else { + ier &= ~(SDHCI_INT_DATA_AVAIL | SDHCI_INT_SPACE_AVAIL); + host->flags |= SDHCI_PIO_DISABLED; + } + sdhci_writel(host, ier, SDHCI_INT_ENABLE); + sdhci_writel(host, ier, SDHCI_SIGNAL_ENABLE); +} + static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_data *data) { u8 count; @@ -740,6 +769,9 @@ static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_data *data) sg_miter_start(&host->sg_miter, data->sg, data->sg_len, SG_MITER_ATOMIC); host->blocks = data->blocks; + sdhci_set_pio_irqs(host, true); + } else { + sdhci_set_pio_irqs(host, false); } /* We do not handle DMA boundaries, so set it to max (512 KiB) */ diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h index c4edd52..2e8dfd1 100644 --- a/drivers/mmc/host/sdhci.h +++ b/drivers/mmc/host/sdhci.h @@ -235,6 +235,8 @@ struct sdhci_host { #define SDHCI_QUIRK_INVERTED_WRITE_PROTECT (1<<17) /* Controller has all registers of 32 bit width */ #define SDHCI_QUIRK_32BIT_REGISTERS (1<<18) +/* Controller issues PIO interrupts during DMA transfers */ +#define SDHCI_QUIRK_PIO_IRQS_DURING_DMA (1<<19) int irq; /* Device IRQ */ void __iomem * ioaddr; /* Mapped address */ @@ -256,6 +258,7 @@ struct sdhci_host { #define SDHCI_USE_ADMA (1<<1) /* Host is ADMA capable */ #define SDHCI_REQ_USE_DMA (1<<2) /* Use DMA for this req. */ #define SDHCI_DEVICE_DEAD (1<<3) /* Device unresponsive */ +#define SDHCI_PIO_DISABLED (1<<4) /* PIO IRQs disabled */ unsigned int version; /* SDHCI spec. version */ -- 1.5.6.5 _______________________________________________ Linuxppc-dev mailing list Linuxppc-dev@ozlabs.org https://ozlabs.org/mailman/listinfo/linuxppc-dev