From 86824e60b0b17b68ba0e2c89e5124f9d53d0474f Mon Sep 17 00:00:00 2001 From: John Hubbard Date: Mon, 25 May 2020 16:49:46 -0700 Subject: drm/etnaviv: convert get_user_pages() --> pin_user_pages() This code was using get_user_pages*(), in a "Case 2" scenario (DMA/RDMA), using the categorization from [1]. That means that it's time to convert the get_user_pages*() + put_page() calls to pin_user_pages*() + unpin_user_pages() calls. There is some helpful background in [2]: basically, this is a small part of fixing a long-standing disconnect between pinning pages, and file systems' use of those pages. [1] Documentation/core-api/pin_user_pages.rst [2] "Explicit pinning of user-space pages": https://lwn.net/Articles/807108/ Signed-off-by: John Hubbard Signed-off-by: Lucas Stach --- drivers/gpu/drm/etnaviv/etnaviv_gem.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/gpu/drm/etnaviv') diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gem.c b/drivers/gpu/drm/etnaviv/etnaviv_gem.c index 701f3995f621..670eaaf783ee 100644 --- a/drivers/gpu/drm/etnaviv/etnaviv_gem.c +++ b/drivers/gpu/drm/etnaviv/etnaviv_gem.c @@ -675,10 +675,10 @@ static int etnaviv_gem_userptr_get_pages(struct etnaviv_gem_object *etnaviv_obj) uint64_t ptr = userptr->ptr + pinned * PAGE_SIZE; struct page **pages = pvec + pinned; - ret = get_user_pages_fast(ptr, num_pages, + ret = pin_user_pages_fast(ptr, num_pages, !userptr->ro ? FOLL_WRITE : 0, pages); if (ret < 0) { - release_pages(pvec, pinned); + unpin_user_pages(pvec, pinned); kvfree(pvec); return ret; } @@ -702,7 +702,7 @@ static void etnaviv_gem_userptr_release(struct etnaviv_gem_object *etnaviv_obj) if (etnaviv_obj->pages) { int npages = etnaviv_obj->base.size >> PAGE_SHIFT; - release_pages(etnaviv_obj->pages, npages); + unpin_user_pages(etnaviv_obj->pages, npages); kvfree(etnaviv_obj->pages); } } -- cgit v1.2.3 From f8794feaf65cdc97767604cf864775d20b97f397 Mon Sep 17 00:00:00 2001 From: Lubomir Rintel Date: Tue, 16 Jun 2020 23:21:24 +0200 Subject: drm/etnaviv: Fix error path on failure to enable bus clk Since commit 65f037e8e908 ("drm/etnaviv: add support for slave interface clock") the reg clock is enabled before the bus clock and we need to undo its enablement on error. Fixes: 65f037e8e908 ("drm/etnaviv: add support for slave interface clock") Signed-off-by: Lubomir Rintel Signed-off-by: Lucas Stach --- drivers/gpu/drm/etnaviv/etnaviv_gpu.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers/gpu/drm/etnaviv') diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gpu.c b/drivers/gpu/drm/etnaviv/etnaviv_gpu.c index a31eeff2b297..c6dacfe3d321 100644 --- a/drivers/gpu/drm/etnaviv/etnaviv_gpu.c +++ b/drivers/gpu/drm/etnaviv/etnaviv_gpu.c @@ -1496,7 +1496,7 @@ static int etnaviv_gpu_clk_enable(struct etnaviv_gpu *gpu) if (gpu->clk_bus) { ret = clk_prepare_enable(gpu->clk_bus); if (ret) - return ret; + goto disable_clk_reg; } if (gpu->clk_core) { @@ -1519,6 +1519,9 @@ disable_clk_core: disable_clk_bus: if (gpu->clk_bus) clk_disable_unprepare(gpu->clk_bus); +disable_clk_reg: + if (gpu->clk_reg) + clk_disable_unprepare(gpu->clk_reg); return ret; } -- cgit v1.2.3 From f76fc5ff9a6533d6eadb8521bf60bf7b1cf293b9 Mon Sep 17 00:00:00 2001 From: Lubomir Rintel Date: Tue, 16 Jun 2020 23:21:25 +0200 Subject: drm/etnaviv: Don't ignore errors on getting clocks There might be good reasons why the getting a clock failed. To treat the clocks as optional we're specifically only interested in ignoring -ENOENT, and devm_clk_get_optional() does just that. Note that this preserves the original behavior of all clocks being optional. The binding document mandates the "bus" clock while the dove machine only specifies "core". Signed-off-by: Lubomir Rintel Signed-off-by: Lucas Stach --- drivers/gpu/drm/etnaviv/etnaviv_gpu.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'drivers/gpu/drm/etnaviv') diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gpu.c b/drivers/gpu/drm/etnaviv/etnaviv_gpu.c index c6dacfe3d321..f303172c091d 100644 --- a/drivers/gpu/drm/etnaviv/etnaviv_gpu.c +++ b/drivers/gpu/drm/etnaviv/etnaviv_gpu.c @@ -1786,26 +1786,26 @@ static int etnaviv_gpu_platform_probe(struct platform_device *pdev) } /* Get Clocks: */ - gpu->clk_reg = devm_clk_get(&pdev->dev, "reg"); + gpu->clk_reg = devm_clk_get_optional(&pdev->dev, "reg"); DBG("clk_reg: %p", gpu->clk_reg); if (IS_ERR(gpu->clk_reg)) - gpu->clk_reg = NULL; + return PTR_ERR(gpu->clk_reg); - gpu->clk_bus = devm_clk_get(&pdev->dev, "bus"); + gpu->clk_bus = devm_clk_get_optional(&pdev->dev, "bus"); DBG("clk_bus: %p", gpu->clk_bus); if (IS_ERR(gpu->clk_bus)) - gpu->clk_bus = NULL; + return PTR_ERR(gpu->clk_bus); - gpu->clk_core = devm_clk_get(&pdev->dev, "core"); + gpu->clk_core = devm_clk_get_optional(&pdev->dev, "core"); DBG("clk_core: %p", gpu->clk_core); if (IS_ERR(gpu->clk_core)) - gpu->clk_core = NULL; + return PTR_ERR(gpu->clk_core); gpu->base_rate_core = clk_get_rate(gpu->clk_core); - gpu->clk_shader = devm_clk_get(&pdev->dev, "shader"); + gpu->clk_shader = devm_clk_get_optional(&pdev->dev, "shader"); DBG("clk_shader: %p", gpu->clk_shader); if (IS_ERR(gpu->clk_shader)) - gpu->clk_shader = NULL; + return PTR_ERR(gpu->clk_shader); gpu->base_rate_shader = clk_get_rate(gpu->clk_shader); /* TODO: figure out max mapped size */ -- cgit v1.2.3 From a59052d2749b678cb7c32ef25d3d47cc451d5f34 Mon Sep 17 00:00:00 2001 From: Lubomir Rintel Date: Tue, 16 Jun 2020 23:21:26 +0200 Subject: drm/etnaviv: Make the "core" clock mandatory It is always present. It was documented as mandatory prior to commit 90aeca875f8a ("dt-bindings: display: Convert etnaviv to json-schema"). Signed-off-by: Lubomir Rintel Signed-off-by: Lucas Stach --- drivers/gpu/drm/etnaviv/etnaviv_gpu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/gpu/drm/etnaviv') diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gpu.c b/drivers/gpu/drm/etnaviv/etnaviv_gpu.c index f303172c091d..798fdbc8ecdb 100644 --- a/drivers/gpu/drm/etnaviv/etnaviv_gpu.c +++ b/drivers/gpu/drm/etnaviv/etnaviv_gpu.c @@ -1796,7 +1796,7 @@ static int etnaviv_gpu_platform_probe(struct platform_device *pdev) if (IS_ERR(gpu->clk_bus)) return PTR_ERR(gpu->clk_bus); - gpu->clk_core = devm_clk_get_optional(&pdev->dev, "core"); + gpu->clk_core = devm_clk_get(&pdev->dev, "core"); DBG("clk_core: %p", gpu->clk_core); if (IS_ERR(gpu->clk_core)) return PTR_ERR(gpu->clk_core); -- cgit v1.2.3 From 6a5ef3b224c63f500cc4a1b9a2cef8a9a3a328da Mon Sep 17 00:00:00 2001 From: Lubomir Rintel Date: Tue, 16 Jun 2020 23:21:27 +0200 Subject: drm/etnaviv: Simplify clock enable/disable All the NULL checks are pointless, clk_*() routines already deal with NULL just fine. Signed-off-by: Lubomir Rintel Signed-off-by: Lucas Stach --- drivers/gpu/drm/etnaviv/etnaviv_gpu.c | 53 +++++++++++++---------------------- 1 file changed, 19 insertions(+), 34 deletions(-) (limited to 'drivers/gpu/drm/etnaviv') diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gpu.c b/drivers/gpu/drm/etnaviv/etnaviv_gpu.c index 798fdbc8ecdb..fb37787449bb 100644 --- a/drivers/gpu/drm/etnaviv/etnaviv_gpu.c +++ b/drivers/gpu/drm/etnaviv/etnaviv_gpu.c @@ -1487,55 +1487,40 @@ static int etnaviv_gpu_clk_enable(struct etnaviv_gpu *gpu) { int ret; - if (gpu->clk_reg) { - ret = clk_prepare_enable(gpu->clk_reg); - if (ret) - return ret; - } + ret = clk_prepare_enable(gpu->clk_reg); + if (ret) + return ret; - if (gpu->clk_bus) { - ret = clk_prepare_enable(gpu->clk_bus); - if (ret) - goto disable_clk_reg; - } + ret = clk_prepare_enable(gpu->clk_bus); + if (ret) + goto disable_clk_reg; - if (gpu->clk_core) { - ret = clk_prepare_enable(gpu->clk_core); - if (ret) - goto disable_clk_bus; - } + ret = clk_prepare_enable(gpu->clk_core); + if (ret) + goto disable_clk_bus; - if (gpu->clk_shader) { - ret = clk_prepare_enable(gpu->clk_shader); - if (ret) - goto disable_clk_core; - } + ret = clk_prepare_enable(gpu->clk_shader); + if (ret) + goto disable_clk_core; return 0; disable_clk_core: - if (gpu->clk_core) - clk_disable_unprepare(gpu->clk_core); + clk_disable_unprepare(gpu->clk_core); disable_clk_bus: - if (gpu->clk_bus) - clk_disable_unprepare(gpu->clk_bus); + clk_disable_unprepare(gpu->clk_bus); disable_clk_reg: - if (gpu->clk_reg) - clk_disable_unprepare(gpu->clk_reg); + clk_disable_unprepare(gpu->clk_reg); return ret; } static int etnaviv_gpu_clk_disable(struct etnaviv_gpu *gpu) { - if (gpu->clk_shader) - clk_disable_unprepare(gpu->clk_shader); - if (gpu->clk_core) - clk_disable_unprepare(gpu->clk_core); - if (gpu->clk_bus) - clk_disable_unprepare(gpu->clk_bus); - if (gpu->clk_reg) - clk_disable_unprepare(gpu->clk_reg); + clk_disable_unprepare(gpu->clk_shader); + clk_disable_unprepare(gpu->clk_core); + clk_disable_unprepare(gpu->clk_bus); + clk_disable_unprepare(gpu->clk_reg); return 0; } -- cgit v1.2.3 From c5d5a32ead1e3a61a07a1e59eb52a53e4a6b2a7f Mon Sep 17 00:00:00 2001 From: Navid Emamdoost Date: Mon, 15 Jun 2020 01:12:20 -0500 Subject: drm/etnaviv: fix ref count leak via pm_runtime_get_sync in etnaviv_gpu_submit, etnaviv_gpu_recover_hang, etnaviv_gpu_debugfs, and etnaviv_gpu_init the call to pm_runtime_get_sync increments the counter even in case of failure, leading to incorrect ref count. In case of failure, decrement the ref count before returning. Signed-off-by: Navid Emamdoost Signed-off-by: Lucas Stach --- drivers/gpu/drm/etnaviv/etnaviv_gpu.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) (limited to 'drivers/gpu/drm/etnaviv') diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gpu.c b/drivers/gpu/drm/etnaviv/etnaviv_gpu.c index fb37787449bb..d5a4cd85a0f6 100644 --- a/drivers/gpu/drm/etnaviv/etnaviv_gpu.c +++ b/drivers/gpu/drm/etnaviv/etnaviv_gpu.c @@ -722,7 +722,7 @@ int etnaviv_gpu_init(struct etnaviv_gpu *gpu) ret = pm_runtime_get_sync(gpu->dev); if (ret < 0) { dev_err(gpu->dev, "Failed to enable GPU power domain\n"); - return ret; + goto pm_put; } etnaviv_hw_identify(gpu); @@ -819,6 +819,7 @@ int etnaviv_gpu_init(struct etnaviv_gpu *gpu) fail: pm_runtime_mark_last_busy(gpu->dev); +pm_put: pm_runtime_put_autosuspend(gpu->dev); return ret; @@ -859,7 +860,7 @@ int etnaviv_gpu_debugfs(struct etnaviv_gpu *gpu, struct seq_file *m) ret = pm_runtime_get_sync(gpu->dev); if (ret < 0) - return ret; + goto pm_put; dma_lo = gpu_read(gpu, VIVS_FE_DMA_LOW); dma_hi = gpu_read(gpu, VIVS_FE_DMA_HIGH); @@ -1003,6 +1004,7 @@ int etnaviv_gpu_debugfs(struct etnaviv_gpu *gpu, struct seq_file *m) ret = 0; pm_runtime_mark_last_busy(gpu->dev); +pm_put: pm_runtime_put_autosuspend(gpu->dev); return ret; @@ -1016,7 +1018,7 @@ void etnaviv_gpu_recover_hang(struct etnaviv_gpu *gpu) dev_err(gpu->dev, "recover hung GPU!\n"); if (pm_runtime_get_sync(gpu->dev) < 0) - return; + goto pm_put; mutex_lock(&gpu->lock); @@ -1035,6 +1037,7 @@ void etnaviv_gpu_recover_hang(struct etnaviv_gpu *gpu) mutex_unlock(&gpu->lock); pm_runtime_mark_last_busy(gpu->dev); +pm_put: pm_runtime_put_autosuspend(gpu->dev); } @@ -1308,8 +1311,10 @@ struct dma_fence *etnaviv_gpu_submit(struct etnaviv_gem_submit *submit) if (!submit->runtime_resumed) { ret = pm_runtime_get_sync(gpu->dev); - if (ret < 0) + if (ret < 0) { + pm_runtime_put_noidle(gpu->dev); return NULL; + } submit->runtime_resumed = true; } @@ -1326,6 +1331,7 @@ struct dma_fence *etnaviv_gpu_submit(struct etnaviv_gem_submit *submit) ret = event_alloc(gpu, nr_events, event); if (ret) { DRM_ERROR("no free events\n"); + pm_runtime_put_noidle(gpu->dev); return NULL; } -- cgit v1.2.3