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