]> asedeno.scripts.mit.edu Git - linux.git/commitdiff
drm/etnaviv: map cmdbuf through MMU on version 2
authorLucas Stach <l.stach@pengutronix.de>
Fri, 19 Aug 2016 21:49:10 +0000 (23:49 +0200)
committerLucas Stach <l.stach@pengutronix.de>
Thu, 15 Sep 2016 13:29:40 +0000 (15:29 +0200)
With MMUv2 all buffers need to be mapped through the MMU once it
is enabled. Align the buffer size to 4K, as the MMU is only able to
map page aligned buffers.

Signed-off-by: Lucas Stach <l.stach@pengutronix.de>
drivers/gpu/drm/etnaviv/etnaviv_gpu.c
drivers/gpu/drm/etnaviv/etnaviv_gpu.h
drivers/gpu/drm/etnaviv/etnaviv_mmu.c
drivers/gpu/drm/etnaviv/etnaviv_mmu.h

index fcf4b927dc83bb8e26c4b0d7b893398741c7ce2b..9b61be847d45c1451fcc414d7139ad48682be6d4 100644 (file)
@@ -1112,6 +1112,9 @@ struct etnaviv_cmdbuf *etnaviv_gpu_cmdbuf_new(struct etnaviv_gpu *gpu, u32 size,
        if (!cmdbuf)
                return NULL;
 
+       if (gpu->mmu->version == ETNAVIV_IOMMU_V2)
+               size = ALIGN(size, SZ_4K);
+
        cmdbuf->vaddr = dma_alloc_wc(gpu->dev, size, &cmdbuf->paddr,
                                     GFP_KERNEL);
        if (!cmdbuf->vaddr) {
@@ -1127,6 +1130,7 @@ struct etnaviv_cmdbuf *etnaviv_gpu_cmdbuf_new(struct etnaviv_gpu *gpu, u32 size,
 
 void etnaviv_gpu_cmdbuf_free(struct etnaviv_cmdbuf *cmdbuf)
 {
+       etnaviv_iommu_put_cmdbuf_va(cmdbuf->gpu, cmdbuf);
        dma_free_wc(cmdbuf->gpu->dev, cmdbuf->size, cmdbuf->vaddr,
                    cmdbuf->paddr);
        kfree(cmdbuf);
index 7a10a9c32a70083bf90cad748ce5e978dbfa12c5..73c278dc37061a54a5c23dc24559c85d5b1d8525 100644 (file)
@@ -160,6 +160,8 @@ struct etnaviv_cmdbuf {
        dma_addr_t paddr;
        u32 size;
        u32 user_size;
+       /* vram node used if the cmdbuf is mapped through the MMUv2 */
+       struct drm_mm_node vram_node;
        /* fence after which this buffer is to be disposed */
        struct fence *fence;
        /* target exec state */
index 69ea0a0a70c29b17ebd0272de76860d8a197afe5..98c84ef862c745b1b1fcc610c8e0a5a4d0b76c80 100644 (file)
@@ -319,9 +319,49 @@ void etnaviv_iommu_restore(struct etnaviv_gpu *gpu)
 u32 etnaviv_iommu_get_cmdbuf_va(struct etnaviv_gpu *gpu,
                                struct etnaviv_cmdbuf *buf)
 {
-       return buf->paddr - gpu->memory_base;
+       struct etnaviv_iommu *mmu = gpu->mmu;
+
+       if (mmu->version == ETNAVIV_IOMMU_V1) {
+               return buf->paddr - gpu->memory_base;
+       } else {
+               int ret;
+
+               if (buf->vram_node.allocated)
+                       return (u32)buf->vram_node.start;
+
+               mutex_lock(&mmu->lock);
+               ret = etnaviv_iommu_find_iova(mmu, &buf->vram_node, buf->size);
+               if (ret < 0) {
+                       mutex_unlock(&mmu->lock);
+                       return 0;
+               }
+               ret = iommu_map(mmu->domain, buf->vram_node.start, buf->paddr,
+                               buf->size, IOMMU_READ);
+               if (ret < 0) {
+                       drm_mm_remove_node(&buf->vram_node);
+                       mutex_unlock(&mmu->lock);
+                       return 0;
+               }
+               mmu->last_iova = buf->vram_node.start + buf->size;
+               gpu->mmu->need_flush = true;
+               mutex_unlock(&mmu->lock);
+
+               return (u32)buf->vram_node.start;
+       }
 }
 
+void etnaviv_iommu_put_cmdbuf_va(struct etnaviv_gpu *gpu,
+                                struct etnaviv_cmdbuf *buf)
+{
+       struct etnaviv_iommu *mmu = gpu->mmu;
+
+       if (mmu->version == ETNAVIV_IOMMU_V2 && buf->vram_node.allocated) {
+               mutex_lock(&mmu->lock);
+               iommu_unmap(mmu->domain, buf->vram_node.start, buf->size);
+               drm_mm_remove_node(&buf->vram_node);
+               mutex_unlock(&mmu->lock);
+       }
+}
 size_t etnaviv_iommu_dump_size(struct etnaviv_iommu *iommu)
 {
        struct etnaviv_iommu_ops *ops;
index 0d34325a318a11d816f3757b40eda7fdfaa644de..e787e49c9693cf74f08177649e1495af8e212f87 100644 (file)
@@ -64,6 +64,8 @@ void etnaviv_iommu_destroy(struct etnaviv_iommu *iommu);
 
 u32 etnaviv_iommu_get_cmdbuf_va(struct etnaviv_gpu *gpu,
                                struct etnaviv_cmdbuf *buf);
+void etnaviv_iommu_put_cmdbuf_va(struct etnaviv_gpu *gpu,
+                                struct etnaviv_cmdbuf *buf);
 
 size_t etnaviv_iommu_dump_size(struct etnaviv_iommu *iommu);
 void etnaviv_iommu_dump(struct etnaviv_iommu *iommu, void *buf);