18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 OR MIT 28c2ecf20Sopenharmony_ci/************************************************************************** 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * Copyright 2009-2015 VMware, Inc., Palo Alto, CA., USA 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a 78c2ecf20Sopenharmony_ci * copy of this software and associated documentation files (the 88c2ecf20Sopenharmony_ci * "Software"), to deal in the Software without restriction, including 98c2ecf20Sopenharmony_ci * without limitation the rights to use, copy, modify, merge, publish, 108c2ecf20Sopenharmony_ci * distribute, sub license, and/or sell copies of the Software, and to 118c2ecf20Sopenharmony_ci * permit persons to whom the Software is furnished to do so, subject to 128c2ecf20Sopenharmony_ci * the following conditions: 138c2ecf20Sopenharmony_ci * 148c2ecf20Sopenharmony_ci * The above copyright notice and this permission notice (including the 158c2ecf20Sopenharmony_ci * next paragraph) shall be included in all copies or substantial portions 168c2ecf20Sopenharmony_ci * of the Software. 178c2ecf20Sopenharmony_ci * 188c2ecf20Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 198c2ecf20Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 208c2ecf20Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL 218c2ecf20Sopenharmony_ci * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, 228c2ecf20Sopenharmony_ci * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 238c2ecf20Sopenharmony_ci * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 248c2ecf20Sopenharmony_ci * USE OR OTHER DEALINGS IN THE SOFTWARE. 258c2ecf20Sopenharmony_ci * 268c2ecf20Sopenharmony_ci **************************************************************************/ 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci#include "vmwgfx_drv.h" 298c2ecf20Sopenharmony_ci#include <drm/vmwgfx_drm.h> 308c2ecf20Sopenharmony_ci#include "vmwgfx_kms.h" 318c2ecf20Sopenharmony_ci#include "device_include/svga3d_caps.h" 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_cistruct svga_3d_compat_cap { 348c2ecf20Sopenharmony_ci SVGA3dCapsRecordHeader header; 358c2ecf20Sopenharmony_ci SVGA3dCapPair pairs[SVGA3D_DEVCAP_MAX]; 368c2ecf20Sopenharmony_ci}; 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ciint vmw_getparam_ioctl(struct drm_device *dev, void *data, 398c2ecf20Sopenharmony_ci struct drm_file *file_priv) 408c2ecf20Sopenharmony_ci{ 418c2ecf20Sopenharmony_ci struct vmw_private *dev_priv = vmw_priv(dev); 428c2ecf20Sopenharmony_ci struct drm_vmw_getparam_arg *param = 438c2ecf20Sopenharmony_ci (struct drm_vmw_getparam_arg *)data; 448c2ecf20Sopenharmony_ci struct vmw_fpriv *vmw_fp = vmw_fpriv(file_priv); 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ci switch (param->param) { 478c2ecf20Sopenharmony_ci case DRM_VMW_PARAM_NUM_STREAMS: 488c2ecf20Sopenharmony_ci param->value = vmw_overlay_num_overlays(dev_priv); 498c2ecf20Sopenharmony_ci break; 508c2ecf20Sopenharmony_ci case DRM_VMW_PARAM_NUM_FREE_STREAMS: 518c2ecf20Sopenharmony_ci param->value = vmw_overlay_num_free_overlays(dev_priv); 528c2ecf20Sopenharmony_ci break; 538c2ecf20Sopenharmony_ci case DRM_VMW_PARAM_3D: 548c2ecf20Sopenharmony_ci param->value = vmw_fifo_have_3d(dev_priv) ? 1 : 0; 558c2ecf20Sopenharmony_ci break; 568c2ecf20Sopenharmony_ci case DRM_VMW_PARAM_HW_CAPS: 578c2ecf20Sopenharmony_ci param->value = dev_priv->capabilities; 588c2ecf20Sopenharmony_ci break; 598c2ecf20Sopenharmony_ci case DRM_VMW_PARAM_HW_CAPS2: 608c2ecf20Sopenharmony_ci param->value = dev_priv->capabilities2; 618c2ecf20Sopenharmony_ci break; 628c2ecf20Sopenharmony_ci case DRM_VMW_PARAM_FIFO_CAPS: 638c2ecf20Sopenharmony_ci param->value = dev_priv->fifo.capabilities; 648c2ecf20Sopenharmony_ci break; 658c2ecf20Sopenharmony_ci case DRM_VMW_PARAM_MAX_FB_SIZE: 668c2ecf20Sopenharmony_ci param->value = dev_priv->prim_bb_mem; 678c2ecf20Sopenharmony_ci break; 688c2ecf20Sopenharmony_ci case DRM_VMW_PARAM_FIFO_HW_VERSION: 698c2ecf20Sopenharmony_ci { 708c2ecf20Sopenharmony_ci u32 *fifo_mem = dev_priv->mmio_virt; 718c2ecf20Sopenharmony_ci const struct vmw_fifo_state *fifo = &dev_priv->fifo; 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci if ((dev_priv->capabilities & SVGA_CAP_GBOBJECTS)) { 748c2ecf20Sopenharmony_ci param->value = SVGA3D_HWVERSION_WS8_B1; 758c2ecf20Sopenharmony_ci break; 768c2ecf20Sopenharmony_ci } 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci param->value = 798c2ecf20Sopenharmony_ci vmw_mmio_read(fifo_mem + 808c2ecf20Sopenharmony_ci ((fifo->capabilities & 818c2ecf20Sopenharmony_ci SVGA_FIFO_CAP_3D_HWVERSION_REVISED) ? 828c2ecf20Sopenharmony_ci SVGA_FIFO_3D_HWVERSION_REVISED : 838c2ecf20Sopenharmony_ci SVGA_FIFO_3D_HWVERSION)); 848c2ecf20Sopenharmony_ci break; 858c2ecf20Sopenharmony_ci } 868c2ecf20Sopenharmony_ci case DRM_VMW_PARAM_MAX_SURF_MEMORY: 878c2ecf20Sopenharmony_ci if ((dev_priv->capabilities & SVGA_CAP_GBOBJECTS) && 888c2ecf20Sopenharmony_ci !vmw_fp->gb_aware) 898c2ecf20Sopenharmony_ci param->value = dev_priv->max_mob_pages * PAGE_SIZE / 2; 908c2ecf20Sopenharmony_ci else 918c2ecf20Sopenharmony_ci param->value = dev_priv->memory_size; 928c2ecf20Sopenharmony_ci break; 938c2ecf20Sopenharmony_ci case DRM_VMW_PARAM_3D_CAPS_SIZE: 948c2ecf20Sopenharmony_ci if ((dev_priv->capabilities & SVGA_CAP_GBOBJECTS) && 958c2ecf20Sopenharmony_ci vmw_fp->gb_aware) 968c2ecf20Sopenharmony_ci param->value = SVGA3D_DEVCAP_MAX * sizeof(uint32_t); 978c2ecf20Sopenharmony_ci else if (dev_priv->capabilities & SVGA_CAP_GBOBJECTS) 988c2ecf20Sopenharmony_ci param->value = sizeof(struct svga_3d_compat_cap) + 998c2ecf20Sopenharmony_ci sizeof(uint32_t); 1008c2ecf20Sopenharmony_ci else 1018c2ecf20Sopenharmony_ci param->value = (SVGA_FIFO_3D_CAPS_LAST - 1028c2ecf20Sopenharmony_ci SVGA_FIFO_3D_CAPS + 1) * 1038c2ecf20Sopenharmony_ci sizeof(uint32_t); 1048c2ecf20Sopenharmony_ci break; 1058c2ecf20Sopenharmony_ci case DRM_VMW_PARAM_MAX_MOB_MEMORY: 1068c2ecf20Sopenharmony_ci vmw_fp->gb_aware = true; 1078c2ecf20Sopenharmony_ci param->value = dev_priv->max_mob_pages * PAGE_SIZE; 1088c2ecf20Sopenharmony_ci break; 1098c2ecf20Sopenharmony_ci case DRM_VMW_PARAM_MAX_MOB_SIZE: 1108c2ecf20Sopenharmony_ci param->value = dev_priv->max_mob_size; 1118c2ecf20Sopenharmony_ci break; 1128c2ecf20Sopenharmony_ci case DRM_VMW_PARAM_SCREEN_TARGET: 1138c2ecf20Sopenharmony_ci param->value = 1148c2ecf20Sopenharmony_ci (dev_priv->active_display_unit == vmw_du_screen_target); 1158c2ecf20Sopenharmony_ci break; 1168c2ecf20Sopenharmony_ci case DRM_VMW_PARAM_DX: 1178c2ecf20Sopenharmony_ci param->value = has_sm4_context(dev_priv); 1188c2ecf20Sopenharmony_ci break; 1198c2ecf20Sopenharmony_ci case DRM_VMW_PARAM_SM4_1: 1208c2ecf20Sopenharmony_ci param->value = has_sm4_1_context(dev_priv); 1218c2ecf20Sopenharmony_ci break; 1228c2ecf20Sopenharmony_ci case DRM_VMW_PARAM_SM5: 1238c2ecf20Sopenharmony_ci param->value = has_sm5_context(dev_priv); 1248c2ecf20Sopenharmony_ci break; 1258c2ecf20Sopenharmony_ci default: 1268c2ecf20Sopenharmony_ci return -EINVAL; 1278c2ecf20Sopenharmony_ci } 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_ci return 0; 1308c2ecf20Sopenharmony_ci} 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_cistatic u32 vmw_mask_legacy_multisample(unsigned int cap, u32 fmt_value) 1338c2ecf20Sopenharmony_ci{ 1348c2ecf20Sopenharmony_ci /* 1358c2ecf20Sopenharmony_ci * A version of user-space exists which use MULTISAMPLE_MASKABLESAMPLES 1368c2ecf20Sopenharmony_ci * to check the sample count supported by virtual device. Since there 1378c2ecf20Sopenharmony_ci * never was support for multisample count for backing MOB return 0. 1388c2ecf20Sopenharmony_ci * 1398c2ecf20Sopenharmony_ci * MULTISAMPLE_MASKABLESAMPLES devcap is marked as deprecated by virtual 1408c2ecf20Sopenharmony_ci * device. 1418c2ecf20Sopenharmony_ci */ 1428c2ecf20Sopenharmony_ci if (cap == SVGA3D_DEVCAP_DEAD5) 1438c2ecf20Sopenharmony_ci return 0; 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_ci return fmt_value; 1468c2ecf20Sopenharmony_ci} 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_cistatic int vmw_fill_compat_cap(struct vmw_private *dev_priv, void *bounce, 1498c2ecf20Sopenharmony_ci size_t size) 1508c2ecf20Sopenharmony_ci{ 1518c2ecf20Sopenharmony_ci struct svga_3d_compat_cap *compat_cap = 1528c2ecf20Sopenharmony_ci (struct svga_3d_compat_cap *) bounce; 1538c2ecf20Sopenharmony_ci unsigned int i; 1548c2ecf20Sopenharmony_ci size_t pair_offset = offsetof(struct svga_3d_compat_cap, pairs); 1558c2ecf20Sopenharmony_ci unsigned int max_size; 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci if (size < pair_offset) 1588c2ecf20Sopenharmony_ci return -EINVAL; 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_ci max_size = (size - pair_offset) / sizeof(SVGA3dCapPair); 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci if (max_size > SVGA3D_DEVCAP_MAX) 1638c2ecf20Sopenharmony_ci max_size = SVGA3D_DEVCAP_MAX; 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci compat_cap->header.length = 1668c2ecf20Sopenharmony_ci (pair_offset + max_size * sizeof(SVGA3dCapPair)) / sizeof(u32); 1678c2ecf20Sopenharmony_ci compat_cap->header.type = SVGA3DCAPS_RECORD_DEVCAPS; 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_ci spin_lock(&dev_priv->cap_lock); 1708c2ecf20Sopenharmony_ci for (i = 0; i < max_size; ++i) { 1718c2ecf20Sopenharmony_ci vmw_write(dev_priv, SVGA_REG_DEV_CAP, i); 1728c2ecf20Sopenharmony_ci compat_cap->pairs[i][0] = i; 1738c2ecf20Sopenharmony_ci compat_cap->pairs[i][1] = vmw_mask_legacy_multisample 1748c2ecf20Sopenharmony_ci (i, vmw_read(dev_priv, SVGA_REG_DEV_CAP)); 1758c2ecf20Sopenharmony_ci } 1768c2ecf20Sopenharmony_ci spin_unlock(&dev_priv->cap_lock); 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_ci return 0; 1798c2ecf20Sopenharmony_ci} 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ciint vmw_get_cap_3d_ioctl(struct drm_device *dev, void *data, 1838c2ecf20Sopenharmony_ci struct drm_file *file_priv) 1848c2ecf20Sopenharmony_ci{ 1858c2ecf20Sopenharmony_ci struct drm_vmw_get_3d_cap_arg *arg = 1868c2ecf20Sopenharmony_ci (struct drm_vmw_get_3d_cap_arg *) data; 1878c2ecf20Sopenharmony_ci struct vmw_private *dev_priv = vmw_priv(dev); 1888c2ecf20Sopenharmony_ci uint32_t size; 1898c2ecf20Sopenharmony_ci u32 *fifo_mem; 1908c2ecf20Sopenharmony_ci void __user *buffer = (void __user *)((unsigned long)(arg->buffer)); 1918c2ecf20Sopenharmony_ci void *bounce; 1928c2ecf20Sopenharmony_ci int ret; 1938c2ecf20Sopenharmony_ci bool gb_objects = !!(dev_priv->capabilities & SVGA_CAP_GBOBJECTS); 1948c2ecf20Sopenharmony_ci struct vmw_fpriv *vmw_fp = vmw_fpriv(file_priv); 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci if (unlikely(arg->pad64 != 0 || arg->max_size == 0)) { 1978c2ecf20Sopenharmony_ci VMW_DEBUG_USER("Illegal GET_3D_CAP argument.\n"); 1988c2ecf20Sopenharmony_ci return -EINVAL; 1998c2ecf20Sopenharmony_ci } 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ci if (gb_objects && vmw_fp->gb_aware) 2028c2ecf20Sopenharmony_ci size = SVGA3D_DEVCAP_MAX * sizeof(uint32_t); 2038c2ecf20Sopenharmony_ci else if (gb_objects) 2048c2ecf20Sopenharmony_ci size = sizeof(struct svga_3d_compat_cap) + sizeof(uint32_t); 2058c2ecf20Sopenharmony_ci else 2068c2ecf20Sopenharmony_ci size = (SVGA_FIFO_3D_CAPS_LAST - SVGA_FIFO_3D_CAPS + 1) * 2078c2ecf20Sopenharmony_ci sizeof(uint32_t); 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_ci if (arg->max_size < size) 2108c2ecf20Sopenharmony_ci size = arg->max_size; 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_ci bounce = vzalloc(size); 2138c2ecf20Sopenharmony_ci if (unlikely(bounce == NULL)) { 2148c2ecf20Sopenharmony_ci DRM_ERROR("Failed to allocate bounce buffer for 3D caps.\n"); 2158c2ecf20Sopenharmony_ci return -ENOMEM; 2168c2ecf20Sopenharmony_ci } 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_ci if (gb_objects && vmw_fp->gb_aware) { 2198c2ecf20Sopenharmony_ci int i, num; 2208c2ecf20Sopenharmony_ci uint32_t *bounce32 = (uint32_t *) bounce; 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_ci num = size / sizeof(uint32_t); 2238c2ecf20Sopenharmony_ci if (num > SVGA3D_DEVCAP_MAX) 2248c2ecf20Sopenharmony_ci num = SVGA3D_DEVCAP_MAX; 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_ci spin_lock(&dev_priv->cap_lock); 2278c2ecf20Sopenharmony_ci for (i = 0; i < num; ++i) { 2288c2ecf20Sopenharmony_ci vmw_write(dev_priv, SVGA_REG_DEV_CAP, i); 2298c2ecf20Sopenharmony_ci *bounce32++ = vmw_mask_legacy_multisample 2308c2ecf20Sopenharmony_ci (i, vmw_read(dev_priv, SVGA_REG_DEV_CAP)); 2318c2ecf20Sopenharmony_ci } 2328c2ecf20Sopenharmony_ci spin_unlock(&dev_priv->cap_lock); 2338c2ecf20Sopenharmony_ci } else if (gb_objects) { 2348c2ecf20Sopenharmony_ci ret = vmw_fill_compat_cap(dev_priv, bounce, size); 2358c2ecf20Sopenharmony_ci if (unlikely(ret != 0)) 2368c2ecf20Sopenharmony_ci goto out_err; 2378c2ecf20Sopenharmony_ci } else { 2388c2ecf20Sopenharmony_ci fifo_mem = dev_priv->mmio_virt; 2398c2ecf20Sopenharmony_ci memcpy(bounce, &fifo_mem[SVGA_FIFO_3D_CAPS], size); 2408c2ecf20Sopenharmony_ci } 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ci ret = copy_to_user(buffer, bounce, size); 2438c2ecf20Sopenharmony_ci if (ret) 2448c2ecf20Sopenharmony_ci ret = -EFAULT; 2458c2ecf20Sopenharmony_ciout_err: 2468c2ecf20Sopenharmony_ci vfree(bounce); 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_ci if (unlikely(ret != 0)) 2498c2ecf20Sopenharmony_ci DRM_ERROR("Failed to report 3D caps info.\n"); 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_ci return ret; 2528c2ecf20Sopenharmony_ci} 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_ciint vmw_present_ioctl(struct drm_device *dev, void *data, 2558c2ecf20Sopenharmony_ci struct drm_file *file_priv) 2568c2ecf20Sopenharmony_ci{ 2578c2ecf20Sopenharmony_ci struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile; 2588c2ecf20Sopenharmony_ci struct vmw_private *dev_priv = vmw_priv(dev); 2598c2ecf20Sopenharmony_ci struct drm_vmw_present_arg *arg = 2608c2ecf20Sopenharmony_ci (struct drm_vmw_present_arg *)data; 2618c2ecf20Sopenharmony_ci struct vmw_surface *surface; 2628c2ecf20Sopenharmony_ci struct drm_vmw_rect __user *clips_ptr; 2638c2ecf20Sopenharmony_ci struct drm_vmw_rect *clips = NULL; 2648c2ecf20Sopenharmony_ci struct drm_framebuffer *fb; 2658c2ecf20Sopenharmony_ci struct vmw_framebuffer *vfb; 2668c2ecf20Sopenharmony_ci struct vmw_resource *res; 2678c2ecf20Sopenharmony_ci uint32_t num_clips; 2688c2ecf20Sopenharmony_ci int ret; 2698c2ecf20Sopenharmony_ci 2708c2ecf20Sopenharmony_ci num_clips = arg->num_clips; 2718c2ecf20Sopenharmony_ci clips_ptr = (struct drm_vmw_rect __user *)(unsigned long)arg->clips_ptr; 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_ci if (unlikely(num_clips == 0)) 2748c2ecf20Sopenharmony_ci return 0; 2758c2ecf20Sopenharmony_ci 2768c2ecf20Sopenharmony_ci if (clips_ptr == NULL) { 2778c2ecf20Sopenharmony_ci VMW_DEBUG_USER("Variable clips_ptr must be specified.\n"); 2788c2ecf20Sopenharmony_ci ret = -EINVAL; 2798c2ecf20Sopenharmony_ci goto out_clips; 2808c2ecf20Sopenharmony_ci } 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_ci clips = kcalloc(num_clips, sizeof(*clips), GFP_KERNEL); 2838c2ecf20Sopenharmony_ci if (clips == NULL) { 2848c2ecf20Sopenharmony_ci DRM_ERROR("Failed to allocate clip rect list.\n"); 2858c2ecf20Sopenharmony_ci ret = -ENOMEM; 2868c2ecf20Sopenharmony_ci goto out_clips; 2878c2ecf20Sopenharmony_ci } 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_ci ret = copy_from_user(clips, clips_ptr, num_clips * sizeof(*clips)); 2908c2ecf20Sopenharmony_ci if (ret) { 2918c2ecf20Sopenharmony_ci DRM_ERROR("Failed to copy clip rects from userspace.\n"); 2928c2ecf20Sopenharmony_ci ret = -EFAULT; 2938c2ecf20Sopenharmony_ci goto out_no_copy; 2948c2ecf20Sopenharmony_ci } 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_ci drm_modeset_lock_all(dev); 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_ci fb = drm_framebuffer_lookup(dev, file_priv, arg->fb_id); 2998c2ecf20Sopenharmony_ci if (!fb) { 3008c2ecf20Sopenharmony_ci VMW_DEBUG_USER("Invalid framebuffer id.\n"); 3018c2ecf20Sopenharmony_ci ret = -ENOENT; 3028c2ecf20Sopenharmony_ci goto out_no_fb; 3038c2ecf20Sopenharmony_ci } 3048c2ecf20Sopenharmony_ci vfb = vmw_framebuffer_to_vfb(fb); 3058c2ecf20Sopenharmony_ci 3068c2ecf20Sopenharmony_ci ret = ttm_read_lock(&dev_priv->reservation_sem, true); 3078c2ecf20Sopenharmony_ci if (unlikely(ret != 0)) 3088c2ecf20Sopenharmony_ci goto out_no_ttm_lock; 3098c2ecf20Sopenharmony_ci 3108c2ecf20Sopenharmony_ci ret = vmw_user_resource_lookup_handle(dev_priv, tfile, arg->sid, 3118c2ecf20Sopenharmony_ci user_surface_converter, 3128c2ecf20Sopenharmony_ci &res); 3138c2ecf20Sopenharmony_ci if (ret) 3148c2ecf20Sopenharmony_ci goto out_no_surface; 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_ci surface = vmw_res_to_srf(res); 3178c2ecf20Sopenharmony_ci ret = vmw_kms_present(dev_priv, file_priv, 3188c2ecf20Sopenharmony_ci vfb, surface, arg->sid, 3198c2ecf20Sopenharmony_ci arg->dest_x, arg->dest_y, 3208c2ecf20Sopenharmony_ci clips, num_clips); 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_ci /* vmw_user_surface_lookup takes one ref so does new_fb */ 3238c2ecf20Sopenharmony_ci vmw_surface_unreference(&surface); 3248c2ecf20Sopenharmony_ci 3258c2ecf20Sopenharmony_ciout_no_surface: 3268c2ecf20Sopenharmony_ci ttm_read_unlock(&dev_priv->reservation_sem); 3278c2ecf20Sopenharmony_ciout_no_ttm_lock: 3288c2ecf20Sopenharmony_ci drm_framebuffer_put(fb); 3298c2ecf20Sopenharmony_ciout_no_fb: 3308c2ecf20Sopenharmony_ci drm_modeset_unlock_all(dev); 3318c2ecf20Sopenharmony_ciout_no_copy: 3328c2ecf20Sopenharmony_ci kfree(clips); 3338c2ecf20Sopenharmony_ciout_clips: 3348c2ecf20Sopenharmony_ci return ret; 3358c2ecf20Sopenharmony_ci} 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_ciint vmw_present_readback_ioctl(struct drm_device *dev, void *data, 3388c2ecf20Sopenharmony_ci struct drm_file *file_priv) 3398c2ecf20Sopenharmony_ci{ 3408c2ecf20Sopenharmony_ci struct vmw_private *dev_priv = vmw_priv(dev); 3418c2ecf20Sopenharmony_ci struct drm_vmw_present_readback_arg *arg = 3428c2ecf20Sopenharmony_ci (struct drm_vmw_present_readback_arg *)data; 3438c2ecf20Sopenharmony_ci struct drm_vmw_fence_rep __user *user_fence_rep = 3448c2ecf20Sopenharmony_ci (struct drm_vmw_fence_rep __user *) 3458c2ecf20Sopenharmony_ci (unsigned long)arg->fence_rep; 3468c2ecf20Sopenharmony_ci struct drm_vmw_rect __user *clips_ptr; 3478c2ecf20Sopenharmony_ci struct drm_vmw_rect *clips = NULL; 3488c2ecf20Sopenharmony_ci struct drm_framebuffer *fb; 3498c2ecf20Sopenharmony_ci struct vmw_framebuffer *vfb; 3508c2ecf20Sopenharmony_ci uint32_t num_clips; 3518c2ecf20Sopenharmony_ci int ret; 3528c2ecf20Sopenharmony_ci 3538c2ecf20Sopenharmony_ci num_clips = arg->num_clips; 3548c2ecf20Sopenharmony_ci clips_ptr = (struct drm_vmw_rect __user *)(unsigned long)arg->clips_ptr; 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_ci if (unlikely(num_clips == 0)) 3578c2ecf20Sopenharmony_ci return 0; 3588c2ecf20Sopenharmony_ci 3598c2ecf20Sopenharmony_ci if (clips_ptr == NULL) { 3608c2ecf20Sopenharmony_ci VMW_DEBUG_USER("Argument clips_ptr must be specified.\n"); 3618c2ecf20Sopenharmony_ci ret = -EINVAL; 3628c2ecf20Sopenharmony_ci goto out_clips; 3638c2ecf20Sopenharmony_ci } 3648c2ecf20Sopenharmony_ci 3658c2ecf20Sopenharmony_ci clips = kcalloc(num_clips, sizeof(*clips), GFP_KERNEL); 3668c2ecf20Sopenharmony_ci if (clips == NULL) { 3678c2ecf20Sopenharmony_ci DRM_ERROR("Failed to allocate clip rect list.\n"); 3688c2ecf20Sopenharmony_ci ret = -ENOMEM; 3698c2ecf20Sopenharmony_ci goto out_clips; 3708c2ecf20Sopenharmony_ci } 3718c2ecf20Sopenharmony_ci 3728c2ecf20Sopenharmony_ci ret = copy_from_user(clips, clips_ptr, num_clips * sizeof(*clips)); 3738c2ecf20Sopenharmony_ci if (ret) { 3748c2ecf20Sopenharmony_ci DRM_ERROR("Failed to copy clip rects from userspace.\n"); 3758c2ecf20Sopenharmony_ci ret = -EFAULT; 3768c2ecf20Sopenharmony_ci goto out_no_copy; 3778c2ecf20Sopenharmony_ci } 3788c2ecf20Sopenharmony_ci 3798c2ecf20Sopenharmony_ci drm_modeset_lock_all(dev); 3808c2ecf20Sopenharmony_ci 3818c2ecf20Sopenharmony_ci fb = drm_framebuffer_lookup(dev, file_priv, arg->fb_id); 3828c2ecf20Sopenharmony_ci if (!fb) { 3838c2ecf20Sopenharmony_ci VMW_DEBUG_USER("Invalid framebuffer id.\n"); 3848c2ecf20Sopenharmony_ci ret = -ENOENT; 3858c2ecf20Sopenharmony_ci goto out_no_fb; 3868c2ecf20Sopenharmony_ci } 3878c2ecf20Sopenharmony_ci 3888c2ecf20Sopenharmony_ci vfb = vmw_framebuffer_to_vfb(fb); 3898c2ecf20Sopenharmony_ci if (!vfb->bo) { 3908c2ecf20Sopenharmony_ci VMW_DEBUG_USER("Framebuffer not buffer backed.\n"); 3918c2ecf20Sopenharmony_ci ret = -EINVAL; 3928c2ecf20Sopenharmony_ci goto out_no_ttm_lock; 3938c2ecf20Sopenharmony_ci } 3948c2ecf20Sopenharmony_ci 3958c2ecf20Sopenharmony_ci ret = ttm_read_lock(&dev_priv->reservation_sem, true); 3968c2ecf20Sopenharmony_ci if (unlikely(ret != 0)) 3978c2ecf20Sopenharmony_ci goto out_no_ttm_lock; 3988c2ecf20Sopenharmony_ci 3998c2ecf20Sopenharmony_ci ret = vmw_kms_readback(dev_priv, file_priv, 4008c2ecf20Sopenharmony_ci vfb, user_fence_rep, 4018c2ecf20Sopenharmony_ci clips, num_clips); 4028c2ecf20Sopenharmony_ci 4038c2ecf20Sopenharmony_ci ttm_read_unlock(&dev_priv->reservation_sem); 4048c2ecf20Sopenharmony_ciout_no_ttm_lock: 4058c2ecf20Sopenharmony_ci drm_framebuffer_put(fb); 4068c2ecf20Sopenharmony_ciout_no_fb: 4078c2ecf20Sopenharmony_ci drm_modeset_unlock_all(dev); 4088c2ecf20Sopenharmony_ciout_no_copy: 4098c2ecf20Sopenharmony_ci kfree(clips); 4108c2ecf20Sopenharmony_ciout_clips: 4118c2ecf20Sopenharmony_ci return ret; 4128c2ecf20Sopenharmony_ci} 4138c2ecf20Sopenharmony_ci 4148c2ecf20Sopenharmony_ci 4158c2ecf20Sopenharmony_ci/** 4168c2ecf20Sopenharmony_ci * vmw_fops_poll - wrapper around the drm_poll function 4178c2ecf20Sopenharmony_ci * 4188c2ecf20Sopenharmony_ci * @filp: See the linux fops poll documentation. 4198c2ecf20Sopenharmony_ci * @wait: See the linux fops poll documentation. 4208c2ecf20Sopenharmony_ci * 4218c2ecf20Sopenharmony_ci * Wrapper around the drm_poll function that makes sure the device is 4228c2ecf20Sopenharmony_ci * processing the fifo if drm_poll decides to wait. 4238c2ecf20Sopenharmony_ci */ 4248c2ecf20Sopenharmony_ci__poll_t vmw_fops_poll(struct file *filp, struct poll_table_struct *wait) 4258c2ecf20Sopenharmony_ci{ 4268c2ecf20Sopenharmony_ci struct drm_file *file_priv = filp->private_data; 4278c2ecf20Sopenharmony_ci struct vmw_private *dev_priv = 4288c2ecf20Sopenharmony_ci vmw_priv(file_priv->minor->dev); 4298c2ecf20Sopenharmony_ci 4308c2ecf20Sopenharmony_ci vmw_fifo_ping_host(dev_priv, SVGA_SYNC_GENERIC); 4318c2ecf20Sopenharmony_ci return drm_poll(filp, wait); 4328c2ecf20Sopenharmony_ci} 4338c2ecf20Sopenharmony_ci 4348c2ecf20Sopenharmony_ci 4358c2ecf20Sopenharmony_ci/** 4368c2ecf20Sopenharmony_ci * vmw_fops_read - wrapper around the drm_read function 4378c2ecf20Sopenharmony_ci * 4388c2ecf20Sopenharmony_ci * @filp: See the linux fops read documentation. 4398c2ecf20Sopenharmony_ci * @buffer: See the linux fops read documentation. 4408c2ecf20Sopenharmony_ci * @count: See the linux fops read documentation. 4418c2ecf20Sopenharmony_ci * offset: See the linux fops read documentation. 4428c2ecf20Sopenharmony_ci * 4438c2ecf20Sopenharmony_ci * Wrapper around the drm_read function that makes sure the device is 4448c2ecf20Sopenharmony_ci * processing the fifo if drm_read decides to wait. 4458c2ecf20Sopenharmony_ci */ 4468c2ecf20Sopenharmony_cissize_t vmw_fops_read(struct file *filp, char __user *buffer, 4478c2ecf20Sopenharmony_ci size_t count, loff_t *offset) 4488c2ecf20Sopenharmony_ci{ 4498c2ecf20Sopenharmony_ci struct drm_file *file_priv = filp->private_data; 4508c2ecf20Sopenharmony_ci struct vmw_private *dev_priv = 4518c2ecf20Sopenharmony_ci vmw_priv(file_priv->minor->dev); 4528c2ecf20Sopenharmony_ci 4538c2ecf20Sopenharmony_ci vmw_fifo_ping_host(dev_priv, SVGA_SYNC_GENERIC); 4548c2ecf20Sopenharmony_ci return drm_read(filp, buffer, count, offset); 4558c2ecf20Sopenharmony_ci} 456