drm/vmwgfx: Stop using raw ttm_buffer_object's
[sfrench/cifs-2.6.git] / drivers / gpu / drm / vmwgfx / vmwgfx_context.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_user_context {
36         struct ttm_base_object base;
37         struct vmw_resource res;
38         struct vmw_ctx_binding_state *cbs;
39         struct vmw_cmdbuf_res_manager *man;
40         struct vmw_resource *cotables[SVGA_COTABLE_MAX];
41         spinlock_t cotable_lock;
42         struct vmw_bo *dx_query_mob;
43 };
44
45 static void vmw_user_context_free(struct vmw_resource *res);
46 static struct vmw_resource *
47 vmw_user_context_base_to_res(struct ttm_base_object *base);
48
49 static int vmw_gb_context_create(struct vmw_resource *res);
50 static int vmw_gb_context_bind(struct vmw_resource *res,
51                                struct ttm_validate_buffer *val_buf);
52 static int vmw_gb_context_unbind(struct vmw_resource *res,
53                                  bool readback,
54                                  struct ttm_validate_buffer *val_buf);
55 static int vmw_gb_context_destroy(struct vmw_resource *res);
56 static int vmw_dx_context_create(struct vmw_resource *res);
57 static int vmw_dx_context_bind(struct vmw_resource *res,
58                                struct ttm_validate_buffer *val_buf);
59 static int vmw_dx_context_unbind(struct vmw_resource *res,
60                                  bool readback,
61                                  struct ttm_validate_buffer *val_buf);
62 static int vmw_dx_context_destroy(struct vmw_resource *res);
63
64 static const struct vmw_user_resource_conv user_context_conv = {
65         .object_type = VMW_RES_CONTEXT,
66         .base_obj_to_res = vmw_user_context_base_to_res,
67         .res_free = vmw_user_context_free
68 };
69
70 const struct vmw_user_resource_conv *user_context_converter =
71         &user_context_conv;
72
73
74 static const struct vmw_res_func vmw_legacy_context_func = {
75         .res_type = vmw_res_context,
76         .needs_guest_memory = false,
77         .may_evict = false,
78         .type_name = "legacy contexts",
79         .domain = VMW_BO_DOMAIN_SYS,
80         .busy_domain = VMW_BO_DOMAIN_SYS,
81         .create = NULL,
82         .destroy = NULL,
83         .bind = NULL,
84         .unbind = NULL
85 };
86
87 static const struct vmw_res_func vmw_gb_context_func = {
88         .res_type = vmw_res_context,
89         .needs_guest_memory = true,
90         .may_evict = true,
91         .prio = 3,
92         .dirty_prio = 3,
93         .type_name = "guest backed contexts",
94         .domain = VMW_BO_DOMAIN_MOB,
95         .busy_domain = VMW_BO_DOMAIN_MOB,
96         .create = vmw_gb_context_create,
97         .destroy = vmw_gb_context_destroy,
98         .bind = vmw_gb_context_bind,
99         .unbind = vmw_gb_context_unbind
100 };
101
102 static const struct vmw_res_func vmw_dx_context_func = {
103         .res_type = vmw_res_dx_context,
104         .needs_guest_memory = true,
105         .may_evict = true,
106         .prio = 3,
107         .dirty_prio = 3,
108         .type_name = "dx contexts",
109         .domain = VMW_BO_DOMAIN_MOB,
110         .busy_domain = VMW_BO_DOMAIN_MOB,
111         .create = vmw_dx_context_create,
112         .destroy = vmw_dx_context_destroy,
113         .bind = vmw_dx_context_bind,
114         .unbind = vmw_dx_context_unbind
115 };
116
117 /*
118  * Context management:
119  */
120
121 static void vmw_context_cotables_unref(struct vmw_private *dev_priv,
122                                        struct vmw_user_context *uctx)
123 {
124         struct vmw_resource *res;
125         int i;
126         u32 cotable_max = has_sm5_context(dev_priv) ?
127                 SVGA_COTABLE_MAX : SVGA_COTABLE_DX10_MAX;
128
129         for (i = 0; i < cotable_max; ++i) {
130                 spin_lock(&uctx->cotable_lock);
131                 res = uctx->cotables[i];
132                 uctx->cotables[i] = NULL;
133                 spin_unlock(&uctx->cotable_lock);
134
135                 if (res)
136                         vmw_resource_unreference(&res);
137         }
138 }
139
140 static void vmw_hw_context_destroy(struct vmw_resource *res)
141 {
142         struct vmw_user_context *uctx =
143                 container_of(res, struct vmw_user_context, res);
144         struct vmw_private *dev_priv = res->dev_priv;
145         struct {
146                 SVGA3dCmdHeader header;
147                 SVGA3dCmdDestroyContext body;
148         } *cmd;
149
150
151         if (res->func->destroy == vmw_gb_context_destroy ||
152             res->func->destroy == vmw_dx_context_destroy) {
153                 mutex_lock(&dev_priv->cmdbuf_mutex);
154                 vmw_cmdbuf_res_man_destroy(uctx->man);
155                 mutex_lock(&dev_priv->binding_mutex);
156                 vmw_binding_state_kill(uctx->cbs);
157                 (void) res->func->destroy(res);
158                 mutex_unlock(&dev_priv->binding_mutex);
159                 if (dev_priv->pinned_bo != NULL &&
160                     !dev_priv->query_cid_valid)
161                         __vmw_execbuf_release_pinned_bo(dev_priv, NULL);
162                 mutex_unlock(&dev_priv->cmdbuf_mutex);
163                 vmw_context_cotables_unref(dev_priv, uctx);
164                 return;
165         }
166
167         vmw_execbuf_release_pinned_bo(dev_priv);
168         cmd = VMW_CMD_RESERVE(dev_priv, sizeof(*cmd));
169         if (unlikely(cmd == NULL))
170                 return;
171
172         cmd->header.id = SVGA_3D_CMD_CONTEXT_DESTROY;
173         cmd->header.size = sizeof(cmd->body);
174         cmd->body.cid = res->id;
175
176         vmw_cmd_commit(dev_priv, sizeof(*cmd));
177         vmw_fifo_resource_dec(dev_priv);
178 }
179
180 static int vmw_gb_context_init(struct vmw_private *dev_priv,
181                                bool dx,
182                                struct vmw_resource *res,
183                                void (*res_free)(struct vmw_resource *res))
184 {
185         int ret, i;
186         struct vmw_user_context *uctx =
187                 container_of(res, struct vmw_user_context, res);
188
189         res->guest_memory_size = (dx ? sizeof(SVGADXContextMobFormat) :
190                                  sizeof(SVGAGBContextData));
191         ret = vmw_resource_init(dev_priv, res, true,
192                                 res_free,
193                                 dx ? &vmw_dx_context_func :
194                                 &vmw_gb_context_func);
195         if (unlikely(ret != 0))
196                 goto out_err;
197
198         if (dev_priv->has_mob) {
199                 uctx->man = vmw_cmdbuf_res_man_create(dev_priv);
200                 if (IS_ERR(uctx->man)) {
201                         ret = PTR_ERR(uctx->man);
202                         uctx->man = NULL;
203                         goto out_err;
204                 }
205         }
206
207         uctx->cbs = vmw_binding_state_alloc(dev_priv);
208         if (IS_ERR(uctx->cbs)) {
209                 ret = PTR_ERR(uctx->cbs);
210                 goto out_err;
211         }
212
213         spin_lock_init(&uctx->cotable_lock);
214
215         if (dx) {
216                 u32 cotable_max = has_sm5_context(dev_priv) ?
217                         SVGA_COTABLE_MAX : SVGA_COTABLE_DX10_MAX;
218                 for (i = 0; i < cotable_max; ++i) {
219                         uctx->cotables[i] = vmw_cotable_alloc(dev_priv,
220                                                               &uctx->res, i);
221                         if (IS_ERR(uctx->cotables[i])) {
222                                 ret = PTR_ERR(uctx->cotables[i]);
223                                 goto out_cotables;
224                         }
225                 }
226         }
227
228         res->hw_destroy = vmw_hw_context_destroy;
229         return 0;
230
231 out_cotables:
232         vmw_context_cotables_unref(dev_priv, uctx);
233 out_err:
234         if (res_free)
235                 res_free(res);
236         else
237                 kfree(res);
238         return ret;
239 }
240
241 static int vmw_context_init(struct vmw_private *dev_priv,
242                             struct vmw_resource *res,
243                             void (*res_free)(struct vmw_resource *res),
244                             bool dx)
245 {
246         int ret;
247
248         struct {
249                 SVGA3dCmdHeader header;
250                 SVGA3dCmdDefineContext body;
251         } *cmd;
252
253         if (dev_priv->has_mob)
254                 return vmw_gb_context_init(dev_priv, dx, res, res_free);
255
256         ret = vmw_resource_init(dev_priv, res, false,
257                                 res_free, &vmw_legacy_context_func);
258
259         if (unlikely(ret != 0)) {
260                 DRM_ERROR("Failed to allocate a resource id.\n");
261                 goto out_early;
262         }
263
264         if (unlikely(res->id >= SVGA3D_HB_MAX_CONTEXT_IDS)) {
265                 DRM_ERROR("Out of hw context ids.\n");
266                 vmw_resource_unreference(&res);
267                 return -ENOMEM;
268         }
269
270         cmd = VMW_CMD_RESERVE(dev_priv, sizeof(*cmd));
271         if (unlikely(cmd == NULL)) {
272                 vmw_resource_unreference(&res);
273                 return -ENOMEM;
274         }
275
276         cmd->header.id = SVGA_3D_CMD_CONTEXT_DEFINE;
277         cmd->header.size = sizeof(cmd->body);
278         cmd->body.cid = res->id;
279
280         vmw_cmd_commit(dev_priv, sizeof(*cmd));
281         vmw_fifo_resource_inc(dev_priv);
282         res->hw_destroy = vmw_hw_context_destroy;
283         return 0;
284
285 out_early:
286         if (res_free == NULL)
287                 kfree(res);
288         else
289                 res_free(res);
290         return ret;
291 }
292
293
294 /*
295  * GB context.
296  */
297
298 static int vmw_gb_context_create(struct vmw_resource *res)
299 {
300         struct vmw_private *dev_priv = res->dev_priv;
301         int ret;
302         struct {
303                 SVGA3dCmdHeader header;
304                 SVGA3dCmdDefineGBContext body;
305         } *cmd;
306
307         if (likely(res->id != -1))
308                 return 0;
309
310         ret = vmw_resource_alloc_id(res);
311         if (unlikely(ret != 0)) {
312                 DRM_ERROR("Failed to allocate a context id.\n");
313                 goto out_no_id;
314         }
315
316         if (unlikely(res->id >= VMWGFX_NUM_GB_CONTEXT)) {
317                 ret = -EBUSY;
318                 goto out_no_fifo;
319         }
320
321         cmd = VMW_CMD_RESERVE(dev_priv, sizeof(*cmd));
322         if (unlikely(cmd == NULL)) {
323                 ret = -ENOMEM;
324                 goto out_no_fifo;
325         }
326
327         cmd->header.id = SVGA_3D_CMD_DEFINE_GB_CONTEXT;
328         cmd->header.size = sizeof(cmd->body);
329         cmd->body.cid = res->id;
330         vmw_cmd_commit(dev_priv, sizeof(*cmd));
331         vmw_fifo_resource_inc(dev_priv);
332
333         return 0;
334
335 out_no_fifo:
336         vmw_resource_release_id(res);
337 out_no_id:
338         return ret;
339 }
340
341 static int vmw_gb_context_bind(struct vmw_resource *res,
342                                struct ttm_validate_buffer *val_buf)
343 {
344         struct vmw_private *dev_priv = res->dev_priv;
345         struct {
346                 SVGA3dCmdHeader header;
347                 SVGA3dCmdBindGBContext body;
348         } *cmd;
349         struct ttm_buffer_object *bo = val_buf->bo;
350
351         BUG_ON(bo->resource->mem_type != VMW_PL_MOB);
352
353         cmd = VMW_CMD_RESERVE(dev_priv, sizeof(*cmd));
354         if (unlikely(cmd == NULL))
355                 return -ENOMEM;
356
357         cmd->header.id = SVGA_3D_CMD_BIND_GB_CONTEXT;
358         cmd->header.size = sizeof(cmd->body);
359         cmd->body.cid = res->id;
360         cmd->body.mobid = bo->resource->start;
361         cmd->body.validContents = res->guest_memory_dirty;
362         res->guest_memory_dirty = false;
363         vmw_cmd_commit(dev_priv, sizeof(*cmd));
364
365         return 0;
366 }
367
368 static int vmw_gb_context_unbind(struct vmw_resource *res,
369                                  bool readback,
370                                  struct ttm_validate_buffer *val_buf)
371 {
372         struct vmw_private *dev_priv = res->dev_priv;
373         struct ttm_buffer_object *bo = val_buf->bo;
374         struct vmw_fence_obj *fence;
375         struct vmw_user_context *uctx =
376                 container_of(res, struct vmw_user_context, res);
377
378         struct {
379                 SVGA3dCmdHeader header;
380                 SVGA3dCmdReadbackGBContext body;
381         } *cmd1;
382         struct {
383                 SVGA3dCmdHeader header;
384                 SVGA3dCmdBindGBContext body;
385         } *cmd2;
386         uint32_t submit_size;
387         uint8_t *cmd;
388
389
390         BUG_ON(bo->resource->mem_type != VMW_PL_MOB);
391
392         mutex_lock(&dev_priv->binding_mutex);
393         vmw_binding_state_scrub(uctx->cbs);
394
395         submit_size = sizeof(*cmd2) + (readback ? sizeof(*cmd1) : 0);
396
397         cmd = VMW_CMD_RESERVE(dev_priv, submit_size);
398         if (unlikely(cmd == NULL)) {
399                 mutex_unlock(&dev_priv->binding_mutex);
400                 return -ENOMEM;
401         }
402
403         cmd2 = (void *) cmd;
404         if (readback) {
405                 cmd1 = (void *) cmd;
406                 cmd1->header.id = SVGA_3D_CMD_READBACK_GB_CONTEXT;
407                 cmd1->header.size = sizeof(cmd1->body);
408                 cmd1->body.cid = res->id;
409                 cmd2 = (void *) (&cmd1[1]);
410         }
411         cmd2->header.id = SVGA_3D_CMD_BIND_GB_CONTEXT;
412         cmd2->header.size = sizeof(cmd2->body);
413         cmd2->body.cid = res->id;
414         cmd2->body.mobid = SVGA3D_INVALID_ID;
415
416         vmw_cmd_commit(dev_priv, submit_size);
417         mutex_unlock(&dev_priv->binding_mutex);
418
419         /*
420          * Create a fence object and fence the backup buffer.
421          */
422
423         (void) vmw_execbuf_fence_commands(NULL, dev_priv,
424                                           &fence, NULL);
425
426         vmw_bo_fence_single(bo, fence);
427
428         if (likely(fence != NULL))
429                 vmw_fence_obj_unreference(&fence);
430
431         return 0;
432 }
433
434 static int vmw_gb_context_destroy(struct vmw_resource *res)
435 {
436         struct vmw_private *dev_priv = res->dev_priv;
437         struct {
438                 SVGA3dCmdHeader header;
439                 SVGA3dCmdDestroyGBContext body;
440         } *cmd;
441
442         if (likely(res->id == -1))
443                 return 0;
444
445         cmd = VMW_CMD_RESERVE(dev_priv, sizeof(*cmd));
446         if (unlikely(cmd == NULL))
447                 return -ENOMEM;
448
449         cmd->header.id = SVGA_3D_CMD_DESTROY_GB_CONTEXT;
450         cmd->header.size = sizeof(cmd->body);
451         cmd->body.cid = res->id;
452         vmw_cmd_commit(dev_priv, sizeof(*cmd));
453         if (dev_priv->query_cid == res->id)
454                 dev_priv->query_cid_valid = false;
455         vmw_resource_release_id(res);
456         vmw_fifo_resource_dec(dev_priv);
457
458         return 0;
459 }
460
461 /*
462  * DX context.
463  */
464
465 static int vmw_dx_context_create(struct vmw_resource *res)
466 {
467         struct vmw_private *dev_priv = res->dev_priv;
468         int ret;
469         struct {
470                 SVGA3dCmdHeader header;
471                 SVGA3dCmdDXDefineContext body;
472         } *cmd;
473
474         if (likely(res->id != -1))
475                 return 0;
476
477         ret = vmw_resource_alloc_id(res);
478         if (unlikely(ret != 0)) {
479                 DRM_ERROR("Failed to allocate a context id.\n");
480                 goto out_no_id;
481         }
482
483         if (unlikely(res->id >= VMWGFX_NUM_DXCONTEXT)) {
484                 ret = -EBUSY;
485                 goto out_no_fifo;
486         }
487
488         cmd = VMW_CMD_RESERVE(dev_priv, sizeof(*cmd));
489         if (unlikely(cmd == NULL)) {
490                 ret = -ENOMEM;
491                 goto out_no_fifo;
492         }
493
494         cmd->header.id = SVGA_3D_CMD_DX_DEFINE_CONTEXT;
495         cmd->header.size = sizeof(cmd->body);
496         cmd->body.cid = res->id;
497         vmw_cmd_commit(dev_priv, sizeof(*cmd));
498         vmw_fifo_resource_inc(dev_priv);
499
500         return 0;
501
502 out_no_fifo:
503         vmw_resource_release_id(res);
504 out_no_id:
505         return ret;
506 }
507
508 static int vmw_dx_context_bind(struct vmw_resource *res,
509                                struct ttm_validate_buffer *val_buf)
510 {
511         struct vmw_private *dev_priv = res->dev_priv;
512         struct {
513                 SVGA3dCmdHeader header;
514                 SVGA3dCmdDXBindContext body;
515         } *cmd;
516         struct ttm_buffer_object *bo = val_buf->bo;
517
518         BUG_ON(bo->resource->mem_type != VMW_PL_MOB);
519
520         cmd = VMW_CMD_RESERVE(dev_priv, sizeof(*cmd));
521         if (unlikely(cmd == NULL))
522                 return -ENOMEM;
523
524         cmd->header.id = SVGA_3D_CMD_DX_BIND_CONTEXT;
525         cmd->header.size = sizeof(cmd->body);
526         cmd->body.cid = res->id;
527         cmd->body.mobid = bo->resource->start;
528         cmd->body.validContents = res->guest_memory_dirty;
529         res->guest_memory_dirty = false;
530         vmw_cmd_commit(dev_priv, sizeof(*cmd));
531
532
533         return 0;
534 }
535
536 /**
537  * vmw_dx_context_scrub_cotables - Scrub all bindings and
538  * cotables from a context
539  *
540  * @ctx: Pointer to the context resource
541  * @readback: Whether to save the otable contents on scrubbing.
542  *
543  * COtables must be unbound before their context, but unbinding requires
544  * the backup buffer being reserved, whereas scrubbing does not.
545  * This function scrubs all cotables of a context, potentially reading back
546  * the contents into their backup buffers. However, scrubbing cotables
547  * also makes the device context invalid, so scrub all bindings first so
548  * that doesn't have to be done later with an invalid context.
549  */
550 void vmw_dx_context_scrub_cotables(struct vmw_resource *ctx,
551                                    bool readback)
552 {
553         struct vmw_user_context *uctx =
554                 container_of(ctx, struct vmw_user_context, res);
555         u32 cotable_max = has_sm5_context(ctx->dev_priv) ?
556                 SVGA_COTABLE_MAX : SVGA_COTABLE_DX10_MAX;
557         int i;
558
559         vmw_binding_state_scrub(uctx->cbs);
560         for (i = 0; i < cotable_max; ++i) {
561                 struct vmw_resource *res;
562
563                 /* Avoid racing with ongoing cotable destruction. */
564                 spin_lock(&uctx->cotable_lock);
565                 res = uctx->cotables[vmw_cotable_scrub_order[i]];
566                 if (res)
567                         res = vmw_resource_reference_unless_doomed(res);
568                 spin_unlock(&uctx->cotable_lock);
569                 if (!res)
570                         continue;
571
572                 WARN_ON(vmw_cotable_scrub(res, readback));
573                 vmw_resource_unreference(&res);
574         }
575 }
576
577 static int vmw_dx_context_unbind(struct vmw_resource *res,
578                                  bool readback,
579                                  struct ttm_validate_buffer *val_buf)
580 {
581         struct vmw_private *dev_priv = res->dev_priv;
582         struct ttm_buffer_object *bo = val_buf->bo;
583         struct vmw_fence_obj *fence;
584         struct vmw_user_context *uctx =
585                 container_of(res, struct vmw_user_context, res);
586
587         struct {
588                 SVGA3dCmdHeader header;
589                 SVGA3dCmdDXReadbackContext body;
590         } *cmd1;
591         struct {
592                 SVGA3dCmdHeader header;
593                 SVGA3dCmdDXBindContext body;
594         } *cmd2;
595         uint32_t submit_size;
596         uint8_t *cmd;
597
598
599         BUG_ON(bo->resource->mem_type != VMW_PL_MOB);
600
601         mutex_lock(&dev_priv->binding_mutex);
602         vmw_dx_context_scrub_cotables(res, readback);
603
604         if (uctx->dx_query_mob && uctx->dx_query_mob->dx_query_ctx &&
605             readback) {
606                 WARN_ON(uctx->dx_query_mob->dx_query_ctx != res);
607                 if (vmw_query_readback_all(uctx->dx_query_mob))
608                         DRM_ERROR("Failed to read back query states\n");
609         }
610
611         submit_size = sizeof(*cmd2) + (readback ? sizeof(*cmd1) : 0);
612
613         cmd = VMW_CMD_RESERVE(dev_priv, submit_size);
614         if (unlikely(cmd == NULL)) {
615                 mutex_unlock(&dev_priv->binding_mutex);
616                 return -ENOMEM;
617         }
618
619         cmd2 = (void *) cmd;
620         if (readback) {
621                 cmd1 = (void *) cmd;
622                 cmd1->header.id = SVGA_3D_CMD_DX_READBACK_CONTEXT;
623                 cmd1->header.size = sizeof(cmd1->body);
624                 cmd1->body.cid = res->id;
625                 cmd2 = (void *) (&cmd1[1]);
626         }
627         cmd2->header.id = SVGA_3D_CMD_DX_BIND_CONTEXT;
628         cmd2->header.size = sizeof(cmd2->body);
629         cmd2->body.cid = res->id;
630         cmd2->body.mobid = SVGA3D_INVALID_ID;
631
632         vmw_cmd_commit(dev_priv, submit_size);
633         mutex_unlock(&dev_priv->binding_mutex);
634
635         /*
636          * Create a fence object and fence the backup buffer.
637          */
638
639         (void) vmw_execbuf_fence_commands(NULL, dev_priv,
640                                           &fence, NULL);
641
642         vmw_bo_fence_single(bo, fence);
643
644         if (likely(fence != NULL))
645                 vmw_fence_obj_unreference(&fence);
646
647         return 0;
648 }
649
650 static int vmw_dx_context_destroy(struct vmw_resource *res)
651 {
652         struct vmw_private *dev_priv = res->dev_priv;
653         struct {
654                 SVGA3dCmdHeader header;
655                 SVGA3dCmdDXDestroyContext body;
656         } *cmd;
657
658         if (likely(res->id == -1))
659                 return 0;
660
661         cmd = VMW_CMD_RESERVE(dev_priv, sizeof(*cmd));
662         if (unlikely(cmd == NULL))
663                 return -ENOMEM;
664
665         cmd->header.id = SVGA_3D_CMD_DX_DESTROY_CONTEXT;
666         cmd->header.size = sizeof(cmd->body);
667         cmd->body.cid = res->id;
668         vmw_cmd_commit(dev_priv, sizeof(*cmd));
669         if (dev_priv->query_cid == res->id)
670                 dev_priv->query_cid_valid = false;
671         vmw_resource_release_id(res);
672         vmw_fifo_resource_dec(dev_priv);
673
674         return 0;
675 }
676
677 /*
678  * User-space context management:
679  */
680
681 static struct vmw_resource *
682 vmw_user_context_base_to_res(struct ttm_base_object *base)
683 {
684         return &(container_of(base, struct vmw_user_context, base)->res);
685 }
686
687 static void vmw_user_context_free(struct vmw_resource *res)
688 {
689         struct vmw_user_context *ctx =
690             container_of(res, struct vmw_user_context, res);
691
692         if (ctx->cbs)
693                 vmw_binding_state_free(ctx->cbs);
694
695         (void) vmw_context_bind_dx_query(res, NULL);
696
697         ttm_base_object_kfree(ctx, base);
698 }
699
700 /*
701  * This function is called when user space has no more references on the
702  * base object. It releases the base-object's reference on the resource object.
703  */
704
705 static void vmw_user_context_base_release(struct ttm_base_object **p_base)
706 {
707         struct ttm_base_object *base = *p_base;
708         struct vmw_user_context *ctx =
709             container_of(base, struct vmw_user_context, base);
710         struct vmw_resource *res = &ctx->res;
711
712         *p_base = NULL;
713         vmw_resource_unreference(&res);
714 }
715
716 int vmw_context_destroy_ioctl(struct drm_device *dev, void *data,
717                               struct drm_file *file_priv)
718 {
719         struct drm_vmw_context_arg *arg = (struct drm_vmw_context_arg *)data;
720         struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile;
721
722         return ttm_ref_object_base_unref(tfile, arg->cid);
723 }
724
725 static int vmw_context_define(struct drm_device *dev, void *data,
726                               struct drm_file *file_priv, bool dx)
727 {
728         struct vmw_private *dev_priv = vmw_priv(dev);
729         struct vmw_user_context *ctx;
730         struct vmw_resource *res;
731         struct vmw_resource *tmp;
732         struct drm_vmw_context_arg *arg = (struct drm_vmw_context_arg *)data;
733         struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile;
734         int ret;
735
736         if (!has_sm4_context(dev_priv) && dx) {
737                 VMW_DEBUG_USER("DX contexts not supported by device.\n");
738                 return -EINVAL;
739         }
740
741         ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
742         if (unlikely(!ctx)) {
743                 ret = -ENOMEM;
744                 goto out_ret;
745         }
746
747         res = &ctx->res;
748         ctx->base.shareable = false;
749         ctx->base.tfile = NULL;
750
751         /*
752          * From here on, the destructor takes over resource freeing.
753          */
754
755         ret = vmw_context_init(dev_priv, res, vmw_user_context_free, dx);
756         if (unlikely(ret != 0))
757                 goto out_ret;
758
759         tmp = vmw_resource_reference(&ctx->res);
760         ret = ttm_base_object_init(tfile, &ctx->base, false, VMW_RES_CONTEXT,
761                                    &vmw_user_context_base_release);
762
763         if (unlikely(ret != 0)) {
764                 vmw_resource_unreference(&tmp);
765                 goto out_err;
766         }
767
768         arg->cid = ctx->base.handle;
769 out_err:
770         vmw_resource_unreference(&res);
771 out_ret:
772         return ret;
773 }
774
775 int vmw_context_define_ioctl(struct drm_device *dev, void *data,
776                              struct drm_file *file_priv)
777 {
778         return vmw_context_define(dev, data, file_priv, false);
779 }
780
781 int vmw_extended_context_define_ioctl(struct drm_device *dev, void *data,
782                                       struct drm_file *file_priv)
783 {
784         union drm_vmw_extended_context_arg *arg = (typeof(arg)) data;
785         struct drm_vmw_context_arg *rep = &arg->rep;
786
787         switch (arg->req) {
788         case drm_vmw_context_legacy:
789                 return vmw_context_define(dev, rep, file_priv, false);
790         case drm_vmw_context_dx:
791                 return vmw_context_define(dev, rep, file_priv, true);
792         default:
793                 break;
794         }
795         return -EINVAL;
796 }
797
798 /**
799  * vmw_context_binding_list - Return a list of context bindings
800  *
801  * @ctx: The context resource
802  *
803  * Returns the current list of bindings of the given context. Note that
804  * this list becomes stale as soon as the dev_priv::binding_mutex is unlocked.
805  */
806 struct list_head *vmw_context_binding_list(struct vmw_resource *ctx)
807 {
808         struct vmw_user_context *uctx =
809                 container_of(ctx, struct vmw_user_context, res);
810
811         return vmw_binding_state_list(uctx->cbs);
812 }
813
814 struct vmw_cmdbuf_res_manager *vmw_context_res_man(struct vmw_resource *ctx)
815 {
816         return container_of(ctx, struct vmw_user_context, res)->man;
817 }
818
819 struct vmw_resource *vmw_context_cotable(struct vmw_resource *ctx,
820                                          SVGACOTableType cotable_type)
821 {
822         u32 cotable_max = has_sm5_context(ctx->dev_priv) ?
823                 SVGA_COTABLE_MAX : SVGA_COTABLE_DX10_MAX;
824
825         if (cotable_type >= cotable_max)
826                 return ERR_PTR(-EINVAL);
827
828         return container_of(ctx, struct vmw_user_context, res)->
829                 cotables[cotable_type];
830 }
831
832 /**
833  * vmw_context_binding_state -
834  * Return a pointer to a context binding state structure
835  *
836  * @ctx: The context resource
837  *
838  * Returns the current state of bindings of the given context. Note that
839  * this state becomes stale as soon as the dev_priv::binding_mutex is unlocked.
840  */
841 struct vmw_ctx_binding_state *
842 vmw_context_binding_state(struct vmw_resource *ctx)
843 {
844         return container_of(ctx, struct vmw_user_context, res)->cbs;
845 }
846
847 /**
848  * vmw_context_bind_dx_query -
849  * Sets query MOB for the context.  If @mob is NULL, then this function will
850  * remove the association between the MOB and the context.  This function
851  * assumes the binding_mutex is held.
852  *
853  * @ctx_res: The context resource
854  * @mob: a reference to the query MOB
855  *
856  * Returns -EINVAL if a MOB has already been set and does not match the one
857  * specified in the parameter.  0 otherwise.
858  */
859 int vmw_context_bind_dx_query(struct vmw_resource *ctx_res,
860                               struct vmw_bo *mob)
861 {
862         struct vmw_user_context *uctx =
863                 container_of(ctx_res, struct vmw_user_context, res);
864
865         if (mob == NULL) {
866                 if (uctx->dx_query_mob) {
867                         uctx->dx_query_mob->dx_query_ctx = NULL;
868                         vmw_bo_unreference(&uctx->dx_query_mob);
869                         uctx->dx_query_mob = NULL;
870                 }
871
872                 return 0;
873         }
874
875         /* Can only have one MOB per context for queries */
876         if (uctx->dx_query_mob && uctx->dx_query_mob != mob)
877                 return -EINVAL;
878
879         mob->dx_query_ctx  = ctx_res;
880
881         if (!uctx->dx_query_mob)
882                 uctx->dx_query_mob = vmw_bo_reference(mob);
883
884         return 0;
885 }
886
887 /**
888  * vmw_context_get_dx_query_mob - Returns non-counted reference to DX query mob
889  *
890  * @ctx_res: The context resource
891  */
892 struct vmw_bo *
893 vmw_context_get_dx_query_mob(struct vmw_resource *ctx_res)
894 {
895         struct vmw_user_context *uctx =
896                 container_of(ctx_res, struct vmw_user_context, res);
897
898         return uctx->dx_query_mob;
899 }