Linux-libre 3.10.48-gnu
[librecmc/linux-libre.git] / drivers / gpu / drm / nouveau / core / core / object.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/parent.h>
27 #include <core/namedb.h>
28 #include <core/handle.h>
29 #include <core/engine.h>
30
31 #ifdef NOUVEAU_OBJECT_MAGIC
32 static struct list_head _objlist = LIST_HEAD_INIT(_objlist);
33 static DEFINE_SPINLOCK(_objlist_lock);
34 #endif
35
36 int
37 nouveau_object_create_(struct nouveau_object *parent,
38                        struct nouveau_object *engine,
39                        struct nouveau_oclass *oclass, u32 pclass,
40                        int size, void **pobject)
41 {
42         struct nouveau_object *object;
43
44         object = *pobject = kzalloc(size, GFP_KERNEL);
45         if (!object)
46                 return -ENOMEM;
47
48         nouveau_object_ref(parent, &object->parent);
49         nouveau_object_ref(engine, &object->engine);
50         object->oclass = oclass;
51         object->oclass->handle |= pclass;
52         atomic_set(&object->refcount, 1);
53         atomic_set(&object->usecount, 0);
54
55 #ifdef NOUVEAU_OBJECT_MAGIC
56         object->_magic = NOUVEAU_OBJECT_MAGIC;
57         spin_lock(&_objlist_lock);
58         list_add(&object->list, &_objlist);
59         spin_unlock(&_objlist_lock);
60 #endif
61         return 0;
62 }
63
64 static int
65 _nouveau_object_ctor(struct nouveau_object *parent,
66                      struct nouveau_object *engine,
67                      struct nouveau_oclass *oclass, void *data, u32 size,
68                      struct nouveau_object **pobject)
69 {
70         struct nouveau_object *object;
71         int ret;
72
73         ret = nouveau_object_create(parent, engine, oclass, 0, &object);
74         *pobject = nv_object(object);
75         if (ret)
76                 return ret;
77
78         return 0;
79 }
80
81 void
82 nouveau_object_destroy(struct nouveau_object *object)
83 {
84 #ifdef NOUVEAU_OBJECT_MAGIC
85         spin_lock(&_objlist_lock);
86         list_del(&object->list);
87         spin_unlock(&_objlist_lock);
88 #endif
89         nouveau_object_ref(NULL, &object->engine);
90         nouveau_object_ref(NULL, &object->parent);
91         kfree(object);
92 }
93
94 static void
95 _nouveau_object_dtor(struct nouveau_object *object)
96 {
97         nouveau_object_destroy(object);
98 }
99
100 int
101 nouveau_object_init(struct nouveau_object *object)
102 {
103         return 0;
104 }
105
106 static int
107 _nouveau_object_init(struct nouveau_object *object)
108 {
109         return nouveau_object_init(object);
110 }
111
112 int
113 nouveau_object_fini(struct nouveau_object *object, bool suspend)
114 {
115         return 0;
116 }
117
118 static int
119 _nouveau_object_fini(struct nouveau_object *object, bool suspend)
120 {
121         return nouveau_object_fini(object, suspend);
122 }
123
124 struct nouveau_ofuncs
125 nouveau_object_ofuncs = {
126         .ctor = _nouveau_object_ctor,
127         .dtor = _nouveau_object_dtor,
128         .init = _nouveau_object_init,
129         .fini = _nouveau_object_fini,
130 };
131
132 int
133 nouveau_object_ctor(struct nouveau_object *parent,
134                     struct nouveau_object *engine,
135                     struct nouveau_oclass *oclass, void *data, u32 size,
136                     struct nouveau_object **pobject)
137 {
138         struct nouveau_ofuncs *ofuncs = oclass->ofuncs;
139         struct nouveau_object *object = NULL;
140         int ret;
141
142         ret = ofuncs->ctor(parent, engine, oclass, data, size, &object);
143         *pobject = object;
144         if (ret < 0) {
145                 if (ret != -ENODEV) {
146                         nv_error(parent, "failed to create 0x%08x, %d\n",
147                                  oclass->handle, ret);
148                 }
149
150                 if (object) {
151                         ofuncs->dtor(object);
152                         *pobject = NULL;
153                 }
154
155                 return ret;
156         }
157
158         if (ret == 0) {
159                 nv_debug(object, "created\n");
160                 atomic_set(&object->refcount, 1);
161         }
162
163         return 0;
164 }
165
166 static void
167 nouveau_object_dtor(struct nouveau_object *object)
168 {
169         nv_debug(object, "destroying\n");
170         nv_ofuncs(object)->dtor(object);
171 }
172
173 void
174 nouveau_object_ref(struct nouveau_object *obj, struct nouveau_object **ref)
175 {
176         if (obj) {
177                 atomic_inc(&obj->refcount);
178                 nv_trace(obj, "inc() == %d\n", atomic_read(&obj->refcount));
179         }
180
181         if (*ref) {
182                 int dead = atomic_dec_and_test(&(*ref)->refcount);
183                 nv_trace(*ref, "dec() == %d\n", atomic_read(&(*ref)->refcount));
184                 if (dead)
185                         nouveau_object_dtor(*ref);
186         }
187
188         *ref = obj;
189 }
190
191 int
192 nouveau_object_new(struct nouveau_object *client, u32 _parent, u32 _handle,
193                    u16 _oclass, void *data, u32 size,
194                    struct nouveau_object **pobject)
195 {
196         struct nouveau_object *parent = NULL;
197         struct nouveau_object *engctx = NULL;
198         struct nouveau_object *object = NULL;
199         struct nouveau_object *engine;
200         struct nouveau_oclass *oclass;
201         struct nouveau_handle *handle;
202         int ret;
203
204         /* lookup parent object and ensure it *is* a parent */
205         parent = nouveau_handle_ref(client, _parent);
206         if (!parent) {
207                 nv_error(client, "parent 0x%08x not found\n", _parent);
208                 return -ENOENT;
209         }
210
211         if (!nv_iclass(parent, NV_PARENT_CLASS)) {
212                 nv_error(parent, "cannot have children\n");
213                 ret = -EINVAL;
214                 goto fail_class;
215         }
216
217         /* check that parent supports the requested subclass */
218         ret = nouveau_parent_sclass(parent, _oclass, &engine, &oclass);
219         if (ret) {
220                 nv_debug(parent, "illegal class 0x%04x\n", _oclass);
221                 goto fail_class;
222         }
223
224         /* make sure engine init has been completed *before* any objects
225          * it controls are created - the constructors may depend on
226          * state calculated at init (ie. default context construction)
227          */
228         if (engine) {
229                 ret = nouveau_object_inc(engine);
230                 if (ret)
231                         goto fail_class;
232         }
233
234         /* if engine requires it, create a context object to insert
235          * between the parent and its children (eg. PGRAPH context)
236          */
237         if (engine && nv_engine(engine)->cclass) {
238                 ret = nouveau_object_ctor(parent, engine,
239                                           nv_engine(engine)->cclass,
240                                           data, size, &engctx);
241                 if (ret)
242                         goto fail_engctx;
243         } else {
244                 nouveau_object_ref(parent, &engctx);
245         }
246
247         /* finally, create new object and bind it to its handle */
248         ret = nouveau_object_ctor(engctx, engine, oclass, data, size, &object);
249         *pobject = object;
250         if (ret)
251                 goto fail_ctor;
252
253         ret = nouveau_object_inc(object);
254         if (ret)
255                 goto fail_init;
256
257         ret = nouveau_handle_create(parent, _parent, _handle, object, &handle);
258         if (ret)
259                 goto fail_handle;
260
261         ret = nouveau_handle_init(handle);
262         if (ret)
263                 nouveau_handle_destroy(handle);
264
265 fail_handle:
266         nouveau_object_dec(object, false);
267 fail_init:
268         nouveau_object_ref(NULL, &object);
269 fail_ctor:
270         nouveau_object_ref(NULL, &engctx);
271 fail_engctx:
272         if (engine)
273                 nouveau_object_dec(engine, false);
274 fail_class:
275         nouveau_object_ref(NULL, &parent);
276         return ret;
277 }
278
279 int
280 nouveau_object_del(struct nouveau_object *client, u32 _parent, u32 _handle)
281 {
282         struct nouveau_object *parent = NULL;
283         struct nouveau_object *namedb = NULL;
284         struct nouveau_handle *handle = NULL;
285
286         parent = nouveau_handle_ref(client, _parent);
287         if (!parent)
288                 return -ENOENT;
289
290         namedb = nv_pclass(parent, NV_NAMEDB_CLASS);
291         if (namedb) {
292                 handle = nouveau_namedb_get(nv_namedb(namedb), _handle);
293                 if (handle) {
294                         nouveau_namedb_put(handle);
295                         nouveau_handle_fini(handle, false);
296                         nouveau_handle_destroy(handle);
297                 }
298         }
299
300         nouveau_object_ref(NULL, &parent);
301         return handle ? 0 : -EINVAL;
302 }
303
304 int
305 nouveau_object_inc(struct nouveau_object *object)
306 {
307         int ref = atomic_add_return(1, &object->usecount);
308         int ret;
309
310         nv_trace(object, "use(+1) == %d\n", atomic_read(&object->usecount));
311         if (ref != 1)
312                 return 0;
313
314         nv_trace(object, "initialising...\n");
315         if (object->parent) {
316                 ret = nouveau_object_inc(object->parent);
317                 if (ret) {
318                         nv_error(object, "parent failed, %d\n", ret);
319                         goto fail_parent;
320                 }
321         }
322
323         if (object->engine) {
324                 mutex_lock(&nv_subdev(object->engine)->mutex);
325                 ret = nouveau_object_inc(object->engine);
326                 mutex_unlock(&nv_subdev(object->engine)->mutex);
327                 if (ret) {
328                         nv_error(object, "engine failed, %d\n", ret);
329                         goto fail_engine;
330                 }
331         }
332
333         ret = nv_ofuncs(object)->init(object);
334         atomic_set(&object->usecount, 1);
335         if (ret) {
336                 nv_error(object, "init failed, %d\n", ret);
337                 goto fail_self;
338         }
339
340         nv_debug(object, "initialised\n");
341         return 0;
342
343 fail_self:
344         if (object->engine) {
345                 mutex_lock(&nv_subdev(object->engine)->mutex);
346                 nouveau_object_dec(object->engine, false);
347                 mutex_unlock(&nv_subdev(object->engine)->mutex);
348         }
349 fail_engine:
350         if (object->parent)
351                  nouveau_object_dec(object->parent, false);
352 fail_parent:
353         atomic_dec(&object->usecount);
354         return ret;
355 }
356
357 static int
358 nouveau_object_decf(struct nouveau_object *object)
359 {
360         int ret;
361
362         nv_trace(object, "stopping...\n");
363
364         ret = nv_ofuncs(object)->fini(object, false);
365         atomic_set(&object->usecount, 0);
366         if (ret)
367                 nv_warn(object, "failed fini, %d\n", ret);
368
369         if (object->engine) {
370                 mutex_lock(&nv_subdev(object->engine)->mutex);
371                 nouveau_object_dec(object->engine, false);
372                 mutex_unlock(&nv_subdev(object->engine)->mutex);
373         }
374
375         if (object->parent)
376                 nouveau_object_dec(object->parent, false);
377
378         nv_debug(object, "stopped\n");
379         return 0;
380 }
381
382 static int
383 nouveau_object_decs(struct nouveau_object *object)
384 {
385         int ret, rret;
386
387         nv_trace(object, "suspending...\n");
388
389         ret = nv_ofuncs(object)->fini(object, true);
390         atomic_set(&object->usecount, 0);
391         if (ret) {
392                 nv_error(object, "failed suspend, %d\n", ret);
393                 return ret;
394         }
395
396         if (object->engine) {
397                 mutex_lock(&nv_subdev(object->engine)->mutex);
398                 ret = nouveau_object_dec(object->engine, true);
399                 mutex_unlock(&nv_subdev(object->engine)->mutex);
400                 if (ret) {
401                         nv_warn(object, "engine failed suspend, %d\n", ret);
402                         goto fail_engine;
403                 }
404         }
405
406         if (object->parent) {
407                 ret = nouveau_object_dec(object->parent, true);
408                 if (ret) {
409                         nv_warn(object, "parent failed suspend, %d\n", ret);
410                         goto fail_parent;
411                 }
412         }
413
414         nv_debug(object, "suspended\n");
415         return 0;
416
417 fail_parent:
418         if (object->engine) {
419                 mutex_lock(&nv_subdev(object->engine)->mutex);
420                 rret = nouveau_object_inc(object->engine);
421                 mutex_unlock(&nv_subdev(object->engine)->mutex);
422                 if (rret)
423                         nv_fatal(object, "engine failed to reinit, %d\n", rret);
424         }
425
426 fail_engine:
427         rret = nv_ofuncs(object)->init(object);
428         if (rret)
429                 nv_fatal(object, "failed to reinit, %d\n", rret);
430
431         return ret;
432 }
433
434 int
435 nouveau_object_dec(struct nouveau_object *object, bool suspend)
436 {
437         int ref = atomic_add_return(-1, &object->usecount);
438         int ret;
439
440         nv_trace(object, "use(-1) == %d\n", atomic_read(&object->usecount));
441
442         if (ref == 0) {
443                 if (suspend)
444                         ret = nouveau_object_decs(object);
445                 else
446                         ret = nouveau_object_decf(object);
447
448                 if (ret) {
449                         atomic_inc(&object->usecount);
450                         return ret;
451                 }
452         }
453
454         return 0;
455 }
456
457 void
458 nouveau_object_debug(void)
459 {
460 #ifdef NOUVEAU_OBJECT_MAGIC
461         struct nouveau_object *object;
462         if (!list_empty(&_objlist)) {
463                 nv_fatal(NULL, "*******************************************\n");
464                 nv_fatal(NULL, "* AIIIII! object(s) still exist!!!\n");
465                 nv_fatal(NULL, "*******************************************\n");
466                 list_for_each_entry(object, &_objlist, list) {
467                         nv_fatal(object, "%p/%p/%d/%d\n",
468                                  object->parent, object->engine,
469                                  atomic_read(&object->refcount),
470                                  atomic_read(&object->usecount));
471                 }
472         }
473 #endif
474 }