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