summaryrefslogtreecommitdiffstats
path: root/drivers/gpu/nvgpu/gk20a/mm_gk20a.c
diff options
context:
space:
mode:
authorKonsta Holtta <kholtta@nvidia.com>2016-09-08 07:42:44 -0400
committermobile promotions <svcmobile_promotions@nvidia.com>2016-09-14 16:03:44 -0400
commit93d31990197897471e291d83361d9d57769cd6f2 (patch)
treeffea2b1cdcebfbdabb7b54a758c98a12c08fb2ec /drivers/gpu/nvgpu/gk20a/mm_gk20a.c
parent54e22a2bae2ad7df5fae7a8af873ef3977436705 (diff)
gpu: nvgpu: test free user vidmem atomically
An empty list of soon-to-be-freed userspace vidmem buffers is not enough to safely assume that an allocation may succeed or not if tried again, because removal from the list and actually marking the memory freed is not atomic. Fix this by using an atomic counter for the number of pending frees (so that it's still safe to first remove from the job list and then perform the free), and making allocation attempts combined with a test of pending frees atomic. This still does not guarantee that there is memory available (as the actual amount of pending memory in bytes plus the current free amount isn't computed), but removes the race that produces false negatives in case a single program expects repeated frees and allocs to succeed. Bug 1809939 Change-Id: I6a92da2e21cbf3f886b727000c924d56f35ce55b Signed-off-by: Konsta Holtta <kholtta@nvidia.com> Reviewed-on: http://git-master/r/1217078 (cherry picked from commit 83c1f1e70dccd92fdd4481132cf5b6717760d432) Reviewed-on: http://git-master/r/1220545 Reviewed-by: Automatic_Commit_Validation_User GVS: Gerrit_Virtual_Submit Reviewed-by: Terje Bergstrom <tbergstrom@nvidia.com> Tested-by: Terje Bergstrom <tbergstrom@nvidia.com>
Diffstat (limited to 'drivers/gpu/nvgpu/gk20a/mm_gk20a.c')
-rw-r--r--drivers/gpu/nvgpu/gk20a/mm_gk20a.c32
1 files changed, 19 insertions, 13 deletions
diff --git a/drivers/gpu/nvgpu/gk20a/mm_gk20a.c b/drivers/gpu/nvgpu/gk20a/mm_gk20a.c
index c9f2a840..d66e46b8 100644
--- a/drivers/gpu/nvgpu/gk20a/mm_gk20a.c
+++ b/drivers/gpu/nvgpu/gk20a/mm_gk20a.c
@@ -902,7 +902,8 @@ static int gk20a_init_vidmem(struct mm_gk20a *mm)
902 mm->vidmem.bootstrap_base = bootstrap_base; 902 mm->vidmem.bootstrap_base = bootstrap_base;
903 mm->vidmem.bootstrap_size = bootstrap_size; 903 mm->vidmem.bootstrap_size = bootstrap_size;
904 904
905 INIT_WORK(&mm->vidmem_clear_mem_worker, gk20a_vidmem_clear_mem_worker); 905 INIT_WORK(&mm->vidmem.clear_mem_worker, gk20a_vidmem_clear_mem_worker);
906 atomic_set(&mm->vidmem.clears_pending, 0);
906 INIT_LIST_HEAD(&mm->vidmem.clear_list_head); 907 INIT_LIST_HEAD(&mm->vidmem.clear_list_head);
907 mutex_init(&mm->vidmem.clear_list_mutex); 908 mutex_init(&mm->vidmem.clear_list_mutex);
908 909
@@ -2982,10 +2983,10 @@ int gk20a_gmmu_alloc_attr_vid_at(struct gk20a *g, enum dma_attr attr,
2982#if defined(CONFIG_GK20A_VIDMEM) 2983#if defined(CONFIG_GK20A_VIDMEM)
2983 u64 addr; 2984 u64 addr;
2984 int err; 2985 int err;
2985 bool clear_list_empty;
2986 struct gk20a_allocator *vidmem_alloc = g->mm.vidmem.cleared ? 2986 struct gk20a_allocator *vidmem_alloc = g->mm.vidmem.cleared ?
2987 &g->mm.vidmem.allocator : 2987 &g->mm.vidmem.allocator :
2988 &g->mm.vidmem.bootstrap_allocator; 2988 &g->mm.vidmem.bootstrap_allocator;
2989 int before_pending;
2989 2990
2990 gk20a_dbg_fn(""); 2991 gk20a_dbg_fn("");
2991 2992
@@ -2996,16 +2997,19 @@ int gk20a_gmmu_alloc_attr_vid_at(struct gk20a *g, enum dma_attr attr,
2996 * are not done anyway */ 2997 * are not done anyway */
2997 WARN_ON(attr != 0 && attr != DMA_ATTR_NO_KERNEL_MAPPING); 2998 WARN_ON(attr != 0 && attr != DMA_ATTR_NO_KERNEL_MAPPING);
2998 2999
3000 mutex_lock(&g->mm.vidmem.clear_list_mutex);
3001 before_pending = atomic_read(&g->mm.vidmem.clears_pending);
2999 addr = __gk20a_gmmu_alloc(vidmem_alloc, at, size); 3002 addr = __gk20a_gmmu_alloc(vidmem_alloc, at, size);
3003 mutex_unlock(&g->mm.vidmem.clear_list_mutex);
3000 if (!addr) { 3004 if (!addr) {
3001 mutex_lock(&g->mm.vidmem.clear_list_mutex); 3005 /*
3002 clear_list_empty = list_empty(&g->mm.vidmem.clear_list_head); 3006 * If memory is known to be freed soon, let the user know that
3003 mutex_unlock(&g->mm.vidmem.clear_list_mutex); 3007 * it may be available after a while.
3004 3008 */
3005 if (clear_list_empty) 3009 if (before_pending)
3006 return -ENOMEM;
3007 else
3008 return -EAGAIN; 3010 return -EAGAIN;
3011 else
3012 return -ENOMEM;
3009 } 3013 }
3010 3014
3011 if (at) 3015 if (at)
@@ -3057,11 +3061,12 @@ static void gk20a_gmmu_free_attr_vid(struct gk20a *g, enum dma_attr attr,
3057 was_empty = list_empty(&g->mm.vidmem.clear_list_head); 3061 was_empty = list_empty(&g->mm.vidmem.clear_list_head);
3058 list_add_tail(&mem->clear_list_entry, 3062 list_add_tail(&mem->clear_list_entry,
3059 &g->mm.vidmem.clear_list_head); 3063 &g->mm.vidmem.clear_list_head);
3064 atomic_inc(&g->mm.vidmem.clears_pending);
3060 mutex_unlock(&g->mm.vidmem.clear_list_mutex); 3065 mutex_unlock(&g->mm.vidmem.clear_list_mutex);
3061 3066
3062 if (was_empty) { 3067 if (was_empty) {
3063 cancel_work_sync(&g->mm.vidmem_clear_mem_worker); 3068 cancel_work_sync(&g->mm.vidmem.clear_mem_worker);
3064 schedule_work(&g->mm.vidmem_clear_mem_worker); 3069 schedule_work(&g->mm.vidmem.clear_mem_worker);
3065 } 3070 }
3066 } else { 3071 } else {
3067 gk20a_memset(g, mem, 0, 0, mem->size); 3072 gk20a_memset(g, mem, 0, 0, mem->size);
@@ -3136,7 +3141,7 @@ static struct mem_desc *get_pending_mem_desc(struct mm_gk20a *mm)
3136static void gk20a_vidmem_clear_mem_worker(struct work_struct *work) 3141static void gk20a_vidmem_clear_mem_worker(struct work_struct *work)
3137{ 3142{
3138 struct mm_gk20a *mm = container_of(work, struct mm_gk20a, 3143 struct mm_gk20a *mm = container_of(work, struct mm_gk20a,
3139 vidmem_clear_mem_worker); 3144 vidmem.clear_mem_worker);
3140 struct gk20a *g = mm->g; 3145 struct gk20a *g = mm->g;
3141 struct mem_desc *mem; 3146 struct mem_desc *mem;
3142 3147
@@ -3146,6 +3151,7 @@ static void gk20a_vidmem_clear_mem_worker(struct work_struct *work)
3146 sg_dma_address(mem->sgt->sgl)); 3151 sg_dma_address(mem->sgt->sgl));
3147 gk20a_free_sgtable(&mem->sgt); 3152 gk20a_free_sgtable(&mem->sgt);
3148 3153
3154 WARN_ON(atomic_dec_return(&mm->vidmem.clears_pending) < 0);
3149 mem->size = 0; 3155 mem->size = 0;
3150 mem->aperture = APERTURE_INVALID; 3156 mem->aperture = APERTURE_INVALID;
3151 3157
@@ -5098,7 +5104,7 @@ int gk20a_mm_suspend(struct gk20a *g)
5098{ 5104{
5099 gk20a_dbg_fn(""); 5105 gk20a_dbg_fn("");
5100 5106
5101 cancel_work_sync(&g->mm.vidmem_clear_mem_worker); 5107 cancel_work_sync(&g->mm.vidmem.clear_mem_worker);
5102 5108
5103 g->ops.mm.cbc_clean(g); 5109 g->ops.mm.cbc_clean(g);
5104 g->ops.mm.l2_flush(g, false); 5110 g->ops.mm.l2_flush(g, false);