From 18b3f5ac6b55f5f3f60723a58f14ec235a5b8cfe Mon Sep 17 00:00:00 2001 From: Mikko Perttunen Date: Wed, 2 Aug 2017 12:55:04 +0300 Subject: gpu: host1x: Don't fail on NULL bo physical address Pinning a Host1x BO currently cannot fail and zero is a valid address for a BO when IOMMU is enabled. To avoid false errors remove checks for NULL BO physical addresses. Fixes: 404bfb78daf3 ("gpu: host1x: Add IOMMU support") Signed-off-by: Mikko Perttunen Reviewed-by: Dmitry Osipenko Signed-off-by: Thierry Reding --- drivers/gpu/host1x/job.c | 8 -------- 1 file changed, 8 deletions(-) diff --git a/drivers/gpu/host1x/job.c b/drivers/gpu/host1x/job.c index bee504406cfc..db509ab8874e 100644 --- a/drivers/gpu/host1x/job.c +++ b/drivers/gpu/host1x/job.c @@ -197,10 +197,6 @@ static unsigned int pin_job(struct host1x *host, struct host1x_job *job) } phys_addr = host1x_bo_pin(reloc->target.bo, &sgt); - if (!phys_addr) { - err = -EINVAL; - goto unpin; - } job->addr_phys[job->num_unpins] = phys_addr; job->unpins[job->num_unpins].bo = reloc->target.bo; @@ -225,10 +221,6 @@ static unsigned int pin_job(struct host1x *host, struct host1x_job *job) } phys_addr = host1x_bo_pin(g->bo, &sgt); - if (!phys_addr) { - err = -EINVAL; - goto unpin; - } if (!IS_ENABLED(CONFIG_TEGRA_HOST1X_FIREWALL) && host->domain) { for_each_sg(sgt->sgl, sg, sgt->nents, j) -- cgit From 4ac45eb8d17c1a998182c302bd023ecb055bd9ee Mon Sep 17 00:00:00 2001 From: Mikko Perttunen Date: Wed, 2 Aug 2017 12:55:05 +0300 Subject: gpu: host1x: Fix bitshift/mask multipliers Some parts of Host1x uses BIT_WORD/BIT_MASK/BITS_PER_LONG to calculate register or field offsets. This worked fine on ARMv7, but now that BITS_PER_LONG is 64 but our registers are still 32-bit things are broken. Fix by replacing.. - BIT_WORD with (x / 32) - BIT_MASK with BIT(x % 32) - BITS_PER_LONG with 32 Signed-off-by: Mikko Perttunen Reviewed-by: Dmitry Osipenko Tested-by: Dmitry Osipenko Signed-off-by: Thierry Reding --- drivers/gpu/host1x/hw/intr_hw.c | 24 ++++++++++++------------ drivers/gpu/host1x/hw/syncpt_hw.c | 2 +- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/drivers/gpu/host1x/hw/intr_hw.c b/drivers/gpu/host1x/hw/intr_hw.c index dacb8009a605..37ebb51703fa 100644 --- a/drivers/gpu/host1x/hw/intr_hw.c +++ b/drivers/gpu/host1x/hw/intr_hw.c @@ -33,10 +33,10 @@ static void host1x_intr_syncpt_handle(struct host1x_syncpt *syncpt) unsigned int id = syncpt->id; struct host1x *host = syncpt->host; - host1x_sync_writel(host, BIT_MASK(id), - HOST1X_SYNC_SYNCPT_THRESH_INT_DISABLE(BIT_WORD(id))); - host1x_sync_writel(host, BIT_MASK(id), - HOST1X_SYNC_SYNCPT_THRESH_CPU0_INT_STATUS(BIT_WORD(id))); + host1x_sync_writel(host, BIT(id % 32), + HOST1X_SYNC_SYNCPT_THRESH_INT_DISABLE(id / 32)); + host1x_sync_writel(host, BIT(id % 32), + HOST1X_SYNC_SYNCPT_THRESH_CPU0_INT_STATUS(id / 32)); schedule_work(&syncpt->intr.work); } @@ -50,9 +50,9 @@ static irqreturn_t syncpt_thresh_isr(int irq, void *dev_id) for (i = 0; i < DIV_ROUND_UP(host->info->nb_pts, 32); i++) { reg = host1x_sync_readl(host, HOST1X_SYNC_SYNCPT_THRESH_CPU0_INT_STATUS(i)); - for_each_set_bit(id, ®, BITS_PER_LONG) { + for_each_set_bit(id, ®, 32) { struct host1x_syncpt *syncpt = - host->syncpt + (i * BITS_PER_LONG + id); + host->syncpt + (i * 32 + id); host1x_intr_syncpt_handle(syncpt); } } @@ -117,17 +117,17 @@ static void _host1x_intr_set_syncpt_threshold(struct host1x *host, static void _host1x_intr_enable_syncpt_intr(struct host1x *host, unsigned int id) { - host1x_sync_writel(host, BIT_MASK(id), - HOST1X_SYNC_SYNCPT_THRESH_INT_ENABLE_CPU0(BIT_WORD(id))); + host1x_sync_writel(host, BIT(id % 32), + HOST1X_SYNC_SYNCPT_THRESH_INT_ENABLE_CPU0(id / 32)); } static void _host1x_intr_disable_syncpt_intr(struct host1x *host, unsigned int id) { - host1x_sync_writel(host, BIT_MASK(id), - HOST1X_SYNC_SYNCPT_THRESH_INT_DISABLE(BIT_WORD(id))); - host1x_sync_writel(host, BIT_MASK(id), - HOST1X_SYNC_SYNCPT_THRESH_CPU0_INT_STATUS(BIT_WORD(id))); + host1x_sync_writel(host, BIT(id % 32), + HOST1X_SYNC_SYNCPT_THRESH_INT_DISABLE(id / 32)); + host1x_sync_writel(host, BIT(id % 32), + HOST1X_SYNC_SYNCPT_THRESH_CPU0_INT_STATUS(id / 32)); } static int _host1x_free_syncpt_irq(struct host1x *host) diff --git a/drivers/gpu/host1x/hw/syncpt_hw.c b/drivers/gpu/host1x/hw/syncpt_hw.c index c93f74fcce72..7b0270d60742 100644 --- a/drivers/gpu/host1x/hw/syncpt_hw.c +++ b/drivers/gpu/host1x/hw/syncpt_hw.c @@ -89,7 +89,7 @@ static int syncpt_cpu_incr(struct host1x_syncpt *sp) host1x_syncpt_idle(sp)) return -EINVAL; - host1x_sync_writel(host, BIT_MASK(sp->id), + host1x_sync_writel(host, BIT(sp->id % 32), HOST1X_SYNC_SYNCPT_CPU_INCR(reg_offset)); wmb(); -- cgit From 7b2c63de20080c18d0de35b292ad61fc9bc8328e Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Tue, 8 Aug 2017 00:08:06 -0500 Subject: gpu: host1x: fix error return code in host1x_probe() platform_get_irq() returns an error code, but the host1x driver ignores it and always returns -ENXIO. This is not correct and, prevents -EPROBE_DEFER from being propagated properly. Notice that platform_get_irq() no longer returns 0 on error: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=e330b9a6bb35dc7097a4f02cb1ae7b6f96df92af Print and propagate the return value of platform_get_irq on failure. This issue was detected with the help of Coccinelle. Signed-off-by: Gustavo A. R. Silva Signed-off-by: Thierry Reding --- drivers/gpu/host1x/dev.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/host1x/dev.c b/drivers/gpu/host1x/dev.c index 2c58a390123a..9476a6dad86b 100644 --- a/drivers/gpu/host1x/dev.c +++ b/drivers/gpu/host1x/dev.c @@ -134,8 +134,8 @@ static int host1x_probe(struct platform_device *pdev) syncpt_irq = platform_get_irq(pdev, 0); if (syncpt_irq < 0) { - dev_err(&pdev->dev, "failed to get IRQ\n"); - return -ENXIO; + dev_err(&pdev->dev, "failed to get IRQ: %d\n", syncpt_irq); + return syncpt_irq; } host = devm_kzalloc(&pdev->dev, sizeof(*host), GFP_KERNEL); -- cgit From 25ae30d2a84cf4bc6c8e8bc53c63f261cc190616 Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Tue, 15 Aug 2017 15:46:22 +0200 Subject: gpu: host1x: Support sub-devices recursively The display architecture in Tegra186 changes slightly compared to earlier Tegra generations, which requires that we recursively scan host1x sub-devices from device tree. Signed-off-by: Thierry Reding --- drivers/gpu/host1x/bus.c | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/host1x/bus.c b/drivers/gpu/host1x/bus.c index a048e3ac523d..6693abeca0ed 100644 --- a/drivers/gpu/host1x/bus.c +++ b/drivers/gpu/host1x/bus.c @@ -45,9 +45,12 @@ struct host1x_subdev { * @np: device node */ static int host1x_subdev_add(struct host1x_device *device, + struct host1x_driver *driver, struct device_node *np) { struct host1x_subdev *subdev; + struct device_node *child; + int err; subdev = kzalloc(sizeof(*subdev), GFP_KERNEL); if (!subdev) @@ -60,6 +63,19 @@ static int host1x_subdev_add(struct host1x_device *device, list_add_tail(&subdev->list, &device->subdevs); mutex_unlock(&device->subdevs_lock); + /* recursively add children */ + for_each_child_of_node(np, child) { + if (of_match_node(driver->subdevs, child) && + of_device_is_available(child)) { + err = host1x_subdev_add(device, driver, child); + if (err < 0) { + /* XXX cleanup? */ + of_node_put(child); + return err; + } + } + } + return 0; } @@ -88,7 +104,7 @@ static int host1x_device_parse_dt(struct host1x_device *device, for_each_child_of_node(device->dev.parent->of_node, np) { if (of_match_node(driver->subdevs, np) && of_device_is_available(np)) { - err = host1x_subdev_add(device, np); + err = host1x_subdev_add(device, driver, np); if (err < 0) { of_node_put(np); return err; -- cgit From 2d0f986559a28c16bb59e6c49f4bce36d14548b8 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Fri, 21 Jul 2017 18:13:23 +0200 Subject: drm/tegra: Add CONFIG_OF dependency Without CONFIG_OF, we can run into a build error: drivers/gpu/drm/tegra/dpaux.c:378:20: error: 'pinconf_generic_dt_node_to_map_group' undeclared here (not in a function); did you mean 'pinconf_generic_params'? .dt_node_to_map = pinconf_generic_dt_node_to_map_group, ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ pinconf_generic_params drivers/gpu/drm/tegra/dpaux.c:379:17: error: 'pinconf_generic_dt_free_map' undeclared here (not in a function); did you mean 'pinconf_generic_params'? This adds an explicit dependency. Signed-off-by: Arnd Bergmann Acked-by: Jon Hunter Signed-off-by: Thierry Reding --- drivers/gpu/drm/tegra/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/tegra/Kconfig b/drivers/gpu/drm/tegra/Kconfig index 2db29d67193d..dc58ab140151 100644 --- a/drivers/gpu/drm/tegra/Kconfig +++ b/drivers/gpu/drm/tegra/Kconfig @@ -3,6 +3,7 @@ config DRM_TEGRA depends on ARCH_TEGRA || (ARM && COMPILE_TEST) depends on COMMON_CLK depends on DRM + depends on OF select DRM_KMS_HELPER select DRM_MIPI_DSI select DRM_PANEL -- cgit From 788ff4b6cfd90fcd9608beccec9c5ed1ff8c4041 Mon Sep 17 00:00:00 2001 From: Nicolas Chauvet Date: Tue, 11 Jul 2017 10:39:04 +0200 Subject: drm/tegra: Set MODULE_FIRMWARE for the VIC The defines are set anyway to prevent an empty string. The test for the SoC is the same as for Nouveau for the Tegra GPU firmware (see drivers/gpu/drm/nouveau/nouveau_platform.c) v2: - Place the defines above each chip's vic_config struct - MODULE_FIRMWARE() at the end of the file Fixes: 0ae797a8ba05 ("drm/tegra: Add VIC support") Signed-off-by: Nicolas Chauvet Reviewed-by: Mikko Perttunen Signed-off-by: Thierry Reding --- drivers/gpu/drm/tegra/vic.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/tegra/vic.c b/drivers/gpu/drm/tegra/vic.c index 47cb1aaa58b1..2448229fa653 100644 --- a/drivers/gpu/drm/tegra/vic.c +++ b/drivers/gpu/drm/tegra/vic.c @@ -258,12 +258,16 @@ static const struct tegra_drm_client_ops vic_ops = { .submit = tegra_drm_submit, }; +#define NVIDIA_TEGRA_124_VIC_FIRMWARE "nvidia/tegra124/vic03_ucode.bin" + static const struct vic_config vic_t124_config = { - .firmware = "nvidia/tegra124/vic03_ucode.bin", + .firmware = NVIDIA_TEGRA_124_VIC_FIRMWARE, }; +#define NVIDIA_TEGRA_210_VIC_FIRMWARE "nvidia/tegra210/vic04_ucode.bin" + static const struct vic_config vic_t210_config = { - .firmware = "nvidia/tegra210/vic04_ucode.bin", + .firmware = NVIDIA_TEGRA_210_VIC_FIRMWARE, }; static const struct of_device_id vic_match[] = { @@ -394,3 +398,10 @@ struct platform_driver tegra_vic_driver = { .probe = vic_probe, .remove = vic_remove, }; + +#if IS_ENABLED(CONFIG_ARCH_TEGRA_124_SOC) +MODULE_FIRMWARE(NVIDIA_TEGRA_124_VIC_FIRMWARE); +#endif +#if IS_ENABLED(CONFIG_ARCH_TEGRA_210_SOC) +MODULE_FIRMWARE(NVIDIA_TEGRA_210_VIC_FIRMWARE); +#endif -- cgit From 7664b2fa42b5e962dd9ffd9e386dc20cbc966176 Mon Sep 17 00:00:00 2001 From: Cihangir Akturk Date: Fri, 11 Aug 2017 15:33:07 +0300 Subject: drm/tegra: switch to drm_*_get(), drm_*_put() helpers Use drm_*_get() and drm_*_put() helpers instead of drm_*_reference() and drm_*_unreference() helpers. drm_*_reference() and drm_*_unreference() functions are just compatibility alias for drm_*_get() and drm_*_put() and should not be used by new code. So convert all users of compatibility functions to use the new APIs. Generated by: scripts/coccinelle/api/drm-get-put.cocci Signed-off-by: Cihangir Akturk Signed-off-by: Thierry Reding --- drivers/gpu/drm/tegra/drm.c | 12 ++++++------ drivers/gpu/drm/tegra/fb.c | 8 ++++---- drivers/gpu/drm/tegra/gem.c | 10 +++++----- 3 files changed, 15 insertions(+), 15 deletions(-) diff --git a/drivers/gpu/drm/tegra/drm.c b/drivers/gpu/drm/tegra/drm.c index 518f4b69ea53..eddea778290f 100644 --- a/drivers/gpu/drm/tegra/drm.c +++ b/drivers/gpu/drm/tegra/drm.c @@ -304,7 +304,7 @@ host1x_bo_lookup(struct drm_file *file, u32 handle) if (!gem) return NULL; - drm_gem_object_unreference_unlocked(gem); + drm_gem_object_put_unlocked(gem); bo = to_tegra_bo(gem); return &bo->base; @@ -591,7 +591,7 @@ static int tegra_gem_mmap(struct drm_device *drm, void *data, args->offset = drm_vma_node_offset_addr(&bo->gem.vma_node); - drm_gem_object_unreference_unlocked(gem); + drm_gem_object_put_unlocked(gem); return 0; } @@ -858,7 +858,7 @@ static int tegra_gem_set_tiling(struct drm_device *drm, void *data, bo->tiling.mode = mode; bo->tiling.value = value; - drm_gem_object_unreference_unlocked(gem); + drm_gem_object_put_unlocked(gem); return 0; } @@ -898,7 +898,7 @@ static int tegra_gem_get_tiling(struct drm_device *drm, void *data, break; } - drm_gem_object_unreference_unlocked(gem); + drm_gem_object_put_unlocked(gem); return err; } @@ -923,7 +923,7 @@ static int tegra_gem_set_flags(struct drm_device *drm, void *data, if (args->flags & DRM_TEGRA_GEM_BOTTOM_UP) bo->flags |= TEGRA_BO_BOTTOM_UP; - drm_gem_object_unreference_unlocked(gem); + drm_gem_object_put_unlocked(gem); return 0; } @@ -945,7 +945,7 @@ static int tegra_gem_get_flags(struct drm_device *drm, void *data, if (bo->flags & TEGRA_BO_BOTTOM_UP) args->flags |= DRM_TEGRA_GEM_BOTTOM_UP; - drm_gem_object_unreference_unlocked(gem); + drm_gem_object_put_unlocked(gem); return 0; } diff --git a/drivers/gpu/drm/tegra/fb.c b/drivers/gpu/drm/tegra/fb.c index 25acb73ee728..80540c1c66dc 100644 --- a/drivers/gpu/drm/tegra/fb.c +++ b/drivers/gpu/drm/tegra/fb.c @@ -88,7 +88,7 @@ static void tegra_fb_destroy(struct drm_framebuffer *framebuffer) if (bo->pages) vunmap(bo->vaddr); - drm_gem_object_unreference_unlocked(&bo->gem); + drm_gem_object_put_unlocked(&bo->gem); } } @@ -195,7 +195,7 @@ struct drm_framebuffer *tegra_fb_create(struct drm_device *drm, unreference: while (i--) - drm_gem_object_unreference_unlocked(&planes[i]->gem); + drm_gem_object_put_unlocked(&planes[i]->gem); return ERR_PTR(err); } @@ -242,7 +242,7 @@ static int tegra_fbdev_probe(struct drm_fb_helper *helper, info = drm_fb_helper_alloc_fbi(helper); if (IS_ERR(info)) { dev_err(drm->dev, "failed to allocate framebuffer info\n"); - drm_gem_object_unreference_unlocked(&bo->gem); + drm_gem_object_put_unlocked(&bo->gem); return PTR_ERR(info); } @@ -251,7 +251,7 @@ static int tegra_fbdev_probe(struct drm_fb_helper *helper, err = PTR_ERR(fbdev->fb); dev_err(drm->dev, "failed to allocate DRM framebuffer: %d\n", err); - drm_gem_object_unreference_unlocked(&bo->gem); + drm_gem_object_put_unlocked(&bo->gem); return PTR_ERR(fbdev->fb); } diff --git a/drivers/gpu/drm/tegra/gem.c b/drivers/gpu/drm/tegra/gem.c index 7a39a355678a..fe77bcd23800 100644 --- a/drivers/gpu/drm/tegra/gem.c +++ b/drivers/gpu/drm/tegra/gem.c @@ -24,7 +24,7 @@ static void tegra_bo_put(struct host1x_bo *bo) { struct tegra_bo *obj = host1x_to_tegra_bo(bo); - drm_gem_object_unreference_unlocked(&obj->gem); + drm_gem_object_put_unlocked(&obj->gem); } static dma_addr_t tegra_bo_pin(struct host1x_bo *bo, struct sg_table **sgt) @@ -95,7 +95,7 @@ static struct host1x_bo *tegra_bo_get(struct host1x_bo *bo) { struct tegra_bo *obj = host1x_to_tegra_bo(bo); - drm_gem_object_reference(&obj->gem); + drm_gem_object_get(&obj->gem); return bo; } @@ -325,7 +325,7 @@ struct tegra_bo *tegra_bo_create_with_handle(struct drm_file *file, return ERR_PTR(err); } - drm_gem_object_unreference_unlocked(&bo->gem); + drm_gem_object_put_unlocked(&bo->gem); return bo; } @@ -439,7 +439,7 @@ int tegra_bo_dumb_map_offset(struct drm_file *file, struct drm_device *drm, *offset = drm_vma_node_offset_addr(&bo->gem.vma_node); - drm_gem_object_unreference_unlocked(gem); + drm_gem_object_put_unlocked(gem); return 0; } @@ -654,7 +654,7 @@ struct drm_gem_object *tegra_gem_prime_import(struct drm_device *drm, struct drm_gem_object *gem = buf->priv; if (gem->dev == drm) { - drm_gem_object_reference(gem); + drm_gem_object_get(gem); return gem; } } -- cgit From 68d890a3cca5a96a5443972922c84df89f6301e6 Mon Sep 17 00:00:00 2001 From: Michał Mirosław Date: Mon, 14 Aug 2017 23:53:45 +0200 Subject: drm/tegra: Fix NULL deref in debugfs/iova MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When IOMMU is off, ->mm_lock is not initialized and ->mm is NULL. Signed-off-by: Michał Mirosław Signed-off-by: Thierry Reding --- drivers/gpu/drm/tegra/drm.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/tegra/drm.c b/drivers/gpu/drm/tegra/drm.c index eddea778290f..86b3e1ce0b65 100644 --- a/drivers/gpu/drm/tegra/drm.c +++ b/drivers/gpu/drm/tegra/drm.c @@ -1033,9 +1033,11 @@ static int tegra_debugfs_iova(struct seq_file *s, void *data) struct tegra_drm *tegra = drm->dev_private; struct drm_printer p = drm_seq_file_printer(s); - mutex_lock(&tegra->mm_lock); - drm_mm_print(&tegra->mm, &p); - mutex_unlock(&tegra->mm_lock); + if (tegra->domain) { + mutex_lock(&tegra->mm_lock); + drm_mm_print(&tegra->mm, &p); + mutex_unlock(&tegra->mm_lock); + } return 0; } -- cgit From 3be713be1fbcbdb8fd66e06d58cafd7761498fdd Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Tue, 15 Aug 2017 15:41:05 +0200 Subject: drm/tegra: dc: Use unsigned int for register offsets Register offsets are usually fairly small numbers, so an unsigned int is more than enough to represent them. Signed-off-by: Thierry Reding --- drivers/gpu/drm/tegra/drm.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/tegra/drm.h b/drivers/gpu/drm/tegra/drm.h index 6d6da01282f3..de1bcc519905 100644 --- a/drivers/gpu/drm/tegra/drm.h +++ b/drivers/gpu/drm/tegra/drm.h @@ -172,12 +172,12 @@ static inline struct tegra_dc *to_tegra_dc(struct drm_crtc *crtc) } static inline void tegra_dc_writel(struct tegra_dc *dc, u32 value, - unsigned long offset) + unsigned int offset) { writel(value, dc->regs + (offset << 2)); } -static inline u32 tegra_dc_readl(struct tegra_dc *dc, unsigned long offset) +static inline u32 tegra_dc_readl(struct tegra_dc *dc, unsigned int offset) { return readl(dc->regs + (offset << 2)); } -- cgit From e8ddfdcbea4ff7a902b8508b0c51c45da444fd8a Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Tue, 15 Aug 2017 15:41:06 +0200 Subject: drm/tegra: dpaux: Use unsigned int for register offsets Register offsets are usually fairly small numbers, so an unsigned int is more than enough to represent them. Signed-off-by: Thierry Reding --- drivers/gpu/drm/tegra/dpaux.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/tegra/dpaux.c b/drivers/gpu/drm/tegra/dpaux.c index 2fde44c3a1b3..83f1406bd487 100644 --- a/drivers/gpu/drm/tegra/dpaux.c +++ b/drivers/gpu/drm/tegra/dpaux.c @@ -65,13 +65,13 @@ static inline struct tegra_dpaux *work_to_dpaux(struct work_struct *work) } static inline u32 tegra_dpaux_readl(struct tegra_dpaux *dpaux, - unsigned long offset) + unsigned int offset) { return readl(dpaux->regs + (offset << 2)); } static inline void tegra_dpaux_writel(struct tegra_dpaux *dpaux, - u32 value, unsigned long offset) + u32 value, unsigned int offset) { writel(value, dpaux->regs + (offset << 2)); } -- cgit From 12831076ac366e887e648a1d27ab3361a7b315b8 Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Tue, 15 Aug 2017 15:41:07 +0200 Subject: drm/tegra: dsi: Use unsigned int for register offsets Register offsets are usually fairly small numbers, so an unsigned int is more than enough to represent them. Signed-off-by: Thierry Reding --- drivers/gpu/drm/tegra/dsi.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/tegra/dsi.c b/drivers/gpu/drm/tegra/dsi.c index 3dea1216bafd..444664b92fbb 100644 --- a/drivers/gpu/drm/tegra/dsi.c +++ b/drivers/gpu/drm/tegra/dsi.c @@ -105,15 +105,15 @@ static struct tegra_dsi_state *tegra_dsi_get_state(struct tegra_dsi *dsi) return to_dsi_state(dsi->output.connector.state); } -static inline u32 tegra_dsi_readl(struct tegra_dsi *dsi, unsigned long reg) +static inline u32 tegra_dsi_readl(struct tegra_dsi *dsi, unsigned int offset) { - return readl(dsi->regs + (reg << 2)); + return readl(dsi->regs + (offset << 2)); } static inline void tegra_dsi_writel(struct tegra_dsi *dsi, u32 value, - unsigned long reg) + unsigned int offset) { - writel(value, dsi->regs + (reg << 2)); + writel(value, dsi->regs + (offset << 2)); } static int tegra_dsi_show_regs(struct seq_file *s, void *data) -- cgit From 7efe20cf11655e860ae2852ebefebff244ddabb6 Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Tue, 15 Aug 2017 15:41:08 +0200 Subject: drm/tegra: hdmi: Use unsigned int for register offsets Register offsets are usually fairly small numbers, so an unsigned int is more than enough to represent them. Signed-off-by: Thierry Reding --- drivers/gpu/drm/tegra/hdmi.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/tegra/hdmi.c b/drivers/gpu/drm/tegra/hdmi.c index cda0491ed6bf..9161adaf94c1 100644 --- a/drivers/gpu/drm/tegra/hdmi.c +++ b/drivers/gpu/drm/tegra/hdmi.c @@ -100,13 +100,13 @@ enum { }; static inline u32 tegra_hdmi_readl(struct tegra_hdmi *hdmi, - unsigned long offset) + unsigned int offset) { return readl(hdmi->regs + (offset << 2)); } static inline void tegra_hdmi_writel(struct tegra_hdmi *hdmi, u32 value, - unsigned long offset) + unsigned int offset) { writel(value, hdmi->regs + (offset << 2)); } -- cgit From 5c5f13016d2f4d5144418bec57a75490c5f9fc96 Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Tue, 15 Aug 2017 15:41:09 +0200 Subject: drm/tegra: sor: Use unsigned int for register offsets Register offsets are usually fairly small numbers, so an unsigned int is more than enough to represent them. Signed-off-by: Thierry Reding --- drivers/gpu/drm/tegra/sor.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/tegra/sor.c b/drivers/gpu/drm/tegra/sor.c index a8f528925009..d0f189c5171d 100644 --- a/drivers/gpu/drm/tegra/sor.c +++ b/drivers/gpu/drm/tegra/sor.c @@ -232,13 +232,13 @@ static inline struct tegra_sor *to_sor(struct tegra_output *output) return container_of(output, struct tegra_sor, output); } -static inline u32 tegra_sor_readl(struct tegra_sor *sor, unsigned long offset) +static inline u32 tegra_sor_readl(struct tegra_sor *sor, unsigned int offset) { return readl(sor->regs + (offset << 2)); } static inline void tegra_sor_writel(struct tegra_sor *sor, u32 value, - unsigned long offset) + unsigned int offset) { writel(value, sor->regs + (offset << 2)); } -- cgit From 67e04d1ab19b0cc6d87ca7c44b058edf678bc3a3 Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Tue, 15 Aug 2017 15:41:10 +0200 Subject: drm/tegra: dc: Trace register accesses Add tracepoint events for display controller register accesses. Signed-off-by: Thierry Reding --- drivers/gpu/drm/tegra/Makefile | 2 ++ drivers/gpu/drm/tegra/drm.h | 8 +++++++- drivers/gpu/drm/tegra/trace.c | 2 ++ drivers/gpu/drm/tegra/trace.h | 40 ++++++++++++++++++++++++++++++++++++++++ 4 files changed, 51 insertions(+), 1 deletion(-) create mode 100644 drivers/gpu/drm/tegra/trace.c create mode 100644 drivers/gpu/drm/tegra/trace.h diff --git a/drivers/gpu/drm/tegra/Makefile b/drivers/gpu/drm/tegra/Makefile index 6af3a9ad6565..8927784396e8 100644 --- a/drivers/gpu/drm/tegra/Makefile +++ b/drivers/gpu/drm/tegra/Makefile @@ -17,4 +17,6 @@ tegra-drm-y := \ falcon.o \ vic.o +tegra-drm-y += trace.o + obj-$(CONFIG_DRM_TEGRA) += tegra-drm.o diff --git a/drivers/gpu/drm/tegra/drm.h b/drivers/gpu/drm/tegra/drm.h index de1bcc519905..063f5d397526 100644 --- a/drivers/gpu/drm/tegra/drm.h +++ b/drivers/gpu/drm/tegra/drm.h @@ -23,6 +23,7 @@ #include #include "gem.h" +#include "trace.h" struct reset_control; @@ -174,12 +175,17 @@ static inline struct tegra_dc *to_tegra_dc(struct drm_crtc *crtc) static inline void tegra_dc_writel(struct tegra_dc *dc, u32 value, unsigned int offset) { + trace_dc_writel(dc->dev, offset, value); writel(value, dc->regs + (offset << 2)); } static inline u32 tegra_dc_readl(struct tegra_dc *dc, unsigned int offset) { - return readl(dc->regs + (offset << 2)); + u32 value = readl(dc->regs + (offset << 2)); + + trace_dc_readl(dc->dev, offset, value); + + return value; } struct tegra_dc_window { diff --git a/drivers/gpu/drm/tegra/trace.c b/drivers/gpu/drm/tegra/trace.c new file mode 100644 index 000000000000..006f65c72a34 --- /dev/null +++ b/drivers/gpu/drm/tegra/trace.c @@ -0,0 +1,2 @@ +#define CREATE_TRACE_POINTS +#include "trace.h" diff --git a/drivers/gpu/drm/tegra/trace.h b/drivers/gpu/drm/tegra/trace.h new file mode 100644 index 000000000000..b32d90c967e8 --- /dev/null +++ b/drivers/gpu/drm/tegra/trace.h @@ -0,0 +1,40 @@ +#undef TRACE_SYSTEM +#define TRACE_SYSTEM tegra + +#if !defined(DRM_TEGRA_TRACE_H) || defined(TRACE_HEADER_MULTI_READ) +#define DRM_TEGRA_TRACE_H 1 + +#include +#include + +DECLARE_EVENT_CLASS(register_access, + TP_PROTO(struct device *dev, unsigned int offset, u32 value), + TP_ARGS(dev, offset, value), + TP_STRUCT__entry( + __field(struct device *, dev) + __field(unsigned int, offset) + __field(u32, value) + ), + TP_fast_assign( + __entry->dev = dev; + __entry->offset = offset; + __entry->value = value; + ), + TP_printk("%s %04x %08x", dev_name(__entry->dev), __entry->offset, + __entry->value) +); + +DEFINE_EVENT(register_access, dc_writel, + TP_PROTO(struct device *dev, unsigned int offset, u32 value), + TP_ARGS(dev, offset, value)); +DEFINE_EVENT(register_access, dc_readl, + TP_PROTO(struct device *dev, unsigned int offset, u32 value), + TP_ARGS(dev, offset, value)); + +#endif /* DRM_TEGRA_TRACE_H */ + +/* This part must be outside protection */ +#undef TRACE_INCLUDE_PATH +#define TRACE_INCLUDE_PATH . +#define TRACE_INCLUDE_FILE trace +#include -- cgit From 07a8aab89927ee58100b9a0d121dafacbcc3a5dd Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Tue, 15 Aug 2017 15:41:11 +0200 Subject: drm/tegra: hdmi: Trace register accesses Add tracepoint events for HDMI controller register accesses. Signed-off-by: Thierry Reding --- drivers/gpu/drm/tegra/hdmi.c | 8 +++++++- drivers/gpu/drm/tegra/trace.h | 7 +++++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/tegra/hdmi.c b/drivers/gpu/drm/tegra/hdmi.c index 9161adaf94c1..cf9f69fc12e6 100644 --- a/drivers/gpu/drm/tegra/hdmi.c +++ b/drivers/gpu/drm/tegra/hdmi.c @@ -24,6 +24,7 @@ #include "hdmi.h" #include "drm.h" #include "dc.h" +#include "trace.h" #define HDMI_ELD_BUFFER_SIZE 96 @@ -102,12 +103,17 @@ enum { static inline u32 tegra_hdmi_readl(struct tegra_hdmi *hdmi, unsigned int offset) { - return readl(hdmi->regs + (offset << 2)); + u32 value = readl(hdmi->regs + (offset << 2)); + + trace_hdmi_readl(hdmi->dev, offset, value); + + return value; } static inline void tegra_hdmi_writel(struct tegra_hdmi *hdmi, u32 value, unsigned int offset) { + trace_hdmi_writel(hdmi->dev, offset, value); writel(value, hdmi->regs + (offset << 2)); } diff --git a/drivers/gpu/drm/tegra/trace.h b/drivers/gpu/drm/tegra/trace.h index b32d90c967e8..e5c2e431c101 100644 --- a/drivers/gpu/drm/tegra/trace.h +++ b/drivers/gpu/drm/tegra/trace.h @@ -31,6 +31,13 @@ DEFINE_EVENT(register_access, dc_readl, TP_PROTO(struct device *dev, unsigned int offset, u32 value), TP_ARGS(dev, offset, value)); +DEFINE_EVENT(register_access, hdmi_writel, + TP_PROTO(struct device *dev, unsigned int offset, u32 value), + TP_ARGS(dev, offset, value)); +DEFINE_EVENT(register_access, hdmi_readl, + TP_PROTO(struct device *dev, unsigned int offset, u32 value), + TP_ARGS(dev, offset, value)); + #endif /* DRM_TEGRA_TRACE_H */ /* This part must be outside protection */ -- cgit From 75af8fa7fd47e8f76198e13052b42e66d9e1f233 Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Tue, 15 Aug 2017 15:41:12 +0200 Subject: drm/tegra: dsi: Trace register accesses Add tracepoint events for DSI controller register accesses. Signed-off-by: Thierry Reding --- drivers/gpu/drm/tegra/dsi.c | 8 +++++++- drivers/gpu/drm/tegra/trace.h | 7 +++++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/tegra/dsi.c b/drivers/gpu/drm/tegra/dsi.c index 444664b92fbb..6050cc4ebbaf 100644 --- a/drivers/gpu/drm/tegra/dsi.c +++ b/drivers/gpu/drm/tegra/dsi.c @@ -28,6 +28,7 @@ #include "drm.h" #include "dsi.h" #include "mipi-phy.h" +#include "trace.h" struct tegra_dsi_state { struct drm_connector_state base; @@ -107,12 +108,17 @@ static struct tegra_dsi_state *tegra_dsi_get_state(struct tegra_dsi *dsi) static inline u32 tegra_dsi_readl(struct tegra_dsi *dsi, unsigned int offset) { - return readl(dsi->regs + (offset << 2)); + u32 value = readl(dsi->regs + (offset << 2)); + + trace_dsi_readl(dsi->dev, offset, value); + + return value; } static inline void tegra_dsi_writel(struct tegra_dsi *dsi, u32 value, unsigned int offset) { + trace_dsi_writel(dsi->dev, offset, value); writel(value, dsi->regs + (offset << 2)); } diff --git a/drivers/gpu/drm/tegra/trace.h b/drivers/gpu/drm/tegra/trace.h index e5c2e431c101..dd0176ff81eb 100644 --- a/drivers/gpu/drm/tegra/trace.h +++ b/drivers/gpu/drm/tegra/trace.h @@ -38,6 +38,13 @@ DEFINE_EVENT(register_access, hdmi_readl, TP_PROTO(struct device *dev, unsigned int offset, u32 value), TP_ARGS(dev, offset, value)); +DEFINE_EVENT(register_access, dsi_writel, + TP_PROTO(struct device *dev, unsigned int offset, u32 value), + TP_ARGS(dev, offset, value)); +DEFINE_EVENT(register_access, dsi_readl, + TP_PROTO(struct device *dev, unsigned int offset, u32 value), + TP_ARGS(dev, offset, value)); + #endif /* DRM_TEGRA_TRACE_H */ /* This part must be outside protection */ -- cgit From eba7c4551a9b07bf68126e4f22fec4b66475f529 Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Tue, 15 Aug 2017 15:41:13 +0200 Subject: drm/tegra: dpaux: Trace register accesses Add tracepoint events for DPAUX controller register accesses. Signed-off-by: Thierry Reding --- drivers/gpu/drm/tegra/dpaux.c | 8 +++++++- drivers/gpu/drm/tegra/trace.h | 7 +++++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/tegra/dpaux.c b/drivers/gpu/drm/tegra/dpaux.c index 83f1406bd487..e4da041ba89b 100644 --- a/drivers/gpu/drm/tegra/dpaux.c +++ b/drivers/gpu/drm/tegra/dpaux.c @@ -25,6 +25,7 @@ #include "dpaux.h" #include "drm.h" +#include "trace.h" static DEFINE_MUTEX(dpaux_lock); static LIST_HEAD(dpaux_list); @@ -67,12 +68,17 @@ static inline struct tegra_dpaux *work_to_dpaux(struct work_struct *work) static inline u32 tegra_dpaux_readl(struct tegra_dpaux *dpaux, unsigned int offset) { - return readl(dpaux->regs + (offset << 2)); + u32 value = readl(dpaux->regs + (offset << 2)); + + trace_dpaux_readl(dpaux->dev, offset, value); + + return value; } static inline void tegra_dpaux_writel(struct tegra_dpaux *dpaux, u32 value, unsigned int offset) { + trace_dpaux_writel(dpaux->dev, offset, value); writel(value, dpaux->regs + (offset << 2)); } diff --git a/drivers/gpu/drm/tegra/trace.h b/drivers/gpu/drm/tegra/trace.h index dd0176ff81eb..e497a0258ee4 100644 --- a/drivers/gpu/drm/tegra/trace.h +++ b/drivers/gpu/drm/tegra/trace.h @@ -45,6 +45,13 @@ DEFINE_EVENT(register_access, dsi_readl, TP_PROTO(struct device *dev, unsigned int offset, u32 value), TP_ARGS(dev, offset, value)); +DEFINE_EVENT(register_access, dpaux_writel, + TP_PROTO(struct device *dev, unsigned int offset, u32 value), + TP_ARGS(dev, offset, value)); +DEFINE_EVENT(register_access, dpaux_readl, + TP_PROTO(struct device *dev, unsigned int offset, u32 value), + TP_ARGS(dev, offset, value)); + #endif /* DRM_TEGRA_TRACE_H */ /* This part must be outside protection */ -- cgit From 932f6529139ee7279e4c241eea46402ac7275936 Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Tue, 15 Aug 2017 15:41:14 +0200 Subject: drm/tegra: sor: Trace register accesses Add tracepoint events for SOR controller register accesses. Signed-off-by: Thierry Reding --- drivers/gpu/drm/tegra/sor.c | 8 +++++++- drivers/gpu/drm/tegra/trace.h | 7 +++++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/tegra/sor.c b/drivers/gpu/drm/tegra/sor.c index d0f189c5171d..8de2a6cc317d 100644 --- a/drivers/gpu/drm/tegra/sor.c +++ b/drivers/gpu/drm/tegra/sor.c @@ -26,6 +26,7 @@ #include "dc.h" #include "drm.h" #include "sor.h" +#include "trace.h" #define SOR_REKEY 0x38 @@ -234,12 +235,17 @@ static inline struct tegra_sor *to_sor(struct tegra_output *output) static inline u32 tegra_sor_readl(struct tegra_sor *sor, unsigned int offset) { - return readl(sor->regs + (offset << 2)); + u32 value = readl(sor->regs + (offset << 2)); + + trace_sor_readl(sor->dev, offset, value); + + return value; } static inline void tegra_sor_writel(struct tegra_sor *sor, u32 value, unsigned int offset) { + trace_sor_writel(sor->dev, offset, value); writel(value, sor->regs + (offset << 2)); } diff --git a/drivers/gpu/drm/tegra/trace.h b/drivers/gpu/drm/tegra/trace.h index e497a0258ee4..e9b7cdad5c4c 100644 --- a/drivers/gpu/drm/tegra/trace.h +++ b/drivers/gpu/drm/tegra/trace.h @@ -52,6 +52,13 @@ DEFINE_EVENT(register_access, dpaux_readl, TP_PROTO(struct device *dev, unsigned int offset, u32 value), TP_ARGS(dev, offset, value)); +DEFINE_EVENT(register_access, sor_writel, + TP_PROTO(struct device *dev, unsigned int offset, u32 value), + TP_ARGS(dev, offset, value)); +DEFINE_EVENT(register_access, sor_readl, + TP_PROTO(struct device *dev, unsigned int offset, u32 value), + TP_ARGS(dev, offset, value)); + #endif /* DRM_TEGRA_TRACE_H */ /* This part must be outside protection */ -- cgit From 6c68b71776e760c67f10fbdbe56908793a7b1763 Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Tue, 15 Aug 2017 15:42:39 +0200 Subject: drm/tegra: Support render node None of the driver-specific IOCTLs are privileged, so mark them as such and advertise that the driver supports render nodes. Signed-off-by: Thierry Reding --- drivers/gpu/drm/tegra/drm.c | 44 +++++++++++++++++++++++++++++--------------- 1 file changed, 29 insertions(+), 15 deletions(-) diff --git a/drivers/gpu/drm/tegra/drm.c b/drivers/gpu/drm/tegra/drm.c index 86b3e1ce0b65..0251bb1cb545 100644 --- a/drivers/gpu/drm/tegra/drm.c +++ b/drivers/gpu/drm/tegra/drm.c @@ -953,20 +953,34 @@ static int tegra_gem_get_flags(struct drm_device *drm, void *data, static const struct drm_ioctl_desc tegra_drm_ioctls[] = { #ifdef CONFIG_DRM_TEGRA_STAGING - DRM_IOCTL_DEF_DRV(TEGRA_GEM_CREATE, tegra_gem_create, 0), - DRM_IOCTL_DEF_DRV(TEGRA_GEM_MMAP, tegra_gem_mmap, 0), - DRM_IOCTL_DEF_DRV(TEGRA_SYNCPT_READ, tegra_syncpt_read, 0), - DRM_IOCTL_DEF_DRV(TEGRA_SYNCPT_INCR, tegra_syncpt_incr, 0), - DRM_IOCTL_DEF_DRV(TEGRA_SYNCPT_WAIT, tegra_syncpt_wait, 0), - DRM_IOCTL_DEF_DRV(TEGRA_OPEN_CHANNEL, tegra_open_channel, 0), - DRM_IOCTL_DEF_DRV(TEGRA_CLOSE_CHANNEL, tegra_close_channel, 0), - DRM_IOCTL_DEF_DRV(TEGRA_GET_SYNCPT, tegra_get_syncpt, 0), - DRM_IOCTL_DEF_DRV(TEGRA_SUBMIT, tegra_submit, 0), - DRM_IOCTL_DEF_DRV(TEGRA_GET_SYNCPT_BASE, tegra_get_syncpt_base, 0), - DRM_IOCTL_DEF_DRV(TEGRA_GEM_SET_TILING, tegra_gem_set_tiling, 0), - DRM_IOCTL_DEF_DRV(TEGRA_GEM_GET_TILING, tegra_gem_get_tiling, 0), - DRM_IOCTL_DEF_DRV(TEGRA_GEM_SET_FLAGS, tegra_gem_set_flags, 0), - DRM_IOCTL_DEF_DRV(TEGRA_GEM_GET_FLAGS, tegra_gem_get_flags, 0), + DRM_IOCTL_DEF_DRV(TEGRA_GEM_CREATE, tegra_gem_create, + DRM_UNLOCKED | DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(TEGRA_GEM_MMAP, tegra_gem_mmap, + DRM_UNLOCKED | DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(TEGRA_SYNCPT_READ, tegra_syncpt_read, + DRM_UNLOCKED | DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(TEGRA_SYNCPT_INCR, tegra_syncpt_incr, + DRM_UNLOCKED | DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(TEGRA_SYNCPT_WAIT, tegra_syncpt_wait, + DRM_UNLOCKED | DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(TEGRA_OPEN_CHANNEL, tegra_open_channel, + DRM_UNLOCKED | DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(TEGRA_CLOSE_CHANNEL, tegra_close_channel, + DRM_UNLOCKED | DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(TEGRA_GET_SYNCPT, tegra_get_syncpt, + DRM_UNLOCKED | DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(TEGRA_SUBMIT, tegra_submit, + DRM_UNLOCKED | DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(TEGRA_GET_SYNCPT_BASE, tegra_get_syncpt_base, + DRM_UNLOCKED | DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(TEGRA_GEM_SET_TILING, tegra_gem_set_tiling, + DRM_UNLOCKED | DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(TEGRA_GEM_GET_TILING, tegra_gem_get_tiling, + DRM_UNLOCKED | DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(TEGRA_GEM_SET_FLAGS, tegra_gem_set_flags, + DRM_UNLOCKED | DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(TEGRA_GEM_GET_FLAGS, tegra_gem_get_flags, + DRM_UNLOCKED | DRM_RENDER_ALLOW), #endif }; @@ -1057,7 +1071,7 @@ static int tegra_debugfs_init(struct drm_minor *minor) static struct drm_driver tegra_drm_driver = { .driver_features = DRIVER_MODESET | DRIVER_GEM | DRIVER_PRIME | - DRIVER_ATOMIC, + DRIVER_ATOMIC | DRIVER_RENDER, .load = tegra_drm_load, .unload = tegra_drm_unload, .open = tegra_drm_open, -- cgit From a8bc8c6510d64b759644647a03f8aec55056bded Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Tue, 15 Aug 2017 15:42:40 +0200 Subject: drm/tegra: gem: Implement mmap() for PRIME buffers The mapping of PRIME buffers can reuse much of the GEM mapping code, so extract the common bits into a new tegra_gem_mmap() helper. Reviewed-by: Chris Wilson Signed-off-by: Thierry Reding --- drivers/gpu/drm/tegra/gem.c | 49 +++++++++++++++++++++++++++++++-------------- 1 file changed, 34 insertions(+), 15 deletions(-) diff --git a/drivers/gpu/drm/tegra/gem.c b/drivers/gpu/drm/tegra/gem.c index fe77bcd23800..ef068556a9d7 100644 --- a/drivers/gpu/drm/tegra/gem.c +++ b/drivers/gpu/drm/tegra/gem.c @@ -481,30 +481,28 @@ const struct vm_operations_struct tegra_bo_vm_ops = { .close = drm_gem_vm_close, }; -int tegra_drm_mmap(struct file *file, struct vm_area_struct *vma) +static int tegra_gem_mmap(struct drm_gem_object *gem, + struct vm_area_struct *vma) { - struct drm_gem_object *gem; - struct tegra_bo *bo; - int ret; - - ret = drm_gem_mmap(file, vma); - if (ret) - return ret; - - gem = vma->vm_private_data; - bo = to_tegra_bo(gem); + struct tegra_bo *bo = to_tegra_bo(gem); if (!bo->pages) { unsigned long vm_pgoff = vma->vm_pgoff; + int err; + /* + * Clear the VM_PFNMAP flag that was set by drm_gem_mmap(), + * and set the vm_pgoff (used as a fake buffer offset by DRM) + * to 0 as we want to map the whole buffer. + */ vma->vm_flags &= ~VM_PFNMAP; vma->vm_pgoff = 0; - ret = dma_mmap_wc(gem->dev->dev, vma, bo->vaddr, bo->paddr, + err = dma_mmap_wc(gem->dev->dev, vma, bo->vaddr, bo->paddr, gem->size); - if (ret) { + if (err < 0) { drm_gem_vm_close(vma); - return ret; + return err; } vma->vm_pgoff = vm_pgoff; @@ -520,6 +518,20 @@ int tegra_drm_mmap(struct file *file, struct vm_area_struct *vma) return 0; } +int tegra_drm_mmap(struct file *file, struct vm_area_struct *vma) +{ + struct drm_gem_object *gem; + int err; + + err = drm_gem_mmap(file, vma); + if (err < 0) + return err; + + gem = vma->vm_private_data; + + return tegra_gem_mmap(gem, vma); +} + static struct sg_table * tegra_gem_prime_map_dma_buf(struct dma_buf_attachment *attach, enum dma_data_direction dir) @@ -603,7 +615,14 @@ static void tegra_gem_prime_kunmap(struct dma_buf *buf, unsigned long page, static int tegra_gem_prime_mmap(struct dma_buf *buf, struct vm_area_struct *vma) { - return -EINVAL; + struct drm_gem_object *gem = buf->priv; + int err; + + err = drm_gem_mmap_obj(gem, gem->size, vma); + if (err < 0) + return err; + + return tegra_gem_mmap(gem, vma); } static void *tegra_gem_prime_vmap(struct dma_buf *buf) -- cgit From ec73c4cfe7de6229e49989f7d7754a7039cd5c28 Mon Sep 17 00:00:00 2001 From: Dmitry Osipenko Date: Fri, 11 Aug 2017 19:54:56 +0200 Subject: drm/tegra: Prevent BOs from being freed during job submission Since DRM IOCTL's are lockless, there is a chance that BOs could be released while a job submission is in progress. To avoid that, keep the GEM reference until the job has been pinned, part of which will be to take another reference. v2: remove redundant check and avoid memory leak Signed-off-by: Dmitry Osipenko Signed-off-by: Thierry Reding --- drivers/gpu/drm/tegra/drm.c | 40 +++++++++++++++++++++++++++++++--------- 1 file changed, 31 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/tegra/drm.c b/drivers/gpu/drm/tegra/drm.c index 0251bb1cb545..ba46414e1897 100644 --- a/drivers/gpu/drm/tegra/drm.c +++ b/drivers/gpu/drm/tegra/drm.c @@ -304,8 +304,6 @@ host1x_bo_lookup(struct drm_file *file, u32 handle) if (!gem) return NULL; - drm_gem_object_put_unlocked(gem); - bo = to_tegra_bo(gem); return &bo->base; } @@ -394,8 +392,10 @@ int tegra_drm_submit(struct tegra_drm_context *context, (void __user *)(uintptr_t)args->waitchks; struct drm_tegra_syncpt syncpt; struct host1x *host1x = dev_get_drvdata(drm->dev->parent); + struct drm_gem_object **refs; struct host1x_syncpt *sp; struct host1x_job *job; + unsigned int num_refs; int err; /* We don't yet support other than one syncpt_incr struct per submit */ @@ -417,6 +417,21 @@ int tegra_drm_submit(struct tegra_drm_context *context, job->class = context->client->base.class; job->serialize = true; + /* + * Track referenced BOs so that they can be unreferenced after the + * submission is complete. + */ + num_refs = num_cmdbufs + num_relocs * 2 + num_waitchks; + + refs = kmalloc_array(num_refs, sizeof(*refs), GFP_KERNEL); + if (!refs) { + err = -ENOMEM; + goto put; + } + + /* reuse as an iterator later */ + num_refs = 0; + while (num_cmdbufs) { struct drm_tegra_cmdbuf cmdbuf; struct host1x_bo *bo; @@ -445,6 +460,7 @@ int tegra_drm_submit(struct tegra_drm_context *context, offset = (u64)cmdbuf.offset + (u64)cmdbuf.words * sizeof(u32); obj = host1x_to_tegra_bo(bo); + refs[num_refs++] = &obj->gem; /* * Gather buffer base address must be 4-bytes aligned, @@ -474,6 +490,7 @@ int tegra_drm_submit(struct tegra_drm_context *context, reloc = &job->relocarray[num_relocs]; obj = host1x_to_tegra_bo(reloc->cmdbuf.bo); + refs[num_refs++] = &obj->gem; /* * The unaligned cmdbuf offset will cause an unaligned write @@ -487,6 +504,7 @@ int tegra_drm_submit(struct tegra_drm_context *context, } obj = host1x_to_tegra_bo(reloc->target.bo); + refs[num_refs++] = &obj->gem; if (reloc->target.offset >= obj->gem.size) { err = -EINVAL; @@ -506,6 +524,7 @@ int tegra_drm_submit(struct tegra_drm_context *context, goto fail; obj = host1x_to_tegra_bo(wait->bo); + refs[num_refs++] = &obj->gem; /* * The unaligned offset will cause an unaligned write during @@ -545,17 +564,20 @@ int tegra_drm_submit(struct tegra_drm_context *context, goto fail; err = host1x_job_submit(job); - if (err) - goto fail_submit; + if (err) { + host1x_job_unpin(job); + goto fail; + } args->fence = job->syncpt_end; - host1x_job_put(job); - return 0; - -fail_submit: - host1x_job_unpin(job); fail: + while (num_refs--) + drm_gem_object_put_unlocked(refs[num_refs]); + + kfree(refs); + +put: host1x_job_put(job); return err; } -- cgit