From 781b8bdb2dde76ebd52c26954c09c4500f02522c Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Thu, 1 Sep 2011 20:18:38 +0000 Subject: vmwgfx: Remove the fifo debug ioctl It was only used for bringup debugging, and probably doesn't work anymore. Remove it. Signed-off-by: Thomas Hellstrom Reviewed-by: Jakob Bornecrantz Signed-off-by: Dave Airlie --- drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c | 23 ----------------------- 1 file changed, 23 deletions(-) (limited to 'drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c') diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c b/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c index 570d57775a5..f1b9175bee9 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c @@ -65,26 +65,3 @@ int vmw_getparam_ioctl(struct drm_device *dev, void *data, return 0; } - -int vmw_fifo_debug_ioctl(struct drm_device *dev, void *data, - struct drm_file *file_priv) -{ - struct vmw_private *dev_priv = vmw_priv(dev); - struct vmw_fifo_state *fifo_state = &dev_priv->fifo; - struct drm_vmw_fifo_debug_arg *arg = - (struct drm_vmw_fifo_debug_arg *)data; - __le32 __user *buffer = (__le32 __user *) - (unsigned long)arg->debug_buffer; - - if (unlikely(fifo_state->last_buffer == NULL)) - return -EINVAL; - - if (arg->debug_buffer_size < fifo_state->last_data_size) { - arg->used_size = arg->debug_buffer_size; - arg->did_not_fit = 1; - } else { - arg->used_size = fifo_state->last_data_size; - arg->did_not_fit = 0; - } - return copy_to_user(buffer, fifo_state->last_buffer, arg->used_size); -} -- cgit v1.2.3-70-g09d2 From 07999a7e0e409891cb27f34fa1da851d8484a5c5 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Thu, 1 Sep 2011 20:18:40 +0000 Subject: vmwgfx: Remove the possibility to map the fifo from user-space This was previously used by user-space to check whether a fence sequence had passed or not. With fence objects that's not needed anymore. Signed-off-by: Thomas Hellstrom Reviewed-by: Jakob Bornecrantz Signed-off-by: Dave Airlie --- drivers/gpu/drm/vmwgfx/vmwgfx_drv.h | 1 - drivers/gpu/drm/vmwgfx/vmwgfx_fifo.c | 48 -------------------------------- drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c | 3 -- drivers/gpu/drm/vmwgfx/vmwgfx_ttm_glue.c | 5 ++-- include/drm/vmwgfx_drm.h | 7 ++--- 5 files changed, 5 insertions(+), 59 deletions(-) (limited to 'drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c') diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h index a99400f1053..39be7961906 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h @@ -411,7 +411,6 @@ extern void vmw_fifo_commit(struct vmw_private *dev_priv, uint32_t bytes); extern int vmw_fifo_send_fence(struct vmw_private *dev_priv, uint32_t *sequence); extern void vmw_fifo_ping_host(struct vmw_private *dev_priv, uint32_t reason); -extern int vmw_fifo_mmap(struct file *filp, struct vm_area_struct *vma); extern bool vmw_fifo_have_3d(struct vmw_private *dev_priv); extern bool vmw_fifo_have_pitchlock(struct vmw_private *dev_priv); diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_fifo.c b/drivers/gpu/drm/vmwgfx/vmwgfx_fifo.c index d031c555fa4..aae01b9ae4d 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_fifo.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_fifo.c @@ -491,51 +491,3 @@ int vmw_fifo_send_fence(struct vmw_private *dev_priv, uint32_t *sequence) out_err: return ret; } - -/** - * Map the first page of the FIFO read-only to user-space. - */ - -static int vmw_fifo_vm_fault(struct vm_area_struct *vma, struct vm_fault *vmf) -{ - int ret; - unsigned long address = (unsigned long)vmf->virtual_address; - - if (address != vma->vm_start) - return VM_FAULT_SIGBUS; - - ret = vm_insert_pfn(vma, address, vma->vm_pgoff); - if (likely(ret == -EBUSY || ret == 0)) - return VM_FAULT_NOPAGE; - else if (ret == -ENOMEM) - return VM_FAULT_OOM; - - return VM_FAULT_SIGBUS; -} - -static struct vm_operations_struct vmw_fifo_vm_ops = { - .fault = vmw_fifo_vm_fault, - .open = NULL, - .close = NULL -}; - -int vmw_fifo_mmap(struct file *filp, struct vm_area_struct *vma) -{ - struct drm_file *file_priv; - struct vmw_private *dev_priv; - - file_priv = filp->private_data; - dev_priv = vmw_priv(file_priv->minor->dev); - - if (vma->vm_pgoff != (dev_priv->mmio_start >> PAGE_SHIFT) || - (vma->vm_end - vma->vm_start) != PAGE_SIZE) - return -EINVAL; - - vma->vm_flags &= ~(VM_WRITE | VM_MAYWRITE); - vma->vm_flags |= VM_IO | VM_PFNMAP | VM_DONTEXPAND | VM_SHARED; - vma->vm_page_prot = vm_get_page_prot(vma->vm_flags); - vma->vm_page_prot = ttm_io_prot(TTM_PL_FLAG_UNCACHED, - vma->vm_page_prot); - vma->vm_ops = &vmw_fifo_vm_ops; - return 0; -} diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c b/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c index f1b9175bee9..74b1dc8a7cd 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c @@ -45,9 +45,6 @@ int vmw_getparam_ioctl(struct drm_device *dev, void *data, case DRM_VMW_PARAM_3D: param->value = vmw_fifo_have_3d(dev_priv) ? 1 : 0; break; - case DRM_VMW_PARAM_FIFO_OFFSET: - param->value = dev_priv->mmio_start; - break; case DRM_VMW_PARAM_HW_CAPS: param->value = dev_priv->capabilities; break; diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_ttm_glue.c b/drivers/gpu/drm/vmwgfx/vmwgfx_ttm_glue.c index 1e8eedd901e..d3c11f5184f 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_ttm_glue.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_ttm_glue.c @@ -34,9 +34,8 @@ int vmw_mmap(struct file *filp, struct vm_area_struct *vma) struct vmw_private *dev_priv; if (unlikely(vma->vm_pgoff < VMWGFX_FILE_PAGE_OFFSET)) { - if (vmw_fifo_mmap(filp, vma) == 0) - return 0; - return drm_mmap(filp, vma); + DRM_ERROR("Illegal attempt to mmap old fifo space.\n"); + return -EINVAL; } file_priv = filp->private_data; diff --git a/include/drm/vmwgfx_drm.h b/include/drm/vmwgfx_drm.h index c0b226bc367..490db458d5d 100644 --- a/include/drm/vmwgfx_drm.h +++ b/include/drm/vmwgfx_drm.h @@ -65,10 +65,9 @@ #define DRM_VMW_PARAM_NUM_STREAMS 0 #define DRM_VMW_PARAM_NUM_FREE_STREAMS 1 #define DRM_VMW_PARAM_3D 2 -#define DRM_VMW_PARAM_FIFO_OFFSET 3 -#define DRM_VMW_PARAM_HW_CAPS 4 -#define DRM_VMW_PARAM_FIFO_CAPS 5 -#define DRM_VMW_PARAM_MAX_FB_SIZE 6 +#define DRM_VMW_PARAM_HW_CAPS 3 +#define DRM_VMW_PARAM_FIFO_CAPS 4 +#define DRM_VMW_PARAM_MAX_FB_SIZE 5 /** * struct drm_vmw_getparam_arg -- cgit v1.2.3-70-g09d2 From f63f6a59d3905ac73aeeb617b27ac31516549ed9 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Thu, 1 Sep 2011 20:18:41 +0000 Subject: vmwgfx: Add functionality to get 3D caps Since we don't allow user-space to map the fifo anymore, add a parameter to get fifo hw version and an ioctl to copy the 3D capabilities. Signed-off-by: Thomas Hellstrom Reviewed-by: Jakob Bornecranz Signed-off-by: Dave Airlie --- drivers/gpu/drm/vmwgfx/vmwgfx_drv.c | 5 ++++ drivers/gpu/drm/vmwgfx/vmwgfx_drv.h | 2 ++ drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c | 48 +++++++++++++++++++++++++++++++++++ include/drm/vmwgfx_drm.h | 25 ++++++++++++++++++ 4 files changed, 80 insertions(+) (limited to 'drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c') diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c index 9819d0d048d..8010254e9cf 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c @@ -85,6 +85,9 @@ #define DRM_IOCTL_VMW_FENCE_WAIT \ DRM_IOWR(DRM_COMMAND_BASE + DRM_VMW_FENCE_WAIT, \ struct drm_vmw_fence_wait_arg) +#define DRM_IOCTL_VMW_GET_3D_CAP \ + DRM_IOW(DRM_COMMAND_BASE + DRM_VMW_GET_3D_CAP, \ + struct drm_vmw_get_3d_cap_arg) /** * The core DRM version of this macro doesn't account for @@ -130,6 +133,8 @@ static struct drm_ioctl_desc vmw_ioctls[] = { DRM_AUTH | DRM_UNLOCKED), VMW_IOCTL_DEF(VMW_FENCE_WAIT, vmw_fence_wait_ioctl, DRM_AUTH | DRM_UNLOCKED), + VMW_IOCTL_DEF(VMW_GET_3D_CAP, vmw_get_cap_3d_ioctl, + DRM_AUTH | DRM_UNLOCKED), }; static struct pci_device_id vmw_pci_id_list[] = { diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h index 39be7961906..2374a5c495f 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h @@ -397,6 +397,8 @@ extern int vmw_user_stream_lookup(struct vmw_private *dev_priv, extern int vmw_getparam_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); +extern int vmw_get_cap_3d_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv); /** * Fifo utilities - vmwgfx_fifo.c diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c b/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c index 74b1dc8a7cd..5ecf9666064 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c @@ -54,6 +54,13 @@ int vmw_getparam_ioctl(struct drm_device *dev, void *data, case DRM_VMW_PARAM_MAX_FB_SIZE: param->value = dev_priv->vram_size; break; + case DRM_VMW_PARAM_FIFO_HW_VERSION: + { + __le32 __iomem *fifo_mem = dev_priv->mmio_virt; + + param->value = ioread32(fifo_mem + SVGA_FIFO_3D_HWVERSION); + break; + } default: DRM_ERROR("Illegal vmwgfx get param request: %d\n", param->param); @@ -62,3 +69,44 @@ int vmw_getparam_ioctl(struct drm_device *dev, void *data, return 0; } + + +int vmw_get_cap_3d_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv) +{ + struct drm_vmw_get_3d_cap_arg *arg = + (struct drm_vmw_get_3d_cap_arg *) data; + struct vmw_private *dev_priv = vmw_priv(dev); + uint32_t size; + __le32 __iomem *fifo_mem; + void __user *buffer = (void __user *)((unsigned long)(arg->buffer)); + void *bounce; + int ret; + + if (unlikely(arg->pad64 != 0)) { + DRM_ERROR("Illegal GET_3D_CAP argument.\n"); + return -EINVAL; + } + + size = (SVGA_FIFO_3D_CAPS_LAST - SVGA_FIFO_3D_CAPS + 1) << 2; + + if (arg->max_size < size) + size = arg->max_size; + + bounce = vmalloc(size); + if (unlikely(bounce == NULL)) { + DRM_ERROR("Failed to allocate bounce buffer for 3D caps.\n"); + return -ENOMEM; + } + + fifo_mem = dev_priv->mmio_virt; + memcpy_fromio(bounce, &fifo_mem[SVGA_FIFO_3D_CAPS], size); + + ret = copy_to_user(buffer, bounce, size); + vfree(bounce); + + if (unlikely(ret != 0)) + DRM_ERROR("Failed to report 3D caps info.\n"); + + return ret; +} diff --git a/include/drm/vmwgfx_drm.h b/include/drm/vmwgfx_drm.h index 490db458d5d..467b80c7485 100644 --- a/include/drm/vmwgfx_drm.h +++ b/include/drm/vmwgfx_drm.h @@ -49,6 +49,7 @@ #define DRM_VMW_REF_SURFACE 11 #define DRM_VMW_EXECBUF 12 #define DRM_VMW_FENCE_WAIT 13 +#define DRM_VMW_GET_3D_CAP 14 /*************************************************************************/ /** @@ -68,6 +69,7 @@ #define DRM_VMW_PARAM_HW_CAPS 3 #define DRM_VMW_PARAM_FIFO_CAPS 4 #define DRM_VMW_PARAM_MAX_FB_SIZE 5 +#define DRM_VMW_PARAM_FIFO_HW_VERSION 6 /** * struct drm_vmw_getparam_arg @@ -557,6 +559,29 @@ struct drm_vmw_stream_arg { * Return a single stream that was claimed by this process. Also makes * sure that the stream has been stopped. */ +/*************************************************************************/ +/** + * DRM_VMW_GET_3D_CAP + * + * Read 3D capabilities from the FIFO + * + */ + +/** + * struct drm_vmw_get_3d_cap_arg + * + * @buffer: Pointer to a buffer for capability data, cast to an uint64_t + * @size: Max size to copy + * + * Input argument to the DRM_VMW_GET_3D_CAP_IOCTL + * ioctls. + */ + +struct drm_vmw_get_3d_cap_arg { + uint64_t buffer; + uint32_t max_size; + uint32_t pad64; +}; /*************************************************************************/ /** -- cgit v1.2.3-70-g09d2 From 2fcd5a73bfd5341876f9ea6b5adcc1dd814226d4 Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Tue, 4 Oct 2011 20:13:26 +0200 Subject: vmwgfx: Add present and readback ioctls Signed-off-by: Jakob Bornecrantz Signed-off-by: Thomas Hellstrom Signed-off-by: Dave Airlie --- drivers/gpu/drm/vmwgfx/vmwgfx_drv.c | 13 +++ drivers/gpu/drm/vmwgfx/vmwgfx_drv.h | 19 ++++ drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c | 172 ++++++++++++++++++++++++++++++++++ drivers/gpu/drm/vmwgfx/vmwgfx_kms.c | 170 +++++++++++++++++++++++++++++++++ drivers/gpu/drm/vmwgfx/vmwgfx_kms.h | 3 + include/drm/vmwgfx_drm.h | 63 +++++++++++++ 6 files changed, 440 insertions(+) (limited to 'drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c') diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c index 73757c3db8e..ace4402214c 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c @@ -94,6 +94,12 @@ #define DRM_IOCTL_VMW_FENCE_UNREF \ DRM_IOW(DRM_COMMAND_BASE + DRM_VMW_FENCE_UNREF, \ struct drm_vmw_fence_arg) +#define DRM_IOCTL_VMW_PRESENT \ + DRM_IOW(DRM_COMMAND_BASE + DRM_VMW_PRESENT, \ + struct drm_vmw_present_arg) +#define DRM_IOCTL_VMW_PRESENT_READBACK \ + DRM_IOW(DRM_COMMAND_BASE + DRM_VMW_PRESENT_READBACK, \ + struct drm_vmw_present_readback_arg) /** * The core DRM version of this macro doesn't account for @@ -146,6 +152,13 @@ static struct drm_ioctl_desc vmw_ioctls[] = { DRM_AUTH | DRM_UNLOCKED), VMW_IOCTL_DEF(VMW_GET_3D_CAP, vmw_get_cap_3d_ioctl, DRM_AUTH | DRM_UNLOCKED), + + /* these allow direct access to the framebuffers mark as master only */ + VMW_IOCTL_DEF(VMW_PRESENT, vmw_present_ioctl, + DRM_MASTER | DRM_AUTH | DRM_UNLOCKED), + VMW_IOCTL_DEF(VMW_PRESENT_READBACK, + vmw_present_readback_ioctl, + DRM_MASTER | DRM_AUTH | DRM_UNLOCKED), }; static struct pci_device_id vmw_pci_id_list[] = { diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h index 2124fbc919a..fc0e3bc63ec 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h @@ -97,6 +97,8 @@ struct vmw_cursor_snooper { uint32_t *image; }; +struct vmw_framebuffer; + struct vmw_surface { struct vmw_resource res; uint32_t flags; @@ -430,6 +432,10 @@ extern int vmw_getparam_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); extern int vmw_get_cap_3d_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); +extern int vmw_present_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv); +extern int vmw_present_readback_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv); /** * Fifo utilities - vmwgfx_fifo.c @@ -554,6 +560,19 @@ bool vmw_kms_validate_mode_vram(struct vmw_private *dev_priv, uint32_t pitch, uint32_t height); u32 vmw_get_vblank_counter(struct drm_device *dev, int crtc); +int vmw_kms_present(struct vmw_private *dev_priv, + struct drm_file *file_priv, + struct vmw_framebuffer *vfb, + struct vmw_surface *surface, + uint32_t sid, int32_t destX, int32_t destY, + struct drm_vmw_rect *clips, + uint32_t num_clips); +int vmw_kms_readback(struct vmw_private *dev_priv, + struct drm_file *file_priv, + struct vmw_framebuffer *vfb, + struct drm_vmw_fence_rep __user *user_fence_rep, + struct drm_vmw_rect *clips, + uint32_t num_clips); /** * Overlay control - vmwgfx_overlay.c diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c b/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c index 5ecf9666064..c0284a4784c 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c @@ -27,6 +27,7 @@ #include "vmwgfx_drv.h" #include "vmwgfx_drm.h" +#include "vmwgfx_kms.h" int vmw_getparam_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv) @@ -110,3 +111,174 @@ int vmw_get_cap_3d_ioctl(struct drm_device *dev, void *data, return ret; } + +int vmw_present_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv) +{ + struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile; + struct vmw_private *dev_priv = vmw_priv(dev); + struct drm_vmw_present_arg *arg = + (struct drm_vmw_present_arg *)data; + struct vmw_surface *surface; + struct vmw_master *vmaster = vmw_master(file_priv->master); + struct drm_vmw_rect __user *clips_ptr; + struct drm_vmw_rect *clips = NULL; + struct drm_mode_object *obj; + struct vmw_framebuffer *vfb; + uint32_t num_clips; + int ret; + + num_clips = arg->num_clips; + clips_ptr = (struct drm_vmw_rect *)(unsigned long)arg->clips_ptr; + + if (unlikely(num_clips == 0)) + return 0; + + if (clips_ptr == NULL) { + DRM_ERROR("Variable clips_ptr must be specified.\n"); + ret = -EINVAL; + goto out_clips; + } + + clips = kzalloc(num_clips * sizeof(*clips), GFP_KERNEL); + if (clips == NULL) { + DRM_ERROR("Failed to allocate clip rect list.\n"); + ret = -ENOMEM; + goto out_clips; + } + + ret = copy_from_user(clips, clips_ptr, num_clips * sizeof(*clips)); + if (ret) { + DRM_ERROR("Failed to copy clip rects from userspace.\n"); + goto out_no_copy; + } + + ret = mutex_lock_interruptible(&dev->mode_config.mutex); + if (unlikely(ret != 0)) { + ret = -ERESTARTSYS; + goto out_no_mode_mutex; + } + + obj = drm_mode_object_find(dev, arg->fb_id, DRM_MODE_OBJECT_FB); + if (!obj) { + DRM_ERROR("Invalid framebuffer id.\n"); + ret = -EINVAL; + goto out_no_fb; + } + + vfb = vmw_framebuffer_to_vfb(obj_to_fb(obj)); + if (!vfb->dmabuf) { + DRM_ERROR("Framebuffer not dmabuf backed.\n"); + ret = -EINVAL; + goto out_no_fb; + } + + ret = ttm_read_lock(&vmaster->lock, true); + if (unlikely(ret != 0)) + goto out_no_ttm_lock; + + ret = vmw_user_surface_lookup_handle(dev_priv, tfile, arg->sid, + &surface); + if (ret) + goto out_no_surface; + + ret = vmw_kms_present(dev_priv, file_priv, + vfb, surface, arg->sid, + arg->dest_x, arg->dest_y, + clips, num_clips); + + /* vmw_user_surface_lookup takes one ref so does new_fb */ + vmw_surface_unreference(&surface); + +out_no_surface: + ttm_read_unlock(&vmaster->lock); +out_no_ttm_lock: +out_no_fb: + mutex_unlock(&dev->mode_config.mutex); +out_no_mode_mutex: +out_no_copy: + kfree(clips); +out_clips: + return ret; +} + +int vmw_present_readback_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv) +{ + struct vmw_private *dev_priv = vmw_priv(dev); + struct drm_vmw_present_readback_arg *arg = + (struct drm_vmw_present_readback_arg *)data; + struct drm_vmw_fence_rep __user *user_fence_rep = + (struct drm_vmw_fence_rep __user *) + (unsigned long)arg->fence_rep; + struct vmw_master *vmaster = vmw_master(file_priv->master); + struct drm_vmw_rect __user *clips_ptr; + struct drm_vmw_rect *clips = NULL; + struct drm_mode_object *obj; + struct vmw_framebuffer *vfb; + uint32_t num_clips; + int ret; + + num_clips = arg->num_clips; + clips_ptr = (struct drm_vmw_rect *)(unsigned long)arg->clips_ptr; + + if (unlikely(num_clips == 0)) + return 0; + + if (clips_ptr == NULL) { + DRM_ERROR("Argument clips_ptr must be specified.\n"); + ret = -EINVAL; + goto out_clips; + } + + clips = kzalloc(num_clips * sizeof(*clips), GFP_KERNEL); + if (clips == NULL) { + DRM_ERROR("Failed to allocate clip rect list.\n"); + ret = -ENOMEM; + goto out_clips; + } + + ret = copy_from_user(clips, clips_ptr, num_clips * sizeof(*clips)); + if (ret) { + DRM_ERROR("Failed to copy clip rects from userspace.\n"); + goto out_no_copy; + } + + ret = mutex_lock_interruptible(&dev->mode_config.mutex); + if (unlikely(ret != 0)) { + ret = -ERESTARTSYS; + goto out_no_mode_mutex; + } + + obj = drm_mode_object_find(dev, arg->fb_id, DRM_MODE_OBJECT_FB); + if (!obj) { + DRM_ERROR("Invalid framebuffer id.\n"); + ret = -EINVAL; + goto out_no_fb; + } + + vfb = vmw_framebuffer_to_vfb(obj_to_fb(obj)); + if (!vfb->dmabuf) { + DRM_ERROR("Framebuffer not dmabuf backed.\n"); + ret = -EINVAL; + goto out_no_fb; + } + + ret = ttm_read_lock(&vmaster->lock, true); + if (unlikely(ret != 0)) + goto out_no_ttm_lock; + + ret = vmw_kms_readback(dev_priv, file_priv, + vfb, user_fence_rep, + clips, num_clips); + + ttm_read_unlock(&vmaster->lock); +out_no_ttm_lock: +out_no_fb: + mutex_unlock(&dev->mode_config.mutex); +out_no_mode_mutex: +out_no_copy: + kfree(clips); +out_clips: + return ret; +} diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c index 8628bc7cc0d..41916b58a3f 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c @@ -800,6 +800,7 @@ static int vmw_kms_new_framebuffer_dmabuf(struct vmw_private *dev_priv, vfbd->base.pin = vmw_framebuffer_dmabuf_pin; vfbd->base.unpin = vmw_framebuffer_dmabuf_unpin; } + vfbd->base.dmabuf = true; vfbd->buffer = dmabuf; vfbd->handle = mode_cmd->handle; *out = &vfbd->base; @@ -900,6 +901,175 @@ static struct drm_mode_config_funcs vmw_kms_funcs = { .fb_create = vmw_kms_fb_create, }; +int vmw_kms_present(struct vmw_private *dev_priv, + struct drm_file *file_priv, + struct vmw_framebuffer *vfb, + struct vmw_surface *surface, + uint32_t sid, + int32_t destX, int32_t destY, + struct drm_vmw_rect *clips, + uint32_t num_clips) +{ + size_t fifo_size; + int i, ret; + + struct { + SVGA3dCmdHeader header; + SVGA3dCmdBlitSurfaceToScreen body; + } *cmd; + SVGASignedRect *blits; + + BUG_ON(surface == NULL); + BUG_ON(!clips || !num_clips); + + fifo_size = sizeof(*cmd) + sizeof(SVGASignedRect) * num_clips; + cmd = kmalloc(fifo_size, GFP_KERNEL); + if (unlikely(cmd == NULL)) { + DRM_ERROR("Failed to allocate temporary fifo memory.\n"); + return -ENOMEM; + } + + memset(cmd, 0, fifo_size); + + cmd->header.id = cpu_to_le32(SVGA_3D_CMD_BLIT_SURFACE_TO_SCREEN); + cmd->header.size = cpu_to_le32(fifo_size - sizeof(cmd->header)); + + cmd->body.srcImage.sid = sid; + cmd->body.destScreenId = SVGA_ID_INVALID; /* virtual coords */ + + cmd->body.srcRect.left = 0; + cmd->body.srcRect.right = surface->sizes[0].width; + cmd->body.srcRect.top = 0; + cmd->body.srcRect.bottom = surface->sizes[0].height; + + cmd->body.destRect.left = destX; + cmd->body.destRect.right = destX + surface->sizes[0].width; + cmd->body.destRect.top = destY; + cmd->body.destRect.bottom = destY + surface->sizes[0].height; + + blits = (SVGASignedRect *)&cmd[1]; + for (i = 0; i < num_clips; i++) { + blits[i].left = clips[i].x; + blits[i].right = clips[i].x + clips[i].w; + blits[i].top = clips[i].y; + blits[i].bottom = clips[i].y + clips[i].h; + } + + ret = vmw_execbuf_process(file_priv, dev_priv, NULL, cmd, + fifo_size, 0, NULL); + + kfree(cmd); + + return ret; +} + +int vmw_kms_readback(struct vmw_private *dev_priv, + struct drm_file *file_priv, + struct vmw_framebuffer *vfb, + struct drm_vmw_fence_rep __user *user_fence_rep, + struct drm_vmw_rect *clips, + uint32_t num_clips) +{ + struct vmw_framebuffer_dmabuf *vfbd = + vmw_framebuffer_to_vfbd(&vfb->base); + struct vmw_dma_buffer *dmabuf = vfbd->buffer; + struct vmw_display_unit *units[VMWGFX_NUM_DISPLAY_UNITS]; + struct drm_crtc *crtc; + size_t fifo_size; + int i, k, ret, num_units, blits_pos; + + struct { + uint32_t header; + SVGAFifoCmdDefineGMRFB body; + } *cmd; + struct { + uint32_t header; + SVGAFifoCmdBlitScreenToGMRFB body; + } *blits; + + num_units = 0; + list_for_each_entry(crtc, &dev_priv->dev->mode_config.crtc_list, head) { + if (crtc->fb != &vfb->base) + continue; + units[num_units++] = vmw_crtc_to_du(crtc); + } + + BUG_ON(dmabuf == NULL); + BUG_ON(!clips || !num_clips); + + /* take a safe guess at fifo size */ + fifo_size = sizeof(*cmd) + sizeof(*blits) * num_clips * num_units; + cmd = kmalloc(fifo_size, GFP_KERNEL); + if (unlikely(cmd == NULL)) { + DRM_ERROR("Failed to allocate temporary fifo memory.\n"); + return -ENOMEM; + } + + memset(cmd, 0, fifo_size); + cmd->header = SVGA_CMD_DEFINE_GMRFB; + cmd->body.format.bitsPerPixel = vfb->base.bits_per_pixel; + cmd->body.format.colorDepth = vfb->base.depth; + cmd->body.format.reserved = 0; + cmd->body.bytesPerLine = vfb->base.pitch; + cmd->body.ptr.gmrId = vfbd->handle; + cmd->body.ptr.offset = 0; + + blits = (void *)&cmd[1]; + blits_pos = 0; + for (i = 0; i < num_units; i++) { + struct drm_vmw_rect *c = clips; + for (k = 0; k < num_clips; k++, c++) { + /* transform clip coords to crtc origin based coords */ + int clip_x1 = c->x - units[i]->crtc.x; + int clip_x2 = c->x - units[i]->crtc.x + c->w; + int clip_y1 = c->y - units[i]->crtc.y; + int clip_y2 = c->y - units[i]->crtc.y + c->h; + int dest_x = c->x; + int dest_y = c->y; + + /* compensate for clipping, we negate + * a negative number and add that. + */ + if (clip_x1 < 0) + dest_x += -clip_x1; + if (clip_y1 < 0) + dest_y += -clip_y1; + + /* clip */ + clip_x1 = max(clip_x1, 0); + clip_y1 = max(clip_y1, 0); + clip_x2 = min(clip_x2, units[i]->crtc.mode.hdisplay); + clip_y2 = min(clip_y2, units[i]->crtc.mode.vdisplay); + + /* and cull any rects that misses the crtc */ + if (clip_x1 >= units[i]->crtc.mode.hdisplay || + clip_y1 >= units[i]->crtc.mode.vdisplay || + clip_x2 <= 0 || clip_y2 <= 0) + continue; + + blits[blits_pos].header = SVGA_CMD_BLIT_SCREEN_TO_GMRFB; + blits[blits_pos].body.srcScreenId = units[i]->unit; + blits[blits_pos].body.destOrigin.x = dest_x; + blits[blits_pos].body.destOrigin.y = dest_y; + + blits[blits_pos].body.srcRect.left = clip_x1; + blits[blits_pos].body.srcRect.top = clip_y1; + blits[blits_pos].body.srcRect.right = clip_x2; + blits[blits_pos].body.srcRect.bottom = clip_y2; + blits_pos++; + } + } + /* reset size here and use calculated exact size from loops */ + fifo_size = sizeof(*cmd) + sizeof(*blits) * blits_pos; + + ret = vmw_execbuf_process(file_priv, dev_priv, NULL, cmd, fifo_size, + 0, user_fence_rep); + + kfree(cmd); + + return ret; +} + int vmw_kms_init(struct vmw_private *dev_priv) { struct drm_device *dev = dev_priv->dev; diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h index ee16a06e4ca..08d2630ac3a 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h @@ -47,6 +47,7 @@ struct vmw_framebuffer { struct drm_framebuffer base; int (*pin)(struct vmw_framebuffer *fb); int (*unpin)(struct vmw_framebuffer *fb); + bool dmabuf; }; @@ -95,6 +96,8 @@ struct vmw_display_unit { struct drm_display_mode *pref_mode; }; +#define vmw_crtc_to_du(x) \ + container_of(x, struct vmw_display_unit, crtc) #define vmw_connector_to_du(x) \ container_of(x, struct vmw_display_unit, connector) diff --git a/include/drm/vmwgfx_drm.h b/include/drm/vmwgfx_drm.h index 29cd9cfdd61..5b5b0a891f3 100644 --- a/include/drm/vmwgfx_drm.h +++ b/include/drm/vmwgfx_drm.h @@ -52,6 +52,8 @@ #define DRM_VMW_FENCE_SIGNALED 15 #define DRM_VMW_FENCE_UNREF 16 #define DRM_VMW_FENCE_EVENT 17 +#define DRM_VMW_PRESENT 18 +#define DRM_VMW_PRESENT_READBACK 19 /*************************************************************************/ @@ -681,5 +683,66 @@ struct drm_vmw_fence_arg { }; +/*************************************************************************/ +/** + * DRM_VMW_PRESENT + * + * Executes an SVGA present on a given fb for a given surface. The surface + * is placed on the framebuffer. Cliprects are given relative to the given + * point (the point disignated by dest_{x|y}). + * + */ + +/** + * struct drm_vmw_present_arg + * @fb_id: framebuffer id to present / read back from. + * @sid: Surface id to present from. + * @dest_x: X placement coordinate for surface. + * @dest_y: Y placement coordinate for surface. + * @clips_ptr: Pointer to an array of clip rects cast to an uint64_t. + * @num_clips: Number of cliprects given relative to the framebuffer origin, + * in the same coordinate space as the frame buffer. + * @pad64: Unused 64-bit padding. + * + * Input argument to the DRM_VMW_PRESENT ioctl. + */ + +struct drm_vmw_present_arg { + uint32_t fb_id; + uint32_t sid; + int32_t dest_x; + int32_t dest_y; + uint64_t clips_ptr; + uint32_t num_clips; + uint32_t pad64; +}; + + +/*************************************************************************/ +/** + * DRM_VMW_PRESENT_READBACK + * + * Executes an SVGA present readback from a given fb to the dma buffer + * currently bound as the fb. If there is no dma buffer bound to the fb, + * an error will be returned. + * + */ + +/** + * struct drm_vmw_present_arg + * @fb_id: fb_id to present / read back from. + * @num_clips: Number of cliprects. + * @clips_ptr: Pointer to an array of clip rects cast to an uint64_t. + * @fence_rep: Pointer to a struct drm_vmw_fence_rep, cast to an uint64_t. + * If this member is NULL, then the ioctl should not return a fence. + */ + +struct drm_vmw_present_readback_arg { + uint32_t fb_id; + uint32_t num_clips; + uint64_t clips_ptr; + uint64_t fence_rep; +}; + #endif -- cgit v1.2.3-70-g09d2 From 5438ae88d098c086cfb94be5327c49a04fc6bfd7 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Mon, 10 Oct 2011 12:23:27 +0200 Subject: vmwgfx: Wrap drm_read and drm_poll Make sure the device is processing the fifo when these functions are called in case they might sleep waiting for an event. Signed-off-by: Thomas Hellstrom Signed-off-by: Dave Airlie --- drivers/gpu/drm/vmwgfx/vmwgfx_drv.c | 3 ++- drivers/gpu/drm/vmwgfx/vmwgfx_drv.h | 4 ++++ drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c | 43 +++++++++++++++++++++++++++++++++++ 3 files changed, 49 insertions(+), 1 deletion(-) (limited to 'drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c') diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c index 5e1994a8ffc..e07dcf40a3b 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c @@ -1085,7 +1085,8 @@ static struct drm_driver driver = { .release = drm_release, .unlocked_ioctl = vmw_unlocked_ioctl, .mmap = vmw_mmap, - .poll = drm_poll, + .poll = vmw_fops_poll, + .read = vmw_fops_read, .fasync = drm_fasync, #if defined(CONFIG_COMPAT) .compat_ioctl = drm_compat_ioctl, diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h index 83b2563e684..0e9b2cefaa9 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h @@ -469,6 +469,10 @@ extern int vmw_present_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); extern int vmw_present_readback_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); +extern unsigned int vmw_fops_poll(struct file *filp, + struct poll_table_struct *wait); +extern ssize_t vmw_fops_read(struct file *filp, char __user *buffer, + size_t count, loff_t *offset); /** * Fifo utilities - vmwgfx_fifo.c diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c b/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c index c0284a4784c..97f23abeacd 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c @@ -282,3 +282,46 @@ out_no_copy: out_clips: return ret; } + + +/** + * vmw_fops_poll - wrapper around the drm_poll function + * + * @filp: See the linux fops poll documentation. + * @wait: See the linux fops poll documentation. + * + * Wrapper around the drm_poll function that makes sure the device is + * processing the fifo if drm_poll decides to wait. + */ +unsigned int vmw_fops_poll(struct file *filp, struct poll_table_struct *wait) +{ + struct drm_file *file_priv = filp->private_data; + struct vmw_private *dev_priv = + vmw_priv(file_priv->minor->dev); + + vmw_fifo_ping_host(dev_priv, SVGA_SYNC_GENERIC); + return drm_poll(filp, wait); +} + + +/** + * vmw_fops_read - wrapper around the drm_read function + * + * @filp: See the linux fops read documentation. + * @buffer: See the linux fops read documentation. + * @count: See the linux fops read documentation. + * offset: See the linux fops read documentation. + * + * Wrapper around the drm_read function that makes sure the device is + * processing the fifo if drm_read decides to wait. + */ +ssize_t vmw_fops_read(struct file *filp, char __user *buffer, + size_t count, loff_t *offset) +{ + struct drm_file *file_priv = filp->private_data; + struct vmw_private *dev_priv = + vmw_priv(file_priv->minor->dev); + + vmw_fifo_ping_host(dev_priv, SVGA_SYNC_GENERIC); + return drm_read(filp, buffer, count, offset); +} -- cgit v1.2.3-70-g09d2 From d2c184fb10656f2a6d59fef76efb3a8b12fb6ed4 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Tue, 18 Oct 2011 09:09:19 +0300 Subject: vmwgfx: return -EFAULT instead of number of bytes remaining The intent here was to return an error code, but instead the code returns the number of bytes remaining (that weren't copied). Signed-off-by: Dan Carpenter Reviewed-by: Thomas Hellstrom Signed-off-by: Dave Airlie --- drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c') diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c b/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c index 97f23abeacd..3f6343502d1 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c @@ -150,6 +150,7 @@ int vmw_present_ioctl(struct drm_device *dev, void *data, ret = copy_from_user(clips, clips_ptr, num_clips * sizeof(*clips)); if (ret) { DRM_ERROR("Failed to copy clip rects from userspace.\n"); + ret = -EFAULT; goto out_no_copy; } @@ -241,6 +242,7 @@ int vmw_present_readback_ioctl(struct drm_device *dev, void *data, ret = copy_from_user(clips, clips_ptr, num_clips * sizeof(*clips)); if (ret) { DRM_ERROR("Failed to copy clip rects from userspace.\n"); + ret = -EFAULT; goto out_no_copy; } -- cgit v1.2.3-70-g09d2