diff mbox

[v2,4/8] sdhci: Use threaded IRQ handler

Message ID 1382369157-16129-5-git-send-email-jeremie.samuel.ext@parrot.com (mailing list archive)
State New, archived
Headers show

Commit Message

Jeremie Samuel Oct. 21, 2013, 3:25 p.m. UTC
We only need atomic context to disable SDHCI interrupts, after that
we can run in a kernel thread.

Note that irq handler still grabs an irqsave spinlock, we'll deal
with it in a subsequent patch.

Patch based on: http://thread.gmane.org/gmane.linux.kernel.mmc/2579.

Signed-off-by: Anton Vorontsov <avorontsov@mvista.com>
Signed-off-by: Jeremie Samuel <jeremie.samuel.ext@parrot.com>
---
 drivers/mmc/host/sdhci.c |   46 ++++++++++++++++++++++++++++------------------
 1 file changed, 28 insertions(+), 18 deletions(-)

Comments

Olof Johansson Oct. 30, 2013, 7:30 p.m. UTC | #1
Hi,

On Mon, Oct 21, 2013 at 8:25 AM, Jeremie Samuel
<jeremie.samuel.ext@parrot.com> wrote:
> We only need atomic context to disable SDHCI interrupts, after that
> we can run in a kernel thread.
>
> Note that irq handler still grabs an irqsave spinlock, we'll deal
> with it in a subsequent patch.
>
> Patch based on: http://thread.gmane.org/gmane.linux.kernel.mmc/2579.
>
> Signed-off-by: Anton Vorontsov <avorontsov@mvista.com>
> Signed-off-by: Jeremie Samuel <jeremie.samuel.ext@parrot.com>

It seems like this patch is causing problems on Marvell Dove (such as
SolidRun Cubox). I've bisected a boot issue on that hardware down on
linux-next.

A good boot without this patch (i.e. with this patch reverted)
contains two spurious interrupts at probe time, both of them with
timeout+error set.

Below is the output with MMC_DEBUG turned on. Given the proximity to
the merge window, if we can't sort this out I think I'd prefer to see
this patch merged and retargeted to 3.14...


Good boot without this patch:

[    0.962882] sdhci: Secure Digital Host Controller Interface driver
[    0.969045] sdhci: Copyright(c) Pierre Ossman
[    0.973375] sdhci-pltfm: SDHCI platform and OF driver helper
[    0.979149] sdhci [sdhci_add_host()]: mmc0: Auto-CMD23 unavailable
[    0.985320] mmc0: no vqmmc regulator found
[    0.989396] mmc0: no vmmc regulator found
[    0.993409] sdhci: =========== REGISTER DUMP (mmc0)===========
[    0.999221] sdhci: Sys addr: 0x00000000 | Version:  0x00000000
[    1.005035] sdhci: Blk size: 0x00000000 | Blk cnt:  0x00000000
[    1.010840] sdhci: Argument: 0x00000000 | Trn mode: 0x00000001
[    1.016656] sdhci: Present:  0x017f0000 | Host ctl: 0x00000000
[    1.022461] sdhci: Power:    0x0000000c | Blk gap:  0x00000000
[    1.028275] sdhci: Wake-up:  0x00000000 | Clock:    0x00000100
[    1.034080] sdhci: Timeout:  0x0000000e | Int stat: 0x00000000
[    1.039888] sdhci: Int enab: 0x00ff0003 | Sig enab: 0x00ff0003
[    1.045701] sdhci: AC12 err: 0x00000000 | Slot int: 0x00000000
[    1.051500] sdhci: Caps:     0x01e032b2 | Caps_1:   0x00000000
[    1.057313] sdhci: Cmd:      0x00000000 | Max curr: 0x00000000
[    1.063111] sdhci: Host ctl2: 0x00000000
[    1.067014] sdhci: ===========================================
[    1.073201] mmc0: clock 0Hz busmode 2 powermode 1 cs 0 Vdd 21 width
0 timing 0
[    1.094119] mmc0: clock 400000Hz busmode 2 powermode 2 cs 0 Vdd 21
width 0 timing 0
[    1.114117] mmc0: SDHCI controller on f1092000.sdio-host
[f1092000.sdio-host] using DMA
[    1.122155] mmc0: mmc_rescan_try_freq: trying to init card at 400000 Hz
[    1.128750] mmc0: starting CMD52 arg 00000c00 flags 00000195
[    1.134710] sdhci [sdhci_irq()]: *** mmc0 got interrupt: 0x00018000
[    1.140953] mmc0: Unexpected interrupt 0x00008000.
[    1.145717] sdhci: =========== REGISTER DUMP (mmc0)===========
[    1.151516] sdhci: Sys addr: 0x00000000 | Version:  0x00000000
[    1.157313] sdhci: Blk size: 0x00000000 | Blk cnt:  0x00000000
[    1.163110] sdhci: Argument: 0x00000c00 | Trn mode: 0x00000001
[    1.168908] sdhci: Present:  0x01ff0000 | Host ctl: 0x00000001
[    1.174705] sdhci: Power:    0x0000000f | Blk gap:  0x00000000
[    1.180503] sdhci: Wake-up:  0x00000000 | Clock:    0x00004007
[    1.186300] sdhci: Timeout:  0x0000000e | Int stat: 0x00000000
[    1.192099] sdhci: Int enab: 0x00ff0083 | Sig enab: 0x00ff0083
[    1.197903] sdhci: AC12 err: 0x00000000 | Slot int: 0x00000000
[    1.203702] sdhci: Caps:     0x01e032b2 | Caps_1:   0x00000000
[    1.209499] sdhci: Cmd:      0x0000341a | Max curr: 0x00000000
[    1.215295] sdhci: Host ctl2: 0x00000000
[    1.219191] sdhci: ===========================================
[    1.225037] mmc0: req done (CMD52): -110: 00000000 00000000 00000000 00000000
[    1.232144] mmc0: starting CMD52 arg 80000c08 flags 00000195
[    1.237807] ata1: SATA link down (SStatus 0 SControl F300)
[    1.243266] sdhci [sdhci_irq()]: *** mmc0 got interrupt: 0x00018000
[    1.249503] mmc0: Unexpected interrupt 0x00008000.
[    1.254270] sdhci: =========== REGISTER DUMP (mmc0)===========
[    1.260069] sdhci: Sys addr: 0x00000000 | Version:  0x00000000
[    1.265866] sdhci: Blk size: 0x00000000 | Blk cnt:  0x00000000
[    1.271664] sdhci: Argument: 0x80000c08 | Trn mode: 0x00000001
[    1.277462] sdhci: Present:  0x01ff0000 | Host ctl: 0x00000001
[    1.283266] sdhci: Power:    0x0000000f | Blk gap:  0x00000000
[    1.289064] sdhci: Wake-up:  0x00000000 | Clock:    0x00004007
[    1.294862] sdhci: Timeout:  0x0000000e | Int stat: 0x00000000
[    1.300660] sdhci: Int enab: 0x00ff0083 | Sig enab: 0x00ff0083
[    1.306456] sdhci: AC12 err: 0x00000000 | Slot int: 0x00000000
[    1.312255] sdhci: Caps:     0x01e032b2 | Caps_1:   0x00000000
[    1.318052] sdhci: Cmd:      0x0000341a | Max curr: 0x00000000
[    1.323848] sdhci: Host ctl2: 0x00000000
[    1.327745] sdhci: ===========================================


A bad boot with this patch applied instead only gives:

[    0.962875] sdhci: Secure Digital Host Controller Interface driver
[    0.969042] sdhci: Copyright(c) Pierre Ossman
[    0.973373] sdhci-pltfm: SDHCI platform and OF driver helper
[    0.979146] sdhci [sdhci_add_host()]: mmc0: Auto-CMD23 unavailable
[    0.985318] mmc0: no vqmmc regulator found
[    0.989394] mmc0: no vmmc regulator found
[    0.993478] sdhci: =========== REGISTER DUMP (mmc0)===========
[    0.999290] sdhci: Sys addr: 0x00000000 | Version:  0x00000000
[    1.005104] sdhci: Blk size: 0x00000000 | Blk cnt:  0x00000000
[    1.010907] sdhci: Argument: 0x00000000 | Trn mode: 0x00000001
[    1.016715] sdhci: Present:  0x017f0000 | Host ctl: 0x00000000
[    1.022519] sdhci: Power:    0x0000000c | Blk gap:  0x00000000
[    1.028326] sdhci: Wake-up:  0x00000000 | Clock:    0x00000100
[    1.034139] sdhci: Timeout:  0x0000000e | Int stat: 0x00000000
[    1.039938] sdhci: Int enab: 0x00ff0003 | Sig enab: 0x00ff0003
[    1.045751] sdhci: AC12 err: 0x00000000 | Slot int: 0x00000000
[    1.051550] sdhci: Caps:     0x01e032b2 | Caps_1:   0x00000000
[    1.057363] sdhci: Cmd:      0x00000000 | Max curr: 0x00000000
[    1.063161] sdhci: Host ctl2: 0x00000000
[    1.067064] sdhci: ===========================================
[    1.073351] mmc0: clock 0Hz busmode 2 powermode 1 cs 0 Vdd 21 width
0 timing 0
[    1.094093] mmc0: clock 400000Hz busmode 2 powermode 2 cs 0 Vdd 21
width 0 timing 0
[    1.114093] mmc0: SDHCI controller on f1092000.sdio-host
[f1092000.sdio-host] using DMA
[    1.122130] mmc0: mmc_rescan_try_freq: trying to init card at 400000 Hz
[    1.128731] mmc0: starting CMD52 arg 00000c00 flags 00000195
[    1.134692] sdhci [sdhci_irq()]: *** mmc0 got interrupt: 0x00018000
[    1.140936] sdhci [sdhci_irq()]: *** mmc0 got interrupt: 0x00018000
[    1.147183] sdhci [sdhci_irq()]: *** mmc0 got interrupt: 0x00018000
[ ... repeat forever ]


-Olof
--
To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index 362a838..0bb892c 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -2413,9 +2413,8 @@  static void sdhci_data_irq(struct sdhci_host *host, u32 intmask)
 	}
 }
 
-static irqreturn_t sdhci_irq(int irq, void *dev_id)
+static irqreturn_t sdhci_irq_thread(int irq, void *dev_id)
 {
-	irqreturn_t result;
 	struct sdhci_host *host = dev_id;
 	u32 intmask, unexpected = 0;
 	int cardint = 0, max_loops = 16;
@@ -2431,15 +2430,7 @@  static irqreturn_t sdhci_irq(int irq, void *dev_id)
 
 	intmask = sdhci_readl(host, SDHCI_INT_STATUS);
 
-	if (!intmask || intmask == 0xffffffff) {
-		result = IRQ_NONE;
-		goto out;
-	}
-
 again:
-	DBG("*** %s got interrupt: 0x%08x\n",
-		mmc_hostname(host->mmc), intmask);
-
 	if (intmask & (SDHCI_INT_CARD_INSERT | SDHCI_INT_CARD_REMOVE)) {
 		u32 present = sdhci_readl(host, SDHCI_PRESENT_STATE) &
 			      SDHCI_CARD_PRESENT;
@@ -2499,12 +2490,10 @@  again:
 		sdhci_writel(host, intmask, SDHCI_INT_STATUS);
 	}
 
-	result = IRQ_HANDLED;
-
 	intmask = sdhci_readl(host, SDHCI_INT_STATUS);
 	if (intmask && --max_loops)
 		goto again;
-out:
+
 	spin_unlock(&host->lock);
 
 	if (unexpected) {
@@ -2518,7 +2507,27 @@  out:
 	if (cardint)
 		mmc_signal_sdio_irq(host->mmc);
 
-	return result;
+	intmask = sdhci_readl(host, SDHCI_INT_ENABLE);
+	sdhci_writel(host, intmask, SDHCI_SIGNAL_ENABLE);
+
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t sdhci_irq(int irq, void *dev_id)
+{
+	struct sdhci_host *host = dev_id;
+	u32 intmask = sdhci_readl(host, SDHCI_INT_STATUS);
+
+	if (!intmask || intmask == 0xffffffff)
+		return IRQ_NONE;
+
+	/* Disable interrupts */
+	sdhci_writel(host, 0, SDHCI_SIGNAL_ENABLE);
+
+	DBG("*** %s got interrupt: 0x%08x\n",
+		mmc_hostname(host->mmc), intmask);
+
+	return IRQ_WAKE_THREAD;
 }
 
 /*****************************************************************************\
@@ -2605,8 +2614,9 @@  int sdhci_resume_host(struct sdhci_host *host)
 	}
 
 	if (!device_may_wakeup(mmc_dev(host->mmc))) {
-		ret = request_irq(host->irq, sdhci_irq, IRQF_SHARED,
-				  mmc_hostname(host->mmc), host);
+		ret = request_threaded_irq(host->irq, sdhci_irq,
+			sdhci_irq_thread, IRQF_SHARED,
+			mmc_hostname(host->mmc), host);
 		if (ret)
 			return ret;
 	} else {
@@ -3226,8 +3236,8 @@  int sdhci_add_host(struct sdhci_host *host)
 
 	sdhci_init(host, 0);
 
-	ret = request_irq(host->irq, sdhci_irq, IRQF_SHARED,
-		mmc_hostname(mmc), host);
+	ret = request_threaded_irq(host->irq, sdhci_irq, sdhci_irq_thread,
+			  IRQF_SHARED, mmc_hostname(host->mmc), host);
 	if (ret) {
 		pr_err("%s: Failed to request IRQ %d: %d\n",
 		       mmc_hostname(mmc), host->irq, ret);