]> Git Repo - linux.git/blob - drivers/gpu/drm/vmwgfx/vmwgfx_shader.c
Merge tag 'cxl-for-6.0' of git://git.kernel.org/pub/scm/linux/kernel/git/cxl/cxl
[linux.git] / drivers / gpu / drm / vmwgfx / vmwgfx_shader.c
1 // SPDX-License-Identifier: GPL-2.0 OR MIT
2 /**************************************************************************
3  *
4  * Copyright 2009-2015 VMware, Inc., Palo Alto, CA., USA
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 <drm/ttm/ttm_placement.h>
29
30 #include "vmwgfx_drv.h"
31 #include "vmwgfx_resource_priv.h"
32 #include "vmwgfx_binding.h"
33
34 struct vmw_shader {
35         struct vmw_resource res;
36         SVGA3dShaderType type;
37         uint32_t size;
38         uint8_t num_input_sig;
39         uint8_t num_output_sig;
40 };
41
42 struct vmw_user_shader {
43         struct ttm_base_object base;
44         struct vmw_shader shader;
45 };
46
47 struct vmw_dx_shader {
48         struct vmw_resource res;
49         struct vmw_resource *ctx;
50         struct vmw_resource *cotable;
51         u32 id;
52         bool committed;
53         struct list_head cotable_head;
54 };
55
56 static void vmw_user_shader_free(struct vmw_resource *res);
57 static struct vmw_resource *
58 vmw_user_shader_base_to_res(struct ttm_base_object *base);
59
60 static int vmw_gb_shader_create(struct vmw_resource *res);
61 static int vmw_gb_shader_bind(struct vmw_resource *res,
62                                struct ttm_validate_buffer *val_buf);
63 static int vmw_gb_shader_unbind(struct vmw_resource *res,
64                                  bool readback,
65                                  struct ttm_validate_buffer *val_buf);
66 static int vmw_gb_shader_destroy(struct vmw_resource *res);
67
68 static int vmw_dx_shader_create(struct vmw_resource *res);
69 static int vmw_dx_shader_bind(struct vmw_resource *res,
70                                struct ttm_validate_buffer *val_buf);
71 static int vmw_dx_shader_unbind(struct vmw_resource *res,
72                                  bool readback,
73                                  struct ttm_validate_buffer *val_buf);
74 static void vmw_dx_shader_commit_notify(struct vmw_resource *res,
75                                         enum vmw_cmdbuf_res_state state);
76 static bool vmw_shader_id_ok(u32 user_key, SVGA3dShaderType shader_type);
77 static u32 vmw_shader_key(u32 user_key, SVGA3dShaderType shader_type);
78
79 static const struct vmw_user_resource_conv user_shader_conv = {
80         .object_type = VMW_RES_SHADER,
81         .base_obj_to_res = vmw_user_shader_base_to_res,
82         .res_free = vmw_user_shader_free
83 };
84
85 const struct vmw_user_resource_conv *user_shader_converter =
86         &user_shader_conv;
87
88
89 static const struct vmw_res_func vmw_gb_shader_func = {
90         .res_type = vmw_res_shader,
91         .needs_backup = true,
92         .may_evict = true,
93         .prio = 3,
94         .dirty_prio = 3,
95         .type_name = "guest backed shaders",
96         .backup_placement = &vmw_mob_placement,
97         .create = vmw_gb_shader_create,
98         .destroy = vmw_gb_shader_destroy,
99         .bind = vmw_gb_shader_bind,
100         .unbind = vmw_gb_shader_unbind
101 };
102
103 static const struct vmw_res_func vmw_dx_shader_func = {
104         .res_type = vmw_res_shader,
105         .needs_backup = true,
106         .may_evict = true,
107         .prio = 3,
108         .dirty_prio = 3,
109         .type_name = "dx shaders",
110         .backup_placement = &vmw_mob_placement,
111         .create = vmw_dx_shader_create,
112         /*
113          * The destroy callback is only called with a committed resource on
114          * context destroy, in which case we destroy the cotable anyway,
115          * so there's no need to destroy DX shaders separately.
116          */
117         .destroy = NULL,
118         .bind = vmw_dx_shader_bind,
119         .unbind = vmw_dx_shader_unbind,
120         .commit_notify = vmw_dx_shader_commit_notify,
121 };
122
123 /*
124  * Shader management:
125  */
126
127 static inline struct vmw_shader *
128 vmw_res_to_shader(struct vmw_resource *res)
129 {
130         return container_of(res, struct vmw_shader, res);
131 }
132
133 /**
134  * vmw_res_to_dx_shader - typecast a struct vmw_resource to a
135  * struct vmw_dx_shader
136  *
137  * @res: Pointer to the struct vmw_resource.
138  */
139 static inline struct vmw_dx_shader *
140 vmw_res_to_dx_shader(struct vmw_resource *res)
141 {
142         return container_of(res, struct vmw_dx_shader, res);
143 }
144
145 static void vmw_hw_shader_destroy(struct vmw_resource *res)
146 {
147         if (likely(res->func->destroy))
148                 (void) res->func->destroy(res);
149         else
150                 res->id = -1;
151 }
152
153
154 static int vmw_gb_shader_init(struct vmw_private *dev_priv,
155                               struct vmw_resource *res,
156                               uint32_t size,
157                               uint64_t offset,
158                               SVGA3dShaderType type,
159                               uint8_t num_input_sig,
160                               uint8_t num_output_sig,
161                               struct vmw_buffer_object *byte_code,
162                               void (*res_free) (struct vmw_resource *res))
163 {
164         struct vmw_shader *shader = vmw_res_to_shader(res);
165         int ret;
166
167         ret = vmw_resource_init(dev_priv, res, true, res_free,
168                                 &vmw_gb_shader_func);
169
170         if (unlikely(ret != 0)) {
171                 if (res_free)
172                         res_free(res);
173                 else
174                         kfree(res);
175                 return ret;
176         }
177
178         res->backup_size = size;
179         if (byte_code) {
180                 res->backup = vmw_bo_reference(byte_code);
181                 res->backup_offset = offset;
182         }
183         shader->size = size;
184         shader->type = type;
185         shader->num_input_sig = num_input_sig;
186         shader->num_output_sig = num_output_sig;
187
188         res->hw_destroy = vmw_hw_shader_destroy;
189         return 0;
190 }
191
192 /*
193  * GB shader code:
194  */
195
196 static int vmw_gb_shader_create(struct vmw_resource *res)
197 {
198         struct vmw_private *dev_priv = res->dev_priv;
199         struct vmw_shader *shader = vmw_res_to_shader(res);
200         int ret;
201         struct {
202                 SVGA3dCmdHeader header;
203                 SVGA3dCmdDefineGBShader body;
204         } *cmd;
205
206         if (likely(res->id != -1))
207                 return 0;
208
209         ret = vmw_resource_alloc_id(res);
210         if (unlikely(ret != 0)) {
211                 DRM_ERROR("Failed to allocate a shader id.\n");
212                 goto out_no_id;
213         }
214
215         if (unlikely(res->id >= VMWGFX_NUM_GB_SHADER)) {
216                 ret = -EBUSY;
217                 goto out_no_fifo;
218         }
219
220         cmd = VMW_CMD_RESERVE(dev_priv, sizeof(*cmd));
221         if (unlikely(cmd == NULL)) {
222                 ret = -ENOMEM;
223                 goto out_no_fifo;
224         }
225
226         cmd->header.id = SVGA_3D_CMD_DEFINE_GB_SHADER;
227         cmd->header.size = sizeof(cmd->body);
228         cmd->body.shid = res->id;
229         cmd->body.type = shader->type;
230         cmd->body.sizeInBytes = shader->size;
231         vmw_cmd_commit(dev_priv, sizeof(*cmd));
232         vmw_fifo_resource_inc(dev_priv);
233
234         return 0;
235
236 out_no_fifo:
237         vmw_resource_release_id(res);
238 out_no_id:
239         return ret;
240 }
241
242 static int vmw_gb_shader_bind(struct vmw_resource *res,
243                               struct ttm_validate_buffer *val_buf)
244 {
245         struct vmw_private *dev_priv = res->dev_priv;
246         struct {
247                 SVGA3dCmdHeader header;
248                 SVGA3dCmdBindGBShader body;
249         } *cmd;
250         struct ttm_buffer_object *bo = val_buf->bo;
251
252         BUG_ON(bo->resource->mem_type != VMW_PL_MOB);
253
254         cmd = VMW_CMD_RESERVE(dev_priv, sizeof(*cmd));
255         if (unlikely(cmd == NULL))
256                 return -ENOMEM;
257
258         cmd->header.id = SVGA_3D_CMD_BIND_GB_SHADER;
259         cmd->header.size = sizeof(cmd->body);
260         cmd->body.shid = res->id;
261         cmd->body.mobid = bo->resource->start;
262         cmd->body.offsetInBytes = res->backup_offset;
263         res->backup_dirty = false;
264         vmw_cmd_commit(dev_priv, sizeof(*cmd));
265
266         return 0;
267 }
268
269 static int vmw_gb_shader_unbind(struct vmw_resource *res,
270                                 bool readback,
271                                 struct ttm_validate_buffer *val_buf)
272 {
273         struct vmw_private *dev_priv = res->dev_priv;
274         struct {
275                 SVGA3dCmdHeader header;
276                 SVGA3dCmdBindGBShader body;
277         } *cmd;
278         struct vmw_fence_obj *fence;
279
280         BUG_ON(res->backup->base.resource->mem_type != VMW_PL_MOB);
281
282         cmd = VMW_CMD_RESERVE(dev_priv, sizeof(*cmd));
283         if (unlikely(cmd == NULL))
284                 return -ENOMEM;
285
286         cmd->header.id = SVGA_3D_CMD_BIND_GB_SHADER;
287         cmd->header.size = sizeof(cmd->body);
288         cmd->body.shid = res->id;
289         cmd->body.mobid = SVGA3D_INVALID_ID;
290         cmd->body.offsetInBytes = 0;
291         vmw_cmd_commit(dev_priv, sizeof(*cmd));
292
293         /*
294          * Create a fence object and fence the backup buffer.
295          */
296
297         (void) vmw_execbuf_fence_commands(NULL, dev_priv,
298                                           &fence, NULL);
299
300         vmw_bo_fence_single(val_buf->bo, fence);
301
302         if (likely(fence != NULL))
303                 vmw_fence_obj_unreference(&fence);
304
305         return 0;
306 }
307
308 static int vmw_gb_shader_destroy(struct vmw_resource *res)
309 {
310         struct vmw_private *dev_priv = res->dev_priv;
311         struct {
312                 SVGA3dCmdHeader header;
313                 SVGA3dCmdDestroyGBShader body;
314         } *cmd;
315
316         if (likely(res->id == -1))
317                 return 0;
318
319         mutex_lock(&dev_priv->binding_mutex);
320         vmw_binding_res_list_scrub(&res->binding_head);
321
322         cmd = VMW_CMD_RESERVE(dev_priv, sizeof(*cmd));
323         if (unlikely(cmd == NULL)) {
324                 mutex_unlock(&dev_priv->binding_mutex);
325                 return -ENOMEM;
326         }
327
328         cmd->header.id = SVGA_3D_CMD_DESTROY_GB_SHADER;
329         cmd->header.size = sizeof(cmd->body);
330         cmd->body.shid = res->id;
331         vmw_cmd_commit(dev_priv, sizeof(*cmd));
332         mutex_unlock(&dev_priv->binding_mutex);
333         vmw_resource_release_id(res);
334         vmw_fifo_resource_dec(dev_priv);
335
336         return 0;
337 }
338
339 /*
340  * DX shader code:
341  */
342
343 /**
344  * vmw_dx_shader_commit_notify - Notify that a shader operation has been
345  * committed to hardware from a user-supplied command stream.
346  *
347  * @res: Pointer to the shader resource.
348  * @state: Indicating whether a creation or removal has been committed.
349  *
350  */
351 static void vmw_dx_shader_commit_notify(struct vmw_resource *res,
352                                         enum vmw_cmdbuf_res_state state)
353 {
354         struct vmw_dx_shader *shader = vmw_res_to_dx_shader(res);
355         struct vmw_private *dev_priv = res->dev_priv;
356
357         if (state == VMW_CMDBUF_RES_ADD) {
358                 mutex_lock(&dev_priv->binding_mutex);
359                 vmw_cotable_add_resource(shader->cotable,
360                                          &shader->cotable_head);
361                 shader->committed = true;
362                 res->id = shader->id;
363                 mutex_unlock(&dev_priv->binding_mutex);
364         } else {
365                 mutex_lock(&dev_priv->binding_mutex);
366                 list_del_init(&shader->cotable_head);
367                 shader->committed = false;
368                 res->id = -1;
369                 mutex_unlock(&dev_priv->binding_mutex);
370         }
371 }
372
373 /**
374  * vmw_dx_shader_unscrub - Have the device reattach a MOB to a DX shader.
375  *
376  * @res: The shader resource
377  *
378  * This function reverts a scrub operation.
379  */
380 static int vmw_dx_shader_unscrub(struct vmw_resource *res)
381 {
382         struct vmw_dx_shader *shader = vmw_res_to_dx_shader(res);
383         struct vmw_private *dev_priv = res->dev_priv;
384         struct {
385                 SVGA3dCmdHeader header;
386                 SVGA3dCmdDXBindShader body;
387         } *cmd;
388
389         if (!list_empty(&shader->cotable_head) || !shader->committed)
390                 return 0;
391
392         cmd = VMW_CMD_CTX_RESERVE(dev_priv, sizeof(*cmd), shader->ctx->id);
393         if (unlikely(cmd == NULL))
394                 return -ENOMEM;
395
396         cmd->header.id = SVGA_3D_CMD_DX_BIND_SHADER;
397         cmd->header.size = sizeof(cmd->body);
398         cmd->body.cid = shader->ctx->id;
399         cmd->body.shid = shader->id;
400         cmd->body.mobid = res->backup->base.resource->start;
401         cmd->body.offsetInBytes = res->backup_offset;
402         vmw_cmd_commit(dev_priv, sizeof(*cmd));
403
404         vmw_cotable_add_resource(shader->cotable, &shader->cotable_head);
405
406         return 0;
407 }
408
409 /**
410  * vmw_dx_shader_create - The DX shader create callback
411  *
412  * @res: The DX shader resource
413  *
414  * The create callback is called as part of resource validation and
415  * makes sure that we unscrub the shader if it's previously been scrubbed.
416  */
417 static int vmw_dx_shader_create(struct vmw_resource *res)
418 {
419         struct vmw_private *dev_priv = res->dev_priv;
420         struct vmw_dx_shader *shader = vmw_res_to_dx_shader(res);
421         int ret = 0;
422
423         WARN_ON_ONCE(!shader->committed);
424
425         if (vmw_resource_mob_attached(res)) {
426                 mutex_lock(&dev_priv->binding_mutex);
427                 ret = vmw_dx_shader_unscrub(res);
428                 mutex_unlock(&dev_priv->binding_mutex);
429         }
430
431         res->id = shader->id;
432         return ret;
433 }
434
435 /**
436  * vmw_dx_shader_bind - The DX shader bind callback
437  *
438  * @res: The DX shader resource
439  * @val_buf: Pointer to the validate buffer.
440  *
441  */
442 static int vmw_dx_shader_bind(struct vmw_resource *res,
443                               struct ttm_validate_buffer *val_buf)
444 {
445         struct vmw_private *dev_priv = res->dev_priv;
446         struct ttm_buffer_object *bo = val_buf->bo;
447
448         BUG_ON(bo->resource->mem_type != VMW_PL_MOB);
449         mutex_lock(&dev_priv->binding_mutex);
450         vmw_dx_shader_unscrub(res);
451         mutex_unlock(&dev_priv->binding_mutex);
452
453         return 0;
454 }
455
456 /**
457  * vmw_dx_shader_scrub - Have the device unbind a MOB from a DX shader.
458  *
459  * @res: The shader resource
460  *
461  * This function unbinds a MOB from the DX shader without requiring the
462  * MOB dma_buffer to be reserved. The driver still considers the MOB bound.
463  * However, once the driver eventually decides to unbind the MOB, it doesn't
464  * need to access the context.
465  */
466 static int vmw_dx_shader_scrub(struct vmw_resource *res)
467 {
468         struct vmw_dx_shader *shader = vmw_res_to_dx_shader(res);
469         struct vmw_private *dev_priv = res->dev_priv;
470         struct {
471                 SVGA3dCmdHeader header;
472                 SVGA3dCmdDXBindShader body;
473         } *cmd;
474
475         if (list_empty(&shader->cotable_head))
476                 return 0;
477
478         WARN_ON_ONCE(!shader->committed);
479         cmd = VMW_CMD_RESERVE(dev_priv, sizeof(*cmd));
480         if (unlikely(cmd == NULL))
481                 return -ENOMEM;
482
483         cmd->header.id = SVGA_3D_CMD_DX_BIND_SHADER;
484         cmd->header.size = sizeof(cmd->body);
485         cmd->body.cid = shader->ctx->id;
486         cmd->body.shid = res->id;
487         cmd->body.mobid = SVGA3D_INVALID_ID;
488         cmd->body.offsetInBytes = 0;
489         vmw_cmd_commit(dev_priv, sizeof(*cmd));
490         res->id = -1;
491         list_del_init(&shader->cotable_head);
492
493         return 0;
494 }
495
496 /**
497  * vmw_dx_shader_unbind - The dx shader unbind callback.
498  *
499  * @res: The shader resource
500  * @readback: Whether this is a readback unbind. Currently unused.
501  * @val_buf: MOB buffer information.
502  */
503 static int vmw_dx_shader_unbind(struct vmw_resource *res,
504                                 bool readback,
505                                 struct ttm_validate_buffer *val_buf)
506 {
507         struct vmw_private *dev_priv = res->dev_priv;
508         struct vmw_fence_obj *fence;
509         int ret;
510
511         BUG_ON(res->backup->base.resource->mem_type != VMW_PL_MOB);
512
513         mutex_lock(&dev_priv->binding_mutex);
514         ret = vmw_dx_shader_scrub(res);
515         mutex_unlock(&dev_priv->binding_mutex);
516
517         if (ret)
518                 return ret;
519
520         (void) vmw_execbuf_fence_commands(NULL, dev_priv,
521                                           &fence, NULL);
522         vmw_bo_fence_single(val_buf->bo, fence);
523
524         if (likely(fence != NULL))
525                 vmw_fence_obj_unreference(&fence);
526
527         return 0;
528 }
529
530 /**
531  * vmw_dx_shader_cotable_list_scrub - The cotable unbind_func callback for
532  * DX shaders.
533  *
534  * @dev_priv: Pointer to device private structure.
535  * @list: The list of cotable resources.
536  * @readback: Whether the call was part of a readback unbind.
537  *
538  * Scrubs all shader MOBs so that any subsequent shader unbind or shader
539  * destroy operation won't need to swap in the context.
540  */
541 void vmw_dx_shader_cotable_list_scrub(struct vmw_private *dev_priv,
542                                       struct list_head *list,
543                                       bool readback)
544 {
545         struct vmw_dx_shader *entry, *next;
546
547         lockdep_assert_held_once(&dev_priv->binding_mutex);
548
549         list_for_each_entry_safe(entry, next, list, cotable_head) {
550                 WARN_ON(vmw_dx_shader_scrub(&entry->res));
551                 if (!readback)
552                         entry->committed = false;
553         }
554 }
555
556 /**
557  * vmw_dx_shader_res_free - The DX shader free callback
558  *
559  * @res: The shader resource
560  *
561  * Frees the DX shader resource.
562  */
563 static void vmw_dx_shader_res_free(struct vmw_resource *res)
564 {
565         struct vmw_dx_shader *shader = vmw_res_to_dx_shader(res);
566
567         vmw_resource_unreference(&shader->cotable);
568         kfree(shader);
569 }
570
571 /**
572  * vmw_dx_shader_add - Add a shader resource as a command buffer managed
573  * resource.
574  *
575  * @man: The command buffer resource manager.
576  * @ctx: Pointer to the context resource.
577  * @user_key: The id used for this shader.
578  * @shader_type: The shader type.
579  * @list: The list of staged command buffer managed resources.
580  */
581 int vmw_dx_shader_add(struct vmw_cmdbuf_res_manager *man,
582                       struct vmw_resource *ctx,
583                       u32 user_key,
584                       SVGA3dShaderType shader_type,
585                       struct list_head *list)
586 {
587         struct vmw_dx_shader *shader;
588         struct vmw_resource *res;
589         struct vmw_private *dev_priv = ctx->dev_priv;
590         int ret;
591
592         if (!vmw_shader_id_ok(user_key, shader_type))
593                 return -EINVAL;
594
595         shader = kmalloc(sizeof(*shader), GFP_KERNEL);
596         if (!shader) {
597                 return -ENOMEM;
598         }
599
600         res = &shader->res;
601         shader->ctx = ctx;
602         shader->cotable = vmw_resource_reference
603                 (vmw_context_cotable(ctx, SVGA_COTABLE_DXSHADER));
604         shader->id = user_key;
605         shader->committed = false;
606         INIT_LIST_HEAD(&shader->cotable_head);
607         ret = vmw_resource_init(dev_priv, res, true,
608                                 vmw_dx_shader_res_free, &vmw_dx_shader_func);
609         if (ret)
610                 goto out_resource_init;
611
612         /*
613          * The user_key name-space is not per shader type for DX shaders,
614          * so when hashing, use a single zero shader type.
615          */
616         ret = vmw_cmdbuf_res_add(man, vmw_cmdbuf_res_shader,
617                                  vmw_shader_key(user_key, 0),
618                                  res, list);
619         if (ret)
620                 goto out_resource_init;
621
622         res->id = shader->id;
623         res->hw_destroy = vmw_hw_shader_destroy;
624
625 out_resource_init:
626         vmw_resource_unreference(&res);
627
628         return ret;
629 }
630
631
632
633 /*
634  * User-space shader management:
635  */
636
637 static struct vmw_resource *
638 vmw_user_shader_base_to_res(struct ttm_base_object *base)
639 {
640         return &(container_of(base, struct vmw_user_shader, base)->
641                  shader.res);
642 }
643
644 static void vmw_user_shader_free(struct vmw_resource *res)
645 {
646         struct vmw_user_shader *ushader =
647                 container_of(res, struct vmw_user_shader, shader.res);
648
649         ttm_base_object_kfree(ushader, base);
650 }
651
652 static void vmw_shader_free(struct vmw_resource *res)
653 {
654         struct vmw_shader *shader = vmw_res_to_shader(res);
655
656         kfree(shader);
657 }
658
659 /*
660  * This function is called when user space has no more references on the
661  * base object. It releases the base-object's reference on the resource object.
662  */
663
664 static void vmw_user_shader_base_release(struct ttm_base_object **p_base)
665 {
666         struct ttm_base_object *base = *p_base;
667         struct vmw_resource *res = vmw_user_shader_base_to_res(base);
668
669         *p_base = NULL;
670         vmw_resource_unreference(&res);
671 }
672
673 int vmw_shader_destroy_ioctl(struct drm_device *dev, void *data,
674                               struct drm_file *file_priv)
675 {
676         struct drm_vmw_shader_arg *arg = (struct drm_vmw_shader_arg *)data;
677         struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile;
678
679         return ttm_ref_object_base_unref(tfile, arg->handle);
680 }
681
682 static int vmw_user_shader_alloc(struct vmw_private *dev_priv,
683                                  struct vmw_buffer_object *buffer,
684                                  size_t shader_size,
685                                  size_t offset,
686                                  SVGA3dShaderType shader_type,
687                                  uint8_t num_input_sig,
688                                  uint8_t num_output_sig,
689                                  struct ttm_object_file *tfile,
690                                  u32 *handle)
691 {
692         struct vmw_user_shader *ushader;
693         struct vmw_resource *res, *tmp;
694         int ret;
695
696         ushader = kzalloc(sizeof(*ushader), GFP_KERNEL);
697         if (unlikely(!ushader)) {
698                 ret = -ENOMEM;
699                 goto out;
700         }
701
702         res = &ushader->shader.res;
703         ushader->base.shareable = false;
704         ushader->base.tfile = NULL;
705
706         /*
707          * From here on, the destructor takes over resource freeing.
708          */
709
710         ret = vmw_gb_shader_init(dev_priv, res, shader_size,
711                                  offset, shader_type, num_input_sig,
712                                  num_output_sig, buffer,
713                                  vmw_user_shader_free);
714         if (unlikely(ret != 0))
715                 goto out;
716
717         tmp = vmw_resource_reference(res);
718         ret = ttm_base_object_init(tfile, &ushader->base, false,
719                                    VMW_RES_SHADER,
720                                    &vmw_user_shader_base_release);
721
722         if (unlikely(ret != 0)) {
723                 vmw_resource_unreference(&tmp);
724                 goto out_err;
725         }
726
727         if (handle)
728                 *handle = ushader->base.handle;
729 out_err:
730         vmw_resource_unreference(&res);
731 out:
732         return ret;
733 }
734
735
736 static struct vmw_resource *vmw_shader_alloc(struct vmw_private *dev_priv,
737                                              struct vmw_buffer_object *buffer,
738                                              size_t shader_size,
739                                              size_t offset,
740                                              SVGA3dShaderType shader_type)
741 {
742         struct vmw_shader *shader;
743         struct vmw_resource *res;
744         int ret;
745
746         shader = kzalloc(sizeof(*shader), GFP_KERNEL);
747         if (unlikely(!shader)) {
748                 ret = -ENOMEM;
749                 goto out_err;
750         }
751
752         res = &shader->res;
753
754         /*
755          * From here on, the destructor takes over resource freeing.
756          */
757         ret = vmw_gb_shader_init(dev_priv, res, shader_size,
758                                  offset, shader_type, 0, 0, buffer,
759                                  vmw_shader_free);
760
761 out_err:
762         return ret ? ERR_PTR(ret) : res;
763 }
764
765
766 static int vmw_shader_define(struct drm_device *dev, struct drm_file *file_priv,
767                              enum drm_vmw_shader_type shader_type_drm,
768                              u32 buffer_handle, size_t size, size_t offset,
769                              uint8_t num_input_sig, uint8_t num_output_sig,
770                              uint32_t *shader_handle)
771 {
772         struct vmw_private *dev_priv = vmw_priv(dev);
773         struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile;
774         struct vmw_buffer_object *buffer = NULL;
775         SVGA3dShaderType shader_type;
776         int ret;
777
778         if (buffer_handle != SVGA3D_INVALID_ID) {
779                 ret = vmw_user_bo_lookup(file_priv, buffer_handle, &buffer);
780                 if (unlikely(ret != 0)) {
781                         VMW_DEBUG_USER("Couldn't find buffer for shader creation.\n");
782                         return ret;
783                 }
784
785                 if ((u64)buffer->base.base.size < (u64)size + (u64)offset) {
786                         VMW_DEBUG_USER("Illegal buffer- or shader size.\n");
787                         ret = -EINVAL;
788                         goto out_bad_arg;
789                 }
790         }
791
792         switch (shader_type_drm) {
793         case drm_vmw_shader_type_vs:
794                 shader_type = SVGA3D_SHADERTYPE_VS;
795                 break;
796         case drm_vmw_shader_type_ps:
797                 shader_type = SVGA3D_SHADERTYPE_PS;
798                 break;
799         default:
800                 VMW_DEBUG_USER("Illegal shader type.\n");
801                 ret = -EINVAL;
802                 goto out_bad_arg;
803         }
804
805         ret = vmw_user_shader_alloc(dev_priv, buffer, size, offset,
806                                     shader_type, num_input_sig,
807                                     num_output_sig, tfile, shader_handle);
808 out_bad_arg:
809         vmw_bo_unreference(&buffer);
810         return ret;
811 }
812
813 /**
814  * vmw_shader_id_ok - Check whether a compat shader user key and
815  * shader type are within valid bounds.
816  *
817  * @user_key: User space id of the shader.
818  * @shader_type: Shader type.
819  *
820  * Returns true if valid false if not.
821  */
822 static bool vmw_shader_id_ok(u32 user_key, SVGA3dShaderType shader_type)
823 {
824         return user_key <= ((1 << 20) - 1) && (unsigned) shader_type < 16;
825 }
826
827 /**
828  * vmw_shader_key - Compute a hash key suitable for a compat shader.
829  *
830  * @user_key: User space id of the shader.
831  * @shader_type: Shader type.
832  *
833  * Returns a hash key suitable for a command buffer managed resource
834  * manager hash table.
835  */
836 static u32 vmw_shader_key(u32 user_key, SVGA3dShaderType shader_type)
837 {
838         return user_key | (shader_type << 20);
839 }
840
841 /**
842  * vmw_shader_remove - Stage a compat shader for removal.
843  *
844  * @man: Pointer to the compat shader manager identifying the shader namespace.
845  * @user_key: The key that is used to identify the shader. The key is
846  * unique to the shader type.
847  * @shader_type: Shader type.
848  * @list: Caller's list of staged command buffer resource actions.
849  */
850 int vmw_shader_remove(struct vmw_cmdbuf_res_manager *man,
851                       u32 user_key, SVGA3dShaderType shader_type,
852                       struct list_head *list)
853 {
854         struct vmw_resource *dummy;
855
856         if (!vmw_shader_id_ok(user_key, shader_type))
857                 return -EINVAL;
858
859         return vmw_cmdbuf_res_remove(man, vmw_cmdbuf_res_shader,
860                                      vmw_shader_key(user_key, shader_type),
861                                      list, &dummy);
862 }
863
864 /**
865  * vmw_compat_shader_add - Create a compat shader and stage it for addition
866  * as a command buffer managed resource.
867  *
868  * @dev_priv: Pointer to device private structure.
869  * @man: Pointer to the compat shader manager identifying the shader namespace.
870  * @user_key: The key that is used to identify the shader. The key is
871  * unique to the shader type.
872  * @bytecode: Pointer to the bytecode of the shader.
873  * @shader_type: Shader type.
874  * @size: Command size.
875  * @list: Caller's list of staged command buffer resource actions.
876  *
877  */
878 int vmw_compat_shader_add(struct vmw_private *dev_priv,
879                           struct vmw_cmdbuf_res_manager *man,
880                           u32 user_key, const void *bytecode,
881                           SVGA3dShaderType shader_type,
882                           size_t size,
883                           struct list_head *list)
884 {
885         struct ttm_operation_ctx ctx = { false, true };
886         struct vmw_buffer_object *buf;
887         struct ttm_bo_kmap_obj map;
888         bool is_iomem;
889         int ret;
890         struct vmw_resource *res;
891
892         if (!vmw_shader_id_ok(user_key, shader_type))
893                 return -EINVAL;
894
895         ret = vmw_bo_create(dev_priv, size, &vmw_sys_placement,
896                             true, true, vmw_bo_bo_free, &buf);
897         if (unlikely(ret != 0))
898                 goto out;
899
900         ret = ttm_bo_reserve(&buf->base, false, true, NULL);
901         if (unlikely(ret != 0))
902                 goto no_reserve;
903
904         /* Map and copy shader bytecode. */
905         ret = ttm_bo_kmap(&buf->base, 0, PFN_UP(size), &map);
906         if (unlikely(ret != 0)) {
907                 ttm_bo_unreserve(&buf->base);
908                 goto no_reserve;
909         }
910
911         memcpy(ttm_kmap_obj_virtual(&map, &is_iomem), bytecode, size);
912         WARN_ON(is_iomem);
913
914         ttm_bo_kunmap(&map);
915         ret = ttm_bo_validate(&buf->base, &vmw_sys_placement, &ctx);
916         WARN_ON(ret != 0);
917         ttm_bo_unreserve(&buf->base);
918
919         res = vmw_shader_alloc(dev_priv, buf, size, 0, shader_type);
920         if (unlikely(ret != 0))
921                 goto no_reserve;
922
923         ret = vmw_cmdbuf_res_add(man, vmw_cmdbuf_res_shader,
924                                  vmw_shader_key(user_key, shader_type),
925                                  res, list);
926         vmw_resource_unreference(&res);
927 no_reserve:
928         vmw_bo_unreference(&buf);
929 out:
930         return ret;
931 }
932
933 /**
934  * vmw_shader_lookup - Look up a compat shader
935  *
936  * @man: Pointer to the command buffer managed resource manager identifying
937  * the shader namespace.
938  * @user_key: The user space id of the shader.
939  * @shader_type: The shader type.
940  *
941  * Returns a refcounted pointer to a struct vmw_resource if the shader was
942  * found. An error pointer otherwise.
943  */
944 struct vmw_resource *
945 vmw_shader_lookup(struct vmw_cmdbuf_res_manager *man,
946                   u32 user_key,
947                   SVGA3dShaderType shader_type)
948 {
949         if (!vmw_shader_id_ok(user_key, shader_type))
950                 return ERR_PTR(-EINVAL);
951
952         return vmw_cmdbuf_res_lookup(man, vmw_cmdbuf_res_shader,
953                                      vmw_shader_key(user_key, shader_type));
954 }
955
956 int vmw_shader_define_ioctl(struct drm_device *dev, void *data,
957                              struct drm_file *file_priv)
958 {
959         struct drm_vmw_shader_create_arg *arg =
960                 (struct drm_vmw_shader_create_arg *)data;
961
962         return vmw_shader_define(dev, file_priv, arg->shader_type,
963                                  arg->buffer_handle,
964                                  arg->size, arg->offset,
965                                  0, 0,
966                                  &arg->shader_handle);
967 }
This page took 0.087497 seconds and 4 git commands to generate.