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 |
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 |
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 |
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 |
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 * |
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 * |
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 * |
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 * |
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 |
227 | nouveau_handle_put(struct nouveau_handle *handle) |
228 | { |
229 | if (handle) |
230 | nouveau_namedb_put(handle); |
231 | } |
232 | |