From 1aae839462d56cd67667b0ea224452c62d4d1908 Mon Sep 17 00:00:00 2001 From: Mark Yao Date: Thu, 8 Dec 2016 17:00:30 +0800 Subject: [PATCH] drm/rockchip: fix iommu page fault when use boot logo Since (cacb6f5 FROMLIST: drm/rockchip: Use common IOMMU API to attach devices), rockchip drm use common IOMMU API, the boot logo buffer mapping need change to new api. Change-Id: Ifa2c886e05d2de65de53a868458c56859519a0f2 Signed-off-by: Mark Yao --- drivers/gpu/drm/rockchip/rockchip_drm_drv.c | 42 +++++++++++++++++---- drivers/gpu/drm/rockchip/rockchip_drm_drv.h | 1 + drivers/gpu/drm/rockchip/rockchip_drm_fb.c | 12 +++++- 3 files changed, 45 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c index 148e6d4de154..5b4f1daa45e9 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c @@ -111,7 +111,6 @@ static int init_loader_memory(struct drm_device *drm_dev) unsigned long nr_pages; struct page **pages; struct sg_table *sgt; - DEFINE_DMA_ATTRS(attrs); phys_addr_t start, size; struct resource res; int i, ret; @@ -144,15 +143,35 @@ static int init_loader_memory(struct drm_device *drm_dev) } sgt = drm_prime_pages_to_sg(pages, nr_pages); if (IS_ERR(sgt)) { - kfree(pages); - return PTR_ERR(sgt); + ret = PTR_ERR(sgt); + goto err_free_pages; + } + + if (private->domain) { + int prot = IOMMU_READ | IOMMU_WRITE; + + memset(&logo->mm, 0, sizeof(logo->mm)); + ret = drm_mm_insert_node_generic(&private->mm, &logo->mm, + size, PAGE_SIZE, + 0, 0, 0); + if (ret < 0) { + DRM_ERROR("out of I/O virtual memory: %d\n", ret); + goto err_free_pages; + } + + logo->dma_addr = logo->mm.start; + + if (iommu_map_sg(private->domain, logo->dma_addr, sgt->sgl, + sgt->nents, prot) < size) { + DRM_ERROR("failed to map buffer"); + ret = -ENOMEM; + goto err_remove_node; + } + } else { + dma_map_sg(drm_dev->dev, sgt->sgl, sgt->nents, DMA_TO_DEVICE); + logo->dma_addr = sg_dma_address(sgt->sgl); } - dma_set_attr(DMA_ATTR_SKIP_CPU_SYNC, &attrs); - dma_set_attr(DMA_ATTR_NO_KERNEL_MAPPING, &attrs); - dma_map_sg_attrs(drm_dev->dev, sgt->sgl, sgt->nents, - DMA_TO_DEVICE, &attrs); - logo->dma_addr = sg_dma_address(sgt->sgl); logo->sgt = sgt; logo->start = res.start; logo->size = size; @@ -160,6 +179,13 @@ static int init_loader_memory(struct drm_device *drm_dev) private->logo = logo; return 0; + +err_remove_node: + drm_mm_remove_node(&logo->mm); +err_free_pages: + kfree(pages); + + return ret; } static struct drm_framebuffer * diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h index 31c90c8e9737..72db38bfe84c 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h +++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h @@ -90,6 +90,7 @@ struct rockchip_drm_file_private { struct rockchip_logo { struct sg_table *sgt; + struct drm_mm_node mm; dma_addr_t dma_addr; phys_addr_t start; phys_addr_t size; diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_fb.c b/drivers/gpu/drm/rockchip/rockchip_drm_fb.c index 3f5f8c42fda4..deeeab3afe8f 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_fb.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_fb.c @@ -19,6 +19,7 @@ #include #include #include +#include #include "rockchip_drm_drv.h" #include "rockchip_drm_gem.h" @@ -46,6 +47,7 @@ dma_addr_t rockchip_fb_get_dma_addr(struct drm_framebuffer *fb, static void rockchip_drm_fb_destroy(struct drm_framebuffer *fb) { struct rockchip_drm_fb *rockchip_fb = to_rockchip_fb(fb); + struct rockchip_drm_private *private = fb->dev->dev_private; struct drm_gem_object *obj; int i; @@ -63,8 +65,14 @@ static void rockchip_drm_fb_destroy(struct drm_framebuffer *fb) void *start = phys_to_virt(logo->start); void *end = phys_to_virt(logo->size); - dma_unmap_sg(fb->dev->dev, logo->sgt->sgl, - logo->sgt->nents, DMA_TO_DEVICE); + if (private && private->domain) { + iommu_unmap(private->domain, logo->dma_addr, + logo->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"); -- 2.34.1