xref: /qemu/hw/vfio/pci-quirks.c (revision 6029a424be37e0d7949546af7593b9b604611480)
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 {
245b946d286SAlex Williamson     VFIOPCIDevice *vdev = opaque;
246c00d61d8SAlex Williamson     uint64_t data = vfio_pci_read_config(&vdev->pdev,
247b946d286SAlex Williamson                                          PCI_BASE_ADDRESS_4 + 1, size);
248b946d286SAlex Williamson 
249b946d286SAlex 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      */
267b946d286SAlex Williamson     if (!vfio_pci_is(vdev, PCI_VENDOR_ID_ATI, PCI_ANY_ID) ||
268b946d286SAlex 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));
273b946d286SAlex Williamson     quirk->mem = g_malloc0_n(sizeof(MemoryRegion), 1);
2748c4f2348SAlex Williamson     quirk->nr_mem = 1;
275c00d61d8SAlex Williamson 
276b946d286SAlex 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 
284b946d286SAlex 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  */
393*6029a424SAlex Williamson typedef enum {NONE = 0, SELECT, WINDOW, READ, WRITE} VFIONvidia3d0State;
394*6029a424SAlex Williamson static const char *nv3d0_states[] = { "NONE", "SELECT",
395*6029a424SAlex Williamson                                       "WINDOW", "READ", "WRITE" };
396*6029a424SAlex Williamson 
397*6029a424SAlex Williamson typedef struct VFIONvidia3d0Quirk {
398*6029a424SAlex Williamson     VFIOPCIDevice *vdev;
399*6029a424SAlex Williamson     VFIONvidia3d0State state;
400*6029a424SAlex Williamson     uint32_t offset;
401*6029a424SAlex Williamson } VFIONvidia3d0Quirk;
402*6029a424SAlex Williamson 
403*6029a424SAlex Williamson static uint64_t vfio_nvidia_3d4_quirk_read(void *opaque,
404*6029a424SAlex Williamson                                            hwaddr addr, unsigned size)
405*6029a424SAlex Williamson {
406*6029a424SAlex Williamson     VFIONvidia3d0Quirk *quirk = opaque;
407*6029a424SAlex Williamson     VFIOPCIDevice *vdev = quirk->vdev;
408*6029a424SAlex Williamson 
409*6029a424SAlex Williamson     quirk->state = NONE;
410*6029a424SAlex Williamson 
411*6029a424SAlex Williamson     return vfio_vga_read(&vdev->vga.region[QEMU_PCI_VGA_IO_HI],
412*6029a424SAlex Williamson                          addr + 0x14, size);
413*6029a424SAlex Williamson }
414*6029a424SAlex Williamson 
415*6029a424SAlex Williamson static void vfio_nvidia_3d4_quirk_write(void *opaque, hwaddr addr,
416*6029a424SAlex Williamson                                         uint64_t data, unsigned size)
417*6029a424SAlex Williamson {
418*6029a424SAlex Williamson     VFIONvidia3d0Quirk *quirk = opaque;
419*6029a424SAlex Williamson     VFIOPCIDevice *vdev = quirk->vdev;
420*6029a424SAlex Williamson     VFIONvidia3d0State old_state = quirk->state;
421*6029a424SAlex Williamson 
422*6029a424SAlex Williamson     quirk->state = NONE;
423*6029a424SAlex Williamson 
424*6029a424SAlex Williamson     switch (data) {
425*6029a424SAlex Williamson     case 0x338:
426*6029a424SAlex Williamson         if (old_state == NONE) {
427*6029a424SAlex Williamson             quirk->state = SELECT;
428*6029a424SAlex Williamson             trace_vfio_quirk_nvidia_3d0_state(vdev->vbasedev.name,
429*6029a424SAlex Williamson                                               nv3d0_states[quirk->state]);
430*6029a424SAlex Williamson         }
431*6029a424SAlex Williamson         break;
432*6029a424SAlex Williamson     case 0x538:
433*6029a424SAlex Williamson         if (old_state == WINDOW) {
434*6029a424SAlex Williamson             quirk->state = READ;
435*6029a424SAlex Williamson             trace_vfio_quirk_nvidia_3d0_state(vdev->vbasedev.name,
436*6029a424SAlex Williamson                                               nv3d0_states[quirk->state]);
437*6029a424SAlex Williamson         }
438*6029a424SAlex Williamson         break;
439*6029a424SAlex Williamson     case 0x738:
440*6029a424SAlex Williamson         if (old_state == WINDOW) {
441*6029a424SAlex Williamson             quirk->state = WRITE;
442*6029a424SAlex Williamson             trace_vfio_quirk_nvidia_3d0_state(vdev->vbasedev.name,
443*6029a424SAlex Williamson                                               nv3d0_states[quirk->state]);
444*6029a424SAlex Williamson         }
445*6029a424SAlex Williamson         break;
446*6029a424SAlex Williamson     }
447*6029a424SAlex Williamson 
448*6029a424SAlex Williamson     vfio_vga_write(&vdev->vga.region[QEMU_PCI_VGA_IO_HI],
449*6029a424SAlex Williamson                    addr + 0x14, data, size);
450*6029a424SAlex Williamson }
451*6029a424SAlex Williamson 
452*6029a424SAlex Williamson static const MemoryRegionOps vfio_nvidia_3d4_quirk = {
453*6029a424SAlex Williamson     .read = vfio_nvidia_3d4_quirk_read,
454*6029a424SAlex Williamson     .write = vfio_nvidia_3d4_quirk_write,
455*6029a424SAlex Williamson     .endianness = DEVICE_LITTLE_ENDIAN,
456c00d61d8SAlex Williamson };
457c00d61d8SAlex Williamson 
458c00d61d8SAlex Williamson static uint64_t vfio_nvidia_3d0_quirk_read(void *opaque,
459c00d61d8SAlex Williamson                                            hwaddr addr, unsigned size)
460c00d61d8SAlex Williamson {
461*6029a424SAlex Williamson     VFIONvidia3d0Quirk *quirk = opaque;
462c00d61d8SAlex Williamson     VFIOPCIDevice *vdev = quirk->vdev;
463*6029a424SAlex Williamson     VFIONvidia3d0State old_state = quirk->state;
464c00d61d8SAlex Williamson     uint64_t data = vfio_vga_read(&vdev->vga.region[QEMU_PCI_VGA_IO_HI],
465*6029a424SAlex Williamson                                   addr + 0x10, size);
466c00d61d8SAlex Williamson 
467*6029a424SAlex Williamson     quirk->state = NONE;
468*6029a424SAlex Williamson 
469*6029a424SAlex Williamson     if (old_state == READ &&
470*6029a424SAlex Williamson         (quirk->offset & ~(PCI_CONFIG_SPACE_SIZE - 1)) == 0x1800) {
471*6029a424SAlex Williamson         uint8_t offset = quirk->offset & (PCI_CONFIG_SPACE_SIZE - 1);
472*6029a424SAlex Williamson 
473*6029a424SAlex Williamson         data = vfio_pci_read_config(&vdev->pdev, offset, size);
474*6029a424SAlex Williamson         trace_vfio_quirk_nvidia_3d0_read(vdev->vbasedev.name,
475*6029a424SAlex Williamson                                          offset, size, data);
476c00d61d8SAlex Williamson     }
477c00d61d8SAlex Williamson 
478c00d61d8SAlex Williamson     return data;
479c00d61d8SAlex Williamson }
480c00d61d8SAlex Williamson 
481c00d61d8SAlex Williamson static void vfio_nvidia_3d0_quirk_write(void *opaque, hwaddr addr,
482c00d61d8SAlex Williamson                                         uint64_t data, unsigned size)
483c00d61d8SAlex Williamson {
484*6029a424SAlex Williamson     VFIONvidia3d0Quirk *quirk = opaque;
485c00d61d8SAlex Williamson     VFIOPCIDevice *vdev = quirk->vdev;
486*6029a424SAlex Williamson     VFIONvidia3d0State old_state = quirk->state;
487c00d61d8SAlex Williamson 
488*6029a424SAlex Williamson     quirk->state = NONE;
489*6029a424SAlex Williamson 
490*6029a424SAlex Williamson     if (old_state == SELECT) {
491*6029a424SAlex Williamson         quirk->offset = (uint32_t)data;
492*6029a424SAlex Williamson         quirk->state = WINDOW;
493*6029a424SAlex Williamson         trace_vfio_quirk_nvidia_3d0_state(vdev->vbasedev.name,
494*6029a424SAlex Williamson                                           nv3d0_states[quirk->state]);
495*6029a424SAlex Williamson     } else if (old_state == WRITE) {
496*6029a424SAlex Williamson         if ((quirk->offset & ~(PCI_CONFIG_SPACE_SIZE - 1)) == 0x1800) {
497*6029a424SAlex Williamson             uint8_t offset = quirk->offset & (PCI_CONFIG_SPACE_SIZE - 1);
498*6029a424SAlex Williamson 
499*6029a424SAlex Williamson             vfio_pci_write_config(&vdev->pdev, offset, data, size);
500*6029a424SAlex Williamson             trace_vfio_quirk_nvidia_3d0_write(vdev->vbasedev.name,
501*6029a424SAlex Williamson                                               offset, data, size);
502c00d61d8SAlex Williamson             return;
503c00d61d8SAlex Williamson         }
504c00d61d8SAlex Williamson     }
505c00d61d8SAlex Williamson 
506c00d61d8SAlex Williamson     vfio_vga_write(&vdev->vga.region[QEMU_PCI_VGA_IO_HI],
507*6029a424SAlex Williamson                    addr + 0x10, data, size);
508c00d61d8SAlex Williamson }
509c00d61d8SAlex Williamson 
510c00d61d8SAlex Williamson static const MemoryRegionOps vfio_nvidia_3d0_quirk = {
511c00d61d8SAlex Williamson     .read = vfio_nvidia_3d0_quirk_read,
512c00d61d8SAlex Williamson     .write = vfio_nvidia_3d0_quirk_write,
513c00d61d8SAlex Williamson     .endianness = DEVICE_LITTLE_ENDIAN,
514c00d61d8SAlex Williamson };
515c00d61d8SAlex Williamson 
516c00d61d8SAlex Williamson static void vfio_vga_probe_nvidia_3d0_quirk(VFIOPCIDevice *vdev)
517c00d61d8SAlex Williamson {
518c00d61d8SAlex Williamson     VFIOQuirk *quirk;
519*6029a424SAlex Williamson     VFIONvidia3d0Quirk *data;
520c00d61d8SAlex Williamson 
521*6029a424SAlex Williamson     if (!vfio_pci_is(vdev, PCI_VENDOR_ID_NVIDIA, PCI_ANY_ID) ||
522c00d61d8SAlex Williamson         !vdev->bars[1].region.size) {
523c00d61d8SAlex Williamson         return;
524c00d61d8SAlex Williamson     }
525c00d61d8SAlex Williamson 
526c00d61d8SAlex Williamson     quirk = g_malloc0(sizeof(*quirk));
527*6029a424SAlex Williamson     quirk->data = data = g_malloc0(sizeof(*data));
528*6029a424SAlex Williamson     quirk->mem = g_malloc0_n(sizeof(MemoryRegion), 2);
529*6029a424SAlex Williamson     quirk->nr_mem = 2;
530*6029a424SAlex Williamson     data->vdev = vdev;
531c00d61d8SAlex Williamson 
532*6029a424SAlex Williamson     memory_region_init_io(&quirk->mem[0], OBJECT(vdev), &vfio_nvidia_3d4_quirk,
533*6029a424SAlex Williamson                           data, "vfio-nvidia-3d4-quirk", 2);
534c00d61d8SAlex Williamson     memory_region_add_subregion(&vdev->vga.region[QEMU_PCI_VGA_IO_HI].mem,
535*6029a424SAlex Williamson                                 0x14 /* 0x3c0 + 0x14 */, &quirk->mem[0]);
536*6029a424SAlex Williamson 
537*6029a424SAlex Williamson     memory_region_init_io(&quirk->mem[1], OBJECT(vdev), &vfio_nvidia_3d0_quirk,
538*6029a424SAlex Williamson                           data, "vfio-nvidia-3d0-quirk", 2);
539*6029a424SAlex Williamson     memory_region_add_subregion(&vdev->vga.region[QEMU_PCI_VGA_IO_HI].mem,
540*6029a424SAlex Williamson                                 0x10 /* 0x3c0 + 0x10 */, &quirk->mem[1]);
541c00d61d8SAlex Williamson 
542c00d61d8SAlex Williamson     QLIST_INSERT_HEAD(&vdev->vga.region[QEMU_PCI_VGA_IO_HI].quirks,
543c00d61d8SAlex Williamson                       quirk, next);
544c00d61d8SAlex Williamson 
545*6029a424SAlex Williamson     trace_vfio_quirk_nvidia_3d0_probe(vdev->vbasedev.name);
546c00d61d8SAlex Williamson }
547c00d61d8SAlex Williamson 
548c00d61d8SAlex Williamson /*
549c00d61d8SAlex Williamson  * The second quirk is documented in envytools.  The I/O port BAR5 is just
550c00d61d8SAlex Williamson  * a set of address/data ports to the MMIO BARs.  The BAR we care about is
551c00d61d8SAlex Williamson  * again BAR0.  This backdoor is apparently a bit newer than the one above
552c00d61d8SAlex Williamson  * so we need to not only trap 256 bytes @0x1800, but all of PCI config
553c00d61d8SAlex Williamson  * space, including extended space is available at the 4k @0x88000.
554c00d61d8SAlex Williamson  */
555c00d61d8SAlex Williamson enum {
556c00d61d8SAlex Williamson     NV_BAR5_ADDRESS = 0x1,
557c00d61d8SAlex Williamson     NV_BAR5_ENABLE = 0x2,
558c00d61d8SAlex Williamson     NV_BAR5_MASTER = 0x4,
559c00d61d8SAlex Williamson     NV_BAR5_VALID = 0x7,
560c00d61d8SAlex Williamson };
561c00d61d8SAlex Williamson 
562c00d61d8SAlex Williamson static void vfio_nvidia_bar5_window_quirk_write(void *opaque, hwaddr addr,
563c00d61d8SAlex Williamson                                                 uint64_t data, unsigned size)
564c00d61d8SAlex Williamson {
5658c4f2348SAlex Williamson     VFIOLegacyQuirk *quirk = opaque;
566c00d61d8SAlex Williamson 
567c00d61d8SAlex Williamson     switch (addr) {
568c00d61d8SAlex Williamson     case 0x0:
569c00d61d8SAlex Williamson         if (data & 0x1) {
570c00d61d8SAlex Williamson             quirk->data.flags |= NV_BAR5_MASTER;
571c00d61d8SAlex Williamson         } else {
572c00d61d8SAlex Williamson             quirk->data.flags &= ~NV_BAR5_MASTER;
573c00d61d8SAlex Williamson         }
574c00d61d8SAlex Williamson         break;
575c00d61d8SAlex Williamson     case 0x4:
576c00d61d8SAlex Williamson         if (data & 0x1) {
577c00d61d8SAlex Williamson             quirk->data.flags |= NV_BAR5_ENABLE;
578c00d61d8SAlex Williamson         } else {
579c00d61d8SAlex Williamson             quirk->data.flags &= ~NV_BAR5_ENABLE;
580c00d61d8SAlex Williamson         }
581c00d61d8SAlex Williamson         break;
582c00d61d8SAlex Williamson     case 0x8:
583c00d61d8SAlex Williamson         if (quirk->data.flags & NV_BAR5_MASTER) {
584c00d61d8SAlex Williamson             if ((data & ~0xfff) == 0x88000) {
585c00d61d8SAlex Williamson                 quirk->data.flags |= NV_BAR5_ADDRESS;
586c00d61d8SAlex Williamson                 quirk->data.address_val = data & 0xfff;
587c00d61d8SAlex Williamson             } else if ((data & ~0xff) == 0x1800) {
588c00d61d8SAlex Williamson                 quirk->data.flags |= NV_BAR5_ADDRESS;
589c00d61d8SAlex Williamson                 quirk->data.address_val = data & 0xff;
590c00d61d8SAlex Williamson             } else {
591c00d61d8SAlex Williamson                 quirk->data.flags &= ~NV_BAR5_ADDRESS;
592c00d61d8SAlex Williamson             }
593c00d61d8SAlex Williamson         }
594c00d61d8SAlex Williamson         break;
595c00d61d8SAlex Williamson     }
596c00d61d8SAlex Williamson 
597c00d61d8SAlex Williamson     vfio_generic_window_quirk_write(opaque, addr, data, size);
598c00d61d8SAlex Williamson }
599c00d61d8SAlex Williamson 
600c00d61d8SAlex Williamson static const MemoryRegionOps vfio_nvidia_bar5_window_quirk = {
601c00d61d8SAlex Williamson     .read = vfio_generic_window_quirk_read,
602c00d61d8SAlex Williamson     .write = vfio_nvidia_bar5_window_quirk_write,
603c00d61d8SAlex Williamson     .valid.min_access_size = 4,
604c00d61d8SAlex Williamson     .endianness = DEVICE_LITTLE_ENDIAN,
605c00d61d8SAlex Williamson };
606c00d61d8SAlex Williamson 
607c00d61d8SAlex Williamson static void vfio_probe_nvidia_bar5_window_quirk(VFIOPCIDevice *vdev, int nr)
608c00d61d8SAlex Williamson {
609c00d61d8SAlex Williamson     PCIDevice *pdev = &vdev->pdev;
610c00d61d8SAlex Williamson     VFIOQuirk *quirk;
6118c4f2348SAlex Williamson     VFIOLegacyQuirk *legacy;
612c00d61d8SAlex Williamson 
613c00d61d8SAlex Williamson     if (!vdev->has_vga || nr != 5 ||
614c00d61d8SAlex Williamson         pci_get_word(pdev->config + PCI_VENDOR_ID) != PCI_VENDOR_ID_NVIDIA) {
615c00d61d8SAlex Williamson         return;
616c00d61d8SAlex Williamson     }
617c00d61d8SAlex Williamson 
618c00d61d8SAlex Williamson     quirk = g_malloc0(sizeof(*quirk));
6198c4f2348SAlex Williamson     quirk->data = legacy = g_malloc0(sizeof(*legacy));
6208c4f2348SAlex Williamson     quirk->mem = legacy->mem = g_malloc0_n(sizeof(MemoryRegion), 1);
6218c4f2348SAlex Williamson     quirk->nr_mem = 1;
6228c4f2348SAlex Williamson     legacy->vdev = vdev;
6238c4f2348SAlex Williamson     legacy->data.read_flags = legacy->data.write_flags = NV_BAR5_VALID;
6248c4f2348SAlex Williamson     legacy->data.address_offset = 0x8;
6258c4f2348SAlex Williamson     legacy->data.address_size = 0; /* actually 4, but avoids generic code */
6268c4f2348SAlex Williamson     legacy->data.data_offset = 0xc;
6278c4f2348SAlex Williamson     legacy->data.data_size = 4;
6288c4f2348SAlex Williamson     legacy->data.bar = nr;
629c00d61d8SAlex Williamson 
6308c4f2348SAlex Williamson     memory_region_init_io(quirk->mem, OBJECT(vdev),
6318c4f2348SAlex Williamson                           &vfio_nvidia_bar5_window_quirk, legacy,
632c00d61d8SAlex Williamson                           "vfio-nvidia-bar5-window-quirk", 16);
633c00d61d8SAlex Williamson     memory_region_add_subregion_overlap(&vdev->bars[nr].region.mem,
6348c4f2348SAlex Williamson                                         0, quirk->mem, 1);
635c00d61d8SAlex Williamson 
636c00d61d8SAlex Williamson     QLIST_INSERT_HEAD(&vdev->bars[nr].quirks, quirk, next);
637c00d61d8SAlex Williamson 
638c00d61d8SAlex Williamson     trace_vfio_probe_nvidia_bar5_window_quirk(vdev->vbasedev.name);
639c00d61d8SAlex Williamson }
640c00d61d8SAlex Williamson 
641c00d61d8SAlex Williamson static void vfio_nvidia_88000_quirk_write(void *opaque, hwaddr addr,
642c00d61d8SAlex Williamson                                           uint64_t data, unsigned size)
643c00d61d8SAlex Williamson {
6448c4f2348SAlex Williamson     VFIOLegacyQuirk *quirk = opaque;
645c00d61d8SAlex Williamson     VFIOPCIDevice *vdev = quirk->vdev;
646c00d61d8SAlex Williamson     PCIDevice *pdev = &vdev->pdev;
647c00d61d8SAlex Williamson     hwaddr base = quirk->data.address_match & TARGET_PAGE_MASK;
648c00d61d8SAlex Williamson 
649c00d61d8SAlex Williamson     vfio_generic_quirk_write(opaque, addr, data, size);
650c00d61d8SAlex Williamson 
651c00d61d8SAlex Williamson     /*
652c00d61d8SAlex Williamson      * Nvidia seems to acknowledge MSI interrupts by writing 0xff to the
653c00d61d8SAlex Williamson      * MSI capability ID register.  Both the ID and next register are
654c00d61d8SAlex Williamson      * read-only, so we allow writes covering either of those to real hw.
655c00d61d8SAlex Williamson      * NB - only fixed for the 0x88000 MMIO window.
656c00d61d8SAlex Williamson      */
657c00d61d8SAlex Williamson     if ((pdev->cap_present & QEMU_PCI_CAP_MSI) &&
658c00d61d8SAlex Williamson         vfio_range_contained(addr, size, pdev->msi_cap, PCI_MSI_FLAGS)) {
659c00d61d8SAlex Williamson         vfio_region_write(&vdev->bars[quirk->data.bar].region,
660c00d61d8SAlex Williamson                           addr + base, data, size);
661c00d61d8SAlex Williamson     }
662c00d61d8SAlex Williamson }
663c00d61d8SAlex Williamson 
664c00d61d8SAlex Williamson static const MemoryRegionOps vfio_nvidia_88000_quirk = {
665c00d61d8SAlex Williamson     .read = vfio_generic_quirk_read,
666c00d61d8SAlex Williamson     .write = vfio_nvidia_88000_quirk_write,
667c00d61d8SAlex Williamson     .endianness = DEVICE_LITTLE_ENDIAN,
668c00d61d8SAlex Williamson };
669c00d61d8SAlex Williamson 
670c00d61d8SAlex Williamson /*
671c00d61d8SAlex Williamson  * Finally, BAR0 itself.  We want to redirect any accesses to either
672c00d61d8SAlex Williamson  * 0x1800 or 0x88000 through the PCI config space access functions.
673c00d61d8SAlex Williamson  *
674c00d61d8SAlex Williamson  * NB - quirk at a page granularity or else they don't seem to work when
675c00d61d8SAlex Williamson  *      BARs are mmap'd
676c00d61d8SAlex Williamson  *
677c00d61d8SAlex Williamson  * Here's offset 0x88000...
678c00d61d8SAlex Williamson  */
679c00d61d8SAlex Williamson static void vfio_probe_nvidia_bar0_88000_quirk(VFIOPCIDevice *vdev, int nr)
680c00d61d8SAlex Williamson {
681c00d61d8SAlex Williamson     PCIDevice *pdev = &vdev->pdev;
682c00d61d8SAlex Williamson     VFIOQuirk *quirk;
6838c4f2348SAlex Williamson     VFIOLegacyQuirk *legacy;
684c00d61d8SAlex Williamson     uint16_t vendor, class;
685c00d61d8SAlex Williamson 
686c00d61d8SAlex Williamson     vendor = pci_get_word(pdev->config + PCI_VENDOR_ID);
687c00d61d8SAlex Williamson     class = pci_get_word(pdev->config + PCI_CLASS_DEVICE);
688c00d61d8SAlex Williamson 
689c00d61d8SAlex Williamson     if (nr != 0 || vendor != PCI_VENDOR_ID_NVIDIA ||
690c00d61d8SAlex Williamson         class != PCI_CLASS_DISPLAY_VGA) {
691c00d61d8SAlex Williamson         return;
692c00d61d8SAlex Williamson     }
693c00d61d8SAlex Williamson 
694c00d61d8SAlex Williamson     quirk = g_malloc0(sizeof(*quirk));
6958c4f2348SAlex Williamson     quirk->data = legacy = g_malloc0(sizeof(*legacy));
6968c4f2348SAlex Williamson     quirk->mem = legacy->mem = g_malloc0_n(sizeof(MemoryRegion), 1);
6978c4f2348SAlex Williamson     quirk->nr_mem = 1;
6988c4f2348SAlex Williamson     legacy->vdev = vdev;
6998c4f2348SAlex Williamson     legacy->data.flags = legacy->data.read_flags = legacy->data.write_flags = 1;
7008c4f2348SAlex Williamson     legacy->data.address_match = 0x88000;
7018c4f2348SAlex Williamson     legacy->data.address_mask = PCIE_CONFIG_SPACE_SIZE - 1;
7028c4f2348SAlex Williamson     legacy->data.bar = nr;
703c00d61d8SAlex Williamson 
7048c4f2348SAlex Williamson     memory_region_init_io(quirk->mem, OBJECT(vdev), &vfio_nvidia_88000_quirk,
7058c4f2348SAlex Williamson                           legacy, "vfio-nvidia-bar0-88000-quirk",
7068c4f2348SAlex Williamson                           TARGET_PAGE_ALIGN(legacy->data.address_mask + 1));
707c00d61d8SAlex Williamson     memory_region_add_subregion_overlap(&vdev->bars[nr].region.mem,
7088c4f2348SAlex Williamson                           legacy->data.address_match & TARGET_PAGE_MASK,
7098c4f2348SAlex Williamson                           quirk->mem, 1);
710c00d61d8SAlex Williamson 
711c00d61d8SAlex Williamson     QLIST_INSERT_HEAD(&vdev->bars[nr].quirks, quirk, next);
712c00d61d8SAlex Williamson 
713c00d61d8SAlex Williamson     trace_vfio_probe_nvidia_bar0_88000_quirk(vdev->vbasedev.name);
714c00d61d8SAlex Williamson }
715c00d61d8SAlex Williamson 
716c00d61d8SAlex Williamson /*
717c00d61d8SAlex Williamson  * And here's the same for BAR0 offset 0x1800...
718c00d61d8SAlex Williamson  */
719c00d61d8SAlex Williamson static void vfio_probe_nvidia_bar0_1800_quirk(VFIOPCIDevice *vdev, int nr)
720c00d61d8SAlex Williamson {
721c00d61d8SAlex Williamson     PCIDevice *pdev = &vdev->pdev;
722c00d61d8SAlex Williamson     VFIOQuirk *quirk;
7238c4f2348SAlex Williamson     VFIOLegacyQuirk *legacy;
724c00d61d8SAlex Williamson 
725c00d61d8SAlex Williamson     if (!vdev->has_vga || nr != 0 ||
726c00d61d8SAlex Williamson         pci_get_word(pdev->config + PCI_VENDOR_ID) != PCI_VENDOR_ID_NVIDIA) {
727c00d61d8SAlex Williamson         return;
728c00d61d8SAlex Williamson     }
729c00d61d8SAlex Williamson 
730c00d61d8SAlex Williamson     /* Log the chipset ID */
731c00d61d8SAlex Williamson     trace_vfio_probe_nvidia_bar0_1800_quirk_id(
732c00d61d8SAlex Williamson             (unsigned int)(vfio_region_read(&vdev->bars[0].region, 0, 4) >> 20)
733c00d61d8SAlex Williamson             & 0xff);
734c00d61d8SAlex Williamson 
735c00d61d8SAlex Williamson     quirk = g_malloc0(sizeof(*quirk));
7368c4f2348SAlex Williamson     quirk->data = legacy = g_malloc0(sizeof(*legacy));
7378c4f2348SAlex Williamson     quirk->mem = legacy->mem = g_malloc0_n(sizeof(MemoryRegion), 1);
7388c4f2348SAlex Williamson     quirk->nr_mem = 1;
7398c4f2348SAlex Williamson     legacy->vdev = vdev;
7408c4f2348SAlex Williamson     legacy->data.flags = legacy->data.read_flags = legacy->data.write_flags = 1;
7418c4f2348SAlex Williamson     legacy->data.address_match = 0x1800;
7428c4f2348SAlex Williamson     legacy->data.address_mask = PCI_CONFIG_SPACE_SIZE - 1;
7438c4f2348SAlex Williamson     legacy->data.bar = nr;
744c00d61d8SAlex Williamson 
7458c4f2348SAlex Williamson     memory_region_init_io(quirk->mem, OBJECT(vdev), &vfio_generic_quirk, legacy,
746c00d61d8SAlex Williamson                           "vfio-nvidia-bar0-1800-quirk",
7478c4f2348SAlex Williamson                           TARGET_PAGE_ALIGN(legacy->data.address_mask + 1));
748c00d61d8SAlex Williamson     memory_region_add_subregion_overlap(&vdev->bars[nr].region.mem,
7498c4f2348SAlex Williamson                           legacy->data.address_match & TARGET_PAGE_MASK,
7508c4f2348SAlex Williamson                           quirk->mem, 1);
751c00d61d8SAlex Williamson 
752c00d61d8SAlex Williamson     QLIST_INSERT_HEAD(&vdev->bars[nr].quirks, quirk, next);
753c00d61d8SAlex Williamson 
754c00d61d8SAlex Williamson     trace_vfio_probe_nvidia_bar0_1800_quirk(vdev->vbasedev.name);
755c00d61d8SAlex Williamson }
756c00d61d8SAlex Williamson 
757c00d61d8SAlex Williamson /*
758c00d61d8SAlex Williamson  * TODO - Some Nvidia devices provide config access to their companion HDA
759c00d61d8SAlex Williamson  * device and even to their parent bridge via these config space mirrors.
760c00d61d8SAlex Williamson  * Add quirks for those regions.
761c00d61d8SAlex Williamson  */
762c00d61d8SAlex Williamson 
763c00d61d8SAlex Williamson #define PCI_VENDOR_ID_REALTEK 0x10ec
764c00d61d8SAlex Williamson 
765c00d61d8SAlex Williamson /*
766c00d61d8SAlex Williamson  * RTL8168 devices have a backdoor that can access the MSI-X table.  At BAR2
767c00d61d8SAlex Williamson  * offset 0x70 there is a dword data register, offset 0x74 is a dword address
768c00d61d8SAlex Williamson  * register.  According to the Linux r8169 driver, the MSI-X table is addressed
769c00d61d8SAlex Williamson  * when the "type" portion of the address register is set to 0x1.  This appears
770c00d61d8SAlex Williamson  * to be bits 16:30.  Bit 31 is both a write indicator and some sort of
771c00d61d8SAlex Williamson  * "address latched" indicator.  Bits 12:15 are a mask field, which we can
772c00d61d8SAlex Williamson  * ignore because the MSI-X table should always be accessed as a dword (full
773c00d61d8SAlex Williamson  * mask).  Bits 0:11 is offset within the type.
774c00d61d8SAlex Williamson  *
775c00d61d8SAlex Williamson  * Example trace:
776c00d61d8SAlex Williamson  *
777c00d61d8SAlex Williamson  * Read from MSI-X table offset 0
778c00d61d8SAlex Williamson  * vfio: vfio_bar_write(0000:05:00.0:BAR2+0x74, 0x1f000, 4) // store read addr
779c00d61d8SAlex Williamson  * vfio: vfio_bar_read(0000:05:00.0:BAR2+0x74, 4) = 0x8001f000 // latch
780c00d61d8SAlex Williamson  * vfio: vfio_bar_read(0000:05:00.0:BAR2+0x70, 4) = 0xfee00398 // read data
781c00d61d8SAlex Williamson  *
782c00d61d8SAlex Williamson  * Write 0xfee00000 to MSI-X table offset 0
783c00d61d8SAlex Williamson  * vfio: vfio_bar_write(0000:05:00.0:BAR2+0x70, 0xfee00000, 4) // write data
784c00d61d8SAlex Williamson  * vfio: vfio_bar_write(0000:05:00.0:BAR2+0x74, 0x8001f000, 4) // do write
785c00d61d8SAlex Williamson  * vfio: vfio_bar_read(0000:05:00.0:BAR2+0x74, 4) = 0x1f000 // complete
786c00d61d8SAlex Williamson  */
787c00d61d8SAlex Williamson static uint64_t vfio_rtl8168_window_quirk_read(void *opaque,
788c00d61d8SAlex Williamson                                                hwaddr addr, unsigned size)
789c00d61d8SAlex Williamson {
7908c4f2348SAlex Williamson     VFIOLegacyQuirk *quirk = opaque;
791c00d61d8SAlex Williamson     VFIOPCIDevice *vdev = quirk->vdev;
792c00d61d8SAlex Williamson     uint64_t val = 0;
793c00d61d8SAlex Williamson 
794c00d61d8SAlex Williamson     if (!quirk->data.flags) { /* Non-MSI-X table access */
795c00d61d8SAlex Williamson         return vfio_region_read(&vdev->bars[quirk->data.bar].region,
796c00d61d8SAlex Williamson                                 addr + 0x70, size);
797c00d61d8SAlex Williamson     }
798c00d61d8SAlex Williamson 
799c00d61d8SAlex Williamson     switch (addr) {
800c00d61d8SAlex Williamson     case 4: /* address */
801c00d61d8SAlex Williamson         val = quirk->data.address_match ^ 0x80000000U; /* latch/complete */
802c00d61d8SAlex Williamson         break;
803c00d61d8SAlex Williamson     case 0: /* data */
804c00d61d8SAlex Williamson         if ((vdev->pdev.cap_present & QEMU_PCI_CAP_MSIX)) {
805c00d61d8SAlex Williamson             memory_region_dispatch_read(&vdev->pdev.msix_table_mmio,
806c00d61d8SAlex Williamson                                 (hwaddr)(quirk->data.address_match & 0xfff),
807c00d61d8SAlex Williamson                                 &val, size, MEMTXATTRS_UNSPECIFIED);
808c00d61d8SAlex Williamson         }
809c00d61d8SAlex Williamson         break;
810c00d61d8SAlex Williamson     }
811c00d61d8SAlex Williamson 
812c00d61d8SAlex Williamson     trace_vfio_rtl8168_quirk_read(vdev->vbasedev.name,
813c00d61d8SAlex Williamson                                   addr ? "address" : "data", val);
814c00d61d8SAlex Williamson     return val;
815c00d61d8SAlex Williamson }
816c00d61d8SAlex Williamson 
817c00d61d8SAlex Williamson static void vfio_rtl8168_window_quirk_write(void *opaque, hwaddr addr,
818c00d61d8SAlex Williamson                                             uint64_t data, unsigned size)
819c00d61d8SAlex Williamson {
8208c4f2348SAlex Williamson     VFIOLegacyQuirk *quirk = opaque;
821c00d61d8SAlex Williamson     VFIOPCIDevice *vdev = quirk->vdev;
822c00d61d8SAlex Williamson 
823c00d61d8SAlex Williamson     switch (addr) {
824c00d61d8SAlex Williamson     case 4: /* address */
825c00d61d8SAlex Williamson         if ((data & 0x7fff0000) == 0x10000) { /* MSI-X table */
826c00d61d8SAlex Williamson             quirk->data.flags = 1; /* Activate reads */
827c00d61d8SAlex Williamson             quirk->data.address_match = data;
828c00d61d8SAlex Williamson 
829c00d61d8SAlex Williamson             trace_vfio_rtl8168_quirk_write(vdev->vbasedev.name, data);
830c00d61d8SAlex Williamson 
831c00d61d8SAlex Williamson             if (data & 0x80000000U) { /* Do write */
832c00d61d8SAlex Williamson                 if (vdev->pdev.cap_present & QEMU_PCI_CAP_MSIX) {
833c00d61d8SAlex Williamson                     hwaddr offset = data & 0xfff;
834c00d61d8SAlex Williamson                     uint64_t val = quirk->data.address_mask;
835c00d61d8SAlex Williamson 
836c00d61d8SAlex Williamson                     trace_vfio_rtl8168_quirk_msix(vdev->vbasedev.name,
837c00d61d8SAlex Williamson                                                   (uint16_t)offset, val);
838c00d61d8SAlex Williamson 
839c00d61d8SAlex Williamson                     /* Write to the proper guest MSI-X table instead */
840c00d61d8SAlex Williamson                     memory_region_dispatch_write(&vdev->pdev.msix_table_mmio,
841c00d61d8SAlex Williamson                                                  offset, val, size,
842c00d61d8SAlex Williamson                                                  MEMTXATTRS_UNSPECIFIED);
843c00d61d8SAlex Williamson                 }
844c00d61d8SAlex Williamson                 return; /* Do not write guest MSI-X data to hardware */
845c00d61d8SAlex Williamson             }
846c00d61d8SAlex Williamson         } else {
847c00d61d8SAlex Williamson             quirk->data.flags = 0; /* De-activate reads, non-MSI-X */
848c00d61d8SAlex Williamson         }
849c00d61d8SAlex Williamson         break;
850c00d61d8SAlex Williamson     case 0: /* data */
851c00d61d8SAlex Williamson         quirk->data.address_mask = data;
852c00d61d8SAlex Williamson         break;
853c00d61d8SAlex Williamson     }
854c00d61d8SAlex Williamson 
855c00d61d8SAlex Williamson     vfio_region_write(&vdev->bars[quirk->data.bar].region,
856c00d61d8SAlex Williamson                       addr + 0x70, data, size);
857c00d61d8SAlex Williamson }
858c00d61d8SAlex Williamson 
859c00d61d8SAlex Williamson static const MemoryRegionOps vfio_rtl8168_window_quirk = {
860c00d61d8SAlex Williamson     .read = vfio_rtl8168_window_quirk_read,
861c00d61d8SAlex Williamson     .write = vfio_rtl8168_window_quirk_write,
862c00d61d8SAlex Williamson     .valid = {
863c00d61d8SAlex Williamson         .min_access_size = 4,
864c00d61d8SAlex Williamson         .max_access_size = 4,
865c00d61d8SAlex Williamson         .unaligned = false,
866c00d61d8SAlex Williamson     },
867c00d61d8SAlex Williamson     .endianness = DEVICE_LITTLE_ENDIAN,
868c00d61d8SAlex Williamson };
869c00d61d8SAlex Williamson 
870c00d61d8SAlex Williamson static void vfio_probe_rtl8168_bar2_window_quirk(VFIOPCIDevice *vdev, int nr)
871c00d61d8SAlex Williamson {
872c00d61d8SAlex Williamson     PCIDevice *pdev = &vdev->pdev;
873c00d61d8SAlex Williamson     VFIOQuirk *quirk;
8748c4f2348SAlex Williamson     VFIOLegacyQuirk *legacy;
875c00d61d8SAlex Williamson 
876c00d61d8SAlex Williamson     if (pci_get_word(pdev->config + PCI_VENDOR_ID) != PCI_VENDOR_ID_REALTEK ||
877c00d61d8SAlex Williamson         pci_get_word(pdev->config + PCI_DEVICE_ID) != 0x8168 || nr != 2) {
878c00d61d8SAlex Williamson         return;
879c00d61d8SAlex Williamson     }
880c00d61d8SAlex Williamson 
881c00d61d8SAlex Williamson     quirk = g_malloc0(sizeof(*quirk));
8828c4f2348SAlex Williamson     quirk->data = legacy = g_malloc0(sizeof(*legacy));
8838c4f2348SAlex Williamson     quirk->mem = legacy->mem = g_malloc0_n(sizeof(MemoryRegion), 1);
8848c4f2348SAlex Williamson     quirk->nr_mem = 1;
8858c4f2348SAlex Williamson     legacy->vdev = vdev;
8868c4f2348SAlex Williamson     legacy->data.bar = nr;
887c00d61d8SAlex Williamson 
8888c4f2348SAlex Williamson     memory_region_init_io(quirk->mem, OBJECT(vdev), &vfio_rtl8168_window_quirk,
8898c4f2348SAlex Williamson                           legacy, "vfio-rtl8168-window-quirk", 8);
890c00d61d8SAlex Williamson     memory_region_add_subregion_overlap(&vdev->bars[nr].region.mem,
8918c4f2348SAlex Williamson                                         0x70, quirk->mem, 1);
892c00d61d8SAlex Williamson 
893c00d61d8SAlex Williamson     QLIST_INSERT_HEAD(&vdev->bars[nr].quirks, quirk, next);
894c00d61d8SAlex Williamson 
895c00d61d8SAlex Williamson     trace_vfio_rtl8168_quirk_enable(vdev->vbasedev.name);
896c00d61d8SAlex Williamson }
897c00d61d8SAlex Williamson 
898c00d61d8SAlex Williamson /*
899c00d61d8SAlex Williamson  * Common quirk probe entry points.
900c00d61d8SAlex Williamson  */
901c00d61d8SAlex Williamson void vfio_vga_quirk_setup(VFIOPCIDevice *vdev)
902c00d61d8SAlex Williamson {
903c00d61d8SAlex Williamson     vfio_vga_probe_ati_3c3_quirk(vdev);
904c00d61d8SAlex Williamson     vfio_vga_probe_nvidia_3d0_quirk(vdev);
905c00d61d8SAlex Williamson }
906c00d61d8SAlex Williamson 
907c00d61d8SAlex Williamson void vfio_vga_quirk_teardown(VFIOPCIDevice *vdev)
908c00d61d8SAlex Williamson {
909c00d61d8SAlex Williamson     VFIOQuirk *quirk;
9108c4f2348SAlex Williamson     int i, j;
911c00d61d8SAlex Williamson 
912c00d61d8SAlex Williamson     for (i = 0; i < ARRAY_SIZE(vdev->vga.region); i++) {
913c00d61d8SAlex Williamson         QLIST_FOREACH(quirk, &vdev->vga.region[i].quirks, next) {
9148c4f2348SAlex Williamson             for (j = 0; j < quirk->nr_mem; j++) {
9158c4f2348SAlex Williamson                 memory_region_del_subregion(&vdev->vga.region[i].mem,
9168c4f2348SAlex Williamson                                             &quirk->mem[j]);
9178c4f2348SAlex Williamson             }
918c00d61d8SAlex Williamson         }
919c00d61d8SAlex Williamson     }
920c00d61d8SAlex Williamson }
921c00d61d8SAlex Williamson 
922c00d61d8SAlex Williamson void vfio_vga_quirk_free(VFIOPCIDevice *vdev)
923c00d61d8SAlex Williamson {
9248c4f2348SAlex Williamson     int i, j;
925c00d61d8SAlex Williamson 
926c00d61d8SAlex Williamson     for (i = 0; i < ARRAY_SIZE(vdev->vga.region); i++) {
927c00d61d8SAlex Williamson         while (!QLIST_EMPTY(&vdev->vga.region[i].quirks)) {
928c00d61d8SAlex Williamson             VFIOQuirk *quirk = QLIST_FIRST(&vdev->vga.region[i].quirks);
929c00d61d8SAlex Williamson             QLIST_REMOVE(quirk, next);
9308c4f2348SAlex Williamson             for (j = 0; j < quirk->nr_mem; j++) {
9318c4f2348SAlex Williamson                 object_unparent(OBJECT(&quirk->mem[j]));
9328c4f2348SAlex Williamson             }
9338c4f2348SAlex Williamson             g_free(quirk->mem);
9348c4f2348SAlex Williamson             g_free(quirk->data);
935c00d61d8SAlex Williamson             g_free(quirk);
936c00d61d8SAlex Williamson         }
937c00d61d8SAlex Williamson     }
938c00d61d8SAlex Williamson }
939c00d61d8SAlex Williamson 
940c00d61d8SAlex Williamson void vfio_bar_quirk_setup(VFIOPCIDevice *vdev, int nr)
941c00d61d8SAlex Williamson {
942c00d61d8SAlex Williamson     vfio_probe_ati_bar4_window_quirk(vdev, nr);
943c00d61d8SAlex Williamson     vfio_probe_ati_bar2_4000_quirk(vdev, nr);
944c00d61d8SAlex Williamson     vfio_probe_nvidia_bar5_window_quirk(vdev, nr);
945c00d61d8SAlex Williamson     vfio_probe_nvidia_bar0_88000_quirk(vdev, nr);
946c00d61d8SAlex Williamson     vfio_probe_nvidia_bar0_1800_quirk(vdev, nr);
947c00d61d8SAlex Williamson     vfio_probe_rtl8168_bar2_window_quirk(vdev, nr);
948c00d61d8SAlex Williamson }
949c00d61d8SAlex Williamson 
950c00d61d8SAlex Williamson void vfio_bar_quirk_teardown(VFIOPCIDevice *vdev, int nr)
951c00d61d8SAlex Williamson {
952c00d61d8SAlex Williamson     VFIOBAR *bar = &vdev->bars[nr];
953c00d61d8SAlex Williamson     VFIOQuirk *quirk;
9548c4f2348SAlex Williamson     int i;
955c00d61d8SAlex Williamson 
956c00d61d8SAlex Williamson     QLIST_FOREACH(quirk, &bar->quirks, next) {
9578c4f2348SAlex Williamson         for (i = 0; i < quirk->nr_mem; i++) {
9588c4f2348SAlex Williamson             memory_region_del_subregion(&bar->region.mem, &quirk->mem[i]);
9598c4f2348SAlex Williamson         }
960c00d61d8SAlex Williamson     }
961c00d61d8SAlex Williamson }
962c00d61d8SAlex Williamson 
963c00d61d8SAlex Williamson void vfio_bar_quirk_free(VFIOPCIDevice *vdev, int nr)
964c00d61d8SAlex Williamson {
965c00d61d8SAlex Williamson     VFIOBAR *bar = &vdev->bars[nr];
9668c4f2348SAlex Williamson     int i;
967c00d61d8SAlex Williamson 
968c00d61d8SAlex Williamson     while (!QLIST_EMPTY(&bar->quirks)) {
969c00d61d8SAlex Williamson         VFIOQuirk *quirk = QLIST_FIRST(&bar->quirks);
970c00d61d8SAlex Williamson         QLIST_REMOVE(quirk, next);
9718c4f2348SAlex Williamson         for (i = 0; i < quirk->nr_mem; i++) {
9728c4f2348SAlex Williamson             object_unparent(OBJECT(&quirk->mem[i]));
9738c4f2348SAlex Williamson         }
9748c4f2348SAlex Williamson         g_free(quirk->mem);
9758c4f2348SAlex Williamson         g_free(quirk->data);
976c00d61d8SAlex Williamson         g_free(quirk);
977c00d61d8SAlex Williamson     }
978c00d61d8SAlex Williamson }
979