Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit b537f94c authored by Russell King's avatar Russell King Committed by Chris Ball
Browse files

mmc: sdhci: more efficient interrupt enable register handling



Rather than wasting cycles read-modify-writing the interrupt enable
registers, cache the value locally instead.

Signed-off-by: default avatarRussell King <rmk+kernel@arm.linux.org.uk>
Tested-by: default avatarMarkus Pargmann <mpa@pengutronix.de>
Tested-by: default avatarStephen Warren <swarren@nvidia.com>
Signed-off-by: default avatarUlf Hansson <ulf.hansson@linaro.org>
Signed-off-by: default avatarChris Ball <chris@printf.net>
parent be138554
Loading
Loading
Loading
Loading
+47 −51
Original line number Original line Diff line number Diff line
@@ -131,27 +131,6 @@ static void sdhci_dumpregs(struct sdhci_host *host)
 *                                                                           *
 *                                                                           *
\*****************************************************************************/
\*****************************************************************************/


static void sdhci_clear_set_irqs(struct sdhci_host *host, u32 clear, u32 set)
{
	u32 ier;

	ier = sdhci_readl(host, SDHCI_INT_ENABLE);
	ier &= ~clear;
	ier |= set;
	sdhci_writel(host, ier, SDHCI_INT_ENABLE);
	sdhci_writel(host, ier, SDHCI_SIGNAL_ENABLE);
}

static void sdhci_unmask_irqs(struct sdhci_host *host, u32 irqs)
{
	sdhci_clear_set_irqs(host, 0, irqs);
}

static void sdhci_mask_irqs(struct sdhci_host *host, u32 irqs)
{
	sdhci_clear_set_irqs(host, irqs, 0);
}

static void sdhci_set_card_detection(struct sdhci_host *host, bool enable)
static void sdhci_set_card_detection(struct sdhci_host *host, bool enable)
{
{
	u32 present, irqs;
	u32 present, irqs;
@@ -165,9 +144,12 @@ static void sdhci_set_card_detection(struct sdhci_host *host, bool enable)
	irqs = present ? SDHCI_INT_CARD_REMOVE : SDHCI_INT_CARD_INSERT;
	irqs = present ? SDHCI_INT_CARD_REMOVE : SDHCI_INT_CARD_INSERT;


	if (enable)
	if (enable)
		sdhci_unmask_irqs(host, irqs);
		host->ier |= irqs;
	else
	else
		sdhci_mask_irqs(host, irqs);
		host->ier &= ~irqs;

	sdhci_writel(host, host->ier, SDHCI_INT_ENABLE);
	sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE);
}
}


static void sdhci_enable_card_detection(struct sdhci_host *host)
static void sdhci_enable_card_detection(struct sdhci_host *host)
@@ -183,17 +165,12 @@ static void sdhci_disable_card_detection(struct sdhci_host *host)
static void sdhci_reset(struct sdhci_host *host, u8 mask)
static void sdhci_reset(struct sdhci_host *host, u8 mask)
{
{
	unsigned long timeout;
	unsigned long timeout;
	u32 uninitialized_var(ier);

	if (host->quirks & SDHCI_QUIRK_NO_CARD_NO_RESET) {
	if (host->quirks & SDHCI_QUIRK_NO_CARD_NO_RESET) {
		if (!(sdhci_readl(host, SDHCI_PRESENT_STATE) &
		if (!(sdhci_readl(host, SDHCI_PRESENT_STATE) &
			SDHCI_CARD_PRESENT))
			SDHCI_CARD_PRESENT))
			return;
			return;
	}
	}


	if (host->quirks & SDHCI_QUIRK_RESTORE_IRQS_AFTER_RESET)
		ier = sdhci_readl(host, SDHCI_INT_ENABLE);

	if (host->ops->platform_reset_enter)
	if (host->ops->platform_reset_enter)
		host->ops->platform_reset_enter(host, mask);
		host->ops->platform_reset_enter(host, mask);


@@ -224,8 +201,10 @@ static void sdhci_reset(struct sdhci_host *host, u8 mask)
	if (host->ops->platform_reset_exit)
	if (host->ops->platform_reset_exit)
		host->ops->platform_reset_exit(host, mask);
		host->ops->platform_reset_exit(host, mask);


	if (host->quirks & SDHCI_QUIRK_RESTORE_IRQS_AFTER_RESET)
	if (host->quirks & SDHCI_QUIRK_RESTORE_IRQS_AFTER_RESET) {
		sdhci_clear_set_irqs(host, SDHCI_INT_ALL_MASK, ier);
		sdhci_writel(host, host->ier, SDHCI_INT_ENABLE);
		sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE);
	}


	if (host->flags & (SDHCI_USE_SDMA | SDHCI_USE_ADMA)) {
	if (host->flags & (SDHCI_USE_SDMA | SDHCI_USE_ADMA)) {
		if ((host->ops->enable_dma) && (mask & SDHCI_RESET_ALL))
		if ((host->ops->enable_dma) && (mask & SDHCI_RESET_ALL))
@@ -242,11 +221,14 @@ static void sdhci_init(struct sdhci_host *host, int soft)
	else
	else
		sdhci_reset(host, SDHCI_RESET_ALL);
		sdhci_reset(host, SDHCI_RESET_ALL);


	sdhci_clear_set_irqs(host, SDHCI_INT_ALL_MASK,
	host->ier = SDHCI_INT_BUS_POWER | SDHCI_INT_DATA_END_BIT |
		SDHCI_INT_BUS_POWER | SDHCI_INT_DATA_END_BIT |
		    SDHCI_INT_DATA_CRC | SDHCI_INT_DATA_TIMEOUT |
		SDHCI_INT_DATA_CRC | SDHCI_INT_DATA_TIMEOUT | SDHCI_INT_INDEX |
		    SDHCI_INT_INDEX | SDHCI_INT_END_BIT | SDHCI_INT_CRC |
		SDHCI_INT_END_BIT | SDHCI_INT_CRC | SDHCI_INT_TIMEOUT |
		    SDHCI_INT_TIMEOUT | SDHCI_INT_DATA_END |
		SDHCI_INT_DATA_END | SDHCI_INT_RESPONSE);
		    SDHCI_INT_RESPONSE;

	sdhci_writel(host, host->ier, SDHCI_INT_ENABLE);
	sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE);


	if (soft) {
	if (soft) {
		/* force clock reconfiguration */
		/* force clock reconfiguration */
@@ -721,9 +703,12 @@ static void sdhci_set_transfer_irqs(struct sdhci_host *host)
	u32 dma_irqs = SDHCI_INT_DMA_END | SDHCI_INT_ADMA_ERROR;
	u32 dma_irqs = SDHCI_INT_DMA_END | SDHCI_INT_ADMA_ERROR;


	if (host->flags & SDHCI_REQ_USE_DMA)
	if (host->flags & SDHCI_REQ_USE_DMA)
		sdhci_clear_set_irqs(host, pio_irqs, dma_irqs);
		host->ier = (host->ier & ~pio_irqs) | dma_irqs;
	else
	else
		sdhci_clear_set_irqs(host, dma_irqs, pio_irqs);
		host->ier = (host->ier & ~dma_irqs) | pio_irqs;

	sdhci_writel(host, host->ier, SDHCI_INT_ENABLE);
	sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE);
}
}


static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_command *cmd)
static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_command *cmd)
@@ -1713,9 +1698,12 @@ static void sdhci_enable_sdio_irq_nolock(struct sdhci_host *host, int enable)
{
{
	if (!(host->flags & SDHCI_DEVICE_DEAD)) {
	if (!(host->flags & SDHCI_DEVICE_DEAD)) {
		if (enable)
		if (enable)
			sdhci_unmask_irqs(host, SDHCI_INT_CARD_INT);
			host->ier |= SDHCI_INT_CARD_INT;
		else
		else
			sdhci_mask_irqs(host, SDHCI_INT_CARD_INT);
			host->ier &= ~SDHCI_INT_CARD_INT;

		sdhci_writel(host, host->ier, SDHCI_INT_ENABLE);
		sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE);
		mmiowb();
		mmiowb();
	}
	}
}
}
@@ -1857,7 +1845,6 @@ static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode)
{
{
	struct sdhci_host *host;
	struct sdhci_host *host;
	u16 ctrl;
	u16 ctrl;
	u32 ier;
	int tuning_loop_counter = MAX_TUNING_LOOP;
	int tuning_loop_counter = MAX_TUNING_LOOP;
	unsigned long timeout;
	unsigned long timeout;
	int err = 0;
	int err = 0;
@@ -1911,8 +1898,8 @@ static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode)
	 * to make sure we don't hit a controller bug, we _only_
	 * to make sure we don't hit a controller bug, we _only_
	 * enable Buffer Read Ready interrupt here.
	 * enable Buffer Read Ready interrupt here.
	 */
	 */
	ier = sdhci_readl(host, SDHCI_INT_ENABLE);
	sdhci_writel(host, SDHCI_INT_DATA_AVAIL, SDHCI_INT_ENABLE);
	sdhci_clear_set_irqs(host, ier, SDHCI_INT_DATA_AVAIL);
	sdhci_writel(host, SDHCI_INT_DATA_AVAIL, SDHCI_SIGNAL_ENABLE);


	/*
	/*
	 * Issue CMD19 repeatedly till Execute Tuning is set to 0 or the number
	 * Issue CMD19 repeatedly till Execute Tuning is set to 0 or the number
@@ -2047,7 +2034,8 @@ static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode)
	if (err && (host->flags & SDHCI_USING_RETUNING_TIMER))
	if (err && (host->flags & SDHCI_USING_RETUNING_TIMER))
		err = 0;
		err = 0;


	sdhci_clear_set_irqs(host, SDHCI_INT_DATA_AVAIL, ier);
	sdhci_writel(host, host->ier, SDHCI_INT_ENABLE);
	sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE);
	spin_unlock_irqrestore(&host->lock, flags);
	spin_unlock_irqrestore(&host->lock, flags);
	sdhci_runtime_pm_put(host);
	sdhci_runtime_pm_put(host);


@@ -2460,10 +2448,12 @@ static irqreturn_t sdhci_irq(int irq, void *dev_id)
			 * More testing are needed here to ensure it works
			 * More testing are needed here to ensure it works
			 * for other platforms though.
			 * for other platforms though.
			 */
			 */
			sdhci_mask_irqs(host, present ? SDHCI_INT_CARD_INSERT :
			host->ier &= ~(SDHCI_INT_CARD_INSERT |
				       SDHCI_INT_CARD_REMOVE);
				       SDHCI_INT_CARD_REMOVE);
			sdhci_unmask_irqs(host, present ? SDHCI_INT_CARD_REMOVE :
			host->ier |= present ? SDHCI_INT_CARD_REMOVE :
							  SDHCI_INT_CARD_INSERT);
					       SDHCI_INT_CARD_INSERT;
			sdhci_writel(host, host->ier, SDHCI_INT_ENABLE);
			sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE);


			sdhci_writel(host, intmask & (SDHCI_INT_CARD_INSERT |
			sdhci_writel(host, intmask & (SDHCI_INT_CARD_INSERT |
				     SDHCI_INT_CARD_REMOVE), SDHCI_INT_STATUS);
				     SDHCI_INT_CARD_REMOVE), SDHCI_INT_STATUS);
@@ -2592,7 +2582,9 @@ int sdhci_suspend_host(struct sdhci_host *host)
	}
	}


	if (!device_may_wakeup(mmc_dev(host->mmc))) {
	if (!device_may_wakeup(mmc_dev(host->mmc))) {
		sdhci_mask_irqs(host, SDHCI_INT_ALL_MASK);
		host->ier = 0;
		sdhci_writel(host, 0, SDHCI_INT_ENABLE);
		sdhci_writel(host, 0, SDHCI_SIGNAL_ENABLE);
		free_irq(host->irq, host);
		free_irq(host->irq, host);
	} else {
	} else {
		sdhci_enable_irq_wakeups(host);
		sdhci_enable_irq_wakeups(host);
@@ -2691,7 +2683,9 @@ int sdhci_runtime_suspend_host(struct sdhci_host *host)
	}
	}


	spin_lock_irqsave(&host->lock, flags);
	spin_lock_irqsave(&host->lock, flags);
	sdhci_mask_irqs(host, SDHCI_INT_ALL_MASK & ~SDHCI_INT_CARD_INT);
	host->ier &= SDHCI_INT_CARD_INT;
	sdhci_writel(host, host->ier, SDHCI_INT_ENABLE);
	sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE);
	spin_unlock_irqrestore(&host->lock, flags);
	spin_unlock_irqrestore(&host->lock, flags);


	synchronize_hardirq(host->irq);
	synchronize_hardirq(host->irq);
@@ -3282,7 +3276,8 @@ int sdhci_add_host(struct sdhci_host *host)
#ifdef SDHCI_USE_LEDS_CLASS
#ifdef SDHCI_USE_LEDS_CLASS
reset:
reset:
	sdhci_reset(host, SDHCI_RESET_ALL);
	sdhci_reset(host, SDHCI_RESET_ALL);
	sdhci_mask_irqs(host, SDHCI_INT_ALL_MASK);
	sdhci_writel(host, 0, SDHCI_INT_ENABLE);
	sdhci_writel(host, 0, SDHCI_SIGNAL_ENABLE);
	free_irq(host->irq, host);
	free_irq(host->irq, host);
#endif
#endif
untasklet:
untasklet:
@@ -3324,7 +3319,8 @@ void sdhci_remove_host(struct sdhci_host *host, int dead)
	if (!dead)
	if (!dead)
		sdhci_reset(host, SDHCI_RESET_ALL);
		sdhci_reset(host, SDHCI_RESET_ALL);


	sdhci_mask_irqs(host, SDHCI_INT_ALL_MASK);
	sdhci_writel(host, 0, SDHCI_INT_ENABLE);
	sdhci_writel(host, 0, SDHCI_SIGNAL_ENABLE);
	free_irq(host->irq, host);
	free_irq(host->irq, host);


	del_timer_sync(&host->timer);
	del_timer_sync(&host->timer);
+3 −0
Original line number Original line Diff line number Diff line
@@ -178,6 +178,9 @@ struct sdhci_host {


	u32			thread_isr;
	u32			thread_isr;


	/* cached registers */
	u32			ier;

	wait_queue_head_t	buf_ready_int;	/* Waitqueue for Buffer Read Ready interrupt */
	wait_queue_head_t	buf_ready_int;	/* Waitqueue for Buffer Read Ready interrupt */
	unsigned int		tuning_done;	/* Condition flag set when CMD19 succeeds */
	unsigned int		tuning_done;	/* Condition flag set when CMD19 succeeds */