From b52e5684070a9dda73b4bef57886f700cdaab7c8 Mon Sep 17 00:00:00 2001 From: Mark Yao Date: Fri, 31 Mar 2017 20:15:02 +0800 Subject: [PATCH] drm/rockchip: fix some loader logo bugs fix some bugs: 1, If all connector failed to display, loader logo can't free. 2, if first route failed to display, loder logo free unexpect, cause iommu crash. Change-Id: I838c9fd6768a5ac48d8ce4175038b4620a95cd42 Signed-off-by: Mark Yao --- drivers/gpu/drm/rockchip/rockchip_drm_drv.c | 48 ++++++++++++++++++--- drivers/gpu/drm/rockchip/rockchip_drm_drv.h | 3 ++ drivers/gpu/drm/rockchip/rockchip_drm_fb.c | 23 +--------- 3 files changed, 47 insertions(+), 27 deletions(-) diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c index cf83cd1ec676..e7846ae7f9f6 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c @@ -67,6 +67,7 @@ struct rockchip_drm_mode_set { int ratio; }; +#ifndef MODULE static struct drm_crtc *find_crtc_by_node(struct drm_device *drm_dev, struct device_node *node) { @@ -103,6 +104,34 @@ static struct drm_connector *find_connector_by_node(struct drm_device *drm_dev, return NULL; } +void rockchip_free_loader_memory(struct drm_device *drm) +{ + struct rockchip_drm_private *private = drm->dev_private; + struct rockchip_logo *logo; + void *start, *end; + + if (!private || !private->logo || --private->logo->count) + return; + + logo = private->logo; + start = phys_to_virt(logo->start); + end = phys_to_virt(logo->size); + + if (private->domain) { + iommu_unmap(private->domain, logo->dma_addr, + logo->iommu_map_size); + drm_mm_remove_node(&logo->mm); + } else { + dma_unmap_sg(drm->dev, logo->sgt->sgl, + logo->sgt->nents, DMA_TO_DEVICE); + } + sg_free_table(logo->sgt); + memblock_free(logo->start, logo->size); + free_reserved_area(start, end, -1, "drm_logo"); + kfree(logo); + private->logo = NULL; +} + static int init_loader_memory(struct drm_device *drm_dev) { struct rockchip_drm_private *private = drm_dev->dev_private; @@ -116,10 +145,6 @@ static int init_loader_memory(struct drm_device *drm_dev) struct resource res; int i, ret; - logo = devm_kmalloc(drm_dev->dev, sizeof(*logo), GFP_KERNEL); - if (!logo) - return -ENOMEM; - node = of_parse_phandle(np, "memory-region", 0); if (!node) return -ENOMEM; @@ -132,10 +157,14 @@ static int init_loader_memory(struct drm_device *drm_dev) if (!size) return -ENOMEM; + logo = kmalloc(sizeof(*logo), GFP_KERNEL); + if (!logo) + return -ENOMEM; + nr_pages = PAGE_ALIGN(size) >> PAGE_SHIFT; pages = kmalloc_array(nr_pages, sizeof(*pages), GFP_KERNEL); if (!pages) - return -ENOMEM; + goto err_free_logo; i = 0; while (i < nr_pages) { pages[i] = phys_to_page(start); @@ -176,7 +205,7 @@ static int init_loader_memory(struct drm_device *drm_dev) logo->sgt = sgt; logo->start = res.start; logo->size = size; - logo->count = 0; + logo->count = 1; private->logo = logo; return 0; @@ -185,6 +214,8 @@ err_remove_node: drm_mm_remove_node(&logo->mm); err_free_pages: kfree(pages); +err_free_logo: + kfree(logo); return ret; } @@ -633,6 +664,8 @@ static void show_loader_logo(struct drm_device *drm_dev) if (ret) goto err_free_state; + rockchip_free_loader_memory(drm_dev); + drm_modeset_unlock_all(drm_dev); return; @@ -643,6 +676,7 @@ err_unlock: if (ret) dev_err(drm_dev->dev, "failed to show loader logo\n"); } +#endif /* * Attach a (component) device to the shared drm dma mapping from master drm @@ -910,7 +944,9 @@ static int rockchip_drm_bind(struct device *dev) drm_mode_config_reset(drm_dev); +#ifndef MODULE show_loader_logo(drm_dev); +#endif ret = rockchip_drm_fbdev_init(drm_dev); if (ret) diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h index 521331acbf40..f41cf66dfd91 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h +++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h @@ -135,6 +135,9 @@ struct rockchip_drm_private { struct drm_mm mm; }; +#ifndef MODULE +void rockchip_free_loader_memory(struct drm_device *drm); +#endif void rockchip_drm_atomic_work(struct work_struct *work); int rockchip_register_crtc_funcs(struct drm_crtc *crtc, const struct rockchip_crtc_funcs *crtc_funcs); diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_fb.c b/drivers/gpu/drm/rockchip/rockchip_drm_fb.c index 9b8d15b1e267..c261a166ca22 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_fb.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_fb.c @@ -57,27 +57,8 @@ static void rockchip_drm_fb_destroy(struct drm_framebuffer *fb) } #ifndef MODULE - if (rockchip_fb->logo) { - struct rockchip_drm_private *private = fb->dev->dev_private; - struct rockchip_logo *logo = rockchip_fb->logo; - - if (!--logo->count) { - void *start = phys_to_virt(logo->start); - void *end = phys_to_virt(logo->size); - - if (private && private->domain) { - iommu_unmap(private->domain, logo->dma_addr, - logo->iommu_map_size); - drm_mm_remove_node(&logo->mm); - } else { - dma_unmap_sg(fb->dev->dev, logo->sgt->sgl, - logo->sgt->nents, DMA_TO_DEVICE); - } - sg_free_table(logo->sgt); - memblock_free(logo->start, logo->size); - free_reserved_area(start, end, -1, "drm_logo"); - } - } + if (rockchip_fb->logo) + rockchip_free_loader_memory(fb->dev); #else WARN_ON(rockchip_fb->logo); #endif -- 2.34.1