• 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 
150 	*phandle = handle;
151 
152 	return 0;
153 }
154 
155 void
nouveau_handle_destroy(struct nouveau_handle * handle)156 nouveau_handle_destroy(struct nouveau_handle *handle)
157 {
158 	struct nouveau_handle *item, *temp;
159 
160 	hprintk(handle, TRACE, "destroy running\n");
161 	list_for_each_entry_safe(item, temp, &handle->tree, head) {
162 		nouveau_handle_destroy(item);
163 	}
164 	list_del(&handle->head);
165 
166 	if (handle->priv != ~0) {
167 		struct nouveau_object *parent = handle->parent->object;
168 		nv_parent(parent)->object_detach(parent, handle->priv);
169 	}
170 
171 	hprintk(handle, TRACE, "destroy completed\n");
172 	nouveau_namedb_remove(handle);
173 	kfree(handle);
174 }
175 
176 struct nouveau_object *
nouveau_handle_ref(struct nouveau_object * parent,u32 name)177 nouveau_handle_ref(struct nouveau_object *parent, u32 name)
178 {
179 	struct nouveau_object *object = NULL;
180 	struct nouveau_handle *handle;
181 
182 	while (!nv_iclass(parent, NV_NAMEDB_CLASS))
183 		parent = parent->parent;
184 
185 	handle = nouveau_namedb_get(nv_namedb(parent), name);
186 	if (handle) {
187 		nouveau_object_ref(handle->object, &object);
188 		nouveau_namedb_put(handle);
189 	}
190 
191 	return object;
192 }
193 
194 struct nouveau_handle *
nouveau_handle_get_class(struct nouveau_object * engctx,u16 oclass)195 nouveau_handle_get_class(struct nouveau_object *engctx, u16 oclass)
196 {
197 	struct nouveau_namedb *namedb;
198 	if (engctx && (namedb = (void *)nv_pclass(engctx, NV_NAMEDB_CLASS)))
199 		return nouveau_namedb_get_class(namedb, oclass);
200 	return NULL;
201 }
202 
203 struct nouveau_handle *
nouveau_handle_get_vinst(struct nouveau_object * engctx,u64 vinst)204 nouveau_handle_get_vinst(struct nouveau_object *engctx, u64 vinst)
205 {
206 	struct nouveau_namedb *namedb;
207 	if (engctx && (namedb = (void *)nv_pclass(engctx, NV_NAMEDB_CLASS)))
208 		return nouveau_namedb_get_vinst(namedb, vinst);
209 	return NULL;
210 }
211 
212 struct nouveau_handle *
nouveau_handle_get_cinst(struct nouveau_object * engctx,u32 cinst)213 nouveau_handle_get_cinst(struct nouveau_object *engctx, u32 cinst)
214 {
215 	struct nouveau_namedb *namedb;
216 	if (engctx && (namedb = (void *)nv_pclass(engctx, NV_NAMEDB_CLASS)))
217 		return nouveau_namedb_get_cinst(namedb, cinst);
218 	return NULL;
219 }
220 
221 void
nouveau_handle_put(struct nouveau_handle * handle)222 nouveau_handle_put(struct nouveau_handle *handle)
223 {
224 	if (handle)
225 		nouveau_namedb_put(handle);
226 }
227