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