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 44c2e04fdaSChangbin Du /* bitmap for writable bits (RW or RW1C bits, but cannot co-exist in one 45c2e04fdaSChangbin Du * byte) byte by byte in standard pci configuration space. (not the full 46c2e04fdaSChangbin Du * 256 bytes.) 47c2e04fdaSChangbin Du */ 48c2e04fdaSChangbin Du static const u8 pci_cfg_space_rw_bmp[PCI_INTERRUPT_LINE + 4] = { 49c2e04fdaSChangbin Du [PCI_COMMAND] = 0xff, 0x07, 50c2e04fdaSChangbin Du [PCI_STATUS] = 0x00, 0xf9, /* the only one RW1C byte */ 51c2e04fdaSChangbin Du [PCI_CACHE_LINE_SIZE] = 0xff, 52c2e04fdaSChangbin Du [PCI_BASE_ADDRESS_0 ... PCI_CARDBUS_CIS - 1] = 0xff, 53c2e04fdaSChangbin Du [PCI_ROM_ADDRESS] = 0x01, 0xf8, 0xff, 0xff, 54c2e04fdaSChangbin Du [PCI_INTERRUPT_LINE] = 0xff, 55c2e04fdaSChangbin Du }; 56c2e04fdaSChangbin Du 57c2e04fdaSChangbin Du /** 58c2e04fdaSChangbin Du * vgpu_pci_cfg_mem_write - write virtual cfg space memory 59a752b070SZhenyu Wang * @vgpu: target vgpu 60a752b070SZhenyu Wang * @off: offset 61a752b070SZhenyu Wang * @src: src ptr to write 62a752b070SZhenyu Wang * @bytes: number of bytes 63c2e04fdaSChangbin Du * 64c2e04fdaSChangbin Du * Use this function to write virtual cfg space memory. 65c2e04fdaSChangbin Du * For standard cfg space, only RW bits can be changed, 66c2e04fdaSChangbin Du * and we emulates the RW1C behavior of PCI_STATUS register. 67c2e04fdaSChangbin Du */ 68c2e04fdaSChangbin Du static void vgpu_pci_cfg_mem_write(struct intel_vgpu *vgpu, unsigned int off, 69c2e04fdaSChangbin Du u8 *src, unsigned int bytes) 70c2e04fdaSChangbin Du { 71c2e04fdaSChangbin Du u8 *cfg_base = vgpu_cfg_space(vgpu); 72c2e04fdaSChangbin Du u8 mask, new, old; 73ba25d977SColin Xu pci_power_t pwr; 74c2e04fdaSChangbin Du int i = 0; 75c2e04fdaSChangbin Du 76c2e04fdaSChangbin Du for (; i < bytes && (off + i < sizeof(pci_cfg_space_rw_bmp)); i++) { 77c2e04fdaSChangbin Du mask = pci_cfg_space_rw_bmp[off + i]; 78c2e04fdaSChangbin Du old = cfg_base[off + i]; 79c2e04fdaSChangbin Du new = src[i] & mask; 80c2e04fdaSChangbin Du 81c2e04fdaSChangbin Du /** 82c2e04fdaSChangbin Du * The PCI_STATUS high byte has RW1C bits, here 83c2e04fdaSChangbin Du * emulates clear by writing 1 for these bits. 84c2e04fdaSChangbin Du * Writing a 0b to RW1C bits has no effect. 85c2e04fdaSChangbin Du */ 86c2e04fdaSChangbin Du if (off + i == PCI_STATUS + 1) 87c2e04fdaSChangbin Du new = (~new & old) & mask; 88c2e04fdaSChangbin Du 89c2e04fdaSChangbin Du cfg_base[off + i] = (old & ~mask) | new; 90c2e04fdaSChangbin Du } 91c2e04fdaSChangbin Du 92c2e04fdaSChangbin Du /* For other configuration space directly copy as it is. */ 93c2e04fdaSChangbin Du if (i < bytes) 94c2e04fdaSChangbin Du memcpy(cfg_base + off + i, src + i, bytes - i); 95ba25d977SColin Xu 96ba25d977SColin Xu if (off == vgpu->cfg_space.pmcsr_off && vgpu->cfg_space.pmcsr_off) { 97ba25d977SColin Xu pwr = (pci_power_t __force)(*(u16*)(&vgpu_cfg_space(vgpu)[off]) 98ba25d977SColin Xu & PCI_PM_CTRL_STATE_MASK); 99ba25d977SColin Xu if (pwr == PCI_D3hot) 100ba25d977SColin Xu vgpu->d3_entered = true; 101ba25d977SColin Xu gvt_dbg_core("vgpu-%d power status changed to %d\n", 102ba25d977SColin Xu vgpu->id, pwr); 103ba25d977SColin Xu } 104c2e04fdaSChangbin Du } 105c2e04fdaSChangbin Du 1064d60c5fdSZhi Wang /** 1074d60c5fdSZhi Wang * intel_vgpu_emulate_cfg_read - emulate vGPU configuration space read 108a752b070SZhenyu Wang * @vgpu: target vgpu 109a752b070SZhenyu Wang * @offset: offset 110a752b070SZhenyu Wang * @p_data: return data ptr 111a752b070SZhenyu Wang * @bytes: number of bytes to read 1124d60c5fdSZhi Wang * 1134d60c5fdSZhi Wang * Returns: 1144d60c5fdSZhi Wang * Zero on success, negative error code if failed. 1154d60c5fdSZhi Wang */ 1169ec1e66bSJike Song int intel_vgpu_emulate_cfg_read(struct intel_vgpu *vgpu, unsigned int offset, 1174d60c5fdSZhi Wang void *p_data, unsigned int bytes) 1184d60c5fdSZhi Wang { 119a61ac1e7SChris Wilson struct drm_i915_private *i915 = vgpu->gvt->gt->i915; 12012d58619SPankaj Bharadiya 12112d58619SPankaj Bharadiya if (drm_WARN_ON(&i915->drm, bytes > 4)) 1224d60c5fdSZhi Wang return -EINVAL; 1234d60c5fdSZhi Wang 12412d58619SPankaj Bharadiya if (drm_WARN_ON(&i915->drm, 12512d58619SPankaj Bharadiya offset + bytes > vgpu->gvt->device_info.cfg_space_size)) 1264d60c5fdSZhi Wang return -EINVAL; 1274d60c5fdSZhi Wang 1284d60c5fdSZhi Wang memcpy(p_data, vgpu_cfg_space(vgpu) + offset, bytes); 1294d60c5fdSZhi Wang return 0; 1304d60c5fdSZhi Wang } 1314d60c5fdSZhi Wang 1324d60c5fdSZhi Wang static int map_aperture(struct intel_vgpu *vgpu, bool map) 1334d60c5fdSZhi Wang { 134f090a00dSChangbin Du phys_addr_t aperture_pa = vgpu_aperture_pa_base(vgpu); 135f090a00dSChangbin Du unsigned long aperture_sz = vgpu_aperture_sz(vgpu); 136f090a00dSChangbin Du u64 first_gfn; 1374d60c5fdSZhi Wang u64 val; 1384d60c5fdSZhi Wang int ret; 1394d60c5fdSZhi Wang 1404d60c5fdSZhi Wang if (map == vgpu->cfg_space.bar[INTEL_GVT_PCI_BAR_APERTURE].tracked) 1414d60c5fdSZhi Wang return 0; 1424d60c5fdSZhi Wang 1434d60c5fdSZhi Wang val = vgpu_cfg_space(vgpu)[PCI_BASE_ADDRESS_2]; 1444d60c5fdSZhi Wang if (val & PCI_BASE_ADDRESS_MEM_TYPE_64) 1454d60c5fdSZhi Wang val = *(u64 *)(vgpu_cfg_space(vgpu) + PCI_BASE_ADDRESS_2); 1464d60c5fdSZhi Wang else 1474d60c5fdSZhi Wang val = *(u32 *)(vgpu_cfg_space(vgpu) + PCI_BASE_ADDRESS_2); 1484d60c5fdSZhi Wang 1494d60c5fdSZhi Wang first_gfn = (val + vgpu_aperture_offset(vgpu)) >> PAGE_SHIFT; 1504d60c5fdSZhi Wang 1514d60c5fdSZhi Wang ret = intel_gvt_hypervisor_map_gfn_to_mfn(vgpu, first_gfn, 152f090a00dSChangbin Du aperture_pa >> PAGE_SHIFT, 153f090a00dSChangbin Du aperture_sz >> PAGE_SHIFT, 154f090a00dSChangbin Du map); 155d480b28aSChangbin Du if (ret) 1564d60c5fdSZhi Wang return ret; 1574d60c5fdSZhi Wang 1584d60c5fdSZhi Wang vgpu->cfg_space.bar[INTEL_GVT_PCI_BAR_APERTURE].tracked = map; 1594d60c5fdSZhi Wang return 0; 1604d60c5fdSZhi Wang } 1614d60c5fdSZhi Wang 1624d60c5fdSZhi Wang static int trap_gttmmio(struct intel_vgpu *vgpu, bool trap) 1634d60c5fdSZhi Wang { 1644d60c5fdSZhi Wang u64 start, end; 1654d60c5fdSZhi Wang u64 val; 1664d60c5fdSZhi Wang int ret; 1674d60c5fdSZhi Wang 1684d60c5fdSZhi Wang if (trap == vgpu->cfg_space.bar[INTEL_GVT_PCI_BAR_GTTMMIO].tracked) 1694d60c5fdSZhi Wang return 0; 1704d60c5fdSZhi Wang 1714d60c5fdSZhi Wang val = vgpu_cfg_space(vgpu)[PCI_BASE_ADDRESS_0]; 1724d60c5fdSZhi Wang if (val & PCI_BASE_ADDRESS_MEM_TYPE_64) 1734d60c5fdSZhi Wang start = *(u64 *)(vgpu_cfg_space(vgpu) + PCI_BASE_ADDRESS_0); 1744d60c5fdSZhi Wang else 1754d60c5fdSZhi Wang start = *(u32 *)(vgpu_cfg_space(vgpu) + PCI_BASE_ADDRESS_0); 1764d60c5fdSZhi Wang 1774d60c5fdSZhi Wang start &= ~GENMASK(3, 0); 1784d60c5fdSZhi Wang end = start + vgpu->cfg_space.bar[INTEL_GVT_PCI_BAR_GTTMMIO].size - 1; 1794d60c5fdSZhi Wang 1804d60c5fdSZhi Wang ret = intel_gvt_hypervisor_set_trap_area(vgpu, start, end, trap); 1814d60c5fdSZhi Wang if (ret) 1824d60c5fdSZhi Wang return ret; 1834d60c5fdSZhi Wang 1844d60c5fdSZhi Wang vgpu->cfg_space.bar[INTEL_GVT_PCI_BAR_GTTMMIO].tracked = trap; 1854d60c5fdSZhi Wang return 0; 1864d60c5fdSZhi Wang } 1874d60c5fdSZhi Wang 1884d60c5fdSZhi Wang static int emulate_pci_command_write(struct intel_vgpu *vgpu, 1894d60c5fdSZhi Wang unsigned int offset, void *p_data, unsigned int bytes) 1904d60c5fdSZhi Wang { 1914d60c5fdSZhi Wang u8 old = vgpu_cfg_space(vgpu)[offset]; 1924d60c5fdSZhi Wang u8 new = *(u8 *)p_data; 1934d60c5fdSZhi Wang u8 changed = old ^ new; 1944d60c5fdSZhi Wang int ret; 1954d60c5fdSZhi Wang 196c2e04fdaSChangbin Du vgpu_pci_cfg_mem_write(vgpu, offset, p_data, bytes); 1974d60c5fdSZhi Wang if (!(changed & PCI_COMMAND_MEMORY)) 1984d60c5fdSZhi Wang return 0; 1994d60c5fdSZhi Wang 2004d60c5fdSZhi Wang if (old & PCI_COMMAND_MEMORY) { 2014d60c5fdSZhi Wang ret = trap_gttmmio(vgpu, false); 2024d60c5fdSZhi Wang if (ret) 2034d60c5fdSZhi Wang return ret; 2044d60c5fdSZhi Wang ret = map_aperture(vgpu, false); 2054d60c5fdSZhi Wang if (ret) 2064d60c5fdSZhi Wang return ret; 2074d60c5fdSZhi Wang } else { 2084d60c5fdSZhi Wang ret = trap_gttmmio(vgpu, true); 2094d60c5fdSZhi Wang if (ret) 2104d60c5fdSZhi Wang return ret; 2114d60c5fdSZhi Wang ret = map_aperture(vgpu, true); 2124d60c5fdSZhi Wang if (ret) 2134d60c5fdSZhi Wang return ret; 2144d60c5fdSZhi Wang } 2154d60c5fdSZhi Wang 2164d60c5fdSZhi Wang return 0; 2174d60c5fdSZhi Wang } 2184d60c5fdSZhi Wang 219c4270d12SChangbin Du static int emulate_pci_rom_bar_write(struct intel_vgpu *vgpu, 220c4270d12SChangbin Du unsigned int offset, void *p_data, unsigned int bytes) 221c4270d12SChangbin Du { 222c4270d12SChangbin Du u32 *pval = (u32 *)(vgpu_cfg_space(vgpu) + offset); 223c4270d12SChangbin Du u32 new = *(u32 *)(p_data); 224c4270d12SChangbin Du 225c4270d12SChangbin Du if ((new & PCI_ROM_ADDRESS_MASK) == PCI_ROM_ADDRESS_MASK) 226c4270d12SChangbin Du /* We don't have rom, return size of 0. */ 227c4270d12SChangbin Du *pval = 0; 228c4270d12SChangbin Du else 229c4270d12SChangbin Du vgpu_pci_cfg_mem_write(vgpu, offset, p_data, bytes); 230c4270d12SChangbin Du return 0; 231c4270d12SChangbin Du } 232c4270d12SChangbin Du 2334d60c5fdSZhi Wang static int emulate_pci_bar_write(struct intel_vgpu *vgpu, unsigned int offset, 2344d60c5fdSZhi Wang void *p_data, unsigned int bytes) 2354d60c5fdSZhi Wang { 2364d60c5fdSZhi Wang u32 new = *(u32 *)(p_data); 2374d60c5fdSZhi Wang bool lo = IS_ALIGNED(offset, 8); 2384d60c5fdSZhi Wang u64 size; 2394d60c5fdSZhi Wang int ret = 0; 2404d60c5fdSZhi Wang bool mmio_enabled = 2414d60c5fdSZhi Wang vgpu_cfg_space(vgpu)[PCI_COMMAND] & PCI_COMMAND_MEMORY; 242f1751362SChangbin Du struct intel_vgpu_pci_bar *bars = vgpu->cfg_space.bar; 2434d60c5fdSZhi Wang 2444d60c5fdSZhi Wang /* 2454d60c5fdSZhi Wang * Power-up software can determine how much address 2464d60c5fdSZhi Wang * space the device requires by writing a value of 2474d60c5fdSZhi Wang * all 1's to the register and then reading the value 2484d60c5fdSZhi Wang * back. The device will return 0's in all don't-care 2494d60c5fdSZhi Wang * address bits. 2504d60c5fdSZhi Wang */ 251f1751362SChangbin Du if (new == 0xffffffff) { 252f1751362SChangbin Du switch (offset) { 253f1751362SChangbin Du case PCI_BASE_ADDRESS_0: 254f1751362SChangbin Du case PCI_BASE_ADDRESS_1: 255f1751362SChangbin Du size = ~(bars[INTEL_GVT_PCI_BAR_GTTMMIO].size -1); 256f1751362SChangbin Du intel_vgpu_write_pci_bar(vgpu, offset, 257f1751362SChangbin Du size >> (lo ? 0 : 32), lo); 2584d60c5fdSZhi Wang /* 259f1751362SChangbin Du * Untrap the BAR, since guest hasn't configured a 2604d60c5fdSZhi Wang * valid GPA 2614d60c5fdSZhi Wang */ 2624d60c5fdSZhi Wang ret = trap_gttmmio(vgpu, false); 2634d60c5fdSZhi Wang break; 264f1751362SChangbin Du case PCI_BASE_ADDRESS_2: 265f1751362SChangbin Du case PCI_BASE_ADDRESS_3: 266f1751362SChangbin Du size = ~(bars[INTEL_GVT_PCI_BAR_APERTURE].size -1); 267f1751362SChangbin Du intel_vgpu_write_pci_bar(vgpu, offset, 268f1751362SChangbin Du size >> (lo ? 0 : 32), lo); 2694d60c5fdSZhi Wang ret = map_aperture(vgpu, false); 2704d60c5fdSZhi Wang break; 271f1751362SChangbin Du default: 272f1751362SChangbin Du /* Unimplemented BARs */ 273f1751362SChangbin Du intel_vgpu_write_pci_bar(vgpu, offset, 0x0, false); 2744d60c5fdSZhi Wang } 2754d60c5fdSZhi Wang } else { 276f1751362SChangbin Du switch (offset) { 277f1751362SChangbin Du case PCI_BASE_ADDRESS_0: 278f1751362SChangbin Du case PCI_BASE_ADDRESS_1: 2794d60c5fdSZhi Wang /* 280f1751362SChangbin Du * Untrap the old BAR first, since guest has 2814d60c5fdSZhi Wang * re-configured the BAR 2824d60c5fdSZhi Wang */ 283f1751362SChangbin Du trap_gttmmio(vgpu, false); 2844d60c5fdSZhi Wang intel_vgpu_write_pci_bar(vgpu, offset, new, lo); 285f1751362SChangbin Du ret = trap_gttmmio(vgpu, mmio_enabled); 2864d60c5fdSZhi Wang break; 287f1751362SChangbin Du case PCI_BASE_ADDRESS_2: 288f1751362SChangbin Du case PCI_BASE_ADDRESS_3: 289f1751362SChangbin Du map_aperture(vgpu, false); 290f1751362SChangbin Du intel_vgpu_write_pci_bar(vgpu, offset, new, lo); 291f1751362SChangbin Du ret = map_aperture(vgpu, mmio_enabled); 2924d60c5fdSZhi Wang break; 293f1751362SChangbin Du default: 294f1751362SChangbin Du intel_vgpu_write_pci_bar(vgpu, offset, new, lo); 2954d60c5fdSZhi Wang } 2964d60c5fdSZhi Wang } 2974d60c5fdSZhi Wang return ret; 2984d60c5fdSZhi Wang } 2994d60c5fdSZhi Wang 3004d60c5fdSZhi Wang /** 3014d60c5fdSZhi Wang * intel_vgpu_emulate_cfg_read - emulate vGPU configuration space write 302a752b070SZhenyu Wang * @vgpu: target vgpu 303a752b070SZhenyu Wang * @offset: offset 304a752b070SZhenyu Wang * @p_data: write data ptr 305a752b070SZhenyu Wang * @bytes: number of bytes to write 3064d60c5fdSZhi Wang * 3074d60c5fdSZhi Wang * Returns: 3084d60c5fdSZhi Wang * Zero on success, negative error code if failed. 3094d60c5fdSZhi Wang */ 3109ec1e66bSJike Song int intel_vgpu_emulate_cfg_write(struct intel_vgpu *vgpu, unsigned int offset, 3114d60c5fdSZhi Wang void *p_data, unsigned int bytes) 3124d60c5fdSZhi Wang { 313a61ac1e7SChris Wilson struct drm_i915_private *i915 = vgpu->gvt->gt->i915; 3144d60c5fdSZhi Wang int ret; 3154d60c5fdSZhi Wang 31612d58619SPankaj Bharadiya if (drm_WARN_ON(&i915->drm, bytes > 4)) 3174d60c5fdSZhi Wang return -EINVAL; 3184d60c5fdSZhi Wang 31912d58619SPankaj Bharadiya if (drm_WARN_ON(&i915->drm, 32012d58619SPankaj Bharadiya offset + bytes > vgpu->gvt->device_info.cfg_space_size)) 3214d60c5fdSZhi Wang return -EINVAL; 3224d60c5fdSZhi Wang 3234d60c5fdSZhi Wang /* First check if it's PCI_COMMAND */ 3244d60c5fdSZhi Wang if (IS_ALIGNED(offset, 2) && offset == PCI_COMMAND) { 32512d58619SPankaj Bharadiya if (drm_WARN_ON(&i915->drm, bytes > 2)) 3264d60c5fdSZhi Wang return -EINVAL; 3274d60c5fdSZhi Wang return emulate_pci_command_write(vgpu, offset, p_data, bytes); 3284d60c5fdSZhi Wang } 3294d60c5fdSZhi Wang 3304d60c5fdSZhi Wang switch (rounddown(offset, 4)) { 331c4270d12SChangbin Du case PCI_ROM_ADDRESS: 33212d58619SPankaj Bharadiya if (drm_WARN_ON(&i915->drm, !IS_ALIGNED(offset, 4))) 333c4270d12SChangbin Du return -EINVAL; 334c4270d12SChangbin Du return emulate_pci_rom_bar_write(vgpu, offset, p_data, bytes); 335c4270d12SChangbin Du 336f1751362SChangbin Du case PCI_BASE_ADDRESS_0 ... PCI_BASE_ADDRESS_5: 33712d58619SPankaj Bharadiya if (drm_WARN_ON(&i915->drm, !IS_ALIGNED(offset, 4))) 3384d60c5fdSZhi Wang return -EINVAL; 3394d60c5fdSZhi Wang return emulate_pci_bar_write(vgpu, offset, p_data, bytes); 3404d60c5fdSZhi Wang 3414d60c5fdSZhi Wang case INTEL_GVT_PCI_SWSCI: 34212d58619SPankaj Bharadiya if (drm_WARN_ON(&i915->drm, !IS_ALIGNED(offset, 4))) 3434d60c5fdSZhi Wang return -EINVAL; 3444d60c5fdSZhi Wang ret = intel_vgpu_emulate_opregion_request(vgpu, *(u32 *)p_data); 3454d60c5fdSZhi Wang if (ret) 3464d60c5fdSZhi Wang return ret; 3474d60c5fdSZhi Wang break; 3484d60c5fdSZhi Wang 3494d60c5fdSZhi Wang case INTEL_GVT_PCI_OPREGION: 35012d58619SPankaj Bharadiya if (drm_WARN_ON(&i915->drm, !IS_ALIGNED(offset, 4))) 3514d60c5fdSZhi Wang return -EINVAL; 3524dff110bSXiong Zhang ret = intel_vgpu_opregion_base_write_handler(vgpu, 3534dff110bSXiong Zhang *(u32 *)p_data); 3544d60c5fdSZhi Wang if (ret) 3554d60c5fdSZhi Wang return ret; 3564d60c5fdSZhi Wang 357c2e04fdaSChangbin Du vgpu_pci_cfg_mem_write(vgpu, offset, p_data, bytes); 3584d60c5fdSZhi Wang break; 3594d60c5fdSZhi Wang default: 360c2e04fdaSChangbin Du vgpu_pci_cfg_mem_write(vgpu, offset, p_data, bytes); 3614d60c5fdSZhi Wang break; 3624d60c5fdSZhi Wang } 3634d60c5fdSZhi Wang return 0; 3644d60c5fdSZhi Wang } 365536fc234SChangbin Du 366536fc234SChangbin Du /** 367536fc234SChangbin Du * intel_vgpu_init_cfg_space - init vGPU configuration space when create vGPU 368536fc234SChangbin Du * 369536fc234SChangbin Du * @vgpu: a vGPU 370536fc234SChangbin Du * @primary: is the vGPU presented as primary 371536fc234SChangbin Du * 372536fc234SChangbin Du */ 373536fc234SChangbin Du void intel_vgpu_init_cfg_space(struct intel_vgpu *vgpu, 374536fc234SChangbin Du bool primary) 375536fc234SChangbin Du { 376536fc234SChangbin Du struct intel_gvt *gvt = vgpu->gvt; 377*9ff06c38SThomas Zimmermann struct pci_dev *pdev = to_pci_dev(gvt->gt->i915->drm.dev); 378536fc234SChangbin Du const struct intel_gvt_device_info *info = &gvt->device_info; 379536fc234SChangbin Du u16 *gmch_ctl; 380ba25d977SColin Xu u8 next; 381536fc234SChangbin Du 382536fc234SChangbin Du memcpy(vgpu_cfg_space(vgpu), gvt->firmware.cfg_space, 383536fc234SChangbin Du info->cfg_space_size); 384536fc234SChangbin Du 385536fc234SChangbin Du if (!primary) { 386536fc234SChangbin Du vgpu_cfg_space(vgpu)[PCI_CLASS_DEVICE] = 387536fc234SChangbin Du INTEL_GVT_PCI_CLASS_VGA_OTHER; 388536fc234SChangbin Du vgpu_cfg_space(vgpu)[PCI_CLASS_PROG] = 389536fc234SChangbin Du INTEL_GVT_PCI_CLASS_VGA_OTHER; 390536fc234SChangbin Du } 391536fc234SChangbin Du 392536fc234SChangbin Du /* Show guest that there isn't any stolen memory.*/ 393536fc234SChangbin Du gmch_ctl = (u16 *)(vgpu_cfg_space(vgpu) + INTEL_GVT_PCI_GMCH_CONTROL); 394536fc234SChangbin Du *gmch_ctl &= ~(BDW_GMCH_GMS_MASK << BDW_GMCH_GMS_SHIFT); 395536fc234SChangbin Du 396536fc234SChangbin Du intel_vgpu_write_pci_bar(vgpu, PCI_BASE_ADDRESS_2, 397536fc234SChangbin Du gvt_aperture_pa_base(gvt), true); 398536fc234SChangbin Du 399536fc234SChangbin Du vgpu_cfg_space(vgpu)[PCI_COMMAND] &= ~(PCI_COMMAND_IO 400536fc234SChangbin Du | PCI_COMMAND_MEMORY 401536fc234SChangbin Du | PCI_COMMAND_MASTER); 402536fc234SChangbin Du /* 403536fc234SChangbin Du * Clear the bar upper 32bit and let guest to assign the new value 404536fc234SChangbin Du */ 405536fc234SChangbin Du memset(vgpu_cfg_space(vgpu) + PCI_BASE_ADDRESS_1, 0, 4); 406536fc234SChangbin Du memset(vgpu_cfg_space(vgpu) + PCI_BASE_ADDRESS_3, 0, 4); 407f1751362SChangbin Du memset(vgpu_cfg_space(vgpu) + PCI_BASE_ADDRESS_4, 0, 8); 408536fc234SChangbin Du memset(vgpu_cfg_space(vgpu) + INTEL_GVT_PCI_OPREGION, 0, 4); 409536fc234SChangbin Du 410f1751362SChangbin Du vgpu->cfg_space.bar[INTEL_GVT_PCI_BAR_GTTMMIO].size = 411*9ff06c38SThomas Zimmermann pci_resource_len(pdev, 0); 412f1751362SChangbin Du vgpu->cfg_space.bar[INTEL_GVT_PCI_BAR_APERTURE].size = 413*9ff06c38SThomas Zimmermann pci_resource_len(pdev, 2); 414c4270d12SChangbin Du 415c4270d12SChangbin Du memset(vgpu_cfg_space(vgpu) + PCI_ROM_ADDRESS, 0, 4); 416ba25d977SColin Xu 417ba25d977SColin Xu /* PM Support */ 418ba25d977SColin Xu vgpu->cfg_space.pmcsr_off = 0; 419ba25d977SColin Xu if (vgpu_cfg_space(vgpu)[PCI_STATUS] & PCI_STATUS_CAP_LIST) { 420ba25d977SColin Xu next = vgpu_cfg_space(vgpu)[PCI_CAPABILITY_LIST]; 421ba25d977SColin Xu do { 422ba25d977SColin Xu if (vgpu_cfg_space(vgpu)[next + PCI_CAP_LIST_ID] == PCI_CAP_ID_PM) { 423ba25d977SColin Xu vgpu->cfg_space.pmcsr_off = next + PCI_PM_CTRL; 424ba25d977SColin Xu break; 425ba25d977SColin Xu } 426ba25d977SColin Xu next = vgpu_cfg_space(vgpu)[next + PCI_CAP_LIST_NEXT]; 427ba25d977SColin Xu } while (next); 428ba25d977SColin Xu } 429536fc234SChangbin Du } 430c64ff6c7SChangbin Du 431c64ff6c7SChangbin Du /** 432c64ff6c7SChangbin Du * intel_vgpu_reset_cfg_space - reset vGPU configuration space 433c64ff6c7SChangbin Du * 434c64ff6c7SChangbin Du * @vgpu: a vGPU 435c64ff6c7SChangbin Du * 436c64ff6c7SChangbin Du */ 437c64ff6c7SChangbin Du void intel_vgpu_reset_cfg_space(struct intel_vgpu *vgpu) 438c64ff6c7SChangbin Du { 439c64ff6c7SChangbin Du u8 cmd = vgpu_cfg_space(vgpu)[PCI_COMMAND]; 440c64ff6c7SChangbin Du bool primary = vgpu_cfg_space(vgpu)[PCI_CLASS_DEVICE] != 441c64ff6c7SChangbin Du INTEL_GVT_PCI_CLASS_VGA_OTHER; 442c64ff6c7SChangbin Du 443c64ff6c7SChangbin Du if (cmd & PCI_COMMAND_MEMORY) { 444c64ff6c7SChangbin Du trap_gttmmio(vgpu, false); 445c64ff6c7SChangbin Du map_aperture(vgpu, false); 446c64ff6c7SChangbin Du } 447c64ff6c7SChangbin Du 448c64ff6c7SChangbin Du /** 449c64ff6c7SChangbin Du * Currently we only do such reset when vGPU is not 450c64ff6c7SChangbin Du * owned by any VM, so we simply restore entire cfg 451c64ff6c7SChangbin Du * space to default value. 452c64ff6c7SChangbin Du */ 453c64ff6c7SChangbin Du intel_vgpu_init_cfg_space(vgpu, primary); 454c64ff6c7SChangbin Du } 455