18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * Copyright(c) 2011-2015 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 248c2ecf20Sopenharmony_ci#include "i915_drv.h" 258c2ecf20Sopenharmony_ci#include "i915_pvinfo.h" 268c2ecf20Sopenharmony_ci#include "i915_vgpu.h" 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci/** 298c2ecf20Sopenharmony_ci * DOC: Intel GVT-g guest support 308c2ecf20Sopenharmony_ci * 318c2ecf20Sopenharmony_ci * Intel GVT-g is a graphics virtualization technology which shares the 328c2ecf20Sopenharmony_ci * GPU among multiple virtual machines on a time-sharing basis. Each 338c2ecf20Sopenharmony_ci * virtual machine is presented a virtual GPU (vGPU), which has equivalent 348c2ecf20Sopenharmony_ci * features as the underlying physical GPU (pGPU), so i915 driver can run 358c2ecf20Sopenharmony_ci * seamlessly in a virtual machine. This file provides vGPU specific 368c2ecf20Sopenharmony_ci * optimizations when running in a virtual machine, to reduce the complexity 378c2ecf20Sopenharmony_ci * of vGPU emulation and to improve the overall performance. 388c2ecf20Sopenharmony_ci * 398c2ecf20Sopenharmony_ci * A primary function introduced here is so-called "address space ballooning" 408c2ecf20Sopenharmony_ci * technique. Intel GVT-g partitions global graphics memory among multiple VMs, 418c2ecf20Sopenharmony_ci * so each VM can directly access a portion of the memory without hypervisor's 428c2ecf20Sopenharmony_ci * intervention, e.g. filling textures or queuing commands. However with the 438c2ecf20Sopenharmony_ci * partitioning an unmodified i915 driver would assume a smaller graphics 448c2ecf20Sopenharmony_ci * memory starting from address ZERO, then requires vGPU emulation module to 458c2ecf20Sopenharmony_ci * translate the graphics address between 'guest view' and 'host view', for 468c2ecf20Sopenharmony_ci * all registers and command opcodes which contain a graphics memory address. 478c2ecf20Sopenharmony_ci * To reduce the complexity, Intel GVT-g introduces "address space ballooning", 488c2ecf20Sopenharmony_ci * by telling the exact partitioning knowledge to each guest i915 driver, which 498c2ecf20Sopenharmony_ci * then reserves and prevents non-allocated portions from allocation. Thus vGPU 508c2ecf20Sopenharmony_ci * emulation module only needs to scan and validate graphics addresses without 518c2ecf20Sopenharmony_ci * complexity of address translation. 528c2ecf20Sopenharmony_ci * 538c2ecf20Sopenharmony_ci */ 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci/** 568c2ecf20Sopenharmony_ci * intel_vgpu_detect - detect virtual GPU 578c2ecf20Sopenharmony_ci * @dev_priv: i915 device private 588c2ecf20Sopenharmony_ci * 598c2ecf20Sopenharmony_ci * This function is called at the initialization stage, to detect whether 608c2ecf20Sopenharmony_ci * running on a vGPU. 618c2ecf20Sopenharmony_ci */ 628c2ecf20Sopenharmony_civoid intel_vgpu_detect(struct drm_i915_private *dev_priv) 638c2ecf20Sopenharmony_ci{ 648c2ecf20Sopenharmony_ci struct pci_dev *pdev = dev_priv->drm.pdev; 658c2ecf20Sopenharmony_ci u64 magic; 668c2ecf20Sopenharmony_ci u16 version_major; 678c2ecf20Sopenharmony_ci void __iomem *shared_area; 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ci BUILD_BUG_ON(sizeof(struct vgt_if) != VGT_PVINFO_SIZE); 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci /* 728c2ecf20Sopenharmony_ci * This is called before we setup the main MMIO BAR mappings used via 738c2ecf20Sopenharmony_ci * the uncore structure, so we need to access the BAR directly. Since 748c2ecf20Sopenharmony_ci * we do not support VGT on older gens, return early so we don't have 758c2ecf20Sopenharmony_ci * to consider differently numbered or sized MMIO bars 768c2ecf20Sopenharmony_ci */ 778c2ecf20Sopenharmony_ci if (INTEL_GEN(dev_priv) < 6) 788c2ecf20Sopenharmony_ci return; 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ci shared_area = pci_iomap_range(pdev, 0, VGT_PVINFO_PAGE, VGT_PVINFO_SIZE); 818c2ecf20Sopenharmony_ci if (!shared_area) { 828c2ecf20Sopenharmony_ci drm_err(&dev_priv->drm, 838c2ecf20Sopenharmony_ci "failed to map MMIO bar to check for VGT\n"); 848c2ecf20Sopenharmony_ci return; 858c2ecf20Sopenharmony_ci } 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci magic = readq(shared_area + vgtif_offset(magic)); 888c2ecf20Sopenharmony_ci if (magic != VGT_MAGIC) 898c2ecf20Sopenharmony_ci goto out; 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_ci version_major = readw(shared_area + vgtif_offset(version_major)); 928c2ecf20Sopenharmony_ci if (version_major < VGT_VERSION_MAJOR) { 938c2ecf20Sopenharmony_ci drm_info(&dev_priv->drm, "VGT interface version mismatch!\n"); 948c2ecf20Sopenharmony_ci goto out; 958c2ecf20Sopenharmony_ci } 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_ci dev_priv->vgpu.caps = readl(shared_area + vgtif_offset(vgt_caps)); 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci dev_priv->vgpu.active = true; 1008c2ecf20Sopenharmony_ci mutex_init(&dev_priv->vgpu.lock); 1018c2ecf20Sopenharmony_ci drm_info(&dev_priv->drm, "Virtual GPU for Intel GVT-g detected.\n"); 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ciout: 1048c2ecf20Sopenharmony_ci pci_iounmap(pdev, shared_area); 1058c2ecf20Sopenharmony_ci} 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_civoid intel_vgpu_register(struct drm_i915_private *i915) 1088c2ecf20Sopenharmony_ci{ 1098c2ecf20Sopenharmony_ci /* 1108c2ecf20Sopenharmony_ci * Notify a valid surface after modesetting, when running inside a VM. 1118c2ecf20Sopenharmony_ci */ 1128c2ecf20Sopenharmony_ci if (intel_vgpu_active(i915)) 1138c2ecf20Sopenharmony_ci intel_uncore_write(&i915->uncore, vgtif_reg(display_ready), 1148c2ecf20Sopenharmony_ci VGT_DRV_DISPLAY_READY); 1158c2ecf20Sopenharmony_ci} 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_cibool intel_vgpu_active(struct drm_i915_private *dev_priv) 1188c2ecf20Sopenharmony_ci{ 1198c2ecf20Sopenharmony_ci return dev_priv->vgpu.active; 1208c2ecf20Sopenharmony_ci} 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_cibool intel_vgpu_has_full_ppgtt(struct drm_i915_private *dev_priv) 1238c2ecf20Sopenharmony_ci{ 1248c2ecf20Sopenharmony_ci return dev_priv->vgpu.caps & VGT_CAPS_FULL_PPGTT; 1258c2ecf20Sopenharmony_ci} 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_cibool intel_vgpu_has_hwsp_emulation(struct drm_i915_private *dev_priv) 1288c2ecf20Sopenharmony_ci{ 1298c2ecf20Sopenharmony_ci return dev_priv->vgpu.caps & VGT_CAPS_HWSP_EMULATION; 1308c2ecf20Sopenharmony_ci} 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_cibool intel_vgpu_has_huge_gtt(struct drm_i915_private *dev_priv) 1338c2ecf20Sopenharmony_ci{ 1348c2ecf20Sopenharmony_ci return dev_priv->vgpu.caps & VGT_CAPS_HUGE_GTT; 1358c2ecf20Sopenharmony_ci} 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_cistruct _balloon_info_ { 1388c2ecf20Sopenharmony_ci /* 1398c2ecf20Sopenharmony_ci * There are up to 2 regions per mappable/unmappable graphic 1408c2ecf20Sopenharmony_ci * memory that might be ballooned. Here, index 0/1 is for mappable 1418c2ecf20Sopenharmony_ci * graphic memory, 2/3 for unmappable graphic memory. 1428c2ecf20Sopenharmony_ci */ 1438c2ecf20Sopenharmony_ci struct drm_mm_node space[4]; 1448c2ecf20Sopenharmony_ci}; 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_cistatic struct _balloon_info_ bl_info; 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_cistatic void vgt_deballoon_space(struct i915_ggtt *ggtt, 1498c2ecf20Sopenharmony_ci struct drm_mm_node *node) 1508c2ecf20Sopenharmony_ci{ 1518c2ecf20Sopenharmony_ci struct drm_i915_private *dev_priv = ggtt->vm.i915; 1528c2ecf20Sopenharmony_ci if (!drm_mm_node_allocated(node)) 1538c2ecf20Sopenharmony_ci return; 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci drm_dbg(&dev_priv->drm, 1568c2ecf20Sopenharmony_ci "deballoon space: range [0x%llx - 0x%llx] %llu KiB.\n", 1578c2ecf20Sopenharmony_ci node->start, 1588c2ecf20Sopenharmony_ci node->start + node->size, 1598c2ecf20Sopenharmony_ci node->size / 1024); 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci ggtt->vm.reserved -= node->size; 1628c2ecf20Sopenharmony_ci drm_mm_remove_node(node); 1638c2ecf20Sopenharmony_ci} 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci/** 1668c2ecf20Sopenharmony_ci * intel_vgt_deballoon - deballoon reserved graphics address trunks 1678c2ecf20Sopenharmony_ci * @ggtt: the global GGTT from which we reserved earlier 1688c2ecf20Sopenharmony_ci * 1698c2ecf20Sopenharmony_ci * This function is called to deallocate the ballooned-out graphic memory, when 1708c2ecf20Sopenharmony_ci * driver is unloaded or when ballooning fails. 1718c2ecf20Sopenharmony_ci */ 1728c2ecf20Sopenharmony_civoid intel_vgt_deballoon(struct i915_ggtt *ggtt) 1738c2ecf20Sopenharmony_ci{ 1748c2ecf20Sopenharmony_ci struct drm_i915_private *dev_priv = ggtt->vm.i915; 1758c2ecf20Sopenharmony_ci int i; 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ci if (!intel_vgpu_active(ggtt->vm.i915)) 1788c2ecf20Sopenharmony_ci return; 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_ci drm_dbg(&dev_priv->drm, "VGT deballoon.\n"); 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ci for (i = 0; i < 4; i++) 1838c2ecf20Sopenharmony_ci vgt_deballoon_space(ggtt, &bl_info.space[i]); 1848c2ecf20Sopenharmony_ci} 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_cistatic int vgt_balloon_space(struct i915_ggtt *ggtt, 1878c2ecf20Sopenharmony_ci struct drm_mm_node *node, 1888c2ecf20Sopenharmony_ci unsigned long start, unsigned long end) 1898c2ecf20Sopenharmony_ci{ 1908c2ecf20Sopenharmony_ci struct drm_i915_private *dev_priv = ggtt->vm.i915; 1918c2ecf20Sopenharmony_ci unsigned long size = end - start; 1928c2ecf20Sopenharmony_ci int ret; 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_ci if (start >= end) 1958c2ecf20Sopenharmony_ci return -EINVAL; 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_ci drm_info(&dev_priv->drm, 1988c2ecf20Sopenharmony_ci "balloon space: range [ 0x%lx - 0x%lx ] %lu KiB.\n", 1998c2ecf20Sopenharmony_ci start, end, size / 1024); 2008c2ecf20Sopenharmony_ci ret = i915_gem_gtt_reserve(&ggtt->vm, node, 2018c2ecf20Sopenharmony_ci size, start, I915_COLOR_UNEVICTABLE, 2028c2ecf20Sopenharmony_ci 0); 2038c2ecf20Sopenharmony_ci if (!ret) 2048c2ecf20Sopenharmony_ci ggtt->vm.reserved += size; 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_ci return ret; 2078c2ecf20Sopenharmony_ci} 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_ci/** 2108c2ecf20Sopenharmony_ci * intel_vgt_balloon - balloon out reserved graphics address trunks 2118c2ecf20Sopenharmony_ci * @ggtt: the global GGTT from which to reserve 2128c2ecf20Sopenharmony_ci * 2138c2ecf20Sopenharmony_ci * This function is called at the initialization stage, to balloon out the 2148c2ecf20Sopenharmony_ci * graphic address space allocated to other vGPUs, by marking these spaces as 2158c2ecf20Sopenharmony_ci * reserved. The ballooning related knowledge(starting address and size of 2168c2ecf20Sopenharmony_ci * the mappable/unmappable graphic memory) is described in the vgt_if structure 2178c2ecf20Sopenharmony_ci * in a reserved mmio range. 2188c2ecf20Sopenharmony_ci * 2198c2ecf20Sopenharmony_ci * To give an example, the drawing below depicts one typical scenario after 2208c2ecf20Sopenharmony_ci * ballooning. Here the vGPU1 has 2 pieces of graphic address spaces ballooned 2218c2ecf20Sopenharmony_ci * out each for the mappable and the non-mappable part. From the vGPU1 point of 2228c2ecf20Sopenharmony_ci * view, the total size is the same as the physical one, with the start address 2238c2ecf20Sopenharmony_ci * of its graphic space being zero. Yet there are some portions ballooned out( 2248c2ecf20Sopenharmony_ci * the shadow part, which are marked as reserved by drm allocator). From the 2258c2ecf20Sopenharmony_ci * host point of view, the graphic address space is partitioned by multiple 2268c2ecf20Sopenharmony_ci * vGPUs in different VMs. :: 2278c2ecf20Sopenharmony_ci * 2288c2ecf20Sopenharmony_ci * vGPU1 view Host view 2298c2ecf20Sopenharmony_ci * 0 ------> +-----------+ +-----------+ 2308c2ecf20Sopenharmony_ci * ^ |###########| | vGPU3 | 2318c2ecf20Sopenharmony_ci * | |###########| +-----------+ 2328c2ecf20Sopenharmony_ci * | |###########| | vGPU2 | 2338c2ecf20Sopenharmony_ci * | +-----------+ +-----------+ 2348c2ecf20Sopenharmony_ci * mappable GM | available | ==> | vGPU1 | 2358c2ecf20Sopenharmony_ci * | +-----------+ +-----------+ 2368c2ecf20Sopenharmony_ci * | |###########| | | 2378c2ecf20Sopenharmony_ci * v |###########| | Host | 2388c2ecf20Sopenharmony_ci * +=======+===========+ +===========+ 2398c2ecf20Sopenharmony_ci * ^ |###########| | vGPU3 | 2408c2ecf20Sopenharmony_ci * | |###########| +-----------+ 2418c2ecf20Sopenharmony_ci * | |###########| | vGPU2 | 2428c2ecf20Sopenharmony_ci * | +-----------+ +-----------+ 2438c2ecf20Sopenharmony_ci * unmappable GM | available | ==> | vGPU1 | 2448c2ecf20Sopenharmony_ci * | +-----------+ +-----------+ 2458c2ecf20Sopenharmony_ci * | |###########| | | 2468c2ecf20Sopenharmony_ci * | |###########| | Host | 2478c2ecf20Sopenharmony_ci * v |###########| | | 2488c2ecf20Sopenharmony_ci * total GM size ------> +-----------+ +-----------+ 2498c2ecf20Sopenharmony_ci * 2508c2ecf20Sopenharmony_ci * Returns: 2518c2ecf20Sopenharmony_ci * zero on success, non-zero if configuration invalid or ballooning failed 2528c2ecf20Sopenharmony_ci */ 2538c2ecf20Sopenharmony_ciint intel_vgt_balloon(struct i915_ggtt *ggtt) 2548c2ecf20Sopenharmony_ci{ 2558c2ecf20Sopenharmony_ci struct drm_i915_private *dev_priv = ggtt->vm.i915; 2568c2ecf20Sopenharmony_ci struct intel_uncore *uncore = &dev_priv->uncore; 2578c2ecf20Sopenharmony_ci unsigned long ggtt_end = ggtt->vm.total; 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_ci unsigned long mappable_base, mappable_size, mappable_end; 2608c2ecf20Sopenharmony_ci unsigned long unmappable_base, unmappable_size, unmappable_end; 2618c2ecf20Sopenharmony_ci int ret; 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_ci if (!intel_vgpu_active(ggtt->vm.i915)) 2648c2ecf20Sopenharmony_ci return 0; 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_ci mappable_base = 2678c2ecf20Sopenharmony_ci intel_uncore_read(uncore, vgtif_reg(avail_rs.mappable_gmadr.base)); 2688c2ecf20Sopenharmony_ci mappable_size = 2698c2ecf20Sopenharmony_ci intel_uncore_read(uncore, vgtif_reg(avail_rs.mappable_gmadr.size)); 2708c2ecf20Sopenharmony_ci unmappable_base = 2718c2ecf20Sopenharmony_ci intel_uncore_read(uncore, vgtif_reg(avail_rs.nonmappable_gmadr.base)); 2728c2ecf20Sopenharmony_ci unmappable_size = 2738c2ecf20Sopenharmony_ci intel_uncore_read(uncore, vgtif_reg(avail_rs.nonmappable_gmadr.size)); 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_ci mappable_end = mappable_base + mappable_size; 2768c2ecf20Sopenharmony_ci unmappable_end = unmappable_base + unmappable_size; 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_ci drm_info(&dev_priv->drm, "VGT ballooning configuration:\n"); 2798c2ecf20Sopenharmony_ci drm_info(&dev_priv->drm, 2808c2ecf20Sopenharmony_ci "Mappable graphic memory: base 0x%lx size %ldKiB\n", 2818c2ecf20Sopenharmony_ci mappable_base, mappable_size / 1024); 2828c2ecf20Sopenharmony_ci drm_info(&dev_priv->drm, 2838c2ecf20Sopenharmony_ci "Unmappable graphic memory: base 0x%lx size %ldKiB\n", 2848c2ecf20Sopenharmony_ci unmappable_base, unmappable_size / 1024); 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_ci if (mappable_end > ggtt->mappable_end || 2878c2ecf20Sopenharmony_ci unmappable_base < ggtt->mappable_end || 2888c2ecf20Sopenharmony_ci unmappable_end > ggtt_end) { 2898c2ecf20Sopenharmony_ci drm_err(&dev_priv->drm, "Invalid ballooning configuration!\n"); 2908c2ecf20Sopenharmony_ci return -EINVAL; 2918c2ecf20Sopenharmony_ci } 2928c2ecf20Sopenharmony_ci 2938c2ecf20Sopenharmony_ci /* Unmappable graphic memory ballooning */ 2948c2ecf20Sopenharmony_ci if (unmappable_base > ggtt->mappable_end) { 2958c2ecf20Sopenharmony_ci ret = vgt_balloon_space(ggtt, &bl_info.space[2], 2968c2ecf20Sopenharmony_ci ggtt->mappable_end, unmappable_base); 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_ci if (ret) 2998c2ecf20Sopenharmony_ci goto err; 3008c2ecf20Sopenharmony_ci } 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_ci if (unmappable_end < ggtt_end) { 3038c2ecf20Sopenharmony_ci ret = vgt_balloon_space(ggtt, &bl_info.space[3], 3048c2ecf20Sopenharmony_ci unmappable_end, ggtt_end); 3058c2ecf20Sopenharmony_ci if (ret) 3068c2ecf20Sopenharmony_ci goto err_upon_mappable; 3078c2ecf20Sopenharmony_ci } 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_ci /* Mappable graphic memory ballooning */ 3108c2ecf20Sopenharmony_ci if (mappable_base) { 3118c2ecf20Sopenharmony_ci ret = vgt_balloon_space(ggtt, &bl_info.space[0], 3128c2ecf20Sopenharmony_ci 0, mappable_base); 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_ci if (ret) 3158c2ecf20Sopenharmony_ci goto err_upon_unmappable; 3168c2ecf20Sopenharmony_ci } 3178c2ecf20Sopenharmony_ci 3188c2ecf20Sopenharmony_ci if (mappable_end < ggtt->mappable_end) { 3198c2ecf20Sopenharmony_ci ret = vgt_balloon_space(ggtt, &bl_info.space[1], 3208c2ecf20Sopenharmony_ci mappable_end, ggtt->mappable_end); 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_ci if (ret) 3238c2ecf20Sopenharmony_ci goto err_below_mappable; 3248c2ecf20Sopenharmony_ci } 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_ci drm_info(&dev_priv->drm, "VGT balloon successfully\n"); 3278c2ecf20Sopenharmony_ci return 0; 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_cierr_below_mappable: 3308c2ecf20Sopenharmony_ci vgt_deballoon_space(ggtt, &bl_info.space[0]); 3318c2ecf20Sopenharmony_cierr_upon_unmappable: 3328c2ecf20Sopenharmony_ci vgt_deballoon_space(ggtt, &bl_info.space[3]); 3338c2ecf20Sopenharmony_cierr_upon_mappable: 3348c2ecf20Sopenharmony_ci vgt_deballoon_space(ggtt, &bl_info.space[2]); 3358c2ecf20Sopenharmony_cierr: 3368c2ecf20Sopenharmony_ci drm_err(&dev_priv->drm, "VGT balloon fail\n"); 3378c2ecf20Sopenharmony_ci return ret; 3388c2ecf20Sopenharmony_ci} 339