drm/nouveau/device: audit and version NVIF_CONTROL class and methods
[pandora-kernel.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/engine.h>
27
28 #ifdef NOUVEAU_OBJECT_MAGIC
29 static struct list_head _objlist = LIST_HEAD_INIT(_objlist);
30 static DEFINE_SPINLOCK(_objlist_lock);
31 #endif
32
33 int
34 nouveau_object_create_(struct nouveau_object *parent,
35                        struct nouveau_object *engine,
36                        struct nouveau_oclass *oclass, u32 pclass,
37                        int size, void **pobject)
38 {
39         struct nouveau_object *object;
40
41         object = *pobject = kzalloc(size, GFP_KERNEL);
42         if (!object)
43                 return -ENOMEM;
44
45         nouveau_object_ref(parent, &object->parent);
46         nouveau_object_ref(engine, &object->engine);
47         object->oclass = oclass;
48         object->oclass->handle |= pclass;
49         atomic_set(&object->refcount, 1);
50         atomic_set(&object->usecount, 0);
51
52 #ifdef NOUVEAU_OBJECT_MAGIC
53         object->_magic = NOUVEAU_OBJECT_MAGIC;
54         spin_lock(&_objlist_lock);
55         list_add(&object->list, &_objlist);
56         spin_unlock(&_objlist_lock);
57 #endif
58         return 0;
59 }
60
61 int
62 _nouveau_object_ctor(struct nouveau_object *parent,
63                      struct nouveau_object *engine,
64                      struct nouveau_oclass *oclass, void *data, u32 size,
65                      struct nouveau_object **pobject)
66 {
67         if (size != 0)
68                 return -ENOSYS;
69         return nouveau_object_create(parent, engine, oclass, 0, pobject);
70 }
71
72 void
73 nouveau_object_destroy(struct nouveau_object *object)
74 {
75 #ifdef NOUVEAU_OBJECT_MAGIC
76         spin_lock(&_objlist_lock);
77         list_del(&object->list);
78         spin_unlock(&_objlist_lock);
79 #endif
80         nouveau_object_ref(NULL, &object->engine);
81         nouveau_object_ref(NULL, &object->parent);
82         kfree(object);
83 }
84
85 int
86 nouveau_object_init(struct nouveau_object *object)
87 {
88         return 0;
89 }
90
91 int
92 nouveau_object_fini(struct nouveau_object *object, bool suspend)
93 {
94         return 0;
95 }
96
97 struct nouveau_ofuncs
98 nouveau_object_ofuncs = {
99         .ctor = _nouveau_object_ctor,
100         .dtor = nouveau_object_destroy,
101         .init = nouveau_object_init,
102         .fini = nouveau_object_fini,
103 };
104
105 int
106 nouveau_object_ctor(struct nouveau_object *parent,
107                     struct nouveau_object *engine,
108                     struct nouveau_oclass *oclass, void *data, u32 size,
109                     struct nouveau_object **pobject)
110 {
111         struct nouveau_ofuncs *ofuncs = oclass->ofuncs;
112         struct nouveau_object *object = NULL;
113         int ret;
114
115         ret = ofuncs->ctor(parent, engine, oclass, data, size, &object);
116         *pobject = object;
117         if (ret < 0) {
118                 if (ret != -ENODEV) {
119                         nv_error(parent, "failed to create 0x%08x, %d\n",
120                                  oclass->handle, ret);
121                 }
122
123                 if (object) {
124                         ofuncs->dtor(object);
125                         *pobject = NULL;
126                 }
127
128                 return ret;
129         }
130
131         if (ret == 0) {
132                 nv_trace(object, "created\n");
133                 atomic_set(&object->refcount, 1);
134         }
135
136         return 0;
137 }
138
139 static void
140 nouveau_object_dtor(struct nouveau_object *object)
141 {
142         nv_trace(object, "destroying\n");
143         nv_ofuncs(object)->dtor(object);
144 }
145
146 void
147 nouveau_object_ref(struct nouveau_object *obj, struct nouveau_object **ref)
148 {
149         if (obj) {
150                 atomic_inc(&obj->refcount);
151                 nv_trace(obj, "inc() == %d\n", atomic_read(&obj->refcount));
152         }
153
154         if (*ref) {
155                 int dead = atomic_dec_and_test(&(*ref)->refcount);
156                 nv_trace(*ref, "dec() == %d\n", atomic_read(&(*ref)->refcount));
157                 if (dead)
158                         nouveau_object_dtor(*ref);
159         }
160
161         *ref = obj;
162 }
163
164 int
165 nouveau_object_inc(struct nouveau_object *object)
166 {
167         int ref = atomic_add_return(1, &object->usecount);
168         int ret;
169
170         nv_trace(object, "use(+1) == %d\n", atomic_read(&object->usecount));
171         if (ref != 1)
172                 return 0;
173
174         nv_trace(object, "initialising...\n");
175         if (object->parent) {
176                 ret = nouveau_object_inc(object->parent);
177                 if (ret) {
178                         nv_error(object, "parent failed, %d\n", ret);
179                         goto fail_parent;
180                 }
181         }
182
183         if (object->engine) {
184                 mutex_lock(&nv_subdev(object->engine)->mutex);
185                 ret = nouveau_object_inc(object->engine);
186                 mutex_unlock(&nv_subdev(object->engine)->mutex);
187                 if (ret) {
188                         nv_error(object, "engine failed, %d\n", ret);
189                         goto fail_engine;
190                 }
191         }
192
193         ret = nv_ofuncs(object)->init(object);
194         atomic_set(&object->usecount, 1);
195         if (ret) {
196                 nv_error(object, "init failed, %d\n", ret);
197                 goto fail_self;
198         }
199
200         nv_trace(object, "initialised\n");
201         return 0;
202
203 fail_self:
204         if (object->engine) {
205                 mutex_lock(&nv_subdev(object->engine)->mutex);
206                 nouveau_object_dec(object->engine, false);
207                 mutex_unlock(&nv_subdev(object->engine)->mutex);
208         }
209 fail_engine:
210         if (object->parent)
211                  nouveau_object_dec(object->parent, false);
212 fail_parent:
213         atomic_dec(&object->usecount);
214         return ret;
215 }
216
217 static int
218 nouveau_object_decf(struct nouveau_object *object)
219 {
220         int ret;
221
222         nv_trace(object, "stopping...\n");
223
224         ret = nv_ofuncs(object)->fini(object, false);
225         atomic_set(&object->usecount, 0);
226         if (ret)
227                 nv_warn(object, "failed fini, %d\n", ret);
228
229         if (object->engine) {
230                 mutex_lock(&nv_subdev(object->engine)->mutex);
231                 nouveau_object_dec(object->engine, false);
232                 mutex_unlock(&nv_subdev(object->engine)->mutex);
233         }
234
235         if (object->parent)
236                 nouveau_object_dec(object->parent, false);
237
238         nv_trace(object, "stopped\n");
239         return 0;
240 }
241
242 static int
243 nouveau_object_decs(struct nouveau_object *object)
244 {
245         int ret, rret;
246
247         nv_trace(object, "suspending...\n");
248
249         ret = nv_ofuncs(object)->fini(object, true);
250         atomic_set(&object->usecount, 0);
251         if (ret) {
252                 nv_error(object, "failed suspend, %d\n", ret);
253                 return ret;
254         }
255
256         if (object->engine) {
257                 mutex_lock(&nv_subdev(object->engine)->mutex);
258                 ret = nouveau_object_dec(object->engine, true);
259                 mutex_unlock(&nv_subdev(object->engine)->mutex);
260                 if (ret) {
261                         nv_warn(object, "engine failed suspend, %d\n", ret);
262                         goto fail_engine;
263                 }
264         }
265
266         if (object->parent) {
267                 ret = nouveau_object_dec(object->parent, true);
268                 if (ret) {
269                         nv_warn(object, "parent failed suspend, %d\n", ret);
270                         goto fail_parent;
271                 }
272         }
273
274         nv_trace(object, "suspended\n");
275         return 0;
276
277 fail_parent:
278         if (object->engine) {
279                 mutex_lock(&nv_subdev(object->engine)->mutex);
280                 rret = nouveau_object_inc(object->engine);
281                 mutex_unlock(&nv_subdev(object->engine)->mutex);
282                 if (rret)
283                         nv_fatal(object, "engine failed to reinit, %d\n", rret);
284         }
285
286 fail_engine:
287         rret = nv_ofuncs(object)->init(object);
288         if (rret)
289                 nv_fatal(object, "failed to reinit, %d\n", rret);
290
291         return ret;
292 }
293
294 int
295 nouveau_object_dec(struct nouveau_object *object, bool suspend)
296 {
297         int ref = atomic_add_return(-1, &object->usecount);
298         int ret;
299
300         nv_trace(object, "use(-1) == %d\n", atomic_read(&object->usecount));
301
302         if (ref == 0) {
303                 if (suspend)
304                         ret = nouveau_object_decs(object);
305                 else
306                         ret = nouveau_object_decf(object);
307
308                 if (ret) {
309                         atomic_inc(&object->usecount);
310                         return ret;
311                 }
312         }
313
314         return 0;
315 }
316
317 void
318 nouveau_object_debug(void)
319 {
320 #ifdef NOUVEAU_OBJECT_MAGIC
321         struct nouveau_object *object;
322         if (!list_empty(&_objlist)) {
323                 nv_fatal(NULL, "*******************************************\n");
324                 nv_fatal(NULL, "* AIIIII! object(s) still exist!!!\n");
325                 nv_fatal(NULL, "*******************************************\n");
326                 list_for_each_entry(object, &_objlist, list) {
327                         nv_fatal(object, "%p/%p/%d/%d\n",
328                                  object->parent, object->engine,
329                                  atomic_read(&object->refcount),
330                                  atomic_read(&object->usecount));
331                 }
332         }
333 #endif
334 }