14d60c5fdSZhi Wang /* 24d60c5fdSZhi Wang * Copyright(c) 2011-2016 Intel Corporation. All rights reserved. 34d60c5fdSZhi Wang * 44d60c5fdSZhi Wang * Permission is hereby granted, free of charge, to any person obtaining a 54d60c5fdSZhi Wang * copy of this software and associated documentation files (the "Software"), 64d60c5fdSZhi Wang * to deal in the Software without restriction, including without limitation 74d60c5fdSZhi Wang * the rights to use, copy, modify, merge, publish, distribute, sublicense, 84d60c5fdSZhi Wang * and/or sell copies of the Software, and to permit persons to whom the 94d60c5fdSZhi Wang * Software is furnished to do so, subject to the following conditions: 104d60c5fdSZhi Wang * 114d60c5fdSZhi Wang * The above copyright notice and this permission notice (including the next 124d60c5fdSZhi Wang * paragraph) shall be included in all copies or substantial portions of the 134d60c5fdSZhi Wang * Software. 144d60c5fdSZhi Wang * 154d60c5fdSZhi Wang * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 164d60c5fdSZhi Wang * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 174d60c5fdSZhi Wang * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 184d60c5fdSZhi Wang * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 194d60c5fdSZhi Wang * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 204d60c5fdSZhi Wang * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 214d60c5fdSZhi Wang * SOFTWARE. 224d60c5fdSZhi Wang * 234d60c5fdSZhi Wang * Authors: 244d60c5fdSZhi Wang * Eddie Dong <eddie.dong@intel.com> 254d60c5fdSZhi Wang * Jike Song <jike.song@intel.com> 264d60c5fdSZhi Wang * 274d60c5fdSZhi Wang * Contributors: 284d60c5fdSZhi Wang * Zhi Wang <zhi.a.wang@intel.com> 294d60c5fdSZhi Wang * Min He <min.he@intel.com> 304d60c5fdSZhi Wang * Bing Niu <bing.niu@intel.com> 314d60c5fdSZhi Wang * 324d60c5fdSZhi Wang */ 334d60c5fdSZhi Wang 344d60c5fdSZhi Wang #include "i915_drv.h" 35feddf6e8SZhenyu Wang #include "gvt.h" 364d60c5fdSZhi Wang 374d60c5fdSZhi Wang enum { 384d60c5fdSZhi Wang INTEL_GVT_PCI_BAR_GTTMMIO = 0, 394d60c5fdSZhi Wang INTEL_GVT_PCI_BAR_APERTURE, 404d60c5fdSZhi Wang INTEL_GVT_PCI_BAR_PIO, 414d60c5fdSZhi Wang INTEL_GVT_PCI_BAR_MAX, 424d60c5fdSZhi Wang }; 434d60c5fdSZhi Wang 444d60c5fdSZhi Wang /** 454d60c5fdSZhi Wang * intel_vgpu_emulate_cfg_read - emulate vGPU configuration space read 464d60c5fdSZhi Wang * 474d60c5fdSZhi Wang * Returns: 484d60c5fdSZhi Wang * Zero on success, negative error code if failed. 494d60c5fdSZhi Wang */ 509ec1e66bSJike Song int intel_vgpu_emulate_cfg_read(struct intel_vgpu *vgpu, unsigned int offset, 514d60c5fdSZhi Wang void *p_data, unsigned int bytes) 524d60c5fdSZhi Wang { 534d60c5fdSZhi Wang if (WARN_ON(bytes > 4)) 544d60c5fdSZhi Wang return -EINVAL; 554d60c5fdSZhi Wang 564d60c5fdSZhi Wang if (WARN_ON(offset + bytes > INTEL_GVT_MAX_CFG_SPACE_SZ)) 574d60c5fdSZhi Wang return -EINVAL; 584d60c5fdSZhi Wang 594d60c5fdSZhi Wang memcpy(p_data, vgpu_cfg_space(vgpu) + offset, bytes); 604d60c5fdSZhi Wang return 0; 614d60c5fdSZhi Wang } 624d60c5fdSZhi Wang 634d60c5fdSZhi Wang static int map_aperture(struct intel_vgpu *vgpu, bool map) 644d60c5fdSZhi Wang { 654d60c5fdSZhi Wang u64 first_gfn, first_mfn; 664d60c5fdSZhi Wang u64 val; 674d60c5fdSZhi Wang int ret; 684d60c5fdSZhi Wang 694d60c5fdSZhi Wang if (map == vgpu->cfg_space.bar[INTEL_GVT_PCI_BAR_APERTURE].tracked) 704d60c5fdSZhi Wang return 0; 714d60c5fdSZhi Wang 724d60c5fdSZhi Wang val = vgpu_cfg_space(vgpu)[PCI_BASE_ADDRESS_2]; 734d60c5fdSZhi Wang if (val & PCI_BASE_ADDRESS_MEM_TYPE_64) 744d60c5fdSZhi Wang val = *(u64 *)(vgpu_cfg_space(vgpu) + PCI_BASE_ADDRESS_2); 754d60c5fdSZhi Wang else 764d60c5fdSZhi Wang val = *(u32 *)(vgpu_cfg_space(vgpu) + PCI_BASE_ADDRESS_2); 774d60c5fdSZhi Wang 784d60c5fdSZhi Wang first_gfn = (val + vgpu_aperture_offset(vgpu)) >> PAGE_SHIFT; 794d60c5fdSZhi Wang first_mfn = vgpu_aperture_pa_base(vgpu) >> PAGE_SHIFT; 804d60c5fdSZhi Wang 814d60c5fdSZhi Wang ret = intel_gvt_hypervisor_map_gfn_to_mfn(vgpu, first_gfn, 824d60c5fdSZhi Wang first_mfn, 838f89743bSJike Song vgpu_aperture_sz(vgpu) >> 848f89743bSJike Song PAGE_SHIFT, map); 854d60c5fdSZhi Wang if (ret) 864d60c5fdSZhi Wang return ret; 874d60c5fdSZhi Wang 884d60c5fdSZhi Wang vgpu->cfg_space.bar[INTEL_GVT_PCI_BAR_APERTURE].tracked = map; 894d60c5fdSZhi Wang return 0; 904d60c5fdSZhi Wang } 914d60c5fdSZhi Wang 924d60c5fdSZhi Wang static int trap_gttmmio(struct intel_vgpu *vgpu, bool trap) 934d60c5fdSZhi Wang { 944d60c5fdSZhi Wang u64 start, end; 954d60c5fdSZhi Wang u64 val; 964d60c5fdSZhi Wang int ret; 974d60c5fdSZhi Wang 984d60c5fdSZhi Wang if (trap == vgpu->cfg_space.bar[INTEL_GVT_PCI_BAR_GTTMMIO].tracked) 994d60c5fdSZhi Wang return 0; 1004d60c5fdSZhi Wang 1014d60c5fdSZhi Wang val = vgpu_cfg_space(vgpu)[PCI_BASE_ADDRESS_0]; 1024d60c5fdSZhi Wang if (val & PCI_BASE_ADDRESS_MEM_TYPE_64) 1034d60c5fdSZhi Wang start = *(u64 *)(vgpu_cfg_space(vgpu) + PCI_BASE_ADDRESS_0); 1044d60c5fdSZhi Wang else 1054d60c5fdSZhi Wang start = *(u32 *)(vgpu_cfg_space(vgpu) + PCI_BASE_ADDRESS_0); 1064d60c5fdSZhi Wang 1074d60c5fdSZhi Wang start &= ~GENMASK(3, 0); 1084d60c5fdSZhi Wang end = start + vgpu->cfg_space.bar[INTEL_GVT_PCI_BAR_GTTMMIO].size - 1; 1094d60c5fdSZhi Wang 1104d60c5fdSZhi Wang ret = intel_gvt_hypervisor_set_trap_area(vgpu, start, end, trap); 1114d60c5fdSZhi Wang if (ret) 1124d60c5fdSZhi Wang return ret; 1134d60c5fdSZhi Wang 1144d60c5fdSZhi Wang vgpu->cfg_space.bar[INTEL_GVT_PCI_BAR_GTTMMIO].tracked = trap; 1154d60c5fdSZhi Wang return 0; 1164d60c5fdSZhi Wang } 1174d60c5fdSZhi Wang 1184d60c5fdSZhi Wang static int emulate_pci_command_write(struct intel_vgpu *vgpu, 1194d60c5fdSZhi Wang unsigned int offset, void *p_data, unsigned int bytes) 1204d60c5fdSZhi Wang { 1214d60c5fdSZhi Wang u8 old = vgpu_cfg_space(vgpu)[offset]; 1224d60c5fdSZhi Wang u8 new = *(u8 *)p_data; 1234d60c5fdSZhi Wang u8 changed = old ^ new; 1244d60c5fdSZhi Wang int ret; 1254d60c5fdSZhi Wang 1264d60c5fdSZhi Wang if (!(changed & PCI_COMMAND_MEMORY)) 1274d60c5fdSZhi Wang return 0; 1284d60c5fdSZhi Wang 1294d60c5fdSZhi Wang if (old & PCI_COMMAND_MEMORY) { 1304d60c5fdSZhi Wang ret = trap_gttmmio(vgpu, false); 1314d60c5fdSZhi Wang if (ret) 1324d60c5fdSZhi Wang return ret; 1334d60c5fdSZhi Wang ret = map_aperture(vgpu, false); 1344d60c5fdSZhi Wang if (ret) 1354d60c5fdSZhi Wang return ret; 1364d60c5fdSZhi Wang } else { 1374d60c5fdSZhi Wang ret = trap_gttmmio(vgpu, true); 1384d60c5fdSZhi Wang if (ret) 1394d60c5fdSZhi Wang return ret; 1404d60c5fdSZhi Wang ret = map_aperture(vgpu, true); 1414d60c5fdSZhi Wang if (ret) 1424d60c5fdSZhi Wang return ret; 1434d60c5fdSZhi Wang } 1444d60c5fdSZhi Wang 1454d60c5fdSZhi Wang memcpy(vgpu_cfg_space(vgpu) + offset, p_data, bytes); 1464d60c5fdSZhi Wang return 0; 1474d60c5fdSZhi Wang } 1484d60c5fdSZhi Wang 1494d60c5fdSZhi Wang static int emulate_pci_bar_write(struct intel_vgpu *vgpu, unsigned int offset, 1504d60c5fdSZhi Wang void *p_data, unsigned int bytes) 1514d60c5fdSZhi Wang { 1524d60c5fdSZhi Wang unsigned int bar_index = 1534d60c5fdSZhi Wang (rounddown(offset, 8) % PCI_BASE_ADDRESS_0) / 8; 1544d60c5fdSZhi Wang u32 new = *(u32 *)(p_data); 1554d60c5fdSZhi Wang bool lo = IS_ALIGNED(offset, 8); 1564d60c5fdSZhi Wang u64 size; 1574d60c5fdSZhi Wang int ret = 0; 1584d60c5fdSZhi Wang bool mmio_enabled = 1594d60c5fdSZhi Wang vgpu_cfg_space(vgpu)[PCI_COMMAND] & PCI_COMMAND_MEMORY; 1604d60c5fdSZhi Wang 1614d60c5fdSZhi Wang if (WARN_ON(bar_index >= INTEL_GVT_PCI_BAR_MAX)) 1624d60c5fdSZhi Wang return -EINVAL; 1634d60c5fdSZhi Wang 1644d60c5fdSZhi Wang if (new == 0xffffffff) { 1654d60c5fdSZhi Wang /* 1664d60c5fdSZhi Wang * Power-up software can determine how much address 1674d60c5fdSZhi Wang * space the device requires by writing a value of 1684d60c5fdSZhi Wang * all 1's to the register and then reading the value 1694d60c5fdSZhi Wang * back. The device will return 0's in all don't-care 1704d60c5fdSZhi Wang * address bits. 1714d60c5fdSZhi Wang */ 1724d60c5fdSZhi Wang size = vgpu->cfg_space.bar[bar_index].size; 1734d60c5fdSZhi Wang if (lo) { 1744d60c5fdSZhi Wang new = rounddown(new, size); 1754d60c5fdSZhi Wang } else { 1764d60c5fdSZhi Wang u32 val = vgpu_cfg_space(vgpu)[rounddown(offset, 8)]; 1774d60c5fdSZhi Wang /* for 32bit mode bar it returns all-0 in upper 32 1784d60c5fdSZhi Wang * bit, for 64bit mode bar it will calculate the 1794d60c5fdSZhi Wang * size with lower 32bit and return the corresponding 1804d60c5fdSZhi Wang * value 1814d60c5fdSZhi Wang */ 1824d60c5fdSZhi Wang if (val & PCI_BASE_ADDRESS_MEM_TYPE_64) 1834d60c5fdSZhi Wang new &= (~(size-1)) >> 32; 1844d60c5fdSZhi Wang else 1854d60c5fdSZhi Wang new = 0; 1864d60c5fdSZhi Wang } 1874d60c5fdSZhi Wang /* 1884d60c5fdSZhi Wang * Unmapp & untrap the BAR, since guest hasn't configured a 1894d60c5fdSZhi Wang * valid GPA 1904d60c5fdSZhi Wang */ 1914d60c5fdSZhi Wang switch (bar_index) { 1924d60c5fdSZhi Wang case INTEL_GVT_PCI_BAR_GTTMMIO: 1934d60c5fdSZhi Wang ret = trap_gttmmio(vgpu, false); 1944d60c5fdSZhi Wang break; 1954d60c5fdSZhi Wang case INTEL_GVT_PCI_BAR_APERTURE: 1964d60c5fdSZhi Wang ret = map_aperture(vgpu, false); 1974d60c5fdSZhi Wang break; 1984d60c5fdSZhi Wang } 1994d60c5fdSZhi Wang intel_vgpu_write_pci_bar(vgpu, offset, new, lo); 2004d60c5fdSZhi Wang } else { 2014d60c5fdSZhi Wang /* 2024d60c5fdSZhi Wang * Unmapp & untrap the old BAR first, since guest has 2034d60c5fdSZhi Wang * re-configured the BAR 2044d60c5fdSZhi Wang */ 2054d60c5fdSZhi Wang switch (bar_index) { 2064d60c5fdSZhi Wang case INTEL_GVT_PCI_BAR_GTTMMIO: 2074d60c5fdSZhi Wang ret = trap_gttmmio(vgpu, false); 2084d60c5fdSZhi Wang break; 2094d60c5fdSZhi Wang case INTEL_GVT_PCI_BAR_APERTURE: 2104d60c5fdSZhi Wang ret = map_aperture(vgpu, false); 2114d60c5fdSZhi Wang break; 2124d60c5fdSZhi Wang } 2134d60c5fdSZhi Wang intel_vgpu_write_pci_bar(vgpu, offset, new, lo); 2144d60c5fdSZhi Wang /* Track the new BAR */ 2154d60c5fdSZhi Wang if (mmio_enabled) { 2164d60c5fdSZhi Wang switch (bar_index) { 2174d60c5fdSZhi Wang case INTEL_GVT_PCI_BAR_GTTMMIO: 2184d60c5fdSZhi Wang ret = trap_gttmmio(vgpu, true); 2194d60c5fdSZhi Wang break; 2204d60c5fdSZhi Wang case INTEL_GVT_PCI_BAR_APERTURE: 2214d60c5fdSZhi Wang ret = map_aperture(vgpu, true); 2224d60c5fdSZhi Wang break; 2234d60c5fdSZhi Wang } 2244d60c5fdSZhi Wang } 2254d60c5fdSZhi Wang } 2264d60c5fdSZhi Wang return ret; 2274d60c5fdSZhi Wang } 2284d60c5fdSZhi Wang 2294d60c5fdSZhi Wang /** 2304d60c5fdSZhi Wang * intel_vgpu_emulate_cfg_read - emulate vGPU configuration space write 2314d60c5fdSZhi Wang * 2324d60c5fdSZhi Wang * Returns: 2334d60c5fdSZhi Wang * Zero on success, negative error code if failed. 2344d60c5fdSZhi Wang */ 2359ec1e66bSJike Song int intel_vgpu_emulate_cfg_write(struct intel_vgpu *vgpu, unsigned int offset, 2364d60c5fdSZhi Wang void *p_data, unsigned int bytes) 2374d60c5fdSZhi Wang { 2384d60c5fdSZhi Wang int ret; 2394d60c5fdSZhi Wang 2404d60c5fdSZhi Wang if (WARN_ON(bytes > 4)) 2414d60c5fdSZhi Wang return -EINVAL; 2424d60c5fdSZhi Wang 2434d60c5fdSZhi Wang if (WARN_ON(offset + bytes >= INTEL_GVT_MAX_CFG_SPACE_SZ)) 2444d60c5fdSZhi Wang return -EINVAL; 2454d60c5fdSZhi Wang 2464d60c5fdSZhi Wang /* First check if it's PCI_COMMAND */ 2474d60c5fdSZhi Wang if (IS_ALIGNED(offset, 2) && offset == PCI_COMMAND) { 2484d60c5fdSZhi Wang if (WARN_ON(bytes > 2)) 2494d60c5fdSZhi Wang return -EINVAL; 2504d60c5fdSZhi Wang return emulate_pci_command_write(vgpu, offset, p_data, bytes); 2514d60c5fdSZhi Wang } 2524d60c5fdSZhi Wang 2534d60c5fdSZhi Wang switch (rounddown(offset, 4)) { 2544d60c5fdSZhi Wang case PCI_BASE_ADDRESS_0: 2554d60c5fdSZhi Wang case PCI_BASE_ADDRESS_1: 2564d60c5fdSZhi Wang case PCI_BASE_ADDRESS_2: 2574d60c5fdSZhi Wang case PCI_BASE_ADDRESS_3: 2584d60c5fdSZhi Wang if (WARN_ON(!IS_ALIGNED(offset, 4))) 2594d60c5fdSZhi Wang return -EINVAL; 2604d60c5fdSZhi Wang return emulate_pci_bar_write(vgpu, offset, p_data, bytes); 2614d60c5fdSZhi Wang 2624d60c5fdSZhi Wang case INTEL_GVT_PCI_SWSCI: 2634d60c5fdSZhi Wang if (WARN_ON(!IS_ALIGNED(offset, 4))) 2644d60c5fdSZhi Wang return -EINVAL; 2654d60c5fdSZhi Wang ret = intel_vgpu_emulate_opregion_request(vgpu, *(u32 *)p_data); 2664d60c5fdSZhi Wang if (ret) 2674d60c5fdSZhi Wang return ret; 2684d60c5fdSZhi Wang break; 2694d60c5fdSZhi Wang 2704d60c5fdSZhi Wang case INTEL_GVT_PCI_OPREGION: 2714d60c5fdSZhi Wang if (WARN_ON(!IS_ALIGNED(offset, 4))) 2724d60c5fdSZhi Wang return -EINVAL; 2734d60c5fdSZhi Wang ret = intel_vgpu_init_opregion(vgpu, *(u32 *)p_data); 2744d60c5fdSZhi Wang if (ret) 2754d60c5fdSZhi Wang return ret; 2764d60c5fdSZhi Wang 2774d60c5fdSZhi Wang memcpy(vgpu_cfg_space(vgpu) + offset, p_data, bytes); 2784d60c5fdSZhi Wang break; 2794d60c5fdSZhi Wang default: 2804d60c5fdSZhi Wang memcpy(vgpu_cfg_space(vgpu) + offset, p_data, bytes); 2814d60c5fdSZhi Wang break; 2824d60c5fdSZhi Wang } 2834d60c5fdSZhi Wang return 0; 2844d60c5fdSZhi Wang } 285