summaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorLauri Peltonen <lpeltonen@nvidia.com>2014-02-25 07:44:44 -0500
committerDan Willemsen <dwillemsen@nvidia.com>2015-03-18 15:09:52 -0400
commite6b3d1e87f7f2d91c97bf260d4609f17d62ff8bc (patch)
treeb55b9a7adfe7387af1ea376f5edfaf58170a649b /drivers
parentdadaa5af564e9c5da56931c8f48882f985d5c5d1 (diff)
gpu: nvgpu: Add gk20a semaphore APIs
Add semaphore_gk20a.c/h that implement a new semaphore management API for the gk20a driver. The API introduces two entities, 'semaphore pools' and 'semaphores'. Semaphore pools are memory areas dedicated for hosting one or more semaphores. Typically, one pool equals one 4K page. A semaphore pool is always mapped to the kernel memory, and it can be mapped and unmapped to gpu address spaces using gk20a_semaphore_pool_map/unmap. Semaphores are backed by 16 bytes of memory allocated from a semaphore pool. The value of a semaphore can be 0=acuired or 1=released. When allocated, the semaphores are initialized to the acquired state. They can be released, or their releasing can be waited for by the CPU or GPU. Semaphores are intended to be used only once, and after they are released they should be freed so that the slot within the semaphore pool can be reused. However GPU jobs must take references to the semaphores that they use (similarly as they take references on memory buffers that they use) so that the semaphore backing memory is not reused too soon. Bug 1450122 Bug 1445450 Change-Id: I3fd35f34ca55035decc3e06a9c0ede20c1d48db9 Signed-off-by: Lauri Peltonen <lpeltonen@nvidia.com> Reviewed-on: http://git-master/r/374842 Reviewed-by: Arto Merilainen <amerilainen@nvidia.com> Reviewed-by: Terje Bergstrom <tbergstrom@nvidia.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/gpu/nvgpu/gk20a/Makefile1
-rw-r--r--drivers/gpu/nvgpu/gk20a/semaphore_gk20a.c191
-rw-r--r--drivers/gpu/nvgpu/gk20a/semaphore_gk20a.h97
3 files changed, 289 insertions, 0 deletions
diff --git a/drivers/gpu/nvgpu/gk20a/Makefile b/drivers/gpu/nvgpu/gk20a/Makefile
index 81ae027e..e5eb817d 100644
--- a/drivers/gpu/nvgpu/gk20a/Makefile
+++ b/drivers/gpu/nvgpu/gk20a/Makefile
@@ -19,6 +19,7 @@ nvgpu-y := \
19 mm_gk20a.o \ 19 mm_gk20a.o \
20 pmu_gk20a.o \ 20 pmu_gk20a.o \
21 priv_ring_gk20a.o \ 21 priv_ring_gk20a.o \
22 semaphore_gk20a.o \
22 clk_gk20a.o \ 23 clk_gk20a.o \
23 therm_gk20a.o \ 24 therm_gk20a.o \
24 gr_ctx_gk20a_sim.o \ 25 gr_ctx_gk20a_sim.o \
diff --git a/drivers/gpu/nvgpu/gk20a/semaphore_gk20a.c b/drivers/gpu/nvgpu/gk20a/semaphore_gk20a.c
new file mode 100644
index 00000000..55fa0e32
--- /dev/null
+++ b/drivers/gpu/nvgpu/gk20a/semaphore_gk20a.c
@@ -0,0 +1,191 @@
1/*
2 * drivers/video/tegra/host/gk20a/semaphore_gk20a.c
3 *
4 * GK20A Semaphores
5 *
6 * Copyright (c) 2014, NVIDIA CORPORATION. All rights reserved.
7 *
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms and conditions of the GNU General Public License,
10 * version 2, as published by the Free Software Foundation.
11 *
12 * This program is distributed in the hope it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15 * more details.
16 */
17
18#include "semaphore_gk20a.h"
19#include <linux/dma-mapping.h>
20#include <linux/slab.h>
21#include "gk20a.h"
22#include "mm_gk20a.h"
23
24static const int SEMAPHORE_SIZE = 16;
25
26struct gk20a_semaphore_pool *gk20a_semaphore_pool_alloc(struct device *d,
27 const char *unique_name, size_t capacity)
28{
29 struct gk20a_semaphore_pool *p;
30 p = kzalloc(sizeof(*p), GFP_KERNEL);
31 if (!p)
32 return NULL;
33
34 kref_init(&p->ref);
35 INIT_LIST_HEAD(&p->maps);
36 mutex_init(&p->maps_mutex);
37 p->dev = d;
38
39 /* Alloc one 4k page of semaphore per channel. */
40 p->size = roundup(capacity * SEMAPHORE_SIZE, PAGE_SIZE);
41 p->cpu_va = dma_alloc_coherent(d, p->size, &p->iova, GFP_KERNEL);
42 if (!p->cpu_va)
43 goto clean_up;
44 if (gk20a_get_sgtable(d, &p->sgt, p->cpu_va, p->iova, p->size))
45 goto clean_up;
46
47 if (gk20a_allocator_init(&p->alloc, unique_name, 0,
48 p->size, SEMAPHORE_SIZE))
49 goto clean_up;
50
51 gk20a_dbg_info("cpuva=%p iova=%llx phys=%llx", p->cpu_va,
52 (u64)sg_dma_address(p->sgt->sgl), (u64)sg_phys(p->sgt->sgl));
53 return p;
54clean_up:
55 if (p->cpu_va)
56 dma_free_coherent(d, p->size, p->cpu_va, p->iova);
57 if (p->sgt)
58 gk20a_free_sgtable(&p->sgt);
59 kfree(p);
60 return NULL;
61}
62
63static void gk20a_semaphore_pool_free(struct kref *ref)
64{
65 struct gk20a_semaphore_pool *p =
66 container_of(ref, struct gk20a_semaphore_pool, ref);
67 mutex_lock(&p->maps_mutex);
68 WARN_ON(!list_empty(&p->maps));
69 mutex_unlock(&p->maps_mutex);
70 gk20a_free_sgtable(&p->sgt);
71 dma_free_coherent(p->dev, p->size, p->cpu_va, p->iova);
72 gk20a_allocator_destroy(&p->alloc);
73 kfree(p);
74}
75
76static void gk20a_semaphore_pool_get(struct gk20a_semaphore_pool *p)
77{
78 kref_get(&p->ref);
79}
80
81void gk20a_semaphore_pool_put(struct gk20a_semaphore_pool *p)
82{
83 kref_put(&p->ref, gk20a_semaphore_pool_free);
84}
85
86static struct gk20a_semaphore_pool_map *
87gk20a_semaphore_pool_find_map(struct gk20a_semaphore_pool *p,
88 struct vm_gk20a *vm)
89{
90 struct gk20a_semaphore_pool_map *map, *found = NULL;
91 mutex_lock(&p->maps_mutex);
92 list_for_each_entry(map, &p->maps, list) {
93 if (map->vm == vm) {
94 found = map;
95 break;
96 }
97 }
98 mutex_unlock(&p->maps_mutex);
99 return found;
100}
101
102int gk20a_semaphore_pool_map(struct gk20a_semaphore_pool *p,
103 struct vm_gk20a *vm,
104 enum gk20a_mem_rw_flag rw_flag)
105{
106 struct gk20a_semaphore_pool_map *map;
107
108 WARN_ON(gk20a_semaphore_pool_find_map(p, vm));
109 map = kzalloc(sizeof(*map), GFP_KERNEL);
110 if (!map)
111 return -ENOMEM;
112 map->vm = vm;
113 map->rw_flag = rw_flag;
114 map->gpu_va = gk20a_gmmu_map(vm, &p->sgt, p->size,
115 0/*uncached*/, rw_flag);
116 if (!map->gpu_va) {
117 kfree(map);
118 return -ENOMEM;
119 }
120 mutex_lock(&p->maps_mutex);
121 list_add(&map->list, &p->maps);
122 mutex_unlock(&p->maps_mutex);
123 return 0;
124}
125
126void gk20a_semaphore_pool_unmap(struct gk20a_semaphore_pool *p,
127 struct vm_gk20a *vm)
128{
129 struct gk20a_semaphore_pool_map *map =
130 gk20a_semaphore_pool_find_map(p, vm);
131 if (!map)
132 return;
133 gk20a_gmmu_unmap(vm, map->gpu_va, p->size, map->rw_flag);
134 list_del(&map->list);
135 kfree(map);
136}
137
138u64 gk20a_semaphore_pool_gpu_va(struct gk20a_semaphore_pool *p,
139 struct vm_gk20a *vm)
140{
141 struct gk20a_semaphore_pool_map *map =
142 gk20a_semaphore_pool_find_map(p, vm);
143 if (!map)
144 return 0;
145 return map->gpu_va;
146}
147
148struct gk20a_semaphore *gk20a_semaphore_alloc(struct gk20a_semaphore_pool *pool)
149{
150 struct gk20a_semaphore *s;
151
152 s = kzalloc(sizeof(*s), GFP_KERNEL);
153 if (!s)
154 return NULL;
155
156 if (pool->alloc.alloc(&pool->alloc, &s->offset, SEMAPHORE_SIZE)) {
157 gk20a_err(pool->dev, "failed to allocate semaphore");
158 kfree(s);
159 return NULL;
160 }
161
162 gk20a_semaphore_pool_get(pool);
163 s->pool = pool;
164
165 kref_init(&s->ref);
166 s->value = (volatile u32 *)((uintptr_t)pool->cpu_va + s->offset);
167 *s->value = 0; /* Initially acquired. */
168 gk20a_dbg_info("created semaphore offset=%d, value_cpu=%p, value=%d",
169 s->offset, s->value, *s->value);
170 return s;
171}
172
173static void gk20a_semaphore_free(struct kref *ref)
174{
175 struct gk20a_semaphore *s =
176 container_of(ref, struct gk20a_semaphore, ref);
177
178 s->pool->alloc.free(&s->pool->alloc, s->offset, SEMAPHORE_SIZE);
179 gk20a_semaphore_pool_put(s->pool);
180 kfree(s);
181}
182
183void gk20a_semaphore_put(struct gk20a_semaphore *s)
184{
185 kref_put(&s->ref, gk20a_semaphore_free);
186}
187
188void gk20a_semaphore_get(struct gk20a_semaphore *s)
189{
190 kref_get(&s->ref);
191}
diff --git a/drivers/gpu/nvgpu/gk20a/semaphore_gk20a.h b/drivers/gpu/nvgpu/gk20a/semaphore_gk20a.h
new file mode 100644
index 00000000..214db398
--- /dev/null
+++ b/drivers/gpu/nvgpu/gk20a/semaphore_gk20a.h
@@ -0,0 +1,97 @@
1/*
2 * drivers/video/tegra/host/gk20a/semaphore_gk20a.h
3 *
4 * GK20A Semaphores
5 *
6 * Copyright (c) 2014, NVIDIA CORPORATION. All rights reserved.
7 *
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms and conditions of the GNU General Public License,
10 * version 2, as published by the Free Software Foundation.
11 *
12 * This program is distributed in the hope it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15 * more details.
16 */
17
18#ifndef _GK20A_SEMAPHORE_H_
19#define _GK20A_SEMAPHORE_H_
20
21#include <linux/kref.h>
22#include "gk20a_allocator.h"
23#include "mm_gk20a.h"
24
25/* A memory pool for holding semaphores. */
26struct gk20a_semaphore_pool {
27 void *cpu_va;
28 dma_addr_t iova;
29 size_t size;
30 struct device *dev;
31 struct sg_table *sgt;
32 struct list_head maps;
33 struct mutex maps_mutex;
34 struct kref ref;
35 struct gk20a_allocator alloc;
36};
37
38/* A semaphore pool can be mapped to multiple GPU address spaces. */
39struct gk20a_semaphore_pool_map {
40 u64 gpu_va;
41 enum gk20a_mem_rw_flag rw_flag;
42 struct vm_gk20a *vm;
43 struct list_head list;
44};
45
46/* A semaphore that lives inside a semaphore pool. */
47struct gk20a_semaphore {
48 struct gk20a_semaphore_pool *pool;
49 u32 offset; /* byte offset within pool */
50 struct kref ref;
51 /* value is a pointer within the pool's coherent cpu_va.
52 * It is shared between CPU and GPU, hence volatile. */
53 volatile u32 *value; /* 0=acquired, 1=released */
54};
55
56/* Create a semaphore pool that can hold at most 'capacity' semaphores. */
57struct gk20a_semaphore_pool *
58gk20a_semaphore_pool_alloc(struct device *, const char *unique_name,
59 size_t capacity);
60void gk20a_semaphore_pool_put(struct gk20a_semaphore_pool *);
61int gk20a_semaphore_pool_map(struct gk20a_semaphore_pool *,
62 struct vm_gk20a *,
63 enum gk20a_mem_rw_flag);
64void gk20a_semaphore_pool_unmap(struct gk20a_semaphore_pool *,
65 struct vm_gk20a *);
66u64 gk20a_semaphore_pool_gpu_va(struct gk20a_semaphore_pool *,
67 struct vm_gk20a *);
68
69/* Allocate a semaphore from the semaphore pool. The newly allocated
70 * semaphore will be in acquired state (value=0). */
71struct gk20a_semaphore *
72gk20a_semaphore_alloc(struct gk20a_semaphore_pool *);
73void gk20a_semaphore_put(struct gk20a_semaphore *);
74void gk20a_semaphore_get(struct gk20a_semaphore *);
75
76static inline u64 gk20a_semaphore_gpu_va(struct gk20a_semaphore *s,
77 struct vm_gk20a *vm)
78{
79 return gk20a_semaphore_pool_gpu_va(s->pool, vm) + s->offset;
80}
81
82static inline bool gk20a_semaphore_is_acquired(struct gk20a_semaphore *s)
83{
84 u32 v = *s->value;
85
86 /* When often block on value reaching a certain threshold. We must make
87 * sure that if we get unblocked, we haven't read anything too early. */
88 smp_rmb();
89 return v == 0;
90}
91
92static inline void gk20a_semaphore_release(struct gk20a_semaphore *s)
93{
94 smp_wmb();
95 *s->value = 1;
96}
97#endif