Rev 4569 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
4569 | Serge | 1 | /************************************************************************** |
2 | * |
||
3 | * Copyright © 2009-2012 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 | #include "ttm/ttm_placement.h" |
||
31 | |||
5078 | serge | 32 | #define VMW_COMPAT_SHADER_HT_ORDER 12 |
33 | |||
34 | #if 0 |
||
4569 | Serge | 35 | struct vmw_shader { |
36 | struct vmw_resource res; |
||
37 | SVGA3dShaderType type; |
||
38 | uint32_t size; |
||
39 | }; |
||
40 | |||
41 | struct vmw_user_shader { |
||
42 | struct ttm_base_object base; |
||
43 | struct vmw_shader shader; |
||
44 | }; |
||
45 | |||
5078 | serge | 46 | /** |
47 | * enum vmw_compat_shader_state - Staging state for compat shaders |
||
48 | */ |
||
49 | enum vmw_compat_shader_state { |
||
50 | VMW_COMPAT_COMMITED, |
||
51 | VMW_COMPAT_ADD, |
||
52 | VMW_COMPAT_DEL |
||
53 | }; |
||
54 | |||
55 | /** |
||
56 | * struct vmw_compat_shader - Metadata for compat shaders. |
||
57 | * |
||
58 | * @handle: The TTM handle of the guest backed shader. |
||
59 | * @tfile: The struct ttm_object_file the guest backed shader is registered |
||
60 | * with. |
||
61 | * @hash: Hash item for lookup. |
||
62 | * @head: List head for staging lists or the compat shader manager list. |
||
63 | * @state: Staging state. |
||
64 | * |
||
65 | * The structure is protected by the cmdbuf lock. |
||
66 | */ |
||
67 | struct vmw_compat_shader { |
||
68 | u32 handle; |
||
69 | struct ttm_object_file *tfile; |
||
70 | struct drm_hash_item hash; |
||
71 | struct list_head head; |
||
72 | enum vmw_compat_shader_state state; |
||
73 | }; |
||
74 | |||
75 | /** |
||
76 | * struct vmw_compat_shader_manager - Compat shader manager. |
||
77 | * |
||
78 | * @shaders: Hash table containing staged and commited compat shaders |
||
79 | * @list: List of commited shaders. |
||
80 | * @dev_priv: Pointer to a device private structure. |
||
81 | * |
||
82 | * @shaders and @list are protected by the cmdbuf mutex for now. |
||
83 | */ |
||
84 | struct vmw_compat_shader_manager { |
||
85 | struct drm_open_hash shaders; |
||
86 | struct list_head list; |
||
87 | struct vmw_private *dev_priv; |
||
88 | }; |
||
89 | |||
4569 | Serge | 90 | static void vmw_user_shader_free(struct vmw_resource *res); |
91 | static struct vmw_resource * |
||
92 | vmw_user_shader_base_to_res(struct ttm_base_object *base); |
||
93 | |||
94 | static int vmw_gb_shader_create(struct vmw_resource *res); |
||
95 | static int vmw_gb_shader_bind(struct vmw_resource *res, |
||
96 | struct ttm_validate_buffer *val_buf); |
||
97 | static int vmw_gb_shader_unbind(struct vmw_resource *res, |
||
98 | bool readback, |
||
99 | struct ttm_validate_buffer *val_buf); |
||
100 | static int vmw_gb_shader_destroy(struct vmw_resource *res); |
||
101 | |||
102 | static const struct vmw_user_resource_conv user_shader_conv = { |
||
103 | .object_type = VMW_RES_SHADER, |
||
104 | .base_obj_to_res = vmw_user_shader_base_to_res, |
||
105 | .res_free = vmw_user_shader_free |
||
106 | }; |
||
107 | |||
108 | const struct vmw_user_resource_conv *user_shader_converter = |
||
109 | &user_shader_conv; |
||
110 | |||
111 | |||
112 | static const struct vmw_res_func vmw_gb_shader_func = { |
||
113 | .res_type = vmw_res_shader, |
||
114 | .needs_backup = true, |
||
115 | .may_evict = true, |
||
116 | .type_name = "guest backed shaders", |
||
117 | .backup_placement = &vmw_mob_placement, |
||
118 | .create = vmw_gb_shader_create, |
||
119 | .destroy = vmw_gb_shader_destroy, |
||
120 | .bind = vmw_gb_shader_bind, |
||
121 | .unbind = vmw_gb_shader_unbind |
||
122 | }; |
||
123 | |||
124 | /** |
||
125 | * Shader management: |
||
126 | */ |
||
127 | |||
128 | static inline struct vmw_shader * |
||
129 | vmw_res_to_shader(struct vmw_resource *res) |
||
130 | { |
||
131 | return container_of(res, struct vmw_shader, res); |
||
132 | } |
||
133 | |||
134 | static void vmw_hw_shader_destroy(struct vmw_resource *res) |
||
135 | { |
||
136 | (void) vmw_gb_shader_destroy(res); |
||
137 | } |
||
138 | |||
139 | static int vmw_gb_shader_init(struct vmw_private *dev_priv, |
||
140 | struct vmw_resource *res, |
||
141 | uint32_t size, |
||
142 | uint64_t offset, |
||
143 | SVGA3dShaderType type, |
||
144 | struct vmw_dma_buffer *byte_code, |
||
145 | void (*res_free) (struct vmw_resource *res)) |
||
146 | { |
||
147 | struct vmw_shader *shader = vmw_res_to_shader(res); |
||
148 | int ret; |
||
149 | |||
150 | ret = vmw_resource_init(dev_priv, res, true, |
||
151 | res_free, &vmw_gb_shader_func); |
||
152 | |||
153 | |||
154 | if (unlikely(ret != 0)) { |
||
155 | if (res_free) |
||
156 | res_free(res); |
||
157 | else |
||
158 | kfree(res); |
||
159 | return ret; |
||
160 | } |
||
161 | |||
162 | res->backup_size = size; |
||
163 | if (byte_code) { |
||
164 | res->backup = vmw_dmabuf_reference(byte_code); |
||
165 | res->backup_offset = offset; |
||
166 | } |
||
167 | shader->size = size; |
||
168 | shader->type = type; |
||
169 | |||
170 | vmw_resource_activate(res, vmw_hw_shader_destroy); |
||
171 | return 0; |
||
172 | } |
||
173 | |||
174 | static int vmw_gb_shader_create(struct vmw_resource *res) |
||
175 | { |
||
176 | struct vmw_private *dev_priv = res->dev_priv; |
||
177 | struct vmw_shader *shader = vmw_res_to_shader(res); |
||
178 | int ret; |
||
179 | struct { |
||
180 | SVGA3dCmdHeader header; |
||
181 | SVGA3dCmdDefineGBShader body; |
||
182 | } *cmd; |
||
183 | |||
184 | if (likely(res->id != -1)) |
||
185 | return 0; |
||
186 | |||
187 | ret = vmw_resource_alloc_id(res); |
||
188 | if (unlikely(ret != 0)) { |
||
189 | DRM_ERROR("Failed to allocate a shader id.\n"); |
||
190 | goto out_no_id; |
||
191 | } |
||
192 | |||
193 | if (unlikely(res->id >= VMWGFX_NUM_GB_SHADER)) { |
||
194 | ret = -EBUSY; |
||
195 | goto out_no_fifo; |
||
196 | } |
||
197 | |||
198 | cmd = vmw_fifo_reserve(dev_priv, sizeof(*cmd)); |
||
199 | if (unlikely(cmd == NULL)) { |
||
200 | DRM_ERROR("Failed reserving FIFO space for shader " |
||
201 | "creation.\n"); |
||
202 | ret = -ENOMEM; |
||
203 | goto out_no_fifo; |
||
204 | } |
||
205 | |||
206 | cmd->header.id = SVGA_3D_CMD_DEFINE_GB_SHADER; |
||
207 | cmd->header.size = sizeof(cmd->body); |
||
208 | cmd->body.shid = res->id; |
||
209 | cmd->body.type = shader->type; |
||
210 | cmd->body.sizeInBytes = shader->size; |
||
211 | vmw_fifo_commit(dev_priv, sizeof(*cmd)); |
||
212 | (void) vmw_3d_resource_inc(dev_priv, false); |
||
213 | |||
214 | return 0; |
||
215 | |||
216 | out_no_fifo: |
||
217 | vmw_resource_release_id(res); |
||
218 | out_no_id: |
||
219 | return ret; |
||
220 | } |
||
221 | |||
222 | static int vmw_gb_shader_bind(struct vmw_resource *res, |
||
223 | struct ttm_validate_buffer *val_buf) |
||
224 | { |
||
225 | struct vmw_private *dev_priv = res->dev_priv; |
||
226 | struct { |
||
227 | SVGA3dCmdHeader header; |
||
228 | SVGA3dCmdBindGBShader body; |
||
229 | } *cmd; |
||
230 | struct ttm_buffer_object *bo = val_buf->bo; |
||
231 | |||
232 | BUG_ON(bo->mem.mem_type != VMW_PL_MOB); |
||
233 | |||
234 | cmd = vmw_fifo_reserve(dev_priv, sizeof(*cmd)); |
||
235 | if (unlikely(cmd == NULL)) { |
||
236 | DRM_ERROR("Failed reserving FIFO space for shader " |
||
237 | "binding.\n"); |
||
238 | return -ENOMEM; |
||
239 | } |
||
240 | |||
241 | cmd->header.id = SVGA_3D_CMD_BIND_GB_SHADER; |
||
242 | cmd->header.size = sizeof(cmd->body); |
||
243 | cmd->body.shid = res->id; |
||
244 | cmd->body.mobid = bo->mem.start; |
||
245 | cmd->body.offsetInBytes = 0; |
||
246 | res->backup_dirty = false; |
||
247 | vmw_fifo_commit(dev_priv, sizeof(*cmd)); |
||
248 | |||
249 | return 0; |
||
250 | } |
||
251 | |||
252 | static int vmw_gb_shader_unbind(struct vmw_resource *res, |
||
253 | bool readback, |
||
254 | struct ttm_validate_buffer *val_buf) |
||
255 | { |
||
256 | struct vmw_private *dev_priv = res->dev_priv; |
||
257 | struct { |
||
258 | SVGA3dCmdHeader header; |
||
259 | SVGA3dCmdBindGBShader body; |
||
260 | } *cmd; |
||
261 | struct vmw_fence_obj *fence; |
||
262 | |||
263 | BUG_ON(res->backup->base.mem.mem_type != VMW_PL_MOB); |
||
264 | |||
265 | cmd = vmw_fifo_reserve(dev_priv, sizeof(*cmd)); |
||
266 | if (unlikely(cmd == NULL)) { |
||
267 | DRM_ERROR("Failed reserving FIFO space for shader " |
||
268 | "unbinding.\n"); |
||
269 | return -ENOMEM; |
||
270 | } |
||
271 | |||
272 | cmd->header.id = SVGA_3D_CMD_BIND_GB_SHADER; |
||
273 | cmd->header.size = sizeof(cmd->body); |
||
274 | cmd->body.shid = res->id; |
||
275 | cmd->body.mobid = SVGA3D_INVALID_ID; |
||
276 | cmd->body.offsetInBytes = 0; |
||
277 | vmw_fifo_commit(dev_priv, sizeof(*cmd)); |
||
278 | |||
279 | /* |
||
280 | * Create a fence object and fence the backup buffer. |
||
281 | */ |
||
282 | |||
283 | (void) vmw_execbuf_fence_commands(NULL, dev_priv, |
||
284 | &fence, NULL); |
||
285 | |||
286 | vmw_fence_single_bo(val_buf->bo, fence); |
||
287 | |||
288 | if (likely(fence != NULL)) |
||
289 | vmw_fence_obj_unreference(&fence); |
||
290 | |||
291 | return 0; |
||
292 | } |
||
293 | |||
294 | static int vmw_gb_shader_destroy(struct vmw_resource *res) |
||
295 | { |
||
296 | struct vmw_private *dev_priv = res->dev_priv; |
||
297 | struct { |
||
298 | SVGA3dCmdHeader header; |
||
299 | SVGA3dCmdDestroyGBShader body; |
||
300 | } *cmd; |
||
301 | |||
302 | if (likely(res->id == -1)) |
||
303 | return 0; |
||
304 | |||
305 | mutex_lock(&dev_priv->binding_mutex); |
||
5078 | serge | 306 | vmw_context_binding_res_list_scrub(&res->binding_head); |
4569 | Serge | 307 | |
308 | cmd = vmw_fifo_reserve(dev_priv, sizeof(*cmd)); |
||
309 | if (unlikely(cmd == NULL)) { |
||
310 | DRM_ERROR("Failed reserving FIFO space for shader " |
||
311 | "destruction.\n"); |
||
312 | mutex_unlock(&dev_priv->binding_mutex); |
||
313 | return -ENOMEM; |
||
314 | } |
||
315 | |||
316 | cmd->header.id = SVGA_3D_CMD_DESTROY_GB_SHADER; |
||
317 | cmd->header.size = sizeof(cmd->body); |
||
318 | cmd->body.shid = res->id; |
||
319 | vmw_fifo_commit(dev_priv, sizeof(*cmd)); |
||
320 | mutex_unlock(&dev_priv->binding_mutex); |
||
321 | vmw_resource_release_id(res); |
||
322 | vmw_3d_resource_dec(dev_priv, false); |
||
323 | |||
324 | return 0; |
||
325 | } |
||
326 | |||
327 | /** |
||
328 | * User-space shader management: |
||
329 | */ |
||
330 | |||
331 | static struct vmw_resource * |
||
332 | vmw_user_shader_base_to_res(struct ttm_base_object *base) |
||
333 | { |
||
334 | return &(container_of(base, struct vmw_user_shader, base)-> |
||
335 | shader.res); |
||
336 | } |
||
337 | |||
338 | static void vmw_user_shader_free(struct vmw_resource *res) |
||
339 | { |
||
340 | struct vmw_user_shader *ushader = |
||
341 | container_of(res, struct vmw_user_shader, shader.res); |
||
342 | struct vmw_private *dev_priv = res->dev_priv; |
||
343 | |||
5078 | serge | 344 | ttm_base_object_kfree(ushader, base); |
345 | ttm_mem_global_free(vmw_mem_glob(dev_priv), |
||
346 | vmw_user_shader_size); |
||
4569 | Serge | 347 | } |
348 | |||
349 | /** |
||
350 | * This function is called when user space has no more references on the |
||
351 | * base object. It releases the base-object's reference on the resource object. |
||
352 | */ |
||
353 | |||
354 | static void vmw_user_shader_base_release(struct ttm_base_object **p_base) |
||
355 | { |
||
356 | struct ttm_base_object *base = *p_base; |
||
357 | struct vmw_resource *res = vmw_user_shader_base_to_res(base); |
||
358 | |||
359 | *p_base = NULL; |
||
360 | vmw_resource_unreference(&res); |
||
361 | } |
||
362 | |||
363 | int vmw_shader_destroy_ioctl(struct drm_device *dev, void *data, |
||
364 | struct drm_file *file_priv) |
||
365 | { |
||
366 | struct drm_vmw_shader_arg *arg = (struct drm_vmw_shader_arg *)data; |
||
367 | struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile; |
||
368 | |||
369 | return ttm_ref_object_base_unref(tfile, arg->handle, |
||
370 | TTM_REF_USAGE); |
||
371 | } |
||
372 | |||
5078 | serge | 373 | static int vmw_user_shader_alloc(struct vmw_private *dev_priv, |
374 | struct vmw_dma_buffer *buffer, |
||
375 | size_t shader_size, |
||
376 | size_t offset, |
||
377 | SVGA3dShaderType shader_type, |
||
378 | struct ttm_object_file *tfile, |
||
379 | u32 *handle) |
||
380 | { |
||
381 | struct vmw_user_shader *ushader; |
||
382 | struct vmw_resource *res, *tmp; |
||
383 | int ret; |
||
384 | |||
385 | /* |
||
386 | * Approximate idr memory usage with 128 bytes. It will be limited |
||
387 | * by maximum number_of shaders anyway. |
||
388 | */ |
||
389 | if (unlikely(vmw_user_shader_size == 0)) |
||
390 | vmw_user_shader_size = |
||
391 | ttm_round_pot(sizeof(struct vmw_user_shader)) + 128; |
||
392 | |||
393 | ret = ttm_mem_global_alloc(vmw_mem_glob(dev_priv), |
||
394 | vmw_user_shader_size, |
||
395 | false, true); |
||
396 | if (unlikely(ret != 0)) { |
||
397 | if (ret != -ERESTARTSYS) |
||
398 | DRM_ERROR("Out of graphics memory for shader " |
||
399 | "creation.\n"); |
||
400 | goto out; |
||
401 | } |
||
402 | |||
403 | ushader = kzalloc(sizeof(*ushader), GFP_KERNEL); |
||
404 | if (unlikely(ushader == NULL)) { |
||
405 | ttm_mem_global_free(vmw_mem_glob(dev_priv), |
||
406 | vmw_user_shader_size); |
||
407 | ret = -ENOMEM; |
||
408 | goto out; |
||
409 | } |
||
410 | |||
411 | res = &ushader->shader.res; |
||
412 | ushader->base.shareable = false; |
||
413 | ushader->base.tfile = NULL; |
||
414 | |||
415 | /* |
||
416 | * From here on, the destructor takes over resource freeing. |
||
417 | */ |
||
418 | |||
419 | ret = vmw_gb_shader_init(dev_priv, res, shader_size, |
||
420 | offset, shader_type, buffer, |
||
421 | vmw_user_shader_free); |
||
422 | if (unlikely(ret != 0)) |
||
423 | goto out; |
||
424 | |||
425 | tmp = vmw_resource_reference(res); |
||
426 | ret = ttm_base_object_init(tfile, &ushader->base, false, |
||
427 | VMW_RES_SHADER, |
||
428 | &vmw_user_shader_base_release, NULL); |
||
429 | |||
430 | if (unlikely(ret != 0)) { |
||
431 | vmw_resource_unreference(&tmp); |
||
432 | goto out_err; |
||
433 | } |
||
434 | |||
435 | if (handle) |
||
436 | *handle = ushader->base.hash.key; |
||
437 | out_err: |
||
438 | vmw_resource_unreference(&res); |
||
439 | out: |
||
440 | return ret; |
||
441 | } |
||
442 | |||
443 | |||
4569 | Serge | 444 | int vmw_shader_define_ioctl(struct drm_device *dev, void *data, |
445 | struct drm_file *file_priv) |
||
446 | { |
||
447 | struct vmw_private *dev_priv = vmw_priv(dev); |
||
448 | struct drm_vmw_shader_create_arg *arg = |
||
449 | (struct drm_vmw_shader_create_arg *)data; |
||
450 | struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile; |
||
451 | struct vmw_dma_buffer *buffer = NULL; |
||
452 | SVGA3dShaderType shader_type; |
||
453 | int ret; |
||
454 | |||
455 | if (arg->buffer_handle != SVGA3D_INVALID_ID) { |
||
456 | ret = vmw_user_dmabuf_lookup(tfile, arg->buffer_handle, |
||
457 | &buffer); |
||
458 | if (unlikely(ret != 0)) { |
||
459 | DRM_ERROR("Could not find buffer for shader " |
||
460 | "creation.\n"); |
||
461 | return ret; |
||
462 | } |
||
463 | |||
464 | if ((u64)buffer->base.num_pages * PAGE_SIZE < |
||
465 | (u64)arg->size + (u64)arg->offset) { |
||
466 | DRM_ERROR("Illegal buffer- or shader size.\n"); |
||
467 | ret = -EINVAL; |
||
468 | goto out_bad_arg; |
||
469 | } |
||
470 | } |
||
471 | |||
472 | switch (arg->shader_type) { |
||
473 | case drm_vmw_shader_type_vs: |
||
474 | shader_type = SVGA3D_SHADERTYPE_VS; |
||
475 | break; |
||
476 | case drm_vmw_shader_type_ps: |
||
477 | shader_type = SVGA3D_SHADERTYPE_PS; |
||
478 | break; |
||
479 | case drm_vmw_shader_type_gs: |
||
480 | shader_type = SVGA3D_SHADERTYPE_GS; |
||
481 | break; |
||
482 | default: |
||
483 | DRM_ERROR("Illegal shader type.\n"); |
||
484 | ret = -EINVAL; |
||
485 | goto out_bad_arg; |
||
486 | } |
||
487 | |||
5078 | serge | 488 | ret = ttm_read_lock(&dev_priv->reservation_sem, true); |
489 | if (unlikely(ret != 0)) |
||
490 | goto out_bad_arg; |
||
4569 | Serge | 491 | |
5078 | serge | 492 | ret = vmw_user_shader_alloc(dev_priv, buffer, arg->size, arg->offset, |
493 | shader_type, tfile, &arg->shader_handle); |
||
4569 | Serge | 494 | |
5078 | serge | 495 | ttm_read_unlock(&dev_priv->reservation_sem); |
496 | out_bad_arg: |
||
497 | vmw_dmabuf_unreference(&buffer); |
||
498 | return ret; |
||
499 | } |
||
4569 | Serge | 500 | |
5078 | serge | 501 | /** |
502 | * vmw_compat_shader_id_ok - Check whether a compat shader user key and |
||
503 | * shader type are within valid bounds. |
||
504 | * |
||
505 | * @user_key: User space id of the shader. |
||
506 | * @shader_type: Shader type. |
||
507 | * |
||
508 | * Returns true if valid false if not. |
||
509 | */ |
||
510 | static bool vmw_compat_shader_id_ok(u32 user_key, SVGA3dShaderType shader_type) |
||
511 | { |
||
512 | return user_key <= ((1 << 20) - 1) && (unsigned) shader_type < 16; |
||
513 | } |
||
4569 | Serge | 514 | |
5078 | serge | 515 | /** |
516 | * vmw_compat_shader_key - Compute a hash key suitable for a compat shader. |
||
517 | * |
||
518 | * @user_key: User space id of the shader. |
||
519 | * @shader_type: Shader type. |
||
520 | * |
||
521 | * Returns a hash key suitable for a command buffer managed resource |
||
522 | * manager hash table. |
||
523 | */ |
||
524 | static u32 vmw_compat_shader_key(u32 user_key, SVGA3dShaderType shader_type) |
||
525 | { |
||
526 | return user_key | (shader_type << 20); |
||
527 | } |
||
4569 | Serge | 528 | |
5078 | serge | 529 | /** |
530 | * vmw_compat_shader_remove - Stage a compat shader for removal. |
||
531 | * |
||
532 | * @man: Pointer to the compat shader manager identifying the shader namespace. |
||
533 | * @user_key: The key that is used to identify the shader. The key is |
||
534 | * unique to the shader type. |
||
535 | * @shader_type: Shader type. |
||
536 | * @list: Caller's list of staged command buffer resource actions. |
||
537 | */ |
||
538 | int vmw_compat_shader_remove(struct vmw_cmdbuf_res_manager *man, |
||
539 | u32 user_key, SVGA3dShaderType shader_type, |
||
540 | struct list_head *list) |
||
541 | { |
||
542 | if (!vmw_compat_shader_id_ok(user_key, shader_type)) |
||
543 | return -EINVAL; |
||
4569 | Serge | 544 | |
5078 | serge | 545 | return vmw_cmdbuf_res_remove(man, vmw_cmdbuf_res_compat_shader, |
546 | vmw_compat_shader_key(user_key, |
||
547 | shader_type), |
||
548 | list); |
||
549 | } |
||
550 | |||
551 | /** |
||
552 | * vmw_compat_shader_add - Create a compat shader and stage it for addition |
||
553 | * as a command buffer managed resource. |
||
554 | * |
||
555 | * @man: Pointer to the compat shader manager identifying the shader namespace. |
||
556 | * @user_key: The key that is used to identify the shader. The key is |
||
557 | * unique to the shader type. |
||
558 | * @bytecode: Pointer to the bytecode of the shader. |
||
559 | * @shader_type: Shader type. |
||
560 | * @tfile: Pointer to a struct ttm_object_file that the guest-backed shader is |
||
561 | * to be created with. |
||
562 | * @list: Caller's list of staged command buffer resource actions. |
||
563 | * |
||
4569 | Serge | 564 | */ |
5078 | serge | 565 | int vmw_compat_shader_add(struct vmw_private *dev_priv, |
566 | struct vmw_cmdbuf_res_manager *man, |
||
567 | u32 user_key, const void *bytecode, |
||
568 | SVGA3dShaderType shader_type, |
||
569 | size_t size, |
||
570 | struct list_head *list) |
||
571 | { |
||
572 | struct vmw_dma_buffer *buf; |
||
573 | struct ttm_bo_kmap_obj map; |
||
574 | bool is_iomem; |
||
575 | int ret; |
||
576 | struct vmw_resource *res; |
||
4569 | Serge | 577 | |
5078 | serge | 578 | if (!vmw_compat_shader_id_ok(user_key, shader_type)) |
579 | return -EINVAL; |
||
580 | |||
581 | /* Allocate and pin a DMA buffer */ |
||
582 | buf = kzalloc(sizeof(*buf), GFP_KERNEL); |
||
583 | if (unlikely(buf == NULL)) |
||
584 | return -ENOMEM; |
||
585 | |||
586 | ret = vmw_dmabuf_init(dev_priv, buf, size, &vmw_sys_ne_placement, |
||
587 | true, vmw_dmabuf_bo_free); |
||
4569 | Serge | 588 | if (unlikely(ret != 0)) |
5078 | serge | 589 | goto out; |
4569 | Serge | 590 | |
5078 | serge | 591 | ret = ttm_bo_reserve(&buf->base, false, true, false, NULL); |
592 | if (unlikely(ret != 0)) |
||
593 | goto no_reserve; |
||
4569 | Serge | 594 | |
5078 | serge | 595 | /* Map and copy shader bytecode. */ |
596 | ret = ttm_bo_kmap(&buf->base, 0, PAGE_ALIGN(size) >> PAGE_SHIFT, |
||
597 | &map); |
||
4569 | Serge | 598 | if (unlikely(ret != 0)) { |
5078 | serge | 599 | ttm_bo_unreserve(&buf->base); |
600 | goto no_reserve; |
||
4569 | Serge | 601 | } |
602 | |||
5078 | serge | 603 | memcpy(ttm_kmap_obj_virtual(&map, &is_iomem), bytecode, size); |
604 | WARN_ON(is_iomem); |
||
605 | |||
606 | ttm_bo_kunmap(&map); |
||
607 | ret = ttm_bo_validate(&buf->base, &vmw_sys_placement, false, true); |
||
608 | WARN_ON(ret != 0); |
||
609 | ttm_bo_unreserve(&buf->base); |
||
610 | |||
611 | res = vmw_shader_alloc(dev_priv, buf, size, 0, shader_type); |
||
612 | if (unlikely(ret != 0)) |
||
613 | goto no_reserve; |
||
614 | |||
615 | ret = vmw_cmdbuf_res_add(man, vmw_cmdbuf_res_compat_shader, |
||
616 | vmw_compat_shader_key(user_key, shader_type), |
||
617 | res, list); |
||
4569 | Serge | 618 | vmw_resource_unreference(&res); |
5078 | serge | 619 | no_reserve: |
620 | vmw_dmabuf_unreference(&buf); |
||
621 | out: |
||
4569 | Serge | 622 | return ret; |
5078 | serge | 623 | } |
4569 | Serge | 624 | |
5078 | serge | 625 | /** |
626 | * vmw_compat_shader_lookup - Look up a compat shader |
||
627 | * |
||
628 | * @man: Pointer to the command buffer managed resource manager identifying |
||
629 | * the shader namespace. |
||
630 | * @user_key: The user space id of the shader. |
||
631 | * @shader_type: The shader type. |
||
632 | * |
||
633 | * Returns a refcounted pointer to a struct vmw_resource if the shader was |
||
634 | * found. An error pointer otherwise. |
||
635 | */ |
||
636 | struct vmw_resource * |
||
637 | vmw_compat_shader_lookup(struct vmw_cmdbuf_res_manager *man, |
||
638 | u32 user_key, |
||
639 | SVGA3dShaderType shader_type) |
||
640 | { |
||
641 | if (!vmw_compat_shader_id_ok(user_key, shader_type)) |
||
642 | return ERR_PTR(-EINVAL); |
||
643 | |||
644 | return vmw_cmdbuf_res_lookup(man, vmw_cmdbuf_res_compat_shader, |
||
645 | vmw_compat_shader_key(user_key, |
||
646 | shader_type)); |
||
4569 | Serge | 647 | } |
648 | #endif><>>><>=> |