]> git.karo-electronics.de Git - karo-tx-linux.git/blob - drivers/gpu/drm/nouveau/core/core/gpuobj.c
drm/nouveau: quiet some static-related sparse noise
[karo-tx-linux.git] / drivers / gpu / drm / nouveau / core / core / gpuobj.c
1 /*
2  * Copyright 2012 Red Hat Inc.
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a
5  * copy of this software and associated documentation files (the "Software"),
6  * to deal in the Software without restriction, including without limitation
7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8  * and/or sell copies of the Software, and to permit persons to whom the
9  * Software is furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice shall be included in
12  * all copies or substantial portions of the Software.
13  *
14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
17  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
18  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20  * OTHER DEALINGS IN THE SOFTWARE.
21  *
22  * Authors: Ben Skeggs
23  */
24
25 #include <core/object.h>
26 #include <core/gpuobj.h>
27
28 #include <subdev/instmem.h>
29 #include <subdev/bar.h>
30 #include <subdev/vm.h>
31
32 void
33 nouveau_gpuobj_destroy(struct nouveau_gpuobj *gpuobj)
34 {
35         int i;
36
37         if (gpuobj->flags & NVOBJ_FLAG_ZERO_FREE) {
38                 for (i = 0; i < gpuobj->size; i += 4)
39                         nv_wo32(gpuobj, i, 0x00000000);
40         }
41
42         if (gpuobj->heap.block_size)
43                 nouveau_mm_fini(&gpuobj->heap);
44
45         nouveau_object_destroy(&gpuobj->base);
46 }
47
48 int
49 nouveau_gpuobj_create_(struct nouveau_object *parent,
50                        struct nouveau_object *engine,
51                        struct nouveau_oclass *oclass, u32 pclass,
52                        struct nouveau_object *pargpu,
53                        u32 size, u32 align, u32 flags,
54                        int length, void **pobject)
55 {
56         struct nouveau_instmem *imem = nouveau_instmem(parent);
57         struct nouveau_bar *bar = nouveau_bar(parent);
58         struct nouveau_gpuobj *gpuobj;
59         struct nouveau_mm *heap = NULL;
60         int ret, i;
61         u64 addr;
62
63         *pobject = NULL;
64
65         if (pargpu) {
66                 while ((pargpu = nv_pclass(pargpu, NV_GPUOBJ_CLASS))) {
67                         if (nv_gpuobj(pargpu)->heap.block_size)
68                                 break;
69                         pargpu = pargpu->parent;
70                 }
71
72                 if (unlikely(pargpu == NULL)) {
73                         nv_error(parent, "no gpuobj heap\n");
74                         return -EINVAL;
75                 }
76
77                 addr =  nv_gpuobj(pargpu)->addr;
78                 heap = &nv_gpuobj(pargpu)->heap;
79                 atomic_inc(&parent->refcount);
80         } else {
81                 ret = imem->alloc(imem, parent, size, align, &parent);
82                 pargpu = parent;
83                 if (ret)
84                         return ret;
85
86                 addr = nv_memobj(pargpu)->addr;
87                 size = nv_memobj(pargpu)->size;
88
89                 if (bar && bar->alloc) {
90                         struct nouveau_instobj *iobj = (void *)parent;
91                         struct nouveau_mem **mem = (void *)(iobj + 1);
92                         struct nouveau_mem *node = *mem;
93                         if (!bar->alloc(bar, parent, node, &pargpu)) {
94                                 nouveau_object_ref(NULL, &parent);
95                                 parent = pargpu;
96                         }
97                 }
98         }
99
100         ret = nouveau_object_create_(parent, engine, oclass, pclass |
101                                      NV_GPUOBJ_CLASS, length, pobject);
102         nouveau_object_ref(NULL, &parent);
103         gpuobj = *pobject;
104         if (ret)
105                 return ret;
106
107         gpuobj->parent = pargpu;
108         gpuobj->flags = flags;
109         gpuobj->addr = addr;
110         gpuobj->size = size;
111
112         if (heap) {
113                 ret = nouveau_mm_head(heap, 1, size, size,
114                                       max(align, (u32)1), &gpuobj->node);
115                 if (ret)
116                         return ret;
117
118                 gpuobj->addr += gpuobj->node->offset;
119         }
120
121         if (gpuobj->flags & NVOBJ_FLAG_HEAP) {
122                 ret = nouveau_mm_init(&gpuobj->heap, 0, gpuobj->size, 1);
123                 if (ret)
124                         return ret;
125         }
126
127         if (flags & NVOBJ_FLAG_ZERO_ALLOC) {
128                 for (i = 0; i < gpuobj->size; i += 4)
129                         nv_wo32(gpuobj, i, 0x00000000);
130         }
131
132         return ret;
133 }
134
135 struct nouveau_gpuobj_class {
136         struct nouveau_object *pargpu;
137         u64 size;
138         u32 align;
139         u32 flags;
140 };
141
142 static int
143 _nouveau_gpuobj_ctor(struct nouveau_object *parent,
144                      struct nouveau_object *engine,
145                      struct nouveau_oclass *oclass, void *data, u32 size,
146                      struct nouveau_object **pobject)
147 {
148         struct nouveau_gpuobj_class *args = data;
149         struct nouveau_gpuobj *object;
150         int ret;
151
152         ret = nouveau_gpuobj_create(parent, engine, oclass, 0, args->pargpu,
153                                     args->size, args->align, args->flags,
154                                     &object);
155         *pobject = nv_object(object);
156         if (ret)
157                 return ret;
158
159         return 0;
160 }
161
162 void
163 _nouveau_gpuobj_dtor(struct nouveau_object *object)
164 {
165         nouveau_gpuobj_destroy(nv_gpuobj(object));
166 }
167
168 int
169 _nouveau_gpuobj_init(struct nouveau_object *object)
170 {
171         return nouveau_gpuobj_init(nv_gpuobj(object));
172 }
173
174 int
175 _nouveau_gpuobj_fini(struct nouveau_object *object, bool suspend)
176 {
177         return nouveau_gpuobj_fini(nv_gpuobj(object), suspend);
178 }
179
180 u32
181 _nouveau_gpuobj_rd32(struct nouveau_object *object, u32 addr)
182 {
183         struct nouveau_gpuobj *gpuobj = nv_gpuobj(object);
184         struct nouveau_ofuncs *pfuncs = nv_ofuncs(gpuobj->parent);
185         if (gpuobj->node)
186                 addr += gpuobj->node->offset;
187         return pfuncs->rd32(gpuobj->parent, addr);
188 }
189
190 void
191 _nouveau_gpuobj_wr32(struct nouveau_object *object, u32 addr, u32 data)
192 {
193         struct nouveau_gpuobj *gpuobj = nv_gpuobj(object);
194         struct nouveau_ofuncs *pfuncs = nv_ofuncs(gpuobj->parent);
195         if (gpuobj->node)
196                 addr += gpuobj->node->offset;
197         pfuncs->wr32(gpuobj->parent, addr, data);
198 }
199
200 static struct nouveau_oclass
201 _nouveau_gpuobj_oclass = {
202         .handle = 0x00000000,
203         .ofuncs = &(struct nouveau_ofuncs) {
204                 .ctor = _nouveau_gpuobj_ctor,
205                 .dtor = _nouveau_gpuobj_dtor,
206                 .init = _nouveau_gpuobj_init,
207                 .fini = _nouveau_gpuobj_fini,
208                 .rd32 = _nouveau_gpuobj_rd32,
209                 .wr32 = _nouveau_gpuobj_wr32,
210         },
211 };
212
213 int
214 nouveau_gpuobj_new(struct nouveau_object *parent, struct nouveau_object *pargpu,
215                    u32 size, u32 align, u32 flags,
216                    struct nouveau_gpuobj **pgpuobj)
217 {
218         struct nouveau_object *engine = parent;
219         struct nouveau_gpuobj_class args = {
220                 .pargpu = pargpu,
221                 .size = size,
222                 .align = align,
223                 .flags = flags,
224         };
225
226         if (!nv_iclass(engine, NV_SUBDEV_CLASS))
227                 engine = engine->engine;
228         BUG_ON(engine == NULL);
229
230         return nouveau_object_ctor(parent, engine, &_nouveau_gpuobj_oclass,
231                                    &args, sizeof(args),
232                                    (struct nouveau_object **)pgpuobj);
233 }
234
235 int
236 nouveau_gpuobj_map(struct nouveau_gpuobj *gpuobj, u32 access,
237                    struct nouveau_vma *vma)
238 {
239         struct nouveau_bar *bar = nouveau_bar(gpuobj);
240         int ret = -EINVAL;
241
242         if (bar && bar->umap) {
243                 struct nouveau_instobj *iobj = (void *)
244                         nv_pclass(nv_object(gpuobj), NV_MEMOBJ_CLASS);
245                 struct nouveau_mem **mem = (void *)(iobj + 1);
246                 ret = bar->umap(bar, *mem, access, vma);
247         }
248
249         return ret;
250 }
251
252 int
253 nouveau_gpuobj_map_vm(struct nouveau_gpuobj *gpuobj, struct nouveau_vm *vm,
254                       u32 access, struct nouveau_vma *vma)
255 {
256         struct nouveau_instobj *iobj = (void *)
257                 nv_pclass(nv_object(gpuobj), NV_MEMOBJ_CLASS);
258         struct nouveau_mem **mem = (void *)(iobj + 1);
259         int ret;
260
261         ret = nouveau_vm_get(vm, gpuobj->size, 12, access, vma);
262         if (ret)
263                 return ret;
264
265         nouveau_vm_map(vma, *mem);
266         return 0;
267 }
268
269 void
270 nouveau_gpuobj_unmap(struct nouveau_vma *vma)
271 {
272         if (vma->node) {
273                 nouveau_vm_unmap(vma);
274                 nouveau_vm_put(vma);
275         }
276 }
277
278 /* the below is basically only here to support sharing the paged dma object
279  * for PCI(E)GART on <=nv4x chipsets, and should *not* be expected to work
280  * anywhere else.
281  */
282
283 static void
284 nouveau_gpudup_dtor(struct nouveau_object *object)
285 {
286         struct nouveau_gpuobj *gpuobj = (void *)object;
287         nouveau_object_ref(NULL, &gpuobj->parent);
288         nouveau_object_destroy(&gpuobj->base);
289 }
290
291 static struct nouveau_oclass
292 nouveau_gpudup_oclass = {
293         .handle = NV_GPUOBJ_CLASS,
294         .ofuncs = &(struct nouveau_ofuncs) {
295                 .dtor = nouveau_gpudup_dtor,
296                 .init = nouveau_object_init,
297                 .fini = nouveau_object_fini,
298         },
299 };
300
301 int
302 nouveau_gpuobj_dup(struct nouveau_object *parent, struct nouveau_gpuobj *base,
303                    struct nouveau_gpuobj **pgpuobj)
304 {
305         struct nouveau_gpuobj *gpuobj;
306         int ret;
307
308         ret = nouveau_object_create(parent, parent->engine,
309                                    &nouveau_gpudup_oclass, 0, &gpuobj);
310         *pgpuobj = gpuobj;
311         if (ret)
312                 return ret;
313
314         nouveau_object_ref(nv_object(base), &gpuobj->parent);
315         gpuobj->addr = base->addr;
316         gpuobj->size = base->size;
317         return 0;
318 }