Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
6296 | serge | 1 | /************************************************************************** |
2 | * |
||
3 | * Copyright © 2014-2015 VMware, Inc., Palo Alto, CA., USA |
||
4 | * All Rights Reserved. |
||
5 | * |
||
6 | * Permission is hereby granted, free of charge, to any person obtaining a |
||
7 | * copy of this software and associated documentation files (the |
||
8 | * "Software"), to deal in the Software without restriction, including |
||
9 | * without limitation the rights to use, copy, modify, merge, publish, |
||
10 | * distribute, sub license, and/or sell copies of the Software, and to |
||
11 | * permit persons to whom the Software is furnished to do so, subject to |
||
12 | * the following conditions: |
||
13 | * |
||
14 | * The above copyright notice and this permission notice (including the |
||
15 | * next paragraph) shall be included in all copies or substantial portions |
||
16 | * of the Software. |
||
17 | * |
||
18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
||
19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
||
20 | * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL |
||
21 | * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, |
||
22 | * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR |
||
23 | * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE |
||
24 | * USE OR OTHER DEALINGS IN THE SOFTWARE. |
||
25 | * |
||
26 | **************************************************************************/ |
||
27 | |||
28 | #include "vmwgfx_drv.h" |
||
29 | #include "vmwgfx_resource_priv.h" |
||
30 | |||
31 | #define VMW_CMDBUF_RES_MAN_HT_ORDER 12 |
||
32 | |||
33 | /** |
||
34 | * struct vmw_cmdbuf_res - Command buffer managed resource entry. |
||
35 | * |
||
36 | * @res: Refcounted pointer to a struct vmw_resource. |
||
37 | * @hash: Hash entry for the manager hash table. |
||
38 | * @head: List head used either by the staging list or the manager list |
||
39 | * of commited resources. |
||
40 | * @state: Staging state of this resource entry. |
||
41 | * @man: Pointer to a resource manager for this entry. |
||
42 | */ |
||
43 | struct vmw_cmdbuf_res { |
||
44 | struct vmw_resource *res; |
||
45 | struct drm_hash_item hash; |
||
46 | struct list_head head; |
||
47 | enum vmw_cmdbuf_res_state state; |
||
48 | struct vmw_cmdbuf_res_manager *man; |
||
49 | }; |
||
50 | |||
51 | /** |
||
52 | * struct vmw_cmdbuf_res_manager - Command buffer resource manager. |
||
53 | * |
||
54 | * @resources: Hash table containing staged and commited command buffer |
||
55 | * resources |
||
56 | * @list: List of commited command buffer resources. |
||
57 | * @dev_priv: Pointer to a device private structure. |
||
58 | * |
||
59 | * @resources and @list are protected by the cmdbuf mutex for now. |
||
60 | */ |
||
61 | struct vmw_cmdbuf_res_manager { |
||
62 | struct drm_open_hash resources; |
||
63 | struct list_head list; |
||
64 | struct vmw_private *dev_priv; |
||
65 | }; |
||
66 | |||
67 | |||
68 | /** |
||
69 | * vmw_cmdbuf_res_lookup - Look up a command buffer resource |
||
70 | * |
||
71 | * @man: Pointer to the command buffer resource manager |
||
72 | * @resource_type: The resource type, that combined with the user key |
||
73 | * identifies the resource. |
||
74 | * @user_key: The user key. |
||
75 | * |
||
76 | * Returns a valid refcounted struct vmw_resource pointer on success, |
||
77 | * an error pointer on failure. |
||
78 | */ |
||
79 | struct vmw_resource * |
||
80 | vmw_cmdbuf_res_lookup(struct vmw_cmdbuf_res_manager *man, |
||
81 | enum vmw_cmdbuf_res_type res_type, |
||
82 | u32 user_key) |
||
83 | { |
||
84 | struct drm_hash_item *hash; |
||
85 | int ret; |
||
86 | unsigned long key = user_key | (res_type << 24); |
||
87 | |||
88 | ret = drm_ht_find_item(&man->resources, key, &hash); |
||
89 | if (unlikely(ret != 0)) |
||
90 | return ERR_PTR(ret); |
||
91 | |||
92 | return vmw_resource_reference |
||
93 | (drm_hash_entry(hash, struct vmw_cmdbuf_res, hash)->res); |
||
94 | } |
||
95 | |||
96 | /** |
||
97 | * vmw_cmdbuf_res_free - Free a command buffer resource. |
||
98 | * |
||
99 | * @man: Pointer to the command buffer resource manager |
||
100 | * @entry: Pointer to a struct vmw_cmdbuf_res. |
||
101 | * |
||
102 | * Frees a struct vmw_cmdbuf_res entry and drops its reference to the |
||
103 | * struct vmw_resource. |
||
104 | */ |
||
105 | static void vmw_cmdbuf_res_free(struct vmw_cmdbuf_res_manager *man, |
||
106 | struct vmw_cmdbuf_res *entry) |
||
107 | { |
||
108 | list_del(&entry->head); |
||
109 | WARN_ON(drm_ht_remove_item(&man->resources, &entry->hash)); |
||
110 | vmw_resource_unreference(&entry->res); |
||
111 | kfree(entry); |
||
112 | } |
||
113 | |||
114 | /** |
||
115 | * vmw_cmdbuf_res_commit - Commit a list of command buffer resource actions |
||
116 | * |
||
117 | * @list: Caller's list of command buffer resource actions. |
||
118 | * |
||
119 | * This function commits a list of command buffer resource |
||
120 | * additions or removals. |
||
121 | * It is typically called when the execbuf ioctl call triggering these |
||
122 | * actions has commited the fifo contents to the device. |
||
123 | */ |
||
124 | void vmw_cmdbuf_res_commit(struct list_head *list) |
||
125 | { |
||
126 | struct vmw_cmdbuf_res *entry, *next; |
||
127 | |||
128 | list_for_each_entry_safe(entry, next, list, head) { |
||
129 | list_del(&entry->head); |
||
130 | if (entry->res->func->commit_notify) |
||
131 | entry->res->func->commit_notify(entry->res, |
||
132 | entry->state); |
||
133 | switch (entry->state) { |
||
134 | case VMW_CMDBUF_RES_ADD: |
||
135 | entry->state = VMW_CMDBUF_RES_COMMITTED; |
||
136 | list_add_tail(&entry->head, &entry->man->list); |
||
137 | break; |
||
138 | case VMW_CMDBUF_RES_DEL: |
||
139 | vmw_resource_unreference(&entry->res); |
||
140 | kfree(entry); |
||
141 | break; |
||
142 | default: |
||
143 | BUG(); |
||
144 | break; |
||
145 | } |
||
146 | } |
||
147 | } |
||
148 | |||
149 | /** |
||
150 | * vmw_cmdbuf_res_revert - Revert a list of command buffer resource actions |
||
151 | * |
||
152 | * @man: Pointer to the command buffer resource manager |
||
153 | * @list: Caller's list of command buffer resource action |
||
154 | * |
||
155 | * This function reverts a list of command buffer resource |
||
156 | * additions or removals. |
||
157 | * It is typically called when the execbuf ioctl call triggering these |
||
158 | * actions failed for some reason, and the command stream was never |
||
159 | * submitted. |
||
160 | */ |
||
161 | void vmw_cmdbuf_res_revert(struct list_head *list) |
||
162 | { |
||
163 | struct vmw_cmdbuf_res *entry, *next; |
||
164 | int ret; |
||
165 | |||
166 | list_for_each_entry_safe(entry, next, list, head) { |
||
167 | switch (entry->state) { |
||
168 | case VMW_CMDBUF_RES_ADD: |
||
169 | vmw_cmdbuf_res_free(entry->man, entry); |
||
170 | break; |
||
171 | case VMW_CMDBUF_RES_DEL: |
||
172 | ret = drm_ht_insert_item(&entry->man->resources, |
||
173 | &entry->hash); |
||
174 | list_del(&entry->head); |
||
175 | list_add_tail(&entry->head, &entry->man->list); |
||
176 | entry->state = VMW_CMDBUF_RES_COMMITTED; |
||
177 | break; |
||
178 | default: |
||
179 | BUG(); |
||
180 | break; |
||
181 | } |
||
182 | } |
||
183 | } |
||
184 | |||
185 | /** |
||
186 | * vmw_cmdbuf_res_add - Stage a command buffer managed resource for addition. |
||
187 | * |
||
188 | * @man: Pointer to the command buffer resource manager. |
||
189 | * @res_type: The resource type. |
||
190 | * @user_key: The user-space id of the resource. |
||
191 | * @res: Valid (refcount != 0) pointer to a struct vmw_resource. |
||
192 | * @list: The staging list. |
||
193 | * |
||
194 | * This function allocates a struct vmw_cmdbuf_res entry and adds the |
||
195 | * resource to the hash table of the manager identified by @man. The |
||
196 | * entry is then put on the staging list identified by @list. |
||
197 | */ |
||
198 | int vmw_cmdbuf_res_add(struct vmw_cmdbuf_res_manager *man, |
||
199 | enum vmw_cmdbuf_res_type res_type, |
||
200 | u32 user_key, |
||
201 | struct vmw_resource *res, |
||
202 | struct list_head *list) |
||
203 | { |
||
204 | struct vmw_cmdbuf_res *cres; |
||
205 | int ret; |
||
206 | |||
207 | cres = kzalloc(sizeof(*cres), GFP_KERNEL); |
||
208 | if (unlikely(cres == NULL)) |
||
209 | return -ENOMEM; |
||
210 | |||
211 | cres->hash.key = user_key | (res_type << 24); |
||
212 | ret = drm_ht_insert_item(&man->resources, &cres->hash); |
||
213 | if (unlikely(ret != 0)) |
||
214 | goto out_invalid_key; |
||
215 | |||
216 | cres->state = VMW_CMDBUF_RES_ADD; |
||
217 | cres->res = vmw_resource_reference(res); |
||
218 | cres->man = man; |
||
219 | list_add_tail(&cres->head, list); |
||
220 | |||
221 | out_invalid_key: |
||
222 | return ret; |
||
223 | } |
||
224 | |||
225 | /** |
||
226 | * vmw_cmdbuf_res_remove - Stage a command buffer managed resource for removal. |
||
227 | * |
||
228 | * @man: Pointer to the command buffer resource manager. |
||
229 | * @res_type: The resource type. |
||
230 | * @user_key: The user-space id of the resource. |
||
231 | * @list: The staging list. |
||
232 | * @res_p: If the resource is in an already committed state, points to the |
||
233 | * struct vmw_resource on successful return. The pointer will be |
||
234 | * non ref-counted. |
||
235 | * |
||
236 | * This function looks up the struct vmw_cmdbuf_res entry from the manager |
||
237 | * hash table and, if it exists, removes it. Depending on its current staging |
||
238 | * state it then either removes the entry from the staging list or adds it |
||
239 | * to it with a staging state of removal. |
||
240 | */ |
||
241 | int vmw_cmdbuf_res_remove(struct vmw_cmdbuf_res_manager *man, |
||
242 | enum vmw_cmdbuf_res_type res_type, |
||
243 | u32 user_key, |
||
244 | struct list_head *list, |
||
245 | struct vmw_resource **res_p) |
||
246 | { |
||
247 | struct vmw_cmdbuf_res *entry; |
||
248 | struct drm_hash_item *hash; |
||
249 | int ret; |
||
250 | |||
251 | ret = drm_ht_find_item(&man->resources, user_key | (res_type << 24), |
||
252 | &hash); |
||
253 | if (likely(ret != 0)) |
||
254 | return -EINVAL; |
||
255 | |||
256 | entry = drm_hash_entry(hash, struct vmw_cmdbuf_res, hash); |
||
257 | |||
258 | switch (entry->state) { |
||
259 | case VMW_CMDBUF_RES_ADD: |
||
260 | vmw_cmdbuf_res_free(man, entry); |
||
261 | *res_p = NULL; |
||
262 | break; |
||
263 | case VMW_CMDBUF_RES_COMMITTED: |
||
264 | (void) drm_ht_remove_item(&man->resources, &entry->hash); |
||
265 | list_del(&entry->head); |
||
266 | entry->state = VMW_CMDBUF_RES_DEL; |
||
267 | list_add_tail(&entry->head, list); |
||
268 | *res_p = entry->res; |
||
269 | break; |
||
270 | default: |
||
271 | BUG(); |
||
272 | break; |
||
273 | } |
||
274 | |||
275 | return 0; |
||
276 | } |
||
277 | |||
278 | /** |
||
279 | * vmw_cmdbuf_res_man_create - Allocate a command buffer managed resource |
||
280 | * manager. |
||
281 | * |
||
282 | * @dev_priv: Pointer to a struct vmw_private |
||
283 | * |
||
284 | * Allocates and initializes a command buffer managed resource manager. Returns |
||
285 | * an error pointer on failure. |
||
286 | */ |
||
287 | struct vmw_cmdbuf_res_manager * |
||
288 | vmw_cmdbuf_res_man_create(struct vmw_private *dev_priv) |
||
289 | { |
||
290 | struct vmw_cmdbuf_res_manager *man; |
||
291 | int ret; |
||
292 | |||
293 | man = kzalloc(sizeof(*man), GFP_KERNEL); |
||
294 | if (man == NULL) |
||
295 | return ERR_PTR(-ENOMEM); |
||
296 | |||
297 | man->dev_priv = dev_priv; |
||
298 | INIT_LIST_HEAD(&man->list); |
||
299 | ret = drm_ht_create(&man->resources, VMW_CMDBUF_RES_MAN_HT_ORDER); |
||
300 | if (ret == 0) |
||
301 | return man; |
||
302 | |||
303 | kfree(man); |
||
304 | return ERR_PTR(ret); |
||
305 | } |
||
306 | |||
307 | /** |
||
308 | * vmw_cmdbuf_res_man_destroy - Destroy a command buffer managed resource |
||
309 | * manager. |
||
310 | * |
||
311 | * @man: Pointer to the manager to destroy. |
||
312 | * |
||
313 | * This function destroys a command buffer managed resource manager and |
||
314 | * unreferences / frees all command buffer managed resources and -entries |
||
315 | * associated with it. |
||
316 | */ |
||
317 | void vmw_cmdbuf_res_man_destroy(struct vmw_cmdbuf_res_manager *man) |
||
318 | { |
||
319 | struct vmw_cmdbuf_res *entry, *next; |
||
320 | |||
321 | list_for_each_entry_safe(entry, next, &man->list, head) |
||
322 | vmw_cmdbuf_res_free(man, entry); |
||
323 | |||
324 | kfree(man); |
||
325 | } |
||
326 | |||
327 | /** |
||
328 | * |
||
329 | * vmw_cmdbuf_res_man_size - Return the size of a command buffer managed |
||
330 | * resource manager |
||
331 | * |
||
332 | * Returns the approximate allocation size of a command buffer managed |
||
333 | * resource manager. |
||
334 | */ |
||
335 | size_t vmw_cmdbuf_res_man_size(void) |
||
336 | { |
||
337 | static size_t res_man_size; |
||
338 | |||
339 | if (unlikely(res_man_size == 0)) |
||
340 | res_man_size = |
||
341 | ttm_round_pot(sizeof(struct vmw_cmdbuf_res_manager)) + |
||
342 | ttm_round_pot(sizeof(struct hlist_head) << |
||
343 | VMW_CMDBUF_RES_MAN_HT_ORDER); |
||
344 | |||
345 | return res_man_size; |
||
346 | } |