1dff96888SDirk Hohndel (VMware) // SPDX-License-Identifier: GPL-2.0 OR MIT
2fb1d9738SJakob Bornecrantz /**************************************************************************
3fb1d9738SJakob Bornecrantz  *
4*23b0e695SZack Rusin  * Copyright 2009-2022 VMware, Inc., Palo Alto, CA., USA
5fb1d9738SJakob Bornecrantz  *
6fb1d9738SJakob Bornecrantz  * Permission is hereby granted, free of charge, to any person obtaining a
7fb1d9738SJakob Bornecrantz  * copy of this software and associated documentation files (the
8fb1d9738SJakob Bornecrantz  * "Software"), to deal in the Software without restriction, including
9fb1d9738SJakob Bornecrantz  * without limitation the rights to use, copy, modify, merge, publish,
10fb1d9738SJakob Bornecrantz  * distribute, sub license, and/or sell copies of the Software, and to
11fb1d9738SJakob Bornecrantz  * permit persons to whom the Software is furnished to do so, subject to
12fb1d9738SJakob Bornecrantz  * the following conditions:
13fb1d9738SJakob Bornecrantz  *
14fb1d9738SJakob Bornecrantz  * The above copyright notice and this permission notice (including the
15fb1d9738SJakob Bornecrantz  * next paragraph) shall be included in all copies or substantial portions
16fb1d9738SJakob Bornecrantz  * of the Software.
17fb1d9738SJakob Bornecrantz  *
18fb1d9738SJakob Bornecrantz  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19fb1d9738SJakob Bornecrantz  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20fb1d9738SJakob Bornecrantz  * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
21fb1d9738SJakob Bornecrantz  * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
22fb1d9738SJakob Bornecrantz  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
23fb1d9738SJakob Bornecrantz  * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
24fb1d9738SJakob Bornecrantz  * USE OR OTHER DEALINGS IN THE SOFTWARE.
25fb1d9738SJakob Bornecrantz  *
26fb1d9738SJakob Bornecrantz  **************************************************************************/
27fb1d9738SJakob Bornecrantz 
28fb1d9738SJakob Bornecrantz #include "vmwgfx_drv.h"
29d92223eaSZack Rusin #include "vmwgfx_devcaps.h"
302fcd5a73SJakob Bornecrantz #include "vmwgfx_kms.h"
31a6fc955fSThomas Hellstrom 
32*23b0e695SZack Rusin #include <drm/vmwgfx_drm.h>
33*23b0e695SZack Rusin #include <linux/pci.h>
34*23b0e695SZack Rusin 
vmw_getparam_ioctl(struct drm_device * dev,void * data,struct drm_file * file_priv)35fb1d9738SJakob Bornecrantz int vmw_getparam_ioctl(struct drm_device *dev, void *data,
36fb1d9738SJakob Bornecrantz 		       struct drm_file *file_priv)
37fb1d9738SJakob Bornecrantz {
38fb1d9738SJakob Bornecrantz 	struct vmw_private *dev_priv = vmw_priv(dev);
39fb1d9738SJakob Bornecrantz 	struct drm_vmw_getparam_arg *param =
40fb1d9738SJakob Bornecrantz 	    (struct drm_vmw_getparam_arg *)data;
41a6fc955fSThomas Hellstrom 	struct vmw_fpriv *vmw_fp = vmw_fpriv(file_priv);
42fb1d9738SJakob Bornecrantz 
43fb1d9738SJakob Bornecrantz 	switch (param->param) {
44fb1d9738SJakob Bornecrantz 	case DRM_VMW_PARAM_NUM_STREAMS:
45fb1d9738SJakob Bornecrantz 		param->value = vmw_overlay_num_overlays(dev_priv);
46fb1d9738SJakob Bornecrantz 		break;
47fb1d9738SJakob Bornecrantz 	case DRM_VMW_PARAM_NUM_FREE_STREAMS:
48fb1d9738SJakob Bornecrantz 		param->value = vmw_overlay_num_free_overlays(dev_priv);
49fb1d9738SJakob Bornecrantz 		break;
50fb1d9738SJakob Bornecrantz 	case DRM_VMW_PARAM_3D:
518426ed9cSZack Rusin 		param->value = vmw_supports_3d(dev_priv) ? 1 : 0;
52fb1d9738SJakob Bornecrantz 		break;
53f77cef3dSThomas Hellstrom 	case DRM_VMW_PARAM_HW_CAPS:
54f77cef3dSThomas Hellstrom 		param->value = dev_priv->capabilities;
55f77cef3dSThomas Hellstrom 		break;
563b4c2511SNeha Bhende 	case DRM_VMW_PARAM_HW_CAPS2:
573b4c2511SNeha Bhende 		param->value = dev_priv->capabilities2;
583b4c2511SNeha Bhende 		break;
59f77cef3dSThomas Hellstrom 	case DRM_VMW_PARAM_FIFO_CAPS:
602cd80dbdSZack Rusin 		param->value = vmw_fifo_caps(dev_priv);
61f77cef3dSThomas Hellstrom 		break;
6230f47fc8SThomas Hellstrom 	case DRM_VMW_PARAM_MAX_FB_SIZE:
63ebc9ac7cSZack Rusin 		param->value = dev_priv->max_primary_mem;
6430f47fc8SThomas Hellstrom 		break;
65f63f6a59SThomas Hellstrom 	case DRM_VMW_PARAM_FIFO_HW_VERSION:
66f63f6a59SThomas Hellstrom 	{
67*23b0e695SZack Rusin 		if ((dev_priv->capabilities & SVGA_CAP_GBOBJECTS))
68a6fc955fSThomas Hellstrom 			param->value = SVGA3D_HWVERSION_WS8_B1;
69*23b0e695SZack Rusin 		else
70*23b0e695SZack Rusin 			param->value = vmw_fifo_mem_read(
71*23b0e695SZack Rusin 					       dev_priv,
722cd80dbdSZack Rusin 					       ((vmw_fifo_caps(dev_priv) &
73ebd4c6f6SThomas Hellstrom 						 SVGA_FIFO_CAP_3D_HWVERSION_REVISED) ?
74ebd4c6f6SThomas Hellstrom 							SVGA_FIFO_3D_HWVERSION_REVISED :
75ebd4c6f6SThomas Hellstrom 							SVGA_FIFO_3D_HWVERSION));
76f63f6a59SThomas Hellstrom 		break;
77f63f6a59SThomas Hellstrom 	}
78716a2fd6SThomas Hellstrom 	case DRM_VMW_PARAM_MAX_SURF_MEMORY:
79a6fc955fSThomas Hellstrom 		if ((dev_priv->capabilities & SVGA_CAP_GBOBJECTS) &&
80a6fc955fSThomas Hellstrom 		    !vmw_fp->gb_aware)
81a6fc955fSThomas Hellstrom 			param->value = dev_priv->max_mob_pages * PAGE_SIZE / 2;
82a6fc955fSThomas Hellstrom 		else
83716a2fd6SThomas Hellstrom 			param->value = dev_priv->memory_size;
84716a2fd6SThomas Hellstrom 		break;
85716a2fd6SThomas Hellstrom 	case DRM_VMW_PARAM_3D_CAPS_SIZE:
86d92223eaSZack Rusin 		param->value = vmw_devcaps_size(dev_priv, vmw_fp->gb_aware);
87716a2fd6SThomas Hellstrom 		break;
88311474dbSThomas Hellstrom 	case DRM_VMW_PARAM_MAX_MOB_MEMORY:
89a6fc955fSThomas Hellstrom 		vmw_fp->gb_aware = true;
90311474dbSThomas Hellstrom 		param->value = dev_priv->max_mob_pages * PAGE_SIZE;
91311474dbSThomas Hellstrom 		break;
92857aea1cSCharmaine Lee 	case DRM_VMW_PARAM_MAX_MOB_SIZE:
93857aea1cSCharmaine Lee 		param->value = dev_priv->max_mob_size;
94857aea1cSCharmaine Lee 		break;
9535c05125SSinclair Yeh 	case DRM_VMW_PARAM_SCREEN_TARGET:
9635c05125SSinclair Yeh 		param->value =
9735c05125SSinclair Yeh 			(dev_priv->active_display_unit == vmw_du_screen_target);
9835c05125SSinclair Yeh 		break;
99d80efd5cSThomas Hellstrom 	case DRM_VMW_PARAM_DX:
100878c6ecdSDeepak Rawat 		param->value = has_sm4_context(dev_priv);
101d80efd5cSThomas Hellstrom 		break;
1029b07b287SDeepak Rawat 	case DRM_VMW_PARAM_SM4_1:
103878c6ecdSDeepak Rawat 		param->value = has_sm4_1_context(dev_priv);
1049b07b287SDeepak Rawat 		break;
105f0fce233SDeepak Rawat 	case DRM_VMW_PARAM_SM5:
106f0fce233SDeepak Rawat 		param->value = has_sm5_context(dev_priv);
107f0fce233SDeepak Rawat 		break;
108abaad3d9SZack Rusin 	case DRM_VMW_PARAM_GL43:
109abaad3d9SZack Rusin 		param->value = has_gl43_context(dev_priv);
110abaad3d9SZack Rusin 		break;
111*23b0e695SZack Rusin 	case DRM_VMW_PARAM_DEVICE_ID:
112*23b0e695SZack Rusin 		param->value = to_pci_dev(dev_priv->drm.dev)->device;
113*23b0e695SZack Rusin 		break;
114fb1d9738SJakob Bornecrantz 	default:
115fb1d9738SJakob Bornecrantz 		return -EINVAL;
116fb1d9738SJakob Bornecrantz 	}
117fb1d9738SJakob Bornecrantz 
118fb1d9738SJakob Bornecrantz 	return 0;
119fb1d9738SJakob Bornecrantz }
120f63f6a59SThomas Hellstrom 
121f63f6a59SThomas Hellstrom 
vmw_get_cap_3d_ioctl(struct drm_device * dev,void * data,struct drm_file * file_priv)122f63f6a59SThomas Hellstrom int vmw_get_cap_3d_ioctl(struct drm_device *dev, void *data,
123f63f6a59SThomas Hellstrom 			 struct drm_file *file_priv)
124f63f6a59SThomas Hellstrom {
125f63f6a59SThomas Hellstrom 	struct drm_vmw_get_3d_cap_arg *arg =
126f63f6a59SThomas Hellstrom 		(struct drm_vmw_get_3d_cap_arg *) data;
127f63f6a59SThomas Hellstrom 	struct vmw_private *dev_priv = vmw_priv(dev);
128f63f6a59SThomas Hellstrom 	uint32_t size;
129f63f6a59SThomas Hellstrom 	void __user *buffer = (void __user *)((unsigned long)(arg->buffer));
130d92223eaSZack Rusin 	void *bounce = NULL;
131f63f6a59SThomas Hellstrom 	int ret;
132a6fc955fSThomas Hellstrom 	struct vmw_fpriv *vmw_fp = vmw_fpriv(file_priv);
133f63f6a59SThomas Hellstrom 
13463774069SMurray McAllister 	if (unlikely(arg->pad64 != 0 || arg->max_size == 0)) {
1355724f899SDeepak Rawat 		VMW_DEBUG_USER("Illegal GET_3D_CAP argument.\n");
136f63f6a59SThomas Hellstrom 		return -EINVAL;
137f63f6a59SThomas Hellstrom 	}
138f63f6a59SThomas Hellstrom 
139d92223eaSZack Rusin 	size = vmw_devcaps_size(dev_priv, vmw_fp->gb_aware);
140d92223eaSZack Rusin 	if (unlikely(size == 0)) {
141d92223eaSZack Rusin 		DRM_ERROR("Failed to figure out the devcaps size (no 3D).\n");
142d92223eaSZack Rusin 		return -ENOMEM;
143d92223eaSZack Rusin 	}
144f63f6a59SThomas Hellstrom 
145f63f6a59SThomas Hellstrom 	if (arg->max_size < size)
146f63f6a59SThomas Hellstrom 		size = arg->max_size;
147f63f6a59SThomas Hellstrom 
148a6fc955fSThomas Hellstrom 	bounce = vzalloc(size);
149f63f6a59SThomas Hellstrom 	if (unlikely(bounce == NULL)) {
150f63f6a59SThomas Hellstrom 		DRM_ERROR("Failed to allocate bounce buffer for 3D caps.\n");
151f63f6a59SThomas Hellstrom 		return -ENOMEM;
152f63f6a59SThomas Hellstrom 	}
153f63f6a59SThomas Hellstrom 
154d92223eaSZack Rusin 	ret = vmw_devcaps_copy(dev_priv, vmw_fp->gb_aware, bounce, size);
155a6fc955fSThomas Hellstrom 	if (unlikely (ret != 0))
156a6fc955fSThomas Hellstrom 		goto out_err;
157f63f6a59SThomas Hellstrom 
158f63f6a59SThomas Hellstrom 	ret = copy_to_user(buffer, bounce, size);
159888155bbSDan Carpenter 	if (ret)
160888155bbSDan Carpenter 		ret = -EFAULT;
161a6fc955fSThomas Hellstrom out_err:
162f63f6a59SThomas Hellstrom 	vfree(bounce);
163f63f6a59SThomas Hellstrom 
164f63f6a59SThomas Hellstrom 	if (unlikely(ret != 0))
165f63f6a59SThomas Hellstrom 		DRM_ERROR("Failed to report 3D caps info.\n");
166f63f6a59SThomas Hellstrom 
167f63f6a59SThomas Hellstrom 	return ret;
168f63f6a59SThomas Hellstrom }
1692fcd5a73SJakob Bornecrantz 
vmw_present_ioctl(struct drm_device * dev,void * data,struct drm_file * file_priv)1702fcd5a73SJakob Bornecrantz int vmw_present_ioctl(struct drm_device *dev, void *data,
1712fcd5a73SJakob Bornecrantz 		      struct drm_file *file_priv)
1722fcd5a73SJakob Bornecrantz {
1732fcd5a73SJakob Bornecrantz 	struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile;
1742fcd5a73SJakob Bornecrantz 	struct vmw_private *dev_priv = vmw_priv(dev);
1752fcd5a73SJakob Bornecrantz 	struct drm_vmw_present_arg *arg =
1762fcd5a73SJakob Bornecrantz 		(struct drm_vmw_present_arg *)data;
1772fcd5a73SJakob Bornecrantz 	struct vmw_surface *surface;
1782fcd5a73SJakob Bornecrantz 	struct drm_vmw_rect __user *clips_ptr;
1792fcd5a73SJakob Bornecrantz 	struct drm_vmw_rect *clips = NULL;
180786b99edSDaniel Vetter 	struct drm_framebuffer *fb;
1812fcd5a73SJakob Bornecrantz 	struct vmw_framebuffer *vfb;
182c0951b79SThomas Hellstrom 	struct vmw_resource *res;
1832fcd5a73SJakob Bornecrantz 	uint32_t num_clips;
1842fcd5a73SJakob Bornecrantz 	int ret;
1852fcd5a73SJakob Bornecrantz 
1862fcd5a73SJakob Bornecrantz 	num_clips = arg->num_clips;
187b9eb1a61SThomas Hellstrom 	clips_ptr = (struct drm_vmw_rect __user *)(unsigned long)arg->clips_ptr;
1882fcd5a73SJakob Bornecrantz 
1892fcd5a73SJakob Bornecrantz 	if (unlikely(num_clips == 0))
1902fcd5a73SJakob Bornecrantz 		return 0;
1912fcd5a73SJakob Bornecrantz 
1922fcd5a73SJakob Bornecrantz 	if (clips_ptr == NULL) {
1935724f899SDeepak Rawat 		VMW_DEBUG_USER("Variable clips_ptr must be specified.\n");
1942fcd5a73SJakob Bornecrantz 		ret = -EINVAL;
1952fcd5a73SJakob Bornecrantz 		goto out_clips;
1962fcd5a73SJakob Bornecrantz 	}
1972fcd5a73SJakob Bornecrantz 
19824bb5a0cSThomas Meyer 	clips = kcalloc(num_clips, sizeof(*clips), GFP_KERNEL);
1992fcd5a73SJakob Bornecrantz 	if (clips == NULL) {
2002fcd5a73SJakob Bornecrantz 		DRM_ERROR("Failed to allocate clip rect list.\n");
2012fcd5a73SJakob Bornecrantz 		ret = -ENOMEM;
2022fcd5a73SJakob Bornecrantz 		goto out_clips;
2032fcd5a73SJakob Bornecrantz 	}
2042fcd5a73SJakob Bornecrantz 
2052fcd5a73SJakob Bornecrantz 	ret = copy_from_user(clips, clips_ptr, num_clips * sizeof(*clips));
2062fcd5a73SJakob Bornecrantz 	if (ret) {
2072fcd5a73SJakob Bornecrantz 		DRM_ERROR("Failed to copy clip rects from userspace.\n");
208d2c184fbSDan Carpenter 		ret = -EFAULT;
2092fcd5a73SJakob Bornecrantz 		goto out_no_copy;
2102fcd5a73SJakob Bornecrantz 	}
2112fcd5a73SJakob Bornecrantz 
212e7b48185SSean Paul 	drm_modeset_lock_all(dev);
2132fcd5a73SJakob Bornecrantz 
214418da172SKeith Packard 	fb = drm_framebuffer_lookup(dev, file_priv, arg->fb_id);
215786b99edSDaniel Vetter 	if (!fb) {
2165724f899SDeepak Rawat 		VMW_DEBUG_USER("Invalid framebuffer id.\n");
21743789b9eSVille Syrjälä 		ret = -ENOENT;
2182fcd5a73SJakob Bornecrantz 		goto out_no_fb;
2192fcd5a73SJakob Bornecrantz 	}
220786b99edSDaniel Vetter 	vfb = vmw_framebuffer_to_vfb(fb);
2212fcd5a73SJakob Bornecrantz 
222c0951b79SThomas Hellstrom 	ret = vmw_user_resource_lookup_handle(dev_priv, tfile, arg->sid,
223c0951b79SThomas Hellstrom 					      user_surface_converter,
224c0951b79SThomas Hellstrom 					      &res);
2252fcd5a73SJakob Bornecrantz 	if (ret)
2262fcd5a73SJakob Bornecrantz 		goto out_no_surface;
2272fcd5a73SJakob Bornecrantz 
228c0951b79SThomas Hellstrom 	surface = vmw_res_to_srf(res);
2292fcd5a73SJakob Bornecrantz 	ret = vmw_kms_present(dev_priv, file_priv,
2302fcd5a73SJakob Bornecrantz 			      vfb, surface, arg->sid,
2312fcd5a73SJakob Bornecrantz 			      arg->dest_x, arg->dest_y,
2322fcd5a73SJakob Bornecrantz 			      clips, num_clips);
2332fcd5a73SJakob Bornecrantz 
2342fcd5a73SJakob Bornecrantz 	/* vmw_user_surface_lookup takes one ref so does new_fb */
2352fcd5a73SJakob Bornecrantz 	vmw_surface_unreference(&surface);
2362fcd5a73SJakob Bornecrantz 
2372fcd5a73SJakob Bornecrantz out_no_surface:
23825a28906SHaneen Mohammed 	drm_framebuffer_put(fb);
2392fcd5a73SJakob Bornecrantz out_no_fb:
240e7b48185SSean Paul 	drm_modeset_unlock_all(dev);
2412fcd5a73SJakob Bornecrantz out_no_copy:
2422fcd5a73SJakob Bornecrantz 	kfree(clips);
2432fcd5a73SJakob Bornecrantz out_clips:
2442fcd5a73SJakob Bornecrantz 	return ret;
2452fcd5a73SJakob Bornecrantz }
2462fcd5a73SJakob Bornecrantz 
vmw_present_readback_ioctl(struct drm_device * dev,void * data,struct drm_file * file_priv)2472fcd5a73SJakob Bornecrantz int vmw_present_readback_ioctl(struct drm_device *dev, void *data,
2482fcd5a73SJakob Bornecrantz 			       struct drm_file *file_priv)
2492fcd5a73SJakob Bornecrantz {
2502fcd5a73SJakob Bornecrantz 	struct vmw_private *dev_priv = vmw_priv(dev);
2512fcd5a73SJakob Bornecrantz 	struct drm_vmw_present_readback_arg *arg =
2522fcd5a73SJakob Bornecrantz 		(struct drm_vmw_present_readback_arg *)data;
2532fcd5a73SJakob Bornecrantz 	struct drm_vmw_fence_rep __user *user_fence_rep =
2542fcd5a73SJakob Bornecrantz 		(struct drm_vmw_fence_rep __user *)
2552fcd5a73SJakob Bornecrantz 		(unsigned long)arg->fence_rep;
2562fcd5a73SJakob Bornecrantz 	struct drm_vmw_rect __user *clips_ptr;
2572fcd5a73SJakob Bornecrantz 	struct drm_vmw_rect *clips = NULL;
258786b99edSDaniel Vetter 	struct drm_framebuffer *fb;
2592fcd5a73SJakob Bornecrantz 	struct vmw_framebuffer *vfb;
2602fcd5a73SJakob Bornecrantz 	uint32_t num_clips;
2612fcd5a73SJakob Bornecrantz 	int ret;
2622fcd5a73SJakob Bornecrantz 
2632fcd5a73SJakob Bornecrantz 	num_clips = arg->num_clips;
264b9eb1a61SThomas Hellstrom 	clips_ptr = (struct drm_vmw_rect __user *)(unsigned long)arg->clips_ptr;
2652fcd5a73SJakob Bornecrantz 
2662fcd5a73SJakob Bornecrantz 	if (unlikely(num_clips == 0))
2672fcd5a73SJakob Bornecrantz 		return 0;
2682fcd5a73SJakob Bornecrantz 
2692fcd5a73SJakob Bornecrantz 	if (clips_ptr == NULL) {
2705724f899SDeepak Rawat 		VMW_DEBUG_USER("Argument clips_ptr must be specified.\n");
2712fcd5a73SJakob Bornecrantz 		ret = -EINVAL;
2722fcd5a73SJakob Bornecrantz 		goto out_clips;
2732fcd5a73SJakob Bornecrantz 	}
2742fcd5a73SJakob Bornecrantz 
27524bb5a0cSThomas Meyer 	clips = kcalloc(num_clips, sizeof(*clips), GFP_KERNEL);
2762fcd5a73SJakob Bornecrantz 	if (clips == NULL) {
2772fcd5a73SJakob Bornecrantz 		DRM_ERROR("Failed to allocate clip rect list.\n");
2782fcd5a73SJakob Bornecrantz 		ret = -ENOMEM;
2792fcd5a73SJakob Bornecrantz 		goto out_clips;
2802fcd5a73SJakob Bornecrantz 	}
2812fcd5a73SJakob Bornecrantz 
2822fcd5a73SJakob Bornecrantz 	ret = copy_from_user(clips, clips_ptr, num_clips * sizeof(*clips));
2832fcd5a73SJakob Bornecrantz 	if (ret) {
2842fcd5a73SJakob Bornecrantz 		DRM_ERROR("Failed to copy clip rects from userspace.\n");
285d2c184fbSDan Carpenter 		ret = -EFAULT;
2862fcd5a73SJakob Bornecrantz 		goto out_no_copy;
2872fcd5a73SJakob Bornecrantz 	}
2882fcd5a73SJakob Bornecrantz 
289e7b48185SSean Paul 	drm_modeset_lock_all(dev);
2902fcd5a73SJakob Bornecrantz 
291418da172SKeith Packard 	fb = drm_framebuffer_lookup(dev, file_priv, arg->fb_id);
292786b99edSDaniel Vetter 	if (!fb) {
2935724f899SDeepak Rawat 		VMW_DEBUG_USER("Invalid framebuffer id.\n");
29443789b9eSVille Syrjälä 		ret = -ENOENT;
2952fcd5a73SJakob Bornecrantz 		goto out_no_fb;
2962fcd5a73SJakob Bornecrantz 	}
2972fcd5a73SJakob Bornecrantz 
298786b99edSDaniel Vetter 	vfb = vmw_framebuffer_to_vfb(fb);
299f1d34bfdSThomas Hellstrom 	if (!vfb->bo) {
3005724f899SDeepak Rawat 		VMW_DEBUG_USER("Framebuffer not buffer backed.\n");
3012fcd5a73SJakob Bornecrantz 		ret = -EINVAL;
3022fd5eabaSDaniel Vetter 		goto out_no_ttm_lock;
3032fcd5a73SJakob Bornecrantz 	}
3042fcd5a73SJakob Bornecrantz 
3052fcd5a73SJakob Bornecrantz 	ret = vmw_kms_readback(dev_priv, file_priv,
3062fcd5a73SJakob Bornecrantz 			       vfb, user_fence_rep,
3072fcd5a73SJakob Bornecrantz 			       clips, num_clips);
3082fcd5a73SJakob Bornecrantz 
3092fcd5a73SJakob Bornecrantz out_no_ttm_lock:
31025a28906SHaneen Mohammed 	drm_framebuffer_put(fb);
3112fcd5a73SJakob Bornecrantz out_no_fb:
312e7b48185SSean Paul 	drm_modeset_unlock_all(dev);
3132fcd5a73SJakob Bornecrantz out_no_copy:
3142fcd5a73SJakob Bornecrantz 	kfree(clips);
3152fcd5a73SJakob Bornecrantz out_clips:
3162fcd5a73SJakob Bornecrantz 	return ret;
3172fcd5a73SJakob Bornecrantz }
318