1fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz/**************************************************************************
2fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz *
3fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz * Copyright © 2009 VMware, Inc., Palo Alto, CA., USA
4fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz * All Rights Reserved.
5fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz *
6fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz * Permission is hereby granted, free of charge, to any person obtaining a
7fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz * copy of this software and associated documentation files (the
8fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz * "Software"), to deal in the Software without restriction, including
9fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz * without limitation the rights to use, copy, modify, merge, publish,
10fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz * distribute, sub license, and/or sell copies of the Software, and to
11fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz * permit persons to whom the Software is furnished to do so, subject to
12fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz * the following conditions:
13fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz *
14fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz * The above copyright notice and this permission notice (including the
15fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz * next paragraph) shall be included in all copies or substantial portions
16fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz * of the Software.
17fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz *
18fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
21fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
22fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
23fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
24fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz * USE OR OTHER DEALINGS IN THE SOFTWARE.
25fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz *
26fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz **************************************************************************/
27fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
28fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz#include "vmwgfx_drv.h"
29fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz#include "vmwgfx_drm.h"
302fcd5a73bfd5341876f9ea6b5adcc1dd814226d4Jakob Bornecrantz#include "vmwgfx_kms.h"
31fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
32fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantzint vmw_getparam_ioctl(struct drm_device *dev, void *data,
33fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz		       struct drm_file *file_priv)
34fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz{
35fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	struct vmw_private *dev_priv = vmw_priv(dev);
36fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	struct drm_vmw_getparam_arg *param =
37fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	    (struct drm_vmw_getparam_arg *)data;
38fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
39fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	switch (param->param) {
40fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	case DRM_VMW_PARAM_NUM_STREAMS:
41fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz		param->value = vmw_overlay_num_overlays(dev_priv);
42fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz		break;
43fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	case DRM_VMW_PARAM_NUM_FREE_STREAMS:
44fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz		param->value = vmw_overlay_num_free_overlays(dev_priv);
45fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz		break;
46fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	case DRM_VMW_PARAM_3D:
478e19a951774a16cf2626292ae06fd2b62630e67eJakob Bornecrantz		param->value = vmw_fifo_have_3d(dev_priv) ? 1 : 0;
48fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz		break;
49f77cef3db357aeea22d82a2aa4f0ef8fbae41d47Thomas Hellstrom	case DRM_VMW_PARAM_HW_CAPS:
50f77cef3db357aeea22d82a2aa4f0ef8fbae41d47Thomas Hellstrom		param->value = dev_priv->capabilities;
51f77cef3db357aeea22d82a2aa4f0ef8fbae41d47Thomas Hellstrom		break;
52f77cef3db357aeea22d82a2aa4f0ef8fbae41d47Thomas Hellstrom	case DRM_VMW_PARAM_FIFO_CAPS:
53f77cef3db357aeea22d82a2aa4f0ef8fbae41d47Thomas Hellstrom		param->value = dev_priv->fifo.capabilities;
54f77cef3db357aeea22d82a2aa4f0ef8fbae41d47Thomas Hellstrom		break;
5530f47fc85d524d25d63da9e6d77e55ab99c6cc4aThomas Hellstrom	case DRM_VMW_PARAM_MAX_FB_SIZE:
5630f47fc85d524d25d63da9e6d77e55ab99c6cc4aThomas Hellstrom		param->value = dev_priv->vram_size;
5730f47fc85d524d25d63da9e6d77e55ab99c6cc4aThomas Hellstrom		break;
58f63f6a59d3905ac73aeeb617b27ac31516549ed9Thomas Hellstrom	case DRM_VMW_PARAM_FIFO_HW_VERSION:
59f63f6a59d3905ac73aeeb617b27ac31516549ed9Thomas Hellstrom	{
60f63f6a59d3905ac73aeeb617b27ac31516549ed9Thomas Hellstrom		__le32 __iomem *fifo_mem = dev_priv->mmio_virt;
61ebd4c6f6261c96d1cf9f004965384d57c4202fd6Thomas Hellstrom		const struct vmw_fifo_state *fifo = &dev_priv->fifo;
62f63f6a59d3905ac73aeeb617b27ac31516549ed9Thomas Hellstrom
63ebd4c6f6261c96d1cf9f004965384d57c4202fd6Thomas Hellstrom		param->value =
64ebd4c6f6261c96d1cf9f004965384d57c4202fd6Thomas Hellstrom			ioread32(fifo_mem +
65ebd4c6f6261c96d1cf9f004965384d57c4202fd6Thomas Hellstrom				 ((fifo->capabilities &
66ebd4c6f6261c96d1cf9f004965384d57c4202fd6Thomas Hellstrom				   SVGA_FIFO_CAP_3D_HWVERSION_REVISED) ?
67ebd4c6f6261c96d1cf9f004965384d57c4202fd6Thomas Hellstrom				  SVGA_FIFO_3D_HWVERSION_REVISED :
68ebd4c6f6261c96d1cf9f004965384d57c4202fd6Thomas Hellstrom				  SVGA_FIFO_3D_HWVERSION));
69f63f6a59d3905ac73aeeb617b27ac31516549ed9Thomas Hellstrom		break;
70f63f6a59d3905ac73aeeb617b27ac31516549ed9Thomas Hellstrom	}
71fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	default:
72fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz		DRM_ERROR("Illegal vmwgfx get param request: %d\n",
73fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz			  param->param);
74fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz		return -EINVAL;
75fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	}
76fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
77fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	return 0;
78fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz}
79f63f6a59d3905ac73aeeb617b27ac31516549ed9Thomas Hellstrom
80f63f6a59d3905ac73aeeb617b27ac31516549ed9Thomas Hellstrom
81f63f6a59d3905ac73aeeb617b27ac31516549ed9Thomas Hellstromint vmw_get_cap_3d_ioctl(struct drm_device *dev, void *data,
82f63f6a59d3905ac73aeeb617b27ac31516549ed9Thomas Hellstrom			 struct drm_file *file_priv)
83f63f6a59d3905ac73aeeb617b27ac31516549ed9Thomas Hellstrom{
84f63f6a59d3905ac73aeeb617b27ac31516549ed9Thomas Hellstrom	struct drm_vmw_get_3d_cap_arg *arg =
85f63f6a59d3905ac73aeeb617b27ac31516549ed9Thomas Hellstrom		(struct drm_vmw_get_3d_cap_arg *) data;
86f63f6a59d3905ac73aeeb617b27ac31516549ed9Thomas Hellstrom	struct vmw_private *dev_priv = vmw_priv(dev);
87f63f6a59d3905ac73aeeb617b27ac31516549ed9Thomas Hellstrom	uint32_t size;
88f63f6a59d3905ac73aeeb617b27ac31516549ed9Thomas Hellstrom	__le32 __iomem *fifo_mem;
89f63f6a59d3905ac73aeeb617b27ac31516549ed9Thomas Hellstrom	void __user *buffer = (void __user *)((unsigned long)(arg->buffer));
90f63f6a59d3905ac73aeeb617b27ac31516549ed9Thomas Hellstrom	void *bounce;
91f63f6a59d3905ac73aeeb617b27ac31516549ed9Thomas Hellstrom	int ret;
92f63f6a59d3905ac73aeeb617b27ac31516549ed9Thomas Hellstrom
93f63f6a59d3905ac73aeeb617b27ac31516549ed9Thomas Hellstrom	if (unlikely(arg->pad64 != 0)) {
94f63f6a59d3905ac73aeeb617b27ac31516549ed9Thomas Hellstrom		DRM_ERROR("Illegal GET_3D_CAP argument.\n");
95f63f6a59d3905ac73aeeb617b27ac31516549ed9Thomas Hellstrom		return -EINVAL;
96f63f6a59d3905ac73aeeb617b27ac31516549ed9Thomas Hellstrom	}
97f63f6a59d3905ac73aeeb617b27ac31516549ed9Thomas Hellstrom
98f63f6a59d3905ac73aeeb617b27ac31516549ed9Thomas Hellstrom	size = (SVGA_FIFO_3D_CAPS_LAST - SVGA_FIFO_3D_CAPS + 1) << 2;
99f63f6a59d3905ac73aeeb617b27ac31516549ed9Thomas Hellstrom
100f63f6a59d3905ac73aeeb617b27ac31516549ed9Thomas Hellstrom	if (arg->max_size < size)
101f63f6a59d3905ac73aeeb617b27ac31516549ed9Thomas Hellstrom		size = arg->max_size;
102f63f6a59d3905ac73aeeb617b27ac31516549ed9Thomas Hellstrom
103f63f6a59d3905ac73aeeb617b27ac31516549ed9Thomas Hellstrom	bounce = vmalloc(size);
104f63f6a59d3905ac73aeeb617b27ac31516549ed9Thomas Hellstrom	if (unlikely(bounce == NULL)) {
105f63f6a59d3905ac73aeeb617b27ac31516549ed9Thomas Hellstrom		DRM_ERROR("Failed to allocate bounce buffer for 3D caps.\n");
106f63f6a59d3905ac73aeeb617b27ac31516549ed9Thomas Hellstrom		return -ENOMEM;
107f63f6a59d3905ac73aeeb617b27ac31516549ed9Thomas Hellstrom	}
108f63f6a59d3905ac73aeeb617b27ac31516549ed9Thomas Hellstrom
109f63f6a59d3905ac73aeeb617b27ac31516549ed9Thomas Hellstrom	fifo_mem = dev_priv->mmio_virt;
110f63f6a59d3905ac73aeeb617b27ac31516549ed9Thomas Hellstrom	memcpy_fromio(bounce, &fifo_mem[SVGA_FIFO_3D_CAPS], size);
111f63f6a59d3905ac73aeeb617b27ac31516549ed9Thomas Hellstrom
112f63f6a59d3905ac73aeeb617b27ac31516549ed9Thomas Hellstrom	ret = copy_to_user(buffer, bounce, size);
113f63f6a59d3905ac73aeeb617b27ac31516549ed9Thomas Hellstrom	vfree(bounce);
114f63f6a59d3905ac73aeeb617b27ac31516549ed9Thomas Hellstrom
115f63f6a59d3905ac73aeeb617b27ac31516549ed9Thomas Hellstrom	if (unlikely(ret != 0))
116f63f6a59d3905ac73aeeb617b27ac31516549ed9Thomas Hellstrom		DRM_ERROR("Failed to report 3D caps info.\n");
117f63f6a59d3905ac73aeeb617b27ac31516549ed9Thomas Hellstrom
118f63f6a59d3905ac73aeeb617b27ac31516549ed9Thomas Hellstrom	return ret;
119f63f6a59d3905ac73aeeb617b27ac31516549ed9Thomas Hellstrom}
1202fcd5a73bfd5341876f9ea6b5adcc1dd814226d4Jakob Bornecrantz
1212fcd5a73bfd5341876f9ea6b5adcc1dd814226d4Jakob Bornecrantzint vmw_present_ioctl(struct drm_device *dev, void *data,
1222fcd5a73bfd5341876f9ea6b5adcc1dd814226d4Jakob Bornecrantz		      struct drm_file *file_priv)
1232fcd5a73bfd5341876f9ea6b5adcc1dd814226d4Jakob Bornecrantz{
1242fcd5a73bfd5341876f9ea6b5adcc1dd814226d4Jakob Bornecrantz	struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile;
1252fcd5a73bfd5341876f9ea6b5adcc1dd814226d4Jakob Bornecrantz	struct vmw_private *dev_priv = vmw_priv(dev);
1262fcd5a73bfd5341876f9ea6b5adcc1dd814226d4Jakob Bornecrantz	struct drm_vmw_present_arg *arg =
1272fcd5a73bfd5341876f9ea6b5adcc1dd814226d4Jakob Bornecrantz		(struct drm_vmw_present_arg *)data;
1282fcd5a73bfd5341876f9ea6b5adcc1dd814226d4Jakob Bornecrantz	struct vmw_surface *surface;
1292fcd5a73bfd5341876f9ea6b5adcc1dd814226d4Jakob Bornecrantz	struct vmw_master *vmaster = vmw_master(file_priv->master);
1302fcd5a73bfd5341876f9ea6b5adcc1dd814226d4Jakob Bornecrantz	struct drm_vmw_rect __user *clips_ptr;
1312fcd5a73bfd5341876f9ea6b5adcc1dd814226d4Jakob Bornecrantz	struct drm_vmw_rect *clips = NULL;
1322fcd5a73bfd5341876f9ea6b5adcc1dd814226d4Jakob Bornecrantz	struct drm_mode_object *obj;
1332fcd5a73bfd5341876f9ea6b5adcc1dd814226d4Jakob Bornecrantz	struct vmw_framebuffer *vfb;
1342fcd5a73bfd5341876f9ea6b5adcc1dd814226d4Jakob Bornecrantz	uint32_t num_clips;
1352fcd5a73bfd5341876f9ea6b5adcc1dd814226d4Jakob Bornecrantz	int ret;
1362fcd5a73bfd5341876f9ea6b5adcc1dd814226d4Jakob Bornecrantz
1372fcd5a73bfd5341876f9ea6b5adcc1dd814226d4Jakob Bornecrantz	num_clips = arg->num_clips;
1382fcd5a73bfd5341876f9ea6b5adcc1dd814226d4Jakob Bornecrantz	clips_ptr = (struct drm_vmw_rect *)(unsigned long)arg->clips_ptr;
1392fcd5a73bfd5341876f9ea6b5adcc1dd814226d4Jakob Bornecrantz
1402fcd5a73bfd5341876f9ea6b5adcc1dd814226d4Jakob Bornecrantz	if (unlikely(num_clips == 0))
1412fcd5a73bfd5341876f9ea6b5adcc1dd814226d4Jakob Bornecrantz		return 0;
1422fcd5a73bfd5341876f9ea6b5adcc1dd814226d4Jakob Bornecrantz
1432fcd5a73bfd5341876f9ea6b5adcc1dd814226d4Jakob Bornecrantz	if (clips_ptr == NULL) {
1442fcd5a73bfd5341876f9ea6b5adcc1dd814226d4Jakob Bornecrantz		DRM_ERROR("Variable clips_ptr must be specified.\n");
1452fcd5a73bfd5341876f9ea6b5adcc1dd814226d4Jakob Bornecrantz		ret = -EINVAL;
1462fcd5a73bfd5341876f9ea6b5adcc1dd814226d4Jakob Bornecrantz		goto out_clips;
1472fcd5a73bfd5341876f9ea6b5adcc1dd814226d4Jakob Bornecrantz	}
1482fcd5a73bfd5341876f9ea6b5adcc1dd814226d4Jakob Bornecrantz
14924bb5a0ce39c51a2e2602c947f218a19e4b26d7dThomas Meyer	clips = kcalloc(num_clips, sizeof(*clips), GFP_KERNEL);
1502fcd5a73bfd5341876f9ea6b5adcc1dd814226d4Jakob Bornecrantz	if (clips == NULL) {
1512fcd5a73bfd5341876f9ea6b5adcc1dd814226d4Jakob Bornecrantz		DRM_ERROR("Failed to allocate clip rect list.\n");
1522fcd5a73bfd5341876f9ea6b5adcc1dd814226d4Jakob Bornecrantz		ret = -ENOMEM;
1532fcd5a73bfd5341876f9ea6b5adcc1dd814226d4Jakob Bornecrantz		goto out_clips;
1542fcd5a73bfd5341876f9ea6b5adcc1dd814226d4Jakob Bornecrantz	}
1552fcd5a73bfd5341876f9ea6b5adcc1dd814226d4Jakob Bornecrantz
1562fcd5a73bfd5341876f9ea6b5adcc1dd814226d4Jakob Bornecrantz	ret = copy_from_user(clips, clips_ptr, num_clips * sizeof(*clips));
1572fcd5a73bfd5341876f9ea6b5adcc1dd814226d4Jakob Bornecrantz	if (ret) {
1582fcd5a73bfd5341876f9ea6b5adcc1dd814226d4Jakob Bornecrantz		DRM_ERROR("Failed to copy clip rects from userspace.\n");
159d2c184fb10656f2a6d59fef76efb3a8b12fb6ed4Dan Carpenter		ret = -EFAULT;
1602fcd5a73bfd5341876f9ea6b5adcc1dd814226d4Jakob Bornecrantz		goto out_no_copy;
1612fcd5a73bfd5341876f9ea6b5adcc1dd814226d4Jakob Bornecrantz	}
1622fcd5a73bfd5341876f9ea6b5adcc1dd814226d4Jakob Bornecrantz
1632fcd5a73bfd5341876f9ea6b5adcc1dd814226d4Jakob Bornecrantz	ret = mutex_lock_interruptible(&dev->mode_config.mutex);
1642fcd5a73bfd5341876f9ea6b5adcc1dd814226d4Jakob Bornecrantz	if (unlikely(ret != 0)) {
1652fcd5a73bfd5341876f9ea6b5adcc1dd814226d4Jakob Bornecrantz		ret = -ERESTARTSYS;
1662fcd5a73bfd5341876f9ea6b5adcc1dd814226d4Jakob Bornecrantz		goto out_no_mode_mutex;
1672fcd5a73bfd5341876f9ea6b5adcc1dd814226d4Jakob Bornecrantz	}
1682fcd5a73bfd5341876f9ea6b5adcc1dd814226d4Jakob Bornecrantz
1692fcd5a73bfd5341876f9ea6b5adcc1dd814226d4Jakob Bornecrantz	obj = drm_mode_object_find(dev, arg->fb_id, DRM_MODE_OBJECT_FB);
1702fcd5a73bfd5341876f9ea6b5adcc1dd814226d4Jakob Bornecrantz	if (!obj) {
1712fcd5a73bfd5341876f9ea6b5adcc1dd814226d4Jakob Bornecrantz		DRM_ERROR("Invalid framebuffer id.\n");
1722fcd5a73bfd5341876f9ea6b5adcc1dd814226d4Jakob Bornecrantz		ret = -EINVAL;
1732fcd5a73bfd5341876f9ea6b5adcc1dd814226d4Jakob Bornecrantz		goto out_no_fb;
1742fcd5a73bfd5341876f9ea6b5adcc1dd814226d4Jakob Bornecrantz	}
1752fcd5a73bfd5341876f9ea6b5adcc1dd814226d4Jakob Bornecrantz	vfb = vmw_framebuffer_to_vfb(obj_to_fb(obj));
1762fcd5a73bfd5341876f9ea6b5adcc1dd814226d4Jakob Bornecrantz
1772fcd5a73bfd5341876f9ea6b5adcc1dd814226d4Jakob Bornecrantz	ret = ttm_read_lock(&vmaster->lock, true);
1782fcd5a73bfd5341876f9ea6b5adcc1dd814226d4Jakob Bornecrantz	if (unlikely(ret != 0))
1792fcd5a73bfd5341876f9ea6b5adcc1dd814226d4Jakob Bornecrantz		goto out_no_ttm_lock;
1802fcd5a73bfd5341876f9ea6b5adcc1dd814226d4Jakob Bornecrantz
1812fcd5a73bfd5341876f9ea6b5adcc1dd814226d4Jakob Bornecrantz	ret = vmw_user_surface_lookup_handle(dev_priv, tfile, arg->sid,
1822fcd5a73bfd5341876f9ea6b5adcc1dd814226d4Jakob Bornecrantz					     &surface);
1832fcd5a73bfd5341876f9ea6b5adcc1dd814226d4Jakob Bornecrantz	if (ret)
1842fcd5a73bfd5341876f9ea6b5adcc1dd814226d4Jakob Bornecrantz		goto out_no_surface;
1852fcd5a73bfd5341876f9ea6b5adcc1dd814226d4Jakob Bornecrantz
1862fcd5a73bfd5341876f9ea6b5adcc1dd814226d4Jakob Bornecrantz	ret = vmw_kms_present(dev_priv, file_priv,
1872fcd5a73bfd5341876f9ea6b5adcc1dd814226d4Jakob Bornecrantz			      vfb, surface, arg->sid,
1882fcd5a73bfd5341876f9ea6b5adcc1dd814226d4Jakob Bornecrantz			      arg->dest_x, arg->dest_y,
1892fcd5a73bfd5341876f9ea6b5adcc1dd814226d4Jakob Bornecrantz			      clips, num_clips);
1902fcd5a73bfd5341876f9ea6b5adcc1dd814226d4Jakob Bornecrantz
1912fcd5a73bfd5341876f9ea6b5adcc1dd814226d4Jakob Bornecrantz	/* vmw_user_surface_lookup takes one ref so does new_fb */
1922fcd5a73bfd5341876f9ea6b5adcc1dd814226d4Jakob Bornecrantz	vmw_surface_unreference(&surface);
1932fcd5a73bfd5341876f9ea6b5adcc1dd814226d4Jakob Bornecrantz
1942fcd5a73bfd5341876f9ea6b5adcc1dd814226d4Jakob Bornecrantzout_no_surface:
1952fcd5a73bfd5341876f9ea6b5adcc1dd814226d4Jakob Bornecrantz	ttm_read_unlock(&vmaster->lock);
1962fcd5a73bfd5341876f9ea6b5adcc1dd814226d4Jakob Bornecrantzout_no_ttm_lock:
1972fcd5a73bfd5341876f9ea6b5adcc1dd814226d4Jakob Bornecrantzout_no_fb:
1982fcd5a73bfd5341876f9ea6b5adcc1dd814226d4Jakob Bornecrantz	mutex_unlock(&dev->mode_config.mutex);
1992fcd5a73bfd5341876f9ea6b5adcc1dd814226d4Jakob Bornecrantzout_no_mode_mutex:
2002fcd5a73bfd5341876f9ea6b5adcc1dd814226d4Jakob Bornecrantzout_no_copy:
2012fcd5a73bfd5341876f9ea6b5adcc1dd814226d4Jakob Bornecrantz	kfree(clips);
2022fcd5a73bfd5341876f9ea6b5adcc1dd814226d4Jakob Bornecrantzout_clips:
2032fcd5a73bfd5341876f9ea6b5adcc1dd814226d4Jakob Bornecrantz	return ret;
2042fcd5a73bfd5341876f9ea6b5adcc1dd814226d4Jakob Bornecrantz}
2052fcd5a73bfd5341876f9ea6b5adcc1dd814226d4Jakob Bornecrantz
2062fcd5a73bfd5341876f9ea6b5adcc1dd814226d4Jakob Bornecrantzint vmw_present_readback_ioctl(struct drm_device *dev, void *data,
2072fcd5a73bfd5341876f9ea6b5adcc1dd814226d4Jakob Bornecrantz			       struct drm_file *file_priv)
2082fcd5a73bfd5341876f9ea6b5adcc1dd814226d4Jakob Bornecrantz{
2092fcd5a73bfd5341876f9ea6b5adcc1dd814226d4Jakob Bornecrantz	struct vmw_private *dev_priv = vmw_priv(dev);
2102fcd5a73bfd5341876f9ea6b5adcc1dd814226d4Jakob Bornecrantz	struct drm_vmw_present_readback_arg *arg =
2112fcd5a73bfd5341876f9ea6b5adcc1dd814226d4Jakob Bornecrantz		(struct drm_vmw_present_readback_arg *)data;
2122fcd5a73bfd5341876f9ea6b5adcc1dd814226d4Jakob Bornecrantz	struct drm_vmw_fence_rep __user *user_fence_rep =
2132fcd5a73bfd5341876f9ea6b5adcc1dd814226d4Jakob Bornecrantz		(struct drm_vmw_fence_rep __user *)
2142fcd5a73bfd5341876f9ea6b5adcc1dd814226d4Jakob Bornecrantz		(unsigned long)arg->fence_rep;
2152fcd5a73bfd5341876f9ea6b5adcc1dd814226d4Jakob Bornecrantz	struct vmw_master *vmaster = vmw_master(file_priv->master);
2162fcd5a73bfd5341876f9ea6b5adcc1dd814226d4Jakob Bornecrantz	struct drm_vmw_rect __user *clips_ptr;
2172fcd5a73bfd5341876f9ea6b5adcc1dd814226d4Jakob Bornecrantz	struct drm_vmw_rect *clips = NULL;
2182fcd5a73bfd5341876f9ea6b5adcc1dd814226d4Jakob Bornecrantz	struct drm_mode_object *obj;
2192fcd5a73bfd5341876f9ea6b5adcc1dd814226d4Jakob Bornecrantz	struct vmw_framebuffer *vfb;
2202fcd5a73bfd5341876f9ea6b5adcc1dd814226d4Jakob Bornecrantz	uint32_t num_clips;
2212fcd5a73bfd5341876f9ea6b5adcc1dd814226d4Jakob Bornecrantz	int ret;
2222fcd5a73bfd5341876f9ea6b5adcc1dd814226d4Jakob Bornecrantz
2232fcd5a73bfd5341876f9ea6b5adcc1dd814226d4Jakob Bornecrantz	num_clips = arg->num_clips;
2242fcd5a73bfd5341876f9ea6b5adcc1dd814226d4Jakob Bornecrantz	clips_ptr = (struct drm_vmw_rect *)(unsigned long)arg->clips_ptr;
2252fcd5a73bfd5341876f9ea6b5adcc1dd814226d4Jakob Bornecrantz
2262fcd5a73bfd5341876f9ea6b5adcc1dd814226d4Jakob Bornecrantz	if (unlikely(num_clips == 0))
2272fcd5a73bfd5341876f9ea6b5adcc1dd814226d4Jakob Bornecrantz		return 0;
2282fcd5a73bfd5341876f9ea6b5adcc1dd814226d4Jakob Bornecrantz
2292fcd5a73bfd5341876f9ea6b5adcc1dd814226d4Jakob Bornecrantz	if (clips_ptr == NULL) {
2302fcd5a73bfd5341876f9ea6b5adcc1dd814226d4Jakob Bornecrantz		DRM_ERROR("Argument clips_ptr must be specified.\n");
2312fcd5a73bfd5341876f9ea6b5adcc1dd814226d4Jakob Bornecrantz		ret = -EINVAL;
2322fcd5a73bfd5341876f9ea6b5adcc1dd814226d4Jakob Bornecrantz		goto out_clips;
2332fcd5a73bfd5341876f9ea6b5adcc1dd814226d4Jakob Bornecrantz	}
2342fcd5a73bfd5341876f9ea6b5adcc1dd814226d4Jakob Bornecrantz
23524bb5a0ce39c51a2e2602c947f218a19e4b26d7dThomas Meyer	clips = kcalloc(num_clips, sizeof(*clips), GFP_KERNEL);
2362fcd5a73bfd5341876f9ea6b5adcc1dd814226d4Jakob Bornecrantz	if (clips == NULL) {
2372fcd5a73bfd5341876f9ea6b5adcc1dd814226d4Jakob Bornecrantz		DRM_ERROR("Failed to allocate clip rect list.\n");
2382fcd5a73bfd5341876f9ea6b5adcc1dd814226d4Jakob Bornecrantz		ret = -ENOMEM;
2392fcd5a73bfd5341876f9ea6b5adcc1dd814226d4Jakob Bornecrantz		goto out_clips;
2402fcd5a73bfd5341876f9ea6b5adcc1dd814226d4Jakob Bornecrantz	}
2412fcd5a73bfd5341876f9ea6b5adcc1dd814226d4Jakob Bornecrantz
2422fcd5a73bfd5341876f9ea6b5adcc1dd814226d4Jakob Bornecrantz	ret = copy_from_user(clips, clips_ptr, num_clips * sizeof(*clips));
2432fcd5a73bfd5341876f9ea6b5adcc1dd814226d4Jakob Bornecrantz	if (ret) {
2442fcd5a73bfd5341876f9ea6b5adcc1dd814226d4Jakob Bornecrantz		DRM_ERROR("Failed to copy clip rects from userspace.\n");
245d2c184fb10656f2a6d59fef76efb3a8b12fb6ed4Dan Carpenter		ret = -EFAULT;
2462fcd5a73bfd5341876f9ea6b5adcc1dd814226d4Jakob Bornecrantz		goto out_no_copy;
2472fcd5a73bfd5341876f9ea6b5adcc1dd814226d4Jakob Bornecrantz	}
2482fcd5a73bfd5341876f9ea6b5adcc1dd814226d4Jakob Bornecrantz
2492fcd5a73bfd5341876f9ea6b5adcc1dd814226d4Jakob Bornecrantz	ret = mutex_lock_interruptible(&dev->mode_config.mutex);
2502fcd5a73bfd5341876f9ea6b5adcc1dd814226d4Jakob Bornecrantz	if (unlikely(ret != 0)) {
2512fcd5a73bfd5341876f9ea6b5adcc1dd814226d4Jakob Bornecrantz		ret = -ERESTARTSYS;
2522fcd5a73bfd5341876f9ea6b5adcc1dd814226d4Jakob Bornecrantz		goto out_no_mode_mutex;
2532fcd5a73bfd5341876f9ea6b5adcc1dd814226d4Jakob Bornecrantz	}
2542fcd5a73bfd5341876f9ea6b5adcc1dd814226d4Jakob Bornecrantz
2552fcd5a73bfd5341876f9ea6b5adcc1dd814226d4Jakob Bornecrantz	obj = drm_mode_object_find(dev, arg->fb_id, DRM_MODE_OBJECT_FB);
2562fcd5a73bfd5341876f9ea6b5adcc1dd814226d4Jakob Bornecrantz	if (!obj) {
2572fcd5a73bfd5341876f9ea6b5adcc1dd814226d4Jakob Bornecrantz		DRM_ERROR("Invalid framebuffer id.\n");
2582fcd5a73bfd5341876f9ea6b5adcc1dd814226d4Jakob Bornecrantz		ret = -EINVAL;
2592fcd5a73bfd5341876f9ea6b5adcc1dd814226d4Jakob Bornecrantz		goto out_no_fb;
2602fcd5a73bfd5341876f9ea6b5adcc1dd814226d4Jakob Bornecrantz	}
2612fcd5a73bfd5341876f9ea6b5adcc1dd814226d4Jakob Bornecrantz
2622fcd5a73bfd5341876f9ea6b5adcc1dd814226d4Jakob Bornecrantz	vfb = vmw_framebuffer_to_vfb(obj_to_fb(obj));
2632fcd5a73bfd5341876f9ea6b5adcc1dd814226d4Jakob Bornecrantz	if (!vfb->dmabuf) {
2642fcd5a73bfd5341876f9ea6b5adcc1dd814226d4Jakob Bornecrantz		DRM_ERROR("Framebuffer not dmabuf backed.\n");
2652fcd5a73bfd5341876f9ea6b5adcc1dd814226d4Jakob Bornecrantz		ret = -EINVAL;
2662fcd5a73bfd5341876f9ea6b5adcc1dd814226d4Jakob Bornecrantz		goto out_no_fb;
2672fcd5a73bfd5341876f9ea6b5adcc1dd814226d4Jakob Bornecrantz	}
2682fcd5a73bfd5341876f9ea6b5adcc1dd814226d4Jakob Bornecrantz
2692fcd5a73bfd5341876f9ea6b5adcc1dd814226d4Jakob Bornecrantz	ret = ttm_read_lock(&vmaster->lock, true);
2702fcd5a73bfd5341876f9ea6b5adcc1dd814226d4Jakob Bornecrantz	if (unlikely(ret != 0))
2712fcd5a73bfd5341876f9ea6b5adcc1dd814226d4Jakob Bornecrantz		goto out_no_ttm_lock;
2722fcd5a73bfd5341876f9ea6b5adcc1dd814226d4Jakob Bornecrantz
2732fcd5a73bfd5341876f9ea6b5adcc1dd814226d4Jakob Bornecrantz	ret = vmw_kms_readback(dev_priv, file_priv,
2742fcd5a73bfd5341876f9ea6b5adcc1dd814226d4Jakob Bornecrantz			       vfb, user_fence_rep,
2752fcd5a73bfd5341876f9ea6b5adcc1dd814226d4Jakob Bornecrantz			       clips, num_clips);
2762fcd5a73bfd5341876f9ea6b5adcc1dd814226d4Jakob Bornecrantz
2772fcd5a73bfd5341876f9ea6b5adcc1dd814226d4Jakob Bornecrantz	ttm_read_unlock(&vmaster->lock);
2782fcd5a73bfd5341876f9ea6b5adcc1dd814226d4Jakob Bornecrantzout_no_ttm_lock:
2792fcd5a73bfd5341876f9ea6b5adcc1dd814226d4Jakob Bornecrantzout_no_fb:
2802fcd5a73bfd5341876f9ea6b5adcc1dd814226d4Jakob Bornecrantz	mutex_unlock(&dev->mode_config.mutex);
2812fcd5a73bfd5341876f9ea6b5adcc1dd814226d4Jakob Bornecrantzout_no_mode_mutex:
2822fcd5a73bfd5341876f9ea6b5adcc1dd814226d4Jakob Bornecrantzout_no_copy:
2832fcd5a73bfd5341876f9ea6b5adcc1dd814226d4Jakob Bornecrantz	kfree(clips);
2842fcd5a73bfd5341876f9ea6b5adcc1dd814226d4Jakob Bornecrantzout_clips:
2852fcd5a73bfd5341876f9ea6b5adcc1dd814226d4Jakob Bornecrantz	return ret;
2862fcd5a73bfd5341876f9ea6b5adcc1dd814226d4Jakob Bornecrantz}
2875438ae88d098c086cfb94be5327c49a04fc6bfd7Thomas Hellstrom
2885438ae88d098c086cfb94be5327c49a04fc6bfd7Thomas Hellstrom
2895438ae88d098c086cfb94be5327c49a04fc6bfd7Thomas Hellstrom/**
2905438ae88d098c086cfb94be5327c49a04fc6bfd7Thomas Hellstrom * vmw_fops_poll - wrapper around the drm_poll function
2915438ae88d098c086cfb94be5327c49a04fc6bfd7Thomas Hellstrom *
2925438ae88d098c086cfb94be5327c49a04fc6bfd7Thomas Hellstrom * @filp: See the linux fops poll documentation.
2935438ae88d098c086cfb94be5327c49a04fc6bfd7Thomas Hellstrom * @wait: See the linux fops poll documentation.
2945438ae88d098c086cfb94be5327c49a04fc6bfd7Thomas Hellstrom *
2955438ae88d098c086cfb94be5327c49a04fc6bfd7Thomas Hellstrom * Wrapper around the drm_poll function that makes sure the device is
2965438ae88d098c086cfb94be5327c49a04fc6bfd7Thomas Hellstrom * processing the fifo if drm_poll decides to wait.
2975438ae88d098c086cfb94be5327c49a04fc6bfd7Thomas Hellstrom */
2985438ae88d098c086cfb94be5327c49a04fc6bfd7Thomas Hellstromunsigned int vmw_fops_poll(struct file *filp, struct poll_table_struct *wait)
2995438ae88d098c086cfb94be5327c49a04fc6bfd7Thomas Hellstrom{
3005438ae88d098c086cfb94be5327c49a04fc6bfd7Thomas Hellstrom	struct drm_file *file_priv = filp->private_data;
3015438ae88d098c086cfb94be5327c49a04fc6bfd7Thomas Hellstrom	struct vmw_private *dev_priv =
3025438ae88d098c086cfb94be5327c49a04fc6bfd7Thomas Hellstrom		vmw_priv(file_priv->minor->dev);
3035438ae88d098c086cfb94be5327c49a04fc6bfd7Thomas Hellstrom
3045438ae88d098c086cfb94be5327c49a04fc6bfd7Thomas Hellstrom	vmw_fifo_ping_host(dev_priv, SVGA_SYNC_GENERIC);
3055438ae88d098c086cfb94be5327c49a04fc6bfd7Thomas Hellstrom	return drm_poll(filp, wait);
3065438ae88d098c086cfb94be5327c49a04fc6bfd7Thomas Hellstrom}
3075438ae88d098c086cfb94be5327c49a04fc6bfd7Thomas Hellstrom
3085438ae88d098c086cfb94be5327c49a04fc6bfd7Thomas Hellstrom
3095438ae88d098c086cfb94be5327c49a04fc6bfd7Thomas Hellstrom/**
3105438ae88d098c086cfb94be5327c49a04fc6bfd7Thomas Hellstrom * vmw_fops_read - wrapper around the drm_read function
3115438ae88d098c086cfb94be5327c49a04fc6bfd7Thomas Hellstrom *
3125438ae88d098c086cfb94be5327c49a04fc6bfd7Thomas Hellstrom * @filp: See the linux fops read documentation.
3135438ae88d098c086cfb94be5327c49a04fc6bfd7Thomas Hellstrom * @buffer: See the linux fops read documentation.
3145438ae88d098c086cfb94be5327c49a04fc6bfd7Thomas Hellstrom * @count: See the linux fops read documentation.
3155438ae88d098c086cfb94be5327c49a04fc6bfd7Thomas Hellstrom * offset: See the linux fops read documentation.
3165438ae88d098c086cfb94be5327c49a04fc6bfd7Thomas Hellstrom *
3175438ae88d098c086cfb94be5327c49a04fc6bfd7Thomas Hellstrom * Wrapper around the drm_read function that makes sure the device is
3185438ae88d098c086cfb94be5327c49a04fc6bfd7Thomas Hellstrom * processing the fifo if drm_read decides to wait.
3195438ae88d098c086cfb94be5327c49a04fc6bfd7Thomas Hellstrom */
3205438ae88d098c086cfb94be5327c49a04fc6bfd7Thomas Hellstromssize_t vmw_fops_read(struct file *filp, char __user *buffer,
3215438ae88d098c086cfb94be5327c49a04fc6bfd7Thomas Hellstrom		      size_t count, loff_t *offset)
3225438ae88d098c086cfb94be5327c49a04fc6bfd7Thomas Hellstrom{
3235438ae88d098c086cfb94be5327c49a04fc6bfd7Thomas Hellstrom	struct drm_file *file_priv = filp->private_data;
3245438ae88d098c086cfb94be5327c49a04fc6bfd7Thomas Hellstrom	struct vmw_private *dev_priv =
3255438ae88d098c086cfb94be5327c49a04fc6bfd7Thomas Hellstrom		vmw_priv(file_priv->minor->dev);
3265438ae88d098c086cfb94be5327c49a04fc6bfd7Thomas Hellstrom
3275438ae88d098c086cfb94be5327c49a04fc6bfd7Thomas Hellstrom	vmw_fifo_ping_host(dev_priv, SVGA_SYNC_GENERIC);
3285438ae88d098c086cfb94be5327c49a04fc6bfd7Thomas Hellstrom	return drm_read(filp, buffer, count, offset);
3295438ae88d098c086cfb94be5327c49a04fc6bfd7Thomas Hellstrom}
330