Add the rt linux 4.1.3-rt3 as base
[kvmfornfv.git] / kernel / drivers / gpu / drm / vmwgfx / vmwgfx_context.c
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
32 struct vmw_user_context {
33         struct ttm_base_object base;
34         struct vmw_resource res;
35         struct vmw_ctx_binding_state cbs;
36         struct vmw_cmdbuf_res_manager *man;
37 };
38
39
40
41 typedef int (*vmw_scrub_func)(struct vmw_ctx_bindinfo *, bool);
42
43 static void vmw_user_context_free(struct vmw_resource *res);
44 static struct vmw_resource *
45 vmw_user_context_base_to_res(struct ttm_base_object *base);
46
47 static int vmw_gb_context_create(struct vmw_resource *res);
48 static int vmw_gb_context_bind(struct vmw_resource *res,
49                                struct ttm_validate_buffer *val_buf);
50 static int vmw_gb_context_unbind(struct vmw_resource *res,
51                                  bool readback,
52                                  struct ttm_validate_buffer *val_buf);
53 static int vmw_gb_context_destroy(struct vmw_resource *res);
54 static int vmw_context_scrub_shader(struct vmw_ctx_bindinfo *bi, bool rebind);
55 static int vmw_context_scrub_render_target(struct vmw_ctx_bindinfo *bi,
56                                            bool rebind);
57 static int vmw_context_scrub_texture(struct vmw_ctx_bindinfo *bi, bool rebind);
58 static void vmw_context_binding_state_scrub(struct vmw_ctx_binding_state *cbs);
59 static void vmw_context_binding_state_kill(struct vmw_ctx_binding_state *cbs);
60 static uint64_t vmw_user_context_size;
61
62 static const struct vmw_user_resource_conv user_context_conv = {
63         .object_type = VMW_RES_CONTEXT,
64         .base_obj_to_res = vmw_user_context_base_to_res,
65         .res_free = vmw_user_context_free
66 };
67
68 const struct vmw_user_resource_conv *user_context_converter =
69         &user_context_conv;
70
71
72 static const struct vmw_res_func vmw_legacy_context_func = {
73         .res_type = vmw_res_context,
74         .needs_backup = false,
75         .may_evict = false,
76         .type_name = "legacy contexts",
77         .backup_placement = NULL,
78         .create = NULL,
79         .destroy = NULL,
80         .bind = NULL,
81         .unbind = NULL
82 };
83
84 static const struct vmw_res_func vmw_gb_context_func = {
85         .res_type = vmw_res_context,
86         .needs_backup = true,
87         .may_evict = true,
88         .type_name = "guest backed contexts",
89         .backup_placement = &vmw_mob_placement,
90         .create = vmw_gb_context_create,
91         .destroy = vmw_gb_context_destroy,
92         .bind = vmw_gb_context_bind,
93         .unbind = vmw_gb_context_unbind
94 };
95
96 static const vmw_scrub_func vmw_scrub_funcs[vmw_ctx_binding_max] = {
97         [vmw_ctx_binding_shader] = vmw_context_scrub_shader,
98         [vmw_ctx_binding_rt] = vmw_context_scrub_render_target,
99         [vmw_ctx_binding_tex] = vmw_context_scrub_texture };
100
101 /**
102  * Context management:
103  */
104
105 static void vmw_hw_context_destroy(struct vmw_resource *res)
106 {
107         struct vmw_user_context *uctx =
108                 container_of(res, struct vmw_user_context, res);
109         struct vmw_private *dev_priv = res->dev_priv;
110         struct {
111                 SVGA3dCmdHeader header;
112                 SVGA3dCmdDestroyContext body;
113         } *cmd;
114
115
116         if (res->func->destroy == vmw_gb_context_destroy) {
117                 mutex_lock(&dev_priv->cmdbuf_mutex);
118                 vmw_cmdbuf_res_man_destroy(uctx->man);
119                 mutex_lock(&dev_priv->binding_mutex);
120                 (void) vmw_context_binding_state_kill(&uctx->cbs);
121                 (void) vmw_gb_context_destroy(res);
122                 mutex_unlock(&dev_priv->binding_mutex);
123                 if (dev_priv->pinned_bo != NULL &&
124                     !dev_priv->query_cid_valid)
125                         __vmw_execbuf_release_pinned_bo(dev_priv, NULL);
126                 mutex_unlock(&dev_priv->cmdbuf_mutex);
127                 return;
128         }
129
130         vmw_execbuf_release_pinned_bo(dev_priv);
131         cmd = vmw_fifo_reserve(dev_priv, sizeof(*cmd));
132         if (unlikely(cmd == NULL)) {
133                 DRM_ERROR("Failed reserving FIFO space for surface "
134                           "destruction.\n");
135                 return;
136         }
137
138         cmd->header.id = cpu_to_le32(SVGA_3D_CMD_CONTEXT_DESTROY);
139         cmd->header.size = cpu_to_le32(sizeof(cmd->body));
140         cmd->body.cid = cpu_to_le32(res->id);
141
142         vmw_fifo_commit(dev_priv, sizeof(*cmd));
143         vmw_3d_resource_dec(dev_priv, false);
144 }
145
146 static int vmw_gb_context_init(struct vmw_private *dev_priv,
147                                struct vmw_resource *res,
148                                void (*res_free) (struct vmw_resource *res))
149 {
150         int ret;
151         struct vmw_user_context *uctx =
152                 container_of(res, struct vmw_user_context, res);
153
154         ret = vmw_resource_init(dev_priv, res, true,
155                                 res_free, &vmw_gb_context_func);
156         res->backup_size = SVGA3D_CONTEXT_DATA_SIZE;
157         if (unlikely(ret != 0))
158                 goto out_err;
159
160         if (dev_priv->has_mob) {
161                 uctx->man = vmw_cmdbuf_res_man_create(dev_priv);
162                 if (unlikely(IS_ERR(uctx->man))) {
163                         ret = PTR_ERR(uctx->man);
164                         uctx->man = NULL;
165                         goto out_err;
166                 }
167         }
168
169         memset(&uctx->cbs, 0, sizeof(uctx->cbs));
170         INIT_LIST_HEAD(&uctx->cbs.list);
171
172         vmw_resource_activate(res, vmw_hw_context_destroy);
173         return 0;
174
175 out_err:
176         if (res_free)
177                 res_free(res);
178         else
179                 kfree(res);
180         return ret;
181 }
182
183 static int vmw_context_init(struct vmw_private *dev_priv,
184                             struct vmw_resource *res,
185                             void (*res_free) (struct vmw_resource *res))
186 {
187         int ret;
188
189         struct {
190                 SVGA3dCmdHeader header;
191                 SVGA3dCmdDefineContext body;
192         } *cmd;
193
194         if (dev_priv->has_mob)
195                 return vmw_gb_context_init(dev_priv, res, res_free);
196
197         ret = vmw_resource_init(dev_priv, res, false,
198                                 res_free, &vmw_legacy_context_func);
199
200         if (unlikely(ret != 0)) {
201                 DRM_ERROR("Failed to allocate a resource id.\n");
202                 goto out_early;
203         }
204
205         if (unlikely(res->id >= SVGA3D_MAX_CONTEXT_IDS)) {
206                 DRM_ERROR("Out of hw context ids.\n");
207                 vmw_resource_unreference(&res);
208                 return -ENOMEM;
209         }
210
211         cmd = vmw_fifo_reserve(dev_priv, sizeof(*cmd));
212         if (unlikely(cmd == NULL)) {
213                 DRM_ERROR("Fifo reserve failed.\n");
214                 vmw_resource_unreference(&res);
215                 return -ENOMEM;
216         }
217
218         cmd->header.id = cpu_to_le32(SVGA_3D_CMD_CONTEXT_DEFINE);
219         cmd->header.size = cpu_to_le32(sizeof(cmd->body));
220         cmd->body.cid = cpu_to_le32(res->id);
221
222         vmw_fifo_commit(dev_priv, sizeof(*cmd));
223         (void) vmw_3d_resource_inc(dev_priv, false);
224         vmw_resource_activate(res, vmw_hw_context_destroy);
225         return 0;
226
227 out_early:
228         if (res_free == NULL)
229                 kfree(res);
230         else
231                 res_free(res);
232         return ret;
233 }
234
235 struct vmw_resource *vmw_context_alloc(struct vmw_private *dev_priv)
236 {
237         struct vmw_resource *res = kmalloc(sizeof(*res), GFP_KERNEL);
238         int ret;
239
240         if (unlikely(res == NULL))
241                 return NULL;
242
243         ret = vmw_context_init(dev_priv, res, NULL);
244
245         return (ret == 0) ? res : NULL;
246 }
247
248
249 static int vmw_gb_context_create(struct vmw_resource *res)
250 {
251         struct vmw_private *dev_priv = res->dev_priv;
252         int ret;
253         struct {
254                 SVGA3dCmdHeader header;
255                 SVGA3dCmdDefineGBContext body;
256         } *cmd;
257
258         if (likely(res->id != -1))
259                 return 0;
260
261         ret = vmw_resource_alloc_id(res);
262         if (unlikely(ret != 0)) {
263                 DRM_ERROR("Failed to allocate a context id.\n");
264                 goto out_no_id;
265         }
266
267         if (unlikely(res->id >= VMWGFX_NUM_GB_CONTEXT)) {
268                 ret = -EBUSY;
269                 goto out_no_fifo;
270         }
271
272         cmd = vmw_fifo_reserve(dev_priv, sizeof(*cmd));
273         if (unlikely(cmd == NULL)) {
274                 DRM_ERROR("Failed reserving FIFO space for context "
275                           "creation.\n");
276                 ret = -ENOMEM;
277                 goto out_no_fifo;
278         }
279
280         cmd->header.id = SVGA_3D_CMD_DEFINE_GB_CONTEXT;
281         cmd->header.size = sizeof(cmd->body);
282         cmd->body.cid = res->id;
283         vmw_fifo_commit(dev_priv, sizeof(*cmd));
284         (void) vmw_3d_resource_inc(dev_priv, false);
285
286         return 0;
287
288 out_no_fifo:
289         vmw_resource_release_id(res);
290 out_no_id:
291         return ret;
292 }
293
294 static int vmw_gb_context_bind(struct vmw_resource *res,
295                                struct ttm_validate_buffer *val_buf)
296 {
297         struct vmw_private *dev_priv = res->dev_priv;
298         struct {
299                 SVGA3dCmdHeader header;
300                 SVGA3dCmdBindGBContext body;
301         } *cmd;
302         struct ttm_buffer_object *bo = val_buf->bo;
303
304         BUG_ON(bo->mem.mem_type != VMW_PL_MOB);
305
306         cmd = vmw_fifo_reserve(dev_priv, sizeof(*cmd));
307         if (unlikely(cmd == NULL)) {
308                 DRM_ERROR("Failed reserving FIFO space for context "
309                           "binding.\n");
310                 return -ENOMEM;
311         }
312
313         cmd->header.id = SVGA_3D_CMD_BIND_GB_CONTEXT;
314         cmd->header.size = sizeof(cmd->body);
315         cmd->body.cid = res->id;
316         cmd->body.mobid = bo->mem.start;
317         cmd->body.validContents = res->backup_dirty;
318         res->backup_dirty = false;
319         vmw_fifo_commit(dev_priv, sizeof(*cmd));
320
321         return 0;
322 }
323
324 static int vmw_gb_context_unbind(struct vmw_resource *res,
325                                  bool readback,
326                                  struct ttm_validate_buffer *val_buf)
327 {
328         struct vmw_private *dev_priv = res->dev_priv;
329         struct ttm_buffer_object *bo = val_buf->bo;
330         struct vmw_fence_obj *fence;
331         struct vmw_user_context *uctx =
332                 container_of(res, struct vmw_user_context, res);
333
334         struct {
335                 SVGA3dCmdHeader header;
336                 SVGA3dCmdReadbackGBContext body;
337         } *cmd1;
338         struct {
339                 SVGA3dCmdHeader header;
340                 SVGA3dCmdBindGBContext body;
341         } *cmd2;
342         uint32_t submit_size;
343         uint8_t *cmd;
344
345
346         BUG_ON(bo->mem.mem_type != VMW_PL_MOB);
347
348         mutex_lock(&dev_priv->binding_mutex);
349         vmw_context_binding_state_scrub(&uctx->cbs);
350
351         submit_size = sizeof(*cmd2) + (readback ? sizeof(*cmd1) : 0);
352
353         cmd = vmw_fifo_reserve(dev_priv, submit_size);
354         if (unlikely(cmd == NULL)) {
355                 DRM_ERROR("Failed reserving FIFO space for context "
356                           "unbinding.\n");
357                 mutex_unlock(&dev_priv->binding_mutex);
358                 return -ENOMEM;
359         }
360
361         cmd2 = (void *) cmd;
362         if (readback) {
363                 cmd1 = (void *) cmd;
364                 cmd1->header.id = SVGA_3D_CMD_READBACK_GB_CONTEXT;
365                 cmd1->header.size = sizeof(cmd1->body);
366                 cmd1->body.cid = res->id;
367                 cmd2 = (void *) (&cmd1[1]);
368         }
369         cmd2->header.id = SVGA_3D_CMD_BIND_GB_CONTEXT;
370         cmd2->header.size = sizeof(cmd2->body);
371         cmd2->body.cid = res->id;
372         cmd2->body.mobid = SVGA3D_INVALID_ID;
373
374         vmw_fifo_commit(dev_priv, submit_size);
375         mutex_unlock(&dev_priv->binding_mutex);
376
377         /*
378          * Create a fence object and fence the backup buffer.
379          */
380
381         (void) vmw_execbuf_fence_commands(NULL, dev_priv,
382                                           &fence, NULL);
383
384         vmw_fence_single_bo(bo, fence);
385
386         if (likely(fence != NULL))
387                 vmw_fence_obj_unreference(&fence);
388
389         return 0;
390 }
391
392 static int vmw_gb_context_destroy(struct vmw_resource *res)
393 {
394         struct vmw_private *dev_priv = res->dev_priv;
395         struct {
396                 SVGA3dCmdHeader header;
397                 SVGA3dCmdDestroyGBContext body;
398         } *cmd;
399
400         if (likely(res->id == -1))
401                 return 0;
402
403         cmd = vmw_fifo_reserve(dev_priv, sizeof(*cmd));
404         if (unlikely(cmd == NULL)) {
405                 DRM_ERROR("Failed reserving FIFO space for context "
406                           "destruction.\n");
407                 return -ENOMEM;
408         }
409
410         cmd->header.id = SVGA_3D_CMD_DESTROY_GB_CONTEXT;
411         cmd->header.size = sizeof(cmd->body);
412         cmd->body.cid = res->id;
413         vmw_fifo_commit(dev_priv, sizeof(*cmd));
414         if (dev_priv->query_cid == res->id)
415                 dev_priv->query_cid_valid = false;
416         vmw_resource_release_id(res);
417         vmw_3d_resource_dec(dev_priv, false);
418
419         return 0;
420 }
421
422 /**
423  * User-space context management:
424  */
425
426 static struct vmw_resource *
427 vmw_user_context_base_to_res(struct ttm_base_object *base)
428 {
429         return &(container_of(base, struct vmw_user_context, base)->res);
430 }
431
432 static void vmw_user_context_free(struct vmw_resource *res)
433 {
434         struct vmw_user_context *ctx =
435             container_of(res, struct vmw_user_context, res);
436         struct vmw_private *dev_priv = res->dev_priv;
437
438         ttm_base_object_kfree(ctx, base);
439         ttm_mem_global_free(vmw_mem_glob(dev_priv),
440                             vmw_user_context_size);
441 }
442
443 /**
444  * This function is called when user space has no more references on the
445  * base object. It releases the base-object's reference on the resource object.
446  */
447
448 static void vmw_user_context_base_release(struct ttm_base_object **p_base)
449 {
450         struct ttm_base_object *base = *p_base;
451         struct vmw_user_context *ctx =
452             container_of(base, struct vmw_user_context, base);
453         struct vmw_resource *res = &ctx->res;
454
455         *p_base = NULL;
456         vmw_resource_unreference(&res);
457 }
458
459 int vmw_context_destroy_ioctl(struct drm_device *dev, void *data,
460                               struct drm_file *file_priv)
461 {
462         struct drm_vmw_context_arg *arg = (struct drm_vmw_context_arg *)data;
463         struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile;
464
465         return ttm_ref_object_base_unref(tfile, arg->cid, TTM_REF_USAGE);
466 }
467
468 int vmw_context_define_ioctl(struct drm_device *dev, void *data,
469                              struct drm_file *file_priv)
470 {
471         struct vmw_private *dev_priv = vmw_priv(dev);
472         struct vmw_user_context *ctx;
473         struct vmw_resource *res;
474         struct vmw_resource *tmp;
475         struct drm_vmw_context_arg *arg = (struct drm_vmw_context_arg *)data;
476         struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile;
477         int ret;
478
479
480         /*
481          * Approximate idr memory usage with 128 bytes. It will be limited
482          * by maximum number_of contexts anyway.
483          */
484
485         if (unlikely(vmw_user_context_size == 0))
486                 vmw_user_context_size = ttm_round_pot(sizeof(*ctx)) + 128 +
487                   ((dev_priv->has_mob) ? vmw_cmdbuf_res_man_size() : 0);
488
489         ret = ttm_read_lock(&dev_priv->reservation_sem, true);
490         if (unlikely(ret != 0))
491                 return ret;
492
493         ret = ttm_mem_global_alloc(vmw_mem_glob(dev_priv),
494                                    vmw_user_context_size,
495                                    false, true);
496         if (unlikely(ret != 0)) {
497                 if (ret != -ERESTARTSYS)
498                         DRM_ERROR("Out of graphics memory for context"
499                                   " creation.\n");
500                 goto out_unlock;
501         }
502
503         ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
504         if (unlikely(ctx == NULL)) {
505                 ttm_mem_global_free(vmw_mem_glob(dev_priv),
506                                     vmw_user_context_size);
507                 ret = -ENOMEM;
508                 goto out_unlock;
509         }
510
511         res = &ctx->res;
512         ctx->base.shareable = false;
513         ctx->base.tfile = NULL;
514
515         /*
516          * From here on, the destructor takes over resource freeing.
517          */
518
519         ret = vmw_context_init(dev_priv, res, vmw_user_context_free);
520         if (unlikely(ret != 0))
521                 goto out_unlock;
522
523         tmp = vmw_resource_reference(&ctx->res);
524         ret = ttm_base_object_init(tfile, &ctx->base, false, VMW_RES_CONTEXT,
525                                    &vmw_user_context_base_release, NULL);
526
527         if (unlikely(ret != 0)) {
528                 vmw_resource_unreference(&tmp);
529                 goto out_err;
530         }
531
532         arg->cid = ctx->base.hash.key;
533 out_err:
534         vmw_resource_unreference(&res);
535 out_unlock:
536         ttm_read_unlock(&dev_priv->reservation_sem);
537         return ret;
538
539 }
540
541 /**
542  * vmw_context_scrub_shader - scrub a shader binding from a context.
543  *
544  * @bi: single binding information.
545  * @rebind: Whether to issue a bind instead of scrub command.
546  */
547 static int vmw_context_scrub_shader(struct vmw_ctx_bindinfo *bi, bool rebind)
548 {
549         struct vmw_private *dev_priv = bi->ctx->dev_priv;
550         struct {
551                 SVGA3dCmdHeader header;
552                 SVGA3dCmdSetShader body;
553         } *cmd;
554
555         cmd = vmw_fifo_reserve(dev_priv, sizeof(*cmd));
556         if (unlikely(cmd == NULL)) {
557                 DRM_ERROR("Failed reserving FIFO space for shader "
558                           "unbinding.\n");
559                 return -ENOMEM;
560         }
561
562         cmd->header.id = SVGA_3D_CMD_SET_SHADER;
563         cmd->header.size = sizeof(cmd->body);
564         cmd->body.cid = bi->ctx->id;
565         cmd->body.type = bi->i1.shader_type;
566         cmd->body.shid = ((rebind) ? bi->res->id : SVGA3D_INVALID_ID);
567         vmw_fifo_commit(dev_priv, sizeof(*cmd));
568
569         return 0;
570 }
571
572 /**
573  * vmw_context_scrub_render_target - scrub a render target binding
574  * from a context.
575  *
576  * @bi: single binding information.
577  * @rebind: Whether to issue a bind instead of scrub command.
578  */
579 static int vmw_context_scrub_render_target(struct vmw_ctx_bindinfo *bi,
580                                            bool rebind)
581 {
582         struct vmw_private *dev_priv = bi->ctx->dev_priv;
583         struct {
584                 SVGA3dCmdHeader header;
585                 SVGA3dCmdSetRenderTarget body;
586         } *cmd;
587
588         cmd = vmw_fifo_reserve(dev_priv, sizeof(*cmd));
589         if (unlikely(cmd == NULL)) {
590                 DRM_ERROR("Failed reserving FIFO space for render target "
591                           "unbinding.\n");
592                 return -ENOMEM;
593         }
594
595         cmd->header.id = SVGA_3D_CMD_SETRENDERTARGET;
596         cmd->header.size = sizeof(cmd->body);
597         cmd->body.cid = bi->ctx->id;
598         cmd->body.type = bi->i1.rt_type;
599         cmd->body.target.sid = ((rebind) ? bi->res->id : SVGA3D_INVALID_ID);
600         cmd->body.target.face = 0;
601         cmd->body.target.mipmap = 0;
602         vmw_fifo_commit(dev_priv, sizeof(*cmd));
603
604         return 0;
605 }
606
607 /**
608  * vmw_context_scrub_texture - scrub a texture binding from a context.
609  *
610  * @bi: single binding information.
611  * @rebind: Whether to issue a bind instead of scrub command.
612  *
613  * TODO: Possibly complement this function with a function that takes
614  * a list of texture bindings and combines them to a single command.
615  */
616 static int vmw_context_scrub_texture(struct vmw_ctx_bindinfo *bi,
617                                      bool rebind)
618 {
619         struct vmw_private *dev_priv = bi->ctx->dev_priv;
620         struct {
621                 SVGA3dCmdHeader header;
622                 struct {
623                         SVGA3dCmdSetTextureState c;
624                         SVGA3dTextureState s1;
625                 } body;
626         } *cmd;
627
628         cmd = vmw_fifo_reserve(dev_priv, sizeof(*cmd));
629         if (unlikely(cmd == NULL)) {
630                 DRM_ERROR("Failed reserving FIFO space for texture "
631                           "unbinding.\n");
632                 return -ENOMEM;
633         }
634
635
636         cmd->header.id = SVGA_3D_CMD_SETTEXTURESTATE;
637         cmd->header.size = sizeof(cmd->body);
638         cmd->body.c.cid = bi->ctx->id;
639         cmd->body.s1.stage = bi->i1.texture_stage;
640         cmd->body.s1.name = SVGA3D_TS_BIND_TEXTURE;
641         cmd->body.s1.value = ((rebind) ? bi->res->id : SVGA3D_INVALID_ID);
642         vmw_fifo_commit(dev_priv, sizeof(*cmd));
643
644         return 0;
645 }
646
647 /**
648  * vmw_context_binding_drop: Stop tracking a context binding
649  *
650  * @cb: Pointer to binding tracker storage.
651  *
652  * Stops tracking a context binding, and re-initializes its storage.
653  * Typically used when the context binding is replaced with a binding to
654  * another (or the same, for that matter) resource.
655  */
656 static void vmw_context_binding_drop(struct vmw_ctx_binding *cb)
657 {
658         list_del(&cb->ctx_list);
659         if (!list_empty(&cb->res_list))
660                 list_del(&cb->res_list);
661         cb->bi.ctx = NULL;
662 }
663
664 /**
665  * vmw_context_binding_add: Start tracking a context binding
666  *
667  * @cbs: Pointer to the context binding state tracker.
668  * @bi: Information about the binding to track.
669  *
670  * Performs basic checks on the binding to make sure arguments are within
671  * bounds and then starts tracking the binding in the context binding
672  * state structure @cbs.
673  */
674 int vmw_context_binding_add(struct vmw_ctx_binding_state *cbs,
675                             const struct vmw_ctx_bindinfo *bi)
676 {
677         struct vmw_ctx_binding *loc;
678
679         switch (bi->bt) {
680         case vmw_ctx_binding_rt:
681                 if (unlikely((unsigned)bi->i1.rt_type >= SVGA3D_RT_MAX)) {
682                         DRM_ERROR("Illegal render target type %u.\n",
683                                   (unsigned) bi->i1.rt_type);
684                         return -EINVAL;
685                 }
686                 loc = &cbs->render_targets[bi->i1.rt_type];
687                 break;
688         case vmw_ctx_binding_tex:
689                 if (unlikely((unsigned)bi->i1.texture_stage >=
690                              SVGA3D_NUM_TEXTURE_UNITS)) {
691                         DRM_ERROR("Illegal texture/sampler unit %u.\n",
692                                   (unsigned) bi->i1.texture_stage);
693                         return -EINVAL;
694                 }
695                 loc = &cbs->texture_units[bi->i1.texture_stage];
696                 break;
697         case vmw_ctx_binding_shader:
698                 if (unlikely((unsigned)bi->i1.shader_type >=
699                              SVGA3D_SHADERTYPE_MAX)) {
700                         DRM_ERROR("Illegal shader type %u.\n",
701                                   (unsigned) bi->i1.shader_type);
702                         return -EINVAL;
703                 }
704                 loc = &cbs->shaders[bi->i1.shader_type];
705                 break;
706         default:
707                 BUG();
708         }
709
710         if (loc->bi.ctx != NULL)
711                 vmw_context_binding_drop(loc);
712
713         loc->bi = *bi;
714         loc->bi.scrubbed = false;
715         list_add_tail(&loc->ctx_list, &cbs->list);
716         INIT_LIST_HEAD(&loc->res_list);
717
718         return 0;
719 }
720
721 /**
722  * vmw_context_binding_transfer: Transfer a context binding tracking entry.
723  *
724  * @cbs: Pointer to the persistent context binding state tracker.
725  * @bi: Information about the binding to track.
726  *
727  */
728 static void vmw_context_binding_transfer(struct vmw_ctx_binding_state *cbs,
729                                          const struct vmw_ctx_bindinfo *bi)
730 {
731         struct vmw_ctx_binding *loc;
732
733         switch (bi->bt) {
734         case vmw_ctx_binding_rt:
735                 loc = &cbs->render_targets[bi->i1.rt_type];
736                 break;
737         case vmw_ctx_binding_tex:
738                 loc = &cbs->texture_units[bi->i1.texture_stage];
739                 break;
740         case vmw_ctx_binding_shader:
741                 loc = &cbs->shaders[bi->i1.shader_type];
742                 break;
743         default:
744                 BUG();
745         }
746
747         if (loc->bi.ctx != NULL)
748                 vmw_context_binding_drop(loc);
749
750         if (bi->res != NULL) {
751                 loc->bi = *bi;
752                 list_add_tail(&loc->ctx_list, &cbs->list);
753                 list_add_tail(&loc->res_list, &bi->res->binding_head);
754         }
755 }
756
757 /**
758  * vmw_context_binding_kill - Kill a binding on the device
759  * and stop tracking it.
760  *
761  * @cb: Pointer to binding tracker storage.
762  *
763  * Emits FIFO commands to scrub a binding represented by @cb.
764  * Then stops tracking the binding and re-initializes its storage.
765  */
766 static void vmw_context_binding_kill(struct vmw_ctx_binding *cb)
767 {
768         if (!cb->bi.scrubbed) {
769                 (void) vmw_scrub_funcs[cb->bi.bt](&cb->bi, false);
770                 cb->bi.scrubbed = true;
771         }
772         vmw_context_binding_drop(cb);
773 }
774
775 /**
776  * vmw_context_binding_state_kill - Kill all bindings associated with a
777  * struct vmw_ctx_binding state structure, and re-initialize the structure.
778  *
779  * @cbs: Pointer to the context binding state tracker.
780  *
781  * Emits commands to scrub all bindings associated with the
782  * context binding state tracker. Then re-initializes the whole structure.
783  */
784 static void vmw_context_binding_state_kill(struct vmw_ctx_binding_state *cbs)
785 {
786         struct vmw_ctx_binding *entry, *next;
787
788         list_for_each_entry_safe(entry, next, &cbs->list, ctx_list)
789                 vmw_context_binding_kill(entry);
790 }
791
792 /**
793  * vmw_context_binding_state_scrub - Scrub all bindings associated with a
794  * struct vmw_ctx_binding state structure.
795  *
796  * @cbs: Pointer to the context binding state tracker.
797  *
798  * Emits commands to scrub all bindings associated with the
799  * context binding state tracker.
800  */
801 static void vmw_context_binding_state_scrub(struct vmw_ctx_binding_state *cbs)
802 {
803         struct vmw_ctx_binding *entry;
804
805         list_for_each_entry(entry, &cbs->list, ctx_list) {
806                 if (!entry->bi.scrubbed) {
807                         (void) vmw_scrub_funcs[entry->bi.bt](&entry->bi, false);
808                         entry->bi.scrubbed = true;
809                 }
810         }
811 }
812
813 /**
814  * vmw_context_binding_res_list_kill - Kill all bindings on a
815  * resource binding list
816  *
817  * @head: list head of resource binding list
818  *
819  * Kills all bindings associated with a specific resource. Typically
820  * called before the resource is destroyed.
821  */
822 void vmw_context_binding_res_list_kill(struct list_head *head)
823 {
824         struct vmw_ctx_binding *entry, *next;
825
826         list_for_each_entry_safe(entry, next, head, res_list)
827                 vmw_context_binding_kill(entry);
828 }
829
830 /**
831  * vmw_context_binding_res_list_scrub - Scrub all bindings on a
832  * resource binding list
833  *
834  * @head: list head of resource binding list
835  *
836  * Scrub all bindings associated with a specific resource. Typically
837  * called before the resource is evicted.
838  */
839 void vmw_context_binding_res_list_scrub(struct list_head *head)
840 {
841         struct vmw_ctx_binding *entry;
842
843         list_for_each_entry(entry, head, res_list) {
844                 if (!entry->bi.scrubbed) {
845                         (void) vmw_scrub_funcs[entry->bi.bt](&entry->bi, false);
846                         entry->bi.scrubbed = true;
847                 }
848         }
849 }
850
851 /**
852  * vmw_context_binding_state_transfer - Commit staged binding info
853  *
854  * @ctx: Pointer to context to commit the staged binding info to.
855  * @from: Staged binding info built during execbuf.
856  *
857  * Transfers binding info from a temporary structure to the persistent
858  * structure in the context. This can be done once commands
859  */
860 void vmw_context_binding_state_transfer(struct vmw_resource *ctx,
861                                         struct vmw_ctx_binding_state *from)
862 {
863         struct vmw_user_context *uctx =
864                 container_of(ctx, struct vmw_user_context, res);
865         struct vmw_ctx_binding *entry, *next;
866
867         list_for_each_entry_safe(entry, next, &from->list, ctx_list)
868                 vmw_context_binding_transfer(&uctx->cbs, &entry->bi);
869 }
870
871 /**
872  * vmw_context_rebind_all - Rebind all scrubbed bindings of a context
873  *
874  * @ctx: The context resource
875  *
876  * Walks through the context binding list and rebinds all scrubbed
877  * resources.
878  */
879 int vmw_context_rebind_all(struct vmw_resource *ctx)
880 {
881         struct vmw_ctx_binding *entry;
882         struct vmw_user_context *uctx =
883                 container_of(ctx, struct vmw_user_context, res);
884         struct vmw_ctx_binding_state *cbs = &uctx->cbs;
885         int ret;
886
887         list_for_each_entry(entry, &cbs->list, ctx_list) {
888                 if (likely(!entry->bi.scrubbed))
889                         continue;
890
891                 if (WARN_ON(entry->bi.res == NULL || entry->bi.res->id ==
892                             SVGA3D_INVALID_ID))
893                         continue;
894
895                 ret = vmw_scrub_funcs[entry->bi.bt](&entry->bi, true);
896                 if (unlikely(ret != 0))
897                         return ret;
898
899                 entry->bi.scrubbed = false;
900         }
901
902         return 0;
903 }
904
905 /**
906  * vmw_context_binding_list - Return a list of context bindings
907  *
908  * @ctx: The context resource
909  *
910  * Returns the current list of bindings of the given context. Note that
911  * this list becomes stale as soon as the dev_priv::binding_mutex is unlocked.
912  */
913 struct list_head *vmw_context_binding_list(struct vmw_resource *ctx)
914 {
915         return &(container_of(ctx, struct vmw_user_context, res)->cbs.list);
916 }
917
918 struct vmw_cmdbuf_res_manager *vmw_context_res_man(struct vmw_resource *ctx)
919 {
920         return container_of(ctx, struct vmw_user_context, res)->man;
921 }