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 /* 66*0e54f24aSAlex Williamson * Device specific region quirks (mostly backdoors to PCI config space) 67c00d61d8SAlex Williamson */ 68c00d61d8SAlex Williamson 69*0e54f24aSAlex Williamson /* 70*0e54f24aSAlex Williamson * The generic window quirks operate on an address and data register, 71*0e54f24aSAlex Williamson * vfio_generic_window_address_quirk handles the address register and 72*0e54f24aSAlex Williamson * vfio_generic_window_data_quirk handles the data register. These ops 73*0e54f24aSAlex Williamson * pass reads and writes through to hardware until a value matching the 74*0e54f24aSAlex Williamson * stored address match/mask is written. When this occurs, the data 75*0e54f24aSAlex Williamson * register access emulated PCI config space for the device rather than 76*0e54f24aSAlex Williamson * passing through accesses. This enables devices where PCI config space 77*0e54f24aSAlex Williamson * is accessible behind a window register to maintain the virtualization 78*0e54f24aSAlex Williamson * provided through vfio. 79*0e54f24aSAlex Williamson */ 80*0e54f24aSAlex Williamson typedef struct VFIOConfigWindowMatch { 81*0e54f24aSAlex Williamson uint32_t match; 82*0e54f24aSAlex Williamson uint32_t mask; 83*0e54f24aSAlex Williamson } VFIOConfigWindowMatch; 84*0e54f24aSAlex Williamson 85*0e54f24aSAlex Williamson typedef struct VFIOConfigWindowQuirk { 86*0e54f24aSAlex Williamson struct VFIOPCIDevice *vdev; 87*0e54f24aSAlex Williamson 88*0e54f24aSAlex Williamson uint32_t address_val; 89*0e54f24aSAlex Williamson 90*0e54f24aSAlex Williamson uint32_t address_offset; 91*0e54f24aSAlex Williamson uint32_t data_offset; 92*0e54f24aSAlex Williamson 93*0e54f24aSAlex Williamson bool window_enabled; 94*0e54f24aSAlex Williamson uint8_t bar; 95*0e54f24aSAlex Williamson 96*0e54f24aSAlex Williamson MemoryRegion *addr_mem; 97*0e54f24aSAlex Williamson MemoryRegion *data_mem; 98*0e54f24aSAlex Williamson 99*0e54f24aSAlex Williamson uint32_t nr_matches; 100*0e54f24aSAlex Williamson VFIOConfigWindowMatch matches[]; 101*0e54f24aSAlex Williamson } VFIOConfigWindowQuirk; 102*0e54f24aSAlex Williamson 103*0e54f24aSAlex Williamson static uint64_t vfio_generic_window_quirk_address_read(void *opaque, 104*0e54f24aSAlex Williamson hwaddr addr, 105*0e54f24aSAlex Williamson unsigned size) 106*0e54f24aSAlex Williamson { 107*0e54f24aSAlex Williamson VFIOConfigWindowQuirk *window = opaque; 108*0e54f24aSAlex Williamson VFIOPCIDevice *vdev = window->vdev; 109*0e54f24aSAlex Williamson 110*0e54f24aSAlex Williamson return vfio_region_read(&vdev->bars[window->bar].region, 111*0e54f24aSAlex Williamson addr + window->address_offset, size); 112*0e54f24aSAlex Williamson } 113*0e54f24aSAlex Williamson 114*0e54f24aSAlex Williamson static void vfio_generic_window_quirk_address_write(void *opaque, hwaddr addr, 115*0e54f24aSAlex Williamson uint64_t data, 116*0e54f24aSAlex Williamson unsigned size) 117*0e54f24aSAlex Williamson { 118*0e54f24aSAlex Williamson VFIOConfigWindowQuirk *window = opaque; 119*0e54f24aSAlex Williamson VFIOPCIDevice *vdev = window->vdev; 120*0e54f24aSAlex Williamson int i; 121*0e54f24aSAlex Williamson 122*0e54f24aSAlex Williamson window->window_enabled = false; 123*0e54f24aSAlex Williamson 124*0e54f24aSAlex Williamson vfio_region_write(&vdev->bars[window->bar].region, 125*0e54f24aSAlex Williamson addr + window->address_offset, data, size); 126*0e54f24aSAlex Williamson 127*0e54f24aSAlex Williamson for (i = 0; i < window->nr_matches; i++) { 128*0e54f24aSAlex Williamson if ((data & ~window->matches[i].mask) == window->matches[i].match) { 129*0e54f24aSAlex Williamson window->window_enabled = true; 130*0e54f24aSAlex Williamson window->address_val = data & window->matches[i].mask; 131*0e54f24aSAlex Williamson trace_vfio_quirk_generic_window_address_write(vdev->vbasedev.name, 132*0e54f24aSAlex Williamson memory_region_name(window->addr_mem), data); 133*0e54f24aSAlex Williamson break; 134*0e54f24aSAlex Williamson } 135*0e54f24aSAlex Williamson } 136*0e54f24aSAlex Williamson } 137*0e54f24aSAlex Williamson 138*0e54f24aSAlex Williamson static const MemoryRegionOps vfio_generic_window_address_quirk = { 139*0e54f24aSAlex Williamson .read = vfio_generic_window_quirk_address_read, 140*0e54f24aSAlex Williamson .write = vfio_generic_window_quirk_address_write, 141*0e54f24aSAlex Williamson .endianness = DEVICE_LITTLE_ENDIAN, 142*0e54f24aSAlex Williamson }; 143*0e54f24aSAlex Williamson 144*0e54f24aSAlex Williamson static uint64_t vfio_generic_window_quirk_data_read(void *opaque, 145*0e54f24aSAlex Williamson hwaddr addr, unsigned size) 146*0e54f24aSAlex Williamson { 147*0e54f24aSAlex Williamson VFIOConfigWindowQuirk *window = opaque; 148*0e54f24aSAlex Williamson VFIOPCIDevice *vdev = window->vdev; 149*0e54f24aSAlex Williamson uint64_t data; 150*0e54f24aSAlex Williamson 151*0e54f24aSAlex Williamson /* Always read data reg, discard if window enabled */ 152*0e54f24aSAlex Williamson data = vfio_region_read(&vdev->bars[window->bar].region, 153*0e54f24aSAlex Williamson addr + window->data_offset, size); 154*0e54f24aSAlex Williamson 155*0e54f24aSAlex Williamson if (window->window_enabled) { 156*0e54f24aSAlex Williamson data = vfio_pci_read_config(&vdev->pdev, window->address_val, size); 157*0e54f24aSAlex Williamson trace_vfio_quirk_generic_window_data_read(vdev->vbasedev.name, 158*0e54f24aSAlex Williamson memory_region_name(window->data_mem), data); 159*0e54f24aSAlex Williamson } 160*0e54f24aSAlex Williamson 161*0e54f24aSAlex Williamson return data; 162*0e54f24aSAlex Williamson } 163*0e54f24aSAlex Williamson 164*0e54f24aSAlex Williamson static void vfio_generic_window_quirk_data_write(void *opaque, hwaddr addr, 165*0e54f24aSAlex Williamson uint64_t data, unsigned size) 166*0e54f24aSAlex Williamson { 167*0e54f24aSAlex Williamson VFIOConfigWindowQuirk *window = opaque; 168*0e54f24aSAlex Williamson VFIOPCIDevice *vdev = window->vdev; 169*0e54f24aSAlex Williamson 170*0e54f24aSAlex Williamson if (window->window_enabled) { 171*0e54f24aSAlex Williamson vfio_pci_write_config(&vdev->pdev, window->address_val, data, size); 172*0e54f24aSAlex Williamson trace_vfio_quirk_generic_window_data_write(vdev->vbasedev.name, 173*0e54f24aSAlex Williamson memory_region_name(window->data_mem), data); 174*0e54f24aSAlex Williamson return; 175*0e54f24aSAlex Williamson } 176*0e54f24aSAlex Williamson 177*0e54f24aSAlex Williamson vfio_region_write(&vdev->bars[window->bar].region, 178*0e54f24aSAlex Williamson addr + window->data_offset, data, size); 179*0e54f24aSAlex Williamson } 180*0e54f24aSAlex Williamson 181*0e54f24aSAlex Williamson static const MemoryRegionOps vfio_generic_window_data_quirk = { 182*0e54f24aSAlex Williamson .read = vfio_generic_window_quirk_data_read, 183*0e54f24aSAlex Williamson .write = vfio_generic_window_quirk_data_write, 184*0e54f24aSAlex Williamson .endianness = DEVICE_LITTLE_ENDIAN, 185*0e54f24aSAlex Williamson }; 186*0e54f24aSAlex Williamson 187c00d61d8SAlex Williamson /* Is range1 fully contained within range2? */ 188c00d61d8SAlex Williamson static bool vfio_range_contained(uint64_t first1, uint64_t len1, 189c00d61d8SAlex Williamson uint64_t first2, uint64_t len2) { 190c00d61d8SAlex Williamson return (first1 >= first2 && first1 + len1 <= first2 + len2); 191c00d61d8SAlex Williamson } 192c00d61d8SAlex Williamson 193c00d61d8SAlex Williamson static bool vfio_flags_enabled(uint8_t flags, uint8_t mask) 194c00d61d8SAlex Williamson { 195c00d61d8SAlex Williamson return (mask && (flags & mask) == mask); 196c00d61d8SAlex Williamson } 197c00d61d8SAlex Williamson 198c00d61d8SAlex Williamson static uint64_t vfio_generic_window_quirk_read(void *opaque, 199c00d61d8SAlex Williamson hwaddr addr, unsigned size) 200c00d61d8SAlex Williamson { 2018c4f2348SAlex Williamson VFIOLegacyQuirk *quirk = opaque; 202c00d61d8SAlex Williamson VFIOPCIDevice *vdev = quirk->vdev; 203c00d61d8SAlex Williamson uint64_t data; 204c00d61d8SAlex Williamson 205c00d61d8SAlex Williamson if (vfio_flags_enabled(quirk->data.flags, quirk->data.read_flags) && 206c00d61d8SAlex Williamson ranges_overlap(addr, size, 207c00d61d8SAlex Williamson quirk->data.data_offset, quirk->data.data_size)) { 208c00d61d8SAlex Williamson hwaddr offset = addr - quirk->data.data_offset; 209c00d61d8SAlex Williamson 210c00d61d8SAlex Williamson if (!vfio_range_contained(addr, size, quirk->data.data_offset, 211c00d61d8SAlex Williamson quirk->data.data_size)) { 212c00d61d8SAlex Williamson hw_error("%s: window data read not fully contained: %s", 2138c4f2348SAlex Williamson __func__, memory_region_name(quirk->mem)); 214c00d61d8SAlex Williamson } 215c00d61d8SAlex Williamson 216c00d61d8SAlex Williamson data = vfio_pci_read_config(&vdev->pdev, 217c00d61d8SAlex Williamson quirk->data.address_val + offset, size); 218c00d61d8SAlex Williamson 2198c4f2348SAlex Williamson trace_vfio_generic_window_quirk_read(memory_region_name(quirk->mem), 220c00d61d8SAlex Williamson vdev->vbasedev.name, 221c00d61d8SAlex Williamson quirk->data.bar, 222c00d61d8SAlex Williamson addr, size, data); 223c00d61d8SAlex Williamson } else { 224c00d61d8SAlex Williamson data = vfio_region_read(&vdev->bars[quirk->data.bar].region, 225c00d61d8SAlex Williamson addr + quirk->data.base_offset, size); 226c00d61d8SAlex Williamson } 227c00d61d8SAlex Williamson 228c00d61d8SAlex Williamson return data; 229c00d61d8SAlex Williamson } 230c00d61d8SAlex Williamson 231c00d61d8SAlex Williamson static void vfio_generic_window_quirk_write(void *opaque, hwaddr addr, 232c00d61d8SAlex Williamson uint64_t data, unsigned size) 233c00d61d8SAlex Williamson { 2348c4f2348SAlex Williamson VFIOLegacyQuirk *quirk = opaque; 235c00d61d8SAlex Williamson VFIOPCIDevice *vdev = quirk->vdev; 236c00d61d8SAlex Williamson 237c00d61d8SAlex Williamson if (ranges_overlap(addr, size, 238c00d61d8SAlex Williamson quirk->data.address_offset, quirk->data.address_size)) { 239c00d61d8SAlex Williamson 240c00d61d8SAlex Williamson if (addr != quirk->data.address_offset) { 241c00d61d8SAlex Williamson hw_error("%s: offset write into address window: %s", 2428c4f2348SAlex Williamson __func__, memory_region_name(quirk->mem)); 243c00d61d8SAlex Williamson } 244c00d61d8SAlex Williamson 245c00d61d8SAlex Williamson if ((data & ~quirk->data.address_mask) == quirk->data.address_match) { 246c00d61d8SAlex Williamson quirk->data.flags |= quirk->data.write_flags | 247c00d61d8SAlex Williamson quirk->data.read_flags; 248c00d61d8SAlex Williamson quirk->data.address_val = data & quirk->data.address_mask; 249c00d61d8SAlex Williamson } else { 250c00d61d8SAlex Williamson quirk->data.flags &= ~(quirk->data.write_flags | 251c00d61d8SAlex Williamson quirk->data.read_flags); 252c00d61d8SAlex Williamson } 253c00d61d8SAlex Williamson } 254c00d61d8SAlex Williamson 255c00d61d8SAlex Williamson if (vfio_flags_enabled(quirk->data.flags, quirk->data.write_flags) && 256c00d61d8SAlex Williamson ranges_overlap(addr, size, 257c00d61d8SAlex Williamson quirk->data.data_offset, quirk->data.data_size)) { 258c00d61d8SAlex Williamson hwaddr offset = addr - quirk->data.data_offset; 259c00d61d8SAlex Williamson 260c00d61d8SAlex Williamson if (!vfio_range_contained(addr, size, quirk->data.data_offset, 261c00d61d8SAlex Williamson quirk->data.data_size)) { 262c00d61d8SAlex Williamson hw_error("%s: window data write not fully contained: %s", 2638c4f2348SAlex Williamson __func__, memory_region_name(quirk->mem)); 264c00d61d8SAlex Williamson } 265c00d61d8SAlex Williamson 266c00d61d8SAlex Williamson vfio_pci_write_config(&vdev->pdev, 267c00d61d8SAlex Williamson quirk->data.address_val + offset, data, size); 2688c4f2348SAlex Williamson trace_vfio_generic_window_quirk_write(memory_region_name(quirk->mem), 269c00d61d8SAlex Williamson vdev->vbasedev.name, 270c00d61d8SAlex Williamson quirk->data.bar, 271c00d61d8SAlex Williamson addr, data, size); 272c00d61d8SAlex Williamson return; 273c00d61d8SAlex Williamson } 274c00d61d8SAlex Williamson 275c00d61d8SAlex Williamson vfio_region_write(&vdev->bars[quirk->data.bar].region, 276c00d61d8SAlex Williamson addr + quirk->data.base_offset, data, size); 277c00d61d8SAlex Williamson } 278c00d61d8SAlex Williamson 279c00d61d8SAlex Williamson static const MemoryRegionOps vfio_generic_window_quirk = { 280c00d61d8SAlex Williamson .read = vfio_generic_window_quirk_read, 281c00d61d8SAlex Williamson .write = vfio_generic_window_quirk_write, 282c00d61d8SAlex Williamson .endianness = DEVICE_LITTLE_ENDIAN, 283c00d61d8SAlex Williamson }; 284c00d61d8SAlex Williamson 285c00d61d8SAlex Williamson static uint64_t vfio_generic_quirk_read(void *opaque, 286c00d61d8SAlex Williamson hwaddr addr, unsigned size) 287c00d61d8SAlex Williamson { 2888c4f2348SAlex Williamson VFIOLegacyQuirk *quirk = opaque; 289c00d61d8SAlex Williamson VFIOPCIDevice *vdev = quirk->vdev; 290c00d61d8SAlex Williamson hwaddr base = quirk->data.address_match & TARGET_PAGE_MASK; 291c00d61d8SAlex Williamson hwaddr offset = quirk->data.address_match & ~TARGET_PAGE_MASK; 292c00d61d8SAlex Williamson uint64_t data; 293c00d61d8SAlex Williamson 294c00d61d8SAlex Williamson if (vfio_flags_enabled(quirk->data.flags, quirk->data.read_flags) && 295c00d61d8SAlex Williamson ranges_overlap(addr, size, offset, quirk->data.address_mask + 1)) { 296c00d61d8SAlex Williamson if (!vfio_range_contained(addr, size, offset, 297c00d61d8SAlex Williamson quirk->data.address_mask + 1)) { 298c00d61d8SAlex Williamson hw_error("%s: read not fully contained: %s", 2998c4f2348SAlex Williamson __func__, memory_region_name(quirk->mem)); 300c00d61d8SAlex Williamson } 301c00d61d8SAlex Williamson 302c00d61d8SAlex Williamson data = vfio_pci_read_config(&vdev->pdev, addr - offset, size); 303c00d61d8SAlex Williamson 3048c4f2348SAlex Williamson trace_vfio_generic_quirk_read(memory_region_name(quirk->mem), 305c00d61d8SAlex Williamson vdev->vbasedev.name, quirk->data.bar, 306c00d61d8SAlex Williamson addr + base, size, data); 307c00d61d8SAlex Williamson } else { 308c00d61d8SAlex Williamson data = vfio_region_read(&vdev->bars[quirk->data.bar].region, 309c00d61d8SAlex Williamson addr + base, size); 310c00d61d8SAlex Williamson } 311c00d61d8SAlex Williamson 312c00d61d8SAlex Williamson return data; 313c00d61d8SAlex Williamson } 314c00d61d8SAlex Williamson 315c00d61d8SAlex Williamson static void vfio_generic_quirk_write(void *opaque, hwaddr addr, 316c00d61d8SAlex Williamson uint64_t data, unsigned size) 317c00d61d8SAlex Williamson { 3188c4f2348SAlex Williamson VFIOLegacyQuirk *quirk = opaque; 319c00d61d8SAlex Williamson VFIOPCIDevice *vdev = quirk->vdev; 320c00d61d8SAlex Williamson hwaddr base = quirk->data.address_match & TARGET_PAGE_MASK; 321c00d61d8SAlex Williamson hwaddr offset = quirk->data.address_match & ~TARGET_PAGE_MASK; 322c00d61d8SAlex Williamson 323c00d61d8SAlex Williamson if (vfio_flags_enabled(quirk->data.flags, quirk->data.write_flags) && 324c00d61d8SAlex Williamson ranges_overlap(addr, size, offset, quirk->data.address_mask + 1)) { 325c00d61d8SAlex Williamson if (!vfio_range_contained(addr, size, offset, 326c00d61d8SAlex Williamson quirk->data.address_mask + 1)) { 327c00d61d8SAlex Williamson hw_error("%s: write not fully contained: %s", 3288c4f2348SAlex Williamson __func__, memory_region_name(quirk->mem)); 329c00d61d8SAlex Williamson } 330c00d61d8SAlex Williamson 331c00d61d8SAlex Williamson vfio_pci_write_config(&vdev->pdev, addr - offset, data, size); 332c00d61d8SAlex Williamson 3338c4f2348SAlex Williamson trace_vfio_generic_quirk_write(memory_region_name(quirk->mem), 334c00d61d8SAlex Williamson vdev->vbasedev.name, quirk->data.bar, 335c00d61d8SAlex Williamson addr + base, data, size); 336c00d61d8SAlex Williamson } else { 337c00d61d8SAlex Williamson vfio_region_write(&vdev->bars[quirk->data.bar].region, 338c00d61d8SAlex Williamson addr + base, data, size); 339c00d61d8SAlex Williamson } 340c00d61d8SAlex Williamson } 341c00d61d8SAlex Williamson 342c00d61d8SAlex Williamson static const MemoryRegionOps vfio_generic_quirk = { 343c00d61d8SAlex Williamson .read = vfio_generic_quirk_read, 344c00d61d8SAlex Williamson .write = vfio_generic_quirk_write, 345c00d61d8SAlex Williamson .endianness = DEVICE_LITTLE_ENDIAN, 346c00d61d8SAlex Williamson }; 347c00d61d8SAlex Williamson 348c00d61d8SAlex Williamson #define PCI_VENDOR_ID_ATI 0x1002 349c00d61d8SAlex Williamson 350c00d61d8SAlex Williamson /* 351c00d61d8SAlex Williamson * Radeon HD cards (HD5450 & HD7850) report the upper byte of the I/O port BAR 352c00d61d8SAlex Williamson * through VGA register 0x3c3. On newer cards, the I/O port BAR is always 353c00d61d8SAlex Williamson * BAR4 (older cards like the X550 used BAR1, but we don't care to support 354c00d61d8SAlex Williamson * those). Note that on bare metal, a read of 0x3c3 doesn't always return the 355c00d61d8SAlex Williamson * I/O port BAR address. Originally this was coded to return the virtual BAR 356c00d61d8SAlex Williamson * address only if the physical register read returns the actual BAR address, 357c00d61d8SAlex Williamson * but users have reported greater success if we return the virtual address 358c00d61d8SAlex Williamson * unconditionally. 359c00d61d8SAlex Williamson */ 360c00d61d8SAlex Williamson static uint64_t vfio_ati_3c3_quirk_read(void *opaque, 361c00d61d8SAlex Williamson hwaddr addr, unsigned size) 362c00d61d8SAlex Williamson { 363b946d286SAlex Williamson VFIOPCIDevice *vdev = opaque; 364c00d61d8SAlex Williamson uint64_t data = vfio_pci_read_config(&vdev->pdev, 365b946d286SAlex Williamson PCI_BASE_ADDRESS_4 + 1, size); 366b946d286SAlex Williamson 367b946d286SAlex Williamson trace_vfio_quirk_ati_3c3_read(vdev->vbasedev.name, data); 368c00d61d8SAlex Williamson 369c00d61d8SAlex Williamson return data; 370c00d61d8SAlex Williamson } 371c00d61d8SAlex Williamson 372c00d61d8SAlex Williamson static const MemoryRegionOps vfio_ati_3c3_quirk = { 373c00d61d8SAlex Williamson .read = vfio_ati_3c3_quirk_read, 374c00d61d8SAlex Williamson .endianness = DEVICE_LITTLE_ENDIAN, 375c00d61d8SAlex Williamson }; 376c00d61d8SAlex Williamson 377c00d61d8SAlex Williamson static void vfio_vga_probe_ati_3c3_quirk(VFIOPCIDevice *vdev) 378c00d61d8SAlex Williamson { 379c00d61d8SAlex Williamson VFIOQuirk *quirk; 380c00d61d8SAlex Williamson 381c00d61d8SAlex Williamson /* 382c00d61d8SAlex Williamson * As long as the BAR is >= 256 bytes it will be aligned such that the 383c00d61d8SAlex Williamson * lower byte is always zero. Filter out anything else, if it exists. 384c00d61d8SAlex Williamson */ 385b946d286SAlex Williamson if (!vfio_pci_is(vdev, PCI_VENDOR_ID_ATI, PCI_ANY_ID) || 386b946d286SAlex Williamson !vdev->bars[4].ioport || vdev->bars[4].region.size < 256) { 387c00d61d8SAlex Williamson return; 388c00d61d8SAlex Williamson } 389c00d61d8SAlex Williamson 390c00d61d8SAlex Williamson quirk = g_malloc0(sizeof(*quirk)); 391b946d286SAlex Williamson quirk->mem = g_malloc0_n(sizeof(MemoryRegion), 1); 3928c4f2348SAlex Williamson quirk->nr_mem = 1; 393c00d61d8SAlex Williamson 394b946d286SAlex Williamson memory_region_init_io(quirk->mem, OBJECT(vdev), &vfio_ati_3c3_quirk, vdev, 395c00d61d8SAlex Williamson "vfio-ati-3c3-quirk", 1); 396c00d61d8SAlex Williamson memory_region_add_subregion(&vdev->vga.region[QEMU_PCI_VGA_IO_HI].mem, 3978c4f2348SAlex Williamson 3 /* offset 3 bytes from 0x3c0 */, quirk->mem); 398c00d61d8SAlex Williamson 399c00d61d8SAlex Williamson QLIST_INSERT_HEAD(&vdev->vga.region[QEMU_PCI_VGA_IO_HI].quirks, 400c00d61d8SAlex Williamson quirk, next); 401c00d61d8SAlex Williamson 402b946d286SAlex Williamson trace_vfio_quirk_ati_3c3_probe(vdev->vbasedev.name); 403c00d61d8SAlex Williamson } 404c00d61d8SAlex Williamson 405c00d61d8SAlex Williamson /* 406*0e54f24aSAlex Williamson * Newer ATI/AMD devices, including HD5450 and HD7850, have a mirror to PCI 407c00d61d8SAlex Williamson * config space through MMIO BAR2 at offset 0x4000. Nothing seems to access 408c00d61d8SAlex Williamson * the MMIO space directly, but a window to this space is provided through 409c00d61d8SAlex Williamson * I/O port BAR4. Offset 0x0 is the address register and offset 0x4 is the 410c00d61d8SAlex Williamson * data register. When the address is programmed to a range of 0x4000-0x4fff 411c00d61d8SAlex Williamson * PCI configuration space is available. Experimentation seems to indicate 412*0e54f24aSAlex Williamson * that read-only may be provided by hardware. 413c00d61d8SAlex Williamson */ 414*0e54f24aSAlex Williamson static void vfio_probe_ati_bar4_quirk(VFIOPCIDevice *vdev, int nr) 415c00d61d8SAlex Williamson { 416c00d61d8SAlex Williamson VFIOQuirk *quirk; 417*0e54f24aSAlex Williamson VFIOConfigWindowQuirk *window; 418c00d61d8SAlex Williamson 419*0e54f24aSAlex Williamson /* This windows doesn't seem to be used except by legacy VGA code */ 420*0e54f24aSAlex Williamson if (!vfio_pci_is(vdev, PCI_VENDOR_ID_ATI, PCI_ANY_ID) || 421*0e54f24aSAlex Williamson !vdev->has_vga || nr != 4) { 422c00d61d8SAlex Williamson return; 423c00d61d8SAlex Williamson } 424c00d61d8SAlex Williamson 425c00d61d8SAlex Williamson quirk = g_malloc0(sizeof(*quirk)); 426*0e54f24aSAlex Williamson quirk->mem = g_malloc0_n(sizeof(MemoryRegion), 2); 427*0e54f24aSAlex Williamson quirk->nr_mem = 2; 428*0e54f24aSAlex Williamson window = quirk->data = g_malloc0(sizeof(*window) + 429*0e54f24aSAlex Williamson sizeof(VFIOConfigWindowMatch)); 430*0e54f24aSAlex Williamson window->vdev = vdev; 431*0e54f24aSAlex Williamson window->address_offset = 0; 432*0e54f24aSAlex Williamson window->data_offset = 4; 433*0e54f24aSAlex Williamson window->nr_matches = 1; 434*0e54f24aSAlex Williamson window->matches[0].match = 0x4000; 435*0e54f24aSAlex Williamson window->matches[0].mask = PCIE_CONFIG_SPACE_SIZE - 1; 436*0e54f24aSAlex Williamson window->bar = nr; 437*0e54f24aSAlex Williamson window->addr_mem = &quirk->mem[0]; 438*0e54f24aSAlex Williamson window->data_mem = &quirk->mem[1]; 439c00d61d8SAlex Williamson 440*0e54f24aSAlex Williamson memory_region_init_io(window->addr_mem, OBJECT(vdev), 441*0e54f24aSAlex Williamson &vfio_generic_window_address_quirk, window, 442*0e54f24aSAlex Williamson "vfio-ati-bar4-window-address-quirk", 4); 443c00d61d8SAlex Williamson memory_region_add_subregion_overlap(&vdev->bars[nr].region.mem, 444*0e54f24aSAlex Williamson window->address_offset, 445*0e54f24aSAlex Williamson window->addr_mem, 1); 446*0e54f24aSAlex Williamson 447*0e54f24aSAlex Williamson memory_region_init_io(window->data_mem, OBJECT(vdev), 448*0e54f24aSAlex Williamson &vfio_generic_window_data_quirk, window, 449*0e54f24aSAlex Williamson "vfio-ati-bar4-window-data-quirk", 4); 450*0e54f24aSAlex Williamson memory_region_add_subregion_overlap(&vdev->bars[nr].region.mem, 451*0e54f24aSAlex Williamson window->data_offset, 452*0e54f24aSAlex Williamson window->data_mem, 1); 453c00d61d8SAlex Williamson 454c00d61d8SAlex Williamson QLIST_INSERT_HEAD(&vdev->bars[nr].quirks, quirk, next); 455c00d61d8SAlex Williamson 456*0e54f24aSAlex Williamson trace_vfio_quirk_ati_bar4_probe(vdev->vbasedev.name); 457c00d61d8SAlex Williamson } 458c00d61d8SAlex Williamson 459c00d61d8SAlex Williamson /* 460c00d61d8SAlex Williamson * Trap the BAR2 MMIO window to config space as well. 461c00d61d8SAlex Williamson */ 462c00d61d8SAlex Williamson static void vfio_probe_ati_bar2_4000_quirk(VFIOPCIDevice *vdev, int nr) 463c00d61d8SAlex Williamson { 464c00d61d8SAlex Williamson PCIDevice *pdev = &vdev->pdev; 465c00d61d8SAlex Williamson VFIOQuirk *quirk; 4668c4f2348SAlex Williamson VFIOLegacyQuirk *legacy; 467c00d61d8SAlex Williamson 468c00d61d8SAlex Williamson /* Only enable on newer devices where BAR2 is 64bit */ 469c00d61d8SAlex Williamson if (!vdev->has_vga || nr != 2 || !vdev->bars[2].mem64 || 470c00d61d8SAlex Williamson pci_get_word(pdev->config + PCI_VENDOR_ID) != PCI_VENDOR_ID_ATI) { 471c00d61d8SAlex Williamson return; 472c00d61d8SAlex Williamson } 473c00d61d8SAlex Williamson 474c00d61d8SAlex Williamson quirk = g_malloc0(sizeof(*quirk)); 4758c4f2348SAlex Williamson quirk->data = legacy = g_malloc0(sizeof(*legacy)); 4768c4f2348SAlex Williamson quirk->mem = legacy->mem = g_malloc0_n(sizeof(MemoryRegion), 1); 4778c4f2348SAlex Williamson quirk->nr_mem = 1; 4788c4f2348SAlex Williamson legacy->vdev = vdev; 4798c4f2348SAlex Williamson legacy->data.flags = legacy->data.read_flags = legacy->data.write_flags = 1; 4808c4f2348SAlex Williamson legacy->data.address_match = 0x4000; 4818c4f2348SAlex Williamson legacy->data.address_mask = PCIE_CONFIG_SPACE_SIZE - 1; 4828c4f2348SAlex Williamson legacy->data.bar = nr; 483c00d61d8SAlex Williamson 4848c4f2348SAlex Williamson memory_region_init_io(quirk->mem, OBJECT(vdev), &vfio_generic_quirk, legacy, 485c00d61d8SAlex Williamson "vfio-ati-bar2-4000-quirk", 4868c4f2348SAlex Williamson TARGET_PAGE_ALIGN(legacy->data.address_mask + 1)); 487c00d61d8SAlex Williamson memory_region_add_subregion_overlap(&vdev->bars[nr].region.mem, 4888c4f2348SAlex Williamson legacy->data.address_match & TARGET_PAGE_MASK, 4898c4f2348SAlex Williamson quirk->mem, 1); 490c00d61d8SAlex Williamson 491c00d61d8SAlex Williamson QLIST_INSERT_HEAD(&vdev->bars[nr].quirks, quirk, next); 492c00d61d8SAlex Williamson 493c00d61d8SAlex Williamson trace_vfio_probe_ati_bar2_4000_quirk(vdev->vbasedev.name); 494c00d61d8SAlex Williamson } 495c00d61d8SAlex Williamson 496c00d61d8SAlex Williamson /* 497c00d61d8SAlex Williamson * Older ATI/AMD cards like the X550 have a similar window to that above. 498c00d61d8SAlex Williamson * I/O port BAR1 provides a window to a mirror of PCI config space located 499c00d61d8SAlex Williamson * in BAR2 at offset 0xf00. We don't care to support such older cards, but 500c00d61d8SAlex Williamson * note it for future reference. 501c00d61d8SAlex Williamson */ 502c00d61d8SAlex Williamson 503c00d61d8SAlex Williamson #define PCI_VENDOR_ID_NVIDIA 0x10de 504c00d61d8SAlex Williamson 505c00d61d8SAlex Williamson /* 506c00d61d8SAlex Williamson * Nvidia has several different methods to get to config space, the 507c00d61d8SAlex Williamson * nouveu project has several of these documented here: 508c00d61d8SAlex Williamson * https://github.com/pathscale/envytools/tree/master/hwdocs 509c00d61d8SAlex Williamson * 510c00d61d8SAlex Williamson * The first quirk is actually not documented in envytools and is found 511c00d61d8SAlex Williamson * on 10de:01d1 (NVIDIA Corporation G72 [GeForce 7300 LE]). This is an 512c00d61d8SAlex Williamson * NV46 chipset. The backdoor uses the legacy VGA I/O ports to access 513c00d61d8SAlex Williamson * the mirror of PCI config space found at BAR0 offset 0x1800. The access 514c00d61d8SAlex Williamson * sequence first writes 0x338 to I/O port 0x3d4. The target offset is 515c00d61d8SAlex Williamson * then written to 0x3d0. Finally 0x538 is written for a read and 0x738 516c00d61d8SAlex Williamson * is written for a write to 0x3d4. The BAR0 offset is then accessible 517c00d61d8SAlex Williamson * through 0x3d0. This quirk doesn't seem to be necessary on newer cards 518c00d61d8SAlex Williamson * that use the I/O port BAR5 window but it doesn't hurt to leave it. 519c00d61d8SAlex Williamson */ 5206029a424SAlex Williamson typedef enum {NONE = 0, SELECT, WINDOW, READ, WRITE} VFIONvidia3d0State; 5216029a424SAlex Williamson static const char *nv3d0_states[] = { "NONE", "SELECT", 5226029a424SAlex Williamson "WINDOW", "READ", "WRITE" }; 5236029a424SAlex Williamson 5246029a424SAlex Williamson typedef struct VFIONvidia3d0Quirk { 5256029a424SAlex Williamson VFIOPCIDevice *vdev; 5266029a424SAlex Williamson VFIONvidia3d0State state; 5276029a424SAlex Williamson uint32_t offset; 5286029a424SAlex Williamson } VFIONvidia3d0Quirk; 5296029a424SAlex Williamson 5306029a424SAlex Williamson static uint64_t vfio_nvidia_3d4_quirk_read(void *opaque, 5316029a424SAlex Williamson hwaddr addr, unsigned size) 5326029a424SAlex Williamson { 5336029a424SAlex Williamson VFIONvidia3d0Quirk *quirk = opaque; 5346029a424SAlex Williamson VFIOPCIDevice *vdev = quirk->vdev; 5356029a424SAlex Williamson 5366029a424SAlex Williamson quirk->state = NONE; 5376029a424SAlex Williamson 5386029a424SAlex Williamson return vfio_vga_read(&vdev->vga.region[QEMU_PCI_VGA_IO_HI], 5396029a424SAlex Williamson addr + 0x14, size); 5406029a424SAlex Williamson } 5416029a424SAlex Williamson 5426029a424SAlex Williamson static void vfio_nvidia_3d4_quirk_write(void *opaque, hwaddr addr, 5436029a424SAlex Williamson uint64_t data, unsigned size) 5446029a424SAlex Williamson { 5456029a424SAlex Williamson VFIONvidia3d0Quirk *quirk = opaque; 5466029a424SAlex Williamson VFIOPCIDevice *vdev = quirk->vdev; 5476029a424SAlex Williamson VFIONvidia3d0State old_state = quirk->state; 5486029a424SAlex Williamson 5496029a424SAlex Williamson quirk->state = NONE; 5506029a424SAlex Williamson 5516029a424SAlex Williamson switch (data) { 5526029a424SAlex Williamson case 0x338: 5536029a424SAlex Williamson if (old_state == NONE) { 5546029a424SAlex Williamson quirk->state = SELECT; 5556029a424SAlex Williamson trace_vfio_quirk_nvidia_3d0_state(vdev->vbasedev.name, 5566029a424SAlex Williamson nv3d0_states[quirk->state]); 5576029a424SAlex Williamson } 5586029a424SAlex Williamson break; 5596029a424SAlex Williamson case 0x538: 5606029a424SAlex Williamson if (old_state == WINDOW) { 5616029a424SAlex Williamson quirk->state = READ; 5626029a424SAlex Williamson trace_vfio_quirk_nvidia_3d0_state(vdev->vbasedev.name, 5636029a424SAlex Williamson nv3d0_states[quirk->state]); 5646029a424SAlex Williamson } 5656029a424SAlex Williamson break; 5666029a424SAlex Williamson case 0x738: 5676029a424SAlex Williamson if (old_state == WINDOW) { 5686029a424SAlex Williamson quirk->state = WRITE; 5696029a424SAlex Williamson trace_vfio_quirk_nvidia_3d0_state(vdev->vbasedev.name, 5706029a424SAlex Williamson nv3d0_states[quirk->state]); 5716029a424SAlex Williamson } 5726029a424SAlex Williamson break; 5736029a424SAlex Williamson } 5746029a424SAlex Williamson 5756029a424SAlex Williamson vfio_vga_write(&vdev->vga.region[QEMU_PCI_VGA_IO_HI], 5766029a424SAlex Williamson addr + 0x14, data, size); 5776029a424SAlex Williamson } 5786029a424SAlex Williamson 5796029a424SAlex Williamson static const MemoryRegionOps vfio_nvidia_3d4_quirk = { 5806029a424SAlex Williamson .read = vfio_nvidia_3d4_quirk_read, 5816029a424SAlex Williamson .write = vfio_nvidia_3d4_quirk_write, 5826029a424SAlex Williamson .endianness = DEVICE_LITTLE_ENDIAN, 583c00d61d8SAlex Williamson }; 584c00d61d8SAlex Williamson 585c00d61d8SAlex Williamson static uint64_t vfio_nvidia_3d0_quirk_read(void *opaque, 586c00d61d8SAlex Williamson hwaddr addr, unsigned size) 587c00d61d8SAlex Williamson { 5886029a424SAlex Williamson VFIONvidia3d0Quirk *quirk = opaque; 589c00d61d8SAlex Williamson VFIOPCIDevice *vdev = quirk->vdev; 5906029a424SAlex Williamson VFIONvidia3d0State old_state = quirk->state; 591c00d61d8SAlex Williamson uint64_t data = vfio_vga_read(&vdev->vga.region[QEMU_PCI_VGA_IO_HI], 5926029a424SAlex Williamson addr + 0x10, size); 593c00d61d8SAlex Williamson 5946029a424SAlex Williamson quirk->state = NONE; 5956029a424SAlex Williamson 5966029a424SAlex Williamson if (old_state == READ && 5976029a424SAlex Williamson (quirk->offset & ~(PCI_CONFIG_SPACE_SIZE - 1)) == 0x1800) { 5986029a424SAlex Williamson uint8_t offset = quirk->offset & (PCI_CONFIG_SPACE_SIZE - 1); 5996029a424SAlex Williamson 6006029a424SAlex Williamson data = vfio_pci_read_config(&vdev->pdev, offset, size); 6016029a424SAlex Williamson trace_vfio_quirk_nvidia_3d0_read(vdev->vbasedev.name, 6026029a424SAlex Williamson offset, size, data); 603c00d61d8SAlex Williamson } 604c00d61d8SAlex Williamson 605c00d61d8SAlex Williamson return data; 606c00d61d8SAlex Williamson } 607c00d61d8SAlex Williamson 608c00d61d8SAlex Williamson static void vfio_nvidia_3d0_quirk_write(void *opaque, hwaddr addr, 609c00d61d8SAlex Williamson uint64_t data, unsigned size) 610c00d61d8SAlex Williamson { 6116029a424SAlex Williamson VFIONvidia3d0Quirk *quirk = opaque; 612c00d61d8SAlex Williamson VFIOPCIDevice *vdev = quirk->vdev; 6136029a424SAlex Williamson VFIONvidia3d0State old_state = quirk->state; 614c00d61d8SAlex Williamson 6156029a424SAlex Williamson quirk->state = NONE; 6166029a424SAlex Williamson 6176029a424SAlex Williamson if (old_state == SELECT) { 6186029a424SAlex Williamson quirk->offset = (uint32_t)data; 6196029a424SAlex Williamson quirk->state = WINDOW; 6206029a424SAlex Williamson trace_vfio_quirk_nvidia_3d0_state(vdev->vbasedev.name, 6216029a424SAlex Williamson nv3d0_states[quirk->state]); 6226029a424SAlex Williamson } else if (old_state == WRITE) { 6236029a424SAlex Williamson if ((quirk->offset & ~(PCI_CONFIG_SPACE_SIZE - 1)) == 0x1800) { 6246029a424SAlex Williamson uint8_t offset = quirk->offset & (PCI_CONFIG_SPACE_SIZE - 1); 6256029a424SAlex Williamson 6266029a424SAlex Williamson vfio_pci_write_config(&vdev->pdev, offset, data, size); 6276029a424SAlex Williamson trace_vfio_quirk_nvidia_3d0_write(vdev->vbasedev.name, 6286029a424SAlex Williamson offset, data, size); 629c00d61d8SAlex Williamson return; 630c00d61d8SAlex Williamson } 631c00d61d8SAlex Williamson } 632c00d61d8SAlex Williamson 633c00d61d8SAlex Williamson vfio_vga_write(&vdev->vga.region[QEMU_PCI_VGA_IO_HI], 6346029a424SAlex Williamson addr + 0x10, data, size); 635c00d61d8SAlex Williamson } 636c00d61d8SAlex Williamson 637c00d61d8SAlex Williamson static const MemoryRegionOps vfio_nvidia_3d0_quirk = { 638c00d61d8SAlex Williamson .read = vfio_nvidia_3d0_quirk_read, 639c00d61d8SAlex Williamson .write = vfio_nvidia_3d0_quirk_write, 640c00d61d8SAlex Williamson .endianness = DEVICE_LITTLE_ENDIAN, 641c00d61d8SAlex Williamson }; 642c00d61d8SAlex Williamson 643c00d61d8SAlex Williamson static void vfio_vga_probe_nvidia_3d0_quirk(VFIOPCIDevice *vdev) 644c00d61d8SAlex Williamson { 645c00d61d8SAlex Williamson VFIOQuirk *quirk; 6466029a424SAlex Williamson VFIONvidia3d0Quirk *data; 647c00d61d8SAlex Williamson 6486029a424SAlex Williamson if (!vfio_pci_is(vdev, PCI_VENDOR_ID_NVIDIA, PCI_ANY_ID) || 649c00d61d8SAlex Williamson !vdev->bars[1].region.size) { 650c00d61d8SAlex Williamson return; 651c00d61d8SAlex Williamson } 652c00d61d8SAlex Williamson 653c00d61d8SAlex Williamson quirk = g_malloc0(sizeof(*quirk)); 6546029a424SAlex Williamson quirk->data = data = g_malloc0(sizeof(*data)); 6556029a424SAlex Williamson quirk->mem = g_malloc0_n(sizeof(MemoryRegion), 2); 6566029a424SAlex Williamson quirk->nr_mem = 2; 6576029a424SAlex Williamson data->vdev = vdev; 658c00d61d8SAlex Williamson 6596029a424SAlex Williamson memory_region_init_io(&quirk->mem[0], OBJECT(vdev), &vfio_nvidia_3d4_quirk, 6606029a424SAlex Williamson data, "vfio-nvidia-3d4-quirk", 2); 661c00d61d8SAlex Williamson memory_region_add_subregion(&vdev->vga.region[QEMU_PCI_VGA_IO_HI].mem, 6626029a424SAlex Williamson 0x14 /* 0x3c0 + 0x14 */, &quirk->mem[0]); 6636029a424SAlex Williamson 6646029a424SAlex Williamson memory_region_init_io(&quirk->mem[1], OBJECT(vdev), &vfio_nvidia_3d0_quirk, 6656029a424SAlex Williamson data, "vfio-nvidia-3d0-quirk", 2); 6666029a424SAlex Williamson memory_region_add_subregion(&vdev->vga.region[QEMU_PCI_VGA_IO_HI].mem, 6676029a424SAlex Williamson 0x10 /* 0x3c0 + 0x10 */, &quirk->mem[1]); 668c00d61d8SAlex Williamson 669c00d61d8SAlex Williamson QLIST_INSERT_HEAD(&vdev->vga.region[QEMU_PCI_VGA_IO_HI].quirks, 670c00d61d8SAlex Williamson quirk, next); 671c00d61d8SAlex Williamson 6726029a424SAlex Williamson trace_vfio_quirk_nvidia_3d0_probe(vdev->vbasedev.name); 673c00d61d8SAlex Williamson } 674c00d61d8SAlex Williamson 675c00d61d8SAlex Williamson /* 676c00d61d8SAlex Williamson * The second quirk is documented in envytools. The I/O port BAR5 is just 677c00d61d8SAlex Williamson * a set of address/data ports to the MMIO BARs. The BAR we care about is 678c00d61d8SAlex Williamson * again BAR0. This backdoor is apparently a bit newer than the one above 679c00d61d8SAlex Williamson * so we need to not only trap 256 bytes @0x1800, but all of PCI config 680c00d61d8SAlex Williamson * space, including extended space is available at the 4k @0x88000. 681c00d61d8SAlex Williamson */ 682*0e54f24aSAlex Williamson typedef struct VFIONvidiaBAR5Quirk { 683*0e54f24aSAlex Williamson uint32_t master; 684*0e54f24aSAlex Williamson uint32_t enable; 685*0e54f24aSAlex Williamson MemoryRegion *addr_mem; 686*0e54f24aSAlex Williamson MemoryRegion *data_mem; 687*0e54f24aSAlex Williamson bool enabled; 688*0e54f24aSAlex Williamson VFIOConfigWindowQuirk window; /* last for match data */ 689*0e54f24aSAlex Williamson } VFIONvidiaBAR5Quirk; 690c00d61d8SAlex Williamson 691*0e54f24aSAlex Williamson static void vfio_nvidia_bar5_enable(VFIONvidiaBAR5Quirk *bar5) 692*0e54f24aSAlex Williamson { 693*0e54f24aSAlex Williamson VFIOPCIDevice *vdev = bar5->window.vdev; 694*0e54f24aSAlex Williamson 695*0e54f24aSAlex Williamson if (((bar5->master & bar5->enable) & 0x1) == bar5->enabled) { 696*0e54f24aSAlex Williamson return; 697*0e54f24aSAlex Williamson } 698*0e54f24aSAlex Williamson 699*0e54f24aSAlex Williamson bar5->enabled = !bar5->enabled; 700*0e54f24aSAlex Williamson trace_vfio_quirk_nvidia_bar5_state(vdev->vbasedev.name, 701*0e54f24aSAlex Williamson bar5->enabled ? "Enable" : "Disable"); 702*0e54f24aSAlex Williamson memory_region_set_enabled(bar5->addr_mem, bar5->enabled); 703*0e54f24aSAlex Williamson memory_region_set_enabled(bar5->data_mem, bar5->enabled); 704*0e54f24aSAlex Williamson } 705*0e54f24aSAlex Williamson 706*0e54f24aSAlex Williamson static uint64_t vfio_nvidia_bar5_quirk_master_read(void *opaque, 707*0e54f24aSAlex Williamson hwaddr addr, unsigned size) 708*0e54f24aSAlex Williamson { 709*0e54f24aSAlex Williamson VFIONvidiaBAR5Quirk *bar5 = opaque; 710*0e54f24aSAlex Williamson VFIOPCIDevice *vdev = bar5->window.vdev; 711*0e54f24aSAlex Williamson 712*0e54f24aSAlex Williamson return vfio_region_read(&vdev->bars[5].region, addr, size); 713*0e54f24aSAlex Williamson } 714*0e54f24aSAlex Williamson 715*0e54f24aSAlex Williamson static void vfio_nvidia_bar5_quirk_master_write(void *opaque, hwaddr addr, 716c00d61d8SAlex Williamson uint64_t data, unsigned size) 717c00d61d8SAlex Williamson { 718*0e54f24aSAlex Williamson VFIONvidiaBAR5Quirk *bar5 = opaque; 719*0e54f24aSAlex Williamson VFIOPCIDevice *vdev = bar5->window.vdev; 720c00d61d8SAlex Williamson 721*0e54f24aSAlex Williamson vfio_region_write(&vdev->bars[5].region, addr, data, size); 722*0e54f24aSAlex Williamson 723*0e54f24aSAlex Williamson bar5->master = data; 724*0e54f24aSAlex Williamson vfio_nvidia_bar5_enable(bar5); 725c00d61d8SAlex Williamson } 726c00d61d8SAlex Williamson 727*0e54f24aSAlex Williamson static const MemoryRegionOps vfio_nvidia_bar5_quirk_master = { 728*0e54f24aSAlex Williamson .read = vfio_nvidia_bar5_quirk_master_read, 729*0e54f24aSAlex Williamson .write = vfio_nvidia_bar5_quirk_master_write, 730c00d61d8SAlex Williamson .endianness = DEVICE_LITTLE_ENDIAN, 731c00d61d8SAlex Williamson }; 732c00d61d8SAlex Williamson 733*0e54f24aSAlex Williamson static uint64_t vfio_nvidia_bar5_quirk_enable_read(void *opaque, 734*0e54f24aSAlex Williamson hwaddr addr, unsigned size) 735c00d61d8SAlex Williamson { 736*0e54f24aSAlex Williamson VFIONvidiaBAR5Quirk *bar5 = opaque; 737*0e54f24aSAlex Williamson VFIOPCIDevice *vdev = bar5->window.vdev; 738c00d61d8SAlex Williamson 739*0e54f24aSAlex Williamson return vfio_region_read(&vdev->bars[5].region, addr + 4, size); 740*0e54f24aSAlex Williamson } 741*0e54f24aSAlex Williamson 742*0e54f24aSAlex Williamson static void vfio_nvidia_bar5_quirk_enable_write(void *opaque, hwaddr addr, 743*0e54f24aSAlex Williamson uint64_t data, unsigned size) 744*0e54f24aSAlex Williamson { 745*0e54f24aSAlex Williamson VFIONvidiaBAR5Quirk *bar5 = opaque; 746*0e54f24aSAlex Williamson VFIOPCIDevice *vdev = bar5->window.vdev; 747*0e54f24aSAlex Williamson 748*0e54f24aSAlex Williamson vfio_region_write(&vdev->bars[5].region, addr + 4, data, size); 749*0e54f24aSAlex Williamson 750*0e54f24aSAlex Williamson bar5->enable = data; 751*0e54f24aSAlex Williamson vfio_nvidia_bar5_enable(bar5); 752*0e54f24aSAlex Williamson } 753*0e54f24aSAlex Williamson 754*0e54f24aSAlex Williamson static const MemoryRegionOps vfio_nvidia_bar5_quirk_enable = { 755*0e54f24aSAlex Williamson .read = vfio_nvidia_bar5_quirk_enable_read, 756*0e54f24aSAlex Williamson .write = vfio_nvidia_bar5_quirk_enable_write, 757*0e54f24aSAlex Williamson .endianness = DEVICE_LITTLE_ENDIAN, 758*0e54f24aSAlex Williamson }; 759*0e54f24aSAlex Williamson 760*0e54f24aSAlex Williamson static void vfio_probe_nvidia_bar5_quirk(VFIOPCIDevice *vdev, int nr) 761*0e54f24aSAlex Williamson { 762*0e54f24aSAlex Williamson VFIOQuirk *quirk; 763*0e54f24aSAlex Williamson VFIONvidiaBAR5Quirk *bar5; 764*0e54f24aSAlex Williamson VFIOConfigWindowQuirk *window; 765*0e54f24aSAlex Williamson 766*0e54f24aSAlex Williamson if (!vfio_pci_is(vdev, PCI_VENDOR_ID_NVIDIA, PCI_ANY_ID) || 767*0e54f24aSAlex Williamson !vdev->has_vga || nr != 5) { 768c00d61d8SAlex Williamson return; 769c00d61d8SAlex Williamson } 770c00d61d8SAlex Williamson 771c00d61d8SAlex Williamson quirk = g_malloc0(sizeof(*quirk)); 772*0e54f24aSAlex Williamson quirk->mem = g_malloc0_n(sizeof(MemoryRegion), 4); 773*0e54f24aSAlex Williamson quirk->nr_mem = 4; 774*0e54f24aSAlex Williamson bar5 = quirk->data = g_malloc0(sizeof(*bar5) + 775*0e54f24aSAlex Williamson (sizeof(VFIOConfigWindowMatch) * 2)); 776*0e54f24aSAlex Williamson window = &bar5->window; 777c00d61d8SAlex Williamson 778*0e54f24aSAlex Williamson window->vdev = vdev; 779*0e54f24aSAlex Williamson window->address_offset = 0x8; 780*0e54f24aSAlex Williamson window->data_offset = 0xc; 781*0e54f24aSAlex Williamson window->nr_matches = 2; 782*0e54f24aSAlex Williamson window->matches[0].match = 0x1800; 783*0e54f24aSAlex Williamson window->matches[0].mask = PCI_CONFIG_SPACE_SIZE - 1; 784*0e54f24aSAlex Williamson window->matches[1].match = 0x88000; 785*0e54f24aSAlex Williamson window->matches[1].mask = PCIE_CONFIG_SPACE_SIZE - 1; 786*0e54f24aSAlex Williamson window->bar = nr; 787*0e54f24aSAlex Williamson window->addr_mem = bar5->addr_mem = &quirk->mem[0]; 788*0e54f24aSAlex Williamson window->data_mem = bar5->data_mem = &quirk->mem[1]; 789*0e54f24aSAlex Williamson 790*0e54f24aSAlex Williamson memory_region_init_io(window->addr_mem, OBJECT(vdev), 791*0e54f24aSAlex Williamson &vfio_generic_window_address_quirk, window, 792*0e54f24aSAlex Williamson "vfio-nvidia-bar5-window-address-quirk", 4); 793c00d61d8SAlex Williamson memory_region_add_subregion_overlap(&vdev->bars[nr].region.mem, 794*0e54f24aSAlex Williamson window->address_offset, 795*0e54f24aSAlex Williamson window->addr_mem, 1); 796*0e54f24aSAlex Williamson memory_region_set_enabled(window->addr_mem, false); 797*0e54f24aSAlex Williamson 798*0e54f24aSAlex Williamson memory_region_init_io(window->data_mem, OBJECT(vdev), 799*0e54f24aSAlex Williamson &vfio_generic_window_data_quirk, window, 800*0e54f24aSAlex Williamson "vfio-nvidia-bar5-window-data-quirk", 4); 801*0e54f24aSAlex Williamson memory_region_add_subregion_overlap(&vdev->bars[nr].region.mem, 802*0e54f24aSAlex Williamson window->data_offset, 803*0e54f24aSAlex Williamson window->data_mem, 1); 804*0e54f24aSAlex Williamson memory_region_set_enabled(window->data_mem, false); 805*0e54f24aSAlex Williamson 806*0e54f24aSAlex Williamson memory_region_init_io(&quirk->mem[2], OBJECT(vdev), 807*0e54f24aSAlex Williamson &vfio_nvidia_bar5_quirk_master, bar5, 808*0e54f24aSAlex Williamson "vfio-nvidia-bar5-master-quirk", 4); 809*0e54f24aSAlex Williamson memory_region_add_subregion_overlap(&vdev->bars[nr].region.mem, 810*0e54f24aSAlex Williamson 0, &quirk->mem[2], 1); 811*0e54f24aSAlex Williamson 812*0e54f24aSAlex Williamson memory_region_init_io(&quirk->mem[3], OBJECT(vdev), 813*0e54f24aSAlex Williamson &vfio_nvidia_bar5_quirk_enable, bar5, 814*0e54f24aSAlex Williamson "vfio-nvidia-bar5-enable-quirk", 4); 815*0e54f24aSAlex Williamson memory_region_add_subregion_overlap(&vdev->bars[nr].region.mem, 816*0e54f24aSAlex Williamson 4, &quirk->mem[3], 1); 817c00d61d8SAlex Williamson 818c00d61d8SAlex Williamson QLIST_INSERT_HEAD(&vdev->bars[nr].quirks, quirk, next); 819c00d61d8SAlex Williamson 820*0e54f24aSAlex Williamson trace_vfio_quirk_nvidia_bar5_probe(vdev->vbasedev.name); 821c00d61d8SAlex Williamson } 822c00d61d8SAlex Williamson 823c00d61d8SAlex Williamson static void vfio_nvidia_88000_quirk_write(void *opaque, hwaddr addr, 824c00d61d8SAlex Williamson uint64_t data, unsigned size) 825c00d61d8SAlex Williamson { 8268c4f2348SAlex Williamson VFIOLegacyQuirk *quirk = opaque; 827c00d61d8SAlex Williamson VFIOPCIDevice *vdev = quirk->vdev; 828c00d61d8SAlex Williamson PCIDevice *pdev = &vdev->pdev; 829c00d61d8SAlex Williamson hwaddr base = quirk->data.address_match & TARGET_PAGE_MASK; 830c00d61d8SAlex Williamson 831c00d61d8SAlex Williamson vfio_generic_quirk_write(opaque, addr, data, size); 832c00d61d8SAlex Williamson 833c00d61d8SAlex Williamson /* 834c00d61d8SAlex Williamson * Nvidia seems to acknowledge MSI interrupts by writing 0xff to the 835c00d61d8SAlex Williamson * MSI capability ID register. Both the ID and next register are 836c00d61d8SAlex Williamson * read-only, so we allow writes covering either of those to real hw. 837c00d61d8SAlex Williamson * NB - only fixed for the 0x88000 MMIO window. 838c00d61d8SAlex Williamson */ 839c00d61d8SAlex Williamson if ((pdev->cap_present & QEMU_PCI_CAP_MSI) && 840c00d61d8SAlex Williamson vfio_range_contained(addr, size, pdev->msi_cap, PCI_MSI_FLAGS)) { 841c00d61d8SAlex Williamson vfio_region_write(&vdev->bars[quirk->data.bar].region, 842c00d61d8SAlex Williamson addr + base, data, size); 843c00d61d8SAlex Williamson } 844c00d61d8SAlex Williamson } 845c00d61d8SAlex Williamson 846c00d61d8SAlex Williamson static const MemoryRegionOps vfio_nvidia_88000_quirk = { 847c00d61d8SAlex Williamson .read = vfio_generic_quirk_read, 848c00d61d8SAlex Williamson .write = vfio_nvidia_88000_quirk_write, 849c00d61d8SAlex Williamson .endianness = DEVICE_LITTLE_ENDIAN, 850c00d61d8SAlex Williamson }; 851c00d61d8SAlex Williamson 852c00d61d8SAlex Williamson /* 853c00d61d8SAlex Williamson * Finally, BAR0 itself. We want to redirect any accesses to either 854c00d61d8SAlex Williamson * 0x1800 or 0x88000 through the PCI config space access functions. 855c00d61d8SAlex Williamson * 856c00d61d8SAlex Williamson * NB - quirk at a page granularity or else they don't seem to work when 857c00d61d8SAlex Williamson * BARs are mmap'd 858c00d61d8SAlex Williamson * 859c00d61d8SAlex Williamson * Here's offset 0x88000... 860c00d61d8SAlex Williamson */ 861c00d61d8SAlex Williamson static void vfio_probe_nvidia_bar0_88000_quirk(VFIOPCIDevice *vdev, int nr) 862c00d61d8SAlex Williamson { 863c00d61d8SAlex Williamson PCIDevice *pdev = &vdev->pdev; 864c00d61d8SAlex Williamson VFIOQuirk *quirk; 8658c4f2348SAlex Williamson VFIOLegacyQuirk *legacy; 866c00d61d8SAlex Williamson uint16_t vendor, class; 867c00d61d8SAlex Williamson 868c00d61d8SAlex Williamson vendor = pci_get_word(pdev->config + PCI_VENDOR_ID); 869c00d61d8SAlex Williamson class = pci_get_word(pdev->config + PCI_CLASS_DEVICE); 870c00d61d8SAlex Williamson 871c00d61d8SAlex Williamson if (nr != 0 || vendor != PCI_VENDOR_ID_NVIDIA || 872c00d61d8SAlex Williamson class != PCI_CLASS_DISPLAY_VGA) { 873c00d61d8SAlex Williamson return; 874c00d61d8SAlex Williamson } 875c00d61d8SAlex Williamson 876c00d61d8SAlex Williamson quirk = g_malloc0(sizeof(*quirk)); 8778c4f2348SAlex Williamson quirk->data = legacy = g_malloc0(sizeof(*legacy)); 8788c4f2348SAlex Williamson quirk->mem = legacy->mem = g_malloc0_n(sizeof(MemoryRegion), 1); 8798c4f2348SAlex Williamson quirk->nr_mem = 1; 8808c4f2348SAlex Williamson legacy->vdev = vdev; 8818c4f2348SAlex Williamson legacy->data.flags = legacy->data.read_flags = legacy->data.write_flags = 1; 8828c4f2348SAlex Williamson legacy->data.address_match = 0x88000; 8838c4f2348SAlex Williamson legacy->data.address_mask = PCIE_CONFIG_SPACE_SIZE - 1; 8848c4f2348SAlex Williamson legacy->data.bar = nr; 885c00d61d8SAlex Williamson 8868c4f2348SAlex Williamson memory_region_init_io(quirk->mem, OBJECT(vdev), &vfio_nvidia_88000_quirk, 8878c4f2348SAlex Williamson legacy, "vfio-nvidia-bar0-88000-quirk", 8888c4f2348SAlex Williamson TARGET_PAGE_ALIGN(legacy->data.address_mask + 1)); 889c00d61d8SAlex Williamson memory_region_add_subregion_overlap(&vdev->bars[nr].region.mem, 8908c4f2348SAlex Williamson legacy->data.address_match & TARGET_PAGE_MASK, 8918c4f2348SAlex Williamson quirk->mem, 1); 892c00d61d8SAlex Williamson 893c00d61d8SAlex Williamson QLIST_INSERT_HEAD(&vdev->bars[nr].quirks, quirk, next); 894c00d61d8SAlex Williamson 895c00d61d8SAlex Williamson trace_vfio_probe_nvidia_bar0_88000_quirk(vdev->vbasedev.name); 896c00d61d8SAlex Williamson } 897c00d61d8SAlex Williamson 898c00d61d8SAlex Williamson /* 899c00d61d8SAlex Williamson * And here's the same for BAR0 offset 0x1800... 900c00d61d8SAlex Williamson */ 901c00d61d8SAlex Williamson static void vfio_probe_nvidia_bar0_1800_quirk(VFIOPCIDevice *vdev, int nr) 902c00d61d8SAlex Williamson { 903c00d61d8SAlex Williamson PCIDevice *pdev = &vdev->pdev; 904c00d61d8SAlex Williamson VFIOQuirk *quirk; 9058c4f2348SAlex Williamson VFIOLegacyQuirk *legacy; 906c00d61d8SAlex Williamson 907c00d61d8SAlex Williamson if (!vdev->has_vga || nr != 0 || 908c00d61d8SAlex Williamson pci_get_word(pdev->config + PCI_VENDOR_ID) != PCI_VENDOR_ID_NVIDIA) { 909c00d61d8SAlex Williamson return; 910c00d61d8SAlex Williamson } 911c00d61d8SAlex Williamson 912c00d61d8SAlex Williamson /* Log the chipset ID */ 913c00d61d8SAlex Williamson trace_vfio_probe_nvidia_bar0_1800_quirk_id( 914c00d61d8SAlex Williamson (unsigned int)(vfio_region_read(&vdev->bars[0].region, 0, 4) >> 20) 915c00d61d8SAlex Williamson & 0xff); 916c00d61d8SAlex Williamson 917c00d61d8SAlex Williamson quirk = g_malloc0(sizeof(*quirk)); 9188c4f2348SAlex Williamson quirk->data = legacy = g_malloc0(sizeof(*legacy)); 9198c4f2348SAlex Williamson quirk->mem = legacy->mem = g_malloc0_n(sizeof(MemoryRegion), 1); 9208c4f2348SAlex Williamson quirk->nr_mem = 1; 9218c4f2348SAlex Williamson legacy->vdev = vdev; 9228c4f2348SAlex Williamson legacy->data.flags = legacy->data.read_flags = legacy->data.write_flags = 1; 9238c4f2348SAlex Williamson legacy->data.address_match = 0x1800; 9248c4f2348SAlex Williamson legacy->data.address_mask = PCI_CONFIG_SPACE_SIZE - 1; 9258c4f2348SAlex Williamson legacy->data.bar = nr; 926c00d61d8SAlex Williamson 9278c4f2348SAlex Williamson memory_region_init_io(quirk->mem, OBJECT(vdev), &vfio_generic_quirk, legacy, 928c00d61d8SAlex Williamson "vfio-nvidia-bar0-1800-quirk", 9298c4f2348SAlex Williamson TARGET_PAGE_ALIGN(legacy->data.address_mask + 1)); 930c00d61d8SAlex Williamson memory_region_add_subregion_overlap(&vdev->bars[nr].region.mem, 9318c4f2348SAlex Williamson legacy->data.address_match & TARGET_PAGE_MASK, 9328c4f2348SAlex Williamson quirk->mem, 1); 933c00d61d8SAlex Williamson 934c00d61d8SAlex Williamson QLIST_INSERT_HEAD(&vdev->bars[nr].quirks, quirk, next); 935c00d61d8SAlex Williamson 936c00d61d8SAlex Williamson trace_vfio_probe_nvidia_bar0_1800_quirk(vdev->vbasedev.name); 937c00d61d8SAlex Williamson } 938c00d61d8SAlex Williamson 939c00d61d8SAlex Williamson /* 940c00d61d8SAlex Williamson * TODO - Some Nvidia devices provide config access to their companion HDA 941c00d61d8SAlex Williamson * device and even to their parent bridge via these config space mirrors. 942c00d61d8SAlex Williamson * Add quirks for those regions. 943c00d61d8SAlex Williamson */ 944c00d61d8SAlex Williamson 945c00d61d8SAlex Williamson #define PCI_VENDOR_ID_REALTEK 0x10ec 946c00d61d8SAlex Williamson 947c00d61d8SAlex Williamson /* 948c00d61d8SAlex Williamson * RTL8168 devices have a backdoor that can access the MSI-X table. At BAR2 949c00d61d8SAlex Williamson * offset 0x70 there is a dword data register, offset 0x74 is a dword address 950c00d61d8SAlex Williamson * register. According to the Linux r8169 driver, the MSI-X table is addressed 951c00d61d8SAlex Williamson * when the "type" portion of the address register is set to 0x1. This appears 952c00d61d8SAlex Williamson * to be bits 16:30. Bit 31 is both a write indicator and some sort of 953c00d61d8SAlex Williamson * "address latched" indicator. Bits 12:15 are a mask field, which we can 954c00d61d8SAlex Williamson * ignore because the MSI-X table should always be accessed as a dword (full 955c00d61d8SAlex Williamson * mask). Bits 0:11 is offset within the type. 956c00d61d8SAlex Williamson * 957c00d61d8SAlex Williamson * Example trace: 958c00d61d8SAlex Williamson * 959c00d61d8SAlex Williamson * Read from MSI-X table offset 0 960c00d61d8SAlex Williamson * vfio: vfio_bar_write(0000:05:00.0:BAR2+0x74, 0x1f000, 4) // store read addr 961c00d61d8SAlex Williamson * vfio: vfio_bar_read(0000:05:00.0:BAR2+0x74, 4) = 0x8001f000 // latch 962c00d61d8SAlex Williamson * vfio: vfio_bar_read(0000:05:00.0:BAR2+0x70, 4) = 0xfee00398 // read data 963c00d61d8SAlex Williamson * 964c00d61d8SAlex Williamson * Write 0xfee00000 to MSI-X table offset 0 965c00d61d8SAlex Williamson * vfio: vfio_bar_write(0000:05:00.0:BAR2+0x70, 0xfee00000, 4) // write data 966c00d61d8SAlex Williamson * vfio: vfio_bar_write(0000:05:00.0:BAR2+0x74, 0x8001f000, 4) // do write 967c00d61d8SAlex Williamson * vfio: vfio_bar_read(0000:05:00.0:BAR2+0x74, 4) = 0x1f000 // complete 968c00d61d8SAlex Williamson */ 969954258a5SAlex Williamson typedef struct VFIOrtl8168Quirk { 970954258a5SAlex Williamson VFIOPCIDevice *vdev; 971954258a5SAlex Williamson uint32_t addr; 972954258a5SAlex Williamson uint32_t data; 973954258a5SAlex Williamson bool enabled; 974954258a5SAlex Williamson } VFIOrtl8168Quirk; 975954258a5SAlex Williamson 976954258a5SAlex Williamson static uint64_t vfio_rtl8168_quirk_address_read(void *opaque, 977c00d61d8SAlex Williamson hwaddr addr, unsigned size) 978c00d61d8SAlex Williamson { 979954258a5SAlex Williamson VFIOrtl8168Quirk *rtl = opaque; 980954258a5SAlex Williamson VFIOPCIDevice *vdev = rtl->vdev; 981954258a5SAlex Williamson uint64_t data = vfio_region_read(&vdev->bars[2].region, addr + 0x74, size); 982c00d61d8SAlex Williamson 983954258a5SAlex Williamson if (rtl->enabled) { 984954258a5SAlex Williamson data = rtl->addr ^ 0x80000000U; /* latch/complete */ 985954258a5SAlex Williamson trace_vfio_quirk_rtl8168_fake_latch(vdev->vbasedev.name, data); 986c00d61d8SAlex Williamson } 987c00d61d8SAlex Williamson 988954258a5SAlex Williamson return data; 989c00d61d8SAlex Williamson } 990c00d61d8SAlex Williamson 991954258a5SAlex Williamson static void vfio_rtl8168_quirk_address_write(void *opaque, hwaddr addr, 992c00d61d8SAlex Williamson uint64_t data, unsigned size) 993c00d61d8SAlex Williamson { 994954258a5SAlex Williamson VFIOrtl8168Quirk *rtl = opaque; 995954258a5SAlex Williamson VFIOPCIDevice *vdev = rtl->vdev; 996c00d61d8SAlex Williamson 997954258a5SAlex Williamson rtl->enabled = false; 998954258a5SAlex Williamson 999c00d61d8SAlex Williamson if ((data & 0x7fff0000) == 0x10000) { /* MSI-X table */ 1000954258a5SAlex Williamson rtl->enabled = true; 1001954258a5SAlex Williamson rtl->addr = (uint32_t)data; 1002c00d61d8SAlex Williamson 1003c00d61d8SAlex Williamson if (data & 0x80000000U) { /* Do write */ 1004c00d61d8SAlex Williamson if (vdev->pdev.cap_present & QEMU_PCI_CAP_MSIX) { 1005c00d61d8SAlex Williamson hwaddr offset = data & 0xfff; 1006954258a5SAlex Williamson uint64_t val = rtl->data; 1007c00d61d8SAlex Williamson 1008954258a5SAlex Williamson trace_vfio_quirk_rtl8168_msix_write(vdev->vbasedev.name, 1009c00d61d8SAlex Williamson (uint16_t)offset, val); 1010c00d61d8SAlex Williamson 1011c00d61d8SAlex Williamson /* Write to the proper guest MSI-X table instead */ 1012c00d61d8SAlex Williamson memory_region_dispatch_write(&vdev->pdev.msix_table_mmio, 1013c00d61d8SAlex Williamson offset, val, size, 1014c00d61d8SAlex Williamson MEMTXATTRS_UNSPECIFIED); 1015c00d61d8SAlex Williamson } 1016c00d61d8SAlex Williamson return; /* Do not write guest MSI-X data to hardware */ 1017c00d61d8SAlex Williamson } 1018c00d61d8SAlex Williamson } 1019c00d61d8SAlex Williamson 1020954258a5SAlex Williamson vfio_region_write(&vdev->bars[2].region, addr + 0x74, data, size); 1021c00d61d8SAlex Williamson } 1022c00d61d8SAlex Williamson 1023954258a5SAlex Williamson static const MemoryRegionOps vfio_rtl_address_quirk = { 1024954258a5SAlex Williamson .read = vfio_rtl8168_quirk_address_read, 1025954258a5SAlex Williamson .write = vfio_rtl8168_quirk_address_write, 1026c00d61d8SAlex Williamson .valid = { 1027c00d61d8SAlex Williamson .min_access_size = 4, 1028c00d61d8SAlex Williamson .max_access_size = 4, 1029c00d61d8SAlex Williamson .unaligned = false, 1030c00d61d8SAlex Williamson }, 1031c00d61d8SAlex Williamson .endianness = DEVICE_LITTLE_ENDIAN, 1032c00d61d8SAlex Williamson }; 1033c00d61d8SAlex Williamson 1034954258a5SAlex Williamson static uint64_t vfio_rtl8168_quirk_data_read(void *opaque, 1035954258a5SAlex Williamson hwaddr addr, unsigned size) 1036c00d61d8SAlex Williamson { 1037954258a5SAlex Williamson VFIOrtl8168Quirk *rtl = opaque; 1038954258a5SAlex Williamson VFIOPCIDevice *vdev = rtl->vdev; 1039954258a5SAlex Williamson uint64_t data = vfio_region_read(&vdev->bars[2].region, addr + 0x74, size); 1040c00d61d8SAlex Williamson 1041954258a5SAlex Williamson if (rtl->enabled && (vdev->pdev.cap_present & QEMU_PCI_CAP_MSIX)) { 1042954258a5SAlex Williamson hwaddr offset = rtl->addr & 0xfff; 1043954258a5SAlex Williamson memory_region_dispatch_read(&vdev->pdev.msix_table_mmio, offset, 1044954258a5SAlex Williamson &data, size, MEMTXATTRS_UNSPECIFIED); 1045954258a5SAlex Williamson trace_vfio_quirk_rtl8168_msix_read(vdev->vbasedev.name, offset, data); 1046954258a5SAlex Williamson } 1047954258a5SAlex Williamson 1048954258a5SAlex Williamson return data; 1049954258a5SAlex Williamson } 1050954258a5SAlex Williamson 1051954258a5SAlex Williamson static void vfio_rtl8168_quirk_data_write(void *opaque, hwaddr addr, 1052954258a5SAlex Williamson uint64_t data, unsigned size) 1053954258a5SAlex Williamson { 1054954258a5SAlex Williamson VFIOrtl8168Quirk *rtl = opaque; 1055954258a5SAlex Williamson VFIOPCIDevice *vdev = rtl->vdev; 1056954258a5SAlex Williamson 1057954258a5SAlex Williamson rtl->data = (uint32_t)data; 1058954258a5SAlex Williamson 1059954258a5SAlex Williamson vfio_region_write(&vdev->bars[2].region, addr + 0x70, data, size); 1060954258a5SAlex Williamson } 1061954258a5SAlex Williamson 1062954258a5SAlex Williamson static const MemoryRegionOps vfio_rtl_data_quirk = { 1063954258a5SAlex Williamson .read = vfio_rtl8168_quirk_data_read, 1064954258a5SAlex Williamson .write = vfio_rtl8168_quirk_data_write, 1065954258a5SAlex Williamson .valid = { 1066954258a5SAlex Williamson .min_access_size = 4, 1067954258a5SAlex Williamson .max_access_size = 4, 1068954258a5SAlex Williamson .unaligned = false, 1069954258a5SAlex Williamson }, 1070954258a5SAlex Williamson .endianness = DEVICE_LITTLE_ENDIAN, 1071954258a5SAlex Williamson }; 1072954258a5SAlex Williamson 1073954258a5SAlex Williamson static void vfio_probe_rtl8168_bar2_quirk(VFIOPCIDevice *vdev, int nr) 1074954258a5SAlex Williamson { 1075954258a5SAlex Williamson VFIOQuirk *quirk; 1076954258a5SAlex Williamson VFIOrtl8168Quirk *rtl; 1077954258a5SAlex Williamson 1078954258a5SAlex Williamson if (!vfio_pci_is(vdev, PCI_VENDOR_ID_REALTEK, 0x8168) || nr != 2) { 1079c00d61d8SAlex Williamson return; 1080c00d61d8SAlex Williamson } 1081c00d61d8SAlex Williamson 1082c00d61d8SAlex Williamson quirk = g_malloc0(sizeof(*quirk)); 1083954258a5SAlex Williamson quirk->mem = g_malloc0_n(sizeof(MemoryRegion), 2); 1084954258a5SAlex Williamson quirk->nr_mem = 2; 1085954258a5SAlex Williamson quirk->data = rtl = g_malloc0(sizeof(*rtl)); 1086954258a5SAlex Williamson rtl->vdev = vdev; 1087c00d61d8SAlex Williamson 1088954258a5SAlex Williamson memory_region_init_io(&quirk->mem[0], OBJECT(vdev), 1089954258a5SAlex Williamson &vfio_rtl_address_quirk, rtl, 1090954258a5SAlex Williamson "vfio-rtl8168-window-address-quirk", 4); 1091c00d61d8SAlex Williamson memory_region_add_subregion_overlap(&vdev->bars[nr].region.mem, 1092954258a5SAlex Williamson 0x74, &quirk->mem[0], 1); 1093954258a5SAlex Williamson 1094954258a5SAlex Williamson memory_region_init_io(&quirk->mem[1], OBJECT(vdev), 1095954258a5SAlex Williamson &vfio_rtl_data_quirk, rtl, 1096954258a5SAlex Williamson "vfio-rtl8168-window-data-quirk", 4); 1097954258a5SAlex Williamson memory_region_add_subregion_overlap(&vdev->bars[nr].region.mem, 1098954258a5SAlex Williamson 0x70, &quirk->mem[1], 1); 1099c00d61d8SAlex Williamson 1100c00d61d8SAlex Williamson QLIST_INSERT_HEAD(&vdev->bars[nr].quirks, quirk, next); 1101c00d61d8SAlex Williamson 1102954258a5SAlex Williamson trace_vfio_quirk_rtl8168_probe(vdev->vbasedev.name); 1103c00d61d8SAlex Williamson } 1104c00d61d8SAlex Williamson 1105c00d61d8SAlex Williamson /* 1106c00d61d8SAlex Williamson * Common quirk probe entry points. 1107c00d61d8SAlex Williamson */ 1108c00d61d8SAlex Williamson void vfio_vga_quirk_setup(VFIOPCIDevice *vdev) 1109c00d61d8SAlex Williamson { 1110c00d61d8SAlex Williamson vfio_vga_probe_ati_3c3_quirk(vdev); 1111c00d61d8SAlex Williamson vfio_vga_probe_nvidia_3d0_quirk(vdev); 1112c00d61d8SAlex Williamson } 1113c00d61d8SAlex Williamson 1114c00d61d8SAlex Williamson void vfio_vga_quirk_teardown(VFIOPCIDevice *vdev) 1115c00d61d8SAlex Williamson { 1116c00d61d8SAlex Williamson VFIOQuirk *quirk; 11178c4f2348SAlex Williamson int i, j; 1118c00d61d8SAlex Williamson 1119c00d61d8SAlex Williamson for (i = 0; i < ARRAY_SIZE(vdev->vga.region); i++) { 1120c00d61d8SAlex Williamson QLIST_FOREACH(quirk, &vdev->vga.region[i].quirks, next) { 11218c4f2348SAlex Williamson for (j = 0; j < quirk->nr_mem; j++) { 11228c4f2348SAlex Williamson memory_region_del_subregion(&vdev->vga.region[i].mem, 11238c4f2348SAlex Williamson &quirk->mem[j]); 11248c4f2348SAlex Williamson } 1125c00d61d8SAlex Williamson } 1126c00d61d8SAlex Williamson } 1127c00d61d8SAlex Williamson } 1128c00d61d8SAlex Williamson 1129c00d61d8SAlex Williamson void vfio_vga_quirk_free(VFIOPCIDevice *vdev) 1130c00d61d8SAlex Williamson { 11318c4f2348SAlex Williamson int i, j; 1132c00d61d8SAlex Williamson 1133c00d61d8SAlex Williamson for (i = 0; i < ARRAY_SIZE(vdev->vga.region); i++) { 1134c00d61d8SAlex Williamson while (!QLIST_EMPTY(&vdev->vga.region[i].quirks)) { 1135c00d61d8SAlex Williamson VFIOQuirk *quirk = QLIST_FIRST(&vdev->vga.region[i].quirks); 1136c00d61d8SAlex Williamson QLIST_REMOVE(quirk, next); 11378c4f2348SAlex Williamson for (j = 0; j < quirk->nr_mem; j++) { 11388c4f2348SAlex Williamson object_unparent(OBJECT(&quirk->mem[j])); 11398c4f2348SAlex Williamson } 11408c4f2348SAlex Williamson g_free(quirk->mem); 11418c4f2348SAlex Williamson g_free(quirk->data); 1142c00d61d8SAlex Williamson g_free(quirk); 1143c00d61d8SAlex Williamson } 1144c00d61d8SAlex Williamson } 1145c00d61d8SAlex Williamson } 1146c00d61d8SAlex Williamson 1147c00d61d8SAlex Williamson void vfio_bar_quirk_setup(VFIOPCIDevice *vdev, int nr) 1148c00d61d8SAlex Williamson { 1149*0e54f24aSAlex Williamson vfio_probe_ati_bar4_quirk(vdev, nr); 1150c00d61d8SAlex Williamson vfio_probe_ati_bar2_4000_quirk(vdev, nr); 1151*0e54f24aSAlex Williamson vfio_probe_nvidia_bar5_quirk(vdev, nr); 1152c00d61d8SAlex Williamson vfio_probe_nvidia_bar0_88000_quirk(vdev, nr); 1153c00d61d8SAlex Williamson vfio_probe_nvidia_bar0_1800_quirk(vdev, nr); 1154954258a5SAlex Williamson vfio_probe_rtl8168_bar2_quirk(vdev, nr); 1155c00d61d8SAlex Williamson } 1156c00d61d8SAlex Williamson 1157c00d61d8SAlex Williamson void vfio_bar_quirk_teardown(VFIOPCIDevice *vdev, int nr) 1158c00d61d8SAlex Williamson { 1159c00d61d8SAlex Williamson VFIOBAR *bar = &vdev->bars[nr]; 1160c00d61d8SAlex Williamson VFIOQuirk *quirk; 11618c4f2348SAlex Williamson int i; 1162c00d61d8SAlex Williamson 1163c00d61d8SAlex Williamson QLIST_FOREACH(quirk, &bar->quirks, next) { 11648c4f2348SAlex Williamson for (i = 0; i < quirk->nr_mem; i++) { 11658c4f2348SAlex Williamson memory_region_del_subregion(&bar->region.mem, &quirk->mem[i]); 11668c4f2348SAlex Williamson } 1167c00d61d8SAlex Williamson } 1168c00d61d8SAlex Williamson } 1169c00d61d8SAlex Williamson 1170c00d61d8SAlex Williamson void vfio_bar_quirk_free(VFIOPCIDevice *vdev, int nr) 1171c00d61d8SAlex Williamson { 1172c00d61d8SAlex Williamson VFIOBAR *bar = &vdev->bars[nr]; 11738c4f2348SAlex Williamson int i; 1174c00d61d8SAlex Williamson 1175c00d61d8SAlex Williamson while (!QLIST_EMPTY(&bar->quirks)) { 1176c00d61d8SAlex Williamson VFIOQuirk *quirk = QLIST_FIRST(&bar->quirks); 1177c00d61d8SAlex Williamson QLIST_REMOVE(quirk, next); 11788c4f2348SAlex Williamson for (i = 0; i < quirk->nr_mem; i++) { 11798c4f2348SAlex Williamson object_unparent(OBJECT(&quirk->mem[i])); 11808c4f2348SAlex Williamson } 11818c4f2348SAlex Williamson g_free(quirk->mem); 11828c4f2348SAlex Williamson g_free(quirk->data); 1183c00d61d8SAlex Williamson g_free(quirk); 1184c00d61d8SAlex Williamson } 1185c00d61d8SAlex Williamson } 1186