1c00d61d8SAlex Williamson /* 2c00d61d8SAlex Williamson * device quirks for PCI devices 3c00d61d8SAlex Williamson * 4c00d61d8SAlex Williamson * Copyright Red Hat, Inc. 2012-2015 5c00d61d8SAlex Williamson * 6c00d61d8SAlex Williamson * Authors: 7c00d61d8SAlex Williamson * Alex Williamson <alex.williamson@redhat.com> 8c00d61d8SAlex Williamson * 9c00d61d8SAlex Williamson * This work is licensed under the terms of the GNU GPL, version 2. See 10c00d61d8SAlex Williamson * the COPYING file in the top-level directory. 11c00d61d8SAlex Williamson */ 12c00d61d8SAlex Williamson 13c00d61d8SAlex Williamson #include "pci.h" 14c00d61d8SAlex Williamson #include "trace.h" 15c00d61d8SAlex Williamson #include "qemu/range.h" 16c00d61d8SAlex Williamson 17056dfcb6SAlex Williamson #define PCI_ANY_ID (~0) 18056dfcb6SAlex Williamson 19056dfcb6SAlex Williamson /* Use uin32_t for vendor & device so PCI_ANY_ID expands and cannot match hw */ 20056dfcb6SAlex Williamson static bool vfio_pci_is(VFIOPCIDevice *vdev, uint32_t vendor, uint32_t device) 21056dfcb6SAlex Williamson { 22056dfcb6SAlex Williamson PCIDevice *pdev = &vdev->pdev; 23056dfcb6SAlex Williamson 24056dfcb6SAlex Williamson return (vendor == PCI_ANY_ID || 25056dfcb6SAlex Williamson vendor == pci_get_word(pdev->config + PCI_VENDOR_ID)) && 26056dfcb6SAlex Williamson (device == PCI_ANY_ID || 27056dfcb6SAlex Williamson device == pci_get_word(pdev->config + PCI_DEVICE_ID)); 28056dfcb6SAlex Williamson } 29056dfcb6SAlex Williamson 30c00d61d8SAlex Williamson /* 31c00d61d8SAlex Williamson * List of device ids/vendor ids for which to disable 32c00d61d8SAlex Williamson * option rom loading. This avoids the guest hangs during rom 33c00d61d8SAlex Williamson * execution as noticed with the BCM 57810 card for lack of a 34c00d61d8SAlex Williamson * more better way to handle such issues. 35c00d61d8SAlex Williamson * The user can still override by specifying a romfile or 36c00d61d8SAlex Williamson * rombar=1. 37c00d61d8SAlex Williamson * Please see https://bugs.launchpad.net/qemu/+bug/1284874 38c00d61d8SAlex Williamson * for an analysis of the 57810 card hang. When adding 39c00d61d8SAlex Williamson * a new vendor id/device id combination below, please also add 40c00d61d8SAlex Williamson * your card/environment details and information that could 41c00d61d8SAlex Williamson * help in debugging to the bug tracking this issue 42c00d61d8SAlex Williamson */ 43056dfcb6SAlex Williamson static const struct { 44056dfcb6SAlex Williamson uint32_t vendor; 45056dfcb6SAlex Williamson uint32_t device; 46056dfcb6SAlex Williamson } romblacklist[] = { 47056dfcb6SAlex Williamson { 0x14e4, 0x168e }, /* Broadcom BCM 57810 */ 48c00d61d8SAlex Williamson }; 49c00d61d8SAlex Williamson 50c00d61d8SAlex Williamson bool vfio_blacklist_opt_rom(VFIOPCIDevice *vdev) 51c00d61d8SAlex Williamson { 52056dfcb6SAlex Williamson int i; 53c00d61d8SAlex Williamson 54056dfcb6SAlex Williamson for (i = 0 ; i < ARRAY_SIZE(romblacklist); i++) { 55056dfcb6SAlex Williamson if (vfio_pci_is(vdev, romblacklist[i].vendor, romblacklist[i].device)) { 56056dfcb6SAlex Williamson trace_vfio_quirk_rom_blacklisted(vdev->vbasedev.name, 57056dfcb6SAlex Williamson romblacklist[i].vendor, 58056dfcb6SAlex Williamson romblacklist[i].device); 59c00d61d8SAlex Williamson return true; 60c00d61d8SAlex Williamson } 61c00d61d8SAlex Williamson } 62c00d61d8SAlex Williamson return false; 63c00d61d8SAlex Williamson } 64c00d61d8SAlex Williamson 65c00d61d8SAlex Williamson /* 66c00d61d8SAlex Williamson * Device specific quirks 67c00d61d8SAlex Williamson */ 68c00d61d8SAlex Williamson 69c00d61d8SAlex Williamson /* Is range1 fully contained within range2? */ 70c00d61d8SAlex Williamson static bool vfio_range_contained(uint64_t first1, uint64_t len1, 71c00d61d8SAlex Williamson uint64_t first2, uint64_t len2) { 72c00d61d8SAlex Williamson return (first1 >= first2 && first1 + len1 <= first2 + len2); 73c00d61d8SAlex Williamson } 74c00d61d8SAlex Williamson 75c00d61d8SAlex Williamson static bool vfio_flags_enabled(uint8_t flags, uint8_t mask) 76c00d61d8SAlex Williamson { 77c00d61d8SAlex Williamson return (mask && (flags & mask) == mask); 78c00d61d8SAlex Williamson } 79c00d61d8SAlex Williamson 80c00d61d8SAlex Williamson static uint64_t vfio_generic_window_quirk_read(void *opaque, 81c00d61d8SAlex Williamson hwaddr addr, unsigned size) 82c00d61d8SAlex Williamson { 838c4f2348SAlex Williamson VFIOLegacyQuirk *quirk = opaque; 84c00d61d8SAlex Williamson VFIOPCIDevice *vdev = quirk->vdev; 85c00d61d8SAlex Williamson uint64_t data; 86c00d61d8SAlex Williamson 87c00d61d8SAlex Williamson if (vfio_flags_enabled(quirk->data.flags, quirk->data.read_flags) && 88c00d61d8SAlex Williamson ranges_overlap(addr, size, 89c00d61d8SAlex Williamson quirk->data.data_offset, quirk->data.data_size)) { 90c00d61d8SAlex Williamson hwaddr offset = addr - quirk->data.data_offset; 91c00d61d8SAlex Williamson 92c00d61d8SAlex Williamson if (!vfio_range_contained(addr, size, quirk->data.data_offset, 93c00d61d8SAlex Williamson quirk->data.data_size)) { 94c00d61d8SAlex Williamson hw_error("%s: window data read not fully contained: %s", 958c4f2348SAlex Williamson __func__, memory_region_name(quirk->mem)); 96c00d61d8SAlex Williamson } 97c00d61d8SAlex Williamson 98c00d61d8SAlex Williamson data = vfio_pci_read_config(&vdev->pdev, 99c00d61d8SAlex Williamson quirk->data.address_val + offset, size); 100c00d61d8SAlex Williamson 1018c4f2348SAlex Williamson trace_vfio_generic_window_quirk_read(memory_region_name(quirk->mem), 102c00d61d8SAlex Williamson vdev->vbasedev.name, 103c00d61d8SAlex Williamson quirk->data.bar, 104c00d61d8SAlex Williamson addr, size, data); 105c00d61d8SAlex Williamson } else { 106c00d61d8SAlex Williamson data = vfio_region_read(&vdev->bars[quirk->data.bar].region, 107c00d61d8SAlex Williamson addr + quirk->data.base_offset, size); 108c00d61d8SAlex Williamson } 109c00d61d8SAlex Williamson 110c00d61d8SAlex Williamson return data; 111c00d61d8SAlex Williamson } 112c00d61d8SAlex Williamson 113c00d61d8SAlex Williamson static void vfio_generic_window_quirk_write(void *opaque, hwaddr addr, 114c00d61d8SAlex Williamson uint64_t data, unsigned size) 115c00d61d8SAlex Williamson { 1168c4f2348SAlex Williamson VFIOLegacyQuirk *quirk = opaque; 117c00d61d8SAlex Williamson VFIOPCIDevice *vdev = quirk->vdev; 118c00d61d8SAlex Williamson 119c00d61d8SAlex Williamson if (ranges_overlap(addr, size, 120c00d61d8SAlex Williamson quirk->data.address_offset, quirk->data.address_size)) { 121c00d61d8SAlex Williamson 122c00d61d8SAlex Williamson if (addr != quirk->data.address_offset) { 123c00d61d8SAlex Williamson hw_error("%s: offset write into address window: %s", 1248c4f2348SAlex Williamson __func__, memory_region_name(quirk->mem)); 125c00d61d8SAlex Williamson } 126c00d61d8SAlex Williamson 127c00d61d8SAlex Williamson if ((data & ~quirk->data.address_mask) == quirk->data.address_match) { 128c00d61d8SAlex Williamson quirk->data.flags |= quirk->data.write_flags | 129c00d61d8SAlex Williamson quirk->data.read_flags; 130c00d61d8SAlex Williamson quirk->data.address_val = data & quirk->data.address_mask; 131c00d61d8SAlex Williamson } else { 132c00d61d8SAlex Williamson quirk->data.flags &= ~(quirk->data.write_flags | 133c00d61d8SAlex Williamson quirk->data.read_flags); 134c00d61d8SAlex Williamson } 135c00d61d8SAlex Williamson } 136c00d61d8SAlex Williamson 137c00d61d8SAlex Williamson if (vfio_flags_enabled(quirk->data.flags, quirk->data.write_flags) && 138c00d61d8SAlex Williamson ranges_overlap(addr, size, 139c00d61d8SAlex Williamson quirk->data.data_offset, quirk->data.data_size)) { 140c00d61d8SAlex Williamson hwaddr offset = addr - quirk->data.data_offset; 141c00d61d8SAlex Williamson 142c00d61d8SAlex Williamson if (!vfio_range_contained(addr, size, quirk->data.data_offset, 143c00d61d8SAlex Williamson quirk->data.data_size)) { 144c00d61d8SAlex Williamson hw_error("%s: window data write not fully contained: %s", 1458c4f2348SAlex Williamson __func__, memory_region_name(quirk->mem)); 146c00d61d8SAlex Williamson } 147c00d61d8SAlex Williamson 148c00d61d8SAlex Williamson vfio_pci_write_config(&vdev->pdev, 149c00d61d8SAlex Williamson quirk->data.address_val + offset, data, size); 1508c4f2348SAlex Williamson trace_vfio_generic_window_quirk_write(memory_region_name(quirk->mem), 151c00d61d8SAlex Williamson vdev->vbasedev.name, 152c00d61d8SAlex Williamson quirk->data.bar, 153c00d61d8SAlex Williamson addr, data, size); 154c00d61d8SAlex Williamson return; 155c00d61d8SAlex Williamson } 156c00d61d8SAlex Williamson 157c00d61d8SAlex Williamson vfio_region_write(&vdev->bars[quirk->data.bar].region, 158c00d61d8SAlex Williamson addr + quirk->data.base_offset, data, size); 159c00d61d8SAlex Williamson } 160c00d61d8SAlex Williamson 161c00d61d8SAlex Williamson static const MemoryRegionOps vfio_generic_window_quirk = { 162c00d61d8SAlex Williamson .read = vfio_generic_window_quirk_read, 163c00d61d8SAlex Williamson .write = vfio_generic_window_quirk_write, 164c00d61d8SAlex Williamson .endianness = DEVICE_LITTLE_ENDIAN, 165c00d61d8SAlex Williamson }; 166c00d61d8SAlex Williamson 167c00d61d8SAlex Williamson static uint64_t vfio_generic_quirk_read(void *opaque, 168c00d61d8SAlex Williamson hwaddr addr, unsigned size) 169c00d61d8SAlex Williamson { 1708c4f2348SAlex Williamson VFIOLegacyQuirk *quirk = opaque; 171c00d61d8SAlex Williamson VFIOPCIDevice *vdev = quirk->vdev; 172c00d61d8SAlex Williamson hwaddr base = quirk->data.address_match & TARGET_PAGE_MASK; 173c00d61d8SAlex Williamson hwaddr offset = quirk->data.address_match & ~TARGET_PAGE_MASK; 174c00d61d8SAlex Williamson uint64_t data; 175c00d61d8SAlex Williamson 176c00d61d8SAlex Williamson if (vfio_flags_enabled(quirk->data.flags, quirk->data.read_flags) && 177c00d61d8SAlex Williamson ranges_overlap(addr, size, offset, quirk->data.address_mask + 1)) { 178c00d61d8SAlex Williamson if (!vfio_range_contained(addr, size, offset, 179c00d61d8SAlex Williamson quirk->data.address_mask + 1)) { 180c00d61d8SAlex Williamson hw_error("%s: read not fully contained: %s", 1818c4f2348SAlex Williamson __func__, memory_region_name(quirk->mem)); 182c00d61d8SAlex Williamson } 183c00d61d8SAlex Williamson 184c00d61d8SAlex Williamson data = vfio_pci_read_config(&vdev->pdev, addr - offset, size); 185c00d61d8SAlex Williamson 1868c4f2348SAlex Williamson trace_vfio_generic_quirk_read(memory_region_name(quirk->mem), 187c00d61d8SAlex Williamson vdev->vbasedev.name, quirk->data.bar, 188c00d61d8SAlex Williamson addr + base, size, data); 189c00d61d8SAlex Williamson } else { 190c00d61d8SAlex Williamson data = vfio_region_read(&vdev->bars[quirk->data.bar].region, 191c00d61d8SAlex Williamson addr + base, size); 192c00d61d8SAlex Williamson } 193c00d61d8SAlex Williamson 194c00d61d8SAlex Williamson return data; 195c00d61d8SAlex Williamson } 196c00d61d8SAlex Williamson 197c00d61d8SAlex Williamson static void vfio_generic_quirk_write(void *opaque, hwaddr addr, 198c00d61d8SAlex Williamson uint64_t data, unsigned size) 199c00d61d8SAlex Williamson { 2008c4f2348SAlex Williamson VFIOLegacyQuirk *quirk = opaque; 201c00d61d8SAlex Williamson VFIOPCIDevice *vdev = quirk->vdev; 202c00d61d8SAlex Williamson hwaddr base = quirk->data.address_match & TARGET_PAGE_MASK; 203c00d61d8SAlex Williamson hwaddr offset = quirk->data.address_match & ~TARGET_PAGE_MASK; 204c00d61d8SAlex Williamson 205c00d61d8SAlex Williamson if (vfio_flags_enabled(quirk->data.flags, quirk->data.write_flags) && 206c00d61d8SAlex Williamson ranges_overlap(addr, size, offset, quirk->data.address_mask + 1)) { 207c00d61d8SAlex Williamson if (!vfio_range_contained(addr, size, offset, 208c00d61d8SAlex Williamson quirk->data.address_mask + 1)) { 209c00d61d8SAlex Williamson hw_error("%s: write not fully contained: %s", 2108c4f2348SAlex Williamson __func__, memory_region_name(quirk->mem)); 211c00d61d8SAlex Williamson } 212c00d61d8SAlex Williamson 213c00d61d8SAlex Williamson vfio_pci_write_config(&vdev->pdev, addr - offset, data, size); 214c00d61d8SAlex Williamson 2158c4f2348SAlex Williamson trace_vfio_generic_quirk_write(memory_region_name(quirk->mem), 216c00d61d8SAlex Williamson vdev->vbasedev.name, quirk->data.bar, 217c00d61d8SAlex Williamson addr + base, data, size); 218c00d61d8SAlex Williamson } else { 219c00d61d8SAlex Williamson vfio_region_write(&vdev->bars[quirk->data.bar].region, 220c00d61d8SAlex Williamson addr + base, data, size); 221c00d61d8SAlex Williamson } 222c00d61d8SAlex Williamson } 223c00d61d8SAlex Williamson 224c00d61d8SAlex Williamson static const MemoryRegionOps vfio_generic_quirk = { 225c00d61d8SAlex Williamson .read = vfio_generic_quirk_read, 226c00d61d8SAlex Williamson .write = vfio_generic_quirk_write, 227c00d61d8SAlex Williamson .endianness = DEVICE_LITTLE_ENDIAN, 228c00d61d8SAlex Williamson }; 229c00d61d8SAlex Williamson 230c00d61d8SAlex Williamson #define PCI_VENDOR_ID_ATI 0x1002 231c00d61d8SAlex Williamson 232c00d61d8SAlex Williamson /* 233c00d61d8SAlex Williamson * Radeon HD cards (HD5450 & HD7850) report the upper byte of the I/O port BAR 234c00d61d8SAlex Williamson * through VGA register 0x3c3. On newer cards, the I/O port BAR is always 235c00d61d8SAlex Williamson * BAR4 (older cards like the X550 used BAR1, but we don't care to support 236c00d61d8SAlex Williamson * those). Note that on bare metal, a read of 0x3c3 doesn't always return the 237c00d61d8SAlex Williamson * I/O port BAR address. Originally this was coded to return the virtual BAR 238c00d61d8SAlex Williamson * address only if the physical register read returns the actual BAR address, 239c00d61d8SAlex Williamson * but users have reported greater success if we return the virtual address 240c00d61d8SAlex Williamson * unconditionally. 241c00d61d8SAlex Williamson */ 242c00d61d8SAlex Williamson static uint64_t vfio_ati_3c3_quirk_read(void *opaque, 243c00d61d8SAlex Williamson hwaddr addr, unsigned size) 244c00d61d8SAlex Williamson { 245*b946d286SAlex Williamson VFIOPCIDevice *vdev = opaque; 246c00d61d8SAlex Williamson uint64_t data = vfio_pci_read_config(&vdev->pdev, 247*b946d286SAlex Williamson PCI_BASE_ADDRESS_4 + 1, size); 248*b946d286SAlex Williamson 249*b946d286SAlex Williamson trace_vfio_quirk_ati_3c3_read(vdev->vbasedev.name, data); 250c00d61d8SAlex Williamson 251c00d61d8SAlex Williamson return data; 252c00d61d8SAlex Williamson } 253c00d61d8SAlex Williamson 254c00d61d8SAlex Williamson static const MemoryRegionOps vfio_ati_3c3_quirk = { 255c00d61d8SAlex Williamson .read = vfio_ati_3c3_quirk_read, 256c00d61d8SAlex Williamson .endianness = DEVICE_LITTLE_ENDIAN, 257c00d61d8SAlex Williamson }; 258c00d61d8SAlex Williamson 259c00d61d8SAlex Williamson static void vfio_vga_probe_ati_3c3_quirk(VFIOPCIDevice *vdev) 260c00d61d8SAlex Williamson { 261c00d61d8SAlex Williamson VFIOQuirk *quirk; 262c00d61d8SAlex Williamson 263c00d61d8SAlex Williamson /* 264c00d61d8SAlex Williamson * As long as the BAR is >= 256 bytes it will be aligned such that the 265c00d61d8SAlex Williamson * lower byte is always zero. Filter out anything else, if it exists. 266c00d61d8SAlex Williamson */ 267*b946d286SAlex Williamson if (!vfio_pci_is(vdev, PCI_VENDOR_ID_ATI, PCI_ANY_ID) || 268*b946d286SAlex Williamson !vdev->bars[4].ioport || vdev->bars[4].region.size < 256) { 269c00d61d8SAlex Williamson return; 270c00d61d8SAlex Williamson } 271c00d61d8SAlex Williamson 272c00d61d8SAlex Williamson quirk = g_malloc0(sizeof(*quirk)); 273*b946d286SAlex Williamson quirk->mem = g_malloc0_n(sizeof(MemoryRegion), 1); 2748c4f2348SAlex Williamson quirk->nr_mem = 1; 275c00d61d8SAlex Williamson 276*b946d286SAlex Williamson memory_region_init_io(quirk->mem, OBJECT(vdev), &vfio_ati_3c3_quirk, vdev, 277c00d61d8SAlex Williamson "vfio-ati-3c3-quirk", 1); 278c00d61d8SAlex Williamson memory_region_add_subregion(&vdev->vga.region[QEMU_PCI_VGA_IO_HI].mem, 2798c4f2348SAlex Williamson 3 /* offset 3 bytes from 0x3c0 */, quirk->mem); 280c00d61d8SAlex Williamson 281c00d61d8SAlex Williamson QLIST_INSERT_HEAD(&vdev->vga.region[QEMU_PCI_VGA_IO_HI].quirks, 282c00d61d8SAlex Williamson quirk, next); 283c00d61d8SAlex Williamson 284*b946d286SAlex Williamson trace_vfio_quirk_ati_3c3_probe(vdev->vbasedev.name); 285c00d61d8SAlex Williamson } 286c00d61d8SAlex Williamson 287c00d61d8SAlex Williamson /* 288c00d61d8SAlex Williamson * Newer ATI/AMD devices, including HD5450 and HD7850, have a window to PCI 289c00d61d8SAlex Williamson * config space through MMIO BAR2 at offset 0x4000. Nothing seems to access 290c00d61d8SAlex Williamson * the MMIO space directly, but a window to this space is provided through 291c00d61d8SAlex Williamson * I/O port BAR4. Offset 0x0 is the address register and offset 0x4 is the 292c00d61d8SAlex Williamson * data register. When the address is programmed to a range of 0x4000-0x4fff 293c00d61d8SAlex Williamson * PCI configuration space is available. Experimentation seems to indicate 294c00d61d8SAlex Williamson * that only read-only access is provided, but we drop writes when the window 295c00d61d8SAlex Williamson * is enabled to config space nonetheless. 296c00d61d8SAlex Williamson */ 297c00d61d8SAlex Williamson static void vfio_probe_ati_bar4_window_quirk(VFIOPCIDevice *vdev, int nr) 298c00d61d8SAlex Williamson { 299c00d61d8SAlex Williamson PCIDevice *pdev = &vdev->pdev; 300c00d61d8SAlex Williamson VFIOQuirk *quirk; 3018c4f2348SAlex Williamson VFIOLegacyQuirk *legacy; 302c00d61d8SAlex Williamson 303c00d61d8SAlex Williamson if (!vdev->has_vga || nr != 4 || 304c00d61d8SAlex Williamson pci_get_word(pdev->config + PCI_VENDOR_ID) != PCI_VENDOR_ID_ATI) { 305c00d61d8SAlex Williamson return; 306c00d61d8SAlex Williamson } 307c00d61d8SAlex Williamson 308c00d61d8SAlex Williamson quirk = g_malloc0(sizeof(*quirk)); 3098c4f2348SAlex Williamson quirk->data = legacy = g_malloc0(sizeof(*legacy)); 3108c4f2348SAlex Williamson quirk->mem = legacy->mem = g_malloc0_n(sizeof(MemoryRegion), 1); 3118c4f2348SAlex Williamson quirk->nr_mem = 1; 3128c4f2348SAlex Williamson legacy->vdev = vdev; 3138c4f2348SAlex Williamson legacy->data.address_size = 4; 3148c4f2348SAlex Williamson legacy->data.data_offset = 4; 3158c4f2348SAlex Williamson legacy->data.data_size = 4; 3168c4f2348SAlex Williamson legacy->data.address_match = 0x4000; 3178c4f2348SAlex Williamson legacy->data.address_mask = PCIE_CONFIG_SPACE_SIZE - 1; 3188c4f2348SAlex Williamson legacy->data.bar = nr; 3198c4f2348SAlex Williamson legacy->data.read_flags = legacy->data.write_flags = 1; 320c00d61d8SAlex Williamson 3218c4f2348SAlex Williamson memory_region_init_io(quirk->mem, OBJECT(vdev), 3228c4f2348SAlex Williamson &vfio_generic_window_quirk, legacy, 323c00d61d8SAlex Williamson "vfio-ati-bar4-window-quirk", 8); 324c00d61d8SAlex Williamson memory_region_add_subregion_overlap(&vdev->bars[nr].region.mem, 3258c4f2348SAlex Williamson legacy->data.base_offset, quirk->mem, 1); 326c00d61d8SAlex Williamson 327c00d61d8SAlex Williamson QLIST_INSERT_HEAD(&vdev->bars[nr].quirks, quirk, next); 328c00d61d8SAlex Williamson 329c00d61d8SAlex Williamson trace_vfio_probe_ati_bar4_window_quirk(vdev->vbasedev.name); 330c00d61d8SAlex Williamson } 331c00d61d8SAlex Williamson 332c00d61d8SAlex Williamson /* 333c00d61d8SAlex Williamson * Trap the BAR2 MMIO window to config space as well. 334c00d61d8SAlex Williamson */ 335c00d61d8SAlex Williamson static void vfio_probe_ati_bar2_4000_quirk(VFIOPCIDevice *vdev, int nr) 336c00d61d8SAlex Williamson { 337c00d61d8SAlex Williamson PCIDevice *pdev = &vdev->pdev; 338c00d61d8SAlex Williamson VFIOQuirk *quirk; 3398c4f2348SAlex Williamson VFIOLegacyQuirk *legacy; 340c00d61d8SAlex Williamson 341c00d61d8SAlex Williamson /* Only enable on newer devices where BAR2 is 64bit */ 342c00d61d8SAlex Williamson if (!vdev->has_vga || nr != 2 || !vdev->bars[2].mem64 || 343c00d61d8SAlex Williamson pci_get_word(pdev->config + PCI_VENDOR_ID) != PCI_VENDOR_ID_ATI) { 344c00d61d8SAlex Williamson return; 345c00d61d8SAlex Williamson } 346c00d61d8SAlex Williamson 347c00d61d8SAlex Williamson quirk = g_malloc0(sizeof(*quirk)); 3488c4f2348SAlex Williamson quirk->data = legacy = g_malloc0(sizeof(*legacy)); 3498c4f2348SAlex Williamson quirk->mem = legacy->mem = g_malloc0_n(sizeof(MemoryRegion), 1); 3508c4f2348SAlex Williamson quirk->nr_mem = 1; 3518c4f2348SAlex Williamson legacy->vdev = vdev; 3528c4f2348SAlex Williamson legacy->data.flags = legacy->data.read_flags = legacy->data.write_flags = 1; 3538c4f2348SAlex Williamson legacy->data.address_match = 0x4000; 3548c4f2348SAlex Williamson legacy->data.address_mask = PCIE_CONFIG_SPACE_SIZE - 1; 3558c4f2348SAlex Williamson legacy->data.bar = nr; 356c00d61d8SAlex Williamson 3578c4f2348SAlex Williamson memory_region_init_io(quirk->mem, OBJECT(vdev), &vfio_generic_quirk, legacy, 358c00d61d8SAlex Williamson "vfio-ati-bar2-4000-quirk", 3598c4f2348SAlex Williamson TARGET_PAGE_ALIGN(legacy->data.address_mask + 1)); 360c00d61d8SAlex Williamson memory_region_add_subregion_overlap(&vdev->bars[nr].region.mem, 3618c4f2348SAlex Williamson legacy->data.address_match & TARGET_PAGE_MASK, 3628c4f2348SAlex Williamson quirk->mem, 1); 363c00d61d8SAlex Williamson 364c00d61d8SAlex Williamson QLIST_INSERT_HEAD(&vdev->bars[nr].quirks, quirk, next); 365c00d61d8SAlex Williamson 366c00d61d8SAlex Williamson trace_vfio_probe_ati_bar2_4000_quirk(vdev->vbasedev.name); 367c00d61d8SAlex Williamson } 368c00d61d8SAlex Williamson 369c00d61d8SAlex Williamson /* 370c00d61d8SAlex Williamson * Older ATI/AMD cards like the X550 have a similar window to that above. 371c00d61d8SAlex Williamson * I/O port BAR1 provides a window to a mirror of PCI config space located 372c00d61d8SAlex Williamson * in BAR2 at offset 0xf00. We don't care to support such older cards, but 373c00d61d8SAlex Williamson * note it for future reference. 374c00d61d8SAlex Williamson */ 375c00d61d8SAlex Williamson 376c00d61d8SAlex Williamson #define PCI_VENDOR_ID_NVIDIA 0x10de 377c00d61d8SAlex Williamson 378c00d61d8SAlex Williamson /* 379c00d61d8SAlex Williamson * Nvidia has several different methods to get to config space, the 380c00d61d8SAlex Williamson * nouveu project has several of these documented here: 381c00d61d8SAlex Williamson * https://github.com/pathscale/envytools/tree/master/hwdocs 382c00d61d8SAlex Williamson * 383c00d61d8SAlex Williamson * The first quirk is actually not documented in envytools and is found 384c00d61d8SAlex Williamson * on 10de:01d1 (NVIDIA Corporation G72 [GeForce 7300 LE]). This is an 385c00d61d8SAlex Williamson * NV46 chipset. The backdoor uses the legacy VGA I/O ports to access 386c00d61d8SAlex Williamson * the mirror of PCI config space found at BAR0 offset 0x1800. The access 387c00d61d8SAlex Williamson * sequence first writes 0x338 to I/O port 0x3d4. The target offset is 388c00d61d8SAlex Williamson * then written to 0x3d0. Finally 0x538 is written for a read and 0x738 389c00d61d8SAlex Williamson * is written for a write to 0x3d4. The BAR0 offset is then accessible 390c00d61d8SAlex Williamson * through 0x3d0. This quirk doesn't seem to be necessary on newer cards 391c00d61d8SAlex Williamson * that use the I/O port BAR5 window but it doesn't hurt to leave it. 392c00d61d8SAlex Williamson */ 393c00d61d8SAlex Williamson enum { 394c00d61d8SAlex Williamson NV_3D0_NONE = 0, 395c00d61d8SAlex Williamson NV_3D0_SELECT, 396c00d61d8SAlex Williamson NV_3D0_WINDOW, 397c00d61d8SAlex Williamson NV_3D0_READ, 398c00d61d8SAlex Williamson NV_3D0_WRITE, 399c00d61d8SAlex Williamson }; 400c00d61d8SAlex Williamson 401c00d61d8SAlex Williamson static uint64_t vfio_nvidia_3d0_quirk_read(void *opaque, 402c00d61d8SAlex Williamson hwaddr addr, unsigned size) 403c00d61d8SAlex Williamson { 4048c4f2348SAlex Williamson VFIOLegacyQuirk *quirk = opaque; 405c00d61d8SAlex Williamson VFIOPCIDevice *vdev = quirk->vdev; 406c00d61d8SAlex Williamson PCIDevice *pdev = &vdev->pdev; 407c00d61d8SAlex Williamson uint64_t data = vfio_vga_read(&vdev->vga.region[QEMU_PCI_VGA_IO_HI], 408c00d61d8SAlex Williamson addr + quirk->data.base_offset, size); 409c00d61d8SAlex Williamson 410c00d61d8SAlex Williamson if (quirk->data.flags == NV_3D0_READ && addr == quirk->data.data_offset) { 411c00d61d8SAlex Williamson data = vfio_pci_read_config(pdev, quirk->data.address_val, size); 412c00d61d8SAlex Williamson trace_vfio_nvidia_3d0_quirk_read(size, data); 413c00d61d8SAlex Williamson } 414c00d61d8SAlex Williamson 415c00d61d8SAlex Williamson quirk->data.flags = NV_3D0_NONE; 416c00d61d8SAlex Williamson 417c00d61d8SAlex Williamson return data; 418c00d61d8SAlex Williamson } 419c00d61d8SAlex Williamson 420c00d61d8SAlex Williamson static void vfio_nvidia_3d0_quirk_write(void *opaque, hwaddr addr, 421c00d61d8SAlex Williamson uint64_t data, unsigned size) 422c00d61d8SAlex Williamson { 4238c4f2348SAlex Williamson VFIOLegacyQuirk *quirk = opaque; 424c00d61d8SAlex Williamson VFIOPCIDevice *vdev = quirk->vdev; 425c00d61d8SAlex Williamson PCIDevice *pdev = &vdev->pdev; 426c00d61d8SAlex Williamson 427c00d61d8SAlex Williamson switch (quirk->data.flags) { 428c00d61d8SAlex Williamson case NV_3D0_NONE: 429c00d61d8SAlex Williamson if (addr == quirk->data.address_offset && data == 0x338) { 430c00d61d8SAlex Williamson quirk->data.flags = NV_3D0_SELECT; 431c00d61d8SAlex Williamson } 432c00d61d8SAlex Williamson break; 433c00d61d8SAlex Williamson case NV_3D0_SELECT: 434c00d61d8SAlex Williamson quirk->data.flags = NV_3D0_NONE; 435c00d61d8SAlex Williamson if (addr == quirk->data.data_offset && 436c00d61d8SAlex Williamson (data & ~quirk->data.address_mask) == quirk->data.address_match) { 437c00d61d8SAlex Williamson quirk->data.flags = NV_3D0_WINDOW; 438c00d61d8SAlex Williamson quirk->data.address_val = data & quirk->data.address_mask; 439c00d61d8SAlex Williamson } 440c00d61d8SAlex Williamson break; 441c00d61d8SAlex Williamson case NV_3D0_WINDOW: 442c00d61d8SAlex Williamson quirk->data.flags = NV_3D0_NONE; 443c00d61d8SAlex Williamson if (addr == quirk->data.address_offset) { 444c00d61d8SAlex Williamson if (data == 0x538) { 445c00d61d8SAlex Williamson quirk->data.flags = NV_3D0_READ; 446c00d61d8SAlex Williamson } else if (data == 0x738) { 447c00d61d8SAlex Williamson quirk->data.flags = NV_3D0_WRITE; 448c00d61d8SAlex Williamson } 449c00d61d8SAlex Williamson } 450c00d61d8SAlex Williamson break; 451c00d61d8SAlex Williamson case NV_3D0_WRITE: 452c00d61d8SAlex Williamson quirk->data.flags = NV_3D0_NONE; 453c00d61d8SAlex Williamson if (addr == quirk->data.data_offset) { 454c00d61d8SAlex Williamson vfio_pci_write_config(pdev, quirk->data.address_val, data, size); 455c00d61d8SAlex Williamson trace_vfio_nvidia_3d0_quirk_write(data, size); 456c00d61d8SAlex Williamson return; 457c00d61d8SAlex Williamson } 458c00d61d8SAlex Williamson break; 459c00d61d8SAlex Williamson } 460c00d61d8SAlex Williamson 461c00d61d8SAlex Williamson vfio_vga_write(&vdev->vga.region[QEMU_PCI_VGA_IO_HI], 462c00d61d8SAlex Williamson addr + quirk->data.base_offset, data, size); 463c00d61d8SAlex Williamson } 464c00d61d8SAlex Williamson 465c00d61d8SAlex Williamson static const MemoryRegionOps vfio_nvidia_3d0_quirk = { 466c00d61d8SAlex Williamson .read = vfio_nvidia_3d0_quirk_read, 467c00d61d8SAlex Williamson .write = vfio_nvidia_3d0_quirk_write, 468c00d61d8SAlex Williamson .endianness = DEVICE_LITTLE_ENDIAN, 469c00d61d8SAlex Williamson }; 470c00d61d8SAlex Williamson 471c00d61d8SAlex Williamson static void vfio_vga_probe_nvidia_3d0_quirk(VFIOPCIDevice *vdev) 472c00d61d8SAlex Williamson { 473c00d61d8SAlex Williamson PCIDevice *pdev = &vdev->pdev; 474c00d61d8SAlex Williamson VFIOQuirk *quirk; 4758c4f2348SAlex Williamson VFIOLegacyQuirk *legacy; 476c00d61d8SAlex Williamson 477c00d61d8SAlex Williamson if (pci_get_word(pdev->config + PCI_VENDOR_ID) != PCI_VENDOR_ID_NVIDIA || 478c00d61d8SAlex Williamson !vdev->bars[1].region.size) { 479c00d61d8SAlex Williamson return; 480c00d61d8SAlex Williamson } 481c00d61d8SAlex Williamson 482c00d61d8SAlex Williamson quirk = g_malloc0(sizeof(*quirk)); 4838c4f2348SAlex Williamson quirk->data = legacy = g_malloc0(sizeof(*legacy)); 4848c4f2348SAlex Williamson quirk->mem = legacy->mem = g_malloc0_n(sizeof(MemoryRegion), 1); 4858c4f2348SAlex Williamson quirk->nr_mem = 1; 4868c4f2348SAlex Williamson legacy->vdev = vdev; 4878c4f2348SAlex Williamson legacy->data.base_offset = 0x10; 4888c4f2348SAlex Williamson legacy->data.address_offset = 4; 4898c4f2348SAlex Williamson legacy->data.address_size = 2; 4908c4f2348SAlex Williamson legacy->data.address_match = 0x1800; 4918c4f2348SAlex Williamson legacy->data.address_mask = PCI_CONFIG_SPACE_SIZE - 1; 4928c4f2348SAlex Williamson legacy->data.data_offset = 0; 4938c4f2348SAlex Williamson legacy->data.data_size = 4; 494c00d61d8SAlex Williamson 4958c4f2348SAlex Williamson memory_region_init_io(quirk->mem, OBJECT(vdev), &vfio_nvidia_3d0_quirk, 4968c4f2348SAlex Williamson legacy, "vfio-nvidia-3d0-quirk", 6); 497c00d61d8SAlex Williamson memory_region_add_subregion(&vdev->vga.region[QEMU_PCI_VGA_IO_HI].mem, 4988c4f2348SAlex Williamson legacy->data.base_offset, quirk->mem); 499c00d61d8SAlex Williamson 500c00d61d8SAlex Williamson QLIST_INSERT_HEAD(&vdev->vga.region[QEMU_PCI_VGA_IO_HI].quirks, 501c00d61d8SAlex Williamson quirk, next); 502c00d61d8SAlex Williamson 503c00d61d8SAlex Williamson trace_vfio_vga_probe_nvidia_3d0_quirk(vdev->vbasedev.name); 504c00d61d8SAlex Williamson } 505c00d61d8SAlex Williamson 506c00d61d8SAlex Williamson /* 507c00d61d8SAlex Williamson * The second quirk is documented in envytools. The I/O port BAR5 is just 508c00d61d8SAlex Williamson * a set of address/data ports to the MMIO BARs. The BAR we care about is 509c00d61d8SAlex Williamson * again BAR0. This backdoor is apparently a bit newer than the one above 510c00d61d8SAlex Williamson * so we need to not only trap 256 bytes @0x1800, but all of PCI config 511c00d61d8SAlex Williamson * space, including extended space is available at the 4k @0x88000. 512c00d61d8SAlex Williamson */ 513c00d61d8SAlex Williamson enum { 514c00d61d8SAlex Williamson NV_BAR5_ADDRESS = 0x1, 515c00d61d8SAlex Williamson NV_BAR5_ENABLE = 0x2, 516c00d61d8SAlex Williamson NV_BAR5_MASTER = 0x4, 517c00d61d8SAlex Williamson NV_BAR5_VALID = 0x7, 518c00d61d8SAlex Williamson }; 519c00d61d8SAlex Williamson 520c00d61d8SAlex Williamson static void vfio_nvidia_bar5_window_quirk_write(void *opaque, hwaddr addr, 521c00d61d8SAlex Williamson uint64_t data, unsigned size) 522c00d61d8SAlex Williamson { 5238c4f2348SAlex Williamson VFIOLegacyQuirk *quirk = opaque; 524c00d61d8SAlex Williamson 525c00d61d8SAlex Williamson switch (addr) { 526c00d61d8SAlex Williamson case 0x0: 527c00d61d8SAlex Williamson if (data & 0x1) { 528c00d61d8SAlex Williamson quirk->data.flags |= NV_BAR5_MASTER; 529c00d61d8SAlex Williamson } else { 530c00d61d8SAlex Williamson quirk->data.flags &= ~NV_BAR5_MASTER; 531c00d61d8SAlex Williamson } 532c00d61d8SAlex Williamson break; 533c00d61d8SAlex Williamson case 0x4: 534c00d61d8SAlex Williamson if (data & 0x1) { 535c00d61d8SAlex Williamson quirk->data.flags |= NV_BAR5_ENABLE; 536c00d61d8SAlex Williamson } else { 537c00d61d8SAlex Williamson quirk->data.flags &= ~NV_BAR5_ENABLE; 538c00d61d8SAlex Williamson } 539c00d61d8SAlex Williamson break; 540c00d61d8SAlex Williamson case 0x8: 541c00d61d8SAlex Williamson if (quirk->data.flags & NV_BAR5_MASTER) { 542c00d61d8SAlex Williamson if ((data & ~0xfff) == 0x88000) { 543c00d61d8SAlex Williamson quirk->data.flags |= NV_BAR5_ADDRESS; 544c00d61d8SAlex Williamson quirk->data.address_val = data & 0xfff; 545c00d61d8SAlex Williamson } else if ((data & ~0xff) == 0x1800) { 546c00d61d8SAlex Williamson quirk->data.flags |= NV_BAR5_ADDRESS; 547c00d61d8SAlex Williamson quirk->data.address_val = data & 0xff; 548c00d61d8SAlex Williamson } else { 549c00d61d8SAlex Williamson quirk->data.flags &= ~NV_BAR5_ADDRESS; 550c00d61d8SAlex Williamson } 551c00d61d8SAlex Williamson } 552c00d61d8SAlex Williamson break; 553c00d61d8SAlex Williamson } 554c00d61d8SAlex Williamson 555c00d61d8SAlex Williamson vfio_generic_window_quirk_write(opaque, addr, data, size); 556c00d61d8SAlex Williamson } 557c00d61d8SAlex Williamson 558c00d61d8SAlex Williamson static const MemoryRegionOps vfio_nvidia_bar5_window_quirk = { 559c00d61d8SAlex Williamson .read = vfio_generic_window_quirk_read, 560c00d61d8SAlex Williamson .write = vfio_nvidia_bar5_window_quirk_write, 561c00d61d8SAlex Williamson .valid.min_access_size = 4, 562c00d61d8SAlex Williamson .endianness = DEVICE_LITTLE_ENDIAN, 563c00d61d8SAlex Williamson }; 564c00d61d8SAlex Williamson 565c00d61d8SAlex Williamson static void vfio_probe_nvidia_bar5_window_quirk(VFIOPCIDevice *vdev, int nr) 566c00d61d8SAlex Williamson { 567c00d61d8SAlex Williamson PCIDevice *pdev = &vdev->pdev; 568c00d61d8SAlex Williamson VFIOQuirk *quirk; 5698c4f2348SAlex Williamson VFIOLegacyQuirk *legacy; 570c00d61d8SAlex Williamson 571c00d61d8SAlex Williamson if (!vdev->has_vga || nr != 5 || 572c00d61d8SAlex Williamson pci_get_word(pdev->config + PCI_VENDOR_ID) != PCI_VENDOR_ID_NVIDIA) { 573c00d61d8SAlex Williamson return; 574c00d61d8SAlex Williamson } 575c00d61d8SAlex Williamson 576c00d61d8SAlex Williamson quirk = g_malloc0(sizeof(*quirk)); 5778c4f2348SAlex Williamson quirk->data = legacy = g_malloc0(sizeof(*legacy)); 5788c4f2348SAlex Williamson quirk->mem = legacy->mem = g_malloc0_n(sizeof(MemoryRegion), 1); 5798c4f2348SAlex Williamson quirk->nr_mem = 1; 5808c4f2348SAlex Williamson legacy->vdev = vdev; 5818c4f2348SAlex Williamson legacy->data.read_flags = legacy->data.write_flags = NV_BAR5_VALID; 5828c4f2348SAlex Williamson legacy->data.address_offset = 0x8; 5838c4f2348SAlex Williamson legacy->data.address_size = 0; /* actually 4, but avoids generic code */ 5848c4f2348SAlex Williamson legacy->data.data_offset = 0xc; 5858c4f2348SAlex Williamson legacy->data.data_size = 4; 5868c4f2348SAlex Williamson legacy->data.bar = nr; 587c00d61d8SAlex Williamson 5888c4f2348SAlex Williamson memory_region_init_io(quirk->mem, OBJECT(vdev), 5898c4f2348SAlex Williamson &vfio_nvidia_bar5_window_quirk, legacy, 590c00d61d8SAlex Williamson "vfio-nvidia-bar5-window-quirk", 16); 591c00d61d8SAlex Williamson memory_region_add_subregion_overlap(&vdev->bars[nr].region.mem, 5928c4f2348SAlex Williamson 0, quirk->mem, 1); 593c00d61d8SAlex Williamson 594c00d61d8SAlex Williamson QLIST_INSERT_HEAD(&vdev->bars[nr].quirks, quirk, next); 595c00d61d8SAlex Williamson 596c00d61d8SAlex Williamson trace_vfio_probe_nvidia_bar5_window_quirk(vdev->vbasedev.name); 597c00d61d8SAlex Williamson } 598c00d61d8SAlex Williamson 599c00d61d8SAlex Williamson static void vfio_nvidia_88000_quirk_write(void *opaque, hwaddr addr, 600c00d61d8SAlex Williamson uint64_t data, unsigned size) 601c00d61d8SAlex Williamson { 6028c4f2348SAlex Williamson VFIOLegacyQuirk *quirk = opaque; 603c00d61d8SAlex Williamson VFIOPCIDevice *vdev = quirk->vdev; 604c00d61d8SAlex Williamson PCIDevice *pdev = &vdev->pdev; 605c00d61d8SAlex Williamson hwaddr base = quirk->data.address_match & TARGET_PAGE_MASK; 606c00d61d8SAlex Williamson 607c00d61d8SAlex Williamson vfio_generic_quirk_write(opaque, addr, data, size); 608c00d61d8SAlex Williamson 609c00d61d8SAlex Williamson /* 610c00d61d8SAlex Williamson * Nvidia seems to acknowledge MSI interrupts by writing 0xff to the 611c00d61d8SAlex Williamson * MSI capability ID register. Both the ID and next register are 612c00d61d8SAlex Williamson * read-only, so we allow writes covering either of those to real hw. 613c00d61d8SAlex Williamson * NB - only fixed for the 0x88000 MMIO window. 614c00d61d8SAlex Williamson */ 615c00d61d8SAlex Williamson if ((pdev->cap_present & QEMU_PCI_CAP_MSI) && 616c00d61d8SAlex Williamson vfio_range_contained(addr, size, pdev->msi_cap, PCI_MSI_FLAGS)) { 617c00d61d8SAlex Williamson vfio_region_write(&vdev->bars[quirk->data.bar].region, 618c00d61d8SAlex Williamson addr + base, data, size); 619c00d61d8SAlex Williamson } 620c00d61d8SAlex Williamson } 621c00d61d8SAlex Williamson 622c00d61d8SAlex Williamson static const MemoryRegionOps vfio_nvidia_88000_quirk = { 623c00d61d8SAlex Williamson .read = vfio_generic_quirk_read, 624c00d61d8SAlex Williamson .write = vfio_nvidia_88000_quirk_write, 625c00d61d8SAlex Williamson .endianness = DEVICE_LITTLE_ENDIAN, 626c00d61d8SAlex Williamson }; 627c00d61d8SAlex Williamson 628c00d61d8SAlex Williamson /* 629c00d61d8SAlex Williamson * Finally, BAR0 itself. We want to redirect any accesses to either 630c00d61d8SAlex Williamson * 0x1800 or 0x88000 through the PCI config space access functions. 631c00d61d8SAlex Williamson * 632c00d61d8SAlex Williamson * NB - quirk at a page granularity or else they don't seem to work when 633c00d61d8SAlex Williamson * BARs are mmap'd 634c00d61d8SAlex Williamson * 635c00d61d8SAlex Williamson * Here's offset 0x88000... 636c00d61d8SAlex Williamson */ 637c00d61d8SAlex Williamson static void vfio_probe_nvidia_bar0_88000_quirk(VFIOPCIDevice *vdev, int nr) 638c00d61d8SAlex Williamson { 639c00d61d8SAlex Williamson PCIDevice *pdev = &vdev->pdev; 640c00d61d8SAlex Williamson VFIOQuirk *quirk; 6418c4f2348SAlex Williamson VFIOLegacyQuirk *legacy; 642c00d61d8SAlex Williamson uint16_t vendor, class; 643c00d61d8SAlex Williamson 644c00d61d8SAlex Williamson vendor = pci_get_word(pdev->config + PCI_VENDOR_ID); 645c00d61d8SAlex Williamson class = pci_get_word(pdev->config + PCI_CLASS_DEVICE); 646c00d61d8SAlex Williamson 647c00d61d8SAlex Williamson if (nr != 0 || vendor != PCI_VENDOR_ID_NVIDIA || 648c00d61d8SAlex Williamson class != PCI_CLASS_DISPLAY_VGA) { 649c00d61d8SAlex Williamson return; 650c00d61d8SAlex Williamson } 651c00d61d8SAlex Williamson 652c00d61d8SAlex Williamson quirk = g_malloc0(sizeof(*quirk)); 6538c4f2348SAlex Williamson quirk->data = legacy = g_malloc0(sizeof(*legacy)); 6548c4f2348SAlex Williamson quirk->mem = legacy->mem = g_malloc0_n(sizeof(MemoryRegion), 1); 6558c4f2348SAlex Williamson quirk->nr_mem = 1; 6568c4f2348SAlex Williamson legacy->vdev = vdev; 6578c4f2348SAlex Williamson legacy->data.flags = legacy->data.read_flags = legacy->data.write_flags = 1; 6588c4f2348SAlex Williamson legacy->data.address_match = 0x88000; 6598c4f2348SAlex Williamson legacy->data.address_mask = PCIE_CONFIG_SPACE_SIZE - 1; 6608c4f2348SAlex Williamson legacy->data.bar = nr; 661c00d61d8SAlex Williamson 6628c4f2348SAlex Williamson memory_region_init_io(quirk->mem, OBJECT(vdev), &vfio_nvidia_88000_quirk, 6638c4f2348SAlex Williamson legacy, "vfio-nvidia-bar0-88000-quirk", 6648c4f2348SAlex Williamson TARGET_PAGE_ALIGN(legacy->data.address_mask + 1)); 665c00d61d8SAlex Williamson memory_region_add_subregion_overlap(&vdev->bars[nr].region.mem, 6668c4f2348SAlex Williamson legacy->data.address_match & TARGET_PAGE_MASK, 6678c4f2348SAlex Williamson quirk->mem, 1); 668c00d61d8SAlex Williamson 669c00d61d8SAlex Williamson QLIST_INSERT_HEAD(&vdev->bars[nr].quirks, quirk, next); 670c00d61d8SAlex Williamson 671c00d61d8SAlex Williamson trace_vfio_probe_nvidia_bar0_88000_quirk(vdev->vbasedev.name); 672c00d61d8SAlex Williamson } 673c00d61d8SAlex Williamson 674c00d61d8SAlex Williamson /* 675c00d61d8SAlex Williamson * And here's the same for BAR0 offset 0x1800... 676c00d61d8SAlex Williamson */ 677c00d61d8SAlex Williamson static void vfio_probe_nvidia_bar0_1800_quirk(VFIOPCIDevice *vdev, int nr) 678c00d61d8SAlex Williamson { 679c00d61d8SAlex Williamson PCIDevice *pdev = &vdev->pdev; 680c00d61d8SAlex Williamson VFIOQuirk *quirk; 6818c4f2348SAlex Williamson VFIOLegacyQuirk *legacy; 682c00d61d8SAlex Williamson 683c00d61d8SAlex Williamson if (!vdev->has_vga || nr != 0 || 684c00d61d8SAlex Williamson pci_get_word(pdev->config + PCI_VENDOR_ID) != PCI_VENDOR_ID_NVIDIA) { 685c00d61d8SAlex Williamson return; 686c00d61d8SAlex Williamson } 687c00d61d8SAlex Williamson 688c00d61d8SAlex Williamson /* Log the chipset ID */ 689c00d61d8SAlex Williamson trace_vfio_probe_nvidia_bar0_1800_quirk_id( 690c00d61d8SAlex Williamson (unsigned int)(vfio_region_read(&vdev->bars[0].region, 0, 4) >> 20) 691c00d61d8SAlex Williamson & 0xff); 692c00d61d8SAlex Williamson 693c00d61d8SAlex Williamson quirk = g_malloc0(sizeof(*quirk)); 6948c4f2348SAlex Williamson quirk->data = legacy = g_malloc0(sizeof(*legacy)); 6958c4f2348SAlex Williamson quirk->mem = legacy->mem = g_malloc0_n(sizeof(MemoryRegion), 1); 6968c4f2348SAlex Williamson quirk->nr_mem = 1; 6978c4f2348SAlex Williamson legacy->vdev = vdev; 6988c4f2348SAlex Williamson legacy->data.flags = legacy->data.read_flags = legacy->data.write_flags = 1; 6998c4f2348SAlex Williamson legacy->data.address_match = 0x1800; 7008c4f2348SAlex Williamson legacy->data.address_mask = PCI_CONFIG_SPACE_SIZE - 1; 7018c4f2348SAlex Williamson legacy->data.bar = nr; 702c00d61d8SAlex Williamson 7038c4f2348SAlex Williamson memory_region_init_io(quirk->mem, OBJECT(vdev), &vfio_generic_quirk, legacy, 704c00d61d8SAlex Williamson "vfio-nvidia-bar0-1800-quirk", 7058c4f2348SAlex Williamson TARGET_PAGE_ALIGN(legacy->data.address_mask + 1)); 706c00d61d8SAlex Williamson memory_region_add_subregion_overlap(&vdev->bars[nr].region.mem, 7078c4f2348SAlex Williamson legacy->data.address_match & TARGET_PAGE_MASK, 7088c4f2348SAlex Williamson quirk->mem, 1); 709c00d61d8SAlex Williamson 710c00d61d8SAlex Williamson QLIST_INSERT_HEAD(&vdev->bars[nr].quirks, quirk, next); 711c00d61d8SAlex Williamson 712c00d61d8SAlex Williamson trace_vfio_probe_nvidia_bar0_1800_quirk(vdev->vbasedev.name); 713c00d61d8SAlex Williamson } 714c00d61d8SAlex Williamson 715c00d61d8SAlex Williamson /* 716c00d61d8SAlex Williamson * TODO - Some Nvidia devices provide config access to their companion HDA 717c00d61d8SAlex Williamson * device and even to their parent bridge via these config space mirrors. 718c00d61d8SAlex Williamson * Add quirks for those regions. 719c00d61d8SAlex Williamson */ 720c00d61d8SAlex Williamson 721c00d61d8SAlex Williamson #define PCI_VENDOR_ID_REALTEK 0x10ec 722c00d61d8SAlex Williamson 723c00d61d8SAlex Williamson /* 724c00d61d8SAlex Williamson * RTL8168 devices have a backdoor that can access the MSI-X table. At BAR2 725c00d61d8SAlex Williamson * offset 0x70 there is a dword data register, offset 0x74 is a dword address 726c00d61d8SAlex Williamson * register. According to the Linux r8169 driver, the MSI-X table is addressed 727c00d61d8SAlex Williamson * when the "type" portion of the address register is set to 0x1. This appears 728c00d61d8SAlex Williamson * to be bits 16:30. Bit 31 is both a write indicator and some sort of 729c00d61d8SAlex Williamson * "address latched" indicator. Bits 12:15 are a mask field, which we can 730c00d61d8SAlex Williamson * ignore because the MSI-X table should always be accessed as a dword (full 731c00d61d8SAlex Williamson * mask). Bits 0:11 is offset within the type. 732c00d61d8SAlex Williamson * 733c00d61d8SAlex Williamson * Example trace: 734c00d61d8SAlex Williamson * 735c00d61d8SAlex Williamson * Read from MSI-X table offset 0 736c00d61d8SAlex Williamson * vfio: vfio_bar_write(0000:05:00.0:BAR2+0x74, 0x1f000, 4) // store read addr 737c00d61d8SAlex Williamson * vfio: vfio_bar_read(0000:05:00.0:BAR2+0x74, 4) = 0x8001f000 // latch 738c00d61d8SAlex Williamson * vfio: vfio_bar_read(0000:05:00.0:BAR2+0x70, 4) = 0xfee00398 // read data 739c00d61d8SAlex Williamson * 740c00d61d8SAlex Williamson * Write 0xfee00000 to MSI-X table offset 0 741c00d61d8SAlex Williamson * vfio: vfio_bar_write(0000:05:00.0:BAR2+0x70, 0xfee00000, 4) // write data 742c00d61d8SAlex Williamson * vfio: vfio_bar_write(0000:05:00.0:BAR2+0x74, 0x8001f000, 4) // do write 743c00d61d8SAlex Williamson * vfio: vfio_bar_read(0000:05:00.0:BAR2+0x74, 4) = 0x1f000 // complete 744c00d61d8SAlex Williamson */ 745c00d61d8SAlex Williamson static uint64_t vfio_rtl8168_window_quirk_read(void *opaque, 746c00d61d8SAlex Williamson hwaddr addr, unsigned size) 747c00d61d8SAlex Williamson { 7488c4f2348SAlex Williamson VFIOLegacyQuirk *quirk = opaque; 749c00d61d8SAlex Williamson VFIOPCIDevice *vdev = quirk->vdev; 750c00d61d8SAlex Williamson uint64_t val = 0; 751c00d61d8SAlex Williamson 752c00d61d8SAlex Williamson if (!quirk->data.flags) { /* Non-MSI-X table access */ 753c00d61d8SAlex Williamson return vfio_region_read(&vdev->bars[quirk->data.bar].region, 754c00d61d8SAlex Williamson addr + 0x70, size); 755c00d61d8SAlex Williamson } 756c00d61d8SAlex Williamson 757c00d61d8SAlex Williamson switch (addr) { 758c00d61d8SAlex Williamson case 4: /* address */ 759c00d61d8SAlex Williamson val = quirk->data.address_match ^ 0x80000000U; /* latch/complete */ 760c00d61d8SAlex Williamson break; 761c00d61d8SAlex Williamson case 0: /* data */ 762c00d61d8SAlex Williamson if ((vdev->pdev.cap_present & QEMU_PCI_CAP_MSIX)) { 763c00d61d8SAlex Williamson memory_region_dispatch_read(&vdev->pdev.msix_table_mmio, 764c00d61d8SAlex Williamson (hwaddr)(quirk->data.address_match & 0xfff), 765c00d61d8SAlex Williamson &val, size, MEMTXATTRS_UNSPECIFIED); 766c00d61d8SAlex Williamson } 767c00d61d8SAlex Williamson break; 768c00d61d8SAlex Williamson } 769c00d61d8SAlex Williamson 770c00d61d8SAlex Williamson trace_vfio_rtl8168_quirk_read(vdev->vbasedev.name, 771c00d61d8SAlex Williamson addr ? "address" : "data", val); 772c00d61d8SAlex Williamson return val; 773c00d61d8SAlex Williamson } 774c00d61d8SAlex Williamson 775c00d61d8SAlex Williamson static void vfio_rtl8168_window_quirk_write(void *opaque, hwaddr addr, 776c00d61d8SAlex Williamson uint64_t data, unsigned size) 777c00d61d8SAlex Williamson { 7788c4f2348SAlex Williamson VFIOLegacyQuirk *quirk = opaque; 779c00d61d8SAlex Williamson VFIOPCIDevice *vdev = quirk->vdev; 780c00d61d8SAlex Williamson 781c00d61d8SAlex Williamson switch (addr) { 782c00d61d8SAlex Williamson case 4: /* address */ 783c00d61d8SAlex Williamson if ((data & 0x7fff0000) == 0x10000) { /* MSI-X table */ 784c00d61d8SAlex Williamson quirk->data.flags = 1; /* Activate reads */ 785c00d61d8SAlex Williamson quirk->data.address_match = data; 786c00d61d8SAlex Williamson 787c00d61d8SAlex Williamson trace_vfio_rtl8168_quirk_write(vdev->vbasedev.name, data); 788c00d61d8SAlex Williamson 789c00d61d8SAlex Williamson if (data & 0x80000000U) { /* Do write */ 790c00d61d8SAlex Williamson if (vdev->pdev.cap_present & QEMU_PCI_CAP_MSIX) { 791c00d61d8SAlex Williamson hwaddr offset = data & 0xfff; 792c00d61d8SAlex Williamson uint64_t val = quirk->data.address_mask; 793c00d61d8SAlex Williamson 794c00d61d8SAlex Williamson trace_vfio_rtl8168_quirk_msix(vdev->vbasedev.name, 795c00d61d8SAlex Williamson (uint16_t)offset, val); 796c00d61d8SAlex Williamson 797c00d61d8SAlex Williamson /* Write to the proper guest MSI-X table instead */ 798c00d61d8SAlex Williamson memory_region_dispatch_write(&vdev->pdev.msix_table_mmio, 799c00d61d8SAlex Williamson offset, val, size, 800c00d61d8SAlex Williamson MEMTXATTRS_UNSPECIFIED); 801c00d61d8SAlex Williamson } 802c00d61d8SAlex Williamson return; /* Do not write guest MSI-X data to hardware */ 803c00d61d8SAlex Williamson } 804c00d61d8SAlex Williamson } else { 805c00d61d8SAlex Williamson quirk->data.flags = 0; /* De-activate reads, non-MSI-X */ 806c00d61d8SAlex Williamson } 807c00d61d8SAlex Williamson break; 808c00d61d8SAlex Williamson case 0: /* data */ 809c00d61d8SAlex Williamson quirk->data.address_mask = data; 810c00d61d8SAlex Williamson break; 811c00d61d8SAlex Williamson } 812c00d61d8SAlex Williamson 813c00d61d8SAlex Williamson vfio_region_write(&vdev->bars[quirk->data.bar].region, 814c00d61d8SAlex Williamson addr + 0x70, data, size); 815c00d61d8SAlex Williamson } 816c00d61d8SAlex Williamson 817c00d61d8SAlex Williamson static const MemoryRegionOps vfio_rtl8168_window_quirk = { 818c00d61d8SAlex Williamson .read = vfio_rtl8168_window_quirk_read, 819c00d61d8SAlex Williamson .write = vfio_rtl8168_window_quirk_write, 820c00d61d8SAlex Williamson .valid = { 821c00d61d8SAlex Williamson .min_access_size = 4, 822c00d61d8SAlex Williamson .max_access_size = 4, 823c00d61d8SAlex Williamson .unaligned = false, 824c00d61d8SAlex Williamson }, 825c00d61d8SAlex Williamson .endianness = DEVICE_LITTLE_ENDIAN, 826c00d61d8SAlex Williamson }; 827c00d61d8SAlex Williamson 828c00d61d8SAlex Williamson static void vfio_probe_rtl8168_bar2_window_quirk(VFIOPCIDevice *vdev, int nr) 829c00d61d8SAlex Williamson { 830c00d61d8SAlex Williamson PCIDevice *pdev = &vdev->pdev; 831c00d61d8SAlex Williamson VFIOQuirk *quirk; 8328c4f2348SAlex Williamson VFIOLegacyQuirk *legacy; 833c00d61d8SAlex Williamson 834c00d61d8SAlex Williamson if (pci_get_word(pdev->config + PCI_VENDOR_ID) != PCI_VENDOR_ID_REALTEK || 835c00d61d8SAlex Williamson pci_get_word(pdev->config + PCI_DEVICE_ID) != 0x8168 || nr != 2) { 836c00d61d8SAlex Williamson return; 837c00d61d8SAlex Williamson } 838c00d61d8SAlex Williamson 839c00d61d8SAlex Williamson quirk = g_malloc0(sizeof(*quirk)); 8408c4f2348SAlex Williamson quirk->data = legacy = g_malloc0(sizeof(*legacy)); 8418c4f2348SAlex Williamson quirk->mem = legacy->mem = g_malloc0_n(sizeof(MemoryRegion), 1); 8428c4f2348SAlex Williamson quirk->nr_mem = 1; 8438c4f2348SAlex Williamson legacy->vdev = vdev; 8448c4f2348SAlex Williamson legacy->data.bar = nr; 845c00d61d8SAlex Williamson 8468c4f2348SAlex Williamson memory_region_init_io(quirk->mem, OBJECT(vdev), &vfio_rtl8168_window_quirk, 8478c4f2348SAlex Williamson legacy, "vfio-rtl8168-window-quirk", 8); 848c00d61d8SAlex Williamson memory_region_add_subregion_overlap(&vdev->bars[nr].region.mem, 8498c4f2348SAlex Williamson 0x70, quirk->mem, 1); 850c00d61d8SAlex Williamson 851c00d61d8SAlex Williamson QLIST_INSERT_HEAD(&vdev->bars[nr].quirks, quirk, next); 852c00d61d8SAlex Williamson 853c00d61d8SAlex Williamson trace_vfio_rtl8168_quirk_enable(vdev->vbasedev.name); 854c00d61d8SAlex Williamson } 855c00d61d8SAlex Williamson 856c00d61d8SAlex Williamson /* 857c00d61d8SAlex Williamson * Common quirk probe entry points. 858c00d61d8SAlex Williamson */ 859c00d61d8SAlex Williamson void vfio_vga_quirk_setup(VFIOPCIDevice *vdev) 860c00d61d8SAlex Williamson { 861c00d61d8SAlex Williamson vfio_vga_probe_ati_3c3_quirk(vdev); 862c00d61d8SAlex Williamson vfio_vga_probe_nvidia_3d0_quirk(vdev); 863c00d61d8SAlex Williamson } 864c00d61d8SAlex Williamson 865c00d61d8SAlex Williamson void vfio_vga_quirk_teardown(VFIOPCIDevice *vdev) 866c00d61d8SAlex Williamson { 867c00d61d8SAlex Williamson VFIOQuirk *quirk; 8688c4f2348SAlex Williamson int i, j; 869c00d61d8SAlex Williamson 870c00d61d8SAlex Williamson for (i = 0; i < ARRAY_SIZE(vdev->vga.region); i++) { 871c00d61d8SAlex Williamson QLIST_FOREACH(quirk, &vdev->vga.region[i].quirks, next) { 8728c4f2348SAlex Williamson for (j = 0; j < quirk->nr_mem; j++) { 8738c4f2348SAlex Williamson memory_region_del_subregion(&vdev->vga.region[i].mem, 8748c4f2348SAlex Williamson &quirk->mem[j]); 8758c4f2348SAlex Williamson } 876c00d61d8SAlex Williamson } 877c00d61d8SAlex Williamson } 878c00d61d8SAlex Williamson } 879c00d61d8SAlex Williamson 880c00d61d8SAlex Williamson void vfio_vga_quirk_free(VFIOPCIDevice *vdev) 881c00d61d8SAlex Williamson { 8828c4f2348SAlex Williamson int i, j; 883c00d61d8SAlex Williamson 884c00d61d8SAlex Williamson for (i = 0; i < ARRAY_SIZE(vdev->vga.region); i++) { 885c00d61d8SAlex Williamson while (!QLIST_EMPTY(&vdev->vga.region[i].quirks)) { 886c00d61d8SAlex Williamson VFIOQuirk *quirk = QLIST_FIRST(&vdev->vga.region[i].quirks); 887c00d61d8SAlex Williamson QLIST_REMOVE(quirk, next); 8888c4f2348SAlex Williamson for (j = 0; j < quirk->nr_mem; j++) { 8898c4f2348SAlex Williamson object_unparent(OBJECT(&quirk->mem[j])); 8908c4f2348SAlex Williamson } 8918c4f2348SAlex Williamson g_free(quirk->mem); 8928c4f2348SAlex Williamson g_free(quirk->data); 893c00d61d8SAlex Williamson g_free(quirk); 894c00d61d8SAlex Williamson } 895c00d61d8SAlex Williamson } 896c00d61d8SAlex Williamson } 897c00d61d8SAlex Williamson 898c00d61d8SAlex Williamson void vfio_bar_quirk_setup(VFIOPCIDevice *vdev, int nr) 899c00d61d8SAlex Williamson { 900c00d61d8SAlex Williamson vfio_probe_ati_bar4_window_quirk(vdev, nr); 901c00d61d8SAlex Williamson vfio_probe_ati_bar2_4000_quirk(vdev, nr); 902c00d61d8SAlex Williamson vfio_probe_nvidia_bar5_window_quirk(vdev, nr); 903c00d61d8SAlex Williamson vfio_probe_nvidia_bar0_88000_quirk(vdev, nr); 904c00d61d8SAlex Williamson vfio_probe_nvidia_bar0_1800_quirk(vdev, nr); 905c00d61d8SAlex Williamson vfio_probe_rtl8168_bar2_window_quirk(vdev, nr); 906c00d61d8SAlex Williamson } 907c00d61d8SAlex Williamson 908c00d61d8SAlex Williamson void vfio_bar_quirk_teardown(VFIOPCIDevice *vdev, int nr) 909c00d61d8SAlex Williamson { 910c00d61d8SAlex Williamson VFIOBAR *bar = &vdev->bars[nr]; 911c00d61d8SAlex Williamson VFIOQuirk *quirk; 9128c4f2348SAlex Williamson int i; 913c00d61d8SAlex Williamson 914c00d61d8SAlex Williamson QLIST_FOREACH(quirk, &bar->quirks, next) { 9158c4f2348SAlex Williamson for (i = 0; i < quirk->nr_mem; i++) { 9168c4f2348SAlex Williamson memory_region_del_subregion(&bar->region.mem, &quirk->mem[i]); 9178c4f2348SAlex Williamson } 918c00d61d8SAlex Williamson } 919c00d61d8SAlex Williamson } 920c00d61d8SAlex Williamson 921c00d61d8SAlex Williamson void vfio_bar_quirk_free(VFIOPCIDevice *vdev, int nr) 922c00d61d8SAlex Williamson { 923c00d61d8SAlex Williamson VFIOBAR *bar = &vdev->bars[nr]; 9248c4f2348SAlex Williamson int i; 925c00d61d8SAlex Williamson 926c00d61d8SAlex Williamson while (!QLIST_EMPTY(&bar->quirks)) { 927c00d61d8SAlex Williamson VFIOQuirk *quirk = QLIST_FIRST(&bar->quirks); 928c00d61d8SAlex Williamson QLIST_REMOVE(quirk, next); 9298c4f2348SAlex Williamson for (i = 0; i < quirk->nr_mem; i++) { 9308c4f2348SAlex Williamson object_unparent(OBJECT(&quirk->mem[i])); 9318c4f2348SAlex Williamson } 9328c4f2348SAlex Williamson g_free(quirk->mem); 9338c4f2348SAlex Williamson g_free(quirk->data); 934c00d61d8SAlex Williamson g_free(quirk); 935c00d61d8SAlex Williamson } 936c00d61d8SAlex Williamson } 937