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