summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJordan Crouse <jcrouse@codeaurora.org>2020-12-31 13:55:39 +0530
committerTiwari, Shubham <shubtiwa@codeaurora.org>2021-03-15 02:38:42 -0700
commit854ef3ce73f55f3ce1a193322796f155cb40717b (patch)
treee45ddcefc5e9ce0cbca2222349728d7e13a35301
parent79c8161aeac99344506e989af2ca92b13e0d0676 (diff)
msm: kgsl: Protect the memdesc->gpuaddr in SVM use cases.
When SVM is being used there can only be one GPU address assigned to the memory descriptor. Don't allow the GPU address to be changed after it has been negotiated the first time by a process. Change-Id: Ic0dedbad2a1b3ccdc2c1598a6c501b2be288d64e Signed-off-by: Jordan Crouse <jcrouse@codeaurora.org> Signed-off-by: Harshitha Sai Neelati <hsaine@codeaurora.org> Signed-off-by: Kamal Agrawal <kamaagra@codeaurora.org>
-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))