aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTobias Jakobi <tjakobi@math.uni-bielefeld.de>2016-09-27 11:50:09 -0400
committerInki Dae <daeinki@gmail.com>2016-09-30 11:39:40 -0400
commit134a0fe98471b2e15a2b1bc22f4bddbb98bd6e18 (patch)
tree09809563854add622ba6f9a0408f27bda937dad8
parent5332737432ad5989830dae75df0d3e9cce56e893 (diff)
drm/exynos: g2d: wait for engine to finish
While the engine works on a runqueue node it does memory access to the buffers associated with that node. Make sure that the engine is idle when g2d_close() and/or g2d_remove() are called, i.e. buffer associated with the process (for g2d_close()), or all buffers (for g2d_remove()) can be safely be unmapped. We have to take into account that the engine might be in an undefined state, i.e. it hangs and doesn't become idle. In this case, we issue a hardware reset to return the hardware and the driver context into a proper state. Signed-off-by: Tobias Jakobi <tjakobi@math.uni-bielefeld.de> Acked-by: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Inki Dae <inki.dae@samsung.com>
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_g2d.c84
1 files changed, 77 insertions, 7 deletions
diff --git a/drivers/gpu/drm/exynos/exynos_drm_g2d.c b/drivers/gpu/drm/exynos/exynos_drm_g2d.c
index 0f84e7b32c0f..94fb9d2f90c1 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_g2d.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_g2d.c
@@ -258,6 +258,12 @@ struct g2d_data {
258 unsigned long max_pool; 258 unsigned long max_pool;
259}; 259};
260 260
261static inline void g2d_hw_reset(struct g2d_data *g2d)
262{
263 writel(G2D_R | G2D_SFRCLEAR, g2d->regs + G2D_SOFT_RESET);
264 clear_bit(G2D_BIT_ENGINE_BUSY, &g2d->flags);
265}
266
261static int g2d_init_cmdlist(struct g2d_data *g2d) 267static int g2d_init_cmdlist(struct g2d_data *g2d)
262{ 268{
263 struct device *dev = g2d->dev; 269 struct device *dev = g2d->dev;
@@ -969,6 +975,63 @@ static irqreturn_t g2d_irq_handler(int irq, void *dev_id)
969 return IRQ_HANDLED; 975 return IRQ_HANDLED;
970} 976}
971 977
978/**
979 * g2d_wait_finish - wait for the G2D engine to finish the current runqueue node
980 * @g2d: G2D state object
981 * @file: if not zero, only wait if the current runqueue node belongs
982 * to the DRM file
983 *
984 * Should the engine not become idle after a 100ms timeout, a hardware
985 * reset is issued.
986 */
987static void g2d_wait_finish(struct g2d_data *g2d, struct drm_file *file)
988{
989 struct device *dev = g2d->dev;
990
991 struct g2d_runqueue_node *runqueue_node = NULL;
992 unsigned int tries = 10;
993
994 mutex_lock(&g2d->runqueue_mutex);
995
996 /* If no node is currently processed, we have nothing to do. */
997 if (!g2d->runqueue_node)
998 goto out;
999
1000 runqueue_node = g2d->runqueue_node;
1001
1002 /* Check if the currently processed item belongs to us. */
1003 if (file && runqueue_node->filp != file)
1004 goto out;
1005
1006 mutex_unlock(&g2d->runqueue_mutex);
1007
1008 /* Wait for the G2D engine to finish. */
1009 while (tries-- && (g2d->runqueue_node == runqueue_node))
1010 mdelay(10);
1011
1012 mutex_lock(&g2d->runqueue_mutex);
1013
1014 if (g2d->runqueue_node != runqueue_node)
1015 goto out;
1016
1017 dev_err(dev, "wait timed out, resetting engine...\n");
1018 g2d_hw_reset(g2d);
1019
1020 /*
1021 * After the hardware reset of the engine we are going to loose
1022 * the IRQ which triggers the PM runtime put().
1023 * So do this manually here.
1024 */
1025 pm_runtime_put(dev);
1026
1027 complete(&runqueue_node->complete);
1028 if (runqueue_node->async)
1029 g2d_free_runqueue_node(g2d, runqueue_node);
1030
1031out:
1032 mutex_unlock(&g2d->runqueue_mutex);
1033}
1034
972static int g2d_check_reg_offset(struct device *dev, 1035static int g2d_check_reg_offset(struct device *dev,
973 struct g2d_cmdlist_node *node, 1036 struct g2d_cmdlist_node *node,
974 int nr, bool for_addr) 1037 int nr, bool for_addr)
@@ -1391,6 +1454,13 @@ static void g2d_close(struct drm_device *drm_dev, struct device *dev,
1391 mutex_unlock(&g2d->runqueue_mutex); 1454 mutex_unlock(&g2d->runqueue_mutex);
1392 1455
1393 /* 1456 /*
1457 * Wait for the runqueue worker to finish its current node.
1458 * After this the engine should no longer be accessing any
1459 * memory belonging to us.
1460 */
1461 g2d_wait_finish(g2d, file);
1462
1463 /*
1394 * Even after the engine is idle, there might still be stale cmdlists 1464 * Even after the engine is idle, there might still be stale cmdlists
1395 * (i.e. cmdlisst which we submitted but never executed) around, with 1465 * (i.e. cmdlisst which we submitted but never executed) around, with
1396 * their corresponding GEM/userptr buffers. 1466 * their corresponding GEM/userptr buffers.
@@ -1510,8 +1580,9 @@ static int g2d_remove(struct platform_device *pdev)
1510{ 1580{
1511 struct g2d_data *g2d = platform_get_drvdata(pdev); 1581 struct g2d_data *g2d = platform_get_drvdata(pdev);
1512 1582
1513 /* Suspend runqueue operation. */ 1583 /* Suspend operation and wait for engine idle. */
1514 set_bit(G2D_BIT_SUSPEND_RUNQUEUE, &g2d->flags); 1584 set_bit(G2D_BIT_SUSPEND_RUNQUEUE, &g2d->flags);
1585 g2d_wait_finish(g2d, NULL);
1515 1586
1516 cancel_work_sync(&g2d->runqueue_work); 1587 cancel_work_sync(&g2d->runqueue_work);
1517 exynos_drm_subdrv_unregister(&g2d->subdrv); 1588 exynos_drm_subdrv_unregister(&g2d->subdrv);
@@ -1533,13 +1604,12 @@ static int g2d_suspend(struct device *dev)
1533{ 1604{
1534 struct g2d_data *g2d = dev_get_drvdata(dev); 1605 struct g2d_data *g2d = dev_get_drvdata(dev);
1535 1606
1536 /* Suspend runqueue operation. */ 1607 /*
1608 * Suspend the runqueue worker operation and wait until the G2D
1609 * engine is idle.
1610 */
1537 set_bit(G2D_BIT_SUSPEND_RUNQUEUE, &g2d->flags); 1611 set_bit(G2D_BIT_SUSPEND_RUNQUEUE, &g2d->flags);
1538 1612 g2d_wait_finish(g2d, NULL);
1539 while (g2d->runqueue_node)
1540 /* FIXME: good range? */
1541 usleep_range(500, 1000);
1542
1543 flush_work(&g2d->runqueue_work); 1613 flush_work(&g2d->runqueue_work);
1544 1614
1545 return 0; 1615 return 0;