aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c
diff options
context:
space:
mode:
authorJakob Bornecrantz <jakob@vmware.com>2009-12-09 19:19:58 -0500
committerDave Airlie <airlied@redhat.com>2009-12-14 17:38:43 -0500
commitfb1d9738ca053ea8afa5e86af6463155f983b01c (patch)
tree53aa407922c989f48aead5fcf61f9945ca6051d5 /drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c
parent632f61178d0473861ba77e774bb654b37bc7eccc (diff)
drm/vmwgfx: Add DRM driver for VMware Virtual GPU
This commit adds the vmwgfx driver for the VWware Virtual GPU aka SVGA. The driver is under staging the same as Nouveau and Radeon KMS. Hopefully the 2D ioctls are bug free and don't need changing, so that part of the API should be stable. But there there is a pretty big chance that the 3D API will change in the future. Signed-off-by: Thomas Hellström <thellstrom@vmware.com> Signed-off-by: Jakob Bornecrantz <jakob@vmware.com> Signed-off-by: Dave Airlie <airlied@redhat.com>
Diffstat (limited to 'drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c')
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c516
1 files changed, 516 insertions, 0 deletions
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c b/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c
new file mode 100644
index 000000000000..7a39f3e6dc2c
--- /dev/null
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c
@@ -0,0 +1,516 @@
1/**************************************************************************
2 *
3 * Copyright © 2009 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_reg.h"
30#include "ttm/ttm_bo_api.h"
31#include "ttm/ttm_placement.h"
32
33static int vmw_cmd_invalid(struct vmw_private *dev_priv,
34 struct vmw_sw_context *sw_context,
35 SVGA3dCmdHeader *header)
36{
37 return capable(CAP_SYS_ADMIN) ? : -EINVAL;
38}
39
40static int vmw_cmd_ok(struct vmw_private *dev_priv,
41 struct vmw_sw_context *sw_context,
42 SVGA3dCmdHeader *header)
43{
44 return 0;
45}
46
47static int vmw_cmd_cid_check(struct vmw_private *dev_priv,
48 struct vmw_sw_context *sw_context,
49 SVGA3dCmdHeader *header)
50{
51 struct vmw_cid_cmd {
52 SVGA3dCmdHeader header;
53 __le32 cid;
54 } *cmd;
55 int ret;
56
57 cmd = container_of(header, struct vmw_cid_cmd, header);
58 if (likely(sw_context->cid_valid && cmd->cid == sw_context->last_cid))
59 return 0;
60
61 ret = vmw_context_check(dev_priv, sw_context->tfile, cmd->cid);
62 if (unlikely(ret != 0)) {
63 DRM_ERROR("Could not find or use context %u\n",
64 (unsigned) cmd->cid);
65 return ret;
66 }
67
68 sw_context->last_cid = cmd->cid;
69 sw_context->cid_valid = true;
70
71 return 0;
72}
73
74static int vmw_cmd_sid_check(struct vmw_private *dev_priv,
75 struct vmw_sw_context *sw_context,
76 uint32_t sid)
77{
78 if (unlikely((!sw_context->sid_valid || sid != sw_context->last_sid) &&
79 sid != SVGA3D_INVALID_ID)) {
80 int ret = vmw_surface_check(dev_priv, sw_context->tfile, sid);
81
82 if (unlikely(ret != 0)) {
83 DRM_ERROR("Could ot find or use surface %u\n",
84 (unsigned) sid);
85 return ret;
86 }
87
88 sw_context->last_sid = sid;
89 sw_context->sid_valid = true;
90 }
91 return 0;
92}
93
94
95static int vmw_cmd_set_render_target_check(struct vmw_private *dev_priv,
96 struct vmw_sw_context *sw_context,
97 SVGA3dCmdHeader *header)
98{
99 struct vmw_sid_cmd {
100 SVGA3dCmdHeader header;
101 SVGA3dCmdSetRenderTarget body;
102 } *cmd;
103 int ret;
104
105 ret = vmw_cmd_cid_check(dev_priv, sw_context, header);
106 if (unlikely(ret != 0))
107 return ret;
108
109 cmd = container_of(header, struct vmw_sid_cmd, header);
110 return vmw_cmd_sid_check(dev_priv, sw_context, cmd->body.target.sid);
111}
112
113static int vmw_cmd_surface_copy_check(struct vmw_private *dev_priv,
114 struct vmw_sw_context *sw_context,
115 SVGA3dCmdHeader *header)
116{
117 struct vmw_sid_cmd {
118 SVGA3dCmdHeader header;
119 SVGA3dCmdSurfaceCopy body;
120 } *cmd;
121 int ret;
122
123 cmd = container_of(header, struct vmw_sid_cmd, header);
124 ret = vmw_cmd_sid_check(dev_priv, sw_context, cmd->body.src.sid);
125 if (unlikely(ret != 0))
126 return ret;
127 return vmw_cmd_sid_check(dev_priv, sw_context, cmd->body.dest.sid);
128}
129
130static int vmw_cmd_stretch_blt_check(struct vmw_private *dev_priv,
131 struct vmw_sw_context *sw_context,
132 SVGA3dCmdHeader *header)
133{
134 struct vmw_sid_cmd {
135 SVGA3dCmdHeader header;
136 SVGA3dCmdSurfaceStretchBlt body;
137 } *cmd;
138 int ret;
139
140 cmd = container_of(header, struct vmw_sid_cmd, header);
141 ret = vmw_cmd_sid_check(dev_priv, sw_context, cmd->body.src.sid);
142 if (unlikely(ret != 0))
143 return ret;
144 return vmw_cmd_sid_check(dev_priv, sw_context, cmd->body.dest.sid);
145}
146
147static int vmw_cmd_blt_surf_screen_check(struct vmw_private *dev_priv,
148 struct vmw_sw_context *sw_context,
149 SVGA3dCmdHeader *header)
150{
151 struct vmw_sid_cmd {
152 SVGA3dCmdHeader header;
153 SVGA3dCmdBlitSurfaceToScreen body;
154 } *cmd;
155
156 cmd = container_of(header, struct vmw_sid_cmd, header);
157 return vmw_cmd_sid_check(dev_priv, sw_context, cmd->body.srcImage.sid);
158}
159
160static int vmw_cmd_present_check(struct vmw_private *dev_priv,
161 struct vmw_sw_context *sw_context,
162 SVGA3dCmdHeader *header)
163{
164 struct vmw_sid_cmd {
165 SVGA3dCmdHeader header;
166 SVGA3dCmdPresent body;
167 } *cmd;
168
169 cmd = container_of(header, struct vmw_sid_cmd, header);
170 return vmw_cmd_sid_check(dev_priv, sw_context, cmd->body.sid);
171}
172
173static int vmw_cmd_dma(struct vmw_private *dev_priv,
174 struct vmw_sw_context *sw_context,
175 SVGA3dCmdHeader *header)
176{
177 uint32_t handle;
178 struct vmw_dma_buffer *vmw_bo = NULL;
179 struct ttm_buffer_object *bo;
180 struct vmw_surface *srf = NULL;
181 struct vmw_dma_cmd {
182 SVGA3dCmdHeader header;
183 SVGA3dCmdSurfaceDMA dma;
184 } *cmd;
185 struct vmw_relocation *reloc;
186 int ret;
187 uint32_t cur_validate_node;
188 struct ttm_validate_buffer *val_buf;
189
190
191 cmd = container_of(header, struct vmw_dma_cmd, header);
192 ret = vmw_cmd_sid_check(dev_priv, sw_context, cmd->dma.host.sid);
193 if (unlikely(ret != 0))
194 return ret;
195
196 handle = cmd->dma.guest.ptr.gmrId;
197 ret = vmw_user_dmabuf_lookup(sw_context->tfile, handle, &vmw_bo);
198 if (unlikely(ret != 0)) {
199 DRM_ERROR("Could not find or use GMR region.\n");
200 return -EINVAL;
201 }
202 bo = &vmw_bo->base;
203
204 if (unlikely(sw_context->cur_reloc >= VMWGFX_MAX_RELOCATIONS)) {
205 DRM_ERROR("Max number of DMA commands per submission"
206 " exceeded\n");
207 ret = -EINVAL;
208 goto out_no_reloc;
209 }
210
211 reloc = &sw_context->relocs[sw_context->cur_reloc++];
212 reloc->location = &cmd->dma.guest.ptr;
213
214 cur_validate_node = vmw_dmabuf_validate_node(bo, sw_context->cur_val_buf);
215 if (unlikely(cur_validate_node >= VMWGFX_MAX_GMRS)) {
216 DRM_ERROR("Max number of DMA buffers per submission"
217 " exceeded.\n");
218 ret = -EINVAL;
219 goto out_no_reloc;
220 }
221
222 reloc->index = cur_validate_node;
223 if (unlikely(cur_validate_node == sw_context->cur_val_buf)) {
224 val_buf = &sw_context->val_bufs[cur_validate_node];
225 val_buf->bo = ttm_bo_reference(bo);
226 val_buf->new_sync_obj_arg = (void *) dev_priv;
227 list_add_tail(&val_buf->head, &sw_context->validate_nodes);
228 ++sw_context->cur_val_buf;
229 }
230
231 ret = vmw_user_surface_lookup(dev_priv, sw_context->tfile,
232 cmd->dma.host.sid, &srf);
233 if (ret) {
234 DRM_ERROR("could not find surface\n");
235 goto out_no_reloc;
236 }
237
238 vmw_kms_cursor_snoop(srf, sw_context->tfile, bo, header);
239 vmw_surface_unreference(&srf);
240
241out_no_reloc:
242 vmw_dmabuf_unreference(&vmw_bo);
243 return ret;
244}
245
246
247typedef int (*vmw_cmd_func) (struct vmw_private *,
248 struct vmw_sw_context *,
249 SVGA3dCmdHeader *);
250
251#define VMW_CMD_DEF(cmd, func) \
252 [cmd - SVGA_3D_CMD_BASE] = func
253
254static vmw_cmd_func vmw_cmd_funcs[SVGA_3D_CMD_MAX] = {
255 VMW_CMD_DEF(SVGA_3D_CMD_SURFACE_DEFINE, &vmw_cmd_invalid),
256 VMW_CMD_DEF(SVGA_3D_CMD_SURFACE_DESTROY, &vmw_cmd_invalid),
257 VMW_CMD_DEF(SVGA_3D_CMD_SURFACE_COPY, &vmw_cmd_surface_copy_check),
258 VMW_CMD_DEF(SVGA_3D_CMD_SURFACE_STRETCHBLT, &vmw_cmd_stretch_blt_check),
259 VMW_CMD_DEF(SVGA_3D_CMD_SURFACE_DMA, &vmw_cmd_dma),
260 VMW_CMD_DEF(SVGA_3D_CMD_CONTEXT_DEFINE, &vmw_cmd_invalid),
261 VMW_CMD_DEF(SVGA_3D_CMD_CONTEXT_DESTROY, &vmw_cmd_invalid),
262 VMW_CMD_DEF(SVGA_3D_CMD_SETTRANSFORM, &vmw_cmd_cid_check),
263 VMW_CMD_DEF(SVGA_3D_CMD_SETZRANGE, &vmw_cmd_cid_check),
264 VMW_CMD_DEF(SVGA_3D_CMD_SETRENDERSTATE, &vmw_cmd_cid_check),
265 VMW_CMD_DEF(SVGA_3D_CMD_SETRENDERTARGET,
266 &vmw_cmd_set_render_target_check),
267 VMW_CMD_DEF(SVGA_3D_CMD_SETTEXTURESTATE, &vmw_cmd_cid_check),
268 VMW_CMD_DEF(SVGA_3D_CMD_SETMATERIAL, &vmw_cmd_cid_check),
269 VMW_CMD_DEF(SVGA_3D_CMD_SETLIGHTDATA, &vmw_cmd_cid_check),
270 VMW_CMD_DEF(SVGA_3D_CMD_SETLIGHTENABLED, &vmw_cmd_cid_check),
271 VMW_CMD_DEF(SVGA_3D_CMD_SETVIEWPORT, &vmw_cmd_cid_check),
272 VMW_CMD_DEF(SVGA_3D_CMD_SETCLIPPLANE, &vmw_cmd_cid_check),
273 VMW_CMD_DEF(SVGA_3D_CMD_CLEAR, &vmw_cmd_cid_check),
274 VMW_CMD_DEF(SVGA_3D_CMD_PRESENT, &vmw_cmd_present_check),
275 VMW_CMD_DEF(SVGA_3D_CMD_SHADER_DEFINE, &vmw_cmd_cid_check),
276 VMW_CMD_DEF(SVGA_3D_CMD_SHADER_DESTROY, &vmw_cmd_cid_check),
277 VMW_CMD_DEF(SVGA_3D_CMD_SET_SHADER, &vmw_cmd_cid_check),
278 VMW_CMD_DEF(SVGA_3D_CMD_SET_SHADER_CONST, &vmw_cmd_cid_check),
279 VMW_CMD_DEF(SVGA_3D_CMD_DRAW_PRIMITIVES, &vmw_cmd_cid_check),
280 VMW_CMD_DEF(SVGA_3D_CMD_SETSCISSORRECT, &vmw_cmd_cid_check),
281 VMW_CMD_DEF(SVGA_3D_CMD_BEGIN_QUERY, &vmw_cmd_cid_check),
282 VMW_CMD_DEF(SVGA_3D_CMD_END_QUERY, &vmw_cmd_cid_check),
283 VMW_CMD_DEF(SVGA_3D_CMD_WAIT_FOR_QUERY, &vmw_cmd_cid_check),
284 VMW_CMD_DEF(SVGA_3D_CMD_PRESENT_READBACK, &vmw_cmd_ok),
285 VMW_CMD_DEF(SVGA_3D_CMD_BLIT_SURFACE_TO_SCREEN,
286 &vmw_cmd_blt_surf_screen_check)
287};
288
289static int vmw_cmd_check(struct vmw_private *dev_priv,
290 struct vmw_sw_context *sw_context,
291 void *buf, uint32_t *size)
292{
293 uint32_t cmd_id;
294 SVGA3dCmdHeader *header = (SVGA3dCmdHeader *) buf;
295 int ret;
296
297 cmd_id = ((uint32_t *)buf)[0];
298 if (cmd_id == SVGA_CMD_UPDATE) {
299 *size = 5 << 2;
300 return 0;
301 }
302
303 cmd_id = le32_to_cpu(header->id);
304 *size = le32_to_cpu(header->size) + sizeof(SVGA3dCmdHeader);
305
306 cmd_id -= SVGA_3D_CMD_BASE;
307 if (unlikely(cmd_id >= SVGA_3D_CMD_MAX - SVGA_3D_CMD_BASE))
308 goto out_err;
309
310 ret = vmw_cmd_funcs[cmd_id](dev_priv, sw_context, header);
311 if (unlikely(ret != 0))
312 goto out_err;
313
314 return 0;
315out_err:
316 DRM_ERROR("Illegal / Invalid SVGA3D command: %d\n",
317 cmd_id + SVGA_3D_CMD_BASE);
318 return -EINVAL;
319}
320
321static int vmw_cmd_check_all(struct vmw_private *dev_priv,
322 struct vmw_sw_context *sw_context,
323 void *buf, uint32_t size)
324{
325 int32_t cur_size = size;
326 int ret;
327
328 while (cur_size > 0) {
329 ret = vmw_cmd_check(dev_priv, sw_context, buf, &size);
330 if (unlikely(ret != 0))
331 return ret;
332 buf = (void *)((unsigned long) buf + size);
333 cur_size -= size;
334 }
335
336 if (unlikely(cur_size != 0)) {
337 DRM_ERROR("Command verifier out of sync.\n");
338 return -EINVAL;
339 }
340
341 return 0;
342}
343
344static void vmw_free_relocations(struct vmw_sw_context *sw_context)
345{
346 sw_context->cur_reloc = 0;
347}
348
349static void vmw_apply_relocations(struct vmw_sw_context *sw_context)
350{
351 uint32_t i;
352 struct vmw_relocation *reloc;
353 struct ttm_validate_buffer *validate;
354 struct ttm_buffer_object *bo;
355
356 for (i = 0; i < sw_context->cur_reloc; ++i) {
357 reloc = &sw_context->relocs[i];
358 validate = &sw_context->val_bufs[reloc->index];
359 bo = validate->bo;
360 reloc->location->offset += bo->offset;
361 reloc->location->gmrId = vmw_dmabuf_gmr(bo);
362 }
363 vmw_free_relocations(sw_context);
364}
365
366static void vmw_clear_validations(struct vmw_sw_context *sw_context)
367{
368 struct ttm_validate_buffer *entry, *next;
369
370 list_for_each_entry_safe(entry, next, &sw_context->validate_nodes,
371 head) {
372 list_del(&entry->head);
373 vmw_dmabuf_validate_clear(entry->bo);
374 ttm_bo_unref(&entry->bo);
375 sw_context->cur_val_buf--;
376 }
377 BUG_ON(sw_context->cur_val_buf != 0);
378}
379
380static int vmw_validate_single_buffer(struct vmw_private *dev_priv,
381 struct ttm_buffer_object *bo)
382{
383 int ret;
384
385 if (vmw_dmabuf_gmr(bo) != SVGA_GMR_NULL)
386 return 0;
387
388 ret = vmw_gmr_bind(dev_priv, bo);
389 if (likely(ret == 0 || ret == -ERESTART))
390 return ret;
391
392
393 ret = ttm_bo_validate(bo, &vmw_vram_placement, true, false);
394 return ret;
395}
396
397
398static int vmw_validate_buffers(struct vmw_private *dev_priv,
399 struct vmw_sw_context *sw_context)
400{
401 struct ttm_validate_buffer *entry;
402 int ret;
403
404 list_for_each_entry(entry, &sw_context->validate_nodes, head) {
405 ret = vmw_validate_single_buffer(dev_priv, entry->bo);
406 if (unlikely(ret != 0))
407 return ret;
408 }
409 return 0;
410}
411
412int vmw_execbuf_ioctl(struct drm_device *dev, void *data,
413 struct drm_file *file_priv)
414{
415 struct vmw_private *dev_priv = vmw_priv(dev);
416 struct drm_vmw_execbuf_arg *arg = (struct drm_vmw_execbuf_arg *)data;
417 struct drm_vmw_fence_rep fence_rep;
418 struct drm_vmw_fence_rep __user *user_fence_rep;
419 int ret;
420 void *user_cmd;
421 void *cmd;
422 uint32_t sequence;
423 struct vmw_sw_context *sw_context = &dev_priv->ctx;
424 struct vmw_master *vmaster = vmw_master(file_priv->master);
425
426 ret = ttm_read_lock(&vmaster->lock, true);
427 if (unlikely(ret != 0))
428 return ret;
429
430 ret = mutex_lock_interruptible(&dev_priv->cmdbuf_mutex);
431 if (unlikely(ret != 0)) {
432 ret = -ERESTART;
433 goto out_no_cmd_mutex;
434 }
435
436 cmd = vmw_fifo_reserve(dev_priv, arg->command_size);
437 if (unlikely(cmd == NULL)) {
438 DRM_ERROR("Failed reserving fifo space for commands.\n");
439 ret = -ENOMEM;
440 goto out_unlock;
441 }
442
443 user_cmd = (void __user *)(unsigned long)arg->commands;
444 ret = copy_from_user(cmd, user_cmd, arg->command_size);
445
446 if (unlikely(ret != 0)) {
447 DRM_ERROR("Failed copying commands.\n");
448 goto out_commit;
449 }
450
451 sw_context->tfile = vmw_fpriv(file_priv)->tfile;
452 sw_context->cid_valid = false;
453 sw_context->sid_valid = false;
454 sw_context->cur_reloc = 0;
455 sw_context->cur_val_buf = 0;
456
457 INIT_LIST_HEAD(&sw_context->validate_nodes);
458
459 ret = vmw_cmd_check_all(dev_priv, sw_context, cmd, arg->command_size);
460 if (unlikely(ret != 0))
461 goto out_err;
462 ret = ttm_eu_reserve_buffers(&sw_context->validate_nodes,
463 dev_priv->val_seq++);
464 if (unlikely(ret != 0))
465 goto out_err;
466
467 ret = vmw_validate_buffers(dev_priv, sw_context);
468 if (unlikely(ret != 0))
469 goto out_err;
470
471 vmw_apply_relocations(sw_context);
472 vmw_fifo_commit(dev_priv, arg->command_size);
473
474 ret = vmw_fifo_send_fence(dev_priv, &sequence);
475
476 ttm_eu_fence_buffer_objects(&sw_context->validate_nodes,
477 (void *)(unsigned long) sequence);
478 vmw_clear_validations(sw_context);
479 mutex_unlock(&dev_priv->cmdbuf_mutex);
480
481 /*
482 * This error is harmless, because if fence submission fails,
483 * vmw_fifo_send_fence will sync.
484 */
485
486 if (ret != 0)
487 DRM_ERROR("Fence submission error. Syncing.\n");
488
489 fence_rep.error = ret;
490 fence_rep.fence_seq = (uint64_t) sequence;
491
492 user_fence_rep = (struct drm_vmw_fence_rep __user *)
493 (unsigned long)arg->fence_rep;
494
495 /*
496 * copy_to_user errors will be detected by user space not
497 * seeing fence_rep::error filled in.
498 */
499
500 ret = copy_to_user(user_fence_rep, &fence_rep, sizeof(fence_rep));
501
502 vmw_kms_cursor_post_execbuf(dev_priv);
503 ttm_read_unlock(&vmaster->lock);
504 return 0;
505out_err:
506 vmw_free_relocations(sw_context);
507 ttm_eu_backoff_reservation(&sw_context->validate_nodes);
508 vmw_clear_validations(sw_context);
509out_commit:
510 vmw_fifo_commit(dev_priv, 0);
511out_unlock:
512 mutex_unlock(&dev_priv->cmdbuf_mutex);
513out_no_cmd_mutex:
514 ttm_read_unlock(&vmaster->lock);
515 return ret;
516}