Re: [PATCH] mmc: mmci: Send a CMD12 to clear the DPSM at errors

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



hi Ulf

I think you can apply this patch.
The R1B problem (due to busy timeout) can be seen in a future series
about busy detect.
Thanks

Tested-by: Ludovic Barre <ludovic.barre@xxxxxx>

Regards
Ludo

On 2/20/19 11:27 AM, Ludovic BARRE wrote:
hi Ulf

On 2/4/19 4:39 PM, Ulf Hansson wrote:
On Mon, 4 Feb 2019 at 15:18, Ludovic BARRE <ludovic.barre@xxxxxx> wrote:

hi Ulf

One comment below in mmci_cmd_irq function

when I rebase my next serie about "busy detect" I've a kernel panic
null pointer, could you give me some time to investigate this issue
before apply this patch.

Sure!

FYI, I have tested this on a ux500 and didn't observe any regressions.

great




On 1/29/19 3:35 PM, Ulf Hansson wrote:
The current approach with sending a CMD12 (STOP_TRANSMISSION) to complete a data transfer request, either because of using the open-ended transmission type or because of receiving an error during a pre-defined data transfer, isn't sufficient for the STM32 sdmmc variant. More precisely, this variant needs to clear the DPSM ("Data Path State Machine") by sending a CMD12, for
all failing ADTC commands.

Support this, by adding a struct mmc_command inside the struct mmci_host and initialize it to a CMD12 during ->probe(). Let's also add checks for
the new conditions, to enable mmci_data_irq() and mmci_cmd_irq() to
postpone the calls to mmci_request_end(), but instead send the CMD12.

Cc: Ludovic Barre <ludovic.barre@xxxxxx>
Signed-off-by: Ulf Hansson <ulf.hansson@xxxxxxxxxx>
---
   drivers/mmc/host/mmci.c | 25 +++++++++++++++++++++++--
   drivers/mmc/host/mmci.h |  1 +
   2 files changed, 24 insertions(+), 2 deletions(-)

diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c
index e352f5ad5801..45b97b41601c 100644
--- a/drivers/mmc/host/mmci.c
+++ b/drivers/mmc/host/mmci.c
@@ -1127,6 +1127,12 @@ mmci_start_command(struct mmci_host *host, struct mmc_command *cmd, u32 c)
       writel(c, base + MMCICOMMAND);
   }

+static void mmci_stop_command(struct mmci_host *host)
+{
+     host->stop_abort.error = 0;
+     mmci_start_command(host, &host->stop_abort, 0);
+}
+
   static void
   mmci_data_irq(struct mmci_host *host, struct mmc_data *data,
             unsigned int status)
@@ -1196,10 +1202,16 @@ mmci_data_irq(struct mmci_host *host, struct mmc_data *data,                        /* The error clause is handled above, success! */
                       data->bytes_xfered = data->blksz * data->blocks;

-             if (!data->stop || (host->mrq->sbc && !data->error))
+             if (!data->stop) {
+                     if (host->variant->cmdreg_stop && data->error)
+                             mmci_stop_command(host);
+                     else
+                             mmci_request_end(host, data->mrq);
+             } else if (host->mrq->sbc && !data->error) {
                       mmci_request_end(host, data->mrq);
-             else
+             } else {
                       mmci_start_command(host, data->stop, 0);
+             }
       }
   }

@@ -1298,6 +1310,10 @@ mmci_cmd_irq(struct mmci_host *host, struct mmc_command *cmd,
                       mmci_dma_error(host);

                       mmci_stop_data(host);
+                     if (host->variant->cmdreg_stop && cmd->error) {
+                             mmci_stop_command(host);
+                             return;
+                     }

               }

In fact a cmd without host->data could fail with DPSM enabled.
example:
sent a cmd12 with MMC_RSP_BUSY flag (R1B command) and so no data.
In sdmmc variant the MMCIDATATIMER is used to busy timeout.
The DPSM is used to sample D0 line and is activated.
the DTIMEOUT flag is set after when no end of busy received before the
timeout. (DPSM stays in BUSY and wait for Abort)

Oh, that I didn't know about! That make it quite complicated, I am afraid.

To send a new CMD12 to clear the DPSM, because the previous CDM12
failed seems just wrong. Why would the second CMD12 succeed and not
timeout again, if you see what I mean.

There are also other commands using R1B, that doesn't involve
transferring data. The CMD5 (sleep) for example. If any of these
commands would timeout, then why would a following CMD12 not do so as
well?

To me, it seems like a reset of the controller is the only really sane
way of treating these scenarios, isn't it? Of course, it means we need
to be able to restore the state of the controller after such a reset
as well. Is this possible?


POV sdmmc hardware block the second cmd12 just allows to clear the DPSM
(for stop abort cmd the R1B may not be set).
I agree with you, if a command fail due to R1B (busy timeout) the better
way is to reset the controller, protocol...

Do to that we could call mmc_hw_reset function
(drivers/mmc/core/core.c). However this function can't be call
in irq context and ongoing request must be completed.

proposition:
The host driver could set a error value (in cmd->error or data->error)
like EDEADLK or ECONNRESET (to be defined)...
The framework could check error value (for example in
mmc_wait_for_req_done) and call mmc_hw_reset if needed.

What do you think?


So The mmci_stop_command may be sent when there are cmd->error  and
status & MCI_DATATIMEOUT


               mmci_request_end(host, host->mrq);
       } else if (sbc) {
@@ -1956,6 +1972,11 @@ static int mmci_probe(struct amba_device *dev,
               mmc->max_busy_timeout = 0;
       }

+     /* Prepare a CMD12 - needed to clear the DPSM on some variants. */
+     host->stop_abort.opcode = MMC_STOP_TRANSMISSION;
+     host->stop_abort.arg = 0;
+     host->stop_abort.flags = MMC_RSP_R1B | MMC_CMD_AC;
+
       mmc->ops = &mmci_ops;

       /* We support these PM capabilities. */
diff --git a/drivers/mmc/host/mmci.h b/drivers/mmc/host/mmci.h
index 24229097d05c..14df81054438 100644
--- a/drivers/mmc/host/mmci.h
+++ b/drivers/mmc/host/mmci.h
@@ -377,6 +377,7 @@ struct mmci_host {
       void __iomem            *base;
       struct mmc_request      *mrq;
       struct mmc_command      *cmd;
+     struct mmc_command      stop_abort;
       struct mmc_data         *data;
       struct mmc_host         *mmc;
       struct clk              *clk;


Kind regards
Uffe




[Index of Archives]     [Linux Memonry Technology]     [Linux USB Devel]     [Linux Media]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux