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