tsif: workaround for stuck dma
During tsif stress tests it was reported that the dma flush caused by
calling action_close() is sometimes unrecoverable. The root cause is
stopping the tsif while a read by the dma of the tsif FIFO is in
progress. This workaround works by starving the tsif FIFO allowing
any in-flight transfers to complete, and thus ensuring a clean shutdown.
CRs-Fixed: 357934
CRs-Fixed: 358384
Change-Id: I766f53abe4a6a6a5905caa55c2e7fa0afba5cff4
Signed-off-by: Joel Nider <jnider@codeaurora.org>
diff --git a/drivers/misc/tsif.c b/drivers/misc/tsif.c
index 2b09d7c..aeda38c 100644
--- a/drivers/misc/tsif.c
+++ b/drivers/misc/tsif.c
@@ -304,7 +304,9 @@
for (i = size-1; i >= 0; i--) {
int tmp;
g = table + i;
- tmp = gpio_tlmm_config(g->gpio_cfg, GPIO_CFG_DISABLE);
+ tmp = gpio_tlmm_config(GPIO_CFG(GPIO_PIN(g->gpio_cfg),
+ 0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
+ GPIO_CFG_DISABLE);
if (tmp) {
pr_err("gpio_tlmm_config(0x%08x, GPIO_CFG_DISABLE)"
" <%s> failed: %d\n",
@@ -681,7 +683,7 @@
while (tsif_device->xfer[0].busy ||
tsif_device->xfer[1].busy) {
msm_dmov_flush(tsif_device->dma, 1);
- msleep(10);
+ usleep(10000);
}
}
tsif_device->state = tsif_state_stopped;
@@ -1031,6 +1033,15 @@
return rc;
}
tsif_device->state = tsif_state_running;
+
+ /* make sure the GPIO's are set up */
+ rc = tsif_start_gpios(tsif_device);
+ if (rc) {
+ dev_err(&tsif_device->pdev->dev, "failed to start GPIOs\n");
+ tsif_dma_exit(tsif_device);
+ return rc;
+ }
+
/*
* DMA should be scheduled prior to TSIF hardware initialization,
* otherwise "bus error" will be reported by Data Mover
@@ -1046,6 +1057,7 @@
rc = tsif_start_hw(tsif_device);
if (rc) {
dev_err(&tsif_device->pdev->dev, "Unable to start HW\n");
+ tsif_stop_gpios(tsif_device);
tsif_dma_exit(tsif_device);
tsif_clock(tsif_device, 0);
return rc;
@@ -1067,10 +1079,19 @@
{
dev_info(&tsif_device->pdev->dev, "%s, state %d\n", __func__,
(int)tsif_device->state);
- /*
- * DMA should be flushed/stopped prior to TSIF hardware stop,
- * otherwise "bus error" will be reported by Data Mover
+
+ /* turn off the GPIO's to prevent new data from entering */
+ tsif_stop_gpios(tsif_device);
+
+ /* we unfortunately must sleep here to give the ADM time to
+ * complete any outstanding reads after the GPIO's are turned
+ * off. There is no indication from the ADM hardware that
+ * there are any outstanding reads on the bus, and if we
+ * stop the TSIF too quickly, it can cause a bus error.
*/
+ msleep(100);
+
+ /* now we can stop the core */
tsif_stop_hw(tsif_device);
tsif_dma_exit(tsif_device);
tsif_clock(tsif_device, 0);
@@ -1317,9 +1338,6 @@
}
dev_info(&pdev->dev, "remapped phys 0x%08x => virt %p\n",
tsif_device->memres->start, tsif_device->base);
- rc = tsif_start_gpios(tsif_device);
- if (rc)
- goto err_gpio;
pm_runtime_set_active(&pdev->dev);
pm_runtime_enable(&pdev->dev);
@@ -1355,8 +1373,6 @@
free_irq(tsif_device->irq, tsif_device);
err_irq:
tsif_debugfs_exit(tsif_device);
- tsif_stop_gpios(tsif_device);
-err_gpio:
iounmap(tsif_device->base);
err_ioremap:
err_rgn: