diff mbox

[09/10] mmc: mmci: Handle CMD irq before DATA irq

Message ID 1390402824-9850-10-git-send-email-ulf.hansson@linaro.org
State Superseded
Headers show

Commit Message

Ulf Hansson Jan. 22, 2014, 3 p.m. UTC
In case of a read operation both MCI_CMDRESPEND and MCI_DATAEND can be
set in the status register when entering the interrupt handler. This is
due to that the card start sending data before the host has
acknowledged the command response.

To resolve the issue for this scenario, we must start by handling the
CMD irq instead of the DATA irq. The reason is beacuse the completion
of the DATA irq will not respect the current command and then causing
it to be garbled.

Cc: Russell King <linux@arm.linux.org.uk>
Cc: Johan Rudholm <jrudholm@gmail.com>
Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
---
 drivers/mmc/host/mmci.c |    9 +++++----
 1 file changed, 5 insertions(+), 4 deletions(-)

Comments

Ulf Hansson Jan. 22, 2014, 3:43 p.m. UTC | #1
On 22 January 2014 16:19, Russell King - ARM Linux
<linux@arm.linux.org.uk> wrote:
> On Wed, Jan 22, 2014 at 04:00:23PM +0100, Ulf Hansson wrote:
>> In case of a read operation both MCI_CMDRESPEND and MCI_DATAEND can be
>> set in the status register when entering the interrupt handler. This is
>> due to that the card start sending data before the host has
>> acknowledged the command response.
>>
>> To resolve the issue for this scenario, we must start by handling the
>> CMD irq instead of the DATA irq. The reason is beacuse the completion
>> of the DATA irq will not respect the current command and then causing
>> it to be garbled.
>
> And that's because the driver isn't written to be able to handle a
> command being issued concurrently with a data transfer, because it
> only has one place to store the current command.

For a READ request, we are starting the data state machine by invoking
mmci_start_data before we send the READ command. That is not like we
handle concurrent requests, it is still only one request we are
operating on.

Now, suppose you have a high interface speed and a well performing
card, that will mean you can actually get the DATAEND irq at the same
time you get the CMD response. It is only because of this scenario we
need to reverse the order of handling the IRQs. Sorry if the commit
message was to vague.

>
> Consider what happens in this case:
>
> - Command issued to start a transfer.
> - Command completes, data transfer starts.
> - New command comes along to be issued, and is in progress
> - Data transfer finishes, we now issue the stop command to halt the
>   transfer
> - We overwrite the new command with the stop command
>
> All hell breaks loose.  No, this isn't a fix I want to see until the
> driver can properly handle concurrent commands.

This is not the scenario I want or need to solve. The host must only
handle one request at time. When we are done, we do call
mmc_request_done, which tells the mmc core it's fine to start a new
one. So the above sequence is not even possible.

Kind regards
Ulf Hansson

>
> --
> FTTC broadband for 0.8mile line: 5.8Mbps down 500kbps up.  Estimation
> in database were 13.1 to 19Mbit for a good line, about 7.5+ for a bad.
> Estimate before purchase was "up to 13.2Mbit".
--
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/mmci.c b/drivers/mmc/host/mmci.c
index f320579..1a4b153 100644
--- a/drivers/mmc/host/mmci.c
+++ b/drivers/mmc/host/mmci.c
@@ -1144,16 +1144,17 @@  static irqreturn_t mmci_irq(int irq, void *dev_id)
 
 		dev_dbg(mmc_dev(host->mmc), "irq0 (data+cmd) %08x\n", status);
 
+		cmd = host->cmd;
+		if (status & (MCI_CMDCRCFAIL|MCI_CMDTIMEOUT|MCI_CMDSENT|
+			      MCI_CMDRESPEND) && cmd)
+			mmci_cmd_irq(host, cmd, status);
+
 		data = host->data;
 		if (status & (MCI_DATACRCFAIL|MCI_DATATIMEOUT|MCI_STARTBITERR|
 			      MCI_TXUNDERRUN|MCI_RXOVERRUN|MCI_DATAEND|
 			      MCI_DATABLOCKEND) && data)
 			mmci_data_irq(host, data, status);
 
-		cmd = host->cmd;
-		if (status & (MCI_CMDCRCFAIL|MCI_CMDTIMEOUT|MCI_CMDSENT|MCI_CMDRESPEND) && cmd)
-			mmci_cmd_irq(host, cmd, status);
-
 		ret = 1;
 	} while (status);