From patchwork Tue Sep 27 15:50:09 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Tobias Jakobi X-Patchwork-Id: 9352141 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id 52C7D6077B for ; Tue, 27 Sep 2016 15:53:31 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 44872291F2 for ; Tue, 27 Sep 2016 15:53:31 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 395AA2928A; Tue, 27 Sep 2016 15:53:31 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-4.2 required=2.0 tests=BAYES_00, RCVD_IN_DNSWL_MED autolearn=ham version=3.3.1 Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) (using TLSv1.2 with cipher DHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id 9446E29282 for ; Tue, 27 Sep 2016 15:53:30 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 265776E2FB; Tue, 27 Sep 2016 15:53:30 +0000 (UTC) X-Original-To: dri-devel@lists.freedesktop.org Delivered-To: dri-devel@lists.freedesktop.org Received: from smtp.math.uni-bielefeld.de (smtp.math.uni-bielefeld.de [129.70.45.10]) by gabe.freedesktop.org (Postfix) with ESMTPS id 842E76E2FB for ; Tue, 27 Sep 2016 15:53:28 +0000 (UTC) Received: from chidori.dhcp.uni-bielefeld.de (unknown [10.68.161.86]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-SHA256 (128/128 bits)) (Client did not present a certificate) by smtp.math.uni-bielefeld.de (Postfix) with ESMTPSA id C31115F61A; Tue, 27 Sep 2016 17:53:26 +0200 (CEST) From: Tobias Jakobi To: linux-samsung-soc@vger.kernel.org Subject: [PATCH 4/6] drm/exynos: g2d: wait for engine to finish Date: Tue, 27 Sep 2016 17:50:09 +0200 Message-Id: <1474991411-2937-5-git-send-email-tjakobi@math.uni-bielefeld.de> X-Mailer: git-send-email 2.7.3 In-Reply-To: <1474991411-2937-1-git-send-email-tjakobi@math.uni-bielefeld.de> References: <1474991411-2937-1-git-send-email-tjakobi@math.uni-bielefeld.de> Cc: Tobias Jakobi , dri-devel@lists.freedesktop.org, m.szyprowski@samsung.com X-BeenThere: dri-devel@lists.freedesktop.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: Direct Rendering Infrastructure - Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: dri-devel-bounces@lists.freedesktop.org Sender: "dri-devel" X-Virus-Scanned: ClamAV using ClamSMTP 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 --- drivers/gpu/drm/exynos/exynos_drm_g2d.c | 84 ++++++++++++++++++++++++++++++--- 1 file 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 3599489..5de5ea4 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 { unsigned long max_pool; }; +static inline void g2d_hw_reset(struct g2d_data *g2d) +{ + writel(G2D_R | G2D_SFRCLEAR, g2d->regs + G2D_SOFT_RESET); + clear_bit(G2D_BIT_ENGINE_BUSY, &g2d->flags); +} + static int g2d_init_cmdlist(struct g2d_data *g2d) { struct device *dev = g2d->dev; @@ -969,6 +975,63 @@ static irqreturn_t g2d_irq_handler(int irq, void *dev_id) return IRQ_HANDLED; } +/** + * g2d_wait_finish - wait for the G2D engine to finish the current runqueue node + * @g2d: G2D state object + * @file: if not zero, only wait if the current runqueue node belongs + * to the DRM file + * + * Should the engine not become idle after a 100ms timeout, a hardware + * reset is issued. + */ +static void g2d_wait_finish(struct g2d_data *g2d, struct drm_file *file) +{ + struct device *dev = g2d->dev; + + struct g2d_runqueue_node *runqueue_node = NULL; + unsigned int tries = 10; + + mutex_lock(&g2d->runqueue_mutex); + + /* If no node is currently processed, we have nothing to do. */ + if (!g2d->runqueue_node) + goto out; + + runqueue_node = g2d->runqueue_node; + + /* Check if the currently processed item belongs to us. */ + if (file && runqueue_node->filp != file) + goto out; + + mutex_unlock(&g2d->runqueue_mutex); + + /* Wait for the G2D engine to finish. */ + while (tries-- && (g2d->runqueue_node == runqueue_node)) + mdelay(10); + + mutex_lock(&g2d->runqueue_mutex); + + if (g2d->runqueue_node != runqueue_node) + goto out; + + dev_err(dev, "wait timed out, resetting engine...\n"); + g2d_hw_reset(g2d); + + /* + * After the hardware reset of the engine we are going to loose + * the IRQ which triggers the PM runtime put(). + * So do this manually here. + */ + pm_runtime_put(dev); + + complete(&runqueue_node->complete); + if (runqueue_node->async) + g2d_free_runqueue_node(g2d, runqueue_node); + +out: + mutex_unlock(&g2d->runqueue_mutex); +} + static int g2d_check_reg_offset(struct device *dev, struct g2d_cmdlist_node *node, int nr, bool for_addr) @@ -1391,6 +1454,13 @@ static void g2d_close(struct drm_device *drm_dev, struct device *dev, mutex_unlock(&g2d->runqueue_mutex); /* + * Wait for the runqueue worker to finish its current node. + * After this the engine should no longer be accessing any + * memory belonging to us. + */ + g2d_wait_finish(g2d, file); + + /* * Even after the engine is idle, there might still be stale cmdlists * (i.e. cmdlisst which we submitted but never executed) around, with * their corresponding GEM/userptr buffers. @@ -1510,8 +1580,9 @@ static int g2d_remove(struct platform_device *pdev) { struct g2d_data *g2d = platform_get_drvdata(pdev); - /* Suspend runqueue operation. */ + /* Suspend operation and wait for engine idle. */ set_bit(G2D_BIT_SUSPEND_RUNQUEUE, &g2d->flags); + g2d_wait_finish(g2d, NULL); cancel_work_sync(&g2d->runqueue_work); exynos_drm_subdrv_unregister(&g2d->subdrv); @@ -1533,13 +1604,12 @@ static int g2d_suspend(struct device *dev) { struct g2d_data *g2d = dev_get_drvdata(dev); - /* Suspend runqueue operation. */ + /* + * Suspend the runqueue worker operation and wait until the G2D + * engine is idle. + */ set_bit(G2D_BIT_SUSPEND_RUNQUEUE, &g2d->flags); - - while (g2d->runqueue_node) - /* FIXME: good range? */ - usleep_range(500, 1000); - + g2d_wait_finish(g2d, NULL); flush_work(&g2d->runqueue_work); return 0;