18c2ecf20Sopenharmony_ci/*
28c2ecf20Sopenharmony_ci * Copyright(c) 2011-2016 Intel Corporation. All rights reserved.
38c2ecf20Sopenharmony_ci *
48c2ecf20Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a
58c2ecf20Sopenharmony_ci * copy of this software and associated documentation files (the "Software"),
68c2ecf20Sopenharmony_ci * to deal in the Software without restriction, including without limitation
78c2ecf20Sopenharmony_ci * the rights to use, copy, modify, merge, publish, distribute, sublicense,
88c2ecf20Sopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the
98c2ecf20Sopenharmony_ci * Software is furnished to do so, subject to the following conditions:
108c2ecf20Sopenharmony_ci *
118c2ecf20Sopenharmony_ci * The above copyright notice and this permission notice (including the next
128c2ecf20Sopenharmony_ci * paragraph) shall be included in all copies or substantial portions of the
138c2ecf20Sopenharmony_ci * Software.
148c2ecf20Sopenharmony_ci *
158c2ecf20Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
168c2ecf20Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
178c2ecf20Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
188c2ecf20Sopenharmony_ci * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
198c2ecf20Sopenharmony_ci * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
208c2ecf20Sopenharmony_ci * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
218c2ecf20Sopenharmony_ci * SOFTWARE.
228c2ecf20Sopenharmony_ci *
238c2ecf20Sopenharmony_ci * Authors:
248c2ecf20Sopenharmony_ci *    Kevin Tian <kevin.tian@intel.com>
258c2ecf20Sopenharmony_ci *    Eddie Dong <eddie.dong@intel.com>
268c2ecf20Sopenharmony_ci *
278c2ecf20Sopenharmony_ci * Contributors:
288c2ecf20Sopenharmony_ci *    Niu Bing <bing.niu@intel.com>
298c2ecf20Sopenharmony_ci *    Zhi Wang <zhi.a.wang@intel.com>
308c2ecf20Sopenharmony_ci *
318c2ecf20Sopenharmony_ci */
328c2ecf20Sopenharmony_ci
338c2ecf20Sopenharmony_ci#include <linux/types.h>
348c2ecf20Sopenharmony_ci#include <linux/kthread.h>
358c2ecf20Sopenharmony_ci
368c2ecf20Sopenharmony_ci#include "i915_drv.h"
378c2ecf20Sopenharmony_ci#include "intel_gvt.h"
388c2ecf20Sopenharmony_ci#include "gvt.h"
398c2ecf20Sopenharmony_ci#include <linux/vfio.h>
408c2ecf20Sopenharmony_ci#include <linux/mdev.h>
418c2ecf20Sopenharmony_ci
428c2ecf20Sopenharmony_cistruct intel_gvt_host intel_gvt_host;
438c2ecf20Sopenharmony_ci
448c2ecf20Sopenharmony_cistatic const char * const supported_hypervisors[] = {
458c2ecf20Sopenharmony_ci	[INTEL_GVT_HYPERVISOR_XEN] = "XEN",
468c2ecf20Sopenharmony_ci	[INTEL_GVT_HYPERVISOR_KVM] = "KVM",
478c2ecf20Sopenharmony_ci};
488c2ecf20Sopenharmony_ci
498c2ecf20Sopenharmony_cistatic struct intel_vgpu_type *intel_gvt_find_vgpu_type(struct intel_gvt *gvt,
508c2ecf20Sopenharmony_ci		const char *name)
518c2ecf20Sopenharmony_ci{
528c2ecf20Sopenharmony_ci	const char *driver_name =
538c2ecf20Sopenharmony_ci		dev_driver_string(&gvt->gt->i915->drm.pdev->dev);
548c2ecf20Sopenharmony_ci	int i;
558c2ecf20Sopenharmony_ci
568c2ecf20Sopenharmony_ci	name += strlen(driver_name) + 1;
578c2ecf20Sopenharmony_ci	for (i = 0; i < gvt->num_types; i++) {
588c2ecf20Sopenharmony_ci		struct intel_vgpu_type *t = &gvt->types[i];
598c2ecf20Sopenharmony_ci
608c2ecf20Sopenharmony_ci		if (!strncmp(t->name, name, sizeof(t->name)))
618c2ecf20Sopenharmony_ci			return t;
628c2ecf20Sopenharmony_ci	}
638c2ecf20Sopenharmony_ci
648c2ecf20Sopenharmony_ci	return NULL;
658c2ecf20Sopenharmony_ci}
668c2ecf20Sopenharmony_ci
678c2ecf20Sopenharmony_cistatic ssize_t available_instances_show(struct kobject *kobj,
688c2ecf20Sopenharmony_ci					struct device *dev, char *buf)
698c2ecf20Sopenharmony_ci{
708c2ecf20Sopenharmony_ci	struct intel_vgpu_type *type;
718c2ecf20Sopenharmony_ci	unsigned int num = 0;
728c2ecf20Sopenharmony_ci	void *gvt = kdev_to_i915(dev)->gvt;
738c2ecf20Sopenharmony_ci
748c2ecf20Sopenharmony_ci	type = intel_gvt_find_vgpu_type(gvt, kobject_name(kobj));
758c2ecf20Sopenharmony_ci	if (!type)
768c2ecf20Sopenharmony_ci		num = 0;
778c2ecf20Sopenharmony_ci	else
788c2ecf20Sopenharmony_ci		num = type->avail_instance;
798c2ecf20Sopenharmony_ci
808c2ecf20Sopenharmony_ci	return sprintf(buf, "%u\n", num);
818c2ecf20Sopenharmony_ci}
828c2ecf20Sopenharmony_ci
838c2ecf20Sopenharmony_cistatic ssize_t device_api_show(struct kobject *kobj, struct device *dev,
848c2ecf20Sopenharmony_ci		char *buf)
858c2ecf20Sopenharmony_ci{
868c2ecf20Sopenharmony_ci	return sprintf(buf, "%s\n", VFIO_DEVICE_API_PCI_STRING);
878c2ecf20Sopenharmony_ci}
888c2ecf20Sopenharmony_ci
898c2ecf20Sopenharmony_cistatic ssize_t description_show(struct kobject *kobj, struct device *dev,
908c2ecf20Sopenharmony_ci		char *buf)
918c2ecf20Sopenharmony_ci{
928c2ecf20Sopenharmony_ci	struct intel_vgpu_type *type;
938c2ecf20Sopenharmony_ci	void *gvt = kdev_to_i915(dev)->gvt;
948c2ecf20Sopenharmony_ci
958c2ecf20Sopenharmony_ci	type = intel_gvt_find_vgpu_type(gvt, kobject_name(kobj));
968c2ecf20Sopenharmony_ci	if (!type)
978c2ecf20Sopenharmony_ci		return 0;
988c2ecf20Sopenharmony_ci
998c2ecf20Sopenharmony_ci	return sprintf(buf, "low_gm_size: %dMB\nhigh_gm_size: %dMB\n"
1008c2ecf20Sopenharmony_ci		       "fence: %d\nresolution: %s\n"
1018c2ecf20Sopenharmony_ci		       "weight: %d\n",
1028c2ecf20Sopenharmony_ci		       BYTES_TO_MB(type->low_gm_size),
1038c2ecf20Sopenharmony_ci		       BYTES_TO_MB(type->high_gm_size),
1048c2ecf20Sopenharmony_ci		       type->fence, vgpu_edid_str(type->resolution),
1058c2ecf20Sopenharmony_ci		       type->weight);
1068c2ecf20Sopenharmony_ci}
1078c2ecf20Sopenharmony_ci
1088c2ecf20Sopenharmony_cistatic MDEV_TYPE_ATTR_RO(available_instances);
1098c2ecf20Sopenharmony_cistatic MDEV_TYPE_ATTR_RO(device_api);
1108c2ecf20Sopenharmony_cistatic MDEV_TYPE_ATTR_RO(description);
1118c2ecf20Sopenharmony_ci
1128c2ecf20Sopenharmony_cistatic struct attribute *gvt_type_attrs[] = {
1138c2ecf20Sopenharmony_ci	&mdev_type_attr_available_instances.attr,
1148c2ecf20Sopenharmony_ci	&mdev_type_attr_device_api.attr,
1158c2ecf20Sopenharmony_ci	&mdev_type_attr_description.attr,
1168c2ecf20Sopenharmony_ci	NULL,
1178c2ecf20Sopenharmony_ci};
1188c2ecf20Sopenharmony_ci
1198c2ecf20Sopenharmony_cistatic struct attribute_group *gvt_vgpu_type_groups[] = {
1208c2ecf20Sopenharmony_ci	[0 ... NR_MAX_INTEL_VGPU_TYPES - 1] = NULL,
1218c2ecf20Sopenharmony_ci};
1228c2ecf20Sopenharmony_ci
1238c2ecf20Sopenharmony_cistatic bool intel_get_gvt_attrs(struct attribute_group ***intel_vgpu_type_groups)
1248c2ecf20Sopenharmony_ci{
1258c2ecf20Sopenharmony_ci	*intel_vgpu_type_groups = gvt_vgpu_type_groups;
1268c2ecf20Sopenharmony_ci	return true;
1278c2ecf20Sopenharmony_ci}
1288c2ecf20Sopenharmony_ci
1298c2ecf20Sopenharmony_cistatic int intel_gvt_init_vgpu_type_groups(struct intel_gvt *gvt)
1308c2ecf20Sopenharmony_ci{
1318c2ecf20Sopenharmony_ci	int i, j;
1328c2ecf20Sopenharmony_ci	struct intel_vgpu_type *type;
1338c2ecf20Sopenharmony_ci	struct attribute_group *group;
1348c2ecf20Sopenharmony_ci
1358c2ecf20Sopenharmony_ci	for (i = 0; i < gvt->num_types; i++) {
1368c2ecf20Sopenharmony_ci		type = &gvt->types[i];
1378c2ecf20Sopenharmony_ci
1388c2ecf20Sopenharmony_ci		group = kzalloc(sizeof(struct attribute_group), GFP_KERNEL);
1398c2ecf20Sopenharmony_ci		if (WARN_ON(!group))
1408c2ecf20Sopenharmony_ci			goto unwind;
1418c2ecf20Sopenharmony_ci
1428c2ecf20Sopenharmony_ci		group->name = type->name;
1438c2ecf20Sopenharmony_ci		group->attrs = gvt_type_attrs;
1448c2ecf20Sopenharmony_ci		gvt_vgpu_type_groups[i] = group;
1458c2ecf20Sopenharmony_ci	}
1468c2ecf20Sopenharmony_ci
1478c2ecf20Sopenharmony_ci	return 0;
1488c2ecf20Sopenharmony_ci
1498c2ecf20Sopenharmony_ciunwind:
1508c2ecf20Sopenharmony_ci	for (j = 0; j < i; j++) {
1518c2ecf20Sopenharmony_ci		group = gvt_vgpu_type_groups[j];
1528c2ecf20Sopenharmony_ci		kfree(group);
1538c2ecf20Sopenharmony_ci	}
1548c2ecf20Sopenharmony_ci
1558c2ecf20Sopenharmony_ci	return -ENOMEM;
1568c2ecf20Sopenharmony_ci}
1578c2ecf20Sopenharmony_ci
1588c2ecf20Sopenharmony_cistatic void intel_gvt_cleanup_vgpu_type_groups(struct intel_gvt *gvt)
1598c2ecf20Sopenharmony_ci{
1608c2ecf20Sopenharmony_ci	int i;
1618c2ecf20Sopenharmony_ci	struct attribute_group *group;
1628c2ecf20Sopenharmony_ci
1638c2ecf20Sopenharmony_ci	for (i = 0; i < gvt->num_types; i++) {
1648c2ecf20Sopenharmony_ci		group = gvt_vgpu_type_groups[i];
1658c2ecf20Sopenharmony_ci		gvt_vgpu_type_groups[i] = NULL;
1668c2ecf20Sopenharmony_ci		kfree(group);
1678c2ecf20Sopenharmony_ci	}
1688c2ecf20Sopenharmony_ci}
1698c2ecf20Sopenharmony_ci
1708c2ecf20Sopenharmony_cistatic const struct intel_gvt_ops intel_gvt_ops = {
1718c2ecf20Sopenharmony_ci	.emulate_cfg_read = intel_vgpu_emulate_cfg_read,
1728c2ecf20Sopenharmony_ci	.emulate_cfg_write = intel_vgpu_emulate_cfg_write,
1738c2ecf20Sopenharmony_ci	.emulate_mmio_read = intel_vgpu_emulate_mmio_read,
1748c2ecf20Sopenharmony_ci	.emulate_mmio_write = intel_vgpu_emulate_mmio_write,
1758c2ecf20Sopenharmony_ci	.vgpu_create = intel_gvt_create_vgpu,
1768c2ecf20Sopenharmony_ci	.vgpu_destroy = intel_gvt_destroy_vgpu,
1778c2ecf20Sopenharmony_ci	.vgpu_release = intel_gvt_release_vgpu,
1788c2ecf20Sopenharmony_ci	.vgpu_reset = intel_gvt_reset_vgpu,
1798c2ecf20Sopenharmony_ci	.vgpu_activate = intel_gvt_activate_vgpu,
1808c2ecf20Sopenharmony_ci	.vgpu_deactivate = intel_gvt_deactivate_vgpu,
1818c2ecf20Sopenharmony_ci	.gvt_find_vgpu_type = intel_gvt_find_vgpu_type,
1828c2ecf20Sopenharmony_ci	.get_gvt_attrs = intel_get_gvt_attrs,
1838c2ecf20Sopenharmony_ci	.vgpu_query_plane = intel_vgpu_query_plane,
1848c2ecf20Sopenharmony_ci	.vgpu_get_dmabuf = intel_vgpu_get_dmabuf,
1858c2ecf20Sopenharmony_ci	.write_protect_handler = intel_vgpu_page_track_handler,
1868c2ecf20Sopenharmony_ci	.emulate_hotplug = intel_vgpu_emulate_hotplug,
1878c2ecf20Sopenharmony_ci};
1888c2ecf20Sopenharmony_ci
1898c2ecf20Sopenharmony_cistatic void init_device_info(struct intel_gvt *gvt)
1908c2ecf20Sopenharmony_ci{
1918c2ecf20Sopenharmony_ci	struct intel_gvt_device_info *info = &gvt->device_info;
1928c2ecf20Sopenharmony_ci	struct pci_dev *pdev = gvt->gt->i915->drm.pdev;
1938c2ecf20Sopenharmony_ci
1948c2ecf20Sopenharmony_ci	info->max_support_vgpus = 8;
1958c2ecf20Sopenharmony_ci	info->cfg_space_size = PCI_CFG_SPACE_EXP_SIZE;
1968c2ecf20Sopenharmony_ci	info->mmio_size = 2 * 1024 * 1024;
1978c2ecf20Sopenharmony_ci	info->mmio_bar = 0;
1988c2ecf20Sopenharmony_ci	info->gtt_start_offset = 8 * 1024 * 1024;
1998c2ecf20Sopenharmony_ci	info->gtt_entry_size = 8;
2008c2ecf20Sopenharmony_ci	info->gtt_entry_size_shift = 3;
2018c2ecf20Sopenharmony_ci	info->gmadr_bytes_in_cmd = 8;
2028c2ecf20Sopenharmony_ci	info->max_surface_size = 36 * 1024 * 1024;
2038c2ecf20Sopenharmony_ci	info->msi_cap_offset = pdev->msi_cap;
2048c2ecf20Sopenharmony_ci}
2058c2ecf20Sopenharmony_ci
2068c2ecf20Sopenharmony_cistatic int gvt_service_thread(void *data)
2078c2ecf20Sopenharmony_ci{
2088c2ecf20Sopenharmony_ci	struct intel_gvt *gvt = (struct intel_gvt *)data;
2098c2ecf20Sopenharmony_ci	int ret;
2108c2ecf20Sopenharmony_ci
2118c2ecf20Sopenharmony_ci	gvt_dbg_core("service thread start\n");
2128c2ecf20Sopenharmony_ci
2138c2ecf20Sopenharmony_ci	while (!kthread_should_stop()) {
2148c2ecf20Sopenharmony_ci		ret = wait_event_interruptible(gvt->service_thread_wq,
2158c2ecf20Sopenharmony_ci				kthread_should_stop() || gvt->service_request);
2168c2ecf20Sopenharmony_ci
2178c2ecf20Sopenharmony_ci		if (kthread_should_stop())
2188c2ecf20Sopenharmony_ci			break;
2198c2ecf20Sopenharmony_ci
2208c2ecf20Sopenharmony_ci		if (WARN_ONCE(ret, "service thread is waken up by signal.\n"))
2218c2ecf20Sopenharmony_ci			continue;
2228c2ecf20Sopenharmony_ci
2238c2ecf20Sopenharmony_ci		if (test_and_clear_bit(INTEL_GVT_REQUEST_EMULATE_VBLANK,
2248c2ecf20Sopenharmony_ci					(void *)&gvt->service_request))
2258c2ecf20Sopenharmony_ci			intel_gvt_emulate_vblank(gvt);
2268c2ecf20Sopenharmony_ci
2278c2ecf20Sopenharmony_ci		if (test_bit(INTEL_GVT_REQUEST_SCHED,
2288c2ecf20Sopenharmony_ci				(void *)&gvt->service_request) ||
2298c2ecf20Sopenharmony_ci			test_bit(INTEL_GVT_REQUEST_EVENT_SCHED,
2308c2ecf20Sopenharmony_ci					(void *)&gvt->service_request)) {
2318c2ecf20Sopenharmony_ci			intel_gvt_schedule(gvt);
2328c2ecf20Sopenharmony_ci		}
2338c2ecf20Sopenharmony_ci	}
2348c2ecf20Sopenharmony_ci
2358c2ecf20Sopenharmony_ci	return 0;
2368c2ecf20Sopenharmony_ci}
2378c2ecf20Sopenharmony_ci
2388c2ecf20Sopenharmony_cistatic void clean_service_thread(struct intel_gvt *gvt)
2398c2ecf20Sopenharmony_ci{
2408c2ecf20Sopenharmony_ci	kthread_stop(gvt->service_thread);
2418c2ecf20Sopenharmony_ci}
2428c2ecf20Sopenharmony_ci
2438c2ecf20Sopenharmony_cistatic int init_service_thread(struct intel_gvt *gvt)
2448c2ecf20Sopenharmony_ci{
2458c2ecf20Sopenharmony_ci	init_waitqueue_head(&gvt->service_thread_wq);
2468c2ecf20Sopenharmony_ci
2478c2ecf20Sopenharmony_ci	gvt->service_thread = kthread_run(gvt_service_thread,
2488c2ecf20Sopenharmony_ci			gvt, "gvt_service_thread");
2498c2ecf20Sopenharmony_ci	if (IS_ERR(gvt->service_thread)) {
2508c2ecf20Sopenharmony_ci		gvt_err("fail to start service thread.\n");
2518c2ecf20Sopenharmony_ci		return PTR_ERR(gvt->service_thread);
2528c2ecf20Sopenharmony_ci	}
2538c2ecf20Sopenharmony_ci	return 0;
2548c2ecf20Sopenharmony_ci}
2558c2ecf20Sopenharmony_ci
2568c2ecf20Sopenharmony_ci/**
2578c2ecf20Sopenharmony_ci * intel_gvt_clean_device - clean a GVT device
2588c2ecf20Sopenharmony_ci * @i915: i915 private
2598c2ecf20Sopenharmony_ci *
2608c2ecf20Sopenharmony_ci * This function is called at the driver unloading stage, to free the
2618c2ecf20Sopenharmony_ci * resources owned by a GVT device.
2628c2ecf20Sopenharmony_ci *
2638c2ecf20Sopenharmony_ci */
2648c2ecf20Sopenharmony_civoid intel_gvt_clean_device(struct drm_i915_private *i915)
2658c2ecf20Sopenharmony_ci{
2668c2ecf20Sopenharmony_ci	struct intel_gvt *gvt = fetch_and_zero(&i915->gvt);
2678c2ecf20Sopenharmony_ci
2688c2ecf20Sopenharmony_ci	if (drm_WARN_ON(&i915->drm, !gvt))
2698c2ecf20Sopenharmony_ci		return;
2708c2ecf20Sopenharmony_ci
2718c2ecf20Sopenharmony_ci	intel_gvt_destroy_idle_vgpu(gvt->idle_vgpu);
2728c2ecf20Sopenharmony_ci	intel_gvt_cleanup_vgpu_type_groups(gvt);
2738c2ecf20Sopenharmony_ci	intel_gvt_clean_vgpu_types(gvt);
2748c2ecf20Sopenharmony_ci
2758c2ecf20Sopenharmony_ci	intel_gvt_debugfs_clean(gvt);
2768c2ecf20Sopenharmony_ci	clean_service_thread(gvt);
2778c2ecf20Sopenharmony_ci	intel_gvt_clean_cmd_parser(gvt);
2788c2ecf20Sopenharmony_ci	intel_gvt_clean_sched_policy(gvt);
2798c2ecf20Sopenharmony_ci	intel_gvt_clean_workload_scheduler(gvt);
2808c2ecf20Sopenharmony_ci	intel_gvt_clean_gtt(gvt);
2818c2ecf20Sopenharmony_ci	intel_gvt_clean_irq(gvt);
2828c2ecf20Sopenharmony_ci	intel_gvt_free_firmware(gvt);
2838c2ecf20Sopenharmony_ci	intel_gvt_clean_mmio_info(gvt);
2848c2ecf20Sopenharmony_ci	idr_destroy(&gvt->vgpu_idr);
2858c2ecf20Sopenharmony_ci
2868c2ecf20Sopenharmony_ci	kfree(i915->gvt);
2878c2ecf20Sopenharmony_ci}
2888c2ecf20Sopenharmony_ci
2898c2ecf20Sopenharmony_ci/**
2908c2ecf20Sopenharmony_ci * intel_gvt_init_device - initialize a GVT device
2918c2ecf20Sopenharmony_ci * @i915: drm i915 private data
2928c2ecf20Sopenharmony_ci *
2938c2ecf20Sopenharmony_ci * This function is called at the initialization stage, to initialize
2948c2ecf20Sopenharmony_ci * necessary GVT components.
2958c2ecf20Sopenharmony_ci *
2968c2ecf20Sopenharmony_ci * Returns:
2978c2ecf20Sopenharmony_ci * Zero on success, negative error code if failed.
2988c2ecf20Sopenharmony_ci *
2998c2ecf20Sopenharmony_ci */
3008c2ecf20Sopenharmony_ciint intel_gvt_init_device(struct drm_i915_private *i915)
3018c2ecf20Sopenharmony_ci{
3028c2ecf20Sopenharmony_ci	struct intel_gvt *gvt;
3038c2ecf20Sopenharmony_ci	struct intel_vgpu *vgpu;
3048c2ecf20Sopenharmony_ci	int ret;
3058c2ecf20Sopenharmony_ci
3068c2ecf20Sopenharmony_ci	if (drm_WARN_ON(&i915->drm, i915->gvt))
3078c2ecf20Sopenharmony_ci		return -EEXIST;
3088c2ecf20Sopenharmony_ci
3098c2ecf20Sopenharmony_ci	gvt = kzalloc(sizeof(struct intel_gvt), GFP_KERNEL);
3108c2ecf20Sopenharmony_ci	if (!gvt)
3118c2ecf20Sopenharmony_ci		return -ENOMEM;
3128c2ecf20Sopenharmony_ci
3138c2ecf20Sopenharmony_ci	gvt_dbg_core("init gvt device\n");
3148c2ecf20Sopenharmony_ci
3158c2ecf20Sopenharmony_ci	idr_init(&gvt->vgpu_idr);
3168c2ecf20Sopenharmony_ci	spin_lock_init(&gvt->scheduler.mmio_context_lock);
3178c2ecf20Sopenharmony_ci	mutex_init(&gvt->lock);
3188c2ecf20Sopenharmony_ci	mutex_init(&gvt->sched_lock);
3198c2ecf20Sopenharmony_ci	gvt->gt = &i915->gt;
3208c2ecf20Sopenharmony_ci	i915->gvt = gvt;
3218c2ecf20Sopenharmony_ci
3228c2ecf20Sopenharmony_ci	init_device_info(gvt);
3238c2ecf20Sopenharmony_ci
3248c2ecf20Sopenharmony_ci	ret = intel_gvt_setup_mmio_info(gvt);
3258c2ecf20Sopenharmony_ci	if (ret)
3268c2ecf20Sopenharmony_ci		goto out_clean_idr;
3278c2ecf20Sopenharmony_ci
3288c2ecf20Sopenharmony_ci	intel_gvt_init_engine_mmio_context(gvt);
3298c2ecf20Sopenharmony_ci
3308c2ecf20Sopenharmony_ci	ret = intel_gvt_load_firmware(gvt);
3318c2ecf20Sopenharmony_ci	if (ret)
3328c2ecf20Sopenharmony_ci		goto out_clean_mmio_info;
3338c2ecf20Sopenharmony_ci
3348c2ecf20Sopenharmony_ci	ret = intel_gvt_init_irq(gvt);
3358c2ecf20Sopenharmony_ci	if (ret)
3368c2ecf20Sopenharmony_ci		goto out_free_firmware;
3378c2ecf20Sopenharmony_ci
3388c2ecf20Sopenharmony_ci	ret = intel_gvt_init_gtt(gvt);
3398c2ecf20Sopenharmony_ci	if (ret)
3408c2ecf20Sopenharmony_ci		goto out_clean_irq;
3418c2ecf20Sopenharmony_ci
3428c2ecf20Sopenharmony_ci	ret = intel_gvt_init_workload_scheduler(gvt);
3438c2ecf20Sopenharmony_ci	if (ret)
3448c2ecf20Sopenharmony_ci		goto out_clean_gtt;
3458c2ecf20Sopenharmony_ci
3468c2ecf20Sopenharmony_ci	ret = intel_gvt_init_sched_policy(gvt);
3478c2ecf20Sopenharmony_ci	if (ret)
3488c2ecf20Sopenharmony_ci		goto out_clean_workload_scheduler;
3498c2ecf20Sopenharmony_ci
3508c2ecf20Sopenharmony_ci	ret = intel_gvt_init_cmd_parser(gvt);
3518c2ecf20Sopenharmony_ci	if (ret)
3528c2ecf20Sopenharmony_ci		goto out_clean_sched_policy;
3538c2ecf20Sopenharmony_ci
3548c2ecf20Sopenharmony_ci	ret = init_service_thread(gvt);
3558c2ecf20Sopenharmony_ci	if (ret)
3568c2ecf20Sopenharmony_ci		goto out_clean_cmd_parser;
3578c2ecf20Sopenharmony_ci
3588c2ecf20Sopenharmony_ci	ret = intel_gvt_init_vgpu_types(gvt);
3598c2ecf20Sopenharmony_ci	if (ret)
3608c2ecf20Sopenharmony_ci		goto out_clean_thread;
3618c2ecf20Sopenharmony_ci
3628c2ecf20Sopenharmony_ci	ret = intel_gvt_init_vgpu_type_groups(gvt);
3638c2ecf20Sopenharmony_ci	if (ret) {
3648c2ecf20Sopenharmony_ci		gvt_err("failed to init vgpu type groups: %d\n", ret);
3658c2ecf20Sopenharmony_ci		goto out_clean_types;
3668c2ecf20Sopenharmony_ci	}
3678c2ecf20Sopenharmony_ci
3688c2ecf20Sopenharmony_ci	vgpu = intel_gvt_create_idle_vgpu(gvt);
3698c2ecf20Sopenharmony_ci	if (IS_ERR(vgpu)) {
3708c2ecf20Sopenharmony_ci		ret = PTR_ERR(vgpu);
3718c2ecf20Sopenharmony_ci		gvt_err("failed to create idle vgpu\n");
3728c2ecf20Sopenharmony_ci		goto out_clean_types;
3738c2ecf20Sopenharmony_ci	}
3748c2ecf20Sopenharmony_ci	gvt->idle_vgpu = vgpu;
3758c2ecf20Sopenharmony_ci
3768c2ecf20Sopenharmony_ci	intel_gvt_debugfs_init(gvt);
3778c2ecf20Sopenharmony_ci
3788c2ecf20Sopenharmony_ci	gvt_dbg_core("gvt device initialization is done\n");
3798c2ecf20Sopenharmony_ci	intel_gvt_host.dev = &i915->drm.pdev->dev;
3808c2ecf20Sopenharmony_ci	intel_gvt_host.initialized = true;
3818c2ecf20Sopenharmony_ci	return 0;
3828c2ecf20Sopenharmony_ci
3838c2ecf20Sopenharmony_ciout_clean_types:
3848c2ecf20Sopenharmony_ci	intel_gvt_clean_vgpu_types(gvt);
3858c2ecf20Sopenharmony_ciout_clean_thread:
3868c2ecf20Sopenharmony_ci	clean_service_thread(gvt);
3878c2ecf20Sopenharmony_ciout_clean_cmd_parser:
3888c2ecf20Sopenharmony_ci	intel_gvt_clean_cmd_parser(gvt);
3898c2ecf20Sopenharmony_ciout_clean_sched_policy:
3908c2ecf20Sopenharmony_ci	intel_gvt_clean_sched_policy(gvt);
3918c2ecf20Sopenharmony_ciout_clean_workload_scheduler:
3928c2ecf20Sopenharmony_ci	intel_gvt_clean_workload_scheduler(gvt);
3938c2ecf20Sopenharmony_ciout_clean_gtt:
3948c2ecf20Sopenharmony_ci	intel_gvt_clean_gtt(gvt);
3958c2ecf20Sopenharmony_ciout_clean_irq:
3968c2ecf20Sopenharmony_ci	intel_gvt_clean_irq(gvt);
3978c2ecf20Sopenharmony_ciout_free_firmware:
3988c2ecf20Sopenharmony_ci	intel_gvt_free_firmware(gvt);
3998c2ecf20Sopenharmony_ciout_clean_mmio_info:
4008c2ecf20Sopenharmony_ci	intel_gvt_clean_mmio_info(gvt);
4018c2ecf20Sopenharmony_ciout_clean_idr:
4028c2ecf20Sopenharmony_ci	idr_destroy(&gvt->vgpu_idr);
4038c2ecf20Sopenharmony_ci	kfree(gvt);
4048c2ecf20Sopenharmony_ci	i915->gvt = NULL;
4058c2ecf20Sopenharmony_ci	return ret;
4068c2ecf20Sopenharmony_ci}
4078c2ecf20Sopenharmony_ci
4088c2ecf20Sopenharmony_ciint
4098c2ecf20Sopenharmony_ciintel_gvt_pm_resume(struct intel_gvt *gvt)
4108c2ecf20Sopenharmony_ci{
4118c2ecf20Sopenharmony_ci	intel_gvt_restore_fence(gvt);
4128c2ecf20Sopenharmony_ci	intel_gvt_restore_mmio(gvt);
4138c2ecf20Sopenharmony_ci	intel_gvt_restore_ggtt(gvt);
4148c2ecf20Sopenharmony_ci	return 0;
4158c2ecf20Sopenharmony_ci}
4168c2ecf20Sopenharmony_ci
4178c2ecf20Sopenharmony_ciint
4188c2ecf20Sopenharmony_ciintel_gvt_register_hypervisor(struct intel_gvt_mpt *m)
4198c2ecf20Sopenharmony_ci{
4208c2ecf20Sopenharmony_ci	int ret;
4218c2ecf20Sopenharmony_ci	void *gvt;
4228c2ecf20Sopenharmony_ci
4238c2ecf20Sopenharmony_ci	if (!intel_gvt_host.initialized)
4248c2ecf20Sopenharmony_ci		return -ENODEV;
4258c2ecf20Sopenharmony_ci
4268c2ecf20Sopenharmony_ci	if (m->type != INTEL_GVT_HYPERVISOR_KVM &&
4278c2ecf20Sopenharmony_ci	    m->type != INTEL_GVT_HYPERVISOR_XEN)
4288c2ecf20Sopenharmony_ci		return -EINVAL;
4298c2ecf20Sopenharmony_ci
4308c2ecf20Sopenharmony_ci	/* Get a reference for device model module */
4318c2ecf20Sopenharmony_ci	if (!try_module_get(THIS_MODULE))
4328c2ecf20Sopenharmony_ci		return -ENODEV;
4338c2ecf20Sopenharmony_ci
4348c2ecf20Sopenharmony_ci	intel_gvt_host.mpt = m;
4358c2ecf20Sopenharmony_ci	intel_gvt_host.hypervisor_type = m->type;
4368c2ecf20Sopenharmony_ci	gvt = (void *)kdev_to_i915(intel_gvt_host.dev)->gvt;
4378c2ecf20Sopenharmony_ci
4388c2ecf20Sopenharmony_ci	ret = intel_gvt_hypervisor_host_init(intel_gvt_host.dev, gvt,
4398c2ecf20Sopenharmony_ci					     &intel_gvt_ops);
4408c2ecf20Sopenharmony_ci	if (ret < 0) {
4418c2ecf20Sopenharmony_ci		gvt_err("Failed to init %s hypervisor module\n",
4428c2ecf20Sopenharmony_ci			supported_hypervisors[intel_gvt_host.hypervisor_type]);
4438c2ecf20Sopenharmony_ci		module_put(THIS_MODULE);
4448c2ecf20Sopenharmony_ci		return -ENODEV;
4458c2ecf20Sopenharmony_ci	}
4468c2ecf20Sopenharmony_ci	gvt_dbg_core("Running with hypervisor %s in host mode\n",
4478c2ecf20Sopenharmony_ci		     supported_hypervisors[intel_gvt_host.hypervisor_type]);
4488c2ecf20Sopenharmony_ci	return 0;
4498c2ecf20Sopenharmony_ci}
4508c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(intel_gvt_register_hypervisor);
4518c2ecf20Sopenharmony_ci
4528c2ecf20Sopenharmony_civoid
4538c2ecf20Sopenharmony_ciintel_gvt_unregister_hypervisor(void)
4548c2ecf20Sopenharmony_ci{
4558c2ecf20Sopenharmony_ci	intel_gvt_hypervisor_host_exit(intel_gvt_host.dev);
4568c2ecf20Sopenharmony_ci	module_put(THIS_MODULE);
4578c2ecf20Sopenharmony_ci}
4588c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(intel_gvt_unregister_hypervisor);
459