319 lines · c
1// SPDX-License-Identifier: GPL-2.0 OR MIT2/**************************************************************************3 *4 * Copyright 2009-2022 VMware, Inc., Palo Alto, CA., USA5 *6 * Permission is hereby granted, free of charge, to any person obtaining a7 * copy of this software and associated documentation files (the8 * "Software"), to deal in the Software without restriction, including9 * without limitation the rights to use, copy, modify, merge, publish,10 * distribute, sub license, and/or sell copies of the Software, and to11 * permit persons to whom the Software is furnished to do so, subject to12 * the following conditions:13 *14 * The above copyright notice and this permission notice (including the15 * next paragraph) shall be included in all copies or substantial portions16 * of the Software.17 *18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR19 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,20 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL21 * 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 OR23 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE24 * USE OR OTHER DEALINGS IN THE SOFTWARE.25 *26 **************************************************************************/27 28#include "vmwgfx_drv.h"29#include "vmwgfx_devcaps.h"30#include "vmwgfx_kms.h"31 32#include <drm/vmwgfx_drm.h>33#include <linux/pci.h>34#include <linux/vmalloc.h>35 36int vmw_getparam_ioctl(struct drm_device *dev, void *data,37 struct drm_file *file_priv)38{39 struct vmw_private *dev_priv = vmw_priv(dev);40 struct drm_vmw_getparam_arg *param =41 (struct drm_vmw_getparam_arg *)data;42 struct vmw_fpriv *vmw_fp = vmw_fpriv(file_priv);43 44 switch (param->param) {45 case DRM_VMW_PARAM_NUM_STREAMS:46 param->value = vmw_overlay_num_overlays(dev_priv);47 break;48 case DRM_VMW_PARAM_NUM_FREE_STREAMS:49 param->value = vmw_overlay_num_free_overlays(dev_priv);50 break;51 case DRM_VMW_PARAM_3D:52 param->value = vmw_supports_3d(dev_priv) ? 1 : 0;53 break;54 case DRM_VMW_PARAM_HW_CAPS:55 param->value = dev_priv->capabilities;56 break;57 case DRM_VMW_PARAM_HW_CAPS2:58 param->value = dev_priv->capabilities2;59 break;60 case DRM_VMW_PARAM_FIFO_CAPS:61 param->value = vmw_fifo_caps(dev_priv);62 break;63 case DRM_VMW_PARAM_MAX_FB_SIZE:64 param->value = dev_priv->max_primary_mem;65 break;66 case DRM_VMW_PARAM_FIFO_HW_VERSION:67 {68 if ((dev_priv->capabilities & SVGA_CAP_GBOBJECTS))69 param->value = SVGA3D_HWVERSION_WS8_B1;70 else71 param->value = vmw_fifo_mem_read(72 dev_priv,73 ((vmw_fifo_caps(dev_priv) &74 SVGA_FIFO_CAP_3D_HWVERSION_REVISED) ?75 SVGA_FIFO_3D_HWVERSION_REVISED :76 SVGA_FIFO_3D_HWVERSION));77 break;78 }79 case DRM_VMW_PARAM_MAX_SURF_MEMORY:80 if ((dev_priv->capabilities & SVGA_CAP_GBOBJECTS) &&81 !vmw_fp->gb_aware)82 param->value = dev_priv->max_mob_pages * PAGE_SIZE / 2;83 else84 param->value = dev_priv->memory_size;85 break;86 case DRM_VMW_PARAM_3D_CAPS_SIZE:87 param->value = vmw_devcaps_size(dev_priv, vmw_fp->gb_aware);88 break;89 case DRM_VMW_PARAM_MAX_MOB_MEMORY:90 vmw_fp->gb_aware = true;91 param->value = dev_priv->max_mob_pages * PAGE_SIZE;92 break;93 case DRM_VMW_PARAM_MAX_MOB_SIZE:94 param->value = dev_priv->max_mob_size;95 break;96 case DRM_VMW_PARAM_SCREEN_TARGET:97 param->value =98 (dev_priv->active_display_unit == vmw_du_screen_target);99 break;100 case DRM_VMW_PARAM_DX:101 param->value = has_sm4_context(dev_priv);102 break;103 case DRM_VMW_PARAM_SM4_1:104 param->value = has_sm4_1_context(dev_priv);105 break;106 case DRM_VMW_PARAM_SM5:107 param->value = has_sm5_context(dev_priv);108 break;109 case DRM_VMW_PARAM_GL43:110 param->value = has_gl43_context(dev_priv);111 break;112 case DRM_VMW_PARAM_DEVICE_ID:113 param->value = to_pci_dev(dev_priv->drm.dev)->device;114 break;115 default:116 return -EINVAL;117 }118 119 return 0;120}121 122 123int vmw_get_cap_3d_ioctl(struct drm_device *dev, void *data,124 struct drm_file *file_priv)125{126 struct drm_vmw_get_3d_cap_arg *arg =127 (struct drm_vmw_get_3d_cap_arg *) data;128 struct vmw_private *dev_priv = vmw_priv(dev);129 uint32_t size;130 void __user *buffer = (void __user *)((unsigned long)(arg->buffer));131 void *bounce = NULL;132 int ret;133 struct vmw_fpriv *vmw_fp = vmw_fpriv(file_priv);134 135 if (unlikely(arg->pad64 != 0 || arg->max_size == 0)) {136 VMW_DEBUG_USER("Illegal GET_3D_CAP argument.\n");137 return -EINVAL;138 }139 140 size = vmw_devcaps_size(dev_priv, vmw_fp->gb_aware);141 if (unlikely(size == 0)) {142 DRM_ERROR("Failed to figure out the devcaps size (no 3D).\n");143 return -ENOMEM;144 }145 146 if (arg->max_size < size)147 size = arg->max_size;148 149 bounce = vzalloc(size);150 if (unlikely(bounce == NULL)) {151 DRM_ERROR("Failed to allocate bounce buffer for 3D caps.\n");152 return -ENOMEM;153 }154 155 ret = vmw_devcaps_copy(dev_priv, vmw_fp->gb_aware, bounce, size);156 if (unlikely (ret != 0))157 goto out_err;158 159 ret = copy_to_user(buffer, bounce, size);160 if (ret)161 ret = -EFAULT;162out_err:163 vfree(bounce);164 165 if (unlikely(ret != 0))166 DRM_ERROR("Failed to report 3D caps info.\n");167 168 return ret;169}170 171int vmw_present_ioctl(struct drm_device *dev, void *data,172 struct drm_file *file_priv)173{174 struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile;175 struct vmw_private *dev_priv = vmw_priv(dev);176 struct drm_vmw_present_arg *arg =177 (struct drm_vmw_present_arg *)data;178 struct vmw_surface *surface;179 struct drm_vmw_rect __user *clips_ptr;180 struct drm_vmw_rect *clips = NULL;181 struct drm_framebuffer *fb;182 struct vmw_framebuffer *vfb;183 struct vmw_resource *res;184 uint32_t num_clips;185 int ret;186 187 num_clips = arg->num_clips;188 clips_ptr = (struct drm_vmw_rect __user *)(unsigned long)arg->clips_ptr;189 190 if (unlikely(num_clips == 0))191 return 0;192 193 if (clips_ptr == NULL) {194 VMW_DEBUG_USER("Variable clips_ptr must be specified.\n");195 ret = -EINVAL;196 goto out_clips;197 }198 199 clips = kcalloc(num_clips, sizeof(*clips), GFP_KERNEL);200 if (clips == NULL) {201 DRM_ERROR("Failed to allocate clip rect list.\n");202 ret = -ENOMEM;203 goto out_clips;204 }205 206 ret = copy_from_user(clips, clips_ptr, num_clips * sizeof(*clips));207 if (ret) {208 DRM_ERROR("Failed to copy clip rects from userspace.\n");209 ret = -EFAULT;210 goto out_no_copy;211 }212 213 drm_modeset_lock_all(dev);214 215 fb = drm_framebuffer_lookup(dev, file_priv, arg->fb_id);216 if (!fb) {217 VMW_DEBUG_USER("Invalid framebuffer id.\n");218 ret = -ENOENT;219 goto out_no_fb;220 }221 vfb = vmw_framebuffer_to_vfb(fb);222 223 ret = vmw_user_resource_lookup_handle(dev_priv, tfile, arg->sid,224 user_surface_converter,225 &res);226 if (ret)227 goto out_no_surface;228 229 surface = vmw_res_to_srf(res);230 ret = vmw_kms_present(dev_priv, file_priv,231 vfb, surface, arg->sid,232 arg->dest_x, arg->dest_y,233 clips, num_clips);234 235 /* vmw_user_surface_lookup takes one ref so does new_fb */236 vmw_surface_unreference(&surface);237 238out_no_surface:239 drm_framebuffer_put(fb);240out_no_fb:241 drm_modeset_unlock_all(dev);242out_no_copy:243 kfree(clips);244out_clips:245 return ret;246}247 248int vmw_present_readback_ioctl(struct drm_device *dev, void *data,249 struct drm_file *file_priv)250{251 struct vmw_private *dev_priv = vmw_priv(dev);252 struct drm_vmw_present_readback_arg *arg =253 (struct drm_vmw_present_readback_arg *)data;254 struct drm_vmw_fence_rep __user *user_fence_rep =255 (struct drm_vmw_fence_rep __user *)256 (unsigned long)arg->fence_rep;257 struct drm_vmw_rect __user *clips_ptr;258 struct drm_vmw_rect *clips = NULL;259 struct drm_framebuffer *fb;260 struct vmw_framebuffer *vfb;261 uint32_t num_clips;262 int ret;263 264 num_clips = arg->num_clips;265 clips_ptr = (struct drm_vmw_rect __user *)(unsigned long)arg->clips_ptr;266 267 if (unlikely(num_clips == 0))268 return 0;269 270 if (clips_ptr == NULL) {271 VMW_DEBUG_USER("Argument clips_ptr must be specified.\n");272 ret = -EINVAL;273 goto out_clips;274 }275 276 clips = kcalloc(num_clips, sizeof(*clips), GFP_KERNEL);277 if (clips == NULL) {278 DRM_ERROR("Failed to allocate clip rect list.\n");279 ret = -ENOMEM;280 goto out_clips;281 }282 283 ret = copy_from_user(clips, clips_ptr, num_clips * sizeof(*clips));284 if (ret) {285 DRM_ERROR("Failed to copy clip rects from userspace.\n");286 ret = -EFAULT;287 goto out_no_copy;288 }289 290 drm_modeset_lock_all(dev);291 292 fb = drm_framebuffer_lookup(dev, file_priv, arg->fb_id);293 if (!fb) {294 VMW_DEBUG_USER("Invalid framebuffer id.\n");295 ret = -ENOENT;296 goto out_no_fb;297 }298 299 vfb = vmw_framebuffer_to_vfb(fb);300 if (!vfb->bo) {301 VMW_DEBUG_USER("Framebuffer not buffer backed.\n");302 ret = -EINVAL;303 goto out_no_ttm_lock;304 }305 306 ret = vmw_kms_readback(dev_priv, file_priv,307 vfb, user_fence_rep,308 clips, num_clips);309 310out_no_ttm_lock:311 drm_framebuffer_put(fb);312out_no_fb:313 drm_modeset_unlock_all(dev);314out_no_copy:315 kfree(clips);316out_clips:317 return ret;318}319