linux-mmc.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Mike Looijmans <mike.looijmans@topic.nl>
To: linux-mmc@vger.kernel.org
Cc: cjb@laptop.org, ulf.hansson@linaro.org, linux-kernel@vger.kernel.org
Subject: Re: [PATCH] davinci-mmc: Use IRQ to detect "card not busy" status change
Date: Fri, 29 Aug 2014 08:43:41 +0200	[thread overview]
Message-ID: <5400211D.1060107@topic.nl> (raw)
In-Reply-To: <1409294496-4220-1-git-send-email-mike.looijmans@topic.nl>

Note: I have not been able to test or even compile this on recent 
kernels. Can somebody verify that this does not kill the SD driver?

Mike.

On 08/29/2014 08:41 AM, Mike Looijmans wrote:
> The davinci-mmc driver uses a busy wait loop to wait for the card to
> become ready (BUSY signal). The MMC card uses this to signal the
> controller that it's busy writing and cannot handle new requests yet.
> This loop often takes 100k cycles and 10ms to complete.
>
> The controller can raise an interrupt when the BUSY signal is deasserted,
> so the routine has been adapted to trigger an interrupt and wait for it
> using a wait_event_timeout instead of a busy wait loop.
>
> This reduces the CPU usage of the mmcqd process drastically, from 35% to
> 2% when writing to SD. No noticable change in performance or reliability.
>
> Tested on a custom board with an OMAP-L138 CPU. Patch originally applied
> to a 2.6.37 kernel and ported to 3.14.
>
> Signed-off-by: Mike Looijmans <mike.looijmans@topic.nl>
> ---
>   drivers/mmc/host/davinci_mmc.c |   52 +++++++++++++++++++++++++---------------
>   1 file changed, 33 insertions(+), 19 deletions(-)
>
> diff --git a/drivers/mmc/host/davinci_mmc.c b/drivers/mmc/host/davinci_mmc.c
> index d615374..50458f4 100644
> --- a/drivers/mmc/host/davinci_mmc.c
> +++ b/drivers/mmc/host/davinci_mmc.c
> @@ -223,6 +223,7 @@ struct mmc_davinci_host {
>   #ifdef CONFIG_CPU_FREQ
>   	struct notifier_block	freq_transition;
>   #endif
> +	wait_queue_head_t 	wait_while_busy_queue
>   };
>
>   static irqreturn_t mmc_davinci_irq(int irq, void *dev_id);
> @@ -628,23 +629,28 @@ mmc_davinci_prepare_data(struct mmc_davinci_host *host, struct mmc_request *req)
>   static void mmc_davinci_request(struct mmc_host *mmc, struct mmc_request *req)
>   {
>   	struct mmc_davinci_host *host = mmc_priv(mmc);
> -	unsigned long timeout = jiffies + msecs_to_jiffies(900);
> -	u32 mmcst1 = 0;
> +	unsigned int remaining;
>
>   	/* Card may still be sending BUSY after a previous operation,
>   	 * typically some kind of write.  If so, we can't proceed yet.
>   	 */
> -	while (time_before(jiffies, timeout)) {
> -		mmcst1  = readl(host->base + DAVINCI_MMCST1);
> -		if (!(mmcst1 & MMCST1_BUSY))
> -			break;
> -		cpu_relax();
> -	}
> -	if (mmcst1 & MMCST1_BUSY) {
> -		dev_err(mmc_dev(host->mmc), "still BUSY? bad ... \n");
> -		req->cmd->error = -ETIMEDOUT;
> -		mmc_request_done(mmc, req);
> -		return;
> +	if (readl(host->base + DAVINCI_MMCST1) & MMCST1_BUSY) {
> +		/* Arm BSYDNE interrupt and wait for it */
> +		writel(MMCST0_BSYDNE, host->base + DAVINCI_MMCIM);
> +		remaining = wait_event_timeout(
> +				host->wait_while_busy_queue,
> +				((readl(host->base + DAVINCI_MMCST1) & MMCST1_BUSY) == 0),
> +				msecs_to_jiffies(900));
> +		writel(0, host->base + DAVINCI_MMCIM);
> +		if (unlikely(remaining == 0))
> +		{
> +			if (readl(host->base + DAVINCI_MMCST1) & MMCST1_BUSY) {
> +				dev_err(mmc_dev(host->mmc), "Timeout waiting for BSYDNE interrupt.\n");
> +				req->cmd->error = -ETIMEDOUT;
> +				mmc_request_done(mmc, req);
> +				return;
> +			}
> +		}
>   	}
>
>   	host->do_dma = 0;
> @@ -914,18 +920,21 @@ static irqreturn_t mmc_davinci_irq(int irq, void *dev_id)
>   	int end_transfer = 0;
>   	struct mmc_data *data = host->data;
>
> +	status = readl(host->base + DAVINCI_MMCST0);
> +	qstatus = status;
> +
>   	if (host->cmd == NULL && host->data == NULL) {
> -		status = readl(host->base + DAVINCI_MMCST0);
> -		dev_dbg(mmc_dev(host->mmc),
> -			"Spurious interrupt 0x%04x\n", status);
> +		/* We may have been waiting for the busy-done signal */
> +		if (qstatus & MMCST0_BSYDNE) {
> +			wake_up(&host->wait_while_busy_queue);
> +			return IRQ_HANDLED;
> +		}
> +		dev_dbg(mmc_dev(host->mmc), "Spurious interrupt %#x\n", status);
>   		/* Disable the interrupt from mmcsd */
>   		writel(0, host->base + DAVINCI_MMCIM);
>   		return IRQ_NONE;
>   	}
>
> -	status = readl(host->base + DAVINCI_MMCST0);
> -	qstatus = status;
> -
>   	/* handle FIFO first when using PIO for data.
>   	 * bytes_left will decrease to zero as I/O progress and status will
>   	 * read zero over iteration because this controller status
> @@ -1044,6 +1053,10 @@ static irqreturn_t mmc_davinci_irq(int irq, void *dev_id)
>   		end_command = (int) host->cmd;
>   	}
>
> +	if (qstatus & MMCST0_BSYDNE) {
> +		wake_up(&host->wait_while_busy_queue);
> +	}
> +
>   	if (end_command)
>   		mmc_davinci_cmd_done(host, host->cmd);
>   	if (end_transfer)
> @@ -1261,6 +1274,7 @@ static int __init davinci_mmcsd_probe(struct platform_device *pdev)
>
>   	host = mmc_priv(mmc);
>   	host->mmc = mmc;	/* Important */
> +	init_waitqueue_head(&host->wait_while_busy_queue);
>
>   	r = platform_get_resource(pdev, IORESOURCE_DMA, 0);
>   	if (!r)
>


-- 
Mike Looijmans

      reply	other threads:[~2014-08-29  6:51 UTC|newest]

Thread overview: 2+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2014-08-29  6:41 [PATCH] davinci-mmc: Use IRQ to detect "card not busy" status change Mike Looijmans
2014-08-29  6:43 ` Mike Looijmans [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=5400211D.1060107@topic.nl \
    --to=mike.looijmans@topic.nl \
    --cc=cjb@laptop.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-mmc@vger.kernel.org \
    --cc=ulf.hansson@linaro.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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).