• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/handle.h>
27 #include <core/client.h>
28 
29 #define hprintk(h,l,f,a...) do {                                               \
30 	struct nouveau_client *c = nouveau_client((h)->object);                \
31 	struct nouveau_handle *p = (h)->parent; u32 n = p ? p->name : ~0;      \
32 	nv_printk((c), l, "0x%08x:0x%08x "f, n, (h)->name, ##a);               \
33 } while(0)
34 
35 int
nouveau_handle_init(struct nouveau_handle * handle)36 nouveau_handle_init(struct nouveau_handle *handle)
37 {
38 	struct nouveau_handle *item;
39 	int ret;
40 
41 	hprintk(handle, TRACE, "init running\n");
42 	ret = nouveau_object_inc(handle->object);
43 	if (ret)
44 		return ret;
45 
46 	hprintk(handle, TRACE, "init children\n");
47 	list_for_each_entry(item, &handle->tree, head) {
48 		ret = nouveau_handle_init(item);
49 		if (ret)
50 			goto fail;
51 	}
52 
53 	hprintk(handle, TRACE, "init completed\n");
54 	return 0;
55 fail:
56 	hprintk(handle, ERROR, "init failed with %d\n", ret);
57 	list_for_each_entry_continue_reverse(item, &handle->tree, head) {
58 		nouveau_handle_fini(item, false);
59 	}
60 
61 	nouveau_object_dec(handle->object, false);
62 	return ret;
63 }
64 
65 int
nouveau_handle_fini(struct nouveau_handle * handle,bool suspend)66 nouveau_handle_fini(struct nouveau_handle *handle, bool suspend)
67 {
68 	static char *name[2] = { "fini", "suspend" };
69 	struct nouveau_handle *item;
70 	int ret;
71 
72 	hprintk(handle, TRACE, "%s children\n", name[suspend]);
73 	list_for_each_entry(item, &handle->tree, head) {
74 		ret = nouveau_handle_fini(item, suspend);
75 		if (ret && suspend)
76 			goto fail;
77 	}
78 
79 	hprintk(handle, TRACE, "%s running\n", name[suspend]);
80 	if (handle->object) {
81 		ret = nouveau_object_dec(handle->object, suspend);
82 		if (ret && suspend)
83 			goto fail;
84 	}
85 
86 	hprintk(handle, TRACE, "%s completed\n", name[suspend]);
87 	return 0;
88 fail:
89 	hprintk(handle, ERROR, "%s failed with %d\n", name[suspend], ret);
90 	list_for_each_entry_continue_reverse(item, &handle->tree, head) {
91 		int rret = nouveau_handle_init(item);
92 		if (rret)
93 			hprintk(handle, FATAL, "failed to restart, %d\n", rret);
94 	}
95 
96 	return ret;
97 }
98 
99 int
nouveau_handle_create(struct nouveau_object * parent,u32 _parent,u32 _handle,struct nouveau_object * object,struct nouveau_handle ** phandle)100 nouveau_handle_create(struct nouveau_object *parent, u32 _parent, u32 _handle,
101 		      struct nouveau_object *object,
102 		      struct nouveau_handle **phandle)
103 {
104 	struct nouveau_object *namedb;
105 	struct nouveau_handle *handle;
106 	int ret;
107 
108 	namedb = parent;
109 	while (!nv_iclass(namedb, NV_NAMEDB_CLASS))
110 		namedb = namedb->parent;
111 
112 	handle = kzalloc(sizeof(*handle), GFP_KERNEL);
113 	if (!handle)
114 		return -ENOMEM;
115 
116 	INIT_LIST_HEAD(&handle->head);
117 	INIT_LIST_HEAD(&handle->tree);
118 	handle->name = _handle;
119 	handle->priv = ~0;
120 
121 	ret = nouveau_namedb_insert(nv_namedb(namedb), _handle, object, handle);
122 	if (ret) {
123 		kfree(handle);
124 		return ret;
125 	}
126 
127 	if (nv_parent(parent)->object_attach) {
128 		ret = nv_parent(parent)->object_attach(parent, object, _handle);
129 		if (ret < 0) {
130 			nouveau_handle_destroy(handle);
131 			return ret;
132 		}
133 
134 		handle->priv = ret;
135 	}
136 
137 	if (object != namedb) {
138 		while (!nv_iclass(namedb, NV_CLIENT_CLASS))
139 			namedb = namedb->parent;
140 
141 		handle->parent = nouveau_namedb_get(nv_namedb(namedb), _parent);
142 		if (handle->parent) {
143 			list_add(&handle->head, &handle->parent->tree);
144 			nouveau_namedb_put(handle->parent);
145 		}
146 	}
147 
148 	hprintk(handle, TRACE, "created\n");
149 	*phandle = handle;
150 	return 0;
151 }
152 
153 void
nouveau_handle_destroy(struct nouveau_handle * handle)154 nouveau_handle_destroy(struct nouveau_handle *handle)
155 {
156 	struct nouveau_handle *item, *temp;
157 
158 	hprintk(handle, TRACE, "destroy running\n");
159 	list_for_each_entry_safe(item, temp, &handle->tree, head) {
160 		nouveau_handle_destroy(item);
161 	}
162 	list_del(&handle->head);
163 
164 	if (handle->priv != ~0) {
165 		struct nouveau_object *parent = handle->parent->object;
166 		nv_parent(parent)->object_detach(parent, handle->priv);
167 	}
168 
169 	hprintk(handle, TRACE, "destroy completed\n");
170 	nouveau_namedb_remove(handle);
171 	kfree(handle);
172 }
173 
174 struct nouveau_object *
nouveau_handle_ref(struct nouveau_object * parent,u32 name)175 nouveau_handle_ref(struct nouveau_object *parent, u32 name)
176 {
177 	struct nouveau_object *object = NULL;
178 	struct nouveau_handle *handle;
179 
180 	while (!nv_iclass(parent, NV_NAMEDB_CLASS))
181 		parent = parent->parent;
182 
183 	handle = nouveau_namedb_get(nv_namedb(parent), name);
184 	if (handle) {
185 		nouveau_object_ref(handle->object, &object);
186 		nouveau_namedb_put(handle);
187 	}
188 
189 	return object;
190 }
191 
192 struct nouveau_handle *
nouveau_handle_get_class(struct nouveau_object * engctx,u16 oclass)193 nouveau_handle_get_class(struct nouveau_object *engctx, u16 oclass)
194 {
195 	struct nouveau_namedb *namedb;
196 	if (engctx && (namedb = (void *)nv_pclass(engctx, NV_NAMEDB_CLASS)))
197 		return nouveau_namedb_get_class(namedb, oclass);
198 	return NULL;
199 }
200 
201 struct nouveau_handle *
nouveau_handle_get_vinst(struct nouveau_object * engctx,u64 vinst)202 nouveau_handle_get_vinst(struct nouveau_object *engctx, u64 vinst)
203 {
204 	struct nouveau_namedb *namedb;
205 	if (engctx && (namedb = (void *)nv_pclass(engctx, NV_NAMEDB_CLASS)))
206 		return nouveau_namedb_get_vinst(namedb, vinst);
207 	return NULL;
208 }
209 
210 struct nouveau_handle *
nouveau_handle_get_cinst(struct nouveau_object * engctx,u32 cinst)211 nouveau_handle_get_cinst(struct nouveau_object *engctx, u32 cinst)
212 {
213 	struct nouveau_namedb *namedb;
214 	if (engctx && (namedb = (void *)nv_pclass(engctx, NV_NAMEDB_CLASS)))
215 		return nouveau_namedb_get_cinst(namedb, cinst);
216 	return NULL;
217 }
218 
219 void
nouveau_handle_put(struct nouveau_handle * handle)220 nouveau_handle_put(struct nouveau_handle *handle)
221 {
222 	if (handle)
223 		nouveau_namedb_put(handle);
224 }
225 
226 int
nouveau_handle_new(struct nouveau_object * client,u32 _parent,u32 _handle,u16 _oclass,void * data,u32 size,struct nouveau_object ** pobject)227 nouveau_handle_new(struct nouveau_object *client, u32 _parent, u32 _handle,
228 		   u16 _oclass, void *data, u32 size,
229 		   struct nouveau_object **pobject)
230 {
231 	struct nouveau_object *parent = NULL;
232 	struct nouveau_object *engctx = NULL;
233 	struct nouveau_object *object = NULL;
234 	struct nouveau_object *engine;
235 	struct nouveau_oclass *oclass;
236 	struct nouveau_handle *handle;
237 	int ret;
238 
239 	/* lookup parent object and ensure it *is* a parent */
240 	parent = nouveau_handle_ref(client, _parent);
241 	if (!parent) {
242 		nv_error(client, "parent 0x%08x not found\n", _parent);
243 		return -ENOENT;
244 	}
245 
246 	if (!nv_iclass(parent, NV_PARENT_CLASS)) {
247 		nv_error(parent, "cannot have children\n");
248 		ret = -EINVAL;
249 		goto fail_class;
250 	}
251 
252 	/* check that parent supports the requested subclass */
253 	ret = nouveau_parent_sclass(parent, _oclass, &engine, &oclass);
254 	if (ret) {
255 		nv_debug(parent, "illegal class 0x%04x\n", _oclass);
256 		goto fail_class;
257 	}
258 
259 	/* make sure engine init has been completed *before* any objects
260 	 * it controls are created - the constructors may depend on
261 	 * state calculated at init (ie. default context construction)
262 	 */
263 	if (engine) {
264 		ret = nouveau_object_inc(engine);
265 		if (ret)
266 			goto fail_class;
267 	}
268 
269 	/* if engine requires it, create a context object to insert
270 	 * between the parent and its children (eg. PGRAPH context)
271 	 */
272 	if (engine && nv_engine(engine)->cclass) {
273 		ret = nouveau_object_ctor(parent, engine,
274 					  nv_engine(engine)->cclass,
275 					  data, size, &engctx);
276 		if (ret)
277 			goto fail_engctx;
278 	} else {
279 		nouveau_object_ref(parent, &engctx);
280 	}
281 
282 	/* finally, create new object and bind it to its handle */
283 	ret = nouveau_object_ctor(engctx, engine, oclass, data, size, &object);
284 	*pobject = object;
285 	if (ret)
286 		goto fail_ctor;
287 
288 	ret = nouveau_object_inc(object);
289 	if (ret)
290 		goto fail_init;
291 
292 	ret = nouveau_handle_create(parent, _parent, _handle, object, &handle);
293 	if (ret)
294 		goto fail_handle;
295 
296 	ret = nouveau_handle_init(handle);
297 	if (ret)
298 		nouveau_handle_destroy(handle);
299 
300 fail_handle:
301 	nouveau_object_dec(object, false);
302 fail_init:
303 	nouveau_object_ref(NULL, &object);
304 fail_ctor:
305 	nouveau_object_ref(NULL, &engctx);
306 fail_engctx:
307 	if (engine)
308 		nouveau_object_dec(engine, false);
309 fail_class:
310 	nouveau_object_ref(NULL, &parent);
311 	return ret;
312 }
313 
314 int
nouveau_handle_del(struct nouveau_object * client,u32 _parent,u32 _handle)315 nouveau_handle_del(struct nouveau_object *client, u32 _parent, u32 _handle)
316 {
317 	struct nouveau_object *parent = NULL;
318 	struct nouveau_object *namedb = NULL;
319 	struct nouveau_handle *handle = NULL;
320 
321 	parent = nouveau_handle_ref(client, _parent);
322 	if (!parent)
323 		return -ENOENT;
324 
325 	namedb = nv_pclass(parent, NV_NAMEDB_CLASS);
326 	if (namedb) {
327 		handle = nouveau_namedb_get(nv_namedb(namedb), _handle);
328 		if (handle) {
329 			nouveau_namedb_put(handle);
330 			nouveau_handle_fini(handle, false);
331 			nouveau_handle_destroy(handle);
332 		}
333 	}
334 
335 	nouveau_object_ref(NULL, &parent);
336 	return handle ? 0 : -EINVAL;
337 }
338