Skip to content

Commit

Permalink
Merge branch android-msm-sunfish-4.14-android11-qpr2
Browse files Browse the repository at this point in the history
sync 548ba76 May 2021.1

Signed-off-by: engstk <[email protected]>
  • Loading branch information
engstk committed May 4, 2021
1 parent 6ca2c7a commit 6c2a017
Show file tree
Hide file tree
Showing 8 changed files with 149 additions and 63 deletions.
7 changes: 6 additions & 1 deletion drivers/char/adsprpc.c
Original file line number Diff line number Diff line change
Expand Up @@ -2713,8 +2713,13 @@ static int fastrpc_internal_munmap(struct fastrpc_file *fl,
mutex_unlock(&fl->map_mutex);
if (err)
goto bail;
VERIFY(err, map != NULL);
if (err) {
err = -EINVAL;
goto bail;
}
VERIFY(err, !fastrpc_munmap_on_dsp(fl, map->raddr,
map->phys, map->size, map->flags));
map->phys, map->size, map->flags));
if (err)
goto bail;
mutex_lock(&fl->map_mutex);
Expand Down
114 changes: 78 additions & 36 deletions drivers/gpu/msm/kgsl.c
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/* Copyright (c) 2008-2020, The Linux Foundation. All rights reserved.
/* Copyright (c) 2008-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
Expand Down Expand Up @@ -282,6 +282,7 @@ kgsl_mem_entry_create(void)
kref_get(&entry->refcount);
}

atomic_set(&entry->map_count, 0);
return entry;
}

Expand Down Expand Up @@ -533,9 +534,6 @@ static void kgsl_mem_entry_detach_process(struct kgsl_mem_entry *entry)
idr_remove(&entry->priv->mem_idr, entry->id);
entry->id = 0;

atomic64_sub(atomic64_read(&entry->memdesc.mapsize),
&entry->priv->gpumem_mapped);

spin_unlock(&entry->priv->mem_lock);

kgsl_mmu_put_gpuaddr(&entry->memdesc);
Expand Down Expand Up @@ -1044,17 +1042,24 @@ static struct kgsl_process_private *kgsl_process_private_new(
list_for_each_entry(private, &kgsl_driver.process_list, list) {
if (private->pid == cur_pid) {
if (!kgsl_process_private_get(private)) {
put_pid(cur_pid);
private = ERR_PTR(-EINVAL);
}
/*
* We need to hold only one reference to the PID for
* each process struct to avoid overflowing the
* reference counter which can lead to use-after-free.
*/
put_pid(cur_pid);
return private;
}
}

/* Create a new object */
private = kzalloc(sizeof(struct kgsl_process_private), GFP_KERNEL);
if (private == NULL)
if (private == NULL) {
put_pid(cur_pid);
return ERR_PTR(-ENOMEM);
}

kref_init(&private->refcount);

Expand Down Expand Up @@ -2338,7 +2343,7 @@ static int check_vma(unsigned long hostptr, u64 size)
return true;
}

static int memdesc_sg_virt(struct kgsl_memdesc *memdesc)
static int memdesc_sg_virt(struct kgsl_memdesc *memdesc, unsigned long useraddr)
{
int ret = 0;
long npages = 0, i;
Expand All @@ -2361,13 +2366,13 @@ static int memdesc_sg_virt(struct kgsl_memdesc *memdesc)
}

down_read(&current->mm->mmap_sem);
if (!check_vma(memdesc->useraddr, memdesc->size)) {
if (!check_vma(useraddr, memdesc->size)) {
up_read(&current->mm->mmap_sem);
ret = -EFAULT;
goto out;
}

npages = get_user_pages(memdesc->useraddr, sglen, write, pages, NULL);
npages = get_user_pages(useraddr, sglen, write, pages, NULL);
up_read(&current->mm->mmap_sem);

ret = (npages < 0) ? (int)npages : 0;
Expand Down Expand Up @@ -2398,30 +2403,34 @@ static int kgsl_setup_anon_useraddr(struct kgsl_pagetable *pagetable,
size_t offset, size_t size)
{
/* Map an anonymous memory chunk */
int ret;

if (size == 0 || offset != 0 ||
!IS_ALIGNED(size, PAGE_SIZE))
return -EINVAL;

entry->memdesc.pagetable = pagetable;
entry->memdesc.size = (uint64_t) size;
entry->memdesc.useraddr = hostptr;
entry->memdesc.flags |= (uint64_t)KGSL_MEMFLAGS_USERMEM_ADDR;

if (kgsl_memdesc_use_cpu_map(&entry->memdesc)) {
int ret;

/* Register the address in the database */
ret = kgsl_mmu_set_svm_region(pagetable,
(uint64_t) entry->memdesc.useraddr, (uint64_t) size);
(uint64_t) hostptr, (uint64_t) size);

if (ret)
return ret;

entry->memdesc.gpuaddr = (uint64_t) entry->memdesc.useraddr;
entry->memdesc.gpuaddr = (uint64_t) hostptr;
}

return memdesc_sg_virt(&entry->memdesc);
ret = memdesc_sg_virt(&entry->memdesc, hostptr);

if (ret && kgsl_memdesc_use_cpu_map(&entry->memdesc))
kgsl_mmu_put_gpuaddr(&entry->memdesc);

return ret;
}

#ifdef CONFIG_DMA_SHARED_BUFFER
Expand Down Expand Up @@ -2506,8 +2515,7 @@ static int kgsl_setup_dmabuf_useraddr(struct kgsl_device *device,
return ret;
}

/* Setup the user addr/cache mode for cache operations */
entry->memdesc.useraddr = hostptr;
/* Setup the cache mode for cache operations */
_setup_cache_mode(entry, vma);
up_read(&current->mm->mmap_sem);
return 0;
Expand Down Expand Up @@ -3535,7 +3543,12 @@ long kgsl_ioctl_gpumem_get_info(struct kgsl_device_private *dev_priv,
param->flags = (unsigned int) entry->memdesc.flags;
param->size = (size_t) entry->memdesc.size;
param->mmapsize = (size_t) kgsl_memdesc_footprint(&entry->memdesc);
param->useraddr = entry->memdesc.useraddr;
/*
* Entries can have multiple user mappings so thre isn't any one address
* we can report. Plus, the user should already know their mappings, so
* there isn't any value in reporting it back to them.
*/
param->useraddr = 0;

kgsl_mem_entry_put(entry);
return result;
Expand Down Expand Up @@ -4008,9 +4021,6 @@ static int _sparse_bind(struct kgsl_process_private *process,
if (memdesc->gpuaddr)
return -EINVAL;

if (memdesc->useraddr != 0)
return -EINVAL;

pagetable = memdesc->pagetable;

/* Clear out any mappings */
Expand Down Expand Up @@ -4291,7 +4301,12 @@ long kgsl_ioctl_gpuobj_info(struct kgsl_device_private *dev_priv,
param->flags = entry->memdesc.flags;
param->size = entry->memdesc.size;
param->va_len = kgsl_memdesc_footprint(&entry->memdesc);
param->va_addr = (uint64_t) entry->memdesc.useraddr;
/*
* Entries can have multiple user mappings so thre isn't any one address
* we can report. Plus, the user should already know their mappings, so
* there isn't any value in reporting it back to them.
*/
param->va_addr = 0;

kgsl_mem_entry_put(entry);
return 0;
Expand Down Expand Up @@ -4398,24 +4413,21 @@ static void kgsl_gpumem_vm_open(struct vm_area_struct *vma)

if (kgsl_mem_entry_get(entry) == 0)
vma->vm_private_data = NULL;

atomic_inc(&entry->map_count);
}

static int
kgsl_gpumem_vm_fault(struct vm_fault *vmf)
{
struct kgsl_mem_entry *entry = vmf->vma->vm_private_data;
int ret;

if (!entry)
return VM_FAULT_SIGBUS;
if (!entry->memdesc.ops || !entry->memdesc.ops->vmfault)
return VM_FAULT_SIGBUS;

ret = entry->memdesc.ops->vmfault(&entry->memdesc, vmf->vma, vmf);
if ((ret == 0) || (ret == VM_FAULT_NOPAGE))
atomic64_add(PAGE_SIZE, &entry->priv->gpumem_mapped);

return ret;
return entry->memdesc.ops->vmfault(&entry->memdesc, vmf->vma, vmf);
}

static void
Expand All @@ -4426,7 +4438,13 @@ kgsl_gpumem_vm_close(struct vm_area_struct *vma)
if (!entry)
return;

entry->memdesc.useraddr = 0;
/*
* Remove the memdesc from the mapped stat once all the mappings have
* gone away
*/
if (!atomic_dec_return(&entry->map_count))
atomic64_sub(entry->memdesc.size, &entry->priv->gpumem_mapped);

kgsl_mem_entry_put(entry);
}

Expand Down Expand Up @@ -4465,7 +4483,8 @@ get_mmap_entry(struct kgsl_process_private *private,
}
}

if (entry->memdesc.useraddr != 0) {
/* Don't allow ourselves to remap user memory */
if (entry->memdesc.flags & KGSL_MEMFLAGS_USERMEM_ADDR) {
ret = -EBUSY;
goto err_put;
}
Expand Down Expand Up @@ -4498,19 +4517,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,
Expand Down Expand Up @@ -4574,6 +4608,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);

Expand Down Expand Up @@ -4795,15 +4837,15 @@ static int kgsl_mmap(struct file *file, struct vm_area_struct *vma)
vm_insert_page(vma, addr, page);
addr += PAGE_SIZE;
}
atomic64_add(m->size, &m->mapsize);
atomic64_add(m->size, &entry->priv->gpumem_mapped);
}

vma->vm_file = file;

entry->memdesc.useraddr = vma->vm_start;
if (atomic_inc_return(&entry->map_count) == 1)
atomic64_add(entry->memdesc.size,
&entry->priv->gpumem_mapped);

trace_kgsl_mem_mmap(entry);
trace_kgsl_mem_mmap(entry, vma->vm_start);
return 0;
}

Expand Down
16 changes: 11 additions & 5 deletions drivers/gpu/msm/kgsl.h
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/* Copyright (c) 2008-2020, The Linux Foundation. All rights reserved.
/* Copyright (c) 2008-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
Expand Down Expand Up @@ -202,11 +202,9 @@ struct kgsl_memdesc_ops {
* @pagetable: Pointer to the pagetable that the object is mapped in
* @hostptr: Kernel virtual address
* @hostptr_count: Number of threads using hostptr
* @useraddr: User virtual address (if applicable)
* @gpuaddr: GPU virtual address
* @physaddr: Physical address of the memory object
* @size: Size of the memory object
* @mapsize: Size of memory mapped in userspace
* @pad_to: Size that we pad the memdesc to
* @priv: Internal flags and settings
* @sgt: Scatter gather table for allocated pages
Expand All @@ -222,11 +220,9 @@ struct kgsl_memdesc {
struct kgsl_pagetable *pagetable;
void *hostptr;
unsigned int hostptr_count;
unsigned long useraddr;
uint64_t gpuaddr;
phys_addr_t physaddr;
uint64_t size;
atomic64_t mapsize;
uint64_t pad_to;
unsigned int priv;
struct sg_table *sgt;
Expand All @@ -237,6 +233,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;
};

/*
Expand Down Expand Up @@ -285,6 +286,11 @@ struct kgsl_mem_entry {
struct work_struct work;
spinlock_t bind_lock;
struct rb_root bind_tree;
/**
* @map_count: Count how many vmas this object is mapped in - used for
* debugfs accounting
*/
atomic_t map_count;
};

struct kgsl_device_private;
Expand Down
Loading

0 comments on commit 6c2a017

Please sign in to comment.