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