Home | History | Annotate | Line # | Download | only in vmwgfx
vmwgfx_ioctl.c revision 1.1.1.1.8.2
      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 <drm/vmwgfx_drm.h>
     30 #include "vmwgfx_kms.h"
     31 
     32 int vmw_getparam_ioctl(struct drm_device *dev, void *data,
     33 		       struct drm_file *file_priv)
     34 {
     35 	struct vmw_private *dev_priv = vmw_priv(dev);
     36 	struct drm_vmw_getparam_arg *param =
     37 	    (struct drm_vmw_getparam_arg *)data;
     38 
     39 	switch (param->param) {
     40 	case DRM_VMW_PARAM_NUM_STREAMS:
     41 		param->value = vmw_overlay_num_overlays(dev_priv);
     42 		break;
     43 	case DRM_VMW_PARAM_NUM_FREE_STREAMS:
     44 		param->value = vmw_overlay_num_free_overlays(dev_priv);
     45 		break;
     46 	case DRM_VMW_PARAM_3D:
     47 		param->value = vmw_fifo_have_3d(dev_priv) ? 1 : 0;
     48 		break;
     49 	case DRM_VMW_PARAM_HW_CAPS:
     50 		param->value = dev_priv->capabilities;
     51 		break;
     52 	case DRM_VMW_PARAM_FIFO_CAPS:
     53 		param->value = dev_priv->fifo.capabilities;
     54 		break;
     55 	case DRM_VMW_PARAM_MAX_FB_SIZE:
     56 		param->value = dev_priv->vram_size;
     57 		break;
     58 	case DRM_VMW_PARAM_FIFO_HW_VERSION:
     59 	{
     60 		__le32 __iomem *fifo_mem = dev_priv->mmio_virt;
     61 		const struct vmw_fifo_state *fifo = &dev_priv->fifo;
     62 
     63 		param->value =
     64 			ioread32(fifo_mem +
     65 				 ((fifo->capabilities &
     66 				   SVGA_FIFO_CAP_3D_HWVERSION_REVISED) ?
     67 				  SVGA_FIFO_3D_HWVERSION_REVISED :
     68 				  SVGA_FIFO_3D_HWVERSION));
     69 		break;
     70 	}
     71 	default:
     72 		DRM_ERROR("Illegal vmwgfx get param request: %d\n",
     73 			  param->param);
     74 		return -EINVAL;
     75 	}
     76 
     77 	return 0;
     78 }
     79 
     80 
     81 int vmw_get_cap_3d_ioctl(struct drm_device *dev, void *data,
     82 			 struct drm_file *file_priv)
     83 {
     84 	struct drm_vmw_get_3d_cap_arg *arg =
     85 		(struct drm_vmw_get_3d_cap_arg *) data;
     86 	struct vmw_private *dev_priv = vmw_priv(dev);
     87 	uint32_t size;
     88 	__le32 __iomem *fifo_mem;
     89 	void __user *buffer = (void __user *)((unsigned long)(arg->buffer));
     90 	void *bounce;
     91 	int ret;
     92 
     93 	if (unlikely(arg->pad64 != 0)) {
     94 		DRM_ERROR("Illegal GET_3D_CAP argument.\n");
     95 		return -EINVAL;
     96 	}
     97 
     98 	size = (SVGA_FIFO_3D_CAPS_LAST - SVGA_FIFO_3D_CAPS + 1) << 2;
     99 
    100 	if (arg->max_size < size)
    101 		size = arg->max_size;
    102 
    103 	bounce = vmalloc(size);
    104 	if (unlikely(bounce == NULL)) {
    105 		DRM_ERROR("Failed to allocate bounce buffer for 3D caps.\n");
    106 		return -ENOMEM;
    107 	}
    108 
    109 	fifo_mem = dev_priv->mmio_virt;
    110 	memcpy_fromio(bounce, &fifo_mem[SVGA_FIFO_3D_CAPS], size);
    111 
    112 	ret = copy_to_user(buffer, bounce, size);
    113 	if (ret)
    114 		ret = -EFAULT;
    115 	vfree(bounce);
    116 
    117 	if (unlikely(ret != 0))
    118 		DRM_ERROR("Failed to report 3D caps info.\n");
    119 
    120 	return ret;
    121 }
    122 
    123 int vmw_present_ioctl(struct drm_device *dev, void *data,
    124 		      struct drm_file *file_priv)
    125 {
    126 	struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile;
    127 	struct vmw_private *dev_priv = vmw_priv(dev);
    128 	struct drm_vmw_present_arg *arg =
    129 		(struct drm_vmw_present_arg *)data;
    130 	struct vmw_surface *surface;
    131 	struct vmw_master *vmaster = vmw_master(file_priv->master);
    132 	struct drm_vmw_rect __user *clips_ptr;
    133 	struct drm_vmw_rect *clips = NULL;
    134 	struct drm_mode_object *obj;
    135 	struct vmw_framebuffer *vfb;
    136 	struct vmw_resource *res;
    137 	uint32_t num_clips;
    138 	int ret;
    139 
    140 	num_clips = arg->num_clips;
    141 	clips_ptr = (struct drm_vmw_rect *)(unsigned long)arg->clips_ptr;
    142 
    143 	if (unlikely(num_clips == 0))
    144 		return 0;
    145 
    146 	if (clips_ptr == NULL) {
    147 		DRM_ERROR("Variable clips_ptr must be specified.\n");
    148 		ret = -EINVAL;
    149 		goto out_clips;
    150 	}
    151 
    152 	clips = kcalloc(num_clips, sizeof(*clips), GFP_KERNEL);
    153 	if (clips == NULL) {
    154 		DRM_ERROR("Failed to allocate clip rect list.\n");
    155 		ret = -ENOMEM;
    156 		goto out_clips;
    157 	}
    158 
    159 	ret = copy_from_user(clips, clips_ptr, num_clips * sizeof(*clips));
    160 	if (ret) {
    161 		DRM_ERROR("Failed to copy clip rects from userspace.\n");
    162 		ret = -EFAULT;
    163 		goto out_no_copy;
    164 	}
    165 
    166 	ret = mutex_lock_interruptible(&dev->mode_config.mutex);
    167 	if (unlikely(ret != 0)) {
    168 		ret = -ERESTARTSYS;
    169 		goto out_no_mode_mutex;
    170 	}
    171 
    172 	obj = drm_mode_object_find(dev, arg->fb_id, DRM_MODE_OBJECT_FB);
    173 	if (!obj) {
    174 		DRM_ERROR("Invalid framebuffer id.\n");
    175 		ret = -EINVAL;
    176 		goto out_no_fb;
    177 	}
    178 	vfb = vmw_framebuffer_to_vfb(obj_to_fb(obj));
    179 
    180 	ret = ttm_read_lock(&vmaster->lock, true);
    181 	if (unlikely(ret != 0))
    182 		goto out_no_ttm_lock;
    183 
    184 	ret = vmw_user_resource_lookup_handle(dev_priv, tfile, arg->sid,
    185 					      user_surface_converter,
    186 					      &res);
    187 	if (ret)
    188 		goto out_no_surface;
    189 
    190 	surface = vmw_res_to_srf(res);
    191 	ret = vmw_kms_present(dev_priv, file_priv,
    192 			      vfb, surface, arg->sid,
    193 			      arg->dest_x, arg->dest_y,
    194 			      clips, num_clips);
    195 
    196 	/* vmw_user_surface_lookup takes one ref so does new_fb */
    197 	vmw_surface_unreference(&surface);
    198 
    199 out_no_surface:
    200 	ttm_read_unlock(&vmaster->lock);
    201 out_no_ttm_lock:
    202 out_no_fb:
    203 	mutex_unlock(&dev->mode_config.mutex);
    204 out_no_mode_mutex:
    205 out_no_copy:
    206 	kfree(clips);
    207 out_clips:
    208 	return ret;
    209 }
    210 
    211 int vmw_present_readback_ioctl(struct drm_device *dev, void *data,
    212 			       struct drm_file *file_priv)
    213 {
    214 	struct vmw_private *dev_priv = vmw_priv(dev);
    215 	struct drm_vmw_present_readback_arg *arg =
    216 		(struct drm_vmw_present_readback_arg *)data;
    217 	struct drm_vmw_fence_rep __user *user_fence_rep =
    218 		(struct drm_vmw_fence_rep __user *)
    219 		(unsigned long)arg->fence_rep;
    220 	struct vmw_master *vmaster = vmw_master(file_priv->master);
    221 	struct drm_vmw_rect __user *clips_ptr;
    222 	struct drm_vmw_rect *clips = NULL;
    223 	struct drm_mode_object *obj;
    224 	struct vmw_framebuffer *vfb;
    225 	uint32_t num_clips;
    226 	int ret;
    227 
    228 	num_clips = arg->num_clips;
    229 	clips_ptr = (struct drm_vmw_rect *)(unsigned long)arg->clips_ptr;
    230 
    231 	if (unlikely(num_clips == 0))
    232 		return 0;
    233 
    234 	if (clips_ptr == NULL) {
    235 		DRM_ERROR("Argument clips_ptr must be specified.\n");
    236 		ret = -EINVAL;
    237 		goto out_clips;
    238 	}
    239 
    240 	clips = kcalloc(num_clips, sizeof(*clips), GFP_KERNEL);
    241 	if (clips == NULL) {
    242 		DRM_ERROR("Failed to allocate clip rect list.\n");
    243 		ret = -ENOMEM;
    244 		goto out_clips;
    245 	}
    246 
    247 	ret = copy_from_user(clips, clips_ptr, num_clips * sizeof(*clips));
    248 	if (ret) {
    249 		DRM_ERROR("Failed to copy clip rects from userspace.\n");
    250 		ret = -EFAULT;
    251 		goto out_no_copy;
    252 	}
    253 
    254 	ret = mutex_lock_interruptible(&dev->mode_config.mutex);
    255 	if (unlikely(ret != 0)) {
    256 		ret = -ERESTARTSYS;
    257 		goto out_no_mode_mutex;
    258 	}
    259 
    260 	obj = drm_mode_object_find(dev, arg->fb_id, DRM_MODE_OBJECT_FB);
    261 	if (!obj) {
    262 		DRM_ERROR("Invalid framebuffer id.\n");
    263 		ret = -EINVAL;
    264 		goto out_no_fb;
    265 	}
    266 
    267 	vfb = vmw_framebuffer_to_vfb(obj_to_fb(obj));
    268 	if (!vfb->dmabuf) {
    269 		DRM_ERROR("Framebuffer not dmabuf backed.\n");
    270 		ret = -EINVAL;
    271 		goto out_no_fb;
    272 	}
    273 
    274 	ret = ttm_read_lock(&vmaster->lock, true);
    275 	if (unlikely(ret != 0))
    276 		goto out_no_ttm_lock;
    277 
    278 	ret = vmw_kms_readback(dev_priv, file_priv,
    279 			       vfb, user_fence_rep,
    280 			       clips, num_clips);
    281 
    282 	ttm_read_unlock(&vmaster->lock);
    283 out_no_ttm_lock:
    284 out_no_fb:
    285 	mutex_unlock(&dev->mode_config.mutex);
    286 out_no_mode_mutex:
    287 out_no_copy:
    288 	kfree(clips);
    289 out_clips:
    290 	return ret;
    291 }
    292 
    293 
    294 /**
    295  * vmw_fops_poll - wrapper around the drm_poll function
    296  *
    297  * @filp: See the linux fops poll documentation.
    298  * @wait: See the linux fops poll documentation.
    299  *
    300  * Wrapper around the drm_poll function that makes sure the device is
    301  * processing the fifo if drm_poll decides to wait.
    302  */
    303 unsigned int vmw_fops_poll(struct file *filp, struct poll_table_struct *wait)
    304 {
    305 	struct drm_file *file_priv = filp->private_data;
    306 	struct vmw_private *dev_priv =
    307 		vmw_priv(file_priv->minor->dev);
    308 
    309 	vmw_fifo_ping_host(dev_priv, SVGA_SYNC_GENERIC);
    310 	return drm_poll(filp, wait);
    311 }
    312 
    313 
    314 /**
    315  * vmw_fops_read - wrapper around the drm_read function
    316  *
    317  * @filp: See the linux fops read documentation.
    318  * @buffer: See the linux fops read documentation.
    319  * @count: See the linux fops read documentation.
    320  * offset: See the linux fops read documentation.
    321  *
    322  * Wrapper around the drm_read function that makes sure the device is
    323  * processing the fifo if drm_read decides to wait.
    324  */
    325 ssize_t vmw_fops_read(struct file *filp, char __user *buffer,
    326 		      size_t count, loff_t *offset)
    327 {
    328 	struct drm_file *file_priv = filp->private_data;
    329 	struct vmw_private *dev_priv =
    330 		vmw_priv(file_priv->minor->dev);
    331 
    332 	vmw_fifo_ping_host(dev_priv, SVGA_SYNC_GENERIC);
    333 	return drm_read(filp, buffer, count, offset);
    334 }
    335