diff options
| -rw-r--r-- | drivers/gpu/msm/kgsl.c | 35 | ||||
| -rw-r--r-- | drivers/gpu/msm/kgsl.h | 5 | ||||
| -rw-r--r-- | drivers/gpu/msm/kgsl_iommu.c | 10 | ||||
| -rw-r--r-- | drivers/gpu/msm/kgsl_mmu.c | 10 | ||||
| -rw-r--r-- | drivers/gpu/msm/kgsl_sharedmem.c | 1 | ||||
| -rw-r--r-- | drivers/gpu/msm/kgsl_sharedmem.h | 3 |
6 files changed, 57 insertions, 7 deletions
diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c index 1f6e562bad67..a9b6e24728c7 100644 --- a/drivers/gpu/msm/kgsl.c +++ b/drivers/gpu/msm/kgsl.c @@ -2428,6 +2428,8 @@ long kgsl_ioctl_gpuobj_import(struct kgsl_device_private *dev_priv, if (entry == NULL) return -ENOMEM; + spin_lock_init(&entry->memdesc.lock); + param->flags &= KGSL_MEMFLAGS_GPUREADONLY | KGSL_MEMTYPE_MASK | KGSL_MEMALIGN_MASK @@ -2701,6 +2703,8 @@ long kgsl_ioctl_map_user_mem(struct kgsl_device_private *dev_priv, if (entry == NULL) return -ENOMEM; + spin_lock_init(&entry->memdesc.lock); + /* * Convert from enum value to KGSL_MEM_ENTRY value, so that * we can use the latter consistently everywhere. @@ -3481,6 +3485,8 @@ long kgsl_ioctl_sparse_virt_alloc(struct kgsl_device_private *dev_priv, if (entry == NULL) return -ENOMEM; + spin_lock_init(&entry->memdesc.lock); + entry->memdesc.flags = KGSL_MEMFLAGS_SPARSE_VIRT; entry->memdesc.size = param->size; entry->memdesc.cur_bindings = 0; @@ -4334,19 +4340,34 @@ static unsigned long _gpu_set_svm_region(struct kgsl_process_private *private, { int ret; + /* + * Protect access to the gpuaddr here to prevent multiple vmas from + * trying to map a SVM region at the same time + */ + spin_lock(&entry->memdesc.lock); + + if (entry->memdesc.gpuaddr) { + spin_unlock(&entry->memdesc.lock); + return (unsigned long) -EBUSY; + } + ret = kgsl_mmu_set_svm_region(private->pagetable, (uint64_t) addr, (uint64_t) size); - if (ret != 0) - return ret; + if (ret != 0) { + spin_unlock(&entry->memdesc.lock); + return (unsigned long) ret; + } entry->memdesc.gpuaddr = (uint64_t) addr; + spin_unlock(&entry->memdesc.lock); + entry->memdesc.pagetable = private->pagetable; ret = kgsl_mmu_map(private->pagetable, &entry->memdesc); if (ret) { kgsl_mmu_put_gpuaddr(&entry->memdesc); - return ret; + return (unsigned long) ret; } kgsl_memfree_purge(private->pagetable, entry->memdesc.gpuaddr, @@ -4409,6 +4430,14 @@ static unsigned long _search_range(struct kgsl_process_private *private, result = _gpu_set_svm_region(private, entry, cpu, len); if (!IS_ERR_VALUE(result)) break; + /* + * _gpu_set_svm_region will return -EBUSY if we tried to set up + * SVM on an object that already has a GPU address. If + * that happens don't bother walking the rest of the + * region + */ + if ((long) result == -EBUSY) + return -EBUSY; trace_kgsl_mem_unmapped_area_collision(entry, cpu, len); diff --git a/drivers/gpu/msm/kgsl.h b/drivers/gpu/msm/kgsl.h index 6e6edf67064d..31257d291c7e 100644 --- a/drivers/gpu/msm/kgsl.h +++ b/drivers/gpu/msm/kgsl.h @@ -226,6 +226,11 @@ struct kgsl_memdesc { struct page **pages; unsigned int page_count; unsigned int cur_bindings; + /* + * @lock: Spinlock to protect the gpuaddr from being accessed by + * multiple entities trying to map the same SVM region at once + */ + spinlock_t lock; }; /* diff --git a/drivers/gpu/msm/kgsl_iommu.c b/drivers/gpu/msm/kgsl_iommu.c index f6ff4658c93b..7d7e44893842 100644 --- a/drivers/gpu/msm/kgsl_iommu.c +++ b/drivers/gpu/msm/kgsl_iommu.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2011-2020, The Linux Foundation. All rights reserved. +/* Copyright (c) 2011-2021, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -270,6 +270,7 @@ static void kgsl_setup_qdss_desc(struct kgsl_device *device) return; } + spin_lock_init(&gpu_qdss_desc.lock); gpu_qdss_desc.flags = 0; gpu_qdss_desc.priv = 0; gpu_qdss_desc.physaddr = gpu_qdss_entry[0]; @@ -315,6 +316,7 @@ static void kgsl_setup_qtimer_desc(struct kgsl_device *device) return; } + spin_lock_init(&gpu_qtimer_desc.lock); gpu_qtimer_desc.flags = 0; gpu_qtimer_desc.priv = 0; gpu_qtimer_desc.physaddr = gpu_qtimer_entry[0]; @@ -1499,6 +1501,7 @@ static int _setstate_alloc(struct kgsl_device *device, { int ret; + spin_lock_init(&iommu->setstate.lock); ret = kgsl_sharedmem_alloc_contig(device, &iommu->setstate, PAGE_SIZE); if (!ret) { @@ -2477,6 +2480,11 @@ static int kgsl_iommu_get_gpuaddr(struct kgsl_pagetable *pagetable, goto out; } + /* + * This path is only called in a non-SVM path with locks so we can be + * sure we aren't racing with anybody so we don't need to worry about + * taking the lock + */ ret = _insert_gpuaddr(pagetable, addr, size); if (ret == 0) { memdesc->gpuaddr = addr; diff --git a/drivers/gpu/msm/kgsl_mmu.c b/drivers/gpu/msm/kgsl_mmu.c index aa7157e882ac..2303e8ee0721 100644 --- a/drivers/gpu/msm/kgsl_mmu.c +++ b/drivers/gpu/msm/kgsl_mmu.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2002,2007-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2002,2007-2017,2021, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -443,10 +443,16 @@ void kgsl_mmu_put_gpuaddr(struct kgsl_memdesc *memdesc) if (PT_OP_VALID(pagetable, put_gpuaddr) && (unmap_fail == 0)) pagetable->pt_ops->put_gpuaddr(memdesc); + memdesc->pagetable = NULL; + + /* + * If SVM tries to take a GPU address it will lose the race until the + * gpuaddr returns to zero so we shouldn't need to worry about taking a + * lock here + */ if (!kgsl_memdesc_is_global(memdesc)) memdesc->gpuaddr = 0; - memdesc->pagetable = NULL; } EXPORT_SYMBOL(kgsl_mmu_put_gpuaddr); diff --git a/drivers/gpu/msm/kgsl_sharedmem.c b/drivers/gpu/msm/kgsl_sharedmem.c index c343d90e564c..97e4f8b6fe2d 100644 --- a/drivers/gpu/msm/kgsl_sharedmem.c +++ b/drivers/gpu/msm/kgsl_sharedmem.c @@ -342,6 +342,7 @@ int kgsl_allocate_user(struct kgsl_device *device, int ret; memdesc->flags = flags; + spin_lock_init(&memdesc->lock); if (kgsl_mmu_get_mmutype(device) == KGSL_MMU_TYPE_NONE) ret = kgsl_sharedmem_alloc_contig(device, memdesc, size); diff --git a/drivers/gpu/msm/kgsl_sharedmem.h b/drivers/gpu/msm/kgsl_sharedmem.h index e5da594b77b8..ee89cfb808d7 100644 --- a/drivers/gpu/msm/kgsl_sharedmem.h +++ b/drivers/gpu/msm/kgsl_sharedmem.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2002,2007-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2002,2007-2017,2021, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -283,6 +283,7 @@ static inline int kgsl_allocate_global(struct kgsl_device *device, memdesc->flags = flags; memdesc->priv = priv; + spin_lock_init(&memdesc->lock); if (((memdesc->priv & KGSL_MEMDESC_CONTIG) != 0) || (kgsl_mmu_get_mmutype(device) == KGSL_MMU_TYPE_NONE)) |
