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