162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 OR MIT 262306a36Sopenharmony_ci/************************************************************************** 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * Copyright 2009-2023 VMware, Inc., Palo Alto, CA., USA 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a 762306a36Sopenharmony_ci * copy of this software and associated documentation files (the 862306a36Sopenharmony_ci * "Software"), to deal in the Software without restriction, including 962306a36Sopenharmony_ci * without limitation the rights to use, copy, modify, merge, publish, 1062306a36Sopenharmony_ci * distribute, sub license, and/or sell copies of the Software, and to 1162306a36Sopenharmony_ci * permit persons to whom the Software is furnished to do so, subject to 1262306a36Sopenharmony_ci * the following conditions: 1362306a36Sopenharmony_ci * 1462306a36Sopenharmony_ci * The above copyright notice and this permission notice (including the 1562306a36Sopenharmony_ci * next paragraph) shall be included in all copies or substantial portions 1662306a36Sopenharmony_ci * of the Software. 1762306a36Sopenharmony_ci * 1862306a36Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 1962306a36Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 2062306a36Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL 2162306a36Sopenharmony_ci * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, 2262306a36Sopenharmony_ci * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 2362306a36Sopenharmony_ci * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 2462306a36Sopenharmony_ci * USE OR OTHER DEALINGS IN THE SOFTWARE. 2562306a36Sopenharmony_ci * 2662306a36Sopenharmony_ci **************************************************************************/ 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_ci#include "vmwgfx_drv.h" 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_ci#include "vmwgfx_bo.h" 3262306a36Sopenharmony_ci#include "vmwgfx_binding.h" 3362306a36Sopenharmony_ci#include "vmwgfx_devcaps.h" 3462306a36Sopenharmony_ci#include "vmwgfx_mksstat.h" 3562306a36Sopenharmony_ci#include "ttm_object.h" 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_ci#include <drm/drm_aperture.h> 3862306a36Sopenharmony_ci#include <drm/drm_drv.h> 3962306a36Sopenharmony_ci#include <drm/drm_fbdev_generic.h> 4062306a36Sopenharmony_ci#include <drm/drm_gem_ttm_helper.h> 4162306a36Sopenharmony_ci#include <drm/drm_ioctl.h> 4262306a36Sopenharmony_ci#include <drm/drm_module.h> 4362306a36Sopenharmony_ci#include <drm/drm_sysfs.h> 4462306a36Sopenharmony_ci#include <drm/ttm/ttm_range_manager.h> 4562306a36Sopenharmony_ci#include <drm/ttm/ttm_placement.h> 4662306a36Sopenharmony_ci#include <generated/utsrelease.h> 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci#ifdef CONFIG_X86 4962306a36Sopenharmony_ci#include <asm/hypervisor.h> 5062306a36Sopenharmony_ci#endif 5162306a36Sopenharmony_ci#include <linux/cc_platform.h> 5262306a36Sopenharmony_ci#include <linux/dma-mapping.h> 5362306a36Sopenharmony_ci#include <linux/module.h> 5462306a36Sopenharmony_ci#include <linux/pci.h> 5562306a36Sopenharmony_ci#include <linux/version.h> 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ci#define VMWGFX_DRIVER_DESC "Linux drm driver for VMware graphics devices" 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_ci/* 6062306a36Sopenharmony_ci * Fully encoded drm commands. Might move to vmw_drm.h 6162306a36Sopenharmony_ci */ 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ci#define DRM_IOCTL_VMW_GET_PARAM \ 6462306a36Sopenharmony_ci DRM_IOWR(DRM_COMMAND_BASE + DRM_VMW_GET_PARAM, \ 6562306a36Sopenharmony_ci struct drm_vmw_getparam_arg) 6662306a36Sopenharmony_ci#define DRM_IOCTL_VMW_ALLOC_DMABUF \ 6762306a36Sopenharmony_ci DRM_IOWR(DRM_COMMAND_BASE + DRM_VMW_ALLOC_DMABUF, \ 6862306a36Sopenharmony_ci union drm_vmw_alloc_dmabuf_arg) 6962306a36Sopenharmony_ci#define DRM_IOCTL_VMW_UNREF_DMABUF \ 7062306a36Sopenharmony_ci DRM_IOW(DRM_COMMAND_BASE + DRM_VMW_UNREF_DMABUF, \ 7162306a36Sopenharmony_ci struct drm_vmw_unref_dmabuf_arg) 7262306a36Sopenharmony_ci#define DRM_IOCTL_VMW_CURSOR_BYPASS \ 7362306a36Sopenharmony_ci DRM_IOW(DRM_COMMAND_BASE + DRM_VMW_CURSOR_BYPASS, \ 7462306a36Sopenharmony_ci struct drm_vmw_cursor_bypass_arg) 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ci#define DRM_IOCTL_VMW_CONTROL_STREAM \ 7762306a36Sopenharmony_ci DRM_IOW(DRM_COMMAND_BASE + DRM_VMW_CONTROL_STREAM, \ 7862306a36Sopenharmony_ci struct drm_vmw_control_stream_arg) 7962306a36Sopenharmony_ci#define DRM_IOCTL_VMW_CLAIM_STREAM \ 8062306a36Sopenharmony_ci DRM_IOR(DRM_COMMAND_BASE + DRM_VMW_CLAIM_STREAM, \ 8162306a36Sopenharmony_ci struct drm_vmw_stream_arg) 8262306a36Sopenharmony_ci#define DRM_IOCTL_VMW_UNREF_STREAM \ 8362306a36Sopenharmony_ci DRM_IOW(DRM_COMMAND_BASE + DRM_VMW_UNREF_STREAM, \ 8462306a36Sopenharmony_ci struct drm_vmw_stream_arg) 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci#define DRM_IOCTL_VMW_CREATE_CONTEXT \ 8762306a36Sopenharmony_ci DRM_IOR(DRM_COMMAND_BASE + DRM_VMW_CREATE_CONTEXT, \ 8862306a36Sopenharmony_ci struct drm_vmw_context_arg) 8962306a36Sopenharmony_ci#define DRM_IOCTL_VMW_UNREF_CONTEXT \ 9062306a36Sopenharmony_ci DRM_IOW(DRM_COMMAND_BASE + DRM_VMW_UNREF_CONTEXT, \ 9162306a36Sopenharmony_ci struct drm_vmw_context_arg) 9262306a36Sopenharmony_ci#define DRM_IOCTL_VMW_CREATE_SURFACE \ 9362306a36Sopenharmony_ci DRM_IOWR(DRM_COMMAND_BASE + DRM_VMW_CREATE_SURFACE, \ 9462306a36Sopenharmony_ci union drm_vmw_surface_create_arg) 9562306a36Sopenharmony_ci#define DRM_IOCTL_VMW_UNREF_SURFACE \ 9662306a36Sopenharmony_ci DRM_IOW(DRM_COMMAND_BASE + DRM_VMW_UNREF_SURFACE, \ 9762306a36Sopenharmony_ci struct drm_vmw_surface_arg) 9862306a36Sopenharmony_ci#define DRM_IOCTL_VMW_REF_SURFACE \ 9962306a36Sopenharmony_ci DRM_IOWR(DRM_COMMAND_BASE + DRM_VMW_REF_SURFACE, \ 10062306a36Sopenharmony_ci union drm_vmw_surface_reference_arg) 10162306a36Sopenharmony_ci#define DRM_IOCTL_VMW_EXECBUF \ 10262306a36Sopenharmony_ci DRM_IOW(DRM_COMMAND_BASE + DRM_VMW_EXECBUF, \ 10362306a36Sopenharmony_ci struct drm_vmw_execbuf_arg) 10462306a36Sopenharmony_ci#define DRM_IOCTL_VMW_GET_3D_CAP \ 10562306a36Sopenharmony_ci DRM_IOW(DRM_COMMAND_BASE + DRM_VMW_GET_3D_CAP, \ 10662306a36Sopenharmony_ci struct drm_vmw_get_3d_cap_arg) 10762306a36Sopenharmony_ci#define DRM_IOCTL_VMW_FENCE_WAIT \ 10862306a36Sopenharmony_ci DRM_IOWR(DRM_COMMAND_BASE + DRM_VMW_FENCE_WAIT, \ 10962306a36Sopenharmony_ci struct drm_vmw_fence_wait_arg) 11062306a36Sopenharmony_ci#define DRM_IOCTL_VMW_FENCE_SIGNALED \ 11162306a36Sopenharmony_ci DRM_IOWR(DRM_COMMAND_BASE + DRM_VMW_FENCE_SIGNALED, \ 11262306a36Sopenharmony_ci struct drm_vmw_fence_signaled_arg) 11362306a36Sopenharmony_ci#define DRM_IOCTL_VMW_FENCE_UNREF \ 11462306a36Sopenharmony_ci DRM_IOW(DRM_COMMAND_BASE + DRM_VMW_FENCE_UNREF, \ 11562306a36Sopenharmony_ci struct drm_vmw_fence_arg) 11662306a36Sopenharmony_ci#define DRM_IOCTL_VMW_FENCE_EVENT \ 11762306a36Sopenharmony_ci DRM_IOW(DRM_COMMAND_BASE + DRM_VMW_FENCE_EVENT, \ 11862306a36Sopenharmony_ci struct drm_vmw_fence_event_arg) 11962306a36Sopenharmony_ci#define DRM_IOCTL_VMW_PRESENT \ 12062306a36Sopenharmony_ci DRM_IOW(DRM_COMMAND_BASE + DRM_VMW_PRESENT, \ 12162306a36Sopenharmony_ci struct drm_vmw_present_arg) 12262306a36Sopenharmony_ci#define DRM_IOCTL_VMW_PRESENT_READBACK \ 12362306a36Sopenharmony_ci DRM_IOW(DRM_COMMAND_BASE + DRM_VMW_PRESENT_READBACK, \ 12462306a36Sopenharmony_ci struct drm_vmw_present_readback_arg) 12562306a36Sopenharmony_ci#define DRM_IOCTL_VMW_UPDATE_LAYOUT \ 12662306a36Sopenharmony_ci DRM_IOW(DRM_COMMAND_BASE + DRM_VMW_UPDATE_LAYOUT, \ 12762306a36Sopenharmony_ci struct drm_vmw_update_layout_arg) 12862306a36Sopenharmony_ci#define DRM_IOCTL_VMW_CREATE_SHADER \ 12962306a36Sopenharmony_ci DRM_IOWR(DRM_COMMAND_BASE + DRM_VMW_CREATE_SHADER, \ 13062306a36Sopenharmony_ci struct drm_vmw_shader_create_arg) 13162306a36Sopenharmony_ci#define DRM_IOCTL_VMW_UNREF_SHADER \ 13262306a36Sopenharmony_ci DRM_IOW(DRM_COMMAND_BASE + DRM_VMW_UNREF_SHADER, \ 13362306a36Sopenharmony_ci struct drm_vmw_shader_arg) 13462306a36Sopenharmony_ci#define DRM_IOCTL_VMW_GB_SURFACE_CREATE \ 13562306a36Sopenharmony_ci DRM_IOWR(DRM_COMMAND_BASE + DRM_VMW_GB_SURFACE_CREATE, \ 13662306a36Sopenharmony_ci union drm_vmw_gb_surface_create_arg) 13762306a36Sopenharmony_ci#define DRM_IOCTL_VMW_GB_SURFACE_REF \ 13862306a36Sopenharmony_ci DRM_IOWR(DRM_COMMAND_BASE + DRM_VMW_GB_SURFACE_REF, \ 13962306a36Sopenharmony_ci union drm_vmw_gb_surface_reference_arg) 14062306a36Sopenharmony_ci#define DRM_IOCTL_VMW_SYNCCPU \ 14162306a36Sopenharmony_ci DRM_IOW(DRM_COMMAND_BASE + DRM_VMW_SYNCCPU, \ 14262306a36Sopenharmony_ci struct drm_vmw_synccpu_arg) 14362306a36Sopenharmony_ci#define DRM_IOCTL_VMW_CREATE_EXTENDED_CONTEXT \ 14462306a36Sopenharmony_ci DRM_IOWR(DRM_COMMAND_BASE + DRM_VMW_CREATE_EXTENDED_CONTEXT, \ 14562306a36Sopenharmony_ci struct drm_vmw_context_arg) 14662306a36Sopenharmony_ci#define DRM_IOCTL_VMW_GB_SURFACE_CREATE_EXT \ 14762306a36Sopenharmony_ci DRM_IOWR(DRM_COMMAND_BASE + DRM_VMW_GB_SURFACE_CREATE_EXT, \ 14862306a36Sopenharmony_ci union drm_vmw_gb_surface_create_ext_arg) 14962306a36Sopenharmony_ci#define DRM_IOCTL_VMW_GB_SURFACE_REF_EXT \ 15062306a36Sopenharmony_ci DRM_IOWR(DRM_COMMAND_BASE + DRM_VMW_GB_SURFACE_REF_EXT, \ 15162306a36Sopenharmony_ci union drm_vmw_gb_surface_reference_ext_arg) 15262306a36Sopenharmony_ci#define DRM_IOCTL_VMW_MSG \ 15362306a36Sopenharmony_ci DRM_IOWR(DRM_COMMAND_BASE + DRM_VMW_MSG, \ 15462306a36Sopenharmony_ci struct drm_vmw_msg_arg) 15562306a36Sopenharmony_ci#define DRM_IOCTL_VMW_MKSSTAT_RESET \ 15662306a36Sopenharmony_ci DRM_IO(DRM_COMMAND_BASE + DRM_VMW_MKSSTAT_RESET) 15762306a36Sopenharmony_ci#define DRM_IOCTL_VMW_MKSSTAT_ADD \ 15862306a36Sopenharmony_ci DRM_IOWR(DRM_COMMAND_BASE + DRM_VMW_MKSSTAT_ADD, \ 15962306a36Sopenharmony_ci struct drm_vmw_mksstat_add_arg) 16062306a36Sopenharmony_ci#define DRM_IOCTL_VMW_MKSSTAT_REMOVE \ 16162306a36Sopenharmony_ci DRM_IOW(DRM_COMMAND_BASE + DRM_VMW_MKSSTAT_REMOVE, \ 16262306a36Sopenharmony_ci struct drm_vmw_mksstat_remove_arg) 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_ci/* 16562306a36Sopenharmony_ci * Ioctl definitions. 16662306a36Sopenharmony_ci */ 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_cistatic const struct drm_ioctl_desc vmw_ioctls[] = { 16962306a36Sopenharmony_ci DRM_IOCTL_DEF_DRV(VMW_GET_PARAM, vmw_getparam_ioctl, 17062306a36Sopenharmony_ci DRM_RENDER_ALLOW), 17162306a36Sopenharmony_ci DRM_IOCTL_DEF_DRV(VMW_ALLOC_DMABUF, vmw_gem_object_create_ioctl, 17262306a36Sopenharmony_ci DRM_RENDER_ALLOW), 17362306a36Sopenharmony_ci DRM_IOCTL_DEF_DRV(VMW_UNREF_DMABUF, vmw_bo_unref_ioctl, 17462306a36Sopenharmony_ci DRM_RENDER_ALLOW), 17562306a36Sopenharmony_ci DRM_IOCTL_DEF_DRV(VMW_CURSOR_BYPASS, 17662306a36Sopenharmony_ci vmw_kms_cursor_bypass_ioctl, 17762306a36Sopenharmony_ci DRM_MASTER), 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_ci DRM_IOCTL_DEF_DRV(VMW_CONTROL_STREAM, vmw_overlay_ioctl, 18062306a36Sopenharmony_ci DRM_MASTER), 18162306a36Sopenharmony_ci DRM_IOCTL_DEF_DRV(VMW_CLAIM_STREAM, vmw_stream_claim_ioctl, 18262306a36Sopenharmony_ci DRM_MASTER), 18362306a36Sopenharmony_ci DRM_IOCTL_DEF_DRV(VMW_UNREF_STREAM, vmw_stream_unref_ioctl, 18462306a36Sopenharmony_ci DRM_MASTER), 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_ci DRM_IOCTL_DEF_DRV(VMW_CREATE_CONTEXT, vmw_context_define_ioctl, 18762306a36Sopenharmony_ci DRM_RENDER_ALLOW), 18862306a36Sopenharmony_ci DRM_IOCTL_DEF_DRV(VMW_UNREF_CONTEXT, vmw_context_destroy_ioctl, 18962306a36Sopenharmony_ci DRM_RENDER_ALLOW), 19062306a36Sopenharmony_ci DRM_IOCTL_DEF_DRV(VMW_CREATE_SURFACE, vmw_surface_define_ioctl, 19162306a36Sopenharmony_ci DRM_RENDER_ALLOW), 19262306a36Sopenharmony_ci DRM_IOCTL_DEF_DRV(VMW_UNREF_SURFACE, vmw_surface_destroy_ioctl, 19362306a36Sopenharmony_ci DRM_RENDER_ALLOW), 19462306a36Sopenharmony_ci DRM_IOCTL_DEF_DRV(VMW_REF_SURFACE, vmw_surface_reference_ioctl, 19562306a36Sopenharmony_ci DRM_RENDER_ALLOW), 19662306a36Sopenharmony_ci DRM_IOCTL_DEF_DRV(VMW_EXECBUF, vmw_execbuf_ioctl, 19762306a36Sopenharmony_ci DRM_RENDER_ALLOW), 19862306a36Sopenharmony_ci DRM_IOCTL_DEF_DRV(VMW_FENCE_WAIT, vmw_fence_obj_wait_ioctl, 19962306a36Sopenharmony_ci DRM_RENDER_ALLOW), 20062306a36Sopenharmony_ci DRM_IOCTL_DEF_DRV(VMW_FENCE_SIGNALED, 20162306a36Sopenharmony_ci vmw_fence_obj_signaled_ioctl, 20262306a36Sopenharmony_ci DRM_RENDER_ALLOW), 20362306a36Sopenharmony_ci DRM_IOCTL_DEF_DRV(VMW_FENCE_UNREF, vmw_fence_obj_unref_ioctl, 20462306a36Sopenharmony_ci DRM_RENDER_ALLOW), 20562306a36Sopenharmony_ci DRM_IOCTL_DEF_DRV(VMW_FENCE_EVENT, vmw_fence_event_ioctl, 20662306a36Sopenharmony_ci DRM_RENDER_ALLOW), 20762306a36Sopenharmony_ci DRM_IOCTL_DEF_DRV(VMW_GET_3D_CAP, vmw_get_cap_3d_ioctl, 20862306a36Sopenharmony_ci DRM_RENDER_ALLOW), 20962306a36Sopenharmony_ci 21062306a36Sopenharmony_ci /* these allow direct access to the framebuffers mark as master only */ 21162306a36Sopenharmony_ci DRM_IOCTL_DEF_DRV(VMW_PRESENT, vmw_present_ioctl, 21262306a36Sopenharmony_ci DRM_MASTER | DRM_AUTH), 21362306a36Sopenharmony_ci DRM_IOCTL_DEF_DRV(VMW_PRESENT_READBACK, 21462306a36Sopenharmony_ci vmw_present_readback_ioctl, 21562306a36Sopenharmony_ci DRM_MASTER | DRM_AUTH), 21662306a36Sopenharmony_ci /* 21762306a36Sopenharmony_ci * The permissions of the below ioctl are overridden in 21862306a36Sopenharmony_ci * vmw_generic_ioctl(). We require either 21962306a36Sopenharmony_ci * DRM_MASTER or capable(CAP_SYS_ADMIN). 22062306a36Sopenharmony_ci */ 22162306a36Sopenharmony_ci DRM_IOCTL_DEF_DRV(VMW_UPDATE_LAYOUT, 22262306a36Sopenharmony_ci vmw_kms_update_layout_ioctl, 22362306a36Sopenharmony_ci DRM_RENDER_ALLOW), 22462306a36Sopenharmony_ci DRM_IOCTL_DEF_DRV(VMW_CREATE_SHADER, 22562306a36Sopenharmony_ci vmw_shader_define_ioctl, 22662306a36Sopenharmony_ci DRM_RENDER_ALLOW), 22762306a36Sopenharmony_ci DRM_IOCTL_DEF_DRV(VMW_UNREF_SHADER, 22862306a36Sopenharmony_ci vmw_shader_destroy_ioctl, 22962306a36Sopenharmony_ci DRM_RENDER_ALLOW), 23062306a36Sopenharmony_ci DRM_IOCTL_DEF_DRV(VMW_GB_SURFACE_CREATE, 23162306a36Sopenharmony_ci vmw_gb_surface_define_ioctl, 23262306a36Sopenharmony_ci DRM_RENDER_ALLOW), 23362306a36Sopenharmony_ci DRM_IOCTL_DEF_DRV(VMW_GB_SURFACE_REF, 23462306a36Sopenharmony_ci vmw_gb_surface_reference_ioctl, 23562306a36Sopenharmony_ci DRM_RENDER_ALLOW), 23662306a36Sopenharmony_ci DRM_IOCTL_DEF_DRV(VMW_SYNCCPU, 23762306a36Sopenharmony_ci vmw_user_bo_synccpu_ioctl, 23862306a36Sopenharmony_ci DRM_RENDER_ALLOW), 23962306a36Sopenharmony_ci DRM_IOCTL_DEF_DRV(VMW_CREATE_EXTENDED_CONTEXT, 24062306a36Sopenharmony_ci vmw_extended_context_define_ioctl, 24162306a36Sopenharmony_ci DRM_RENDER_ALLOW), 24262306a36Sopenharmony_ci DRM_IOCTL_DEF_DRV(VMW_GB_SURFACE_CREATE_EXT, 24362306a36Sopenharmony_ci vmw_gb_surface_define_ext_ioctl, 24462306a36Sopenharmony_ci DRM_RENDER_ALLOW), 24562306a36Sopenharmony_ci DRM_IOCTL_DEF_DRV(VMW_GB_SURFACE_REF_EXT, 24662306a36Sopenharmony_ci vmw_gb_surface_reference_ext_ioctl, 24762306a36Sopenharmony_ci DRM_RENDER_ALLOW), 24862306a36Sopenharmony_ci DRM_IOCTL_DEF_DRV(VMW_MSG, 24962306a36Sopenharmony_ci vmw_msg_ioctl, 25062306a36Sopenharmony_ci DRM_RENDER_ALLOW), 25162306a36Sopenharmony_ci DRM_IOCTL_DEF_DRV(VMW_MKSSTAT_RESET, 25262306a36Sopenharmony_ci vmw_mksstat_reset_ioctl, 25362306a36Sopenharmony_ci DRM_RENDER_ALLOW), 25462306a36Sopenharmony_ci DRM_IOCTL_DEF_DRV(VMW_MKSSTAT_ADD, 25562306a36Sopenharmony_ci vmw_mksstat_add_ioctl, 25662306a36Sopenharmony_ci DRM_RENDER_ALLOW), 25762306a36Sopenharmony_ci DRM_IOCTL_DEF_DRV(VMW_MKSSTAT_REMOVE, 25862306a36Sopenharmony_ci vmw_mksstat_remove_ioctl, 25962306a36Sopenharmony_ci DRM_RENDER_ALLOW), 26062306a36Sopenharmony_ci}; 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_cistatic const struct pci_device_id vmw_pci_id_list[] = { 26362306a36Sopenharmony_ci { PCI_DEVICE(PCI_VENDOR_ID_VMWARE, VMWGFX_PCI_ID_SVGA2) }, 26462306a36Sopenharmony_ci { PCI_DEVICE(PCI_VENDOR_ID_VMWARE, VMWGFX_PCI_ID_SVGA3) }, 26562306a36Sopenharmony_ci { } 26662306a36Sopenharmony_ci}; 26762306a36Sopenharmony_ciMODULE_DEVICE_TABLE(pci, vmw_pci_id_list); 26862306a36Sopenharmony_ci 26962306a36Sopenharmony_cistatic int vmw_restrict_iommu; 27062306a36Sopenharmony_cistatic int vmw_force_coherent; 27162306a36Sopenharmony_cistatic int vmw_restrict_dma_mask; 27262306a36Sopenharmony_cistatic int vmw_assume_16bpp; 27362306a36Sopenharmony_ci 27462306a36Sopenharmony_cistatic int vmw_probe(struct pci_dev *, const struct pci_device_id *); 27562306a36Sopenharmony_cistatic int vmwgfx_pm_notifier(struct notifier_block *nb, unsigned long val, 27662306a36Sopenharmony_ci void *ptr); 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_ciMODULE_PARM_DESC(restrict_iommu, "Try to limit IOMMU usage for TTM pages"); 27962306a36Sopenharmony_cimodule_param_named(restrict_iommu, vmw_restrict_iommu, int, 0600); 28062306a36Sopenharmony_ciMODULE_PARM_DESC(force_coherent, "Force coherent TTM pages"); 28162306a36Sopenharmony_cimodule_param_named(force_coherent, vmw_force_coherent, int, 0600); 28262306a36Sopenharmony_ciMODULE_PARM_DESC(restrict_dma_mask, "Restrict DMA mask to 44 bits with IOMMU"); 28362306a36Sopenharmony_cimodule_param_named(restrict_dma_mask, vmw_restrict_dma_mask, int, 0600); 28462306a36Sopenharmony_ciMODULE_PARM_DESC(assume_16bpp, "Assume 16-bpp when filtering modes"); 28562306a36Sopenharmony_cimodule_param_named(assume_16bpp, vmw_assume_16bpp, int, 0600); 28662306a36Sopenharmony_ci 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_cistruct bitmap_name { 28962306a36Sopenharmony_ci uint32 value; 29062306a36Sopenharmony_ci const char *name; 29162306a36Sopenharmony_ci}; 29262306a36Sopenharmony_ci 29362306a36Sopenharmony_cistatic const struct bitmap_name cap1_names[] = { 29462306a36Sopenharmony_ci { SVGA_CAP_RECT_COPY, "rect copy" }, 29562306a36Sopenharmony_ci { SVGA_CAP_CURSOR, "cursor" }, 29662306a36Sopenharmony_ci { SVGA_CAP_CURSOR_BYPASS, "cursor bypass" }, 29762306a36Sopenharmony_ci { SVGA_CAP_CURSOR_BYPASS_2, "cursor bypass 2" }, 29862306a36Sopenharmony_ci { SVGA_CAP_8BIT_EMULATION, "8bit emulation" }, 29962306a36Sopenharmony_ci { SVGA_CAP_ALPHA_CURSOR, "alpha cursor" }, 30062306a36Sopenharmony_ci { SVGA_CAP_3D, "3D" }, 30162306a36Sopenharmony_ci { SVGA_CAP_EXTENDED_FIFO, "extended fifo" }, 30262306a36Sopenharmony_ci { SVGA_CAP_MULTIMON, "multimon" }, 30362306a36Sopenharmony_ci { SVGA_CAP_PITCHLOCK, "pitchlock" }, 30462306a36Sopenharmony_ci { SVGA_CAP_IRQMASK, "irq mask" }, 30562306a36Sopenharmony_ci { SVGA_CAP_DISPLAY_TOPOLOGY, "display topology" }, 30662306a36Sopenharmony_ci { SVGA_CAP_GMR, "gmr" }, 30762306a36Sopenharmony_ci { SVGA_CAP_TRACES, "traces" }, 30862306a36Sopenharmony_ci { SVGA_CAP_GMR2, "gmr2" }, 30962306a36Sopenharmony_ci { SVGA_CAP_SCREEN_OBJECT_2, "screen object 2" }, 31062306a36Sopenharmony_ci { SVGA_CAP_COMMAND_BUFFERS, "command buffers" }, 31162306a36Sopenharmony_ci { SVGA_CAP_CMD_BUFFERS_2, "command buffers 2" }, 31262306a36Sopenharmony_ci { SVGA_CAP_GBOBJECTS, "gbobject" }, 31362306a36Sopenharmony_ci { SVGA_CAP_DX, "dx" }, 31462306a36Sopenharmony_ci { SVGA_CAP_HP_CMD_QUEUE, "hp cmd queue" }, 31562306a36Sopenharmony_ci { SVGA_CAP_NO_BB_RESTRICTION, "no bb restriction" }, 31662306a36Sopenharmony_ci { SVGA_CAP_CAP2_REGISTER, "cap2 register" }, 31762306a36Sopenharmony_ci}; 31862306a36Sopenharmony_ci 31962306a36Sopenharmony_ci 32062306a36Sopenharmony_cistatic const struct bitmap_name cap2_names[] = { 32162306a36Sopenharmony_ci { SVGA_CAP2_GROW_OTABLE, "grow otable" }, 32262306a36Sopenharmony_ci { SVGA_CAP2_INTRA_SURFACE_COPY, "intra surface copy" }, 32362306a36Sopenharmony_ci { SVGA_CAP2_DX2, "dx2" }, 32462306a36Sopenharmony_ci { SVGA_CAP2_GB_MEMSIZE_2, "gb memsize 2" }, 32562306a36Sopenharmony_ci { SVGA_CAP2_SCREENDMA_REG, "screendma reg" }, 32662306a36Sopenharmony_ci { SVGA_CAP2_OTABLE_PTDEPTH_2, "otable ptdepth2" }, 32762306a36Sopenharmony_ci { SVGA_CAP2_NON_MS_TO_MS_STRETCHBLT, "non ms to ms stretchblt" }, 32862306a36Sopenharmony_ci { SVGA_CAP2_CURSOR_MOB, "cursor mob" }, 32962306a36Sopenharmony_ci { SVGA_CAP2_MSHINT, "mshint" }, 33062306a36Sopenharmony_ci { SVGA_CAP2_CB_MAX_SIZE_4MB, "cb max size 4mb" }, 33162306a36Sopenharmony_ci { SVGA_CAP2_DX3, "dx3" }, 33262306a36Sopenharmony_ci { SVGA_CAP2_FRAME_TYPE, "frame type" }, 33362306a36Sopenharmony_ci { SVGA_CAP2_COTABLE_COPY, "cotable copy" }, 33462306a36Sopenharmony_ci { SVGA_CAP2_TRACE_FULL_FB, "trace full fb" }, 33562306a36Sopenharmony_ci { SVGA_CAP2_EXTRA_REGS, "extra regs" }, 33662306a36Sopenharmony_ci { SVGA_CAP2_LO_STAGING, "lo staging" }, 33762306a36Sopenharmony_ci}; 33862306a36Sopenharmony_ci 33962306a36Sopenharmony_cistatic void vmw_print_bitmap(struct drm_device *drm, 34062306a36Sopenharmony_ci const char *prefix, uint32_t bitmap, 34162306a36Sopenharmony_ci const struct bitmap_name *bnames, 34262306a36Sopenharmony_ci uint32_t num_names) 34362306a36Sopenharmony_ci{ 34462306a36Sopenharmony_ci char buf[512]; 34562306a36Sopenharmony_ci uint32_t i; 34662306a36Sopenharmony_ci uint32_t offset = 0; 34762306a36Sopenharmony_ci for (i = 0; i < num_names; ++i) { 34862306a36Sopenharmony_ci if ((bitmap & bnames[i].value) != 0) { 34962306a36Sopenharmony_ci offset += snprintf(buf + offset, 35062306a36Sopenharmony_ci ARRAY_SIZE(buf) - offset, 35162306a36Sopenharmony_ci "%s, ", bnames[i].name); 35262306a36Sopenharmony_ci bitmap &= ~bnames[i].value; 35362306a36Sopenharmony_ci } 35462306a36Sopenharmony_ci } 35562306a36Sopenharmony_ci 35662306a36Sopenharmony_ci drm_info(drm, "%s: %s\n", prefix, buf); 35762306a36Sopenharmony_ci if (bitmap != 0) 35862306a36Sopenharmony_ci drm_dbg(drm, "%s: unknown enums: %x\n", prefix, bitmap); 35962306a36Sopenharmony_ci} 36062306a36Sopenharmony_ci 36162306a36Sopenharmony_ci 36262306a36Sopenharmony_cistatic void vmw_print_sm_type(struct vmw_private *dev_priv) 36362306a36Sopenharmony_ci{ 36462306a36Sopenharmony_ci static const char *names[] = { 36562306a36Sopenharmony_ci [VMW_SM_LEGACY] = "Legacy", 36662306a36Sopenharmony_ci [VMW_SM_4] = "SM4", 36762306a36Sopenharmony_ci [VMW_SM_4_1] = "SM4_1", 36862306a36Sopenharmony_ci [VMW_SM_5] = "SM_5", 36962306a36Sopenharmony_ci [VMW_SM_5_1X] = "SM_5_1X", 37062306a36Sopenharmony_ci [VMW_SM_MAX] = "Invalid" 37162306a36Sopenharmony_ci }; 37262306a36Sopenharmony_ci BUILD_BUG_ON(ARRAY_SIZE(names) != (VMW_SM_MAX + 1)); 37362306a36Sopenharmony_ci drm_info(&dev_priv->drm, "Available shader model: %s.\n", 37462306a36Sopenharmony_ci names[dev_priv->sm_type]); 37562306a36Sopenharmony_ci} 37662306a36Sopenharmony_ci 37762306a36Sopenharmony_ci/** 37862306a36Sopenharmony_ci * vmw_dummy_query_bo_create - create a bo to hold a dummy query result 37962306a36Sopenharmony_ci * 38062306a36Sopenharmony_ci * @dev_priv: A device private structure. 38162306a36Sopenharmony_ci * 38262306a36Sopenharmony_ci * This function creates a small buffer object that holds the query 38362306a36Sopenharmony_ci * result for dummy queries emitted as query barriers. 38462306a36Sopenharmony_ci * The function will then map the first page and initialize a pending 38562306a36Sopenharmony_ci * occlusion query result structure, Finally it will unmap the buffer. 38662306a36Sopenharmony_ci * No interruptible waits are done within this function. 38762306a36Sopenharmony_ci * 38862306a36Sopenharmony_ci * Returns an error if bo creation or initialization fails. 38962306a36Sopenharmony_ci */ 39062306a36Sopenharmony_cistatic int vmw_dummy_query_bo_create(struct vmw_private *dev_priv) 39162306a36Sopenharmony_ci{ 39262306a36Sopenharmony_ci int ret; 39362306a36Sopenharmony_ci struct vmw_bo *vbo; 39462306a36Sopenharmony_ci struct ttm_bo_kmap_obj map; 39562306a36Sopenharmony_ci volatile SVGA3dQueryResult *result; 39662306a36Sopenharmony_ci bool dummy; 39762306a36Sopenharmony_ci struct vmw_bo_params bo_params = { 39862306a36Sopenharmony_ci .domain = VMW_BO_DOMAIN_SYS, 39962306a36Sopenharmony_ci .busy_domain = VMW_BO_DOMAIN_SYS, 40062306a36Sopenharmony_ci .bo_type = ttm_bo_type_kernel, 40162306a36Sopenharmony_ci .size = PAGE_SIZE, 40262306a36Sopenharmony_ci .pin = true 40362306a36Sopenharmony_ci }; 40462306a36Sopenharmony_ci 40562306a36Sopenharmony_ci /* 40662306a36Sopenharmony_ci * Create the vbo as pinned, so that a tryreserve will 40762306a36Sopenharmony_ci * immediately succeed. This is because we're the only 40862306a36Sopenharmony_ci * user of the bo currently. 40962306a36Sopenharmony_ci */ 41062306a36Sopenharmony_ci ret = vmw_bo_create(dev_priv, &bo_params, &vbo); 41162306a36Sopenharmony_ci if (unlikely(ret != 0)) 41262306a36Sopenharmony_ci return ret; 41362306a36Sopenharmony_ci 41462306a36Sopenharmony_ci ret = ttm_bo_reserve(&vbo->tbo, false, true, NULL); 41562306a36Sopenharmony_ci BUG_ON(ret != 0); 41662306a36Sopenharmony_ci vmw_bo_pin_reserved(vbo, true); 41762306a36Sopenharmony_ci 41862306a36Sopenharmony_ci ret = ttm_bo_kmap(&vbo->tbo, 0, 1, &map); 41962306a36Sopenharmony_ci if (likely(ret == 0)) { 42062306a36Sopenharmony_ci result = ttm_kmap_obj_virtual(&map, &dummy); 42162306a36Sopenharmony_ci result->totalSize = sizeof(*result); 42262306a36Sopenharmony_ci result->state = SVGA3D_QUERYSTATE_PENDING; 42362306a36Sopenharmony_ci result->result32 = 0xff; 42462306a36Sopenharmony_ci ttm_bo_kunmap(&map); 42562306a36Sopenharmony_ci } 42662306a36Sopenharmony_ci vmw_bo_pin_reserved(vbo, false); 42762306a36Sopenharmony_ci ttm_bo_unreserve(&vbo->tbo); 42862306a36Sopenharmony_ci 42962306a36Sopenharmony_ci if (unlikely(ret != 0)) { 43062306a36Sopenharmony_ci DRM_ERROR("Dummy query buffer map failed.\n"); 43162306a36Sopenharmony_ci vmw_bo_unreference(&vbo); 43262306a36Sopenharmony_ci } else 43362306a36Sopenharmony_ci dev_priv->dummy_query_bo = vbo; 43462306a36Sopenharmony_ci 43562306a36Sopenharmony_ci return ret; 43662306a36Sopenharmony_ci} 43762306a36Sopenharmony_ci 43862306a36Sopenharmony_cistatic int vmw_device_init(struct vmw_private *dev_priv) 43962306a36Sopenharmony_ci{ 44062306a36Sopenharmony_ci bool uses_fb_traces = false; 44162306a36Sopenharmony_ci 44262306a36Sopenharmony_ci dev_priv->enable_state = vmw_read(dev_priv, SVGA_REG_ENABLE); 44362306a36Sopenharmony_ci dev_priv->config_done_state = vmw_read(dev_priv, SVGA_REG_CONFIG_DONE); 44462306a36Sopenharmony_ci dev_priv->traces_state = vmw_read(dev_priv, SVGA_REG_TRACES); 44562306a36Sopenharmony_ci 44662306a36Sopenharmony_ci vmw_write(dev_priv, SVGA_REG_ENABLE, SVGA_REG_ENABLE_ENABLE | 44762306a36Sopenharmony_ci SVGA_REG_ENABLE_HIDE); 44862306a36Sopenharmony_ci 44962306a36Sopenharmony_ci uses_fb_traces = !vmw_cmd_supported(dev_priv) && 45062306a36Sopenharmony_ci (dev_priv->capabilities & SVGA_CAP_TRACES) != 0; 45162306a36Sopenharmony_ci 45262306a36Sopenharmony_ci vmw_write(dev_priv, SVGA_REG_TRACES, uses_fb_traces); 45362306a36Sopenharmony_ci dev_priv->fifo = vmw_fifo_create(dev_priv); 45462306a36Sopenharmony_ci if (IS_ERR(dev_priv->fifo)) { 45562306a36Sopenharmony_ci int err = PTR_ERR(dev_priv->fifo); 45662306a36Sopenharmony_ci dev_priv->fifo = NULL; 45762306a36Sopenharmony_ci return err; 45862306a36Sopenharmony_ci } else if (!dev_priv->fifo) { 45962306a36Sopenharmony_ci vmw_write(dev_priv, SVGA_REG_CONFIG_DONE, 1); 46062306a36Sopenharmony_ci } 46162306a36Sopenharmony_ci 46262306a36Sopenharmony_ci dev_priv->last_read_seqno = vmw_fence_read(dev_priv); 46362306a36Sopenharmony_ci atomic_set(&dev_priv->marker_seq, dev_priv->last_read_seqno); 46462306a36Sopenharmony_ci return 0; 46562306a36Sopenharmony_ci} 46662306a36Sopenharmony_ci 46762306a36Sopenharmony_cistatic void vmw_device_fini(struct vmw_private *vmw) 46862306a36Sopenharmony_ci{ 46962306a36Sopenharmony_ci /* 47062306a36Sopenharmony_ci * Legacy sync 47162306a36Sopenharmony_ci */ 47262306a36Sopenharmony_ci vmw_write(vmw, SVGA_REG_SYNC, SVGA_SYNC_GENERIC); 47362306a36Sopenharmony_ci while (vmw_read(vmw, SVGA_REG_BUSY) != 0) 47462306a36Sopenharmony_ci ; 47562306a36Sopenharmony_ci 47662306a36Sopenharmony_ci vmw->last_read_seqno = vmw_fence_read(vmw); 47762306a36Sopenharmony_ci 47862306a36Sopenharmony_ci vmw_write(vmw, SVGA_REG_CONFIG_DONE, 47962306a36Sopenharmony_ci vmw->config_done_state); 48062306a36Sopenharmony_ci vmw_write(vmw, SVGA_REG_ENABLE, 48162306a36Sopenharmony_ci vmw->enable_state); 48262306a36Sopenharmony_ci vmw_write(vmw, SVGA_REG_TRACES, 48362306a36Sopenharmony_ci vmw->traces_state); 48462306a36Sopenharmony_ci 48562306a36Sopenharmony_ci vmw_fifo_destroy(vmw); 48662306a36Sopenharmony_ci} 48762306a36Sopenharmony_ci 48862306a36Sopenharmony_ci/** 48962306a36Sopenharmony_ci * vmw_request_device_late - Perform late device setup 49062306a36Sopenharmony_ci * 49162306a36Sopenharmony_ci * @dev_priv: Pointer to device private. 49262306a36Sopenharmony_ci * 49362306a36Sopenharmony_ci * This function performs setup of otables and enables large command 49462306a36Sopenharmony_ci * buffer submission. These tasks are split out to a separate function 49562306a36Sopenharmony_ci * because it reverts vmw_release_device_early and is intended to be used 49662306a36Sopenharmony_ci * by an error path in the hibernation code. 49762306a36Sopenharmony_ci */ 49862306a36Sopenharmony_cistatic int vmw_request_device_late(struct vmw_private *dev_priv) 49962306a36Sopenharmony_ci{ 50062306a36Sopenharmony_ci int ret; 50162306a36Sopenharmony_ci 50262306a36Sopenharmony_ci if (dev_priv->has_mob) { 50362306a36Sopenharmony_ci ret = vmw_otables_setup(dev_priv); 50462306a36Sopenharmony_ci if (unlikely(ret != 0)) { 50562306a36Sopenharmony_ci DRM_ERROR("Unable to initialize " 50662306a36Sopenharmony_ci "guest Memory OBjects.\n"); 50762306a36Sopenharmony_ci return ret; 50862306a36Sopenharmony_ci } 50962306a36Sopenharmony_ci } 51062306a36Sopenharmony_ci 51162306a36Sopenharmony_ci if (dev_priv->cman) { 51262306a36Sopenharmony_ci ret = vmw_cmdbuf_set_pool_size(dev_priv->cman, 256*4096); 51362306a36Sopenharmony_ci if (ret) { 51462306a36Sopenharmony_ci struct vmw_cmdbuf_man *man = dev_priv->cman; 51562306a36Sopenharmony_ci 51662306a36Sopenharmony_ci dev_priv->cman = NULL; 51762306a36Sopenharmony_ci vmw_cmdbuf_man_destroy(man); 51862306a36Sopenharmony_ci } 51962306a36Sopenharmony_ci } 52062306a36Sopenharmony_ci 52162306a36Sopenharmony_ci return 0; 52262306a36Sopenharmony_ci} 52362306a36Sopenharmony_ci 52462306a36Sopenharmony_cistatic int vmw_request_device(struct vmw_private *dev_priv) 52562306a36Sopenharmony_ci{ 52662306a36Sopenharmony_ci int ret; 52762306a36Sopenharmony_ci 52862306a36Sopenharmony_ci ret = vmw_device_init(dev_priv); 52962306a36Sopenharmony_ci if (unlikely(ret != 0)) { 53062306a36Sopenharmony_ci DRM_ERROR("Unable to initialize the device.\n"); 53162306a36Sopenharmony_ci return ret; 53262306a36Sopenharmony_ci } 53362306a36Sopenharmony_ci vmw_fence_fifo_up(dev_priv->fman); 53462306a36Sopenharmony_ci dev_priv->cman = vmw_cmdbuf_man_create(dev_priv); 53562306a36Sopenharmony_ci if (IS_ERR(dev_priv->cman)) { 53662306a36Sopenharmony_ci dev_priv->cman = NULL; 53762306a36Sopenharmony_ci dev_priv->sm_type = VMW_SM_LEGACY; 53862306a36Sopenharmony_ci } 53962306a36Sopenharmony_ci 54062306a36Sopenharmony_ci ret = vmw_request_device_late(dev_priv); 54162306a36Sopenharmony_ci if (ret) 54262306a36Sopenharmony_ci goto out_no_mob; 54362306a36Sopenharmony_ci 54462306a36Sopenharmony_ci ret = vmw_dummy_query_bo_create(dev_priv); 54562306a36Sopenharmony_ci if (unlikely(ret != 0)) 54662306a36Sopenharmony_ci goto out_no_query_bo; 54762306a36Sopenharmony_ci 54862306a36Sopenharmony_ci return 0; 54962306a36Sopenharmony_ci 55062306a36Sopenharmony_ciout_no_query_bo: 55162306a36Sopenharmony_ci if (dev_priv->cman) 55262306a36Sopenharmony_ci vmw_cmdbuf_remove_pool(dev_priv->cman); 55362306a36Sopenharmony_ci if (dev_priv->has_mob) { 55462306a36Sopenharmony_ci struct ttm_resource_manager *man; 55562306a36Sopenharmony_ci 55662306a36Sopenharmony_ci man = ttm_manager_type(&dev_priv->bdev, VMW_PL_MOB); 55762306a36Sopenharmony_ci ttm_resource_manager_evict_all(&dev_priv->bdev, man); 55862306a36Sopenharmony_ci vmw_otables_takedown(dev_priv); 55962306a36Sopenharmony_ci } 56062306a36Sopenharmony_ci if (dev_priv->cman) 56162306a36Sopenharmony_ci vmw_cmdbuf_man_destroy(dev_priv->cman); 56262306a36Sopenharmony_ciout_no_mob: 56362306a36Sopenharmony_ci vmw_fence_fifo_down(dev_priv->fman); 56462306a36Sopenharmony_ci vmw_device_fini(dev_priv); 56562306a36Sopenharmony_ci return ret; 56662306a36Sopenharmony_ci} 56762306a36Sopenharmony_ci 56862306a36Sopenharmony_ci/** 56962306a36Sopenharmony_ci * vmw_release_device_early - Early part of fifo takedown. 57062306a36Sopenharmony_ci * 57162306a36Sopenharmony_ci * @dev_priv: Pointer to device private struct. 57262306a36Sopenharmony_ci * 57362306a36Sopenharmony_ci * This is the first part of command submission takedown, to be called before 57462306a36Sopenharmony_ci * buffer management is taken down. 57562306a36Sopenharmony_ci */ 57662306a36Sopenharmony_cistatic void vmw_release_device_early(struct vmw_private *dev_priv) 57762306a36Sopenharmony_ci{ 57862306a36Sopenharmony_ci /* 57962306a36Sopenharmony_ci * Previous destructions should've released 58062306a36Sopenharmony_ci * the pinned bo. 58162306a36Sopenharmony_ci */ 58262306a36Sopenharmony_ci 58362306a36Sopenharmony_ci BUG_ON(dev_priv->pinned_bo != NULL); 58462306a36Sopenharmony_ci 58562306a36Sopenharmony_ci vmw_bo_unreference(&dev_priv->dummy_query_bo); 58662306a36Sopenharmony_ci if (dev_priv->cman) 58762306a36Sopenharmony_ci vmw_cmdbuf_remove_pool(dev_priv->cman); 58862306a36Sopenharmony_ci 58962306a36Sopenharmony_ci if (dev_priv->has_mob) { 59062306a36Sopenharmony_ci struct ttm_resource_manager *man; 59162306a36Sopenharmony_ci 59262306a36Sopenharmony_ci man = ttm_manager_type(&dev_priv->bdev, VMW_PL_MOB); 59362306a36Sopenharmony_ci ttm_resource_manager_evict_all(&dev_priv->bdev, man); 59462306a36Sopenharmony_ci vmw_otables_takedown(dev_priv); 59562306a36Sopenharmony_ci } 59662306a36Sopenharmony_ci} 59762306a36Sopenharmony_ci 59862306a36Sopenharmony_ci/** 59962306a36Sopenharmony_ci * vmw_release_device_late - Late part of fifo takedown. 60062306a36Sopenharmony_ci * 60162306a36Sopenharmony_ci * @dev_priv: Pointer to device private struct. 60262306a36Sopenharmony_ci * 60362306a36Sopenharmony_ci * This is the last part of the command submission takedown, to be called when 60462306a36Sopenharmony_ci * command submission is no longer needed. It may wait on pending fences. 60562306a36Sopenharmony_ci */ 60662306a36Sopenharmony_cistatic void vmw_release_device_late(struct vmw_private *dev_priv) 60762306a36Sopenharmony_ci{ 60862306a36Sopenharmony_ci vmw_fence_fifo_down(dev_priv->fman); 60962306a36Sopenharmony_ci if (dev_priv->cman) 61062306a36Sopenharmony_ci vmw_cmdbuf_man_destroy(dev_priv->cman); 61162306a36Sopenharmony_ci 61262306a36Sopenharmony_ci vmw_device_fini(dev_priv); 61362306a36Sopenharmony_ci} 61462306a36Sopenharmony_ci 61562306a36Sopenharmony_ci/* 61662306a36Sopenharmony_ci * Sets the initial_[width|height] fields on the given vmw_private. 61762306a36Sopenharmony_ci * 61862306a36Sopenharmony_ci * It does so by reading SVGA_REG_[WIDTH|HEIGHT] regs and then 61962306a36Sopenharmony_ci * clamping the value to fb_max_[width|height] fields and the 62062306a36Sopenharmony_ci * VMW_MIN_INITIAL_[WIDTH|HEIGHT]. 62162306a36Sopenharmony_ci * If the values appear to be invalid, set them to 62262306a36Sopenharmony_ci * VMW_MIN_INITIAL_[WIDTH|HEIGHT]. 62362306a36Sopenharmony_ci */ 62462306a36Sopenharmony_cistatic void vmw_get_initial_size(struct vmw_private *dev_priv) 62562306a36Sopenharmony_ci{ 62662306a36Sopenharmony_ci uint32_t width; 62762306a36Sopenharmony_ci uint32_t height; 62862306a36Sopenharmony_ci 62962306a36Sopenharmony_ci width = vmw_read(dev_priv, SVGA_REG_WIDTH); 63062306a36Sopenharmony_ci height = vmw_read(dev_priv, SVGA_REG_HEIGHT); 63162306a36Sopenharmony_ci 63262306a36Sopenharmony_ci width = max_t(uint32_t, width, VMWGFX_MIN_INITIAL_WIDTH); 63362306a36Sopenharmony_ci height = max_t(uint32_t, height, VMWGFX_MIN_INITIAL_HEIGHT); 63462306a36Sopenharmony_ci 63562306a36Sopenharmony_ci if (width > dev_priv->fb_max_width || 63662306a36Sopenharmony_ci height > dev_priv->fb_max_height) { 63762306a36Sopenharmony_ci 63862306a36Sopenharmony_ci /* 63962306a36Sopenharmony_ci * This is a host error and shouldn't occur. 64062306a36Sopenharmony_ci */ 64162306a36Sopenharmony_ci 64262306a36Sopenharmony_ci width = VMWGFX_MIN_INITIAL_WIDTH; 64362306a36Sopenharmony_ci height = VMWGFX_MIN_INITIAL_HEIGHT; 64462306a36Sopenharmony_ci } 64562306a36Sopenharmony_ci 64662306a36Sopenharmony_ci dev_priv->initial_width = width; 64762306a36Sopenharmony_ci dev_priv->initial_height = height; 64862306a36Sopenharmony_ci} 64962306a36Sopenharmony_ci 65062306a36Sopenharmony_ci/** 65162306a36Sopenharmony_ci * vmw_dma_select_mode - Determine how DMA mappings should be set up for this 65262306a36Sopenharmony_ci * system. 65362306a36Sopenharmony_ci * 65462306a36Sopenharmony_ci * @dev_priv: Pointer to a struct vmw_private 65562306a36Sopenharmony_ci * 65662306a36Sopenharmony_ci * This functions tries to determine what actions need to be taken by the 65762306a36Sopenharmony_ci * driver to make system pages visible to the device. 65862306a36Sopenharmony_ci * If this function decides that DMA is not possible, it returns -EINVAL. 65962306a36Sopenharmony_ci * The driver may then try to disable features of the device that require 66062306a36Sopenharmony_ci * DMA. 66162306a36Sopenharmony_ci */ 66262306a36Sopenharmony_cistatic int vmw_dma_select_mode(struct vmw_private *dev_priv) 66362306a36Sopenharmony_ci{ 66462306a36Sopenharmony_ci static const char *names[vmw_dma_map_max] = { 66562306a36Sopenharmony_ci [vmw_dma_alloc_coherent] = "Using coherent TTM pages.", 66662306a36Sopenharmony_ci [vmw_dma_map_populate] = "Caching DMA mappings.", 66762306a36Sopenharmony_ci [vmw_dma_map_bind] = "Giving up DMA mappings early."}; 66862306a36Sopenharmony_ci 66962306a36Sopenharmony_ci /* TTM currently doesn't fully support SEV encryption. */ 67062306a36Sopenharmony_ci if (cc_platform_has(CC_ATTR_MEM_ENCRYPT)) 67162306a36Sopenharmony_ci return -EINVAL; 67262306a36Sopenharmony_ci 67362306a36Sopenharmony_ci if (vmw_force_coherent) 67462306a36Sopenharmony_ci dev_priv->map_mode = vmw_dma_alloc_coherent; 67562306a36Sopenharmony_ci else if (vmw_restrict_iommu) 67662306a36Sopenharmony_ci dev_priv->map_mode = vmw_dma_map_bind; 67762306a36Sopenharmony_ci else 67862306a36Sopenharmony_ci dev_priv->map_mode = vmw_dma_map_populate; 67962306a36Sopenharmony_ci 68062306a36Sopenharmony_ci drm_info(&dev_priv->drm, 68162306a36Sopenharmony_ci "DMA map mode: %s\n", names[dev_priv->map_mode]); 68262306a36Sopenharmony_ci return 0; 68362306a36Sopenharmony_ci} 68462306a36Sopenharmony_ci 68562306a36Sopenharmony_ci/** 68662306a36Sopenharmony_ci * vmw_dma_masks - set required page- and dma masks 68762306a36Sopenharmony_ci * 68862306a36Sopenharmony_ci * @dev_priv: Pointer to struct drm-device 68962306a36Sopenharmony_ci * 69062306a36Sopenharmony_ci * With 32-bit we can only handle 32 bit PFNs. Optionally set that 69162306a36Sopenharmony_ci * restriction also for 64-bit systems. 69262306a36Sopenharmony_ci */ 69362306a36Sopenharmony_cistatic int vmw_dma_masks(struct vmw_private *dev_priv) 69462306a36Sopenharmony_ci{ 69562306a36Sopenharmony_ci struct drm_device *dev = &dev_priv->drm; 69662306a36Sopenharmony_ci int ret = 0; 69762306a36Sopenharmony_ci 69862306a36Sopenharmony_ci ret = dma_set_mask_and_coherent(dev->dev, DMA_BIT_MASK(64)); 69962306a36Sopenharmony_ci if (sizeof(unsigned long) == 4 || vmw_restrict_dma_mask) { 70062306a36Sopenharmony_ci drm_info(&dev_priv->drm, 70162306a36Sopenharmony_ci "Restricting DMA addresses to 44 bits.\n"); 70262306a36Sopenharmony_ci return dma_set_mask_and_coherent(dev->dev, DMA_BIT_MASK(44)); 70362306a36Sopenharmony_ci } 70462306a36Sopenharmony_ci 70562306a36Sopenharmony_ci return ret; 70662306a36Sopenharmony_ci} 70762306a36Sopenharmony_ci 70862306a36Sopenharmony_cistatic int vmw_vram_manager_init(struct vmw_private *dev_priv) 70962306a36Sopenharmony_ci{ 71062306a36Sopenharmony_ci int ret; 71162306a36Sopenharmony_ci ret = ttm_range_man_init(&dev_priv->bdev, TTM_PL_VRAM, false, 71262306a36Sopenharmony_ci dev_priv->vram_size >> PAGE_SHIFT); 71362306a36Sopenharmony_ci ttm_resource_manager_set_used(ttm_manager_type(&dev_priv->bdev, TTM_PL_VRAM), false); 71462306a36Sopenharmony_ci return ret; 71562306a36Sopenharmony_ci} 71662306a36Sopenharmony_ci 71762306a36Sopenharmony_cistatic void vmw_vram_manager_fini(struct vmw_private *dev_priv) 71862306a36Sopenharmony_ci{ 71962306a36Sopenharmony_ci ttm_range_man_fini(&dev_priv->bdev, TTM_PL_VRAM); 72062306a36Sopenharmony_ci} 72162306a36Sopenharmony_ci 72262306a36Sopenharmony_cistatic int vmw_setup_pci_resources(struct vmw_private *dev, 72362306a36Sopenharmony_ci u32 pci_id) 72462306a36Sopenharmony_ci{ 72562306a36Sopenharmony_ci resource_size_t rmmio_start; 72662306a36Sopenharmony_ci resource_size_t rmmio_size; 72762306a36Sopenharmony_ci resource_size_t fifo_start; 72862306a36Sopenharmony_ci resource_size_t fifo_size; 72962306a36Sopenharmony_ci int ret; 73062306a36Sopenharmony_ci struct pci_dev *pdev = to_pci_dev(dev->drm.dev); 73162306a36Sopenharmony_ci 73262306a36Sopenharmony_ci pci_set_master(pdev); 73362306a36Sopenharmony_ci 73462306a36Sopenharmony_ci ret = pci_request_regions(pdev, "vmwgfx probe"); 73562306a36Sopenharmony_ci if (ret) 73662306a36Sopenharmony_ci return ret; 73762306a36Sopenharmony_ci 73862306a36Sopenharmony_ci dev->pci_id = pci_id; 73962306a36Sopenharmony_ci if (pci_id == VMWGFX_PCI_ID_SVGA3) { 74062306a36Sopenharmony_ci rmmio_start = pci_resource_start(pdev, 0); 74162306a36Sopenharmony_ci rmmio_size = pci_resource_len(pdev, 0); 74262306a36Sopenharmony_ci dev->vram_start = pci_resource_start(pdev, 2); 74362306a36Sopenharmony_ci dev->vram_size = pci_resource_len(pdev, 2); 74462306a36Sopenharmony_ci 74562306a36Sopenharmony_ci drm_info(&dev->drm, 74662306a36Sopenharmony_ci "Register MMIO at 0x%pa size is %llu kiB\n", 74762306a36Sopenharmony_ci &rmmio_start, (uint64_t)rmmio_size / 1024); 74862306a36Sopenharmony_ci dev->rmmio = devm_ioremap(dev->drm.dev, 74962306a36Sopenharmony_ci rmmio_start, 75062306a36Sopenharmony_ci rmmio_size); 75162306a36Sopenharmony_ci if (!dev->rmmio) { 75262306a36Sopenharmony_ci drm_err(&dev->drm, 75362306a36Sopenharmony_ci "Failed mapping registers mmio memory.\n"); 75462306a36Sopenharmony_ci pci_release_regions(pdev); 75562306a36Sopenharmony_ci return -ENOMEM; 75662306a36Sopenharmony_ci } 75762306a36Sopenharmony_ci } else if (pci_id == VMWGFX_PCI_ID_SVGA2) { 75862306a36Sopenharmony_ci dev->io_start = pci_resource_start(pdev, 0); 75962306a36Sopenharmony_ci dev->vram_start = pci_resource_start(pdev, 1); 76062306a36Sopenharmony_ci dev->vram_size = pci_resource_len(pdev, 1); 76162306a36Sopenharmony_ci fifo_start = pci_resource_start(pdev, 2); 76262306a36Sopenharmony_ci fifo_size = pci_resource_len(pdev, 2); 76362306a36Sopenharmony_ci 76462306a36Sopenharmony_ci drm_info(&dev->drm, 76562306a36Sopenharmony_ci "FIFO at %pa size is %llu kiB\n", 76662306a36Sopenharmony_ci &fifo_start, (uint64_t)fifo_size / 1024); 76762306a36Sopenharmony_ci dev->fifo_mem = devm_memremap(dev->drm.dev, 76862306a36Sopenharmony_ci fifo_start, 76962306a36Sopenharmony_ci fifo_size, 77062306a36Sopenharmony_ci MEMREMAP_WB); 77162306a36Sopenharmony_ci 77262306a36Sopenharmony_ci if (IS_ERR(dev->fifo_mem)) { 77362306a36Sopenharmony_ci drm_err(&dev->drm, 77462306a36Sopenharmony_ci "Failed mapping FIFO memory.\n"); 77562306a36Sopenharmony_ci pci_release_regions(pdev); 77662306a36Sopenharmony_ci return PTR_ERR(dev->fifo_mem); 77762306a36Sopenharmony_ci } 77862306a36Sopenharmony_ci } else { 77962306a36Sopenharmony_ci pci_release_regions(pdev); 78062306a36Sopenharmony_ci return -EINVAL; 78162306a36Sopenharmony_ci } 78262306a36Sopenharmony_ci 78362306a36Sopenharmony_ci /* 78462306a36Sopenharmony_ci * This is approximate size of the vram, the exact size will only 78562306a36Sopenharmony_ci * be known after we read SVGA_REG_VRAM_SIZE. The PCI resource 78662306a36Sopenharmony_ci * size will be equal to or bigger than the size reported by 78762306a36Sopenharmony_ci * SVGA_REG_VRAM_SIZE. 78862306a36Sopenharmony_ci */ 78962306a36Sopenharmony_ci drm_info(&dev->drm, 79062306a36Sopenharmony_ci "VRAM at %pa size is %llu kiB\n", 79162306a36Sopenharmony_ci &dev->vram_start, (uint64_t)dev->vram_size / 1024); 79262306a36Sopenharmony_ci 79362306a36Sopenharmony_ci return 0; 79462306a36Sopenharmony_ci} 79562306a36Sopenharmony_ci 79662306a36Sopenharmony_cistatic int vmw_detect_version(struct vmw_private *dev) 79762306a36Sopenharmony_ci{ 79862306a36Sopenharmony_ci uint32_t svga_id; 79962306a36Sopenharmony_ci 80062306a36Sopenharmony_ci vmw_write(dev, SVGA_REG_ID, vmw_is_svga_v3(dev) ? 80162306a36Sopenharmony_ci SVGA_ID_3 : SVGA_ID_2); 80262306a36Sopenharmony_ci svga_id = vmw_read(dev, SVGA_REG_ID); 80362306a36Sopenharmony_ci if (svga_id != SVGA_ID_2 && svga_id != SVGA_ID_3) { 80462306a36Sopenharmony_ci drm_err(&dev->drm, 80562306a36Sopenharmony_ci "Unsupported SVGA ID 0x%x on chipset 0x%x\n", 80662306a36Sopenharmony_ci svga_id, dev->pci_id); 80762306a36Sopenharmony_ci return -ENOSYS; 80862306a36Sopenharmony_ci } 80962306a36Sopenharmony_ci BUG_ON(vmw_is_svga_v3(dev) && (svga_id != SVGA_ID_3)); 81062306a36Sopenharmony_ci drm_info(&dev->drm, 81162306a36Sopenharmony_ci "Running on SVGA version %d.\n", (svga_id & 0xff)); 81262306a36Sopenharmony_ci return 0; 81362306a36Sopenharmony_ci} 81462306a36Sopenharmony_ci 81562306a36Sopenharmony_cistatic void vmw_write_driver_id(struct vmw_private *dev) 81662306a36Sopenharmony_ci{ 81762306a36Sopenharmony_ci if ((dev->capabilities2 & SVGA_CAP2_DX2) != 0) { 81862306a36Sopenharmony_ci vmw_write(dev, SVGA_REG_GUEST_DRIVER_ID, 81962306a36Sopenharmony_ci SVGA_REG_GUEST_DRIVER_ID_LINUX); 82062306a36Sopenharmony_ci 82162306a36Sopenharmony_ci vmw_write(dev, SVGA_REG_GUEST_DRIVER_VERSION1, 82262306a36Sopenharmony_ci LINUX_VERSION_MAJOR << 24 | 82362306a36Sopenharmony_ci LINUX_VERSION_PATCHLEVEL << 16 | 82462306a36Sopenharmony_ci LINUX_VERSION_SUBLEVEL); 82562306a36Sopenharmony_ci vmw_write(dev, SVGA_REG_GUEST_DRIVER_VERSION2, 82662306a36Sopenharmony_ci VMWGFX_DRIVER_MAJOR << 24 | 82762306a36Sopenharmony_ci VMWGFX_DRIVER_MINOR << 16 | 82862306a36Sopenharmony_ci VMWGFX_DRIVER_PATCHLEVEL); 82962306a36Sopenharmony_ci vmw_write(dev, SVGA_REG_GUEST_DRIVER_VERSION3, 0); 83062306a36Sopenharmony_ci 83162306a36Sopenharmony_ci vmw_write(dev, SVGA_REG_GUEST_DRIVER_ID, 83262306a36Sopenharmony_ci SVGA_REG_GUEST_DRIVER_ID_SUBMIT); 83362306a36Sopenharmony_ci } 83462306a36Sopenharmony_ci} 83562306a36Sopenharmony_ci 83662306a36Sopenharmony_cistatic void vmw_sw_context_init(struct vmw_private *dev_priv) 83762306a36Sopenharmony_ci{ 83862306a36Sopenharmony_ci struct vmw_sw_context *sw_context = &dev_priv->ctx; 83962306a36Sopenharmony_ci 84062306a36Sopenharmony_ci hash_init(sw_context->res_ht); 84162306a36Sopenharmony_ci} 84262306a36Sopenharmony_ci 84362306a36Sopenharmony_cistatic void vmw_sw_context_fini(struct vmw_private *dev_priv) 84462306a36Sopenharmony_ci{ 84562306a36Sopenharmony_ci struct vmw_sw_context *sw_context = &dev_priv->ctx; 84662306a36Sopenharmony_ci 84762306a36Sopenharmony_ci vfree(sw_context->cmd_bounce); 84862306a36Sopenharmony_ci if (sw_context->staged_bindings) 84962306a36Sopenharmony_ci vmw_binding_state_free(sw_context->staged_bindings); 85062306a36Sopenharmony_ci} 85162306a36Sopenharmony_ci 85262306a36Sopenharmony_cistatic int vmw_driver_load(struct vmw_private *dev_priv, u32 pci_id) 85362306a36Sopenharmony_ci{ 85462306a36Sopenharmony_ci int ret; 85562306a36Sopenharmony_ci enum vmw_res_type i; 85662306a36Sopenharmony_ci bool refuse_dma = false; 85762306a36Sopenharmony_ci struct pci_dev *pdev = to_pci_dev(dev_priv->drm.dev); 85862306a36Sopenharmony_ci 85962306a36Sopenharmony_ci dev_priv->drm.dev_private = dev_priv; 86062306a36Sopenharmony_ci 86162306a36Sopenharmony_ci vmw_sw_context_init(dev_priv); 86262306a36Sopenharmony_ci 86362306a36Sopenharmony_ci mutex_init(&dev_priv->cmdbuf_mutex); 86462306a36Sopenharmony_ci mutex_init(&dev_priv->binding_mutex); 86562306a36Sopenharmony_ci spin_lock_init(&dev_priv->resource_lock); 86662306a36Sopenharmony_ci spin_lock_init(&dev_priv->hw_lock); 86762306a36Sopenharmony_ci spin_lock_init(&dev_priv->waiter_lock); 86862306a36Sopenharmony_ci spin_lock_init(&dev_priv->cursor_lock); 86962306a36Sopenharmony_ci 87062306a36Sopenharmony_ci ret = vmw_setup_pci_resources(dev_priv, pci_id); 87162306a36Sopenharmony_ci if (ret) 87262306a36Sopenharmony_ci return ret; 87362306a36Sopenharmony_ci ret = vmw_detect_version(dev_priv); 87462306a36Sopenharmony_ci if (ret) 87562306a36Sopenharmony_ci goto out_no_pci_or_version; 87662306a36Sopenharmony_ci 87762306a36Sopenharmony_ci 87862306a36Sopenharmony_ci for (i = vmw_res_context; i < vmw_res_max; ++i) { 87962306a36Sopenharmony_ci idr_init_base(&dev_priv->res_idr[i], 1); 88062306a36Sopenharmony_ci INIT_LIST_HEAD(&dev_priv->res_lru[i]); 88162306a36Sopenharmony_ci } 88262306a36Sopenharmony_ci 88362306a36Sopenharmony_ci init_waitqueue_head(&dev_priv->fence_queue); 88462306a36Sopenharmony_ci init_waitqueue_head(&dev_priv->fifo_queue); 88562306a36Sopenharmony_ci dev_priv->fence_queue_waiters = 0; 88662306a36Sopenharmony_ci dev_priv->fifo_queue_waiters = 0; 88762306a36Sopenharmony_ci 88862306a36Sopenharmony_ci dev_priv->used_memory_size = 0; 88962306a36Sopenharmony_ci 89062306a36Sopenharmony_ci dev_priv->assume_16bpp = !!vmw_assume_16bpp; 89162306a36Sopenharmony_ci 89262306a36Sopenharmony_ci dev_priv->capabilities = vmw_read(dev_priv, SVGA_REG_CAPABILITIES); 89362306a36Sopenharmony_ci vmw_print_bitmap(&dev_priv->drm, "Capabilities", 89462306a36Sopenharmony_ci dev_priv->capabilities, 89562306a36Sopenharmony_ci cap1_names, ARRAY_SIZE(cap1_names)); 89662306a36Sopenharmony_ci if (dev_priv->capabilities & SVGA_CAP_CAP2_REGISTER) { 89762306a36Sopenharmony_ci dev_priv->capabilities2 = vmw_read(dev_priv, SVGA_REG_CAP2); 89862306a36Sopenharmony_ci vmw_print_bitmap(&dev_priv->drm, "Capabilities2", 89962306a36Sopenharmony_ci dev_priv->capabilities2, 90062306a36Sopenharmony_ci cap2_names, ARRAY_SIZE(cap2_names)); 90162306a36Sopenharmony_ci } 90262306a36Sopenharmony_ci 90362306a36Sopenharmony_ci if (!vmwgfx_supported(dev_priv)) { 90462306a36Sopenharmony_ci vmw_disable_backdoor(); 90562306a36Sopenharmony_ci drm_err_once(&dev_priv->drm, 90662306a36Sopenharmony_ci "vmwgfx seems to be running on an unsupported hypervisor."); 90762306a36Sopenharmony_ci drm_err_once(&dev_priv->drm, 90862306a36Sopenharmony_ci "This configuration is likely broken."); 90962306a36Sopenharmony_ci drm_err_once(&dev_priv->drm, 91062306a36Sopenharmony_ci "Please switch to a supported graphics device to avoid problems."); 91162306a36Sopenharmony_ci } 91262306a36Sopenharmony_ci 91362306a36Sopenharmony_ci ret = vmw_dma_select_mode(dev_priv); 91462306a36Sopenharmony_ci if (unlikely(ret != 0)) { 91562306a36Sopenharmony_ci drm_info(&dev_priv->drm, 91662306a36Sopenharmony_ci "Restricting capabilities since DMA not available.\n"); 91762306a36Sopenharmony_ci refuse_dma = true; 91862306a36Sopenharmony_ci if (dev_priv->capabilities & SVGA_CAP_GBOBJECTS) 91962306a36Sopenharmony_ci drm_info(&dev_priv->drm, 92062306a36Sopenharmony_ci "Disabling 3D acceleration.\n"); 92162306a36Sopenharmony_ci } 92262306a36Sopenharmony_ci 92362306a36Sopenharmony_ci dev_priv->vram_size = vmw_read(dev_priv, SVGA_REG_VRAM_SIZE); 92462306a36Sopenharmony_ci dev_priv->fifo_mem_size = vmw_read(dev_priv, SVGA_REG_MEM_SIZE); 92562306a36Sopenharmony_ci dev_priv->fb_max_width = vmw_read(dev_priv, SVGA_REG_MAX_WIDTH); 92662306a36Sopenharmony_ci dev_priv->fb_max_height = vmw_read(dev_priv, SVGA_REG_MAX_HEIGHT); 92762306a36Sopenharmony_ci 92862306a36Sopenharmony_ci vmw_get_initial_size(dev_priv); 92962306a36Sopenharmony_ci 93062306a36Sopenharmony_ci if (dev_priv->capabilities & SVGA_CAP_GMR2) { 93162306a36Sopenharmony_ci dev_priv->max_gmr_ids = 93262306a36Sopenharmony_ci vmw_read(dev_priv, SVGA_REG_GMR_MAX_IDS); 93362306a36Sopenharmony_ci dev_priv->max_gmr_pages = 93462306a36Sopenharmony_ci vmw_read(dev_priv, SVGA_REG_GMRS_MAX_PAGES); 93562306a36Sopenharmony_ci dev_priv->memory_size = 93662306a36Sopenharmony_ci vmw_read(dev_priv, SVGA_REG_MEMORY_SIZE); 93762306a36Sopenharmony_ci dev_priv->memory_size -= dev_priv->vram_size; 93862306a36Sopenharmony_ci } else { 93962306a36Sopenharmony_ci /* 94062306a36Sopenharmony_ci * An arbitrary limit of 512MiB on surface 94162306a36Sopenharmony_ci * memory. But all HWV8 hardware supports GMR2. 94262306a36Sopenharmony_ci */ 94362306a36Sopenharmony_ci dev_priv->memory_size = 512*1024*1024; 94462306a36Sopenharmony_ci } 94562306a36Sopenharmony_ci dev_priv->max_mob_pages = 0; 94662306a36Sopenharmony_ci dev_priv->max_mob_size = 0; 94762306a36Sopenharmony_ci if (dev_priv->capabilities & SVGA_CAP_GBOBJECTS) { 94862306a36Sopenharmony_ci uint64_t mem_size; 94962306a36Sopenharmony_ci 95062306a36Sopenharmony_ci if (dev_priv->capabilities2 & SVGA_CAP2_GB_MEMSIZE_2) 95162306a36Sopenharmony_ci mem_size = vmw_read(dev_priv, 95262306a36Sopenharmony_ci SVGA_REG_GBOBJECT_MEM_SIZE_KB); 95362306a36Sopenharmony_ci else 95462306a36Sopenharmony_ci mem_size = 95562306a36Sopenharmony_ci vmw_read(dev_priv, 95662306a36Sopenharmony_ci SVGA_REG_SUGGESTED_GBOBJECT_MEM_SIZE_KB); 95762306a36Sopenharmony_ci 95862306a36Sopenharmony_ci /* 95962306a36Sopenharmony_ci * Workaround for low memory 2D VMs to compensate for the 96062306a36Sopenharmony_ci * allocation taken by fbdev 96162306a36Sopenharmony_ci */ 96262306a36Sopenharmony_ci if (!(dev_priv->capabilities & SVGA_CAP_3D)) 96362306a36Sopenharmony_ci mem_size *= 3; 96462306a36Sopenharmony_ci 96562306a36Sopenharmony_ci dev_priv->max_mob_pages = mem_size * 1024 / PAGE_SIZE; 96662306a36Sopenharmony_ci dev_priv->max_primary_mem = 96762306a36Sopenharmony_ci vmw_read(dev_priv, SVGA_REG_MAX_PRIMARY_MEM); 96862306a36Sopenharmony_ci dev_priv->max_mob_size = 96962306a36Sopenharmony_ci vmw_read(dev_priv, SVGA_REG_MOB_MAX_SIZE); 97062306a36Sopenharmony_ci dev_priv->stdu_max_width = 97162306a36Sopenharmony_ci vmw_read(dev_priv, SVGA_REG_SCREENTARGET_MAX_WIDTH); 97262306a36Sopenharmony_ci dev_priv->stdu_max_height = 97362306a36Sopenharmony_ci vmw_read(dev_priv, SVGA_REG_SCREENTARGET_MAX_HEIGHT); 97462306a36Sopenharmony_ci 97562306a36Sopenharmony_ci vmw_write(dev_priv, SVGA_REG_DEV_CAP, 97662306a36Sopenharmony_ci SVGA3D_DEVCAP_MAX_TEXTURE_WIDTH); 97762306a36Sopenharmony_ci dev_priv->texture_max_width = vmw_read(dev_priv, 97862306a36Sopenharmony_ci SVGA_REG_DEV_CAP); 97962306a36Sopenharmony_ci vmw_write(dev_priv, SVGA_REG_DEV_CAP, 98062306a36Sopenharmony_ci SVGA3D_DEVCAP_MAX_TEXTURE_HEIGHT); 98162306a36Sopenharmony_ci dev_priv->texture_max_height = vmw_read(dev_priv, 98262306a36Sopenharmony_ci SVGA_REG_DEV_CAP); 98362306a36Sopenharmony_ci } else { 98462306a36Sopenharmony_ci dev_priv->texture_max_width = 8192; 98562306a36Sopenharmony_ci dev_priv->texture_max_height = 8192; 98662306a36Sopenharmony_ci dev_priv->max_primary_mem = dev_priv->vram_size; 98762306a36Sopenharmony_ci } 98862306a36Sopenharmony_ci drm_info(&dev_priv->drm, 98962306a36Sopenharmony_ci "Legacy memory limits: VRAM = %llu kB, FIFO = %llu kB, surface = %u kB\n", 99062306a36Sopenharmony_ci (u64)dev_priv->vram_size / 1024, 99162306a36Sopenharmony_ci (u64)dev_priv->fifo_mem_size / 1024, 99262306a36Sopenharmony_ci dev_priv->memory_size / 1024); 99362306a36Sopenharmony_ci 99462306a36Sopenharmony_ci drm_info(&dev_priv->drm, 99562306a36Sopenharmony_ci "MOB limits: max mob size = %u kB, max mob pages = %u\n", 99662306a36Sopenharmony_ci dev_priv->max_mob_size / 1024, dev_priv->max_mob_pages); 99762306a36Sopenharmony_ci 99862306a36Sopenharmony_ci ret = vmw_dma_masks(dev_priv); 99962306a36Sopenharmony_ci if (unlikely(ret != 0)) 100062306a36Sopenharmony_ci goto out_err0; 100162306a36Sopenharmony_ci 100262306a36Sopenharmony_ci dma_set_max_seg_size(dev_priv->drm.dev, U32_MAX); 100362306a36Sopenharmony_ci 100462306a36Sopenharmony_ci if (dev_priv->capabilities & SVGA_CAP_GMR2) { 100562306a36Sopenharmony_ci drm_info(&dev_priv->drm, 100662306a36Sopenharmony_ci "Max GMR ids is %u\n", 100762306a36Sopenharmony_ci (unsigned)dev_priv->max_gmr_ids); 100862306a36Sopenharmony_ci drm_info(&dev_priv->drm, 100962306a36Sopenharmony_ci "Max number of GMR pages is %u\n", 101062306a36Sopenharmony_ci (unsigned)dev_priv->max_gmr_pages); 101162306a36Sopenharmony_ci } 101262306a36Sopenharmony_ci drm_info(&dev_priv->drm, 101362306a36Sopenharmony_ci "Maximum display memory size is %llu kiB\n", 101462306a36Sopenharmony_ci (uint64_t)dev_priv->max_primary_mem / 1024); 101562306a36Sopenharmony_ci 101662306a36Sopenharmony_ci /* Need mmio memory to check for fifo pitchlock cap. */ 101762306a36Sopenharmony_ci if (!(dev_priv->capabilities & SVGA_CAP_DISPLAY_TOPOLOGY) && 101862306a36Sopenharmony_ci !(dev_priv->capabilities & SVGA_CAP_PITCHLOCK) && 101962306a36Sopenharmony_ci !vmw_fifo_have_pitchlock(dev_priv)) { 102062306a36Sopenharmony_ci ret = -ENOSYS; 102162306a36Sopenharmony_ci DRM_ERROR("Hardware has no pitchlock\n"); 102262306a36Sopenharmony_ci goto out_err0; 102362306a36Sopenharmony_ci } 102462306a36Sopenharmony_ci 102562306a36Sopenharmony_ci dev_priv->tdev = ttm_object_device_init(&vmw_prime_dmabuf_ops); 102662306a36Sopenharmony_ci 102762306a36Sopenharmony_ci if (unlikely(dev_priv->tdev == NULL)) { 102862306a36Sopenharmony_ci drm_err(&dev_priv->drm, 102962306a36Sopenharmony_ci "Unable to initialize TTM object management.\n"); 103062306a36Sopenharmony_ci ret = -ENOMEM; 103162306a36Sopenharmony_ci goto out_err0; 103262306a36Sopenharmony_ci } 103362306a36Sopenharmony_ci 103462306a36Sopenharmony_ci if (dev_priv->capabilities & SVGA_CAP_IRQMASK) { 103562306a36Sopenharmony_ci ret = vmw_irq_install(dev_priv); 103662306a36Sopenharmony_ci if (ret != 0) { 103762306a36Sopenharmony_ci drm_err(&dev_priv->drm, 103862306a36Sopenharmony_ci "Failed installing irq: %d\n", ret); 103962306a36Sopenharmony_ci goto out_no_irq; 104062306a36Sopenharmony_ci } 104162306a36Sopenharmony_ci } 104262306a36Sopenharmony_ci 104362306a36Sopenharmony_ci dev_priv->fman = vmw_fence_manager_init(dev_priv); 104462306a36Sopenharmony_ci if (unlikely(dev_priv->fman == NULL)) { 104562306a36Sopenharmony_ci ret = -ENOMEM; 104662306a36Sopenharmony_ci goto out_no_fman; 104762306a36Sopenharmony_ci } 104862306a36Sopenharmony_ci 104962306a36Sopenharmony_ci ret = ttm_device_init(&dev_priv->bdev, &vmw_bo_driver, 105062306a36Sopenharmony_ci dev_priv->drm.dev, 105162306a36Sopenharmony_ci dev_priv->drm.anon_inode->i_mapping, 105262306a36Sopenharmony_ci dev_priv->drm.vma_offset_manager, 105362306a36Sopenharmony_ci dev_priv->map_mode == vmw_dma_alloc_coherent, 105462306a36Sopenharmony_ci false); 105562306a36Sopenharmony_ci if (unlikely(ret != 0)) { 105662306a36Sopenharmony_ci drm_err(&dev_priv->drm, 105762306a36Sopenharmony_ci "Failed initializing TTM buffer object driver.\n"); 105862306a36Sopenharmony_ci goto out_no_bdev; 105962306a36Sopenharmony_ci } 106062306a36Sopenharmony_ci 106162306a36Sopenharmony_ci /* 106262306a36Sopenharmony_ci * Enable VRAM, but initially don't use it until SVGA is enabled and 106362306a36Sopenharmony_ci * unhidden. 106462306a36Sopenharmony_ci */ 106562306a36Sopenharmony_ci 106662306a36Sopenharmony_ci ret = vmw_vram_manager_init(dev_priv); 106762306a36Sopenharmony_ci if (unlikely(ret != 0)) { 106862306a36Sopenharmony_ci drm_err(&dev_priv->drm, 106962306a36Sopenharmony_ci "Failed initializing memory manager for VRAM.\n"); 107062306a36Sopenharmony_ci goto out_no_vram; 107162306a36Sopenharmony_ci } 107262306a36Sopenharmony_ci 107362306a36Sopenharmony_ci ret = vmw_devcaps_create(dev_priv); 107462306a36Sopenharmony_ci if (unlikely(ret != 0)) { 107562306a36Sopenharmony_ci drm_err(&dev_priv->drm, 107662306a36Sopenharmony_ci "Failed initializing device caps.\n"); 107762306a36Sopenharmony_ci goto out_no_vram; 107862306a36Sopenharmony_ci } 107962306a36Sopenharmony_ci 108062306a36Sopenharmony_ci /* 108162306a36Sopenharmony_ci * "Guest Memory Regions" is an aperture like feature with 108262306a36Sopenharmony_ci * one slot per bo. There is an upper limit of the number of 108362306a36Sopenharmony_ci * slots as well as the bo size. 108462306a36Sopenharmony_ci */ 108562306a36Sopenharmony_ci dev_priv->has_gmr = true; 108662306a36Sopenharmony_ci /* TODO: This is most likely not correct */ 108762306a36Sopenharmony_ci if (((dev_priv->capabilities & (SVGA_CAP_GMR | SVGA_CAP_GMR2)) == 0) || 108862306a36Sopenharmony_ci refuse_dma || 108962306a36Sopenharmony_ci vmw_gmrid_man_init(dev_priv, VMW_PL_GMR) != 0) { 109062306a36Sopenharmony_ci drm_info(&dev_priv->drm, 109162306a36Sopenharmony_ci "No GMR memory available. " 109262306a36Sopenharmony_ci "Graphics memory resources are very limited.\n"); 109362306a36Sopenharmony_ci dev_priv->has_gmr = false; 109462306a36Sopenharmony_ci } 109562306a36Sopenharmony_ci 109662306a36Sopenharmony_ci if (dev_priv->capabilities & SVGA_CAP_GBOBJECTS && !refuse_dma) { 109762306a36Sopenharmony_ci dev_priv->has_mob = true; 109862306a36Sopenharmony_ci 109962306a36Sopenharmony_ci if (vmw_gmrid_man_init(dev_priv, VMW_PL_MOB) != 0) { 110062306a36Sopenharmony_ci drm_info(&dev_priv->drm, 110162306a36Sopenharmony_ci "No MOB memory available. " 110262306a36Sopenharmony_ci "3D will be disabled.\n"); 110362306a36Sopenharmony_ci dev_priv->has_mob = false; 110462306a36Sopenharmony_ci } 110562306a36Sopenharmony_ci if (vmw_sys_man_init(dev_priv) != 0) { 110662306a36Sopenharmony_ci drm_info(&dev_priv->drm, 110762306a36Sopenharmony_ci "No MOB page table memory available. " 110862306a36Sopenharmony_ci "3D will be disabled.\n"); 110962306a36Sopenharmony_ci dev_priv->has_mob = false; 111062306a36Sopenharmony_ci } 111162306a36Sopenharmony_ci } 111262306a36Sopenharmony_ci 111362306a36Sopenharmony_ci if (dev_priv->has_mob && (dev_priv->capabilities & SVGA_CAP_DX)) { 111462306a36Sopenharmony_ci if (vmw_devcap_get(dev_priv, SVGA3D_DEVCAP_DXCONTEXT)) 111562306a36Sopenharmony_ci dev_priv->sm_type = VMW_SM_4; 111662306a36Sopenharmony_ci } 111762306a36Sopenharmony_ci 111862306a36Sopenharmony_ci /* SVGA_CAP2_DX2 (DefineGBSurface_v3) is needed for SM4_1 support */ 111962306a36Sopenharmony_ci if (has_sm4_context(dev_priv) && 112062306a36Sopenharmony_ci (dev_priv->capabilities2 & SVGA_CAP2_DX2)) { 112162306a36Sopenharmony_ci if (vmw_devcap_get(dev_priv, SVGA3D_DEVCAP_SM41)) 112262306a36Sopenharmony_ci dev_priv->sm_type = VMW_SM_4_1; 112362306a36Sopenharmony_ci if (has_sm4_1_context(dev_priv) && 112462306a36Sopenharmony_ci (dev_priv->capabilities2 & SVGA_CAP2_DX3)) { 112562306a36Sopenharmony_ci if (vmw_devcap_get(dev_priv, SVGA3D_DEVCAP_SM5)) { 112662306a36Sopenharmony_ci dev_priv->sm_type = VMW_SM_5; 112762306a36Sopenharmony_ci if (vmw_devcap_get(dev_priv, SVGA3D_DEVCAP_GL43)) 112862306a36Sopenharmony_ci dev_priv->sm_type = VMW_SM_5_1X; 112962306a36Sopenharmony_ci } 113062306a36Sopenharmony_ci } 113162306a36Sopenharmony_ci } 113262306a36Sopenharmony_ci 113362306a36Sopenharmony_ci ret = vmw_kms_init(dev_priv); 113462306a36Sopenharmony_ci if (unlikely(ret != 0)) 113562306a36Sopenharmony_ci goto out_no_kms; 113662306a36Sopenharmony_ci vmw_overlay_init(dev_priv); 113762306a36Sopenharmony_ci 113862306a36Sopenharmony_ci ret = vmw_request_device(dev_priv); 113962306a36Sopenharmony_ci if (ret) 114062306a36Sopenharmony_ci goto out_no_fifo; 114162306a36Sopenharmony_ci 114262306a36Sopenharmony_ci vmw_print_sm_type(dev_priv); 114362306a36Sopenharmony_ci vmw_host_printf("vmwgfx: Module Version: %d.%d.%d (kernel: %s)", 114462306a36Sopenharmony_ci VMWGFX_DRIVER_MAJOR, VMWGFX_DRIVER_MINOR, 114562306a36Sopenharmony_ci VMWGFX_DRIVER_PATCHLEVEL, UTS_RELEASE); 114662306a36Sopenharmony_ci vmw_write_driver_id(dev_priv); 114762306a36Sopenharmony_ci 114862306a36Sopenharmony_ci dev_priv->pm_nb.notifier_call = vmwgfx_pm_notifier; 114962306a36Sopenharmony_ci register_pm_notifier(&dev_priv->pm_nb); 115062306a36Sopenharmony_ci 115162306a36Sopenharmony_ci return 0; 115262306a36Sopenharmony_ci 115362306a36Sopenharmony_ciout_no_fifo: 115462306a36Sopenharmony_ci vmw_overlay_close(dev_priv); 115562306a36Sopenharmony_ci vmw_kms_close(dev_priv); 115662306a36Sopenharmony_ciout_no_kms: 115762306a36Sopenharmony_ci if (dev_priv->has_mob) { 115862306a36Sopenharmony_ci vmw_gmrid_man_fini(dev_priv, VMW_PL_MOB); 115962306a36Sopenharmony_ci vmw_sys_man_fini(dev_priv); 116062306a36Sopenharmony_ci } 116162306a36Sopenharmony_ci if (dev_priv->has_gmr) 116262306a36Sopenharmony_ci vmw_gmrid_man_fini(dev_priv, VMW_PL_GMR); 116362306a36Sopenharmony_ci vmw_devcaps_destroy(dev_priv); 116462306a36Sopenharmony_ci vmw_vram_manager_fini(dev_priv); 116562306a36Sopenharmony_ciout_no_vram: 116662306a36Sopenharmony_ci ttm_device_fini(&dev_priv->bdev); 116762306a36Sopenharmony_ciout_no_bdev: 116862306a36Sopenharmony_ci vmw_fence_manager_takedown(dev_priv->fman); 116962306a36Sopenharmony_ciout_no_fman: 117062306a36Sopenharmony_ci if (dev_priv->capabilities & SVGA_CAP_IRQMASK) 117162306a36Sopenharmony_ci vmw_irq_uninstall(&dev_priv->drm); 117262306a36Sopenharmony_ciout_no_irq: 117362306a36Sopenharmony_ci ttm_object_device_release(&dev_priv->tdev); 117462306a36Sopenharmony_ciout_err0: 117562306a36Sopenharmony_ci for (i = vmw_res_context; i < vmw_res_max; ++i) 117662306a36Sopenharmony_ci idr_destroy(&dev_priv->res_idr[i]); 117762306a36Sopenharmony_ci 117862306a36Sopenharmony_ci if (dev_priv->ctx.staged_bindings) 117962306a36Sopenharmony_ci vmw_binding_state_free(dev_priv->ctx.staged_bindings); 118062306a36Sopenharmony_ciout_no_pci_or_version: 118162306a36Sopenharmony_ci pci_release_regions(pdev); 118262306a36Sopenharmony_ci return ret; 118362306a36Sopenharmony_ci} 118462306a36Sopenharmony_ci 118562306a36Sopenharmony_cistatic void vmw_driver_unload(struct drm_device *dev) 118662306a36Sopenharmony_ci{ 118762306a36Sopenharmony_ci struct vmw_private *dev_priv = vmw_priv(dev); 118862306a36Sopenharmony_ci struct pci_dev *pdev = to_pci_dev(dev->dev); 118962306a36Sopenharmony_ci enum vmw_res_type i; 119062306a36Sopenharmony_ci 119162306a36Sopenharmony_ci unregister_pm_notifier(&dev_priv->pm_nb); 119262306a36Sopenharmony_ci 119362306a36Sopenharmony_ci vmw_sw_context_fini(dev_priv); 119462306a36Sopenharmony_ci vmw_fifo_resource_dec(dev_priv); 119562306a36Sopenharmony_ci 119662306a36Sopenharmony_ci vmw_svga_disable(dev_priv); 119762306a36Sopenharmony_ci 119862306a36Sopenharmony_ci vmw_kms_close(dev_priv); 119962306a36Sopenharmony_ci vmw_overlay_close(dev_priv); 120062306a36Sopenharmony_ci 120162306a36Sopenharmony_ci if (dev_priv->has_gmr) 120262306a36Sopenharmony_ci vmw_gmrid_man_fini(dev_priv, VMW_PL_GMR); 120362306a36Sopenharmony_ci 120462306a36Sopenharmony_ci vmw_release_device_early(dev_priv); 120562306a36Sopenharmony_ci if (dev_priv->has_mob) { 120662306a36Sopenharmony_ci vmw_gmrid_man_fini(dev_priv, VMW_PL_MOB); 120762306a36Sopenharmony_ci vmw_sys_man_fini(dev_priv); 120862306a36Sopenharmony_ci } 120962306a36Sopenharmony_ci vmw_devcaps_destroy(dev_priv); 121062306a36Sopenharmony_ci vmw_vram_manager_fini(dev_priv); 121162306a36Sopenharmony_ci ttm_device_fini(&dev_priv->bdev); 121262306a36Sopenharmony_ci vmw_release_device_late(dev_priv); 121362306a36Sopenharmony_ci vmw_fence_manager_takedown(dev_priv->fman); 121462306a36Sopenharmony_ci if (dev_priv->capabilities & SVGA_CAP_IRQMASK) 121562306a36Sopenharmony_ci vmw_irq_uninstall(&dev_priv->drm); 121662306a36Sopenharmony_ci 121762306a36Sopenharmony_ci ttm_object_device_release(&dev_priv->tdev); 121862306a36Sopenharmony_ci 121962306a36Sopenharmony_ci for (i = vmw_res_context; i < vmw_res_max; ++i) 122062306a36Sopenharmony_ci idr_destroy(&dev_priv->res_idr[i]); 122162306a36Sopenharmony_ci 122262306a36Sopenharmony_ci vmw_mksstat_remove_all(dev_priv); 122362306a36Sopenharmony_ci 122462306a36Sopenharmony_ci pci_release_regions(pdev); 122562306a36Sopenharmony_ci} 122662306a36Sopenharmony_ci 122762306a36Sopenharmony_cistatic void vmw_postclose(struct drm_device *dev, 122862306a36Sopenharmony_ci struct drm_file *file_priv) 122962306a36Sopenharmony_ci{ 123062306a36Sopenharmony_ci struct vmw_fpriv *vmw_fp = vmw_fpriv(file_priv); 123162306a36Sopenharmony_ci 123262306a36Sopenharmony_ci ttm_object_file_release(&vmw_fp->tfile); 123362306a36Sopenharmony_ci kfree(vmw_fp); 123462306a36Sopenharmony_ci} 123562306a36Sopenharmony_ci 123662306a36Sopenharmony_cistatic int vmw_driver_open(struct drm_device *dev, struct drm_file *file_priv) 123762306a36Sopenharmony_ci{ 123862306a36Sopenharmony_ci struct vmw_private *dev_priv = vmw_priv(dev); 123962306a36Sopenharmony_ci struct vmw_fpriv *vmw_fp; 124062306a36Sopenharmony_ci int ret = -ENOMEM; 124162306a36Sopenharmony_ci 124262306a36Sopenharmony_ci vmw_fp = kzalloc(sizeof(*vmw_fp), GFP_KERNEL); 124362306a36Sopenharmony_ci if (unlikely(!vmw_fp)) 124462306a36Sopenharmony_ci return ret; 124562306a36Sopenharmony_ci 124662306a36Sopenharmony_ci vmw_fp->tfile = ttm_object_file_init(dev_priv->tdev); 124762306a36Sopenharmony_ci if (unlikely(vmw_fp->tfile == NULL)) 124862306a36Sopenharmony_ci goto out_no_tfile; 124962306a36Sopenharmony_ci 125062306a36Sopenharmony_ci file_priv->driver_priv = vmw_fp; 125162306a36Sopenharmony_ci 125262306a36Sopenharmony_ci return 0; 125362306a36Sopenharmony_ci 125462306a36Sopenharmony_ciout_no_tfile: 125562306a36Sopenharmony_ci kfree(vmw_fp); 125662306a36Sopenharmony_ci return ret; 125762306a36Sopenharmony_ci} 125862306a36Sopenharmony_ci 125962306a36Sopenharmony_cistatic long vmw_generic_ioctl(struct file *filp, unsigned int cmd, 126062306a36Sopenharmony_ci unsigned long arg, 126162306a36Sopenharmony_ci long (*ioctl_func)(struct file *, unsigned int, 126262306a36Sopenharmony_ci unsigned long)) 126362306a36Sopenharmony_ci{ 126462306a36Sopenharmony_ci struct drm_file *file_priv = filp->private_data; 126562306a36Sopenharmony_ci struct drm_device *dev = file_priv->minor->dev; 126662306a36Sopenharmony_ci unsigned int nr = DRM_IOCTL_NR(cmd); 126762306a36Sopenharmony_ci unsigned int flags; 126862306a36Sopenharmony_ci 126962306a36Sopenharmony_ci /* 127062306a36Sopenharmony_ci * Do extra checking on driver private ioctls. 127162306a36Sopenharmony_ci */ 127262306a36Sopenharmony_ci 127362306a36Sopenharmony_ci if ((nr >= DRM_COMMAND_BASE) && (nr < DRM_COMMAND_END) 127462306a36Sopenharmony_ci && (nr < DRM_COMMAND_BASE + dev->driver->num_ioctls)) { 127562306a36Sopenharmony_ci const struct drm_ioctl_desc *ioctl = 127662306a36Sopenharmony_ci &vmw_ioctls[nr - DRM_COMMAND_BASE]; 127762306a36Sopenharmony_ci 127862306a36Sopenharmony_ci if (nr == DRM_COMMAND_BASE + DRM_VMW_EXECBUF) { 127962306a36Sopenharmony_ci return ioctl_func(filp, cmd, arg); 128062306a36Sopenharmony_ci } else if (nr == DRM_COMMAND_BASE + DRM_VMW_UPDATE_LAYOUT) { 128162306a36Sopenharmony_ci if (!drm_is_current_master(file_priv) && 128262306a36Sopenharmony_ci !capable(CAP_SYS_ADMIN)) 128362306a36Sopenharmony_ci return -EACCES; 128462306a36Sopenharmony_ci } 128562306a36Sopenharmony_ci 128662306a36Sopenharmony_ci if (unlikely(ioctl->cmd != cmd)) 128762306a36Sopenharmony_ci goto out_io_encoding; 128862306a36Sopenharmony_ci 128962306a36Sopenharmony_ci flags = ioctl->flags; 129062306a36Sopenharmony_ci } else if (!drm_ioctl_flags(nr, &flags)) 129162306a36Sopenharmony_ci return -EINVAL; 129262306a36Sopenharmony_ci 129362306a36Sopenharmony_ci return ioctl_func(filp, cmd, arg); 129462306a36Sopenharmony_ci 129562306a36Sopenharmony_ciout_io_encoding: 129662306a36Sopenharmony_ci DRM_ERROR("Invalid command format, ioctl %d\n", 129762306a36Sopenharmony_ci nr - DRM_COMMAND_BASE); 129862306a36Sopenharmony_ci 129962306a36Sopenharmony_ci return -EINVAL; 130062306a36Sopenharmony_ci} 130162306a36Sopenharmony_ci 130262306a36Sopenharmony_cistatic long vmw_unlocked_ioctl(struct file *filp, unsigned int cmd, 130362306a36Sopenharmony_ci unsigned long arg) 130462306a36Sopenharmony_ci{ 130562306a36Sopenharmony_ci return vmw_generic_ioctl(filp, cmd, arg, &drm_ioctl); 130662306a36Sopenharmony_ci} 130762306a36Sopenharmony_ci 130862306a36Sopenharmony_ci#ifdef CONFIG_COMPAT 130962306a36Sopenharmony_cistatic long vmw_compat_ioctl(struct file *filp, unsigned int cmd, 131062306a36Sopenharmony_ci unsigned long arg) 131162306a36Sopenharmony_ci{ 131262306a36Sopenharmony_ci return vmw_generic_ioctl(filp, cmd, arg, &drm_compat_ioctl); 131362306a36Sopenharmony_ci} 131462306a36Sopenharmony_ci#endif 131562306a36Sopenharmony_ci 131662306a36Sopenharmony_cistatic void vmw_master_set(struct drm_device *dev, 131762306a36Sopenharmony_ci struct drm_file *file_priv, 131862306a36Sopenharmony_ci bool from_open) 131962306a36Sopenharmony_ci{ 132062306a36Sopenharmony_ci /* 132162306a36Sopenharmony_ci * Inform a new master that the layout may have changed while 132262306a36Sopenharmony_ci * it was gone. 132362306a36Sopenharmony_ci */ 132462306a36Sopenharmony_ci if (!from_open) 132562306a36Sopenharmony_ci drm_sysfs_hotplug_event(dev); 132662306a36Sopenharmony_ci} 132762306a36Sopenharmony_ci 132862306a36Sopenharmony_cistatic void vmw_master_drop(struct drm_device *dev, 132962306a36Sopenharmony_ci struct drm_file *file_priv) 133062306a36Sopenharmony_ci{ 133162306a36Sopenharmony_ci struct vmw_private *dev_priv = vmw_priv(dev); 133262306a36Sopenharmony_ci 133362306a36Sopenharmony_ci vmw_kms_legacy_hotspot_clear(dev_priv); 133462306a36Sopenharmony_ci} 133562306a36Sopenharmony_ci 133662306a36Sopenharmony_cibool vmwgfx_supported(struct vmw_private *vmw) 133762306a36Sopenharmony_ci{ 133862306a36Sopenharmony_ci#if defined(CONFIG_X86) 133962306a36Sopenharmony_ci return hypervisor_is_type(X86_HYPER_VMWARE); 134062306a36Sopenharmony_ci#elif defined(CONFIG_ARM64) 134162306a36Sopenharmony_ci /* 134262306a36Sopenharmony_ci * On aarch64 only svga3 is supported 134362306a36Sopenharmony_ci */ 134462306a36Sopenharmony_ci return vmw->pci_id == VMWGFX_PCI_ID_SVGA3; 134562306a36Sopenharmony_ci#else 134662306a36Sopenharmony_ci drm_warn_once(&vmw->drm, 134762306a36Sopenharmony_ci "vmwgfx is running on an unknown architecture."); 134862306a36Sopenharmony_ci return false; 134962306a36Sopenharmony_ci#endif 135062306a36Sopenharmony_ci} 135162306a36Sopenharmony_ci 135262306a36Sopenharmony_ci/** 135362306a36Sopenharmony_ci * __vmw_svga_enable - Enable SVGA mode, FIFO and use of VRAM. 135462306a36Sopenharmony_ci * 135562306a36Sopenharmony_ci * @dev_priv: Pointer to device private struct. 135662306a36Sopenharmony_ci * Needs the reservation sem to be held in non-exclusive mode. 135762306a36Sopenharmony_ci */ 135862306a36Sopenharmony_cistatic void __vmw_svga_enable(struct vmw_private *dev_priv) 135962306a36Sopenharmony_ci{ 136062306a36Sopenharmony_ci struct ttm_resource_manager *man = ttm_manager_type(&dev_priv->bdev, TTM_PL_VRAM); 136162306a36Sopenharmony_ci 136262306a36Sopenharmony_ci if (!ttm_resource_manager_used(man)) { 136362306a36Sopenharmony_ci vmw_write(dev_priv, SVGA_REG_ENABLE, SVGA_REG_ENABLE_ENABLE); 136462306a36Sopenharmony_ci ttm_resource_manager_set_used(man, true); 136562306a36Sopenharmony_ci } 136662306a36Sopenharmony_ci} 136762306a36Sopenharmony_ci 136862306a36Sopenharmony_ci/** 136962306a36Sopenharmony_ci * vmw_svga_enable - Enable SVGA mode, FIFO and use of VRAM. 137062306a36Sopenharmony_ci * 137162306a36Sopenharmony_ci * @dev_priv: Pointer to device private struct. 137262306a36Sopenharmony_ci */ 137362306a36Sopenharmony_civoid vmw_svga_enable(struct vmw_private *dev_priv) 137462306a36Sopenharmony_ci{ 137562306a36Sopenharmony_ci __vmw_svga_enable(dev_priv); 137662306a36Sopenharmony_ci} 137762306a36Sopenharmony_ci 137862306a36Sopenharmony_ci/** 137962306a36Sopenharmony_ci * __vmw_svga_disable - Disable SVGA mode and use of VRAM. 138062306a36Sopenharmony_ci * 138162306a36Sopenharmony_ci * @dev_priv: Pointer to device private struct. 138262306a36Sopenharmony_ci * Needs the reservation sem to be held in exclusive mode. 138362306a36Sopenharmony_ci * Will not empty VRAM. VRAM must be emptied by caller. 138462306a36Sopenharmony_ci */ 138562306a36Sopenharmony_cistatic void __vmw_svga_disable(struct vmw_private *dev_priv) 138662306a36Sopenharmony_ci{ 138762306a36Sopenharmony_ci struct ttm_resource_manager *man = ttm_manager_type(&dev_priv->bdev, TTM_PL_VRAM); 138862306a36Sopenharmony_ci 138962306a36Sopenharmony_ci if (ttm_resource_manager_used(man)) { 139062306a36Sopenharmony_ci ttm_resource_manager_set_used(man, false); 139162306a36Sopenharmony_ci vmw_write(dev_priv, SVGA_REG_ENABLE, 139262306a36Sopenharmony_ci SVGA_REG_ENABLE_HIDE | 139362306a36Sopenharmony_ci SVGA_REG_ENABLE_ENABLE); 139462306a36Sopenharmony_ci } 139562306a36Sopenharmony_ci} 139662306a36Sopenharmony_ci 139762306a36Sopenharmony_ci/** 139862306a36Sopenharmony_ci * vmw_svga_disable - Disable SVGA_MODE, and use of VRAM. Keep the fifo 139962306a36Sopenharmony_ci * running. 140062306a36Sopenharmony_ci * 140162306a36Sopenharmony_ci * @dev_priv: Pointer to device private struct. 140262306a36Sopenharmony_ci * Will empty VRAM. 140362306a36Sopenharmony_ci */ 140462306a36Sopenharmony_civoid vmw_svga_disable(struct vmw_private *dev_priv) 140562306a36Sopenharmony_ci{ 140662306a36Sopenharmony_ci struct ttm_resource_manager *man = ttm_manager_type(&dev_priv->bdev, TTM_PL_VRAM); 140762306a36Sopenharmony_ci /* 140862306a36Sopenharmony_ci * Disabling SVGA will turn off device modesetting capabilities, so 140962306a36Sopenharmony_ci * notify KMS about that so that it doesn't cache atomic state that 141062306a36Sopenharmony_ci * isn't valid anymore, for example crtcs turned on. 141162306a36Sopenharmony_ci * Strictly we'd want to do this under the SVGA lock (or an SVGA mutex), 141262306a36Sopenharmony_ci * but vmw_kms_lost_device() takes the reservation sem and thus we'll 141362306a36Sopenharmony_ci * end up with lock order reversal. Thus, a master may actually perform 141462306a36Sopenharmony_ci * a new modeset just after we call vmw_kms_lost_device() and race with 141562306a36Sopenharmony_ci * vmw_svga_disable(), but that should at worst cause atomic KMS state 141662306a36Sopenharmony_ci * to be inconsistent with the device, causing modesetting problems. 141762306a36Sopenharmony_ci * 141862306a36Sopenharmony_ci */ 141962306a36Sopenharmony_ci vmw_kms_lost_device(&dev_priv->drm); 142062306a36Sopenharmony_ci if (ttm_resource_manager_used(man)) { 142162306a36Sopenharmony_ci if (ttm_resource_manager_evict_all(&dev_priv->bdev, man)) 142262306a36Sopenharmony_ci DRM_ERROR("Failed evicting VRAM buffers.\n"); 142362306a36Sopenharmony_ci ttm_resource_manager_set_used(man, false); 142462306a36Sopenharmony_ci vmw_write(dev_priv, SVGA_REG_ENABLE, 142562306a36Sopenharmony_ci SVGA_REG_ENABLE_HIDE | 142662306a36Sopenharmony_ci SVGA_REG_ENABLE_ENABLE); 142762306a36Sopenharmony_ci } 142862306a36Sopenharmony_ci} 142962306a36Sopenharmony_ci 143062306a36Sopenharmony_cistatic void vmw_remove(struct pci_dev *pdev) 143162306a36Sopenharmony_ci{ 143262306a36Sopenharmony_ci struct drm_device *dev = pci_get_drvdata(pdev); 143362306a36Sopenharmony_ci 143462306a36Sopenharmony_ci drm_dev_unregister(dev); 143562306a36Sopenharmony_ci vmw_driver_unload(dev); 143662306a36Sopenharmony_ci} 143762306a36Sopenharmony_ci 143862306a36Sopenharmony_cistatic void vmw_debugfs_resource_managers_init(struct vmw_private *vmw) 143962306a36Sopenharmony_ci{ 144062306a36Sopenharmony_ci struct drm_minor *minor = vmw->drm.primary; 144162306a36Sopenharmony_ci struct dentry *root = minor->debugfs_root; 144262306a36Sopenharmony_ci 144362306a36Sopenharmony_ci ttm_resource_manager_create_debugfs(ttm_manager_type(&vmw->bdev, TTM_PL_SYSTEM), 144462306a36Sopenharmony_ci root, "system_ttm"); 144562306a36Sopenharmony_ci ttm_resource_manager_create_debugfs(ttm_manager_type(&vmw->bdev, TTM_PL_VRAM), 144662306a36Sopenharmony_ci root, "vram_ttm"); 144762306a36Sopenharmony_ci ttm_resource_manager_create_debugfs(ttm_manager_type(&vmw->bdev, VMW_PL_GMR), 144862306a36Sopenharmony_ci root, "gmr_ttm"); 144962306a36Sopenharmony_ci ttm_resource_manager_create_debugfs(ttm_manager_type(&vmw->bdev, VMW_PL_MOB), 145062306a36Sopenharmony_ci root, "mob_ttm"); 145162306a36Sopenharmony_ci ttm_resource_manager_create_debugfs(ttm_manager_type(&vmw->bdev, VMW_PL_SYSTEM), 145262306a36Sopenharmony_ci root, "system_mob_ttm"); 145362306a36Sopenharmony_ci} 145462306a36Sopenharmony_ci 145562306a36Sopenharmony_cistatic int vmwgfx_pm_notifier(struct notifier_block *nb, unsigned long val, 145662306a36Sopenharmony_ci void *ptr) 145762306a36Sopenharmony_ci{ 145862306a36Sopenharmony_ci struct vmw_private *dev_priv = 145962306a36Sopenharmony_ci container_of(nb, struct vmw_private, pm_nb); 146062306a36Sopenharmony_ci 146162306a36Sopenharmony_ci switch (val) { 146262306a36Sopenharmony_ci case PM_HIBERNATION_PREPARE: 146362306a36Sopenharmony_ci /* 146462306a36Sopenharmony_ci * Take the reservation sem in write mode, which will make sure 146562306a36Sopenharmony_ci * there are no other processes holding a buffer object 146662306a36Sopenharmony_ci * reservation, meaning we should be able to evict all buffer 146762306a36Sopenharmony_ci * objects if needed. 146862306a36Sopenharmony_ci * Once user-space processes have been frozen, we can release 146962306a36Sopenharmony_ci * the lock again. 147062306a36Sopenharmony_ci */ 147162306a36Sopenharmony_ci dev_priv->suspend_locked = true; 147262306a36Sopenharmony_ci break; 147362306a36Sopenharmony_ci case PM_POST_HIBERNATION: 147462306a36Sopenharmony_ci case PM_POST_RESTORE: 147562306a36Sopenharmony_ci if (READ_ONCE(dev_priv->suspend_locked)) { 147662306a36Sopenharmony_ci dev_priv->suspend_locked = false; 147762306a36Sopenharmony_ci } 147862306a36Sopenharmony_ci break; 147962306a36Sopenharmony_ci default: 148062306a36Sopenharmony_ci break; 148162306a36Sopenharmony_ci } 148262306a36Sopenharmony_ci return 0; 148362306a36Sopenharmony_ci} 148462306a36Sopenharmony_ci 148562306a36Sopenharmony_cistatic int vmw_pci_suspend(struct pci_dev *pdev, pm_message_t state) 148662306a36Sopenharmony_ci{ 148762306a36Sopenharmony_ci struct drm_device *dev = pci_get_drvdata(pdev); 148862306a36Sopenharmony_ci struct vmw_private *dev_priv = vmw_priv(dev); 148962306a36Sopenharmony_ci 149062306a36Sopenharmony_ci if (dev_priv->refuse_hibernation) 149162306a36Sopenharmony_ci return -EBUSY; 149262306a36Sopenharmony_ci 149362306a36Sopenharmony_ci pci_save_state(pdev); 149462306a36Sopenharmony_ci pci_disable_device(pdev); 149562306a36Sopenharmony_ci pci_set_power_state(pdev, PCI_D3hot); 149662306a36Sopenharmony_ci return 0; 149762306a36Sopenharmony_ci} 149862306a36Sopenharmony_ci 149962306a36Sopenharmony_cistatic int vmw_pci_resume(struct pci_dev *pdev) 150062306a36Sopenharmony_ci{ 150162306a36Sopenharmony_ci pci_set_power_state(pdev, PCI_D0); 150262306a36Sopenharmony_ci pci_restore_state(pdev); 150362306a36Sopenharmony_ci return pci_enable_device(pdev); 150462306a36Sopenharmony_ci} 150562306a36Sopenharmony_ci 150662306a36Sopenharmony_cistatic int vmw_pm_suspend(struct device *kdev) 150762306a36Sopenharmony_ci{ 150862306a36Sopenharmony_ci struct pci_dev *pdev = to_pci_dev(kdev); 150962306a36Sopenharmony_ci struct pm_message dummy; 151062306a36Sopenharmony_ci 151162306a36Sopenharmony_ci dummy.event = 0; 151262306a36Sopenharmony_ci 151362306a36Sopenharmony_ci return vmw_pci_suspend(pdev, dummy); 151462306a36Sopenharmony_ci} 151562306a36Sopenharmony_ci 151662306a36Sopenharmony_cistatic int vmw_pm_resume(struct device *kdev) 151762306a36Sopenharmony_ci{ 151862306a36Sopenharmony_ci struct pci_dev *pdev = to_pci_dev(kdev); 151962306a36Sopenharmony_ci 152062306a36Sopenharmony_ci return vmw_pci_resume(pdev); 152162306a36Sopenharmony_ci} 152262306a36Sopenharmony_ci 152362306a36Sopenharmony_cistatic int vmw_pm_freeze(struct device *kdev) 152462306a36Sopenharmony_ci{ 152562306a36Sopenharmony_ci struct pci_dev *pdev = to_pci_dev(kdev); 152662306a36Sopenharmony_ci struct drm_device *dev = pci_get_drvdata(pdev); 152762306a36Sopenharmony_ci struct vmw_private *dev_priv = vmw_priv(dev); 152862306a36Sopenharmony_ci struct ttm_operation_ctx ctx = { 152962306a36Sopenharmony_ci .interruptible = false, 153062306a36Sopenharmony_ci .no_wait_gpu = false 153162306a36Sopenharmony_ci }; 153262306a36Sopenharmony_ci int ret; 153362306a36Sopenharmony_ci 153462306a36Sopenharmony_ci /* 153562306a36Sopenharmony_ci * No user-space processes should be running now. 153662306a36Sopenharmony_ci */ 153762306a36Sopenharmony_ci ret = vmw_kms_suspend(&dev_priv->drm); 153862306a36Sopenharmony_ci if (ret) { 153962306a36Sopenharmony_ci DRM_ERROR("Failed to freeze modesetting.\n"); 154062306a36Sopenharmony_ci return ret; 154162306a36Sopenharmony_ci } 154262306a36Sopenharmony_ci 154362306a36Sopenharmony_ci vmw_execbuf_release_pinned_bo(dev_priv); 154462306a36Sopenharmony_ci vmw_resource_evict_all(dev_priv); 154562306a36Sopenharmony_ci vmw_release_device_early(dev_priv); 154662306a36Sopenharmony_ci while (ttm_device_swapout(&dev_priv->bdev, &ctx, GFP_KERNEL) > 0); 154762306a36Sopenharmony_ci vmw_fifo_resource_dec(dev_priv); 154862306a36Sopenharmony_ci if (atomic_read(&dev_priv->num_fifo_resources) != 0) { 154962306a36Sopenharmony_ci DRM_ERROR("Can't hibernate while 3D resources are active.\n"); 155062306a36Sopenharmony_ci vmw_fifo_resource_inc(dev_priv); 155162306a36Sopenharmony_ci WARN_ON(vmw_request_device_late(dev_priv)); 155262306a36Sopenharmony_ci dev_priv->suspend_locked = false; 155362306a36Sopenharmony_ci if (dev_priv->suspend_state) 155462306a36Sopenharmony_ci vmw_kms_resume(dev); 155562306a36Sopenharmony_ci return -EBUSY; 155662306a36Sopenharmony_ci } 155762306a36Sopenharmony_ci 155862306a36Sopenharmony_ci vmw_fence_fifo_down(dev_priv->fman); 155962306a36Sopenharmony_ci __vmw_svga_disable(dev_priv); 156062306a36Sopenharmony_ci 156162306a36Sopenharmony_ci vmw_release_device_late(dev_priv); 156262306a36Sopenharmony_ci return 0; 156362306a36Sopenharmony_ci} 156462306a36Sopenharmony_ci 156562306a36Sopenharmony_cistatic int vmw_pm_restore(struct device *kdev) 156662306a36Sopenharmony_ci{ 156762306a36Sopenharmony_ci struct pci_dev *pdev = to_pci_dev(kdev); 156862306a36Sopenharmony_ci struct drm_device *dev = pci_get_drvdata(pdev); 156962306a36Sopenharmony_ci struct vmw_private *dev_priv = vmw_priv(dev); 157062306a36Sopenharmony_ci int ret; 157162306a36Sopenharmony_ci 157262306a36Sopenharmony_ci vmw_detect_version(dev_priv); 157362306a36Sopenharmony_ci 157462306a36Sopenharmony_ci vmw_fifo_resource_inc(dev_priv); 157562306a36Sopenharmony_ci 157662306a36Sopenharmony_ci ret = vmw_request_device(dev_priv); 157762306a36Sopenharmony_ci if (ret) 157862306a36Sopenharmony_ci return ret; 157962306a36Sopenharmony_ci 158062306a36Sopenharmony_ci __vmw_svga_enable(dev_priv); 158162306a36Sopenharmony_ci 158262306a36Sopenharmony_ci vmw_fence_fifo_up(dev_priv->fman); 158362306a36Sopenharmony_ci dev_priv->suspend_locked = false; 158462306a36Sopenharmony_ci if (dev_priv->suspend_state) 158562306a36Sopenharmony_ci vmw_kms_resume(&dev_priv->drm); 158662306a36Sopenharmony_ci 158762306a36Sopenharmony_ci return 0; 158862306a36Sopenharmony_ci} 158962306a36Sopenharmony_ci 159062306a36Sopenharmony_cistatic const struct dev_pm_ops vmw_pm_ops = { 159162306a36Sopenharmony_ci .freeze = vmw_pm_freeze, 159262306a36Sopenharmony_ci .thaw = vmw_pm_restore, 159362306a36Sopenharmony_ci .restore = vmw_pm_restore, 159462306a36Sopenharmony_ci .suspend = vmw_pm_suspend, 159562306a36Sopenharmony_ci .resume = vmw_pm_resume, 159662306a36Sopenharmony_ci}; 159762306a36Sopenharmony_ci 159862306a36Sopenharmony_cistatic const struct file_operations vmwgfx_driver_fops = { 159962306a36Sopenharmony_ci .owner = THIS_MODULE, 160062306a36Sopenharmony_ci .open = drm_open, 160162306a36Sopenharmony_ci .release = drm_release, 160262306a36Sopenharmony_ci .unlocked_ioctl = vmw_unlocked_ioctl, 160362306a36Sopenharmony_ci .mmap = drm_gem_mmap, 160462306a36Sopenharmony_ci .poll = drm_poll, 160562306a36Sopenharmony_ci .read = drm_read, 160662306a36Sopenharmony_ci#if defined(CONFIG_COMPAT) 160762306a36Sopenharmony_ci .compat_ioctl = vmw_compat_ioctl, 160862306a36Sopenharmony_ci#endif 160962306a36Sopenharmony_ci .llseek = noop_llseek, 161062306a36Sopenharmony_ci}; 161162306a36Sopenharmony_ci 161262306a36Sopenharmony_cistatic const struct drm_driver driver = { 161362306a36Sopenharmony_ci .driver_features = 161462306a36Sopenharmony_ci DRIVER_MODESET | DRIVER_RENDER | DRIVER_ATOMIC | DRIVER_GEM | DRIVER_CURSOR_HOTSPOT, 161562306a36Sopenharmony_ci .ioctls = vmw_ioctls, 161662306a36Sopenharmony_ci .num_ioctls = ARRAY_SIZE(vmw_ioctls), 161762306a36Sopenharmony_ci .master_set = vmw_master_set, 161862306a36Sopenharmony_ci .master_drop = vmw_master_drop, 161962306a36Sopenharmony_ci .open = vmw_driver_open, 162062306a36Sopenharmony_ci .postclose = vmw_postclose, 162162306a36Sopenharmony_ci 162262306a36Sopenharmony_ci .dumb_create = vmw_dumb_create, 162362306a36Sopenharmony_ci .dumb_map_offset = drm_gem_ttm_dumb_map_offset, 162462306a36Sopenharmony_ci 162562306a36Sopenharmony_ci .prime_fd_to_handle = vmw_prime_fd_to_handle, 162662306a36Sopenharmony_ci .prime_handle_to_fd = vmw_prime_handle_to_fd, 162762306a36Sopenharmony_ci 162862306a36Sopenharmony_ci .fops = &vmwgfx_driver_fops, 162962306a36Sopenharmony_ci .name = VMWGFX_DRIVER_NAME, 163062306a36Sopenharmony_ci .desc = VMWGFX_DRIVER_DESC, 163162306a36Sopenharmony_ci .date = VMWGFX_DRIVER_DATE, 163262306a36Sopenharmony_ci .major = VMWGFX_DRIVER_MAJOR, 163362306a36Sopenharmony_ci .minor = VMWGFX_DRIVER_MINOR, 163462306a36Sopenharmony_ci .patchlevel = VMWGFX_DRIVER_PATCHLEVEL 163562306a36Sopenharmony_ci}; 163662306a36Sopenharmony_ci 163762306a36Sopenharmony_cistatic struct pci_driver vmw_pci_driver = { 163862306a36Sopenharmony_ci .name = VMWGFX_DRIVER_NAME, 163962306a36Sopenharmony_ci .id_table = vmw_pci_id_list, 164062306a36Sopenharmony_ci .probe = vmw_probe, 164162306a36Sopenharmony_ci .remove = vmw_remove, 164262306a36Sopenharmony_ci .driver = { 164362306a36Sopenharmony_ci .pm = &vmw_pm_ops 164462306a36Sopenharmony_ci } 164562306a36Sopenharmony_ci}; 164662306a36Sopenharmony_ci 164762306a36Sopenharmony_cistatic int vmw_probe(struct pci_dev *pdev, const struct pci_device_id *ent) 164862306a36Sopenharmony_ci{ 164962306a36Sopenharmony_ci struct vmw_private *vmw; 165062306a36Sopenharmony_ci int ret; 165162306a36Sopenharmony_ci 165262306a36Sopenharmony_ci ret = drm_aperture_remove_conflicting_pci_framebuffers(pdev, &driver); 165362306a36Sopenharmony_ci if (ret) 165462306a36Sopenharmony_ci goto out_error; 165562306a36Sopenharmony_ci 165662306a36Sopenharmony_ci ret = pcim_enable_device(pdev); 165762306a36Sopenharmony_ci if (ret) 165862306a36Sopenharmony_ci goto out_error; 165962306a36Sopenharmony_ci 166062306a36Sopenharmony_ci vmw = devm_drm_dev_alloc(&pdev->dev, &driver, 166162306a36Sopenharmony_ci struct vmw_private, drm); 166262306a36Sopenharmony_ci if (IS_ERR(vmw)) { 166362306a36Sopenharmony_ci ret = PTR_ERR(vmw); 166462306a36Sopenharmony_ci goto out_error; 166562306a36Sopenharmony_ci } 166662306a36Sopenharmony_ci 166762306a36Sopenharmony_ci pci_set_drvdata(pdev, &vmw->drm); 166862306a36Sopenharmony_ci 166962306a36Sopenharmony_ci ret = vmw_driver_load(vmw, ent->device); 167062306a36Sopenharmony_ci if (ret) 167162306a36Sopenharmony_ci goto out_error; 167262306a36Sopenharmony_ci 167362306a36Sopenharmony_ci ret = drm_dev_register(&vmw->drm, 0); 167462306a36Sopenharmony_ci if (ret) 167562306a36Sopenharmony_ci goto out_unload; 167662306a36Sopenharmony_ci 167762306a36Sopenharmony_ci vmw_fifo_resource_inc(vmw); 167862306a36Sopenharmony_ci vmw_svga_enable(vmw); 167962306a36Sopenharmony_ci drm_fbdev_generic_setup(&vmw->drm, 0); 168062306a36Sopenharmony_ci 168162306a36Sopenharmony_ci vmw_debugfs_gem_init(vmw); 168262306a36Sopenharmony_ci vmw_debugfs_resource_managers_init(vmw); 168362306a36Sopenharmony_ci 168462306a36Sopenharmony_ci return 0; 168562306a36Sopenharmony_ciout_unload: 168662306a36Sopenharmony_ci vmw_driver_unload(&vmw->drm); 168762306a36Sopenharmony_ciout_error: 168862306a36Sopenharmony_ci return ret; 168962306a36Sopenharmony_ci} 169062306a36Sopenharmony_ci 169162306a36Sopenharmony_cidrm_module_pci_driver(vmw_pci_driver); 169262306a36Sopenharmony_ci 169362306a36Sopenharmony_ciMODULE_AUTHOR("VMware Inc. and others"); 169462306a36Sopenharmony_ciMODULE_DESCRIPTION("Standalone drm driver for the VMware SVGA device"); 169562306a36Sopenharmony_ciMODULE_LICENSE("GPL and additional rights"); 169662306a36Sopenharmony_ciMODULE_VERSION(__stringify(VMWGFX_DRIVER_MAJOR) "." 169762306a36Sopenharmony_ci __stringify(VMWGFX_DRIVER_MINOR) "." 169862306a36Sopenharmony_ci __stringify(VMWGFX_DRIVER_PATCHLEVEL) "." 169962306a36Sopenharmony_ci "0"); 1700