linux-mmc.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [RFC 1/2] mmc: davinci: Eliminate spurious interrupts
       [not found] <4F1E9194.90608@mvista.com>
@ 2012-01-24 11:16 ` Ido Yariv
  2012-01-24 11:16   ` [RFC 2/2] mmc: davinci: Poll status for small size transfers Ido Yariv
                     ` (2 more replies)
  0 siblings, 3 replies; 8+ messages in thread
From: Ido Yariv @ 2012-01-24 11:16 UTC (permalink / raw)
  To: davinci-linux-open-source, linux-mmc, Chris Ball, Sekhar Nori; +Cc: Ido Yariv

The davinci mmc interrupt handler fills the fifo, as long as the DXRDY
or DRRDY bits are set in the status register.

If interrupts fire during this loop, they will be handled by the
handler, but the interrupt controller will still buffer these. As a
result, the handler will be called again to serve these needlessly. In
order to avoid these spurious interrupts, keep interrupts masked while
filling the fifo.

Signed-off-by: Ido Yariv <ido@wizery.com>
---
 drivers/mmc/host/davinci_mmc.c |   33 +++++++++++++++++++++++++++------
 1 files changed, 27 insertions(+), 6 deletions(-)

diff --git a/drivers/mmc/host/davinci_mmc.c b/drivers/mmc/host/davinci_mmc.c
index 64a8325..9cea66f 100644
--- a/drivers/mmc/host/davinci_mmc.c
+++ b/drivers/mmc/host/davinci_mmc.c
@@ -1009,12 +1009,33 @@ static irqreturn_t mmc_davinci_irq(int irq, void *dev_id)
 	 * by read. So, it is not unbouned loop even in the case of
 	 * non-dma.
 	 */
-	while (host->bytes_left && (status & (MMCST0_DXRDY | MMCST0_DRRDY))) {
-		davinci_fifo_data_trans(host, rw_threshold);
-		status = readl(host->base + DAVINCI_MMCST0);
-		if (!status)
-			break;
-		qstatus |= status;
+	if (host->bytes_left && (status & (MMCST0_DXRDY | MMCST0_DRRDY))) {
+		unsigned long im_val;
+
+		/*
+		 * If interrupts fire during the following loop, they will be
+		 * handled by the handler, but the PIC will still buffer these.
+		 * As a result, the handler will be called again to serve these
+		 * needlessly. In order to avoid these spurious interrupts,
+		 * keep interrupts masked during the loop.
+		 */
+		im_val = readl(host->base + DAVINCI_MMCIM);
+		writel(0, host->base + DAVINCI_MMCIM);
+
+		do {
+			davinci_fifo_data_trans(host, rw_threshold);
+			status = readl(host->base + DAVINCI_MMCST0);
+			qstatus |= status;
+		} while (host->bytes_left &&
+			 (status & (MMCST0_DXRDY | MMCST0_DRRDY)));
+
+		/*
+		 * If an interrupt is pending, it is assumed it will fire when
+		 * it is unmasked. This assumption is also taken when the MMCIM
+		 * is first set. Otherwise, writing to MMCIM after reading the
+		 * status is race-prone.
+		 */
+		writel(im_val, host->base + DAVINCI_MMCIM);
 	}
 
 	if (qstatus & MMCST0_DATDNE) {
-- 
1.7.7.5


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [RFC 2/2] mmc: davinci: Poll status for small size transfers
  2012-01-24 11:16 ` [RFC 1/2] mmc: davinci: Eliminate spurious interrupts Ido Yariv
@ 2012-01-24 11:16   ` Ido Yariv
  2012-01-27  8:11   ` [RFC 1/2] mmc: davinci: Eliminate spurious interrupts Rajashekhara, Sudhakar
       [not found]   ` <1327403766-962-1-git-send-email-ido-Ix1uc/W3ht7QT0dZR+AlfA@public.gmane.org>
  2 siblings, 0 replies; 8+ messages in thread
From: Ido Yariv @ 2012-01-24 11:16 UTC (permalink / raw)
  To: davinci-linux-open-source, linux-mmc, Chris Ball, Sekhar Nori; +Cc: Ido Yariv

For small size non-dma sdio transactions, it is sometimes better to poll
the mmc host and avoid interrupts altogether. Polling lowers the number
of interrupts and context switches. Tests have shown that for small
transactions, only a few polling iterations are needed, so this is worth
while.

Signed-off-by: Ido Yariv <ido@wizery.com>
---
 drivers/mmc/host/davinci_mmc.c |   29 ++++++++++++++++++++++++++++-
 1 files changed, 28 insertions(+), 1 deletions(-)

diff --git a/drivers/mmc/host/davinci_mmc.c b/drivers/mmc/host/davinci_mmc.c
index 9cea66f..fb1368a 100644
--- a/drivers/mmc/host/davinci_mmc.c
+++ b/drivers/mmc/host/davinci_mmc.c
@@ -160,6 +160,16 @@ module_param(rw_threshold, uint, S_IRUGO);
 MODULE_PARM_DESC(rw_threshold,
 		"Read/Write threshold. Default = 32");
 
+static unsigned poll_threshold = 128;
+module_param(poll_threshold, uint, S_IRUGO);
+MODULE_PARM_DESC(poll_threshold,
+		 "Polling transaction size threshold. Default = 128");
+
+static unsigned poll_loopcount = 32;
+module_param(poll_loopcount, uint, S_IRUGO);
+MODULE_PARM_DESC(poll_loopcount,
+		 "Maximum polling loop count. Default = 32");
+
 static unsigned __initdata use_dma = 1;
 module_param(use_dma, uint, 0);
 MODULE_PARM_DESC(use_dma, "Whether to use DMA or not. Default = 1");
@@ -193,6 +203,7 @@ struct mmc_davinci_host {
 	bool use_dma;
 	bool do_dma;
 	bool sdio_int;
+	bool active_request;
 
 	/* Scatterlist DMA uses one or more parameter RAM entries:
 	 * the main one (associated with rxdma or txdma) plus zero or
@@ -219,6 +230,7 @@ struct mmc_davinci_host {
 #endif
 };
 
+static irqreturn_t mmc_davinci_irq(int irq, void *dev_id);
 
 /* PIO only */
 static void mmc_davinci_sg_to_buf(struct mmc_davinci_host *host)
@@ -376,7 +388,20 @@ static void mmc_davinci_start_command(struct mmc_davinci_host *host,
 
 	writel(cmd->arg, host->base + DAVINCI_MMCARGHL);
 	writel(cmd_reg,  host->base + DAVINCI_MMCCMD);
-	writel(im_val, host->base + DAVINCI_MMCIM);
+
+	host->active_request = true;
+
+	if (!host->do_dma && host->bytes_left <= poll_threshold) {
+		u32 count = poll_loopcount;
+
+		while (host->active_request && count--) {
+			mmc_davinci_irq(0, host);
+			cpu_relax();
+		}
+	}
+
+	if (host->active_request)
+		writel(im_val, host->base + DAVINCI_MMCIM);
 }
 
 /*----------------------------------------------------------------------*/
@@ -915,6 +940,7 @@ mmc_davinci_xfer_done(struct mmc_davinci_host *host, struct mmc_data *data)
 	if (!data->stop || (host->cmd && host->cmd->error)) {
 		mmc_request_done(host->mmc, data->mrq);
 		writel(0, host->base + DAVINCI_MMCIM);
+		host->active_request = false;
 	} else
 		mmc_davinci_start_command(host, data->stop);
 }
@@ -942,6 +968,7 @@ static void mmc_davinci_cmd_done(struct mmc_davinci_host *host,
 			cmd->mrq->cmd->retries = 0;
 		mmc_request_done(host->mmc, cmd->mrq);
 		writel(0, host->base + DAVINCI_MMCIM);
+		host->active_request = false;
 	}
 }
 
-- 
1.7.7.5


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* RE: [RFC 1/2] mmc: davinci: Eliminate spurious interrupts
  2012-01-24 11:16 ` [RFC 1/2] mmc: davinci: Eliminate spurious interrupts Ido Yariv
  2012-01-24 11:16   ` [RFC 2/2] mmc: davinci: Poll status for small size transfers Ido Yariv
@ 2012-01-27  8:11   ` Rajashekhara, Sudhakar
  2012-01-29 19:37     ` Ido Yariv
       [not found]   ` <1327403766-962-1-git-send-email-ido-Ix1uc/W3ht7QT0dZR+AlfA@public.gmane.org>
  2 siblings, 1 reply; 8+ messages in thread
From: Rajashekhara, Sudhakar @ 2012-01-27  8:11 UTC (permalink / raw)
  To: Ido Yariv, davinci-linux-open-source@linux.davincidsp.com,
	linux-mmc@vger.kernel.org, Chris Ball, Nori, Sekhar

Hello Ido,

On Tue, Jan 24, 2012 at 16:46:05, Ido Yariv wrote:
> The davinci mmc interrupt handler fills the fifo, as long as the DXRDY
> or DRRDY bits are set in the status register.
> 
> If interrupts fire during this loop, they will be handled by the
> handler, but the interrupt controller will still buffer these. As a
> result, the handler will be called again to serve these needlessly. In
> order to avoid these spurious interrupts, keep interrupts masked while
> filling the fifo.
> 

I tested both these patches and they work fine on the OMAP-L138 EVM. I
observed that with these patches the number of interrupts during a transfer
are less compared to earlier. For a 100 MB transfer, I could see around
700-800 interrupts less. Did you see any performance improvement with these
patches?

Thanks,
Sudhakar

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [RFC 1/2] mmc: davinci: Eliminate spurious interrupts
  2012-01-27  8:11   ` [RFC 1/2] mmc: davinci: Eliminate spurious interrupts Rajashekhara, Sudhakar
@ 2012-01-29 19:37     ` Ido Yariv
  0 siblings, 0 replies; 8+ messages in thread
From: Ido Yariv @ 2012-01-29 19:37 UTC (permalink / raw)
  To: Rajashekhara, Sudhakar
  Cc: davinci-linux-open-source@linux.davincidsp.com,
	linux-mmc@vger.kernel.org, Chris Ball, Nori, Sekhar

Hello Sudhakar,

On Fri, Jan 27, 2012 at 08:11:55AM +0000, Rajashekhara, Sudhakar wrote:
> I tested both these patches and they work fine on the OMAP-L138 EVM. I
> observed that with these patches the number of interrupts during a transfer
> are less compared to earlier. For a 100 MB transfer, I could see around
> 700-800 interrupts less. Did you see any performance improvement with these
> patches?

Thanks for testing these.

The difference in the number of interrupts, or rather the ratio, depends
on the scenario you're working on.
The spurious patch has an effect on non-dma transfers, while the polling
optimization affects small (i.e. up to 128 bytes) transactions.
I expect these to have a greater impact on SDIO scenarios than on SD scenarios.

Regarding the performance improvement, these patches were tested using a
WLAN SDIO adapter, which requires quite a few small transactions.
The polling optimization had an impact of around 10-15% in throughput.
The spurious patch did not have any noticeable effect on throughput, but did
lower the number of interrupts by up to 25% in some cases.

Thanks,
Ido.

^ permalink raw reply	[flat|nested] 8+ messages in thread

* RE: [RFC 1/2] mmc: davinci: Eliminate spurious interrupts
       [not found]   ` <1327403766-962-1-git-send-email-ido-Ix1uc/W3ht7QT0dZR+AlfA@public.gmane.org>
@ 2012-01-31 11:30     ` Rajashekhara, Sudhakar
  2012-03-11 21:39       ` [PATCH REPOST " Ido Yariv
  0 siblings, 1 reply; 8+ messages in thread
From: Rajashekhara, Sudhakar @ 2012-01-31 11:30 UTC (permalink / raw)
  To: Ido Yariv,
	davinci-linux-open-source-VycZQUHpC/PFrsHnngEfi1aTQe2KTcn/@public.gmane.org,
	linux-mmc-u79uwXL29TY76Z2rM5mHXA@public.gmane.org, Chris Ball,
	Nori, Sekhar

Hi,

On Tue, Jan 24, 2012 at 16:46:05, Ido Yariv wrote:
> The davinci mmc interrupt handler fills the fifo, as long as the DXRDY
> or DRRDY bits are set in the status register.
> 
> If interrupts fire during this loop, they will be handled by the
> handler, but the interrupt controller will still buffer these. As a
> result, the handler will be called again to serve these needlessly. In
> order to avoid these spurious interrupts, keep interrupts masked while
> filling the fifo.
> 
> Signed-off-by: Ido Yariv <ido-Ix1uc/W3ht7QT0dZR+AlfA@public.gmane.org>
> ---

Tested this series on OMAP-L138 EVM using SD card. Observed that number of
interrupts during IO transaction were less compared to earlier and there
was no drop in performance numbers.

Tested-by: Rajashekhara, Sudhakar <sudhakar.raj-l0cyMroinI0@public.gmane.org>

Regards,
Sudhakar

^ permalink raw reply	[flat|nested] 8+ messages in thread

* [PATCH REPOST 1/2] mmc: davinci: Eliminate spurious interrupts
  2012-01-31 11:30     ` Rajashekhara, Sudhakar
@ 2012-03-11 21:39       ` Ido Yariv
  2012-03-11 21:39         ` [PATCH REPOST 2/2] mmc: davinci: Poll status for small size transfers Ido Yariv
  2012-03-16  3:32         ` [PATCH REPOST 1/2] mmc: davinci: Eliminate spurious interrupts Chris Ball
  0 siblings, 2 replies; 8+ messages in thread
From: Ido Yariv @ 2012-03-11 21:39 UTC (permalink / raw)
  To: Chris Ball, Sekhar Nori, linux-mmc, davinci-linux-open-source; +Cc: Ido Yariv

The davinci mmc interrupt handler fills the fifo, as long as the DXRDY
or DRRDY bits are set in the status register.

If interrupts fire during this loop, they will be handled by the
handler, but the interrupt controller will still buffer these. As a
result, the handler will be called again to serve these needlessly. In
order to avoid these spurious interrupts, keep interrupts masked while
filling the fifo.

Signed-off-by: Ido Yariv <ido@wizery.com>
Tested-by: Rajashekhara, Sudhakar <sudhakar.raj@ti.com>
---
 drivers/mmc/host/davinci_mmc.c |   33 +++++++++++++++++++++++++++------
 1 files changed, 27 insertions(+), 6 deletions(-)

diff --git a/drivers/mmc/host/davinci_mmc.c b/drivers/mmc/host/davinci_mmc.c
index 64a8325..9cea66f 100644
--- a/drivers/mmc/host/davinci_mmc.c
+++ b/drivers/mmc/host/davinci_mmc.c
@@ -1009,12 +1009,33 @@ static irqreturn_t mmc_davinci_irq(int irq, void *dev_id)
 	 * by read. So, it is not unbouned loop even in the case of
 	 * non-dma.
 	 */
-	while (host->bytes_left && (status & (MMCST0_DXRDY | MMCST0_DRRDY))) {
-		davinci_fifo_data_trans(host, rw_threshold);
-		status = readl(host->base + DAVINCI_MMCST0);
-		if (!status)
-			break;
-		qstatus |= status;
+	if (host->bytes_left && (status & (MMCST0_DXRDY | MMCST0_DRRDY))) {
+		unsigned long im_val;
+
+		/*
+		 * If interrupts fire during the following loop, they will be
+		 * handled by the handler, but the PIC will still buffer these.
+		 * As a result, the handler will be called again to serve these
+		 * needlessly. In order to avoid these spurious interrupts,
+		 * keep interrupts masked during the loop.
+		 */
+		im_val = readl(host->base + DAVINCI_MMCIM);
+		writel(0, host->base + DAVINCI_MMCIM);
+
+		do {
+			davinci_fifo_data_trans(host, rw_threshold);
+			status = readl(host->base + DAVINCI_MMCST0);
+			qstatus |= status;
+		} while (host->bytes_left &&
+			 (status & (MMCST0_DXRDY | MMCST0_DRRDY)));
+
+		/*
+		 * If an interrupt is pending, it is assumed it will fire when
+		 * it is unmasked. This assumption is also taken when the MMCIM
+		 * is first set. Otherwise, writing to MMCIM after reading the
+		 * status is race-prone.
+		 */
+		writel(im_val, host->base + DAVINCI_MMCIM);
 	}
 
 	if (qstatus & MMCST0_DATDNE) {
-- 
1.7.7.6


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH REPOST 2/2] mmc: davinci: Poll status for small size transfers
  2012-03-11 21:39       ` [PATCH REPOST " Ido Yariv
@ 2012-03-11 21:39         ` Ido Yariv
  2012-03-16  3:32         ` [PATCH REPOST 1/2] mmc: davinci: Eliminate spurious interrupts Chris Ball
  1 sibling, 0 replies; 8+ messages in thread
From: Ido Yariv @ 2012-03-11 21:39 UTC (permalink / raw)
  To: Chris Ball, Sekhar Nori, linux-mmc, davinci-linux-open-source; +Cc: Ido Yariv

For small size non-dma sdio transactions, it is sometimes better to poll
the mmc host and avoid interrupts altogether. Polling lowers the number
of interrupts and context switches. Tests have shown that for small
transactions, only a few polling iterations are needed, so this is worth
while.

Signed-off-by: Ido Yariv <ido@wizery.com>
Tested-by: Rajashekhara, Sudhakar <sudhakar.raj@ti.com>
---
 drivers/mmc/host/davinci_mmc.c |   29 ++++++++++++++++++++++++++++-
 1 files changed, 28 insertions(+), 1 deletions(-)

diff --git a/drivers/mmc/host/davinci_mmc.c b/drivers/mmc/host/davinci_mmc.c
index 9cea66f..fb1368a 100644
--- a/drivers/mmc/host/davinci_mmc.c
+++ b/drivers/mmc/host/davinci_mmc.c
@@ -160,6 +160,16 @@ module_param(rw_threshold, uint, S_IRUGO);
 MODULE_PARM_DESC(rw_threshold,
 		"Read/Write threshold. Default = 32");
 
+static unsigned poll_threshold = 128;
+module_param(poll_threshold, uint, S_IRUGO);
+MODULE_PARM_DESC(poll_threshold,
+		 "Polling transaction size threshold. Default = 128");
+
+static unsigned poll_loopcount = 32;
+module_param(poll_loopcount, uint, S_IRUGO);
+MODULE_PARM_DESC(poll_loopcount,
+		 "Maximum polling loop count. Default = 32");
+
 static unsigned __initdata use_dma = 1;
 module_param(use_dma, uint, 0);
 MODULE_PARM_DESC(use_dma, "Whether to use DMA or not. Default = 1");
@@ -193,6 +203,7 @@ struct mmc_davinci_host {
 	bool use_dma;
 	bool do_dma;
 	bool sdio_int;
+	bool active_request;
 
 	/* Scatterlist DMA uses one or more parameter RAM entries:
 	 * the main one (associated with rxdma or txdma) plus zero or
@@ -219,6 +230,7 @@ struct mmc_davinci_host {
 #endif
 };
 
+static irqreturn_t mmc_davinci_irq(int irq, void *dev_id);
 
 /* PIO only */
 static void mmc_davinci_sg_to_buf(struct mmc_davinci_host *host)
@@ -376,7 +388,20 @@ static void mmc_davinci_start_command(struct mmc_davinci_host *host,
 
 	writel(cmd->arg, host->base + DAVINCI_MMCARGHL);
 	writel(cmd_reg,  host->base + DAVINCI_MMCCMD);
-	writel(im_val, host->base + DAVINCI_MMCIM);
+
+	host->active_request = true;
+
+	if (!host->do_dma && host->bytes_left <= poll_threshold) {
+		u32 count = poll_loopcount;
+
+		while (host->active_request && count--) {
+			mmc_davinci_irq(0, host);
+			cpu_relax();
+		}
+	}
+
+	if (host->active_request)
+		writel(im_val, host->base + DAVINCI_MMCIM);
 }
 
 /*----------------------------------------------------------------------*/
@@ -915,6 +940,7 @@ mmc_davinci_xfer_done(struct mmc_davinci_host *host, struct mmc_data *data)
 	if (!data->stop || (host->cmd && host->cmd->error)) {
 		mmc_request_done(host->mmc, data->mrq);
 		writel(0, host->base + DAVINCI_MMCIM);
+		host->active_request = false;
 	} else
 		mmc_davinci_start_command(host, data->stop);
 }
@@ -942,6 +968,7 @@ static void mmc_davinci_cmd_done(struct mmc_davinci_host *host,
 			cmd->mrq->cmd->retries = 0;
 		mmc_request_done(host->mmc, cmd->mrq);
 		writel(0, host->base + DAVINCI_MMCIM);
+		host->active_request = false;
 	}
 }
 
-- 
1.7.7.6


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* Re: [PATCH REPOST 1/2] mmc: davinci: Eliminate spurious interrupts
  2012-03-11 21:39       ` [PATCH REPOST " Ido Yariv
  2012-03-11 21:39         ` [PATCH REPOST 2/2] mmc: davinci: Poll status for small size transfers Ido Yariv
@ 2012-03-16  3:32         ` Chris Ball
  1 sibling, 0 replies; 8+ messages in thread
From: Chris Ball @ 2012-03-16  3:32 UTC (permalink / raw)
  To: Ido Yariv; +Cc: Sekhar Nori, linux-mmc, davinci-linux-open-source

Hi,

On Sun, Mar 11 2012, Ido Yariv wrote:
> The davinci mmc interrupt handler fills the fifo, as long as the DXRDY
> or DRRDY bits are set in the status register.
>
> If interrupts fire during this loop, they will be handled by the
> handler, but the interrupt controller will still buffer these. As a
> result, the handler will be called again to serve these needlessly. In
> order to avoid these spurious interrupts, keep interrupts masked while
> filling the fifo.
>
> Signed-off-by: Ido Yariv <ido@wizery.com>
> Tested-by: Rajashekhara, Sudhakar <sudhakar.raj@ti.com>

Thanks, I've pushed both of these two patches to mmc-next for 3.4 now.

- Chris.
-- 
Chris Ball   <cjb@laptop.org>   <http://printf.net/>
One Laptop Per Child

^ permalink raw reply	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2012-03-16  3:32 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
     [not found] <4F1E9194.90608@mvista.com>
2012-01-24 11:16 ` [RFC 1/2] mmc: davinci: Eliminate spurious interrupts Ido Yariv
2012-01-24 11:16   ` [RFC 2/2] mmc: davinci: Poll status for small size transfers Ido Yariv
2012-01-27  8:11   ` [RFC 1/2] mmc: davinci: Eliminate spurious interrupts Rajashekhara, Sudhakar
2012-01-29 19:37     ` Ido Yariv
     [not found]   ` <1327403766-962-1-git-send-email-ido-Ix1uc/W3ht7QT0dZR+AlfA@public.gmane.org>
2012-01-31 11:30     ` Rajashekhara, Sudhakar
2012-03-11 21:39       ` [PATCH REPOST " Ido Yariv
2012-03-11 21:39         ` [PATCH REPOST 2/2] mmc: davinci: Poll status for small size transfers Ido Yariv
2012-03-16  3:32         ` [PATCH REPOST 1/2] mmc: davinci: Eliminate spurious interrupts Chris Ball

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).