X-Git-Url: http://git.monstr.eu/?a=blobdiff_plain;f=drivers%2Fgpu%2Fdrm%2Fetnaviv%2Fetnaviv_iommu.c;h=1a7c89a67bea3c4e2464c8017d7f4d69474d78b1;hb=dbcc574a4bfad810ce6e118f3cf327c7b6e7c897;hp=b163bdbcb8803b1644d191dda9ccec5c4bb26cb0;hpb=d4ec49d332aba29827504cc666205aef91a281c7;p=linux-2.6-microblaze.git diff --git a/drivers/gpu/drm/etnaviv/etnaviv_iommu.c b/drivers/gpu/drm/etnaviv/etnaviv_iommu.c index b163bdbcb880..1a7c89a67bea 100644 --- a/drivers/gpu/drm/etnaviv/etnaviv_iommu.c +++ b/drivers/gpu/drm/etnaviv/etnaviv_iommu.c @@ -3,15 +3,14 @@ * Copyright (C) 2014-2018 Etnaviv Project */ +#include +#include #include #include #include -#include -#include #include "etnaviv_gpu.h" #include "etnaviv_mmu.h" -#include "etnaviv_iommu.h" #include "state_hi.xml.h" #define PT_SIZE SZ_2M @@ -19,124 +18,89 @@ #define GPU_MEM_START 0x80000000 -struct etnaviv_iommuv1_domain { - struct etnaviv_iommu_domain base; +struct etnaviv_iommuv1_context { + struct etnaviv_iommu_context base; u32 *pgtable_cpu; dma_addr_t pgtable_dma; }; -static struct etnaviv_iommuv1_domain * -to_etnaviv_domain(struct etnaviv_iommu_domain *domain) +static struct etnaviv_iommuv1_context * +to_v1_context(struct etnaviv_iommu_context *context) { - return container_of(domain, struct etnaviv_iommuv1_domain, base); + return container_of(context, struct etnaviv_iommuv1_context, base); } -static int __etnaviv_iommu_init(struct etnaviv_iommuv1_domain *etnaviv_domain) +static void etnaviv_iommuv1_free(struct etnaviv_iommu_context *context) { - u32 *p; - int i; - - etnaviv_domain->base.bad_page_cpu = - dma_alloc_wc(etnaviv_domain->base.dev, SZ_4K, - &etnaviv_domain->base.bad_page_dma, - GFP_KERNEL); - if (!etnaviv_domain->base.bad_page_cpu) - return -ENOMEM; - - p = etnaviv_domain->base.bad_page_cpu; - for (i = 0; i < SZ_4K / 4; i++) - *p++ = 0xdead55aa; - - etnaviv_domain->pgtable_cpu = dma_alloc_wc(etnaviv_domain->base.dev, - PT_SIZE, - &etnaviv_domain->pgtable_dma, - GFP_KERNEL); - if (!etnaviv_domain->pgtable_cpu) { - dma_free_wc(etnaviv_domain->base.dev, SZ_4K, - etnaviv_domain->base.bad_page_cpu, - etnaviv_domain->base.bad_page_dma); - return -ENOMEM; - } - - memset32(etnaviv_domain->pgtable_cpu, etnaviv_domain->base.bad_page_dma, - PT_ENTRIES); - - return 0; -} + struct etnaviv_iommuv1_context *v1_context = to_v1_context(context); -static void etnaviv_iommuv1_domain_free(struct etnaviv_iommu_domain *domain) -{ - struct etnaviv_iommuv1_domain *etnaviv_domain = - to_etnaviv_domain(domain); + drm_mm_takedown(&context->mm); - dma_free_wc(etnaviv_domain->base.dev, PT_SIZE, - etnaviv_domain->pgtable_cpu, etnaviv_domain->pgtable_dma); + dma_free_wc(context->global->dev, PT_SIZE, v1_context->pgtable_cpu, + v1_context->pgtable_dma); - dma_free_wc(etnaviv_domain->base.dev, SZ_4K, - etnaviv_domain->base.bad_page_cpu, - etnaviv_domain->base.bad_page_dma); + context->global->v1.shared_context = NULL; - kfree(etnaviv_domain); + kfree(v1_context); } -static int etnaviv_iommuv1_map(struct etnaviv_iommu_domain *domain, +static int etnaviv_iommuv1_map(struct etnaviv_iommu_context *context, unsigned long iova, phys_addr_t paddr, size_t size, int prot) { - struct etnaviv_iommuv1_domain *etnaviv_domain = to_etnaviv_domain(domain); + struct etnaviv_iommuv1_context *v1_context = to_v1_context(context); unsigned int index = (iova - GPU_MEM_START) / SZ_4K; if (size != SZ_4K) return -EINVAL; - etnaviv_domain->pgtable_cpu[index] = paddr; + v1_context->pgtable_cpu[index] = paddr; return 0; } -static size_t etnaviv_iommuv1_unmap(struct etnaviv_iommu_domain *domain, +static size_t etnaviv_iommuv1_unmap(struct etnaviv_iommu_context *context, unsigned long iova, size_t size) { - struct etnaviv_iommuv1_domain *etnaviv_domain = - to_etnaviv_domain(domain); + struct etnaviv_iommuv1_context *v1_context = to_v1_context(context); unsigned int index = (iova - GPU_MEM_START) / SZ_4K; if (size != SZ_4K) return -EINVAL; - etnaviv_domain->pgtable_cpu[index] = etnaviv_domain->base.bad_page_dma; + v1_context->pgtable_cpu[index] = context->global->bad_page_dma; return SZ_4K; } -static size_t etnaviv_iommuv1_dump_size(struct etnaviv_iommu_domain *domain) +static size_t etnaviv_iommuv1_dump_size(struct etnaviv_iommu_context *context) { return PT_SIZE; } -static void etnaviv_iommuv1_dump(struct etnaviv_iommu_domain *domain, void *buf) +static void etnaviv_iommuv1_dump(struct etnaviv_iommu_context *context, + void *buf) { - struct etnaviv_iommuv1_domain *etnaviv_domain = - to_etnaviv_domain(domain); + struct etnaviv_iommuv1_context *v1_context = to_v1_context(context); - memcpy(buf, etnaviv_domain->pgtable_cpu, PT_SIZE); + memcpy(buf, v1_context->pgtable_cpu, PT_SIZE); } -void etnaviv_iommuv1_restore(struct etnaviv_gpu *gpu) +static void etnaviv_iommuv1_restore(struct etnaviv_gpu *gpu, + struct etnaviv_iommu_context *context) { - struct etnaviv_iommuv1_domain *etnaviv_domain = - to_etnaviv_domain(gpu->mmu->domain); + struct etnaviv_iommuv1_context *v1_context = to_v1_context(context); u32 pgtable; /* set base addresses */ - gpu_write(gpu, VIVS_MC_MEMORY_BASE_ADDR_RA, gpu->memory_base); - gpu_write(gpu, VIVS_MC_MEMORY_BASE_ADDR_FE, gpu->memory_base); - gpu_write(gpu, VIVS_MC_MEMORY_BASE_ADDR_TX, gpu->memory_base); - gpu_write(gpu, VIVS_MC_MEMORY_BASE_ADDR_PEZ, gpu->memory_base); - gpu_write(gpu, VIVS_MC_MEMORY_BASE_ADDR_PE, gpu->memory_base); + gpu_write(gpu, VIVS_MC_MEMORY_BASE_ADDR_RA, context->global->memory_base); + gpu_write(gpu, VIVS_MC_MEMORY_BASE_ADDR_FE, context->global->memory_base); + gpu_write(gpu, VIVS_MC_MEMORY_BASE_ADDR_TX, context->global->memory_base); + gpu_write(gpu, VIVS_MC_MEMORY_BASE_ADDR_PEZ, context->global->memory_base); + gpu_write(gpu, VIVS_MC_MEMORY_BASE_ADDR_PE, context->global->memory_base); /* set page table address in MC */ - pgtable = (u32)etnaviv_domain->pgtable_dma; + pgtable = (u32)v1_context->pgtable_dma; gpu_write(gpu, VIVS_MC_MMU_FE_PAGE_TABLE, pgtable); gpu_write(gpu, VIVS_MC_MMU_TX_PAGE_TABLE, pgtable); @@ -145,39 +109,64 @@ void etnaviv_iommuv1_restore(struct etnaviv_gpu *gpu) gpu_write(gpu, VIVS_MC_MMU_RA_PAGE_TABLE, pgtable); } -static const struct etnaviv_iommu_domain_ops etnaviv_iommuv1_ops = { - .free = etnaviv_iommuv1_domain_free, + +const struct etnaviv_iommu_ops etnaviv_iommuv1_ops = { + .free = etnaviv_iommuv1_free, .map = etnaviv_iommuv1_map, .unmap = etnaviv_iommuv1_unmap, .dump_size = etnaviv_iommuv1_dump_size, .dump = etnaviv_iommuv1_dump, + .restore = etnaviv_iommuv1_restore, }; -struct etnaviv_iommu_domain * -etnaviv_iommuv1_domain_alloc(struct etnaviv_gpu *gpu) +struct etnaviv_iommu_context * +etnaviv_iommuv1_context_alloc(struct etnaviv_iommu_global *global) { - struct etnaviv_iommuv1_domain *etnaviv_domain; - struct etnaviv_iommu_domain *domain; - int ret; + struct etnaviv_iommuv1_context *v1_context; + struct etnaviv_iommu_context *context; + + mutex_lock(&global->lock); + + /* + * MMUv1 does not support switching between different contexts without + * a stop the world operation, so we only support a single shared + * context with this version. + */ + if (global->v1.shared_context) { + context = global->v1.shared_context; + etnaviv_iommu_context_get(context); + mutex_unlock(&global->lock); + return context; + } - etnaviv_domain = kzalloc(sizeof(*etnaviv_domain), GFP_KERNEL); - if (!etnaviv_domain) + v1_context = kzalloc(sizeof(*v1_context), GFP_KERNEL); + if (!v1_context) { + mutex_unlock(&global->lock); return NULL; + } + + v1_context->pgtable_cpu = dma_alloc_wc(global->dev, PT_SIZE, + &v1_context->pgtable_dma, + GFP_KERNEL); + if (!v1_context->pgtable_cpu) + goto out_free; - domain = &etnaviv_domain->base; + memset32(v1_context->pgtable_cpu, global->bad_page_dma, PT_ENTRIES); - domain->dev = gpu->dev; - domain->base = GPU_MEM_START; - domain->size = PT_ENTRIES * SZ_4K; - domain->ops = &etnaviv_iommuv1_ops; + context = &v1_context->base; + context->global = global; + kref_init(&context->refcount); + mutex_init(&context->lock); + INIT_LIST_HEAD(&context->mappings); + drm_mm_init(&context->mm, GPU_MEM_START, PT_ENTRIES * SZ_4K); + context->global->v1.shared_context = context; - ret = __etnaviv_iommu_init(etnaviv_domain); - if (ret) - goto out_free; + mutex_unlock(&global->lock); - return &etnaviv_domain->base; + return context; out_free: - kfree(etnaviv_domain); + mutex_unlock(&global->lock); + kfree(v1_context); return NULL; }