1 /* $NetBSD: nouveau_core_handle.c,v 1.2 2014/08/06 13:35:13 riastradh Exp $ */
2
3 /*
4 * Copyright 2012 Red Hat Inc.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, including without limitation
9 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 * and/or sell copies of the Software, and to permit persons to whom the
11 * Software is furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
20 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22 * OTHER DEALINGS IN THE SOFTWARE.
23 *
24 * Authors: Ben Skeggs
25 */
26
27 #include <sys/cdefs.h>
28 __KERNEL_RCSID(0, "$NetBSD: nouveau_core_handle.c,v 1.2 2014/08/06 13:35:13 riastradh Exp $");
29
30 #include <core/object.h>
31 #include <core/handle.h>
32 #include <core/client.h>
33
34 #define hprintk(h,l,f,a...) do { \
35 struct nouveau_client *c = nouveau_client((h)->object); \
36 struct nouveau_handle *p = (h)->parent; u32 n = p ? p->name : ~0; \
37 nv_printk((c), l, "0x%08x:0x%08x "f, n, (h)->name, ##a); \
38 } while(0)
39
40 int
nouveau_handle_init(struct nouveau_handle * handle)41 nouveau_handle_init(struct nouveau_handle *handle)
42 {
43 struct nouveau_handle *item;
44 int ret;
45
46 hprintk(handle, TRACE, "init running\n");
47 ret = nouveau_object_inc(handle->object);
48 if (ret)
49 return ret;
50
51 hprintk(handle, TRACE, "init children\n");
52 list_for_each_entry(item, &handle->tree, head) {
53 ret = nouveau_handle_init(item);
54 if (ret)
55 goto fail;
56 }
57
58 hprintk(handle, TRACE, "init completed\n");
59 return 0;
60 fail:
61 hprintk(handle, ERROR, "init failed with %d\n", ret);
62 list_for_each_entry_continue_reverse(item, &handle->tree, head) {
63 nouveau_handle_fini(item, false);
64 }
65
66 nouveau_object_dec(handle->object, false);
67 return ret;
68 }
69
70 int
nouveau_handle_fini(struct nouveau_handle * handle,bool suspend)71 nouveau_handle_fini(struct nouveau_handle *handle, bool suspend)
72 {
73 static const char *name[2] = { "fini", "suspend" };
74 struct nouveau_handle *item;
75 int ret;
76
77 hprintk(handle, TRACE, "%s children\n", name[suspend]);
78 list_for_each_entry(item, &handle->tree, head) {
79 ret = nouveau_handle_fini(item, suspend);
80 if (ret && suspend)
81 goto fail;
82 }
83
84 hprintk(handle, TRACE, "%s running\n", name[suspend]);
85 if (handle->object) {
86 ret = nouveau_object_dec(handle->object, suspend);
87 if (ret && suspend)
88 goto fail;
89 }
90
91 hprintk(handle, TRACE, "%s completed\n", name[suspend]);
92 return 0;
93 fail:
94 hprintk(handle, ERROR, "%s failed with %d\n", name[suspend], ret);
95 list_for_each_entry_continue_reverse(item, &handle->tree, head) {
96 int rret = nouveau_handle_init(item);
97 if (rret)
98 hprintk(handle, FATAL, "failed to restart, %d\n", rret);
99 }
100
101 return ret;
102 }
103
104 int
nouveau_handle_create(struct nouveau_object * parent,u32 _parent,u32 _handle,struct nouveau_object * object,struct nouveau_handle ** phandle)105 nouveau_handle_create(struct nouveau_object *parent, u32 _parent, u32 _handle,
106 struct nouveau_object *object,
107 struct nouveau_handle **phandle)
108 {
109 struct nouveau_object *namedb;
110 struct nouveau_handle *handle;
111 int ret;
112
113 namedb = parent;
114 while (!nv_iclass(namedb, NV_NAMEDB_CLASS))
115 namedb = namedb->parent;
116
117 handle = kzalloc(sizeof(*handle), GFP_KERNEL);
118 if (!handle)
119 return -ENOMEM;
120
121 INIT_LIST_HEAD(&handle->head);
122 INIT_LIST_HEAD(&handle->tree);
123 handle->name = _handle;
124 handle->priv = ~0;
125
126 ret = nouveau_namedb_insert(nv_namedb(namedb), _handle, object, handle);
127 if (ret) {
128 kfree(handle);
129 return ret;
130 }
131
132 if (nv_parent(parent)->object_attach) {
133 ret = nv_parent(parent)->object_attach(parent, object, _handle);
134 if (ret < 0) {
135 nouveau_handle_destroy(handle);
136 return ret;
137 }
138
139 handle->priv = ret;
140 }
141
142 if (object != namedb) {
143 while (!nv_iclass(namedb, NV_CLIENT_CLASS))
144 namedb = namedb->parent;
145
146 handle->parent = nouveau_namedb_get(nv_namedb(namedb), _parent);
147 if (handle->parent) {
148 list_add(&handle->head, &handle->parent->tree);
149 nouveau_namedb_put(handle->parent);
150 }
151 }
152
153 hprintk(handle, TRACE, "created\n");
154
155 *phandle = handle;
156
157 return 0;
158 }
159
160 void
nouveau_handle_destroy(struct nouveau_handle * handle)161 nouveau_handle_destroy(struct nouveau_handle *handle)
162 {
163 struct nouveau_handle *item, *temp;
164
165 hprintk(handle, TRACE, "destroy running\n");
166 list_for_each_entry_safe(item, temp, &handle->tree, head) {
167 nouveau_handle_destroy(item);
168 }
169 list_del(&handle->head);
170
171 if (handle->priv != ~0) {
172 struct nouveau_object *parent = handle->parent->object;
173 nv_parent(parent)->object_detach(parent, handle->priv);
174 }
175
176 hprintk(handle, TRACE, "destroy completed\n");
177 nouveau_namedb_remove(handle);
178 kfree(handle);
179 }
180
181 struct nouveau_object *
nouveau_handle_ref(struct nouveau_object * parent,u32 name)182 nouveau_handle_ref(struct nouveau_object *parent, u32 name)
183 {
184 struct nouveau_object *object = NULL;
185 struct nouveau_handle *handle;
186
187 while (!nv_iclass(parent, NV_NAMEDB_CLASS))
188 parent = parent->parent;
189
190 handle = nouveau_namedb_get(nv_namedb(parent), name);
191 if (handle) {
192 nouveau_object_ref(handle->object, &object);
193 nouveau_namedb_put(handle);
194 }
195
196 return object;
197 }
198
199 struct nouveau_handle *
nouveau_handle_get_class(struct nouveau_object * engctx,u16 oclass)200 nouveau_handle_get_class(struct nouveau_object *engctx, u16 oclass)
201 {
202 struct nouveau_namedb *namedb;
203 if (engctx && (namedb = (void *)nv_pclass(engctx, NV_NAMEDB_CLASS)))
204 return nouveau_namedb_get_class(namedb, oclass);
205 return NULL;
206 }
207
208 struct nouveau_handle *
nouveau_handle_get_vinst(struct nouveau_object * engctx,u64 vinst)209 nouveau_handle_get_vinst(struct nouveau_object *engctx, u64 vinst)
210 {
211 struct nouveau_namedb *namedb;
212 if (engctx && (namedb = (void *)nv_pclass(engctx, NV_NAMEDB_CLASS)))
213 return nouveau_namedb_get_vinst(namedb, vinst);
214 return NULL;
215 }
216
217 struct nouveau_handle *
nouveau_handle_get_cinst(struct nouveau_object * engctx,u32 cinst)218 nouveau_handle_get_cinst(struct nouveau_object *engctx, u32 cinst)
219 {
220 struct nouveau_namedb *namedb;
221 if (engctx && (namedb = (void *)nv_pclass(engctx, NV_NAMEDB_CLASS)))
222 return nouveau_namedb_get_cinst(namedb, cinst);
223 return NULL;
224 }
225
226 void
nouveau_handle_put(struct nouveau_handle * handle)227 nouveau_handle_put(struct nouveau_handle *handle)
228 {
229 if (handle)
230 nouveau_namedb_put(handle);
231 }
232