From c142c62b580d988adf2baa40e5f09302f3a0f9d9 Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Fri, 15 May 2015 13:04:46 -0700 Subject: drm/vc4: Make sure we clean up GEM if probe fails. We often return -EPROBE_DEFER from the various components, and we would have left a bunch of GEM stuff running and allocated. Cleans up a boot-time warning about how we leaked the 256k of overflow_mem. Signed-off-by: Eric Anholt --- drivers/gpu/drm/vc4/vc4_bo.c | 35 ++++++++++++++++++++++++++++++++++- drivers/gpu/drm/vc4/vc4_drv.c | 4 +++- drivers/gpu/drm/vc4/vc4_drv.h | 2 ++ drivers/gpu/drm/vc4/vc4_gem.c | 21 +++++++++++++++++++++ drivers/gpu/drm/vc4/vc4_irq.c | 4 ++-- drivers/gpu/drm/vc4/vc4_v3d.c | 13 +++++++++++++ 6 files changed, 75 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/vc4/vc4_bo.c b/drivers/gpu/drm/vc4/vc4_bo.c index ba91b7c17ab1..62e8a0c27a39 100644 --- a/drivers/gpu/drm/vc4/vc4_bo.c +++ b/drivers/gpu/drm/vc4/vc4_bo.c @@ -25,6 +25,23 @@ static struct { u32 size_cached; } bo_stats; +static void +vc4_bo_stats_dump(void) +{ + DRM_INFO("num bos allocated: %d\n", + bo_stats.num_allocated); + DRM_INFO("size bos allocated: %dkb\n", + bo_stats.size_allocated / 1024); + DRM_INFO("num bos used: %d\n", + bo_stats.num_allocated - bo_stats.num_cached); + DRM_INFO("size bos used: %dkb\n", + (bo_stats.size_allocated - bo_stats.size_cached) / 1024); + DRM_INFO("num bos cached: %d\n", + bo_stats.num_cached); + DRM_INFO("size bos cached: %dkb\n", + bo_stats.size_cached / 1024); +} + static uint32_t bo_page_index(size_t size) { @@ -88,7 +105,7 @@ vc4_get_cache_list_for_size(struct drm_device *dev, size_t size) return &vc4->bo_cache.size_list[page_index]; } -static void +void vc4_bo_cache_purge(struct drm_device *dev) { struct vc4_dev *vc4 = to_vc4_dev(dev); @@ -273,6 +290,22 @@ vc4_bo_cache_init(struct drm_device *dev) (unsigned long) dev); } +void +vc4_bo_cache_destroy(struct drm_device *dev) +{ + struct vc4_dev *vc4 = to_vc4_dev(dev); + + del_timer(&vc4->bo_cache.time_timer); + cancel_work_sync(&vc4->bo_cache.time_work); + + vc4_bo_cache_purge(dev); + + if (bo_stats.num_allocated) { + DRM_ERROR("Destroying BO cache while BOs still allocated:\n"); + vc4_bo_stats_dump(); + } +} + struct drm_gem_object * vc4_prime_import(struct drm_device *dev, struct dma_buf *dma_buf) { diff --git a/drivers/gpu/drm/vc4/vc4_drv.c b/drivers/gpu/drm/vc4/vc4_drv.c index 471f6bcaee95..8d32dca645ad 100644 --- a/drivers/gpu/drm/vc4/vc4_drv.c +++ b/drivers/gpu/drm/vc4/vc4_drv.c @@ -78,8 +78,10 @@ vc4_drm_load(struct drm_device *dev, unsigned long flags) vc4_gem_init(dev); ret = component_bind_all(dev->dev, dev); - if (ret) + if (ret) { + vc4_gem_destroy(dev); return ret; + } vc4_kms_load(dev); diff --git a/drivers/gpu/drm/vc4/vc4_drv.h b/drivers/gpu/drm/vc4/vc4_drv.h index fa14c801b1a4..57b889e072ef 100644 --- a/drivers/gpu/drm/vc4/vc4_drv.h +++ b/drivers/gpu/drm/vc4/vc4_drv.h @@ -353,6 +353,7 @@ void vc4_disable_vblank(struct drm_device *dev, int crtc_id); /* vc4_bo.c */ void vc4_bo_cache_init(struct drm_device *dev); +void vc4_bo_cache_destroy(struct drm_device *dev); void vc4_free_object(struct drm_gem_object *gem_obj); struct vc4_bo *vc4_bo_create(struct drm_device *dev, size_t size); int vc4_dumb_create(struct drm_file *file_priv, @@ -377,6 +378,7 @@ void __iomem *vc4_ioremap_regs(struct platform_device *dev, int index); /* vc4_gem.c */ void vc4_gem_init(struct drm_device *dev); +void vc4_gem_destroy(struct drm_device *dev); int vc4_submit_cl_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); int vc4_wait_seqno_ioctl(struct drm_device *dev, void *data, diff --git a/drivers/gpu/drm/vc4/vc4_gem.c b/drivers/gpu/drm/vc4/vc4_gem.c index c2561ea1cdb3..3cec0eb16a12 100644 --- a/drivers/gpu/drm/vc4/vc4_gem.c +++ b/drivers/gpu/drm/vc4/vc4_gem.c @@ -634,3 +634,24 @@ vc4_gem_init(struct drm_device *dev) vc4_bo_cache_init(dev); } + +void +vc4_gem_destroy(struct drm_device *dev) +{ + struct vc4_dev *vc4 = to_vc4_dev(dev); + + /* Waiting for exec to finish would need to be done before + * unregistering V3D. + */ + WARN_ON(vc4->emit_seqno != vc4->finished_seqno); + + /* V3D should already have disabled its interrupt and cleared + * the overflow allocation registers. Now free the object. + */ + if (vc4->overflow_mem) { + drm_gem_object_unreference_unlocked(&vc4->overflow_mem->base.base); + vc4->overflow_mem = NULL; + } + + vc4_bo_cache_destroy(dev); +} diff --git a/drivers/gpu/drm/vc4/vc4_irq.c b/drivers/gpu/drm/vc4/vc4_irq.c index c2f539c3b6c6..df9c4c86fa34 100644 --- a/drivers/gpu/drm/vc4/vc4_irq.c +++ b/drivers/gpu/drm/vc4/vc4_irq.c @@ -167,13 +167,13 @@ vc4_irq_uninstall(struct drm_device *dev) { struct vc4_dev *vc4 = to_vc4_dev(dev); - cancel_work_sync(&vc4->overflow_mem_work); - V3D_WRITE(V3D_INTENA, 0); V3D_WRITE(V3D_INTDIS, 0); /* Clear any pending interrupts we might have left. */ V3D_WRITE(V3D_INTCTL, V3D_DRIVER_IRQS); + + cancel_work_sync(&vc4->overflow_mem_work); } /** Reinitializes interrupt registers when a GPU reset is performed. */ diff --git a/drivers/gpu/drm/vc4/vc4_v3d.c b/drivers/gpu/drm/vc4/vc4_v3d.c index 9321fa2a2f23..2ac27c9944f1 100644 --- a/drivers/gpu/drm/vc4/vc4_v3d.c +++ b/drivers/gpu/drm/vc4/vc4_v3d.c @@ -200,6 +200,12 @@ static int vc4_v3d_bind(struct device *dev, struct device *master, void *data) return -EINVAL; } + /* Reset the binner overflow address/size at setup, to be sure + * we don't reuse an old one. + */ + V3D_WRITE(V3D_BPOA, 0); + V3D_WRITE(V3D_BPOS, 0); + vc4_v3d_init_hw(drm); ret = drm_irq_install(drm, platform_get_irq(pdev, 0)); @@ -219,6 +225,13 @@ static void vc4_v3d_unbind(struct device *dev, struct device *master, drm_irq_uninstall(drm); + /* Disable the binner's overflow memory address, so the next + * driver probe (if any) doesn't try to reuse our old + * allocation. + */ + V3D_WRITE(V3D_BPOA, 0); + V3D_WRITE(V3D_BPOS, 0); + vc4->v3d = NULL; } -- cgit v1.2.1