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