Hi, On Fri, Aug 09, 2019 at 02:04:21PM +0200, Lucas Stach wrote: > This reworks the MMU handling to make it possible to have multiple MMU contexts. > A context is basically one instance of GPU page tables. Currently we have one > set of page tables per GPU, which isn't all that clever, as it has the > following two consequences: > > 1. All GPU clients (aka processes) are sharing the same pagetables, which means > there is no isolation between clients, but only between GPU assigned memory > spaces and the rest of the system. Better than nothing, but also not great. > > 2. Clients operating on the same set of buffers with different etnaviv GPU > cores, e.g. a workload using both the 2D and 3D GPU, need to map the used > buffers into the pagetable sets of each used GPU. > > This patch reworks all the MMU handling to introduce the abstraction of the > MMU context. A context can be shared across different GPU cores, as long as > they have compatible MMU implementations, which is the case for all systems > with Vivante GPUs seen in the wild. > > As MMUv1 is not able to change pagetables on the fly, without a > "stop the world" operation, which stops GPU, changes pagetables via CPU > interaction, restarts GPU, the implementation introduces a shared context on > MMUv1, which is returned whenever there is a request for a new context. > > This patch assigns a MMU context to each GPU, so on MMUv2 systems there is > still one set of pagetables per GPU, but due to the shared context MMUv1 > systems see a change in behavior as now a single pagetable set is used > across all GPU cores. > > Signed-off-by: Lucas Stach <l.stach@xxxxxxxxxxxxxx> > Reviewed-by: Philipp Zabel <p.zabel@xxxxxxxxxxxxxx> Reviewed-by: Guido Günther <agx@xxxxxxxxxxx> > --- > v3: > - move ops declaration to header. > - rename gpu struct mmu member to mmu_context for consistency > --- > drivers/gpu/drm/etnaviv/etnaviv_buffer.c | 10 +- > drivers/gpu/drm/etnaviv/etnaviv_cmdbuf.c | 8 +- > drivers/gpu/drm/etnaviv/etnaviv_cmdbuf.h | 6 +- > drivers/gpu/drm/etnaviv/etnaviv_drv.c | 6 +- > drivers/gpu/drm/etnaviv/etnaviv_drv.h | 4 +- > drivers/gpu/drm/etnaviv/etnaviv_dump.c | 12 +- > drivers/gpu/drm/etnaviv/etnaviv_gem.c | 24 +- > drivers/gpu/drm/etnaviv/etnaviv_gem.h | 2 +- > drivers/gpu/drm/etnaviv/etnaviv_gpu.c | 31 ++- > drivers/gpu/drm/etnaviv/etnaviv_gpu.h | 3 +- > drivers/gpu/drm/etnaviv/etnaviv_iommu.c | 151 ++++++------ > drivers/gpu/drm/etnaviv/etnaviv_iommu.h | 20 -- > drivers/gpu/drm/etnaviv/etnaviv_iommu_v2.c | 264 +++++++++------------ > drivers/gpu/drm/etnaviv/etnaviv_mmu.c | 259 ++++++++++++-------- > drivers/gpu/drm/etnaviv/etnaviv_mmu.h | 91 +++++-- > 15 files changed, 461 insertions(+), 430 deletions(-) > delete mode 100644 drivers/gpu/drm/etnaviv/etnaviv_iommu.h > > diff --git a/drivers/gpu/drm/etnaviv/etnaviv_buffer.c b/drivers/gpu/drm/etnaviv/etnaviv_buffer.c > index a3cdb20bfc5f..4324b098689f 100644 > --- a/drivers/gpu/drm/etnaviv/etnaviv_buffer.c > +++ b/drivers/gpu/drm/etnaviv/etnaviv_buffer.c > @@ -207,7 +207,7 @@ u16 etnaviv_buffer_config_mmuv2(struct etnaviv_gpu *gpu, u32 mtlb_addr, u32 safe > return buffer->user_size / 8; > } > > -u16 etnaviv_buffer_config_pta(struct etnaviv_gpu *gpu) > +u16 etnaviv_buffer_config_pta(struct etnaviv_gpu *gpu, unsigned short id) > { > struct etnaviv_cmdbuf *buffer = &gpu->buffer; > > @@ -216,7 +216,7 @@ u16 etnaviv_buffer_config_pta(struct etnaviv_gpu *gpu) > buffer->user_size = 0; > > CMD_LOAD_STATE(buffer, VIVS_MMUv2_PTA_CONFIG, > - VIVS_MMUv2_PTA_CONFIG_INDEX(0)); > + VIVS_MMUv2_PTA_CONFIG_INDEX(id)); > > CMD_END(buffer); > > @@ -315,7 +315,7 @@ void etnaviv_buffer_queue(struct etnaviv_gpu *gpu, u32 exec_state, > u32 return_target, return_dwords; > u32 link_target, link_dwords; > bool switch_context = gpu->exec_state != exec_state; > - unsigned int new_flush_seq = READ_ONCE(gpu->mmu->flush_seq); > + unsigned int new_flush_seq = READ_ONCE(gpu->mmu_context->flush_seq); > bool need_flush = gpu->flush_seq != new_flush_seq; > > lockdep_assert_held(&gpu->lock); > @@ -339,7 +339,7 @@ void etnaviv_buffer_queue(struct etnaviv_gpu *gpu, u32 exec_state, > > /* flush command */ > if (need_flush) { > - if (gpu->mmu->version == ETNAVIV_IOMMU_V1) > + if (gpu->mmu_context->global->version == ETNAVIV_IOMMU_V1) > extra_dwords += 1; > else > extra_dwords += 3; > @@ -353,7 +353,7 @@ void etnaviv_buffer_queue(struct etnaviv_gpu *gpu, u32 exec_state, > > if (need_flush) { > /* Add the MMU flush */ > - if (gpu->mmu->version == ETNAVIV_IOMMU_V1) { > + if (gpu->mmu_context->global->version == ETNAVIV_IOMMU_V1) { > CMD_LOAD_STATE(buffer, VIVS_GL_FLUSH_MMU, > VIVS_GL_FLUSH_MMU_FLUSH_FEMMU | > VIVS_GL_FLUSH_MMU_FLUSH_UNK1 | > diff --git a/drivers/gpu/drm/etnaviv/etnaviv_cmdbuf.c b/drivers/gpu/drm/etnaviv/etnaviv_cmdbuf.c > index b0babc0f7230..f39430ba3593 100644 > --- a/drivers/gpu/drm/etnaviv/etnaviv_cmdbuf.c > +++ b/drivers/gpu/drm/etnaviv/etnaviv_cmdbuf.c > @@ -60,18 +60,18 @@ etnaviv_cmdbuf_suballoc_new(struct device *dev) > } > > int etnaviv_cmdbuf_suballoc_map(struct etnaviv_cmdbuf_suballoc *suballoc, > - struct etnaviv_iommu *mmu, > + struct etnaviv_iommu_context *context, > struct etnaviv_vram_mapping *mapping, > u32 memory_base) > { > - return etnaviv_iommu_get_suballoc_va(mmu, mapping, memory_base, > + return etnaviv_iommu_get_suballoc_va(context, mapping, memory_base, > suballoc->paddr, SUBALLOC_SIZE); > } > > -void etnaviv_cmdbuf_suballoc_unmap(struct etnaviv_iommu *mmu, > +void etnaviv_cmdbuf_suballoc_unmap(struct etnaviv_iommu_context *context, > struct etnaviv_vram_mapping *mapping) > { > - etnaviv_iommu_put_suballoc_va(mmu, mapping); > + etnaviv_iommu_put_suballoc_va(context, mapping); > } > > void etnaviv_cmdbuf_suballoc_destroy(struct etnaviv_cmdbuf_suballoc *suballoc) > diff --git a/drivers/gpu/drm/etnaviv/etnaviv_cmdbuf.h b/drivers/gpu/drm/etnaviv/etnaviv_cmdbuf.h > index a28668e46e26..ad6fd8eb0378 100644 > --- a/drivers/gpu/drm/etnaviv/etnaviv_cmdbuf.h > +++ b/drivers/gpu/drm/etnaviv/etnaviv_cmdbuf.h > @@ -9,7 +9,7 @@ > #include <linux/types.h> > > struct device; > -struct etnaviv_iommu; > +struct etnaviv_iommu_context; > struct etnaviv_vram_mapping; > struct etnaviv_cmdbuf_suballoc; > struct etnaviv_perfmon_request; > @@ -28,10 +28,10 @@ struct etnaviv_cmdbuf_suballoc * > etnaviv_cmdbuf_suballoc_new(struct device *dev); > void etnaviv_cmdbuf_suballoc_destroy(struct etnaviv_cmdbuf_suballoc *suballoc); > int etnaviv_cmdbuf_suballoc_map(struct etnaviv_cmdbuf_suballoc *suballoc, > - struct etnaviv_iommu *mmu, > + struct etnaviv_iommu_context *context, > struct etnaviv_vram_mapping *mapping, > u32 memory_base); > -void etnaviv_cmdbuf_suballoc_unmap(struct etnaviv_iommu *mmu, > +void etnaviv_cmdbuf_suballoc_unmap(struct etnaviv_iommu_context *context, > struct etnaviv_vram_mapping *mapping); > > > diff --git a/drivers/gpu/drm/etnaviv/etnaviv_drv.c b/drivers/gpu/drm/etnaviv/etnaviv_drv.c > index 5fa3aa7bdbc5..eb0c23fe979a 100644 > --- a/drivers/gpu/drm/etnaviv/etnaviv_drv.c > +++ b/drivers/gpu/drm/etnaviv/etnaviv_drv.c > @@ -119,9 +119,9 @@ static int etnaviv_mmu_show(struct etnaviv_gpu *gpu, struct seq_file *m) > > seq_printf(m, "Active Objects (%s):\n", dev_name(gpu->dev)); > > - mutex_lock(&gpu->mmu->lock); > - drm_mm_print(&gpu->mmu->mm, &p); > - mutex_unlock(&gpu->mmu->lock); > + mutex_lock(&gpu->mmu_context->lock); > + drm_mm_print(&gpu->mmu_context->mm, &p); > + mutex_unlock(&gpu->mmu_context->lock); > > return 0; > } > diff --git a/drivers/gpu/drm/etnaviv/etnaviv_drv.h b/drivers/gpu/drm/etnaviv/etnaviv_drv.h > index e052d7db66ae..5f8db08f1c17 100644 > --- a/drivers/gpu/drm/etnaviv/etnaviv_drv.h > +++ b/drivers/gpu/drm/etnaviv/etnaviv_drv.h > @@ -22,6 +22,7 @@ struct etnaviv_gpu; > struct etnaviv_mmu; > struct etnaviv_gem_object; > struct etnaviv_gem_submit; > +struct etnaviv_iommu_global; > > struct etnaviv_file_private { > /* > @@ -37,6 +38,7 @@ struct etnaviv_drm_private { > struct etnaviv_gpu *gpu[ETNA_MAX_PIPES]; > > struct etnaviv_cmdbuf_suballoc *cmdbuf_suballoc; > + struct etnaviv_iommu_global *mmu_global; > > /* list of GEM objects: */ > struct mutex gem_lock; > @@ -69,7 +71,7 @@ int etnaviv_gem_new_userptr(struct drm_device *dev, struct drm_file *file, > uintptr_t ptr, u32 size, u32 flags, u32 *handle); > u16 etnaviv_buffer_init(struct etnaviv_gpu *gpu); > u16 etnaviv_buffer_config_mmuv2(struct etnaviv_gpu *gpu, u32 mtlb_addr, u32 safe_addr); > -u16 etnaviv_buffer_config_pta(struct etnaviv_gpu *gpu); > +u16 etnaviv_buffer_config_pta(struct etnaviv_gpu *gpu, unsigned short id); > void etnaviv_buffer_end(struct etnaviv_gpu *gpu); > void etnaviv_sync_point_queue(struct etnaviv_gpu *gpu, unsigned int event); > void etnaviv_buffer_queue(struct etnaviv_gpu *gpu, u32 exec_state, > diff --git a/drivers/gpu/drm/etnaviv/etnaviv_dump.c b/drivers/gpu/drm/etnaviv/etnaviv_dump.c > index 2ce60baa4ad9..7e6791517693 100644 > --- a/drivers/gpu/drm/etnaviv/etnaviv_dump.c > +++ b/drivers/gpu/drm/etnaviv/etnaviv_dump.c > @@ -93,7 +93,7 @@ static void etnaviv_core_dump_registers(struct core_dump_iterator *iter, > } > > static void etnaviv_core_dump_mmu(struct core_dump_iterator *iter, > - struct etnaviv_iommu *mmu, size_t mmu_size) > + struct etnaviv_iommu_context *mmu, size_t mmu_size) > { > etnaviv_iommu_dump(mmu, iter->data); > > @@ -125,9 +125,9 @@ void etnaviv_core_dump(struct etnaviv_gem_submit *submit) > return; > etnaviv_dump_core = false; > > - mutex_lock(&gpu->mmu->lock); > + mutex_lock(&gpu->mmu_context->lock); > > - mmu_size = etnaviv_iommu_dump_size(gpu->mmu); > + mmu_size = etnaviv_iommu_dump_size(gpu->mmu_context); > > /* We always dump registers, mmu, ring, hanging cmdbuf and end marker */ > n_obj = 5; > @@ -157,7 +157,7 @@ void etnaviv_core_dump(struct etnaviv_gem_submit *submit) > iter.start = __vmalloc(file_size, GFP_KERNEL | __GFP_NOWARN | __GFP_NORETRY, > PAGE_KERNEL); > if (!iter.start) { > - mutex_unlock(&gpu->mmu->lock); > + mutex_unlock(&gpu->mmu_context->lock); > dev_warn(gpu->dev, "failed to allocate devcoredump file\n"); > return; > } > @@ -169,7 +169,7 @@ void etnaviv_core_dump(struct etnaviv_gem_submit *submit) > memset(iter.hdr, 0, iter.data - iter.start); > > etnaviv_core_dump_registers(&iter, gpu); > - etnaviv_core_dump_mmu(&iter, gpu->mmu, mmu_size); > + etnaviv_core_dump_mmu(&iter, gpu->mmu_context, mmu_size); > etnaviv_core_dump_mem(&iter, ETDUMP_BUF_RING, gpu->buffer.vaddr, > gpu->buffer.size, > etnaviv_cmdbuf_get_va(&gpu->buffer, > @@ -221,7 +221,7 @@ void etnaviv_core_dump(struct etnaviv_gem_submit *submit) > obj->base.size); > } > > - mutex_unlock(&gpu->mmu->lock); > + mutex_unlock(&gpu->mmu_context->lock); > > etnaviv_core_dump_header(&iter, ETDUMP_BUF_END, iter.data); > > diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gem.c b/drivers/gpu/drm/etnaviv/etnaviv_gem.c > index e199a6833ff0..0ccc3c4dffc4 100644 > --- a/drivers/gpu/drm/etnaviv/etnaviv_gem.c > +++ b/drivers/gpu/drm/etnaviv/etnaviv_gem.c > @@ -223,12 +223,12 @@ int etnaviv_gem_mmap_offset(struct drm_gem_object *obj, u64 *offset) > > static struct etnaviv_vram_mapping * > etnaviv_gem_get_vram_mapping(struct etnaviv_gem_object *obj, > - struct etnaviv_iommu *mmu) > + struct etnaviv_iommu_context *context) > { > struct etnaviv_vram_mapping *mapping; > > list_for_each_entry(mapping, &obj->vram_list, obj_node) { > - if (mapping->mmu == mmu) > + if (mapping->context == context) > return mapping; > } > > @@ -256,7 +256,7 @@ struct etnaviv_vram_mapping *etnaviv_gem_mapping_get( > int ret = 0; > > mutex_lock(&etnaviv_obj->lock); > - mapping = etnaviv_gem_get_vram_mapping(etnaviv_obj, gpu->mmu); > + mapping = etnaviv_gem_get_vram_mapping(etnaviv_obj, gpu->mmu_context); > if (mapping) { > /* > * Holding the object lock prevents the use count changing > @@ -265,12 +265,12 @@ struct etnaviv_vram_mapping *etnaviv_gem_mapping_get( > * the MMU owns this mapping to close this race. > */ > if (mapping->use == 0) { > - mutex_lock(&gpu->mmu->lock); > - if (mapping->mmu == gpu->mmu) > + mutex_lock(&gpu->mmu_context->lock); > + if (mapping->context == gpu->mmu_context) > mapping->use += 1; > else > mapping = NULL; > - mutex_unlock(&gpu->mmu->lock); > + mutex_unlock(&gpu->mmu_context->lock); > if (mapping) > goto out; > } else { > @@ -303,11 +303,11 @@ struct etnaviv_vram_mapping *etnaviv_gem_mapping_get( > list_del(&mapping->obj_node); > } > > - mapping->mmu = gpu->mmu; > + mapping->context = gpu->mmu_context; > mapping->use = 1; > > - ret = etnaviv_iommu_map_gem(gpu->mmu, etnaviv_obj, gpu->memory_base, > - mapping); > + ret = etnaviv_iommu_map_gem(gpu->mmu_context, etnaviv_obj, > + gpu->memory_base, mapping); > if (ret < 0) > kfree(mapping); > else > @@ -525,12 +525,12 @@ void etnaviv_gem_free_object(struct drm_gem_object *obj) > > list_for_each_entry_safe(mapping, tmp, &etnaviv_obj->vram_list, > obj_node) { > - struct etnaviv_iommu *mmu = mapping->mmu; > + struct etnaviv_iommu_context *context = mapping->context; > > WARN_ON(mapping->use); > > - if (mmu) > - etnaviv_iommu_unmap_gem(mmu, mapping); > + if (context) > + etnaviv_iommu_unmap_gem(context, mapping); > > list_del(&mapping->obj_node); > kfree(mapping); > diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gem.h b/drivers/gpu/drm/etnaviv/etnaviv_gem.h > index d7d8a835f379..5a004d5e4eaa 100644 > --- a/drivers/gpu/drm/etnaviv/etnaviv_gem.h > +++ b/drivers/gpu/drm/etnaviv/etnaviv_gem.h > @@ -25,7 +25,7 @@ struct etnaviv_vram_mapping { > struct list_head scan_node; > struct list_head mmu_node; > struct etnaviv_gem_object *object; > - struct etnaviv_iommu *mmu; > + struct etnaviv_iommu_context *context; > struct drm_mm_node vram_node; > unsigned int use; > u32 iova; > diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gpu.c b/drivers/gpu/drm/etnaviv/etnaviv_gpu.c > index 179bc6c544ca..885ca8f92338 100644 > --- a/drivers/gpu/drm/etnaviv/etnaviv_gpu.c > +++ b/drivers/gpu/drm/etnaviv/etnaviv_gpu.c > @@ -681,7 +681,7 @@ static void etnaviv_gpu_hw_init(struct etnaviv_gpu *gpu) > etnaviv_gpu_setup_pulse_eater(gpu); > > /* setup the MMU */ > - etnaviv_iommu_restore(gpu); > + etnaviv_iommu_restore(gpu, gpu->mmu_context); > > /* Start command processor */ > prefetch = etnaviv_buffer_init(gpu); > @@ -754,14 +754,19 @@ int etnaviv_gpu_init(struct etnaviv_gpu *gpu) > goto fail; > } > > - gpu->mmu = etnaviv_iommu_new(gpu); > - if (IS_ERR(gpu->mmu)) { > - dev_err(gpu->dev, "Failed to instantiate GPU IOMMU\n"); > - ret = PTR_ERR(gpu->mmu); > + ret = etnaviv_iommu_global_init(gpu); > + if (ret) > goto fail; > + > + gpu->mmu_context = etnaviv_iommu_context_init(priv->mmu_global); > + if (IS_ERR(gpu->mmu_context)) { > + dev_err(gpu->dev, "Failed to instantiate GPU IOMMU\n"); > + ret = PTR_ERR(gpu->mmu_context); > + goto iommu_global_fini; > } > > - ret = etnaviv_cmdbuf_suballoc_map(priv->cmdbuf_suballoc, gpu->mmu, > + ret = etnaviv_cmdbuf_suballoc_map(priv->cmdbuf_suballoc, > + gpu->mmu_context, > &gpu->cmdbuf_mapping, > gpu->memory_base); > if (ret) { > @@ -777,7 +782,7 @@ int etnaviv_gpu_init(struct etnaviv_gpu *gpu) > goto unmap_suballoc; > } > > - if (gpu->mmu->version == ETNAVIV_IOMMU_V1 && > + if (!(gpu->identity.minor_features1 & chipMinorFeatures1_MMU_VERSION) && > etnaviv_cmdbuf_get_va(&gpu->buffer, &gpu->cmdbuf_mapping) > 0x80000000) { > ret = -EINVAL; > dev_err(gpu->dev, > @@ -808,9 +813,11 @@ int etnaviv_gpu_init(struct etnaviv_gpu *gpu) > free_buffer: > etnaviv_cmdbuf_free(&gpu->buffer); > unmap_suballoc: > - etnaviv_cmdbuf_suballoc_unmap(gpu->mmu, &gpu->cmdbuf_mapping); > + etnaviv_cmdbuf_suballoc_unmap(gpu->mmu_context, &gpu->cmdbuf_mapping); > destroy_iommu: > - etnaviv_iommu_destroy(gpu->mmu); > + etnaviv_iommu_context_put(gpu->mmu_context); > +iommu_global_fini: > + etnaviv_iommu_global_fini(gpu); > fail: > pm_runtime_mark_last_busy(gpu->dev); > pm_runtime_put_autosuspend(gpu->dev); > @@ -1683,8 +1690,10 @@ static void etnaviv_gpu_unbind(struct device *dev, struct device *master, > > if (gpu->initialized) { > etnaviv_cmdbuf_free(&gpu->buffer); > - etnaviv_cmdbuf_suballoc_unmap(gpu->mmu, &gpu->cmdbuf_mapping); > - etnaviv_iommu_destroy(gpu->mmu); > + etnaviv_cmdbuf_suballoc_unmap(gpu->mmu_context, > + &gpu->cmdbuf_mapping); > + etnaviv_iommu_context_put(gpu->mmu_context); > + etnaviv_iommu_global_fini(gpu); > gpu->initialized = false; > } > > diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gpu.h b/drivers/gpu/drm/etnaviv/etnaviv_gpu.h > index 96380942cd8c..c0bd6018d53b 100644 > --- a/drivers/gpu/drm/etnaviv/etnaviv_gpu.h > +++ b/drivers/gpu/drm/etnaviv/etnaviv_gpu.h > @@ -8,6 +8,7 @@ > > #include "etnaviv_cmdbuf.h" > #include "etnaviv_gem.h" > +#include "etnaviv_mmu.h" > #include "etnaviv_drv.h" > > struct etnaviv_gem_submit; > @@ -136,7 +137,7 @@ struct etnaviv_gpu { > void __iomem *mmio; > int irq; > > - struct etnaviv_iommu *mmu; > + struct etnaviv_iommu_context *mmu_context; > unsigned int flush_seq; > > /* Power Control: */ > diff --git a/drivers/gpu/drm/etnaviv/etnaviv_iommu.c b/drivers/gpu/drm/etnaviv/etnaviv_iommu.c > index 18c627c5cae1..a2f1ff151822 100644 > --- a/drivers/gpu/drm/etnaviv/etnaviv_iommu.c > +++ b/drivers/gpu/drm/etnaviv/etnaviv_iommu.c > @@ -11,7 +11,6 @@ > > #include "etnaviv_gpu.h" > #include "etnaviv_mmu.h" > -#include "etnaviv_iommu.h" > #include "state_hi.xml.h" > > #define PT_SIZE SZ_2M > @@ -19,113 +18,78 @@ > > #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 */ > @@ -136,7 +100,7 @@ void etnaviv_iommuv1_restore(struct etnaviv_gpu *gpu) > gpu_write(gpu, VIVS_MC_MEMORY_BASE_ADDR_PE, gpu->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,62 @@ 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) > return NULL; > > - domain = &etnaviv_domain->base; > + 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->dev = gpu->dev; > - domain->base = GPU_MEM_START; > - domain->size = PT_ENTRIES * SZ_4K; > - domain->ops = &etnaviv_iommuv1_ops; > + memset32(v1_context->pgtable_cpu, global->bad_page_dma, PT_ENTRIES); > > - ret = __etnaviv_iommu_init(etnaviv_domain); > - if (ret) > - goto out_free; > + 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; > + > + mutex_unlock(&global->lock); > > - return &etnaviv_domain->base; > + return context; > > out_free: > - kfree(etnaviv_domain); > + mutex_unlock(&global->lock); > + kfree(v1_context); > return NULL; > } > diff --git a/drivers/gpu/drm/etnaviv/etnaviv_iommu.h b/drivers/gpu/drm/etnaviv/etnaviv_iommu.h > deleted file mode 100644 > index b279404ce91a..000000000000 > --- a/drivers/gpu/drm/etnaviv/etnaviv_iommu.h > +++ /dev/null > @@ -1,20 +0,0 @@ > -/* SPDX-License-Identifier: GPL-2.0 */ > -/* > - * Copyright (C) 2014-2018 Etnaviv Project > - */ > - > -#ifndef __ETNAVIV_IOMMU_H__ > -#define __ETNAVIV_IOMMU_H__ > - > -struct etnaviv_gpu; > -struct etnaviv_iommu_domain; > - > -struct etnaviv_iommu_domain * > -etnaviv_iommuv1_domain_alloc(struct etnaviv_gpu *gpu); > -void etnaviv_iommuv1_restore(struct etnaviv_gpu *gpu); > - > -struct etnaviv_iommu_domain * > -etnaviv_iommuv2_domain_alloc(struct etnaviv_gpu *gpu); > -void etnaviv_iommuv2_restore(struct etnaviv_gpu *gpu); > - > -#endif /* __ETNAVIV_IOMMU_H__ */ > diff --git a/drivers/gpu/drm/etnaviv/etnaviv_iommu_v2.c b/drivers/gpu/drm/etnaviv/etnaviv_iommu_v2.c > index d7cc184da571..5ca2077c148d 100644 > --- a/drivers/gpu/drm/etnaviv/etnaviv_iommu_v2.c > +++ b/drivers/gpu/drm/etnaviv/etnaviv_iommu_v2.c > @@ -13,7 +13,6 @@ > #include "etnaviv_cmdbuf.h" > #include "etnaviv_gpu.h" > #include "etnaviv_mmu.h" > -#include "etnaviv_iommu.h" > #include "state.xml.h" > #include "state_hi.xml.h" > > @@ -28,11 +27,9 @@ > > #define MMUv2_MAX_STLB_ENTRIES 1024 > > -struct etnaviv_iommuv2_domain { > - struct etnaviv_iommu_domain base; > - /* P(age) T(able) A(rray) */ > - u64 *pta_cpu; > - dma_addr_t pta_dma; > +struct etnaviv_iommuv2_context { > + struct etnaviv_iommu_context base; > + unsigned short id; > /* M(aster) TLB aka first level pagetable */ > u32 *mtlb_cpu; > dma_addr_t mtlb_dma; > @@ -41,41 +38,62 @@ struct etnaviv_iommuv2_domain { > dma_addr_t stlb_dma[MMUv2_MAX_STLB_ENTRIES]; > }; > > -static struct etnaviv_iommuv2_domain * > -to_etnaviv_domain(struct etnaviv_iommu_domain *domain) > +static struct etnaviv_iommuv2_context * > +to_v2_context(struct etnaviv_iommu_context *context) > { > - return container_of(domain, struct etnaviv_iommuv2_domain, base); > + return container_of(context, struct etnaviv_iommuv2_context, base); > } > > +static void etnaviv_iommuv2_free(struct etnaviv_iommu_context *context) > +{ > + struct etnaviv_iommuv2_context *v2_context = to_v2_context(context); > + int i; > + > + drm_mm_takedown(&context->mm); > + > + for (i = 0; i < MMUv2_MAX_STLB_ENTRIES; i++) { > + if (v2_context->stlb_cpu[i]) > + dma_free_wc(context->global->dev, SZ_4K, > + v2_context->stlb_cpu[i], > + v2_context->stlb_dma[i]); > + } > + > + dma_free_wc(context->global->dev, SZ_4K, v2_context->mtlb_cpu, > + v2_context->mtlb_dma); > + > + clear_bit(v2_context->id, context->global->v2.pta_alloc); > + > + vfree(v2_context); > +} > static int > -etnaviv_iommuv2_ensure_stlb(struct etnaviv_iommuv2_domain *etnaviv_domain, > +etnaviv_iommuv2_ensure_stlb(struct etnaviv_iommuv2_context *v2_context, > int stlb) > { > - if (etnaviv_domain->stlb_cpu[stlb]) > + if (v2_context->stlb_cpu[stlb]) > return 0; > > - etnaviv_domain->stlb_cpu[stlb] = > - dma_alloc_wc(etnaviv_domain->base.dev, SZ_4K, > - &etnaviv_domain->stlb_dma[stlb], > + v2_context->stlb_cpu[stlb] = > + dma_alloc_wc(v2_context->base.global->dev, SZ_4K, > + &v2_context->stlb_dma[stlb], > GFP_KERNEL); > > - if (!etnaviv_domain->stlb_cpu[stlb]) > + if (!v2_context->stlb_cpu[stlb]) > return -ENOMEM; > > - memset32(etnaviv_domain->stlb_cpu[stlb], MMUv2_PTE_EXCEPTION, > + memset32(v2_context->stlb_cpu[stlb], MMUv2_PTE_EXCEPTION, > SZ_4K / sizeof(u32)); > > - etnaviv_domain->mtlb_cpu[stlb] = etnaviv_domain->stlb_dma[stlb] | > - MMUv2_PTE_PRESENT; > + v2_context->mtlb_cpu[stlb] = > + v2_context->stlb_dma[stlb] | MMUv2_PTE_PRESENT; > + > return 0; > } > > -static int etnaviv_iommuv2_map(struct etnaviv_iommu_domain *domain, > +static int etnaviv_iommuv2_map(struct etnaviv_iommu_context *context, > unsigned long iova, phys_addr_t paddr, > size_t size, int prot) > { > - struct etnaviv_iommuv2_domain *etnaviv_domain = > - to_etnaviv_domain(domain); > + struct etnaviv_iommuv2_context *v2_context = to_v2_context(context); > int mtlb_entry, stlb_entry, ret; > u32 entry = lower_32_bits(paddr) | MMUv2_PTE_PRESENT; > > @@ -91,20 +109,19 @@ static int etnaviv_iommuv2_map(struct etnaviv_iommu_domain *domain, > mtlb_entry = (iova & MMUv2_MTLB_MASK) >> MMUv2_MTLB_SHIFT; > stlb_entry = (iova & MMUv2_STLB_MASK) >> MMUv2_STLB_SHIFT; > > - ret = etnaviv_iommuv2_ensure_stlb(etnaviv_domain, mtlb_entry); > + ret = etnaviv_iommuv2_ensure_stlb(v2_context, mtlb_entry); > if (ret) > return ret; > > - etnaviv_domain->stlb_cpu[mtlb_entry][stlb_entry] = entry; > + v2_context->stlb_cpu[mtlb_entry][stlb_entry] = entry; > > return 0; > } > > -static size_t etnaviv_iommuv2_unmap(struct etnaviv_iommu_domain *domain, > +static size_t etnaviv_iommuv2_unmap(struct etnaviv_iommu_context *context, > unsigned long iova, size_t size) > { > - struct etnaviv_iommuv2_domain *etnaviv_domain = > - to_etnaviv_domain(domain); > + struct etnaviv_iommuv2_context *etnaviv_domain = to_v2_context(context); > int mtlb_entry, stlb_entry; > > if (size != SZ_4K) > @@ -118,118 +135,35 @@ static size_t etnaviv_iommuv2_unmap(struct etnaviv_iommu_domain *domain, > return SZ_4K; > } > > -static int etnaviv_iommuv2_init(struct etnaviv_iommuv2_domain *etnaviv_domain) > -{ > - int ret; > - > - /* allocate scratch page */ > - 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) { > - ret = -ENOMEM; > - goto fail_mem; > - } > - > - memset32(etnaviv_domain->base.bad_page_cpu, 0xdead55aa, > - SZ_4K / sizeof(u32)); > - > - etnaviv_domain->pta_cpu = dma_alloc_wc(etnaviv_domain->base.dev, > - SZ_4K, &etnaviv_domain->pta_dma, > - GFP_KERNEL); > - if (!etnaviv_domain->pta_cpu) { > - ret = -ENOMEM; > - goto fail_mem; > - } > - > - etnaviv_domain->mtlb_cpu = dma_alloc_wc(etnaviv_domain->base.dev, > - SZ_4K, &etnaviv_domain->mtlb_dma, > - GFP_KERNEL); > - if (!etnaviv_domain->mtlb_cpu) { > - ret = -ENOMEM; > - goto fail_mem; > - } > - > - memset32(etnaviv_domain->mtlb_cpu, MMUv2_PTE_EXCEPTION, > - MMUv2_MAX_STLB_ENTRIES); > - > - return 0; > - > -fail_mem: > - if (etnaviv_domain->base.bad_page_cpu) > - dma_free_wc(etnaviv_domain->base.dev, SZ_4K, > - etnaviv_domain->base.bad_page_cpu, > - etnaviv_domain->base.bad_page_dma); > - > - if (etnaviv_domain->pta_cpu) > - dma_free_wc(etnaviv_domain->base.dev, SZ_4K, > - etnaviv_domain->pta_cpu, etnaviv_domain->pta_dma); > - > - if (etnaviv_domain->mtlb_cpu) > - dma_free_wc(etnaviv_domain->base.dev, SZ_4K, > - etnaviv_domain->mtlb_cpu, etnaviv_domain->mtlb_dma); > - > - return ret; > -} > - > -static void etnaviv_iommuv2_domain_free(struct etnaviv_iommu_domain *domain) > -{ > - struct etnaviv_iommuv2_domain *etnaviv_domain = > - to_etnaviv_domain(domain); > - int i; > - > - dma_free_wc(etnaviv_domain->base.dev, SZ_4K, > - etnaviv_domain->base.bad_page_cpu, > - etnaviv_domain->base.bad_page_dma); > - > - dma_free_wc(etnaviv_domain->base.dev, SZ_4K, > - etnaviv_domain->pta_cpu, etnaviv_domain->pta_dma); > - > - dma_free_wc(etnaviv_domain->base.dev, SZ_4K, > - etnaviv_domain->mtlb_cpu, etnaviv_domain->mtlb_dma); > - > - for (i = 0; i < MMUv2_MAX_STLB_ENTRIES; i++) { > - if (etnaviv_domain->stlb_cpu[i]) > - dma_free_wc(etnaviv_domain->base.dev, SZ_4K, > - etnaviv_domain->stlb_cpu[i], > - etnaviv_domain->stlb_dma[i]); > - } > - > - vfree(etnaviv_domain); > -} > - > -static size_t etnaviv_iommuv2_dump_size(struct etnaviv_iommu_domain *domain) > +static size_t etnaviv_iommuv2_dump_size(struct etnaviv_iommu_context *context) > { > - struct etnaviv_iommuv2_domain *etnaviv_domain = > - to_etnaviv_domain(domain); > + struct etnaviv_iommuv2_context *v2_context = to_v2_context(context); > size_t dump_size = SZ_4K; > int i; > > for (i = 0; i < MMUv2_MAX_STLB_ENTRIES; i++) > - if (etnaviv_domain->mtlb_cpu[i] & MMUv2_PTE_PRESENT) > + if (v2_context->mtlb_cpu[i] & MMUv2_PTE_PRESENT) > dump_size += SZ_4K; > > return dump_size; > } > > -static void etnaviv_iommuv2_dump(struct etnaviv_iommu_domain *domain, void *buf) > +static void etnaviv_iommuv2_dump(struct etnaviv_iommu_context *context, void *buf) > { > - struct etnaviv_iommuv2_domain *etnaviv_domain = > - to_etnaviv_domain(domain); > + struct etnaviv_iommuv2_context *v2_context = to_v2_context(context); > int i; > > - memcpy(buf, etnaviv_domain->mtlb_cpu, SZ_4K); > + memcpy(buf, v2_context->mtlb_cpu, SZ_4K); > buf += SZ_4K; > for (i = 0; i < MMUv2_MAX_STLB_ENTRIES; i++, buf += SZ_4K) > - if (etnaviv_domain->mtlb_cpu[i] & MMUv2_PTE_PRESENT) > - memcpy(buf, etnaviv_domain->stlb_cpu[i], SZ_4K); > + if (v2_context->mtlb_cpu[i] & MMUv2_PTE_PRESENT) > + memcpy(buf, v2_context->stlb_cpu[i], SZ_4K); > } > > -static void etnaviv_iommuv2_restore_nonsec(struct etnaviv_gpu *gpu) > +static void etnaviv_iommuv2_restore_nonsec(struct etnaviv_gpu *gpu, > + struct etnaviv_iommu_context *context) > { > - struct etnaviv_iommuv2_domain *etnaviv_domain = > - to_etnaviv_domain(gpu->mmu->domain); > + struct etnaviv_iommuv2_context *v2_context = to_v2_context(context); > u16 prefetch; > > /* If the MMU is already enabled the state is still there. */ > @@ -237,8 +171,8 @@ static void etnaviv_iommuv2_restore_nonsec(struct etnaviv_gpu *gpu) > return; > > prefetch = etnaviv_buffer_config_mmuv2(gpu, > - (u32)etnaviv_domain->mtlb_dma, > - (u32)etnaviv_domain->base.bad_page_dma); > + (u32)v2_context->mtlb_dma, > + (u32)context->global->bad_page_dma); > etnaviv_gpu_start_fe(gpu, (u32)etnaviv_cmdbuf_get_pa(&gpu->buffer), > prefetch); > etnaviv_gpu_wait_idle(gpu, 100); > @@ -246,10 +180,10 @@ static void etnaviv_iommuv2_restore_nonsec(struct etnaviv_gpu *gpu) > gpu_write(gpu, VIVS_MMUv2_CONTROL, VIVS_MMUv2_CONTROL_ENABLE); > } > > -static void etnaviv_iommuv2_restore_sec(struct etnaviv_gpu *gpu) > +static void etnaviv_iommuv2_restore_sec(struct etnaviv_gpu *gpu, > + struct etnaviv_iommu_context *context) > { > - struct etnaviv_iommuv2_domain *etnaviv_domain = > - to_etnaviv_domain(gpu->mmu->domain); > + struct etnaviv_iommuv2_context *v2_context = to_v2_context(context); > u16 prefetch; > > /* If the MMU is already enabled the state is still there. */ > @@ -257,26 +191,26 @@ static void etnaviv_iommuv2_restore_sec(struct etnaviv_gpu *gpu) > return; > > gpu_write(gpu, VIVS_MMUv2_PTA_ADDRESS_LOW, > - lower_32_bits(etnaviv_domain->pta_dma)); > + lower_32_bits(context->global->v2.pta_dma)); > gpu_write(gpu, VIVS_MMUv2_PTA_ADDRESS_HIGH, > - upper_32_bits(etnaviv_domain->pta_dma)); > + upper_32_bits(context->global->v2.pta_dma)); > gpu_write(gpu, VIVS_MMUv2_PTA_CONTROL, VIVS_MMUv2_PTA_CONTROL_ENABLE); > > gpu_write(gpu, VIVS_MMUv2_NONSEC_SAFE_ADDR_LOW, > - lower_32_bits(etnaviv_domain->base.bad_page_dma)); > + lower_32_bits(context->global->bad_page_dma)); > gpu_write(gpu, VIVS_MMUv2_SEC_SAFE_ADDR_LOW, > - lower_32_bits(etnaviv_domain->base.bad_page_dma)); > + lower_32_bits(context->global->bad_page_dma)); > gpu_write(gpu, VIVS_MMUv2_SAFE_ADDRESS_CONFIG, > VIVS_MMUv2_SAFE_ADDRESS_CONFIG_NON_SEC_SAFE_ADDR_HIGH( > - upper_32_bits(etnaviv_domain->base.bad_page_dma)) | > + upper_32_bits(context->global->bad_page_dma)) | > VIVS_MMUv2_SAFE_ADDRESS_CONFIG_SEC_SAFE_ADDR_HIGH( > - upper_32_bits(etnaviv_domain->base.bad_page_dma))); > + upper_32_bits(context->global->bad_page_dma))); > > - etnaviv_domain->pta_cpu[0] = etnaviv_domain->mtlb_dma | > - VIVS_MMUv2_CONFIGURATION_MODE_MODE4_K; > + context->global->v2.pta_cpu[0] = v2_context->mtlb_dma | > + VIVS_MMUv2_CONFIGURATION_MODE_MODE4_K; > > /* trigger a PTA load through the FE */ > - prefetch = etnaviv_buffer_config_pta(gpu); > + prefetch = etnaviv_buffer_config_pta(gpu, v2_context->id); > etnaviv_gpu_start_fe(gpu, (u32)etnaviv_cmdbuf_get_pa(&gpu->buffer), > prefetch); > etnaviv_gpu_wait_idle(gpu, 100); > @@ -284,14 +218,15 @@ static void etnaviv_iommuv2_restore_sec(struct etnaviv_gpu *gpu) > gpu_write(gpu, VIVS_MMUv2_SEC_CONTROL, VIVS_MMUv2_SEC_CONTROL_ENABLE); > } > > -void etnaviv_iommuv2_restore(struct etnaviv_gpu *gpu) > +static void etnaviv_iommuv2_restore(struct etnaviv_gpu *gpu, > + struct etnaviv_iommu_context *context) > { > switch (gpu->sec_mode) { > case ETNA_SEC_NONE: > - etnaviv_iommuv2_restore_nonsec(gpu); > + etnaviv_iommuv2_restore_nonsec(gpu, context); > break; > case ETNA_SEC_KERNEL: > - etnaviv_iommuv2_restore_sec(gpu); > + etnaviv_iommuv2_restore_sec(gpu, context); > break; > default: > WARN(1, "unhandled GPU security mode\n"); > @@ -299,39 +234,56 @@ void etnaviv_iommuv2_restore(struct etnaviv_gpu *gpu) > } > } > > -static const struct etnaviv_iommu_domain_ops etnaviv_iommuv2_ops = { > - .free = etnaviv_iommuv2_domain_free, > +const struct etnaviv_iommu_ops etnaviv_iommuv2_ops = { > + .free = etnaviv_iommuv2_free, > .map = etnaviv_iommuv2_map, > .unmap = etnaviv_iommuv2_unmap, > .dump_size = etnaviv_iommuv2_dump_size, > .dump = etnaviv_iommuv2_dump, > + .restore = etnaviv_iommuv2_restore, > }; > > -struct etnaviv_iommu_domain * > -etnaviv_iommuv2_domain_alloc(struct etnaviv_gpu *gpu) > +struct etnaviv_iommu_context * > +etnaviv_iommuv2_context_alloc(struct etnaviv_iommu_global *global) > { > - struct etnaviv_iommuv2_domain *etnaviv_domain; > - struct etnaviv_iommu_domain *domain; > - int ret; > + struct etnaviv_iommuv2_context *v2_context; > + struct etnaviv_iommu_context *context; > > - etnaviv_domain = vzalloc(sizeof(*etnaviv_domain)); > - if (!etnaviv_domain) > + v2_context = vzalloc(sizeof(*v2_context)); > + if (!v2_context) > return NULL; > > - domain = &etnaviv_domain->base; > + mutex_lock(&global->lock); > + v2_context->id = find_first_zero_bit(global->v2.pta_alloc, > + ETNAVIV_PTA_ENTRIES); > + if (v2_context->id < ETNAVIV_PTA_ENTRIES) { > + set_bit(v2_context->id, global->v2.pta_alloc); > + } else { > + mutex_unlock(&global->lock); > + goto out_free; > + } > + mutex_unlock(&global->lock); > > - domain->dev = gpu->dev; > - domain->base = SZ_4K; > - domain->size = (u64)SZ_1G * 4 - SZ_4K; > - domain->ops = &etnaviv_iommuv2_ops; > + v2_context->mtlb_cpu = dma_alloc_wc(global->dev, SZ_4K, > + &v2_context->mtlb_dma, GFP_KERNEL); > + if (!v2_context->mtlb_cpu) > + goto out_free_id; > > - ret = etnaviv_iommuv2_init(etnaviv_domain); > - if (ret) > - goto out_free; > + memset32(v2_context->mtlb_cpu, MMUv2_PTE_EXCEPTION, > + MMUv2_MAX_STLB_ENTRIES); > + > + context = &v2_context->base; > + context->global = global; > + kref_init(&context->refcount); > + mutex_init(&context->lock); > + INIT_LIST_HEAD(&context->mappings); > + drm_mm_init(&context->mm, SZ_4K, (u64)SZ_1G * 4 - SZ_4K); > > - return &etnaviv_domain->base; > + return context; > > +out_free_id: > + clear_bit(v2_context->id, global->v2.pta_alloc); > out_free: > - vfree(etnaviv_domain); > + vfree(v2_context); > return NULL; > } > diff --git a/drivers/gpu/drm/etnaviv/etnaviv_mmu.c b/drivers/gpu/drm/etnaviv/etnaviv_mmu.c > index bbd1624a3df8..2f64eef773ed 100644 > --- a/drivers/gpu/drm/etnaviv/etnaviv_mmu.c > +++ b/drivers/gpu/drm/etnaviv/etnaviv_mmu.c > @@ -3,6 +3,7 @@ > * Copyright (C) 2015-2018 Etnaviv Project > */ > > +#include <linux/dma-mapping.h> > #include <linux/scatterlist.h> > > #include "common.xml.h" > @@ -10,10 +11,9 @@ > #include "etnaviv_drv.h" > #include "etnaviv_gem.h" > #include "etnaviv_gpu.h" > -#include "etnaviv_iommu.h" > #include "etnaviv_mmu.h" > > -static void etnaviv_domain_unmap(struct etnaviv_iommu_domain *domain, > +static void etnaviv_context_unmap(struct etnaviv_iommu_context *context, > unsigned long iova, size_t size) > { > size_t unmapped_page, unmapped = 0; > @@ -26,7 +26,8 @@ static void etnaviv_domain_unmap(struct etnaviv_iommu_domain *domain, > } > > while (unmapped < size) { > - unmapped_page = domain->ops->unmap(domain, iova, pgsize); > + unmapped_page = context->global->ops->unmap(context, iova, > + pgsize); > if (!unmapped_page) > break; > > @@ -35,7 +36,7 @@ static void etnaviv_domain_unmap(struct etnaviv_iommu_domain *domain, > } > } > > -static int etnaviv_domain_map(struct etnaviv_iommu_domain *domain, > +static int etnaviv_context_map(struct etnaviv_iommu_context *context, > unsigned long iova, phys_addr_t paddr, > size_t size, int prot) > { > @@ -51,7 +52,8 @@ static int etnaviv_domain_map(struct etnaviv_iommu_domain *domain, > } > > while (size) { > - ret = domain->ops->map(domain, iova, paddr, pgsize, prot); > + ret = context->global->ops->map(context, iova, paddr, pgsize, > + prot); > if (ret) > break; > > @@ -62,21 +64,19 @@ static int etnaviv_domain_map(struct etnaviv_iommu_domain *domain, > > /* unroll mapping in case something went wrong */ > if (ret) > - etnaviv_domain_unmap(domain, orig_iova, orig_size - size); > + etnaviv_context_unmap(context, orig_iova, orig_size - size); > > return ret; > } > > -static int etnaviv_iommu_map(struct etnaviv_iommu *iommu, u32 iova, > +static int etnaviv_iommu_map(struct etnaviv_iommu_context *context, u32 iova, > struct sg_table *sgt, unsigned len, int prot) > -{ > - struct etnaviv_iommu_domain *domain = iommu->domain; > - struct scatterlist *sg; > +{ struct scatterlist *sg; > unsigned int da = iova; > unsigned int i, j; > int ret; > > - if (!domain || !sgt) > + if (!context || !sgt) > return -EINVAL; > > for_each_sg(sgt->sgl, sg, sgt->nents, i) { > @@ -85,7 +85,7 @@ static int etnaviv_iommu_map(struct etnaviv_iommu *iommu, u32 iova, > > VERB("map[%d]: %08x %08x(%zx)", i, iova, pa, bytes); > > - ret = etnaviv_domain_map(domain, da, pa, bytes, prot); > + ret = etnaviv_context_map(context, da, pa, bytes, prot); > if (ret) > goto fail; > > @@ -100,16 +100,15 @@ static int etnaviv_iommu_map(struct etnaviv_iommu *iommu, u32 iova, > for_each_sg(sgt->sgl, sg, i, j) { > size_t bytes = sg_dma_len(sg) + sg->offset; > > - etnaviv_domain_unmap(domain, da, bytes); > + etnaviv_context_unmap(context, da, bytes); > da += bytes; > } > return ret; > } > > -static void etnaviv_iommu_unmap(struct etnaviv_iommu *iommu, u32 iova, > +static void etnaviv_iommu_unmap(struct etnaviv_iommu_context *context, u32 iova, > struct sg_table *sgt, unsigned len) > { > - struct etnaviv_iommu_domain *domain = iommu->domain; > struct scatterlist *sg; > unsigned int da = iova; > int i; > @@ -117,7 +116,7 @@ static void etnaviv_iommu_unmap(struct etnaviv_iommu *iommu, u32 iova, > for_each_sg(sgt->sgl, sg, sgt->nents, i) { > size_t bytes = sg_dma_len(sg) + sg->offset; > > - etnaviv_domain_unmap(domain, da, bytes); > + etnaviv_context_unmap(context, da, bytes); > > VERB("unmap[%d]: %08x(%zx)", i, iova, bytes); > > @@ -127,24 +126,24 @@ static void etnaviv_iommu_unmap(struct etnaviv_iommu *iommu, u32 iova, > } > } > > -static void etnaviv_iommu_remove_mapping(struct etnaviv_iommu *mmu, > +static void etnaviv_iommu_remove_mapping(struct etnaviv_iommu_context *context, > struct etnaviv_vram_mapping *mapping) > { > struct etnaviv_gem_object *etnaviv_obj = mapping->object; > > - etnaviv_iommu_unmap(mmu, mapping->vram_node.start, > + etnaviv_iommu_unmap(context, mapping->vram_node.start, > etnaviv_obj->sgt, etnaviv_obj->base.size); > drm_mm_remove_node(&mapping->vram_node); > } > > -static int etnaviv_iommu_find_iova(struct etnaviv_iommu *mmu, > +static int etnaviv_iommu_find_iova(struct etnaviv_iommu_context *context, > struct drm_mm_node *node, size_t size) > { > struct etnaviv_vram_mapping *free = NULL; > enum drm_mm_insert_mode mode = DRM_MM_INSERT_LOW; > int ret; > > - lockdep_assert_held(&mmu->lock); > + lockdep_assert_held(&context->lock); > > while (1) { > struct etnaviv_vram_mapping *m, *n; > @@ -152,17 +151,17 @@ static int etnaviv_iommu_find_iova(struct etnaviv_iommu *mmu, > struct list_head list; > bool found; > > - ret = drm_mm_insert_node_in_range(&mmu->mm, node, > + ret = drm_mm_insert_node_in_range(&context->mm, node, > size, 0, 0, 0, U64_MAX, mode); > if (ret != -ENOSPC) > break; > > /* Try to retire some entries */ > - drm_mm_scan_init(&scan, &mmu->mm, size, 0, 0, mode); > + drm_mm_scan_init(&scan, &context->mm, size, 0, 0, mode); > > found = 0; > INIT_LIST_HEAD(&list); > - list_for_each_entry(free, &mmu->mappings, mmu_node) { > + list_for_each_entry(free, &context->mappings, mmu_node) { > /* If this vram node has not been used, skip this. */ > if (!free->vram_node.mm) > continue; > @@ -204,8 +203,8 @@ static int etnaviv_iommu_find_iova(struct etnaviv_iommu *mmu, > * this mapping. > */ > list_for_each_entry_safe(m, n, &list, scan_node) { > - etnaviv_iommu_remove_mapping(mmu, m); > - m->mmu = NULL; > + etnaviv_iommu_remove_mapping(context, m); > + m->context = NULL; > list_del_init(&m->mmu_node); > list_del_init(&m->scan_node); > } > @@ -221,7 +220,7 @@ static int etnaviv_iommu_find_iova(struct etnaviv_iommu *mmu, > return ret; > } > > -int etnaviv_iommu_map_gem(struct etnaviv_iommu *mmu, > +int etnaviv_iommu_map_gem(struct etnaviv_iommu_context *context, > struct etnaviv_gem_object *etnaviv_obj, u32 memory_base, > struct etnaviv_vram_mapping *mapping) > { > @@ -231,17 +230,17 @@ int etnaviv_iommu_map_gem(struct etnaviv_iommu *mmu, > > lockdep_assert_held(&etnaviv_obj->lock); > > - mutex_lock(&mmu->lock); > + mutex_lock(&context->lock); > > /* v1 MMU can optimize single entry (contiguous) scatterlists */ > - if (mmu->version == ETNAVIV_IOMMU_V1 && > + if (context->global->version == ETNAVIV_IOMMU_V1 && > sgt->nents == 1 && !(etnaviv_obj->flags & ETNA_BO_FORCE_MMU)) { > u32 iova; > > iova = sg_dma_address(sgt->sgl) - memory_base; > if (iova < 0x80000000 - sg_dma_len(sgt->sgl)) { > mapping->iova = iova; > - list_add_tail(&mapping->mmu_node, &mmu->mappings); > + list_add_tail(&mapping->mmu_node, &context->mappings); > ret = 0; > goto unlock; > } > @@ -249,12 +248,12 @@ int etnaviv_iommu_map_gem(struct etnaviv_iommu *mmu, > > node = &mapping->vram_node; > > - ret = etnaviv_iommu_find_iova(mmu, node, etnaviv_obj->base.size); > + ret = etnaviv_iommu_find_iova(context, node, etnaviv_obj->base.size); > if (ret < 0) > goto unlock; > > mapping->iova = node->start; > - ret = etnaviv_iommu_map(mmu, node->start, sgt, etnaviv_obj->base.size, > + ret = etnaviv_iommu_map(context, node->start, sgt, etnaviv_obj->base.size, > ETNAVIV_PROT_READ | ETNAVIV_PROT_WRITE); > > if (ret < 0) { > @@ -262,84 +261,63 @@ int etnaviv_iommu_map_gem(struct etnaviv_iommu *mmu, > goto unlock; > } > > - list_add_tail(&mapping->mmu_node, &mmu->mappings); > - mmu->flush_seq++; > + list_add_tail(&mapping->mmu_node, &context->mappings); > + context->flush_seq++; > unlock: > - mutex_unlock(&mmu->lock); > + mutex_unlock(&context->lock); > > return ret; > } > > -void etnaviv_iommu_unmap_gem(struct etnaviv_iommu *mmu, > +void etnaviv_iommu_unmap_gem(struct etnaviv_iommu_context *context, > struct etnaviv_vram_mapping *mapping) > { > WARN_ON(mapping->use); > > - mutex_lock(&mmu->lock); > + mutex_lock(&context->lock); > > /* If the vram node is on the mm, unmap and remove the node */ > - if (mapping->vram_node.mm == &mmu->mm) > - etnaviv_iommu_remove_mapping(mmu, mapping); > + if (mapping->vram_node.mm == &context->mm) > + etnaviv_iommu_remove_mapping(context, mapping); > > list_del(&mapping->mmu_node); > - mmu->flush_seq++; > - mutex_unlock(&mmu->lock); > + context->flush_seq++; > + mutex_unlock(&context->lock); > } > > -void etnaviv_iommu_destroy(struct etnaviv_iommu *mmu) > +static void etnaviv_iommu_context_free(struct kref *kref) > { > - drm_mm_takedown(&mmu->mm); > - mmu->domain->ops->free(mmu->domain); > - kfree(mmu); > -} > + struct etnaviv_iommu_context *context = > + container_of(kref, struct etnaviv_iommu_context, refcount); > > -struct etnaviv_iommu *etnaviv_iommu_new(struct etnaviv_gpu *gpu) > + context->global->ops->free(context); > +} > +void etnaviv_iommu_context_put(struct etnaviv_iommu_context *context) > { > - enum etnaviv_iommu_version version; > - struct etnaviv_iommu *mmu; > - > - mmu = kzalloc(sizeof(*mmu), GFP_KERNEL); > - if (!mmu) > - return ERR_PTR(-ENOMEM); > - > - if (!(gpu->identity.minor_features1 & chipMinorFeatures1_MMU_VERSION)) { > - mmu->domain = etnaviv_iommuv1_domain_alloc(gpu); > - version = ETNAVIV_IOMMU_V1; > - } else { > - mmu->domain = etnaviv_iommuv2_domain_alloc(gpu); > - version = ETNAVIV_IOMMU_V2; > - } > - > - if (!mmu->domain) { > - dev_err(gpu->dev, "Failed to allocate GPU IOMMU domain\n"); > - kfree(mmu); > - return ERR_PTR(-ENOMEM); > - } > - > - mmu->gpu = gpu; > - mmu->version = version; > - mutex_init(&mmu->lock); > - INIT_LIST_HEAD(&mmu->mappings); > - > - drm_mm_init(&mmu->mm, mmu->domain->base, mmu->domain->size); > - > - return mmu; > + kref_put(&context->refcount, etnaviv_iommu_context_free); > } > > -void etnaviv_iommu_restore(struct etnaviv_gpu *gpu) > +struct etnaviv_iommu_context * > +etnaviv_iommu_context_init(struct etnaviv_iommu_global *global) > { > - if (gpu->mmu->version == ETNAVIV_IOMMU_V1) > - etnaviv_iommuv1_restore(gpu); > + if (global->version == ETNAVIV_IOMMU_V1) > + return etnaviv_iommuv1_context_alloc(global); > else > - etnaviv_iommuv2_restore(gpu); > + return etnaviv_iommuv2_context_alloc(global); > +} > + > +void etnaviv_iommu_restore(struct etnaviv_gpu *gpu, > + struct etnaviv_iommu_context *context) > +{ > + context->global->ops->restore(gpu, context); > } > > -int etnaviv_iommu_get_suballoc_va(struct etnaviv_iommu *mmu, > +int etnaviv_iommu_get_suballoc_va(struct etnaviv_iommu_context *context, > struct etnaviv_vram_mapping *mapping, > u32 memory_base, dma_addr_t paddr, > size_t size) > { > - mutex_lock(&mmu->lock); > + mutex_lock(&context->lock); > > /* > * For MMUv1 we don't add the suballoc region to the pagetables, as > @@ -347,40 +325,40 @@ int etnaviv_iommu_get_suballoc_va(struct etnaviv_iommu *mmu, > * window. Instead we manufacture a mapping to make it look uniform > * to the upper layers. > */ > - if (mmu->version == ETNAVIV_IOMMU_V1) { > + if (context->global->version == ETNAVIV_IOMMU_V1) { > mapping->iova = paddr - memory_base; > } else { > struct drm_mm_node *node = &mapping->vram_node; > int ret; > > - ret = etnaviv_iommu_find_iova(mmu, node, size); > + ret = etnaviv_iommu_find_iova(context, node, size); > if (ret < 0) { > - mutex_unlock(&mmu->lock); > + mutex_unlock(&context->lock); > return ret; > } > > mapping->iova = node->start; > - ret = etnaviv_domain_map(mmu->domain, node->start, paddr, size, > - ETNAVIV_PROT_READ); > + ret = etnaviv_context_map(context, node->start, paddr, size, > + ETNAVIV_PROT_READ); > > if (ret < 0) { > drm_mm_remove_node(node); > - mutex_unlock(&mmu->lock); > + mutex_unlock(&context->lock); > return ret; > } > > - mmu->flush_seq++; > + context->flush_seq++; > } > > - list_add_tail(&mapping->mmu_node, &mmu->mappings); > + list_add_tail(&mapping->mmu_node, &context->mappings); > mapping->use = 1; > > - mutex_unlock(&mmu->lock); > + mutex_unlock(&context->lock); > > return 0; > } > > -void etnaviv_iommu_put_suballoc_va(struct etnaviv_iommu *mmu, > +void etnaviv_iommu_put_suballoc_va(struct etnaviv_iommu_context *context, > struct etnaviv_vram_mapping *mapping) > { > struct drm_mm_node *node = &mapping->vram_node; > @@ -390,21 +368,104 @@ void etnaviv_iommu_put_suballoc_va(struct etnaviv_iommu *mmu, > > mapping->use = 0; > > - if (mmu->version == ETNAVIV_IOMMU_V1) > + if (context->global->version == ETNAVIV_IOMMU_V1) > return; > > - mutex_lock(&mmu->lock); > - etnaviv_domain_unmap(mmu->domain, node->start, node->size); > + mutex_lock(&context->lock); > + etnaviv_context_unmap(context, node->start, node->size); > drm_mm_remove_node(node); > - mutex_unlock(&mmu->lock); > + mutex_unlock(&context->lock); > +} > + > +size_t etnaviv_iommu_dump_size(struct etnaviv_iommu_context *context) > +{ > + return context->global->ops->dump_size(context); > +} > + > +void etnaviv_iommu_dump(struct etnaviv_iommu_context *context, void *buf) > +{ > + context->global->ops->dump(context, buf); > } > > -size_t etnaviv_iommu_dump_size(struct etnaviv_iommu *iommu) > +int etnaviv_iommu_global_init(struct etnaviv_gpu *gpu) > { > - return iommu->domain->ops->dump_size(iommu->domain); > + enum etnaviv_iommu_version version = ETNAVIV_IOMMU_V1; > + struct etnaviv_drm_private *priv = gpu->drm->dev_private; > + struct etnaviv_iommu_global *global; > + struct device *dev = gpu->drm->dev; > + > + if (gpu->identity.minor_features1 & chipMinorFeatures1_MMU_VERSION) > + version = ETNAVIV_IOMMU_V2; > + > + if (priv->mmu_global) { > + if (priv->mmu_global->version != version) { > + dev_err(gpu->dev, > + "MMU version doesn't match global version\n"); > + return -ENXIO; > + } > + > + priv->mmu_global->use++; > + return 0; > + } > + > + global = kzalloc(sizeof(*global), GFP_KERNEL); > + if (!global) > + return -ENOMEM; > + > + global->bad_page_cpu = dma_alloc_wc(dev, SZ_4K, &global->bad_page_dma, > + GFP_KERNEL); > + if (!global->bad_page_cpu) > + goto free_global; > + > + memset32(global->bad_page_cpu, 0xdead55aa, SZ_4K / sizeof(u32)); > + > + if (version == ETNAVIV_IOMMU_V2) { > + global->v2.pta_cpu = dma_alloc_wc(dev, ETNAVIV_PTA_SIZE, > + &global->v2.pta_dma, GFP_KERNEL); > + if (!global->v2.pta_cpu) > + goto free_bad_page; > + } > + > + global->dev = dev; > + global->version = version; > + global->use = 1; > + mutex_init(&global->lock); > + > + if (version == ETNAVIV_IOMMU_V1) > + global->ops = &etnaviv_iommuv1_ops; > + else > + global->ops = &etnaviv_iommuv2_ops; > + > + priv->mmu_global = global; > + > + return 0; > + > +free_bad_page: > + dma_free_wc(dev, SZ_4K, global->bad_page_cpu, global->bad_page_dma); > +free_global: > + kfree(global); > + > + return -ENOMEM; > } > > -void etnaviv_iommu_dump(struct etnaviv_iommu *iommu, void *buf) > +void etnaviv_iommu_global_fini(struct etnaviv_gpu *gpu) > { > - iommu->domain->ops->dump(iommu->domain, buf); > + struct etnaviv_drm_private *priv = gpu->drm->dev_private; > + struct etnaviv_iommu_global *global = priv->mmu_global; > + > + if (--global->use > 0) > + return; > + > + if (global->v2.pta_cpu) > + dma_free_wc(global->dev, ETNAVIV_PTA_SIZE, > + global->v2.pta_cpu, global->v2.pta_dma); > + > + if (global->bad_page_cpu) > + dma_free_wc(global->dev, SZ_4K, > + global->bad_page_cpu, global->bad_page_dma); > + > + mutex_destroy(&global->lock); > + kfree(global); > + > + priv->mmu_global = NULL; > } > diff --git a/drivers/gpu/drm/etnaviv/etnaviv_mmu.h b/drivers/gpu/drm/etnaviv/etnaviv_mmu.h > index 34afe25df9ca..4438d66db6ab 100644 > --- a/drivers/gpu/drm/etnaviv/etnaviv_mmu.h > +++ b/drivers/gpu/drm/etnaviv/etnaviv_mmu.h > @@ -16,33 +16,58 @@ enum etnaviv_iommu_version { > > struct etnaviv_gpu; > struct etnaviv_vram_mapping; > -struct etnaviv_iommu_domain; > +struct etnaviv_iommu_global; > +struct etnaviv_iommu_context; > > -struct etnaviv_iommu_domain_ops { > - void (*free)(struct etnaviv_iommu_domain *); > - int (*map)(struct etnaviv_iommu_domain *domain, unsigned long iova, > +struct etnaviv_iommu_ops { > + struct etnaviv_iommu_context *(*init)(struct etnaviv_iommu_global *); > + void (*free)(struct etnaviv_iommu_context *); > + int (*map)(struct etnaviv_iommu_context *context, unsigned long iova, > phys_addr_t paddr, size_t size, int prot); > - size_t (*unmap)(struct etnaviv_iommu_domain *domain, unsigned long iova, > + size_t (*unmap)(struct etnaviv_iommu_context *context, unsigned long iova, > size_t size); > - size_t (*dump_size)(struct etnaviv_iommu_domain *); > - void (*dump)(struct etnaviv_iommu_domain *, void *); > + size_t (*dump_size)(struct etnaviv_iommu_context *); > + void (*dump)(struct etnaviv_iommu_context *, void *); > + void (*restore)(struct etnaviv_gpu *, struct etnaviv_iommu_context *); > }; > > -struct etnaviv_iommu_domain { > +extern const struct etnaviv_iommu_ops etnaviv_iommuv1_ops; > +extern const struct etnaviv_iommu_ops etnaviv_iommuv2_ops; > + > +#define ETNAVIV_PTA_SIZE SZ_4K > +#define ETNAVIV_PTA_ENTRIES (ETNAVIV_PTA_SIZE / sizeof(u64)) > + > +struct etnaviv_iommu_global { > struct device *dev; > + enum etnaviv_iommu_version version; > + const struct etnaviv_iommu_ops *ops; > + unsigned int use; > + struct mutex lock; > + > void *bad_page_cpu; > dma_addr_t bad_page_dma; > - u64 base; > - u64 size; > > - const struct etnaviv_iommu_domain_ops *ops; > + /* > + * This union holds members needed by either MMUv1 or MMUv2, which > + * can not exist at the same time. > + */ > + union { > + struct { > + struct etnaviv_iommu_context *shared_context; > + } v1; > + struct { > + /* P(age) T(able) A(rray) */ > + u64 *pta_cpu; > + dma_addr_t pta_dma; > + struct spinlock pta_lock; > + DECLARE_BITMAP(pta_alloc, ETNAVIV_PTA_ENTRIES); > + } v2; > + }; > }; > > -struct etnaviv_iommu { > - struct etnaviv_gpu *gpu; > - struct etnaviv_iommu_domain *domain; > - > - enum etnaviv_iommu_version version; > +struct etnaviv_iommu_context { > + struct kref refcount; > + struct etnaviv_iommu_global *global; > > /* memory manager for GPU address area */ > struct mutex lock; > @@ -51,26 +76,40 @@ struct etnaviv_iommu { > unsigned int flush_seq; > }; > > +int etnaviv_iommu_global_init(struct etnaviv_gpu *gpu); > +void etnaviv_iommu_global_fini(struct etnaviv_gpu *gpu); > + > struct etnaviv_gem_object; > > -int etnaviv_iommu_map_gem(struct etnaviv_iommu *mmu, > +int etnaviv_iommu_map_gem(struct etnaviv_iommu_context *context, > struct etnaviv_gem_object *etnaviv_obj, u32 memory_base, > struct etnaviv_vram_mapping *mapping); > -void etnaviv_iommu_unmap_gem(struct etnaviv_iommu *mmu, > +void etnaviv_iommu_unmap_gem(struct etnaviv_iommu_context *context, > struct etnaviv_vram_mapping *mapping); > > -int etnaviv_iommu_get_suballoc_va(struct etnaviv_iommu *mmu, > +int etnaviv_iommu_get_suballoc_va(struct etnaviv_iommu_context *ctx, > struct etnaviv_vram_mapping *mapping, > u32 memory_base, dma_addr_t paddr, > size_t size); > -void etnaviv_iommu_put_suballoc_va(struct etnaviv_iommu *mmu, > +void etnaviv_iommu_put_suballoc_va(struct etnaviv_iommu_context *ctx, > struct etnaviv_vram_mapping *mapping); > > -size_t etnaviv_iommu_dump_size(struct etnaviv_iommu *iommu); > -void etnaviv_iommu_dump(struct etnaviv_iommu *iommu, void *buf); > - > -struct etnaviv_iommu *etnaviv_iommu_new(struct etnaviv_gpu *gpu); > -void etnaviv_iommu_destroy(struct etnaviv_iommu *iommu); > -void etnaviv_iommu_restore(struct etnaviv_gpu *gpu); > +size_t etnaviv_iommu_dump_size(struct etnaviv_iommu_context *ctx); > +void etnaviv_iommu_dump(struct etnaviv_iommu_context *ctx, void *buf); > + > +struct etnaviv_iommu_context * > +etnaviv_iommu_context_init(struct etnaviv_iommu_global *global); > +static inline void etnaviv_iommu_context_get(struct etnaviv_iommu_context *ctx) > +{ > + kref_get(&ctx->refcount); > +} > +void etnaviv_iommu_context_put(struct etnaviv_iommu_context *ctx); > +void etnaviv_iommu_restore(struct etnaviv_gpu *gpu, > + struct etnaviv_iommu_context *ctx); > + > +struct etnaviv_iommu_context * > +etnaviv_iommuv1_context_alloc(struct etnaviv_iommu_global *global); > +struct etnaviv_iommu_context * > +etnaviv_iommuv2_context_alloc(struct etnaviv_iommu_global *global); > > #endif /* __ETNAVIV_MMU_H__ */ > -- > 2.20.1 > > _______________________________________________ > etnaviv mailing list > etnaviv@xxxxxxxxxxxxxxxxxxxxx > https://lists.freedesktop.org/mailman/listinfo/etnaviv _______________________________________________ dri-devel mailing list dri-devel@xxxxxxxxxxxxxxxxxxxxx https://lists.freedesktop.org/mailman/listinfo/dri-devel