diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c index 863782a430bcf8a63c1c7f421ffddf0c5348f51f..67d264431dc1bde89f0941696b7a859f9511e440 100644 --- a/drivers/gpu/msm/kgsl.c +++ b/drivers/gpu/msm/kgsl.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2014, The Linux Foundation. All rights reserved. +/* Copyright (c) 2008-2016, 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 @@ -254,18 +254,13 @@ kgsl_mem_entry_destroy(struct kref *kref) EXPORT_SYMBOL(kgsl_mem_entry_destroy); /** - * kgsl_mem_entry_track_gpuaddr - Insert a mem_entry in the address tree and - * assign it with a gpu address space before insertion + * kgsl_mem_entry_track_gpuaddr - Get the entry gpu address space before + * insertion to the process * @process: the process that owns the memory * @entry: the memory entry * - * @returns - 0 on succcess else error code + * @returns - 0 on success else error code * - * Insert the kgsl_mem_entry in to the rb_tree for searching by GPU address. - * The assignment of gpu address and insertion into list needs to - * happen with the memory lock held to avoid race conditions between - * gpu address being selected and some other thread looking through the - * rb list in search of memory based on gpuaddr * This function should be called with processes memory spinlock held */ static int @@ -273,8 +268,6 @@ kgsl_mem_entry_track_gpuaddr(struct kgsl_process_private *process, struct kgsl_mem_entry *entry) { int ret = 0; - struct rb_node **node; - struct rb_node *parent = NULL; struct kgsl_pagetable *pagetable = process->pagetable; size_t size = entry->memdesc.size; @@ -295,11 +288,22 @@ kgsl_mem_entry_track_gpuaddr(struct kgsl_process_private *process, goto done; } ret = kgsl_mmu_get_gpuaddr(pagetable, &entry->memdesc); - if (ret) - goto done; - node = &process->mem_rb.rb_node; +done: + return ret; +} +static void kgsl_mem_entry_commit_mem_list(struct kgsl_process_private *process, + struct kgsl_mem_entry *entry) +{ + struct rb_node **node; + struct rb_node *parent = NULL; + + if (!entry->memdesc.gpuaddr) + return; + + /* Insert mem entry in mem_rb tree */ + node = &process->mem_rb.rb_node; while (*node) { struct kgsl_mem_entry *cur; @@ -314,9 +318,20 @@ kgsl_mem_entry_track_gpuaddr(struct kgsl_process_private *process, rb_link_node(&entry->node, parent, node); rb_insert_color(&entry->node, &process->mem_rb); +} -done: - return ret; +static void kgsl_mem_entry_commit_process(struct kgsl_process_private *process, + struct kgsl_mem_entry *entry) +{ + if (!entry) + return; + + spin_lock(&entry->priv->mem_lock); + /* Insert mem entry in mem_rb tree */ + kgsl_mem_entry_commit_mem_list(process, entry); + /* Replace mem entry in mem_idr using id */ + idr_replace(&entry->priv->mem_idr, entry, entry->id); + spin_unlock(&entry->priv->mem_lock); } /** @@ -364,7 +379,8 @@ kgsl_mem_entry_attach_process(struct kgsl_mem_entry *entry, return -EBADF; idr_preload(GFP_KERNEL); spin_lock(&process->mem_lock); - id = idr_alloc(&process->mem_idr, entry, 1, 0, GFP_NOWAIT); + /* Allocate the ID but don't attach the pointer just yet */ + id = idr_alloc(&process->mem_idr, NULL, 1, 0, GFP_NOWAIT); spin_unlock(&process->mem_lock); idr_preload_end(); @@ -2994,6 +3010,7 @@ long kgsl_ioctl_map_user_mem(struct kgsl_device_private *dev_priv, trace_kgsl_mem_map(entry, param->fd); + kgsl_mem_entry_commit_process(private, entry); return result; error_attach: @@ -3316,6 +3333,8 @@ long kgsl_ioctl_gpumem_alloc(struct kgsl_device_private *dev_priv, param->gpuaddr = entry->memdesc.gpuaddr; param->size = entry->memdesc.size; param->flags = entry->memdesc.flags; + + kgsl_mem_entry_commit_process(private, entry); return result; err: kgsl_sharedmem_free(&entry->memdesc); @@ -3353,6 +3372,8 @@ long kgsl_ioctl_gpumem_alloc_id(struct kgsl_device_private *dev_priv, param->size = entry->memdesc.size; param->mmapsize = kgsl_memdesc_mmapsize(&entry->memdesc); param->gpuaddr = entry->memdesc.gpuaddr; + + kgsl_mem_entry_commit_process(private, entry); return result; err: if (entry) @@ -3871,6 +3892,11 @@ static int kgsl_check_gpu_addr_collision( spin_lock(&private->mem_lock); kgsl_mem_entry_untrack_gpuaddr(private, entry); spin_unlock(&private->mem_lock); + } else { + /* Insert mem entry in mem_rb tree */ + spin_lock(&private->mem_lock); + kgsl_mem_entry_commit_mem_list(private, entry); + spin_unlock(&private->mem_lock); } } else { trace_kgsl_mem_unmapped_area_collision(entry, addr, len,