1c39f472eSBen Skeggs /*
2c39f472eSBen Skeggs * Copyright 2012 Red Hat Inc.
3c39f472eSBen Skeggs *
4c39f472eSBen Skeggs * Permission is hereby granted, free of charge, to any person obtaining a
5c39f472eSBen Skeggs * copy of this software and associated documentation files (the "Software"),
6c39f472eSBen Skeggs * to deal in the Software without restriction, including without limitation
7c39f472eSBen Skeggs * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8c39f472eSBen Skeggs * and/or sell copies of the Software, and to permit persons to whom the
9c39f472eSBen Skeggs * Software is furnished to do so, subject to the following conditions:
10c39f472eSBen Skeggs *
11c39f472eSBen Skeggs * The above copyright notice and this permission notice shall be included in
12c39f472eSBen Skeggs * all copies or substantial portions of the Software.
13c39f472eSBen Skeggs *
14c39f472eSBen Skeggs * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15c39f472eSBen Skeggs * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16c39f472eSBen Skeggs * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17c39f472eSBen Skeggs * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
18c39f472eSBen Skeggs * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19c39f472eSBen Skeggs * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20c39f472eSBen Skeggs * OTHER DEALINGS IN THE SOFTWARE.
21c39f472eSBen Skeggs *
22c39f472eSBen Skeggs * Authors: Ben Skeggs
23c39f472eSBen Skeggs */
24c39f472eSBen Skeggs #include <core/object.h>
25fbd58ebdSBen Skeggs #include <core/client.h>
26c39f472eSBen Skeggs #include <core/engine.h>
27c39f472eSBen Skeggs
28110cccffSBen Skeggs struct nvkm_object *
nvkm_object_search(struct nvkm_client * client,u64 handle,const struct nvkm_object_func * func)29110cccffSBen Skeggs nvkm_object_search(struct nvkm_client *client, u64 handle,
30110cccffSBen Skeggs const struct nvkm_object_func *func)
31110cccffSBen Skeggs {
32110cccffSBen Skeggs struct nvkm_object *object;
33*b7cc4ff7SDave Airlie unsigned long flags;
34110cccffSBen Skeggs
35110cccffSBen Skeggs if (handle) {
36*b7cc4ff7SDave Airlie spin_lock_irqsave(&client->obj_lock, flags);
37110cccffSBen Skeggs struct rb_node *node = client->objroot.rb_node;
38110cccffSBen Skeggs while (node) {
39110cccffSBen Skeggs object = rb_entry(node, typeof(*object), node);
40110cccffSBen Skeggs if (handle < object->object)
41110cccffSBen Skeggs node = node->rb_left;
42110cccffSBen Skeggs else
43110cccffSBen Skeggs if (handle > object->object)
44110cccffSBen Skeggs node = node->rb_right;
45*b7cc4ff7SDave Airlie else {
46*b7cc4ff7SDave Airlie spin_unlock_irqrestore(&client->obj_lock, flags);
47110cccffSBen Skeggs goto done;
48110cccffSBen Skeggs }
49*b7cc4ff7SDave Airlie }
50*b7cc4ff7SDave Airlie spin_unlock_irqrestore(&client->obj_lock, flags);
51110cccffSBen Skeggs return ERR_PTR(-ENOENT);
52110cccffSBen Skeggs } else {
53110cccffSBen Skeggs object = &client->object;
54110cccffSBen Skeggs }
55110cccffSBen Skeggs
56110cccffSBen Skeggs done:
57110cccffSBen Skeggs if (unlikely(func && object->func != func))
58110cccffSBen Skeggs return ERR_PTR(-EINVAL);
59110cccffSBen Skeggs return object;
60110cccffSBen Skeggs }
61110cccffSBen Skeggs
62110cccffSBen Skeggs void
nvkm_object_remove(struct nvkm_object * object)63110cccffSBen Skeggs nvkm_object_remove(struct nvkm_object *object)
64110cccffSBen Skeggs {
65*b7cc4ff7SDave Airlie unsigned long flags;
66*b7cc4ff7SDave Airlie
67*b7cc4ff7SDave Airlie spin_lock_irqsave(&object->client->obj_lock, flags);
68110cccffSBen Skeggs if (!RB_EMPTY_NODE(&object->node))
69110cccffSBen Skeggs rb_erase(&object->node, &object->client->objroot);
70*b7cc4ff7SDave Airlie spin_unlock_irqrestore(&object->client->obj_lock, flags);
71110cccffSBen Skeggs }
72110cccffSBen Skeggs
73110cccffSBen Skeggs bool
nvkm_object_insert(struct nvkm_object * object)74110cccffSBen Skeggs nvkm_object_insert(struct nvkm_object *object)
75110cccffSBen Skeggs {
76*b7cc4ff7SDave Airlie struct rb_node **ptr;
77110cccffSBen Skeggs struct rb_node *parent = NULL;
78*b7cc4ff7SDave Airlie unsigned long flags;
79110cccffSBen Skeggs
80*b7cc4ff7SDave Airlie spin_lock_irqsave(&object->client->obj_lock, flags);
81*b7cc4ff7SDave Airlie ptr = &object->client->objroot.rb_node;
82110cccffSBen Skeggs while (*ptr) {
83110cccffSBen Skeggs struct nvkm_object *this = rb_entry(*ptr, typeof(*this), node);
84110cccffSBen Skeggs parent = *ptr;
85*b7cc4ff7SDave Airlie if (object->object < this->object) {
86110cccffSBen Skeggs ptr = &parent->rb_left;
87*b7cc4ff7SDave Airlie } else if (object->object > this->object) {
88110cccffSBen Skeggs ptr = &parent->rb_right;
89*b7cc4ff7SDave Airlie } else {
90*b7cc4ff7SDave Airlie spin_unlock_irqrestore(&object->client->obj_lock, flags);
91110cccffSBen Skeggs return false;
92110cccffSBen Skeggs }
93*b7cc4ff7SDave Airlie }
94110cccffSBen Skeggs
95110cccffSBen Skeggs rb_link_node(&object->node, parent, ptr);
96110cccffSBen Skeggs rb_insert_color(&object->node, &object->client->objroot);
97*b7cc4ff7SDave Airlie spin_unlock_irqrestore(&object->client->obj_lock, flags);
98110cccffSBen Skeggs return true;
99110cccffSBen Skeggs }
100110cccffSBen Skeggs
101c39f472eSBen Skeggs int
nvkm_object_mthd(struct nvkm_object * object,u32 mthd,void * data,u32 size)102cbea21e2SBen Skeggs nvkm_object_mthd(struct nvkm_object *object, u32 mthd, void *data, u32 size)
103cbea21e2SBen Skeggs {
104cbea21e2SBen Skeggs if (likely(object->func->mthd))
105cbea21e2SBen Skeggs return object->func->mthd(object, mthd, data, size);
106cbea21e2SBen Skeggs return -ENODEV;
107cbea21e2SBen Skeggs }
108cbea21e2SBen Skeggs
109cbea21e2SBen Skeggs int
nvkm_object_ntfy(struct nvkm_object * object,u32 mthd,struct nvkm_event ** pevent)110cbea21e2SBen Skeggs nvkm_object_ntfy(struct nvkm_object *object, u32 mthd,
111cbea21e2SBen Skeggs struct nvkm_event **pevent)
112cbea21e2SBen Skeggs {
113cbea21e2SBen Skeggs if (likely(object->func->ntfy))
114cbea21e2SBen Skeggs return object->func->ntfy(object, mthd, pevent);
115cbea21e2SBen Skeggs return -ENODEV;
116cbea21e2SBen Skeggs }
117cbea21e2SBen Skeggs
118cbea21e2SBen Skeggs int
nvkm_object_map(struct nvkm_object * object,void * argv,u32 argc,enum nvkm_object_map * type,u64 * addr,u64 * size)11901326050SBen Skeggs nvkm_object_map(struct nvkm_object *object, void *argv, u32 argc,
12001326050SBen Skeggs enum nvkm_object_map *type, u64 *addr, u64 *size)
121cbea21e2SBen Skeggs {
122cbea21e2SBen Skeggs if (likely(object->func->map))
12301326050SBen Skeggs return object->func->map(object, argv, argc, type, addr, size);
124cbea21e2SBen Skeggs return -ENODEV;
125cbea21e2SBen Skeggs }
126cbea21e2SBen Skeggs
127cbea21e2SBen Skeggs int
nvkm_object_unmap(struct nvkm_object * object)1288e0042d5SBen Skeggs nvkm_object_unmap(struct nvkm_object *object)
1298e0042d5SBen Skeggs {
1308e0042d5SBen Skeggs if (likely(object->func->unmap))
1318e0042d5SBen Skeggs return object->func->unmap(object);
1328e0042d5SBen Skeggs return -ENODEV;
1338e0042d5SBen Skeggs }
1348e0042d5SBen Skeggs
1358e0042d5SBen Skeggs int
nvkm_object_rd08(struct nvkm_object * object,u64 addr,u8 * data)136cfdc4c44SBen Skeggs nvkm_object_rd08(struct nvkm_object *object, u64 addr, u8 *data)
137cfdc4c44SBen Skeggs {
138cbea21e2SBen Skeggs if (likely(object->func->rd08))
139cbea21e2SBen Skeggs return object->func->rd08(object, addr, data);
140cbea21e2SBen Skeggs return -ENODEV;
141cbea21e2SBen Skeggs }
142cfdc4c44SBen Skeggs
143cfdc4c44SBen Skeggs int
nvkm_object_rd16(struct nvkm_object * object,u64 addr,u16 * data)144cfdc4c44SBen Skeggs nvkm_object_rd16(struct nvkm_object *object, u64 addr, u16 *data)
145cfdc4c44SBen Skeggs {
146cbea21e2SBen Skeggs if (likely(object->func->rd16))
147cbea21e2SBen Skeggs return object->func->rd16(object, addr, data);
148cbea21e2SBen Skeggs return -ENODEV;
149cbea21e2SBen Skeggs }
150cfdc4c44SBen Skeggs
151cfdc4c44SBen Skeggs int
nvkm_object_rd32(struct nvkm_object * object,u64 addr,u32 * data)152cfdc4c44SBen Skeggs nvkm_object_rd32(struct nvkm_object *object, u64 addr, u32 *data)
153cfdc4c44SBen Skeggs {
154cbea21e2SBen Skeggs if (likely(object->func->rd32))
155cbea21e2SBen Skeggs return object->func->rd32(object, addr, data);
156cfdc4c44SBen Skeggs return -ENODEV;
157cfdc4c44SBen Skeggs }
158cfdc4c44SBen Skeggs
159cfdc4c44SBen Skeggs int
nvkm_object_wr08(struct nvkm_object * object,u64 addr,u8 data)160cfdc4c44SBen Skeggs nvkm_object_wr08(struct nvkm_object *object, u64 addr, u8 data)
161cfdc4c44SBen Skeggs {
162cbea21e2SBen Skeggs if (likely(object->func->wr08))
163cbea21e2SBen Skeggs return object->func->wr08(object, addr, data);
164cbea21e2SBen Skeggs return -ENODEV;
165cbea21e2SBen Skeggs }
166cfdc4c44SBen Skeggs
167cfdc4c44SBen Skeggs int
nvkm_object_wr16(struct nvkm_object * object,u64 addr,u16 data)168cfdc4c44SBen Skeggs nvkm_object_wr16(struct nvkm_object *object, u64 addr, u16 data)
169cfdc4c44SBen Skeggs {
170cbea21e2SBen Skeggs if (likely(object->func->wr16))
171cbea21e2SBen Skeggs return object->func->wr16(object, addr, data);
172cbea21e2SBen Skeggs return -ENODEV;
173cbea21e2SBen Skeggs }
174cfdc4c44SBen Skeggs
175cfdc4c44SBen Skeggs int
nvkm_object_wr32(struct nvkm_object * object,u64 addr,u32 data)176cfdc4c44SBen Skeggs nvkm_object_wr32(struct nvkm_object *object, u64 addr, u32 data)
177cfdc4c44SBen Skeggs {
178cbea21e2SBen Skeggs if (likely(object->func->wr32))
179cbea21e2SBen Skeggs return object->func->wr32(object, addr, data);
180cbea21e2SBen Skeggs return -ENODEV;
181cbea21e2SBen Skeggs }
182cbea21e2SBen Skeggs
183cbea21e2SBen Skeggs int
nvkm_object_bind(struct nvkm_object * object,struct nvkm_gpuobj * gpuobj,int align,struct nvkm_gpuobj ** pgpuobj)184cbea21e2SBen Skeggs nvkm_object_bind(struct nvkm_object *object, struct nvkm_gpuobj *gpuobj,
185cbea21e2SBen Skeggs int align, struct nvkm_gpuobj **pgpuobj)
186cbea21e2SBen Skeggs {
187cbea21e2SBen Skeggs if (object->func->bind)
188cbea21e2SBen Skeggs return object->func->bind(object, gpuobj, align, pgpuobj);
189cbea21e2SBen Skeggs return -ENODEV;
190cbea21e2SBen Skeggs }
191cbea21e2SBen Skeggs
192cbea21e2SBen Skeggs int
nvkm_object_fini(struct nvkm_object * object,bool suspend)193cbea21e2SBen Skeggs nvkm_object_fini(struct nvkm_object *object, bool suspend)
194cbea21e2SBen Skeggs {
195fbd58ebdSBen Skeggs const char *action = suspend ? "suspend" : "fini";
196fbd58ebdSBen Skeggs struct nvkm_object *child;
197fbd58ebdSBen Skeggs s64 time;
198fbd58ebdSBen Skeggs int ret;
199fbd58ebdSBen Skeggs
200fbd58ebdSBen Skeggs nvif_debug(object, "%s children...\n", action);
201fbd58ebdSBen Skeggs time = ktime_to_us(ktime_get());
20283775e15SBen Skeggs list_for_each_entry_reverse(child, &object->tree, head) {
203fbd58ebdSBen Skeggs ret = nvkm_object_fini(child, suspend);
204fbd58ebdSBen Skeggs if (ret && suspend)
205fbd58ebdSBen Skeggs goto fail_child;
206fbd58ebdSBen Skeggs }
207fbd58ebdSBen Skeggs
208fbd58ebdSBen Skeggs nvif_debug(object, "%s running...\n", action);
209fbd58ebdSBen Skeggs if (object->func->fini) {
210fbd58ebdSBen Skeggs ret = object->func->fini(object, suspend);
211fbd58ebdSBen Skeggs if (ret) {
212fbd58ebdSBen Skeggs nvif_error(object, "%s failed with %d\n", action, ret);
213fbd58ebdSBen Skeggs if (suspend)
214fbd58ebdSBen Skeggs goto fail;
215fbd58ebdSBen Skeggs }
216fbd58ebdSBen Skeggs }
217fbd58ebdSBen Skeggs
218fbd58ebdSBen Skeggs time = ktime_to_us(ktime_get()) - time;
219fbd58ebdSBen Skeggs nvif_debug(object, "%s completed in %lldus\n", action, time);
220cbea21e2SBen Skeggs return 0;
221fbd58ebdSBen Skeggs
222fbd58ebdSBen Skeggs fail:
223fbd58ebdSBen Skeggs if (object->func->init) {
224fbd58ebdSBen Skeggs int rret = object->func->init(object);
225fbd58ebdSBen Skeggs if (rret)
226fbd58ebdSBen Skeggs nvif_fatal(object, "failed to restart, %d\n", rret);
227fbd58ebdSBen Skeggs }
228fbd58ebdSBen Skeggs fail_child:
229fbd58ebdSBen Skeggs list_for_each_entry_continue_reverse(child, &object->tree, head) {
230fbd58ebdSBen Skeggs nvkm_object_init(child);
231fbd58ebdSBen Skeggs }
232fbd58ebdSBen Skeggs return ret;
233cbea21e2SBen Skeggs }
234cbea21e2SBen Skeggs
235cbea21e2SBen Skeggs int
nvkm_object_init(struct nvkm_object * object)236cbea21e2SBen Skeggs nvkm_object_init(struct nvkm_object *object)
237cbea21e2SBen Skeggs {
238fbd58ebdSBen Skeggs struct nvkm_object *child;
239fbd58ebdSBen Skeggs s64 time;
240fbd58ebdSBen Skeggs int ret;
241fbd58ebdSBen Skeggs
242fbd58ebdSBen Skeggs nvif_debug(object, "init running...\n");
243fbd58ebdSBen Skeggs time = ktime_to_us(ktime_get());
244fbd58ebdSBen Skeggs if (object->func->init) {
245fbd58ebdSBen Skeggs ret = object->func->init(object);
246fbd58ebdSBen Skeggs if (ret)
247fbd58ebdSBen Skeggs goto fail;
248cbea21e2SBen Skeggs }
249cbea21e2SBen Skeggs
250fbd58ebdSBen Skeggs nvif_debug(object, "init children...\n");
251fbd58ebdSBen Skeggs list_for_each_entry(child, &object->tree, head) {
252fbd58ebdSBen Skeggs ret = nvkm_object_init(child);
253fbd58ebdSBen Skeggs if (ret)
254fbd58ebdSBen Skeggs goto fail_child;
255fbd58ebdSBen Skeggs }
256fbd58ebdSBen Skeggs
257fbd58ebdSBen Skeggs time = ktime_to_us(ktime_get()) - time;
258fbd58ebdSBen Skeggs nvif_debug(object, "init completed in %lldus\n", time);
259fbd58ebdSBen Skeggs return 0;
260fbd58ebdSBen Skeggs
261fbd58ebdSBen Skeggs fail_child:
262fbd58ebdSBen Skeggs list_for_each_entry_continue_reverse(child, &object->tree, head)
263fbd58ebdSBen Skeggs nvkm_object_fini(child, false);
264fbd58ebdSBen Skeggs fail:
265fbd58ebdSBen Skeggs nvif_error(object, "init failed with %d\n", ret);
266fbd58ebdSBen Skeggs if (object->func->fini)
267fbd58ebdSBen Skeggs object->func->fini(object, false);
268fbd58ebdSBen Skeggs return ret;
269fbd58ebdSBen Skeggs }
270fbd58ebdSBen Skeggs
271fbd58ebdSBen Skeggs void *
nvkm_object_dtor(struct nvkm_object * object)272fbd58ebdSBen Skeggs nvkm_object_dtor(struct nvkm_object *object)
273fbd58ebdSBen Skeggs {
274fbd58ebdSBen Skeggs struct nvkm_object *child, *ctemp;
275fbd58ebdSBen Skeggs void *data = object;
276fbd58ebdSBen Skeggs s64 time;
277fbd58ebdSBen Skeggs
278fbd58ebdSBen Skeggs nvif_debug(object, "destroy children...\n");
279fbd58ebdSBen Skeggs time = ktime_to_us(ktime_get());
280fbd58ebdSBen Skeggs list_for_each_entry_safe(child, ctemp, &object->tree, head) {
281fbd58ebdSBen Skeggs nvkm_object_del(&child);
282fbd58ebdSBen Skeggs }
283fbd58ebdSBen Skeggs
284fbd58ebdSBen Skeggs nvif_debug(object, "destroy running...\n");
2858e0042d5SBen Skeggs nvkm_object_unmap(object);
286fbd58ebdSBen Skeggs if (object->func->dtor)
287fbd58ebdSBen Skeggs data = object->func->dtor(object);
288fbd58ebdSBen Skeggs nvkm_engine_unref(&object->engine);
289fbd58ebdSBen Skeggs time = ktime_to_us(ktime_get()) - time;
290fbd58ebdSBen Skeggs nvif_debug(object, "destroy completed in %lldus...\n", time);
291fbd58ebdSBen Skeggs return data;
292fbd58ebdSBen Skeggs }
293fbd58ebdSBen Skeggs
294fbd58ebdSBen Skeggs void
nvkm_object_del(struct nvkm_object ** pobject)295cbea21e2SBen Skeggs nvkm_object_del(struct nvkm_object **pobject)
296cbea21e2SBen Skeggs {
297cbea21e2SBen Skeggs struct nvkm_object *object = *pobject;
298cbea21e2SBen Skeggs if (object && !WARN_ON(!object->func)) {
299fbd58ebdSBen Skeggs *pobject = nvkm_object_dtor(object);
300110cccffSBen Skeggs nvkm_object_remove(object);
301fbd58ebdSBen Skeggs list_del(&object->head);
302cbea21e2SBen Skeggs kfree(*pobject);
303cbea21e2SBen Skeggs *pobject = NULL;
304cbea21e2SBen Skeggs }
305cbea21e2SBen Skeggs }
306cbea21e2SBen Skeggs
307cbea21e2SBen Skeggs void
nvkm_object_ctor(const struct nvkm_object_func * func,const struct nvkm_oclass * oclass,struct nvkm_object * object)308cbea21e2SBen Skeggs nvkm_object_ctor(const struct nvkm_object_func *func,
309cbea21e2SBen Skeggs const struct nvkm_oclass *oclass, struct nvkm_object *object)
310cbea21e2SBen Skeggs {
311cbea21e2SBen Skeggs object->func = func;
312cbea21e2SBen Skeggs object->client = oclass->client;
3136cf813fbSBen Skeggs object->engine = nvkm_engine_ref(oclass->engine);
31468f3f702SBen Skeggs object->oclass = oclass->base.oclass;
315cbea21e2SBen Skeggs object->handle = oclass->handle;
316843faa03SBen Skeggs object->route = oclass->route;
317843faa03SBen Skeggs object->token = oclass->token;
318843faa03SBen Skeggs object->object = oclass->object;
319fbd58ebdSBen Skeggs INIT_LIST_HEAD(&object->head);
320fbd58ebdSBen Skeggs INIT_LIST_HEAD(&object->tree);
321fbd58ebdSBen Skeggs RB_CLEAR_NODE(&object->node);
32289ed10a5SBen Skeggs WARN_ON(IS_ERR(object->engine));
323cbea21e2SBen Skeggs }
324cbea21e2SBen Skeggs
325cbea21e2SBen Skeggs int
nvkm_object_new_(const struct nvkm_object_func * func,const struct nvkm_oclass * oclass,void * data,u32 size,struct nvkm_object ** pobject)326cbea21e2SBen Skeggs nvkm_object_new_(const struct nvkm_object_func *func,
327cbea21e2SBen Skeggs const struct nvkm_oclass *oclass, void *data, u32 size,
328cbea21e2SBen Skeggs struct nvkm_object **pobject)
329cbea21e2SBen Skeggs {
330cbea21e2SBen Skeggs if (size == 0) {
331cbea21e2SBen Skeggs if (!(*pobject = kzalloc(sizeof(**pobject), GFP_KERNEL)))
332cbea21e2SBen Skeggs return -ENOMEM;
333cbea21e2SBen Skeggs nvkm_object_ctor(func, oclass, *pobject);
334cbea21e2SBen Skeggs return 0;
335cbea21e2SBen Skeggs }
336cbea21e2SBen Skeggs return -ENOSYS;
337cbea21e2SBen Skeggs }
338cbea21e2SBen Skeggs
339cbea21e2SBen Skeggs static const struct nvkm_object_func
340cbea21e2SBen Skeggs nvkm_object_func = {
341cbea21e2SBen Skeggs };
342cbea21e2SBen Skeggs
343cbea21e2SBen Skeggs int
nvkm_object_new(const struct nvkm_oclass * oclass,void * data,u32 size,struct nvkm_object ** pobject)344cbea21e2SBen Skeggs nvkm_object_new(const struct nvkm_oclass *oclass, void *data, u32 size,
345cbea21e2SBen Skeggs struct nvkm_object **pobject)
346cbea21e2SBen Skeggs {
347cbea21e2SBen Skeggs const struct nvkm_object_func *func =
348cbea21e2SBen Skeggs oclass->base.func ? oclass->base.func : &nvkm_object_func;
349cbea21e2SBen Skeggs return nvkm_object_new_(func, oclass, data, size, pobject);
350cbea21e2SBen Skeggs }
351