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