summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/gpu/msm/kgsl.c35
-rw-r--r--drivers/gpu/msm/kgsl.h5
-rw-r--r--drivers/gpu/msm/kgsl_iommu.c10
-rw-r--r--drivers/gpu/msm/kgsl_mmu.c10
-rw-r--r--drivers/gpu/msm/kgsl_sharedmem.c1
-rw-r--r--drivers/gpu/msm/kgsl_sharedmem.h3
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))