From 6ae9c84ff249f2756086e71405375fd06124cf1f Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Tue, 15 May 2018 16:09:15 +0200 Subject: [PATCH 1/4] drm/etnaviv: mmuv2: use memset32 to init scratch page Replace the open-coded scratch page initialization loop with memset32 Signed-off-by: Philipp Zabel Signed-off-by: Lucas Stach --- drivers/gpu/drm/etnaviv/etnaviv_iommu_v2.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/etnaviv/etnaviv_iommu_v2.c b/drivers/gpu/drm/etnaviv/etnaviv_iommu_v2.c index 71fbc1f96cb6..f1c88d8ad5ba 100644 --- a/drivers/gpu/drm/etnaviv/etnaviv_iommu_v2.c +++ b/drivers/gpu/drm/etnaviv/etnaviv_iommu_v2.c @@ -119,8 +119,7 @@ static size_t etnaviv_iommuv2_unmap(struct etnaviv_iommu_domain *domain, static int etnaviv_iommuv2_init(struct etnaviv_iommuv2_domain *etnaviv_domain) { - u32 *p; - int ret, i; + int ret; /* allocate scratch page */ etnaviv_domain->base.bad_page_cpu = @@ -131,9 +130,9 @@ static int etnaviv_iommuv2_init(struct etnaviv_iommuv2_domain *etnaviv_domain) ret = -ENOMEM; goto fail_mem; } - p = etnaviv_domain->base.bad_page_cpu; - for (i = 0; i < SZ_4K / 4; i++) - *p++ = 0xdead55aa; + + 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, From a0780bb1df60f00e4573db7bd53e7039e9eee1cb Mon Sep 17 00:00:00 2001 From: Lucas Stach Date: Fri, 25 May 2018 16:51:25 +0200 Subject: [PATCH 2/4] drm/etnaviv: protect sched job submission with fence mutex The documentation of drm_sched_job_init and drm_sched_entity_push_job has been clarified. Both functions should be called under a shared lock, to avoid jobs getting pushed into the scheduler queue in a different order than their sched_fence seqnos, which will confuse checks that are looking at the seqnos to infer information about completion order. Signed-off-by: Lucas Stach --- drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c | 4 ++-- drivers/gpu/drm/etnaviv/etnaviv_gpu.c | 2 +- drivers/gpu/drm/etnaviv/etnaviv_gpu.h | 2 +- drivers/gpu/drm/etnaviv/etnaviv_sched.c | 24 ++++++++++++++------ 4 files changed, 21 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c b/drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c index 46ecd3e66ac9..983e67f19e45 100644 --- a/drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c +++ b/drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c @@ -388,9 +388,9 @@ static void submit_cleanup(struct kref *kref) dma_fence_put(submit->in_fence); if (submit->out_fence) { /* first remove from IDR, so fence can not be found anymore */ - mutex_lock(&submit->gpu->fence_idr_lock); + mutex_lock(&submit->gpu->fence_lock); idr_remove(&submit->gpu->fence_idr, submit->out_fence_id); - mutex_unlock(&submit->gpu->fence_idr_lock); + mutex_unlock(&submit->gpu->fence_lock); dma_fence_put(submit->out_fence); } kfree(submit->pmrs); diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gpu.c b/drivers/gpu/drm/etnaviv/etnaviv_gpu.c index 686f6552db48..18c2224ba0b8 100644 --- a/drivers/gpu/drm/etnaviv/etnaviv_gpu.c +++ b/drivers/gpu/drm/etnaviv/etnaviv_gpu.c @@ -1733,7 +1733,7 @@ static int etnaviv_gpu_platform_probe(struct platform_device *pdev) gpu->dev = &pdev->dev; mutex_init(&gpu->lock); - mutex_init(&gpu->fence_idr_lock); + mutex_init(&gpu->fence_lock); /* Map registers: */ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gpu.h b/drivers/gpu/drm/etnaviv/etnaviv_gpu.h index 90f17ff7888e..9a75a6937268 100644 --- a/drivers/gpu/drm/etnaviv/etnaviv_gpu.h +++ b/drivers/gpu/drm/etnaviv/etnaviv_gpu.h @@ -118,7 +118,7 @@ struct etnaviv_gpu { u32 idle_mask; /* Fencing support */ - struct mutex fence_idr_lock; + struct mutex fence_lock; struct idr fence_idr; u32 next_fence; u32 active_fence; diff --git a/drivers/gpu/drm/etnaviv/etnaviv_sched.c b/drivers/gpu/drm/etnaviv/etnaviv_sched.c index 50d6b88cb7aa..b267d9c4d91c 100644 --- a/drivers/gpu/drm/etnaviv/etnaviv_sched.c +++ b/drivers/gpu/drm/etnaviv/etnaviv_sched.c @@ -140,28 +140,38 @@ static const struct drm_sched_backend_ops etnaviv_sched_ops = { int etnaviv_sched_push_job(struct drm_sched_entity *sched_entity, struct etnaviv_gem_submit *submit) { - int ret; + int ret = 0; + + /* + * Hold the fence lock across the whole operation to avoid jobs being + * pushed out of order with regard to their sched fence seqnos as + * allocated in drm_sched_job_init. + */ + mutex_lock(&submit->gpu->fence_lock); ret = drm_sched_job_init(&submit->sched_job, &submit->gpu->sched, sched_entity, submit->cmdbuf.ctx); if (ret) - return ret; + goto out_unlock; submit->out_fence = dma_fence_get(&submit->sched_job.s_fence->finished); - mutex_lock(&submit->gpu->fence_idr_lock); submit->out_fence_id = idr_alloc_cyclic(&submit->gpu->fence_idr, submit->out_fence, 0, INT_MAX, GFP_KERNEL); - mutex_unlock(&submit->gpu->fence_idr_lock); - if (submit->out_fence_id < 0) - return -ENOMEM; + if (submit->out_fence_id < 0) { + ret = -ENOMEM; + goto out_unlock; + } /* the scheduler holds on to the job now */ kref_get(&submit->refcount); drm_sched_entity_push_job(&submit->sched_job, sched_entity); - return 0; +out_unlock: + mutex_unlock(&submit->gpu->fence_lock); + + return ret; } int etnaviv_sched_init(struct etnaviv_gpu *gpu) From cfad05a24dcb2bf09ba6438e0843c6a0ed90381c Mon Sep 17 00:00:00 2001 From: Souptick Joarder Date: Tue, 29 May 2018 19:17:27 +0530 Subject: [PATCH 3/4] drm/etnaviv: change return type to vm_fault_t Use new return type vm_fault_t for fault handler. For now, this is just documenting that the function returns a VM_FAULT value rather than an errno. Once all instances are converted, vm_fault_t will become a distinct type. Ref- commit 1c8f422059ae ("mm: change return type to vm_fault_t") Previously vm_insert_page() returns err which driver mapped into VM_FAULT_* type. The new function vmf_insert_page() will replace this inefficiency by returning VM_FAULT_* type. vmf_error() is the newly introduce inline function in 4.17-rc6. Signed-off-by: Souptick Joarder Reviewed-by: Matthew Wilcox Signed-off-by: Lucas Stach --- drivers/gpu/drm/etnaviv/etnaviv_drv.h | 3 ++- drivers/gpu/drm/etnaviv/etnaviv_gem.c | 37 +++++++-------------------- 2 files changed, 11 insertions(+), 29 deletions(-) diff --git a/drivers/gpu/drm/etnaviv/etnaviv_drv.h b/drivers/gpu/drm/etnaviv/etnaviv_drv.h index d36c7bbe66db..8d02d1b7dcf5 100644 --- a/drivers/gpu/drm/etnaviv/etnaviv_drv.h +++ b/drivers/gpu/drm/etnaviv/etnaviv_drv.h @@ -18,6 +18,7 @@ #include #include #include +#include #include #include @@ -53,7 +54,7 @@ int etnaviv_ioctl_gem_submit(struct drm_device *dev, void *data, struct drm_file *file); int etnaviv_gem_mmap(struct file *filp, struct vm_area_struct *vma); -int etnaviv_gem_fault(struct vm_fault *vmf); +vm_fault_t etnaviv_gem_fault(struct vm_fault *vmf); int etnaviv_gem_mmap_offset(struct drm_gem_object *obj, u64 *offset); struct sg_table *etnaviv_gem_prime_get_sg_table(struct drm_gem_object *obj); void *etnaviv_gem_prime_vmap(struct drm_gem_object *obj); diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gem.c b/drivers/gpu/drm/etnaviv/etnaviv_gem.c index 209ef1274b80..1fa74226db91 100644 --- a/drivers/gpu/drm/etnaviv/etnaviv_gem.c +++ b/drivers/gpu/drm/etnaviv/etnaviv_gem.c @@ -169,31 +169,30 @@ int etnaviv_gem_mmap(struct file *filp, struct vm_area_struct *vma) return obj->ops->mmap(obj, vma); } -int etnaviv_gem_fault(struct vm_fault *vmf) +vm_fault_t etnaviv_gem_fault(struct vm_fault *vmf) { struct vm_area_struct *vma = vmf->vma; struct drm_gem_object *obj = vma->vm_private_data; struct etnaviv_gem_object *etnaviv_obj = to_etnaviv_bo(obj); struct page **pages, *page; pgoff_t pgoff; - int ret; + int err; /* * Make sure we don't parallel update on a fault, nor move or remove - * something from beneath our feet. Note that vm_insert_page() is + * something from beneath our feet. Note that vmf_insert_page() is * specifically coded to take care of this, so we don't have to. */ - ret = mutex_lock_interruptible(&etnaviv_obj->lock); - if (ret) - goto out; - + err = mutex_lock_interruptible(&etnaviv_obj->lock); + if (err) + return VM_FAULT_NOPAGE; /* make sure we have pages attached now */ pages = etnaviv_gem_get_pages(etnaviv_obj); mutex_unlock(&etnaviv_obj->lock); if (IS_ERR(pages)) { - ret = PTR_ERR(pages); - goto out; + err = PTR_ERR(pages); + return vmf_error(err); } /* We don't use vmf->pgoff since that has the fake offset: */ @@ -204,25 +203,7 @@ int etnaviv_gem_fault(struct vm_fault *vmf) VERB("Inserting %p pfn %lx, pa %lx", (void *)vmf->address, page_to_pfn(page), page_to_pfn(page) << PAGE_SHIFT); - ret = vm_insert_page(vma, vmf->address, page); - -out: - switch (ret) { - case -EAGAIN: - case 0: - case -ERESTARTSYS: - case -EINTR: - case -EBUSY: - /* - * EBUSY is ok: this just means that another thread - * already did the job. - */ - return VM_FAULT_NOPAGE; - case -ENOMEM: - return VM_FAULT_OOM; - default: - return VM_FAULT_SIGBUS; - } + return vmf_insert_page(vma, vmf->address, page); } int etnaviv_gem_mmap_offset(struct drm_gem_object *obj, u64 *offset) From 5b147465532365dc4e2fee8499d6ca1f52dd0d16 Mon Sep 17 00:00:00 2001 From: Lucas Stach Date: Mon, 23 Jul 2018 14:27:23 +0200 Subject: [PATCH 4/4] drm/etnaviv: fix crash in GPU suspend when init failed due to buffer placement When the suballocator was unable to provide a suitable buffer for the MMUv1 linear window, we roll back the GPU initialization. As the GPU is runtime resumed at that point we need to clear the kernel cmdbuf suballoc entry to properly skip any attempt to manipulate the cmdbuf when the GPU gets shut down in the runtime suspend later on. Signed-off-by: Lucas Stach --- drivers/gpu/drm/etnaviv/etnaviv_gpu.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gpu.c b/drivers/gpu/drm/etnaviv/etnaviv_gpu.c index 18c2224ba0b8..ab8dfe7f69d6 100644 --- a/drivers/gpu/drm/etnaviv/etnaviv_gpu.c +++ b/drivers/gpu/drm/etnaviv/etnaviv_gpu.c @@ -799,6 +799,7 @@ int etnaviv_gpu_init(struct etnaviv_gpu *gpu) free_buffer: etnaviv_cmdbuf_free(&gpu->buffer); + gpu->buffer.suballoc = NULL; destroy_iommu: etnaviv_iommu_destroy(gpu->mmu); gpu->mmu = NULL;