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 <mark.yao@rock-chips.com>
This commit is contained in:
Mark Yao
2016-12-08 17:00:30 +08:00
committed by Huang, Tao
parent 20977374c5
commit 1aae839462
3 changed files with 45 additions and 10 deletions

View File

@@ -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 *

View File

@@ -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;

View File

@@ -19,6 +19,7 @@
#include <drm/drm_fb_helper.h>
#include <drm/drm_crtc_helper.h>
#include <linux/memblock.h>
#include <linux/iommu.h>
#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");