summaryrefslogtreecommitdiff
path: root/drivers/gpu/msm
diff options
context:
space:
mode:
authorJordan Crouse <jcrouse@codeaurora.org>2020-12-31 13:55:39 +0530
committerGerrit - the friendly Code Review server <code-review@localhost>2021-01-07 02:28:10 -0800
commit727c4c8471c6aee218bbdd62aa07d743112b487e (patch)
tree07acb8f782a1238b31de7d4a04b817f8ee5d1193 /drivers/gpu/msm
parent9e5dc94f80da0643d5c44327e0473d5c10aecc92 (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>
Diffstat (limited to 'drivers/gpu/msm')
-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 da379ddcfbfa..43ec8d8ff88b 100644
--- a/drivers/gpu/msm/kgsl.c
+++ b/drivers/gpu/msm/kgsl.c
@@ -2441,6 +2441,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
@@ -2714,6 +2716,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.
@@ -3494,6 +3498,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;
@@ -4347,19 +4353,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,
@@ -4422,6 +4443,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 aff54105474a..08f5c6d9d50b 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 0f5e7a0ebc29..dfbea53c306b 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))