1 /**************************************************************************
3 * Copyright © 2009 VMware, Inc., Palo Alto, CA., USA
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:
14 * The above copyright notice and this permission notice (including the
15 * next paragraph) shall be included in all copies or substantial portions
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.
26 **************************************************************************/
28 #include "vmwgfx_drv.h"
29 #include "vmwgfx_reg.h"
30 #include "ttm/ttm_bo_api.h"
31 #include "ttm/ttm_placement.h"
33 static int vmw_cmd_invalid(struct vmw_private
*dev_priv
,
34 struct vmw_sw_context
*sw_context
,
35 SVGA3dCmdHeader
*header
)
37 return capable(CAP_SYS_ADMIN
) ? : -EINVAL
;
40 static int vmw_cmd_ok(struct vmw_private
*dev_priv
,
41 struct vmw_sw_context
*sw_context
,
42 SVGA3dCmdHeader
*header
)
47 static int vmw_cmd_cid_check(struct vmw_private
*dev_priv
,
48 struct vmw_sw_context
*sw_context
,
49 SVGA3dCmdHeader
*header
)
52 SVGA3dCmdHeader header
;
57 cmd
= container_of(header
, struct vmw_cid_cmd
, header
);
58 if (likely(sw_context
->cid_valid
&& cmd
->cid
== sw_context
->last_cid
))
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",
68 sw_context
->last_cid
= cmd
->cid
;
69 sw_context
->cid_valid
= true;
74 static int vmw_cmd_sid_check(struct vmw_private
*dev_priv
,
75 struct vmw_sw_context
*sw_context
,
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
);
82 if (unlikely(ret
!= 0)) {
83 DRM_ERROR("Could ot find or use surface %u\n",
88 sw_context
->last_sid
= sid
;
89 sw_context
->sid_valid
= true;
95 static int vmw_cmd_set_render_target_check(struct vmw_private
*dev_priv
,
96 struct vmw_sw_context
*sw_context
,
97 SVGA3dCmdHeader
*header
)
100 SVGA3dCmdHeader header
;
101 SVGA3dCmdSetRenderTarget body
;
105 ret
= vmw_cmd_cid_check(dev_priv
, sw_context
, header
);
106 if (unlikely(ret
!= 0))
109 cmd
= container_of(header
, struct vmw_sid_cmd
, header
);
110 return vmw_cmd_sid_check(dev_priv
, sw_context
, cmd
->body
.target
.sid
);
113 static int vmw_cmd_surface_copy_check(struct vmw_private
*dev_priv
,
114 struct vmw_sw_context
*sw_context
,
115 SVGA3dCmdHeader
*header
)
118 SVGA3dCmdHeader header
;
119 SVGA3dCmdSurfaceCopy body
;
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))
127 return vmw_cmd_sid_check(dev_priv
, sw_context
, cmd
->body
.dest
.sid
);
130 static int vmw_cmd_stretch_blt_check(struct vmw_private
*dev_priv
,
131 struct vmw_sw_context
*sw_context
,
132 SVGA3dCmdHeader
*header
)
135 SVGA3dCmdHeader header
;
136 SVGA3dCmdSurfaceStretchBlt body
;
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))
144 return vmw_cmd_sid_check(dev_priv
, sw_context
, cmd
->body
.dest
.sid
);
147 static int vmw_cmd_blt_surf_screen_check(struct vmw_private
*dev_priv
,
148 struct vmw_sw_context
*sw_context
,
149 SVGA3dCmdHeader
*header
)
152 SVGA3dCmdHeader header
;
153 SVGA3dCmdBlitSurfaceToScreen body
;
156 cmd
= container_of(header
, struct vmw_sid_cmd
, header
);
157 return vmw_cmd_sid_check(dev_priv
, sw_context
, cmd
->body
.srcImage
.sid
);
160 static int vmw_cmd_present_check(struct vmw_private
*dev_priv
,
161 struct vmw_sw_context
*sw_context
,
162 SVGA3dCmdHeader
*header
)
165 SVGA3dCmdHeader header
;
166 SVGA3dCmdPresent body
;
169 cmd
= container_of(header
, struct vmw_sid_cmd
, header
);
170 return vmw_cmd_sid_check(dev_priv
, sw_context
, cmd
->body
.sid
);
173 static int vmw_cmd_dma(struct vmw_private
*dev_priv
,
174 struct vmw_sw_context
*sw_context
,
175 SVGA3dCmdHeader
*header
)
178 struct vmw_dma_buffer
*vmw_bo
= NULL
;
179 struct ttm_buffer_object
*bo
;
180 struct vmw_surface
*srf
= NULL
;
182 SVGA3dCmdHeader header
;
183 SVGA3dCmdSurfaceDMA dma
;
185 struct vmw_relocation
*reloc
;
187 uint32_t cur_validate_node
;
188 struct ttm_validate_buffer
*val_buf
;
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))
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");
204 if (unlikely(sw_context
->cur_reloc
>= VMWGFX_MAX_RELOCATIONS
)) {
205 DRM_ERROR("Max number of DMA commands per submission"
211 reloc
= &sw_context
->relocs
[sw_context
->cur_reloc
++];
212 reloc
->location
= &cmd
->dma
.guest
.ptr
;
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"
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
;
231 ret
= vmw_user_surface_lookup(dev_priv
, sw_context
->tfile
,
232 cmd
->dma
.host
.sid
, &srf
);
234 DRM_ERROR("could not find surface\n");
238 vmw_kms_cursor_snoop(srf
, sw_context
->tfile
, bo
, header
);
239 vmw_surface_unreference(&srf
);
242 vmw_dmabuf_unreference(&vmw_bo
);
247 typedef int (*vmw_cmd_func
) (struct vmw_private
*,
248 struct vmw_sw_context
*,
251 #define VMW_CMD_DEF(cmd, func) \
252 [cmd - SVGA_3D_CMD_BASE] = func
254 static 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
)
289 static int vmw_cmd_check(struct vmw_private
*dev_priv
,
290 struct vmw_sw_context
*sw_context
,
291 void *buf
, uint32_t *size
)
294 SVGA3dCmdHeader
*header
= (SVGA3dCmdHeader
*) buf
;
297 cmd_id
= ((uint32_t *)buf
)[0];
298 if (cmd_id
== SVGA_CMD_UPDATE
) {
303 cmd_id
= le32_to_cpu(header
->id
);
304 *size
= le32_to_cpu(header
->size
) + sizeof(SVGA3dCmdHeader
);
306 cmd_id
-= SVGA_3D_CMD_BASE
;
307 if (unlikely(cmd_id
>= SVGA_3D_CMD_MAX
- SVGA_3D_CMD_BASE
))
310 ret
= vmw_cmd_funcs
[cmd_id
](dev_priv
, sw_context
, header
);
311 if (unlikely(ret
!= 0))
316 DRM_ERROR("Illegal / Invalid SVGA3D command: %d\n",
317 cmd_id
+ SVGA_3D_CMD_BASE
);
321 static int vmw_cmd_check_all(struct vmw_private
*dev_priv
,
322 struct vmw_sw_context
*sw_context
,
323 void *buf
, uint32_t size
)
325 int32_t cur_size
= size
;
328 while (cur_size
> 0) {
329 ret
= vmw_cmd_check(dev_priv
, sw_context
, buf
, &size
);
330 if (unlikely(ret
!= 0))
332 buf
= (void *)((unsigned long) buf
+ size
);
336 if (unlikely(cur_size
!= 0)) {
337 DRM_ERROR("Command verifier out of sync.\n");
344 static void vmw_free_relocations(struct vmw_sw_context
*sw_context
)
346 sw_context
->cur_reloc
= 0;
349 static void vmw_apply_relocations(struct vmw_sw_context
*sw_context
)
352 struct vmw_relocation
*reloc
;
353 struct ttm_validate_buffer
*validate
;
354 struct ttm_buffer_object
*bo
;
356 for (i
= 0; i
< sw_context
->cur_reloc
; ++i
) {
357 reloc
= &sw_context
->relocs
[i
];
358 validate
= &sw_context
->val_bufs
[reloc
->index
];
360 reloc
->location
->offset
+= bo
->offset
;
361 reloc
->location
->gmrId
= vmw_dmabuf_gmr(bo
);
363 vmw_free_relocations(sw_context
);
366 static void vmw_clear_validations(struct vmw_sw_context
*sw_context
)
368 struct ttm_validate_buffer
*entry
, *next
;
370 list_for_each_entry_safe(entry
, next
, &sw_context
->validate_nodes
,
372 list_del(&entry
->head
);
373 vmw_dmabuf_validate_clear(entry
->bo
);
374 ttm_bo_unref(&entry
->bo
);
375 sw_context
->cur_val_buf
--;
377 BUG_ON(sw_context
->cur_val_buf
!= 0);
380 static int vmw_validate_single_buffer(struct vmw_private
*dev_priv
,
381 struct ttm_buffer_object
*bo
)
385 if (vmw_dmabuf_gmr(bo
) != SVGA_GMR_NULL
)
388 ret
= vmw_gmr_bind(dev_priv
, bo
);
389 if (likely(ret
== 0 || ret
== -ERESTARTSYS
))
393 ret
= ttm_bo_validate(bo
, &vmw_vram_placement
, true, false);
398 static int vmw_validate_buffers(struct vmw_private
*dev_priv
,
399 struct vmw_sw_context
*sw_context
)
401 struct ttm_validate_buffer
*entry
;
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))
412 int vmw_execbuf_ioctl(struct drm_device
*dev
, void *data
,
413 struct drm_file
*file_priv
)
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
;
423 struct vmw_sw_context
*sw_context
= &dev_priv
->ctx
;
424 struct vmw_master
*vmaster
= vmw_master(file_priv
->master
);
426 ret
= ttm_read_lock(&vmaster
->lock
, true);
427 if (unlikely(ret
!= 0))
430 ret
= mutex_lock_interruptible(&dev_priv
->cmdbuf_mutex
);
431 if (unlikely(ret
!= 0)) {
433 goto out_no_cmd_mutex
;
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");
443 user_cmd
= (void __user
*)(unsigned long)arg
->commands
;
444 ret
= copy_from_user(cmd
, user_cmd
, arg
->command_size
);
446 if (unlikely(ret
!= 0)) {
447 DRM_ERROR("Failed copying commands.\n");
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;
457 INIT_LIST_HEAD(&sw_context
->validate_nodes
);
459 ret
= vmw_cmd_check_all(dev_priv
, sw_context
, cmd
, arg
->command_size
);
460 if (unlikely(ret
!= 0))
462 ret
= ttm_eu_reserve_buffers(&sw_context
->validate_nodes
,
463 dev_priv
->val_seq
++);
464 if (unlikely(ret
!= 0))
467 ret
= vmw_validate_buffers(dev_priv
, sw_context
);
468 if (unlikely(ret
!= 0))
471 vmw_apply_relocations(sw_context
);
472 vmw_fifo_commit(dev_priv
, arg
->command_size
);
474 ret
= vmw_fifo_send_fence(dev_priv
, &sequence
);
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
);
482 * This error is harmless, because if fence submission fails,
483 * vmw_fifo_send_fence will sync.
487 DRM_ERROR("Fence submission error. Syncing.\n");
489 fence_rep
.error
= ret
;
490 fence_rep
.fence_seq
= (uint64_t) sequence
;
492 user_fence_rep
= (struct drm_vmw_fence_rep __user
*)
493 (unsigned long)arg
->fence_rep
;
496 * copy_to_user errors will be detected by user space not
497 * seeing fence_rep::error filled in.
500 ret
= copy_to_user(user_fence_rep
, &fence_rep
, sizeof(fence_rep
));
502 vmw_kms_cursor_post_execbuf(dev_priv
);
503 ttm_read_unlock(&vmaster
->lock
);
506 vmw_free_relocations(sw_context
);
507 ttm_eu_backoff_reservation(&sw_context
->validate_nodes
);
508 vmw_clear_validations(sw_context
);
510 vmw_fifo_commit(dev_priv
, 0);
512 mutex_unlock(&dev_priv
->cmdbuf_mutex
);
514 ttm_read_unlock(&vmaster
->lock
);