Discussion:
[PATCH 0/2] mxcmmc driver fixes
Matteo Facchinetti
2014-09-30 14:59:36 UTC
Permalink
From: Matteo Facchinetti <***@sirius-es.it>

Hi,

this patchset contains fixes for the mxcmmc driver.

*Patch 1:
fix a rare race condition that breaks a data trasfer when mxcmmc
driver use dma.
To reproduce this error, use mmc as rootfs and start at boot time
a realtime Xenomai application.
The realtime it's not directly related but entropy produced by
ipipe scheduler highlights the problem.
When this event occurs, the mxcmmc watchdog expires,
this cause a read error and application doesn't run.

*Patch 2:
fix the default value for available voltages into mxcmci_probe

Applied to mainline Linux-3.17.0-rc6-next on arch mpc512x.
Tested on mpc5125twr evaluation board

Applied to custom Linux-3.9.4 on arch mpc512x
Tested on a mpc5125 custom board.

Regards,
Matteo Facchinetti
Sirius Electronic Systems


Matteo Facchinetti (2):
mmc: mxcmmc: fix race condition when dma finish a data transfer
mmc: mxcmmc: fix the default value for available voltages into
mxcmci_probe

drivers/mmc/host/mxcmmc.c | 27 ++++++++++-----------------
1 file changed, 10 insertions(+), 17 deletions(-)
--
1.8.3.2

--
To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
the body of a message to ***@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Matteo Facchinetti
2014-09-30 14:59:38 UTC
Permalink
From: Matteo Facchinetti <***@sirius-es.it>

If available voltages are not given, mmc_regulator_get_supply() function
returns 0 and mxcmmc driver doesn't set a value for ocr_avail mask.

In accordance with the comment in platform_data/mmc-mxcmmc.h,
fix it, assuming MMC_VDD_32_33 | MMC_VDD_33_34 as default value.

Signed-off-by: Matteo Facchinetti <***@sirius-es.it>
---
drivers/mmc/host/mxcmmc.c | 14 +++++++-------
1 file changed, 7 insertions(+), 7 deletions(-)

diff --git a/drivers/mmc/host/mxcmmc.c b/drivers/mmc/host/mxcmmc.c
index 536a898..5350dc5 100644
--- a/drivers/mmc/host/mxcmmc.c
+++ b/drivers/mmc/host/mxcmmc.c
@@ -1077,13 +1077,13 @@ static int mxcmci_probe(struct platform_device *pdev)
dat3_card_detect = true;

ret = mmc_regulator_get_supply(mmc);
- if (ret) {
- if (pdata && ret != -EPROBE_DEFER)
- mmc->ocr_avail = pdata->ocr_avail ? :
- MMC_VDD_32_33 | MMC_VDD_33_34;
- else
- goto out_free;
- }
+ if (ret == -EPROBE_DEFER)
+ goto out_free;
+
+ if (pdata && pdata->ocr_avail)
+ mmc->ocr_avail = pdata->ocr_avail;
+ else
+ mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34;

if (dat3_card_detect)
host->default_irq_mask =
--
1.8.3.2

--
To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
the body of a message to ***@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Sascha Hauer
2014-10-08 06:46:52 UTC
Permalink
Post by Matteo Facchinetti
If available voltages are not given, mmc_regulator_get_supply() function
returns 0 and mxcmmc driver doesn't set a value for ocr_avail mask.
In accordance with the comment in platform_data/mmc-mxcmmc.h,
fix it, assuming MMC_VDD_32_33 | MMC_VDD_33_34 as default value.
---
drivers/mmc/host/mxcmmc.c | 14 +++++++-------
1 file changed, 7 insertions(+), 7 deletions(-)
diff --git a/drivers/mmc/host/mxcmmc.c b/drivers/mmc/host/mxcmmc.c
index 536a898..5350dc5 100644
--- a/drivers/mmc/host/mxcmmc.c
+++ b/drivers/mmc/host/mxcmmc.c
@@ -1077,13 +1077,13 @@ static int mxcmci_probe(struct platform_device *pdev)
dat3_card_detect = true;
ret = mmc_regulator_get_supply(mmc);
mmc_regulator_get_supply() sets mmc->ocr_avail based on the information
of the vmmc regulator if present...
Post by Matteo Facchinetti
- if (ret) {
- if (pdata && ret != -EPROBE_DEFER)
- MMC_VDD_32_33 | MMC_VDD_33_34;
- else
- goto out_free;
- }
+ if (ret == -EPROBE_DEFER)
+ goto out_free;
+
+ if (pdata && pdata->ocr_avail)
+ mmc->ocr_avail = pdata->ocr_avail;
+ else
+ mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34;
... and here mmc->ocr_avail is overwritten unconditionally.

Unfortunately the return value of mmc_regulator_get_supply() doesn't
indicate if it was successful in setting a ocr_avail. So I think the best
you can do here is:

if (!mmc->ocr_avail) {
if (pdata && pdata->ocr_avail)
mmc->ocr_avail = pdata->ocr_avail;
else
mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34;
}

Sascha
--
Pengutronix e.K. | |
Industrial Linux Solutions | http://www.pengutronix.de/ |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0 |
Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 |
--
To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
the body of a message to ***@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Matteo Facchinetti
2014-09-30 14:59:37 UTC
Permalink
From: Matteo Facchinetti <***@sirius-es.it>

During a read of data block using dma, driver might have two ways to finish to read
and free the resources:
1) checking STATUS_DATA_TRANS_DONE mask, in the mxcmci_irq() routine
(pending to mmc irq)
2) mxmmc driver, registers also a mxcmci_dma_callback() and when transfer is finished,
dma driver calls this callback. (pending to dma irq)
Both ways are concurrent with each other.

Race condition happens when following events occur:
/* (1) mxcmci driver start data transfer */
158.418970: mpc_dma_execute: mpc_dma_execute(): will_access_peripheral start cid=31
158.418976: mpc_dma_issue_pending <-mxcmci_request
158.418983: mxcmci_start_cmd <-mxcmci_request
/* (2) mxcmci driver receive mmc irq */
158.419656: mxcmci_irq <-handle_irq_event_percpu
158.419692: mxcmci_read_response <-mxcmci_irq
/* (3) mxcmci driver checks that transfer is complete and call mxcmci_finish_data() */
158.419726: mxcmci_data_done <-mxcmci_irq
158.419729: mxcmci_finish_data <-mxcmci_data_done
158.419733: dma_direct_unmap_sg <-mxcmci_finish_data
158.419736: mxcmci_swap_buffers.isra.24 <-mxcmci_finish_data
158.419762: mxcmci_read_response <-mxcmci_data_done
/* (4) mxcmci driver (no dma): send stop command */
158.419765: mxcmci_start_cmd <-mxcmci_data_done
/* (5) mxcmci driver (no dma): receive the stop command irq response */
158.419782: mxcmci_irq <-handle_irq_event_percpu
158.419812: mxcmci_read_response <-mxcmci_irq
158.419843: mxcmci_finish_request <-mxcmci_irq
/* (6) dma driver: receive dma irq (finish data transfer) related by request on step 1 */
158.419853: mpc_dma_irq <-handle_irq_event_percpu
158.420001: mpc_dma_irq_process <-mpc_dma_irq
158.420004: mpc_dma_irq_process <-mpc_dma_irq
/* (7) dma driver: start dma tasklet to finish the dma irq handling */
158.420008: mpc_dma_irq_process: mpc_dma_irq_process(): completed ch:31
/* (8) mxcmci driver: start next data transfer using dma */
158.420174: mxcmci_request <-mmc_start_req
158.420182: dma_direct_map_sg <-mxcmci_request
158.420192: mpc_dma_prep_slave_sg <-mxcmci_request
/* (9) dma driver: schedule irq tasklet and execute mxcmci dma driver callback */
158.420250: mpc_dma_tasklet <-tasklet_action
158.420254: mpc_dma_process_completed <-tasklet_action
158.420267: mxcmci_dma_callback <-mpc_dma_process_completed
/* ERROR!!! (10) mxcmci driver callback works on dma data related to the step 1
that is already finished */
158.420271: mxcmci_data_done <-mpc_dma_process_completed
158.420273: mxcmci_finish_data <-mxcmci_data_done
/* ERROR!!! (11) mxcmci driver: clear data that should be used by step 8 and
send an other mmc stop command (already sended on step 4) */
158.420276: dma_direct_unmap_sg <-mxcmci_finish_data
158.420279: mxcmci_swap_buffers.isra.24 <-mxcmci_finish_data
158.420330: mxcmci_read_response <-mxcmci_data_done
158.420333: mxcmci_start_cmd <-mxcmci_data_done
158.420338: dma_run_dependencies <-mpc_dma_process_completed
...
...
...
168.474223: mxcmci_watchdog <-call_timer_fn
168.474236: mxcmci_watchdog: mxcmci_watchdog
168.474397: mpc_dma_device_control <-mxcmci_watchdog


In accordance with the other drivers that using the dma engine,
fix it, leaving *only* to dma driver the complete control to
ending the read operation.

Removing STATUS_READ_OP_DONE event activation, has as effect
to force mxcmci driver to handle the finish data transfer only
by mxcmci dma callback.

Signed-off-by: Matteo Facchinetti <***@sirius-es.it>
---
drivers/mmc/host/mxcmmc.c | 13 +++----------
1 file changed, 3 insertions(+), 10 deletions(-)

diff --git a/drivers/mmc/host/mxcmmc.c b/drivers/mmc/host/mxcmmc.c
index ad11142..536a898 100644
--- a/drivers/mmc/host/mxcmmc.c
+++ b/drivers/mmc/host/mxcmmc.c
@@ -373,13 +373,9 @@ static void mxcmci_dma_callback(void *data)
del_timer(&host->watchdog);

stat = mxcmci_readl(host, MMC_REG_STATUS);
- mxcmci_writel(host, stat & ~STATUS_DATA_TRANS_DONE, MMC_REG_STATUS);

dev_dbg(mmc_dev(host->mmc), "%s: 0x%08x\n", __func__, stat);

- if (stat & STATUS_READ_OP_DONE)
- mxcmci_writel(host, STATUS_READ_OP_DONE, MMC_REG_STATUS);
-
mxcmci_data_done(host, stat);
}

@@ -743,10 +739,8 @@ static irqreturn_t mxcmci_irq(int irq, void *devid)
sdio_irq = (stat & STATUS_SDIO_INT_ACTIVE) && host->use_sdio;
spin_unlock_irqrestore(&host->lock, flags);

- if (mxcmci_use_dma(host) &&
- (stat & (STATUS_READ_OP_DONE | STATUS_WRITE_OP_DONE)))
- mxcmci_writel(host, STATUS_READ_OP_DONE | STATUS_WRITE_OP_DONE,
- MMC_REG_STATUS);
+ if (mxcmci_use_dma(host) && (stat & (STATUS_WRITE_OP_DONE)))
+ mxcmci_writel(host, STATUS_WRITE_OP_DONE, MMC_REG_STATUS);

if (sdio_irq) {
mxcmci_writel(host, STATUS_SDIO_INT_ACTIVE, MMC_REG_STATUS);
@@ -756,8 +750,7 @@ static irqreturn_t mxcmci_irq(int irq, void *devid)
if (stat & STATUS_END_CMD_RESP)
mxcmci_cmd_done(host, stat);

- if (mxcmci_use_dma(host) &&
- (stat & (STATUS_DATA_TRANS_DONE | STATUS_WRITE_OP_DONE))) {
+ if (mxcmci_use_dma(host) && (stat & STATUS_WRITE_OP_DONE)) {
del_timer(&host->watchdog);
mxcmci_data_done(host, stat);
}
--
1.8.3.2
Sascha Hauer
2014-10-08 06:49:02 UTC
Permalink
Post by Matteo Facchinetti
In accordance with the other drivers that using the dma engine,
fix it, leaving *only* to dma driver the complete control to
ending the read operation.
Removing STATUS_READ_OP_DONE event activation, has as effect
to force mxcmci driver to handle the finish data transfer only
by mxcmci dma callback.
I can't test this currently, but it looks sane to me and I assume you
invested quite some time to make sure the patch behaves correctly.

Acked-by: Sascha Hauer <***@pengutronix.de>

Sascha
--
Pengutronix e.K. | |
Industrial Linux Solutions | http://www.pengutronix.de/ |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0 |
Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 |
--
To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
the body of a message to ***@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Matteo Facchinetti
2014-10-07 12:50:51 UTC
Permalink
Does anyone have any comments?
Post by Matteo Facchinetti
Hi,
this patchset contains fixes for the mxcmmc driver.
fix a rare race condition that breaks a data trasfer when mxcmmc
driver use dma.
To reproduce this error, use mmc as rootfs and start at boot time
a realtime Xenomai application.
The realtime it's not directly related but entropy produced by
ipipe scheduler highlights the problem.
When this event occurs, the mxcmmc watchdog expires,
this cause a read error and application doesn't run.
fix the default value for available voltages into mxcmci_probe
Applied to mainline Linux-3.17.0-rc6-next on arch mpc512x.
Tested on mpc5125twr evaluation board
Applied to custom Linux-3.9.4 on arch mpc512x
Tested on a mpc5125 custom board.
Regards,
Matteo Facchinetti
Sirius Electronic Systems
mmc: mxcmmc: fix race condition when dma finish a data transfer
mmc: mxcmmc: fix the default value for available voltages into
mxcmci_probe
drivers/mmc/host/mxcmmc.c | 27 ++++++++++-----------------
1 file changed, 10 insertions(+), 17 deletions(-)
Loading...