Commit | Line | Data |
---|---|---|
9274f4a9 BS |
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 | |
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 | |
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 | |
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 | ||
82c805ab | 112 | handle = kzalloc(sizeof(*handle), GFP_KERNEL); |
9274f4a9 BS |
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"); | |
82c805ab MS |
149 | |
150 | *phandle = handle; | |
151 | ||
9274f4a9 BS |
152 | return 0; |
153 | } | |
154 | ||
155 | void | |
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 * | |
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 | } | |
72a14827 BS |
193 | |
194 | struct nouveau_handle * | |
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 * | |
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 * | |
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 | |
222 | nouveau_handle_put(struct nouveau_handle *handle) | |
223 | { | |
224 | if (handle) | |
225 | nouveau_namedb_put(handle); | |
226 | } |