xref: /qemu/hw/vfio/pci-quirks.c (revision 056dfcb695cde3c62b7dc1d5ed6d2e38b3a73e29)
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 
17*056dfcb6SAlex Williamson #define PCI_ANY_ID (~0)
18*056dfcb6SAlex Williamson 
19*056dfcb6SAlex Williamson /* Use uin32_t for vendor & device so PCI_ANY_ID expands and cannot match hw */
20*056dfcb6SAlex Williamson static bool vfio_pci_is(VFIOPCIDevice *vdev, uint32_t vendor, uint32_t device)
21*056dfcb6SAlex Williamson {
22*056dfcb6SAlex Williamson     PCIDevice *pdev = &vdev->pdev;
23*056dfcb6SAlex Williamson 
24*056dfcb6SAlex Williamson     return (vendor == PCI_ANY_ID ||
25*056dfcb6SAlex Williamson             vendor == pci_get_word(pdev->config + PCI_VENDOR_ID)) &&
26*056dfcb6SAlex Williamson            (device == PCI_ANY_ID ||
27*056dfcb6SAlex Williamson             device == pci_get_word(pdev->config + PCI_DEVICE_ID));
28*056dfcb6SAlex Williamson }
29*056dfcb6SAlex 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  */
43*056dfcb6SAlex Williamson static const struct {
44*056dfcb6SAlex Williamson     uint32_t vendor;
45*056dfcb6SAlex Williamson     uint32_t device;
46*056dfcb6SAlex Williamson } romblacklist[] = {
47*056dfcb6SAlex Williamson     { 0x14e4, 0x168e }, /* Broadcom BCM 57810 */
48c00d61d8SAlex Williamson };
49c00d61d8SAlex Williamson 
50c00d61d8SAlex Williamson bool vfio_blacklist_opt_rom(VFIOPCIDevice *vdev)
51c00d61d8SAlex Williamson {
52*056dfcb6SAlex Williamson     int i;
53c00d61d8SAlex Williamson 
54*056dfcb6SAlex Williamson     for (i = 0 ; i < ARRAY_SIZE(romblacklist); i++) {
55*056dfcb6SAlex Williamson         if (vfio_pci_is(vdev, romblacklist[i].vendor, romblacklist[i].device)) {
56*056dfcb6SAlex Williamson             trace_vfio_quirk_rom_blacklisted(vdev->vbasedev.name,
57*056dfcb6SAlex Williamson                                              romblacklist[i].vendor,
58*056dfcb6SAlex 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 {
83c00d61d8SAlex Williamson     VFIOQuirk *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",
95c00d61d8SAlex 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 
101c00d61d8SAlex 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 {
116c00d61d8SAlex Williamson     VFIOQuirk *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",
124c00d61d8SAlex 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",
145c00d61d8SAlex 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);
150c00d61d8SAlex 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 {
170c00d61d8SAlex Williamson     VFIOQuirk *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",
181c00d61d8SAlex 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 
186c00d61d8SAlex 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 {
200c00d61d8SAlex Williamson     VFIOQuirk *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",
210c00d61d8SAlex 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 
215c00d61d8SAlex 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 {
245c00d61d8SAlex Williamson     VFIOQuirk *quirk = opaque;
246c00d61d8SAlex Williamson     VFIOPCIDevice *vdev = quirk->vdev;
247c00d61d8SAlex Williamson     uint64_t data = vfio_pci_read_config(&vdev->pdev,
248c00d61d8SAlex Williamson                                          PCI_BASE_ADDRESS_0 + (4 * 4) + 1,
249c00d61d8SAlex Williamson                                          size);
250c00d61d8SAlex Williamson     trace_vfio_ati_3c3_quirk_read(data);
251c00d61d8SAlex Williamson 
252c00d61d8SAlex Williamson     return data;
253c00d61d8SAlex Williamson }
254c00d61d8SAlex Williamson 
255c00d61d8SAlex Williamson static const MemoryRegionOps vfio_ati_3c3_quirk = {
256c00d61d8SAlex Williamson     .read = vfio_ati_3c3_quirk_read,
257c00d61d8SAlex Williamson     .endianness = DEVICE_LITTLE_ENDIAN,
258c00d61d8SAlex Williamson };
259c00d61d8SAlex Williamson 
260c00d61d8SAlex Williamson static void vfio_vga_probe_ati_3c3_quirk(VFIOPCIDevice *vdev)
261c00d61d8SAlex Williamson {
262c00d61d8SAlex Williamson     PCIDevice *pdev = &vdev->pdev;
263c00d61d8SAlex Williamson     VFIOQuirk *quirk;
264c00d61d8SAlex Williamson 
265c00d61d8SAlex Williamson     if (pci_get_word(pdev->config + PCI_VENDOR_ID) != PCI_VENDOR_ID_ATI) {
266c00d61d8SAlex Williamson         return;
267c00d61d8SAlex Williamson     }
268c00d61d8SAlex Williamson 
269c00d61d8SAlex Williamson     /*
270c00d61d8SAlex Williamson      * As long as the BAR is >= 256 bytes it will be aligned such that the
271c00d61d8SAlex Williamson      * lower byte is always zero.  Filter out anything else, if it exists.
272c00d61d8SAlex Williamson      */
273c00d61d8SAlex Williamson     if (!vdev->bars[4].ioport || vdev->bars[4].region.size < 256) {
274c00d61d8SAlex Williamson         return;
275c00d61d8SAlex Williamson     }
276c00d61d8SAlex Williamson 
277c00d61d8SAlex Williamson     quirk = g_malloc0(sizeof(*quirk));
278c00d61d8SAlex Williamson     quirk->vdev = vdev;
279c00d61d8SAlex Williamson 
280c00d61d8SAlex Williamson     memory_region_init_io(&quirk->mem, OBJECT(vdev), &vfio_ati_3c3_quirk, quirk,
281c00d61d8SAlex Williamson                           "vfio-ati-3c3-quirk", 1);
282c00d61d8SAlex Williamson     memory_region_add_subregion(&vdev->vga.region[QEMU_PCI_VGA_IO_HI].mem,
283c00d61d8SAlex Williamson                                 3 /* offset 3 bytes from 0x3c0 */, &quirk->mem);
284c00d61d8SAlex Williamson 
285c00d61d8SAlex Williamson     QLIST_INSERT_HEAD(&vdev->vga.region[QEMU_PCI_VGA_IO_HI].quirks,
286c00d61d8SAlex Williamson                       quirk, next);
287c00d61d8SAlex Williamson 
288c00d61d8SAlex Williamson     trace_vfio_vga_probe_ati_3c3_quirk(vdev->vbasedev.name);
289c00d61d8SAlex Williamson }
290c00d61d8SAlex Williamson 
291c00d61d8SAlex Williamson /*
292c00d61d8SAlex Williamson  * Newer ATI/AMD devices, including HD5450 and HD7850, have a window to PCI
293c00d61d8SAlex Williamson  * config space through MMIO BAR2 at offset 0x4000.  Nothing seems to access
294c00d61d8SAlex Williamson  * the MMIO space directly, but a window to this space is provided through
295c00d61d8SAlex Williamson  * I/O port BAR4.  Offset 0x0 is the address register and offset 0x4 is the
296c00d61d8SAlex Williamson  * data register.  When the address is programmed to a range of 0x4000-0x4fff
297c00d61d8SAlex Williamson  * PCI configuration space is available.  Experimentation seems to indicate
298c00d61d8SAlex Williamson  * that only read-only access is provided, but we drop writes when the window
299c00d61d8SAlex Williamson  * is enabled to config space nonetheless.
300c00d61d8SAlex Williamson  */
301c00d61d8SAlex Williamson static void vfio_probe_ati_bar4_window_quirk(VFIOPCIDevice *vdev, int nr)
302c00d61d8SAlex Williamson {
303c00d61d8SAlex Williamson     PCIDevice *pdev = &vdev->pdev;
304c00d61d8SAlex Williamson     VFIOQuirk *quirk;
305c00d61d8SAlex Williamson 
306c00d61d8SAlex Williamson     if (!vdev->has_vga || nr != 4 ||
307c00d61d8SAlex Williamson         pci_get_word(pdev->config + PCI_VENDOR_ID) != PCI_VENDOR_ID_ATI) {
308c00d61d8SAlex Williamson         return;
309c00d61d8SAlex Williamson     }
310c00d61d8SAlex Williamson 
311c00d61d8SAlex Williamson     quirk = g_malloc0(sizeof(*quirk));
312c00d61d8SAlex Williamson     quirk->vdev = vdev;
313c00d61d8SAlex Williamson     quirk->data.address_size = 4;
314c00d61d8SAlex Williamson     quirk->data.data_offset = 4;
315c00d61d8SAlex Williamson     quirk->data.data_size = 4;
316c00d61d8SAlex Williamson     quirk->data.address_match = 0x4000;
317c00d61d8SAlex Williamson     quirk->data.address_mask = PCIE_CONFIG_SPACE_SIZE - 1;
318c00d61d8SAlex Williamson     quirk->data.bar = nr;
319c00d61d8SAlex Williamson     quirk->data.read_flags = quirk->data.write_flags = 1;
320c00d61d8SAlex Williamson 
321c00d61d8SAlex Williamson     memory_region_init_io(&quirk->mem, OBJECT(vdev),
322c00d61d8SAlex Williamson                           &vfio_generic_window_quirk, quirk,
323c00d61d8SAlex Williamson                           "vfio-ati-bar4-window-quirk", 8);
324c00d61d8SAlex Williamson     memory_region_add_subregion_overlap(&vdev->bars[nr].region.mem,
325c00d61d8SAlex Williamson                           quirk->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;
339c00d61d8SAlex Williamson 
340c00d61d8SAlex Williamson     /* Only enable on newer devices where BAR2 is 64bit */
341c00d61d8SAlex Williamson     if (!vdev->has_vga || nr != 2 || !vdev->bars[2].mem64 ||
342c00d61d8SAlex Williamson         pci_get_word(pdev->config + PCI_VENDOR_ID) != PCI_VENDOR_ID_ATI) {
343c00d61d8SAlex Williamson         return;
344c00d61d8SAlex Williamson     }
345c00d61d8SAlex Williamson 
346c00d61d8SAlex Williamson     quirk = g_malloc0(sizeof(*quirk));
347c00d61d8SAlex Williamson     quirk->vdev = vdev;
348c00d61d8SAlex Williamson     quirk->data.flags = quirk->data.read_flags = quirk->data.write_flags = 1;
349c00d61d8SAlex Williamson     quirk->data.address_match = 0x4000;
350c00d61d8SAlex Williamson     quirk->data.address_mask = PCIE_CONFIG_SPACE_SIZE - 1;
351c00d61d8SAlex Williamson     quirk->data.bar = nr;
352c00d61d8SAlex Williamson 
353c00d61d8SAlex Williamson     memory_region_init_io(&quirk->mem, OBJECT(vdev), &vfio_generic_quirk, quirk,
354c00d61d8SAlex Williamson                           "vfio-ati-bar2-4000-quirk",
355c00d61d8SAlex Williamson                           TARGET_PAGE_ALIGN(quirk->data.address_mask + 1));
356c00d61d8SAlex Williamson     memory_region_add_subregion_overlap(&vdev->bars[nr].region.mem,
357c00d61d8SAlex Williamson                           quirk->data.address_match & TARGET_PAGE_MASK,
358c00d61d8SAlex Williamson                           &quirk->mem, 1);
359c00d61d8SAlex Williamson 
360c00d61d8SAlex Williamson     QLIST_INSERT_HEAD(&vdev->bars[nr].quirks, quirk, next);
361c00d61d8SAlex Williamson 
362c00d61d8SAlex Williamson     trace_vfio_probe_ati_bar2_4000_quirk(vdev->vbasedev.name);
363c00d61d8SAlex Williamson }
364c00d61d8SAlex Williamson 
365c00d61d8SAlex Williamson /*
366c00d61d8SAlex Williamson  * Older ATI/AMD cards like the X550 have a similar window to that above.
367c00d61d8SAlex Williamson  * I/O port BAR1 provides a window to a mirror of PCI config space located
368c00d61d8SAlex Williamson  * in BAR2 at offset 0xf00.  We don't care to support such older cards, but
369c00d61d8SAlex Williamson  * note it for future reference.
370c00d61d8SAlex Williamson  */
371c00d61d8SAlex Williamson 
372c00d61d8SAlex Williamson #define PCI_VENDOR_ID_NVIDIA                    0x10de
373c00d61d8SAlex Williamson 
374c00d61d8SAlex Williamson /*
375c00d61d8SAlex Williamson  * Nvidia has several different methods to get to config space, the
376c00d61d8SAlex Williamson  * nouveu project has several of these documented here:
377c00d61d8SAlex Williamson  * https://github.com/pathscale/envytools/tree/master/hwdocs
378c00d61d8SAlex Williamson  *
379c00d61d8SAlex Williamson  * The first quirk is actually not documented in envytools and is found
380c00d61d8SAlex Williamson  * on 10de:01d1 (NVIDIA Corporation G72 [GeForce 7300 LE]).  This is an
381c00d61d8SAlex Williamson  * NV46 chipset.  The backdoor uses the legacy VGA I/O ports to access
382c00d61d8SAlex Williamson  * the mirror of PCI config space found at BAR0 offset 0x1800.  The access
383c00d61d8SAlex Williamson  * sequence first writes 0x338 to I/O port 0x3d4.  The target offset is
384c00d61d8SAlex Williamson  * then written to 0x3d0.  Finally 0x538 is written for a read and 0x738
385c00d61d8SAlex Williamson  * is written for a write to 0x3d4.  The BAR0 offset is then accessible
386c00d61d8SAlex Williamson  * through 0x3d0.  This quirk doesn't seem to be necessary on newer cards
387c00d61d8SAlex Williamson  * that use the I/O port BAR5 window but it doesn't hurt to leave it.
388c00d61d8SAlex Williamson  */
389c00d61d8SAlex Williamson enum {
390c00d61d8SAlex Williamson     NV_3D0_NONE = 0,
391c00d61d8SAlex Williamson     NV_3D0_SELECT,
392c00d61d8SAlex Williamson     NV_3D0_WINDOW,
393c00d61d8SAlex Williamson     NV_3D0_READ,
394c00d61d8SAlex Williamson     NV_3D0_WRITE,
395c00d61d8SAlex Williamson };
396c00d61d8SAlex Williamson 
397c00d61d8SAlex Williamson static uint64_t vfio_nvidia_3d0_quirk_read(void *opaque,
398c00d61d8SAlex Williamson                                            hwaddr addr, unsigned size)
399c00d61d8SAlex Williamson {
400c00d61d8SAlex Williamson     VFIOQuirk *quirk = opaque;
401c00d61d8SAlex Williamson     VFIOPCIDevice *vdev = quirk->vdev;
402c00d61d8SAlex Williamson     PCIDevice *pdev = &vdev->pdev;
403c00d61d8SAlex Williamson     uint64_t data = vfio_vga_read(&vdev->vga.region[QEMU_PCI_VGA_IO_HI],
404c00d61d8SAlex Williamson                                   addr + quirk->data.base_offset, size);
405c00d61d8SAlex Williamson 
406c00d61d8SAlex Williamson     if (quirk->data.flags == NV_3D0_READ && addr == quirk->data.data_offset) {
407c00d61d8SAlex Williamson         data = vfio_pci_read_config(pdev, quirk->data.address_val, size);
408c00d61d8SAlex Williamson         trace_vfio_nvidia_3d0_quirk_read(size, data);
409c00d61d8SAlex Williamson     }
410c00d61d8SAlex Williamson 
411c00d61d8SAlex Williamson     quirk->data.flags = NV_3D0_NONE;
412c00d61d8SAlex Williamson 
413c00d61d8SAlex Williamson     return data;
414c00d61d8SAlex Williamson }
415c00d61d8SAlex Williamson 
416c00d61d8SAlex Williamson static void vfio_nvidia_3d0_quirk_write(void *opaque, hwaddr addr,
417c00d61d8SAlex Williamson                                         uint64_t data, unsigned size)
418c00d61d8SAlex Williamson {
419c00d61d8SAlex Williamson     VFIOQuirk *quirk = opaque;
420c00d61d8SAlex Williamson     VFIOPCIDevice *vdev = quirk->vdev;
421c00d61d8SAlex Williamson     PCIDevice *pdev = &vdev->pdev;
422c00d61d8SAlex Williamson 
423c00d61d8SAlex Williamson     switch (quirk->data.flags) {
424c00d61d8SAlex Williamson     case NV_3D0_NONE:
425c00d61d8SAlex Williamson         if (addr == quirk->data.address_offset && data == 0x338) {
426c00d61d8SAlex Williamson             quirk->data.flags = NV_3D0_SELECT;
427c00d61d8SAlex Williamson         }
428c00d61d8SAlex Williamson         break;
429c00d61d8SAlex Williamson     case NV_3D0_SELECT:
430c00d61d8SAlex Williamson         quirk->data.flags = NV_3D0_NONE;
431c00d61d8SAlex Williamson         if (addr == quirk->data.data_offset &&
432c00d61d8SAlex Williamson             (data & ~quirk->data.address_mask) == quirk->data.address_match) {
433c00d61d8SAlex Williamson             quirk->data.flags = NV_3D0_WINDOW;
434c00d61d8SAlex Williamson             quirk->data.address_val = data & quirk->data.address_mask;
435c00d61d8SAlex Williamson         }
436c00d61d8SAlex Williamson         break;
437c00d61d8SAlex Williamson     case NV_3D0_WINDOW:
438c00d61d8SAlex Williamson         quirk->data.flags = NV_3D0_NONE;
439c00d61d8SAlex Williamson         if (addr == quirk->data.address_offset) {
440c00d61d8SAlex Williamson             if (data == 0x538) {
441c00d61d8SAlex Williamson                 quirk->data.flags = NV_3D0_READ;
442c00d61d8SAlex Williamson             } else if (data == 0x738) {
443c00d61d8SAlex Williamson                 quirk->data.flags = NV_3D0_WRITE;
444c00d61d8SAlex Williamson             }
445c00d61d8SAlex Williamson         }
446c00d61d8SAlex Williamson         break;
447c00d61d8SAlex Williamson     case NV_3D0_WRITE:
448c00d61d8SAlex Williamson         quirk->data.flags = NV_3D0_NONE;
449c00d61d8SAlex Williamson         if (addr == quirk->data.data_offset) {
450c00d61d8SAlex Williamson             vfio_pci_write_config(pdev, quirk->data.address_val, data, size);
451c00d61d8SAlex Williamson             trace_vfio_nvidia_3d0_quirk_write(data, size);
452c00d61d8SAlex Williamson             return;
453c00d61d8SAlex Williamson         }
454c00d61d8SAlex Williamson         break;
455c00d61d8SAlex Williamson     }
456c00d61d8SAlex Williamson 
457c00d61d8SAlex Williamson     vfio_vga_write(&vdev->vga.region[QEMU_PCI_VGA_IO_HI],
458c00d61d8SAlex Williamson                    addr + quirk->data.base_offset, data, size);
459c00d61d8SAlex Williamson }
460c00d61d8SAlex Williamson 
461c00d61d8SAlex Williamson static const MemoryRegionOps vfio_nvidia_3d0_quirk = {
462c00d61d8SAlex Williamson     .read = vfio_nvidia_3d0_quirk_read,
463c00d61d8SAlex Williamson     .write = vfio_nvidia_3d0_quirk_write,
464c00d61d8SAlex Williamson     .endianness = DEVICE_LITTLE_ENDIAN,
465c00d61d8SAlex Williamson };
466c00d61d8SAlex Williamson 
467c00d61d8SAlex Williamson static void vfio_vga_probe_nvidia_3d0_quirk(VFIOPCIDevice *vdev)
468c00d61d8SAlex Williamson {
469c00d61d8SAlex Williamson     PCIDevice *pdev = &vdev->pdev;
470c00d61d8SAlex Williamson     VFIOQuirk *quirk;
471c00d61d8SAlex Williamson 
472c00d61d8SAlex Williamson     if (pci_get_word(pdev->config + PCI_VENDOR_ID) != PCI_VENDOR_ID_NVIDIA ||
473c00d61d8SAlex Williamson         !vdev->bars[1].region.size) {
474c00d61d8SAlex Williamson         return;
475c00d61d8SAlex Williamson     }
476c00d61d8SAlex Williamson 
477c00d61d8SAlex Williamson     quirk = g_malloc0(sizeof(*quirk));
478c00d61d8SAlex Williamson     quirk->vdev = vdev;
479c00d61d8SAlex Williamson     quirk->data.base_offset = 0x10;
480c00d61d8SAlex Williamson     quirk->data.address_offset = 4;
481c00d61d8SAlex Williamson     quirk->data.address_size = 2;
482c00d61d8SAlex Williamson     quirk->data.address_match = 0x1800;
483c00d61d8SAlex Williamson     quirk->data.address_mask = PCI_CONFIG_SPACE_SIZE - 1;
484c00d61d8SAlex Williamson     quirk->data.data_offset = 0;
485c00d61d8SAlex Williamson     quirk->data.data_size = 4;
486c00d61d8SAlex Williamson 
487c00d61d8SAlex Williamson     memory_region_init_io(&quirk->mem, OBJECT(vdev), &vfio_nvidia_3d0_quirk,
488c00d61d8SAlex Williamson                           quirk, "vfio-nvidia-3d0-quirk", 6);
489c00d61d8SAlex Williamson     memory_region_add_subregion(&vdev->vga.region[QEMU_PCI_VGA_IO_HI].mem,
490c00d61d8SAlex Williamson                                 quirk->data.base_offset, &quirk->mem);
491c00d61d8SAlex Williamson 
492c00d61d8SAlex Williamson     QLIST_INSERT_HEAD(&vdev->vga.region[QEMU_PCI_VGA_IO_HI].quirks,
493c00d61d8SAlex Williamson                       quirk, next);
494c00d61d8SAlex Williamson 
495c00d61d8SAlex Williamson     trace_vfio_vga_probe_nvidia_3d0_quirk(vdev->vbasedev.name);
496c00d61d8SAlex Williamson }
497c00d61d8SAlex Williamson 
498c00d61d8SAlex Williamson /*
499c00d61d8SAlex Williamson  * The second quirk is documented in envytools.  The I/O port BAR5 is just
500c00d61d8SAlex Williamson  * a set of address/data ports to the MMIO BARs.  The BAR we care about is
501c00d61d8SAlex Williamson  * again BAR0.  This backdoor is apparently a bit newer than the one above
502c00d61d8SAlex Williamson  * so we need to not only trap 256 bytes @0x1800, but all of PCI config
503c00d61d8SAlex Williamson  * space, including extended space is available at the 4k @0x88000.
504c00d61d8SAlex Williamson  */
505c00d61d8SAlex Williamson enum {
506c00d61d8SAlex Williamson     NV_BAR5_ADDRESS = 0x1,
507c00d61d8SAlex Williamson     NV_BAR5_ENABLE = 0x2,
508c00d61d8SAlex Williamson     NV_BAR5_MASTER = 0x4,
509c00d61d8SAlex Williamson     NV_BAR5_VALID = 0x7,
510c00d61d8SAlex Williamson };
511c00d61d8SAlex Williamson 
512c00d61d8SAlex Williamson static void vfio_nvidia_bar5_window_quirk_write(void *opaque, hwaddr addr,
513c00d61d8SAlex Williamson                                                 uint64_t data, unsigned size)
514c00d61d8SAlex Williamson {
515c00d61d8SAlex Williamson     VFIOQuirk *quirk = opaque;
516c00d61d8SAlex Williamson 
517c00d61d8SAlex Williamson     switch (addr) {
518c00d61d8SAlex Williamson     case 0x0:
519c00d61d8SAlex Williamson         if (data & 0x1) {
520c00d61d8SAlex Williamson             quirk->data.flags |= NV_BAR5_MASTER;
521c00d61d8SAlex Williamson         } else {
522c00d61d8SAlex Williamson             quirk->data.flags &= ~NV_BAR5_MASTER;
523c00d61d8SAlex Williamson         }
524c00d61d8SAlex Williamson         break;
525c00d61d8SAlex Williamson     case 0x4:
526c00d61d8SAlex Williamson         if (data & 0x1) {
527c00d61d8SAlex Williamson             quirk->data.flags |= NV_BAR5_ENABLE;
528c00d61d8SAlex Williamson         } else {
529c00d61d8SAlex Williamson             quirk->data.flags &= ~NV_BAR5_ENABLE;
530c00d61d8SAlex Williamson         }
531c00d61d8SAlex Williamson         break;
532c00d61d8SAlex Williamson     case 0x8:
533c00d61d8SAlex Williamson         if (quirk->data.flags & NV_BAR5_MASTER) {
534c00d61d8SAlex Williamson             if ((data & ~0xfff) == 0x88000) {
535c00d61d8SAlex Williamson                 quirk->data.flags |= NV_BAR5_ADDRESS;
536c00d61d8SAlex Williamson                 quirk->data.address_val = data & 0xfff;
537c00d61d8SAlex Williamson             } else if ((data & ~0xff) == 0x1800) {
538c00d61d8SAlex Williamson                 quirk->data.flags |= NV_BAR5_ADDRESS;
539c00d61d8SAlex Williamson                 quirk->data.address_val = data & 0xff;
540c00d61d8SAlex Williamson             } else {
541c00d61d8SAlex Williamson                 quirk->data.flags &= ~NV_BAR5_ADDRESS;
542c00d61d8SAlex Williamson             }
543c00d61d8SAlex Williamson         }
544c00d61d8SAlex Williamson         break;
545c00d61d8SAlex Williamson     }
546c00d61d8SAlex Williamson 
547c00d61d8SAlex Williamson     vfio_generic_window_quirk_write(opaque, addr, data, size);
548c00d61d8SAlex Williamson }
549c00d61d8SAlex Williamson 
550c00d61d8SAlex Williamson static const MemoryRegionOps vfio_nvidia_bar5_window_quirk = {
551c00d61d8SAlex Williamson     .read = vfio_generic_window_quirk_read,
552c00d61d8SAlex Williamson     .write = vfio_nvidia_bar5_window_quirk_write,
553c00d61d8SAlex Williamson     .valid.min_access_size = 4,
554c00d61d8SAlex Williamson     .endianness = DEVICE_LITTLE_ENDIAN,
555c00d61d8SAlex Williamson };
556c00d61d8SAlex Williamson 
557c00d61d8SAlex Williamson static void vfio_probe_nvidia_bar5_window_quirk(VFIOPCIDevice *vdev, int nr)
558c00d61d8SAlex Williamson {
559c00d61d8SAlex Williamson     PCIDevice *pdev = &vdev->pdev;
560c00d61d8SAlex Williamson     VFIOQuirk *quirk;
561c00d61d8SAlex Williamson 
562c00d61d8SAlex Williamson     if (!vdev->has_vga || nr != 5 ||
563c00d61d8SAlex Williamson         pci_get_word(pdev->config + PCI_VENDOR_ID) != PCI_VENDOR_ID_NVIDIA) {
564c00d61d8SAlex Williamson         return;
565c00d61d8SAlex Williamson     }
566c00d61d8SAlex Williamson 
567c00d61d8SAlex Williamson     quirk = g_malloc0(sizeof(*quirk));
568c00d61d8SAlex Williamson     quirk->vdev = vdev;
569c00d61d8SAlex Williamson     quirk->data.read_flags = quirk->data.write_flags = NV_BAR5_VALID;
570c00d61d8SAlex Williamson     quirk->data.address_offset = 0x8;
571c00d61d8SAlex Williamson     quirk->data.address_size = 0; /* actually 4, but avoids generic code */
572c00d61d8SAlex Williamson     quirk->data.data_offset = 0xc;
573c00d61d8SAlex Williamson     quirk->data.data_size = 4;
574c00d61d8SAlex Williamson     quirk->data.bar = nr;
575c00d61d8SAlex Williamson 
576c00d61d8SAlex Williamson     memory_region_init_io(&quirk->mem, OBJECT(vdev),
577c00d61d8SAlex Williamson                           &vfio_nvidia_bar5_window_quirk, quirk,
578c00d61d8SAlex Williamson                           "vfio-nvidia-bar5-window-quirk", 16);
579c00d61d8SAlex Williamson     memory_region_add_subregion_overlap(&vdev->bars[nr].region.mem,
580c00d61d8SAlex Williamson                                         0, &quirk->mem, 1);
581c00d61d8SAlex Williamson 
582c00d61d8SAlex Williamson     QLIST_INSERT_HEAD(&vdev->bars[nr].quirks, quirk, next);
583c00d61d8SAlex Williamson 
584c00d61d8SAlex Williamson     trace_vfio_probe_nvidia_bar5_window_quirk(vdev->vbasedev.name);
585c00d61d8SAlex Williamson }
586c00d61d8SAlex Williamson 
587c00d61d8SAlex Williamson static void vfio_nvidia_88000_quirk_write(void *opaque, hwaddr addr,
588c00d61d8SAlex Williamson                                           uint64_t data, unsigned size)
589c00d61d8SAlex Williamson {
590c00d61d8SAlex Williamson     VFIOQuirk *quirk = opaque;
591c00d61d8SAlex Williamson     VFIOPCIDevice *vdev = quirk->vdev;
592c00d61d8SAlex Williamson     PCIDevice *pdev = &vdev->pdev;
593c00d61d8SAlex Williamson     hwaddr base = quirk->data.address_match & TARGET_PAGE_MASK;
594c00d61d8SAlex Williamson 
595c00d61d8SAlex Williamson     vfio_generic_quirk_write(opaque, addr, data, size);
596c00d61d8SAlex Williamson 
597c00d61d8SAlex Williamson     /*
598c00d61d8SAlex Williamson      * Nvidia seems to acknowledge MSI interrupts by writing 0xff to the
599c00d61d8SAlex Williamson      * MSI capability ID register.  Both the ID and next register are
600c00d61d8SAlex Williamson      * read-only, so we allow writes covering either of those to real hw.
601c00d61d8SAlex Williamson      * NB - only fixed for the 0x88000 MMIO window.
602c00d61d8SAlex Williamson      */
603c00d61d8SAlex Williamson     if ((pdev->cap_present & QEMU_PCI_CAP_MSI) &&
604c00d61d8SAlex Williamson         vfio_range_contained(addr, size, pdev->msi_cap, PCI_MSI_FLAGS)) {
605c00d61d8SAlex Williamson         vfio_region_write(&vdev->bars[quirk->data.bar].region,
606c00d61d8SAlex Williamson                           addr + base, data, size);
607c00d61d8SAlex Williamson     }
608c00d61d8SAlex Williamson }
609c00d61d8SAlex Williamson 
610c00d61d8SAlex Williamson static const MemoryRegionOps vfio_nvidia_88000_quirk = {
611c00d61d8SAlex Williamson     .read = vfio_generic_quirk_read,
612c00d61d8SAlex Williamson     .write = vfio_nvidia_88000_quirk_write,
613c00d61d8SAlex Williamson     .endianness = DEVICE_LITTLE_ENDIAN,
614c00d61d8SAlex Williamson };
615c00d61d8SAlex Williamson 
616c00d61d8SAlex Williamson /*
617c00d61d8SAlex Williamson  * Finally, BAR0 itself.  We want to redirect any accesses to either
618c00d61d8SAlex Williamson  * 0x1800 or 0x88000 through the PCI config space access functions.
619c00d61d8SAlex Williamson  *
620c00d61d8SAlex Williamson  * NB - quirk at a page granularity or else they don't seem to work when
621c00d61d8SAlex Williamson  *      BARs are mmap'd
622c00d61d8SAlex Williamson  *
623c00d61d8SAlex Williamson  * Here's offset 0x88000...
624c00d61d8SAlex Williamson  */
625c00d61d8SAlex Williamson static void vfio_probe_nvidia_bar0_88000_quirk(VFIOPCIDevice *vdev, int nr)
626c00d61d8SAlex Williamson {
627c00d61d8SAlex Williamson     PCIDevice *pdev = &vdev->pdev;
628c00d61d8SAlex Williamson     VFIOQuirk *quirk;
629c00d61d8SAlex Williamson     uint16_t vendor, class;
630c00d61d8SAlex Williamson 
631c00d61d8SAlex Williamson     vendor = pci_get_word(pdev->config + PCI_VENDOR_ID);
632c00d61d8SAlex Williamson     class = pci_get_word(pdev->config + PCI_CLASS_DEVICE);
633c00d61d8SAlex Williamson 
634c00d61d8SAlex Williamson     if (nr != 0 || vendor != PCI_VENDOR_ID_NVIDIA ||
635c00d61d8SAlex Williamson         class != PCI_CLASS_DISPLAY_VGA) {
636c00d61d8SAlex Williamson         return;
637c00d61d8SAlex Williamson     }
638c00d61d8SAlex Williamson 
639c00d61d8SAlex Williamson     quirk = g_malloc0(sizeof(*quirk));
640c00d61d8SAlex Williamson     quirk->vdev = vdev;
641c00d61d8SAlex Williamson     quirk->data.flags = quirk->data.read_flags = quirk->data.write_flags = 1;
642c00d61d8SAlex Williamson     quirk->data.address_match = 0x88000;
643c00d61d8SAlex Williamson     quirk->data.address_mask = PCIE_CONFIG_SPACE_SIZE - 1;
644c00d61d8SAlex Williamson     quirk->data.bar = nr;
645c00d61d8SAlex Williamson 
646c00d61d8SAlex Williamson     memory_region_init_io(&quirk->mem, OBJECT(vdev), &vfio_nvidia_88000_quirk,
647c00d61d8SAlex Williamson                           quirk, "vfio-nvidia-bar0-88000-quirk",
648c00d61d8SAlex Williamson                           TARGET_PAGE_ALIGN(quirk->data.address_mask + 1));
649c00d61d8SAlex Williamson     memory_region_add_subregion_overlap(&vdev->bars[nr].region.mem,
650c00d61d8SAlex Williamson                           quirk->data.address_match & TARGET_PAGE_MASK,
651c00d61d8SAlex Williamson                           &quirk->mem, 1);
652c00d61d8SAlex Williamson 
653c00d61d8SAlex Williamson     QLIST_INSERT_HEAD(&vdev->bars[nr].quirks, quirk, next);
654c00d61d8SAlex Williamson 
655c00d61d8SAlex Williamson     trace_vfio_probe_nvidia_bar0_88000_quirk(vdev->vbasedev.name);
656c00d61d8SAlex Williamson }
657c00d61d8SAlex Williamson 
658c00d61d8SAlex Williamson /*
659c00d61d8SAlex Williamson  * And here's the same for BAR0 offset 0x1800...
660c00d61d8SAlex Williamson  */
661c00d61d8SAlex Williamson static void vfio_probe_nvidia_bar0_1800_quirk(VFIOPCIDevice *vdev, int nr)
662c00d61d8SAlex Williamson {
663c00d61d8SAlex Williamson     PCIDevice *pdev = &vdev->pdev;
664c00d61d8SAlex Williamson     VFIOQuirk *quirk;
665c00d61d8SAlex Williamson 
666c00d61d8SAlex Williamson     if (!vdev->has_vga || nr != 0 ||
667c00d61d8SAlex Williamson         pci_get_word(pdev->config + PCI_VENDOR_ID) != PCI_VENDOR_ID_NVIDIA) {
668c00d61d8SAlex Williamson         return;
669c00d61d8SAlex Williamson     }
670c00d61d8SAlex Williamson 
671c00d61d8SAlex Williamson     /* Log the chipset ID */
672c00d61d8SAlex Williamson     trace_vfio_probe_nvidia_bar0_1800_quirk_id(
673c00d61d8SAlex Williamson             (unsigned int)(vfio_region_read(&vdev->bars[0].region, 0, 4) >> 20)
674c00d61d8SAlex Williamson             & 0xff);
675c00d61d8SAlex Williamson 
676c00d61d8SAlex Williamson     quirk = g_malloc0(sizeof(*quirk));
677c00d61d8SAlex Williamson     quirk->vdev = vdev;
678c00d61d8SAlex Williamson     quirk->data.flags = quirk->data.read_flags = quirk->data.write_flags = 1;
679c00d61d8SAlex Williamson     quirk->data.address_match = 0x1800;
680c00d61d8SAlex Williamson     quirk->data.address_mask = PCI_CONFIG_SPACE_SIZE - 1;
681c00d61d8SAlex Williamson     quirk->data.bar = nr;
682c00d61d8SAlex Williamson 
683c00d61d8SAlex Williamson     memory_region_init_io(&quirk->mem, OBJECT(vdev), &vfio_generic_quirk, quirk,
684c00d61d8SAlex Williamson                           "vfio-nvidia-bar0-1800-quirk",
685c00d61d8SAlex Williamson                           TARGET_PAGE_ALIGN(quirk->data.address_mask + 1));
686c00d61d8SAlex Williamson     memory_region_add_subregion_overlap(&vdev->bars[nr].region.mem,
687c00d61d8SAlex Williamson                           quirk->data.address_match & TARGET_PAGE_MASK,
688c00d61d8SAlex Williamson                           &quirk->mem, 1);
689c00d61d8SAlex Williamson 
690c00d61d8SAlex Williamson     QLIST_INSERT_HEAD(&vdev->bars[nr].quirks, quirk, next);
691c00d61d8SAlex Williamson 
692c00d61d8SAlex Williamson     trace_vfio_probe_nvidia_bar0_1800_quirk(vdev->vbasedev.name);
693c00d61d8SAlex Williamson }
694c00d61d8SAlex Williamson 
695c00d61d8SAlex Williamson /*
696c00d61d8SAlex Williamson  * TODO - Some Nvidia devices provide config access to their companion HDA
697c00d61d8SAlex Williamson  * device and even to their parent bridge via these config space mirrors.
698c00d61d8SAlex Williamson  * Add quirks for those regions.
699c00d61d8SAlex Williamson  */
700c00d61d8SAlex Williamson 
701c00d61d8SAlex Williamson #define PCI_VENDOR_ID_REALTEK 0x10ec
702c00d61d8SAlex Williamson 
703c00d61d8SAlex Williamson /*
704c00d61d8SAlex Williamson  * RTL8168 devices have a backdoor that can access the MSI-X table.  At BAR2
705c00d61d8SAlex Williamson  * offset 0x70 there is a dword data register, offset 0x74 is a dword address
706c00d61d8SAlex Williamson  * register.  According to the Linux r8169 driver, the MSI-X table is addressed
707c00d61d8SAlex Williamson  * when the "type" portion of the address register is set to 0x1.  This appears
708c00d61d8SAlex Williamson  * to be bits 16:30.  Bit 31 is both a write indicator and some sort of
709c00d61d8SAlex Williamson  * "address latched" indicator.  Bits 12:15 are a mask field, which we can
710c00d61d8SAlex Williamson  * ignore because the MSI-X table should always be accessed as a dword (full
711c00d61d8SAlex Williamson  * mask).  Bits 0:11 is offset within the type.
712c00d61d8SAlex Williamson  *
713c00d61d8SAlex Williamson  * Example trace:
714c00d61d8SAlex Williamson  *
715c00d61d8SAlex Williamson  * Read from MSI-X table offset 0
716c00d61d8SAlex Williamson  * vfio: vfio_bar_write(0000:05:00.0:BAR2+0x74, 0x1f000, 4) // store read addr
717c00d61d8SAlex Williamson  * vfio: vfio_bar_read(0000:05:00.0:BAR2+0x74, 4) = 0x8001f000 // latch
718c00d61d8SAlex Williamson  * vfio: vfio_bar_read(0000:05:00.0:BAR2+0x70, 4) = 0xfee00398 // read data
719c00d61d8SAlex Williamson  *
720c00d61d8SAlex Williamson  * Write 0xfee00000 to MSI-X table offset 0
721c00d61d8SAlex Williamson  * vfio: vfio_bar_write(0000:05:00.0:BAR2+0x70, 0xfee00000, 4) // write data
722c00d61d8SAlex Williamson  * vfio: vfio_bar_write(0000:05:00.0:BAR2+0x74, 0x8001f000, 4) // do write
723c00d61d8SAlex Williamson  * vfio: vfio_bar_read(0000:05:00.0:BAR2+0x74, 4) = 0x1f000 // complete
724c00d61d8SAlex Williamson  */
725c00d61d8SAlex Williamson static uint64_t vfio_rtl8168_window_quirk_read(void *opaque,
726c00d61d8SAlex Williamson                                                hwaddr addr, unsigned size)
727c00d61d8SAlex Williamson {
728c00d61d8SAlex Williamson     VFIOQuirk *quirk = opaque;
729c00d61d8SAlex Williamson     VFIOPCIDevice *vdev = quirk->vdev;
730c00d61d8SAlex Williamson     uint64_t val = 0;
731c00d61d8SAlex Williamson 
732c00d61d8SAlex Williamson     if (!quirk->data.flags) { /* Non-MSI-X table access */
733c00d61d8SAlex Williamson         return vfio_region_read(&vdev->bars[quirk->data.bar].region,
734c00d61d8SAlex Williamson                                 addr + 0x70, size);
735c00d61d8SAlex Williamson     }
736c00d61d8SAlex Williamson 
737c00d61d8SAlex Williamson     switch (addr) {
738c00d61d8SAlex Williamson     case 4: /* address */
739c00d61d8SAlex Williamson         val = quirk->data.address_match ^ 0x80000000U; /* latch/complete */
740c00d61d8SAlex Williamson         break;
741c00d61d8SAlex Williamson     case 0: /* data */
742c00d61d8SAlex Williamson         if ((vdev->pdev.cap_present & QEMU_PCI_CAP_MSIX)) {
743c00d61d8SAlex Williamson             memory_region_dispatch_read(&vdev->pdev.msix_table_mmio,
744c00d61d8SAlex Williamson                                 (hwaddr)(quirk->data.address_match & 0xfff),
745c00d61d8SAlex Williamson                                 &val, size, MEMTXATTRS_UNSPECIFIED);
746c00d61d8SAlex Williamson         }
747c00d61d8SAlex Williamson         break;
748c00d61d8SAlex Williamson     }
749c00d61d8SAlex Williamson 
750c00d61d8SAlex Williamson     trace_vfio_rtl8168_quirk_read(vdev->vbasedev.name,
751c00d61d8SAlex Williamson                                   addr ? "address" : "data", val);
752c00d61d8SAlex Williamson     return val;
753c00d61d8SAlex Williamson }
754c00d61d8SAlex Williamson 
755c00d61d8SAlex Williamson static void vfio_rtl8168_window_quirk_write(void *opaque, hwaddr addr,
756c00d61d8SAlex Williamson                                             uint64_t data, unsigned size)
757c00d61d8SAlex Williamson {
758c00d61d8SAlex Williamson     VFIOQuirk *quirk = opaque;
759c00d61d8SAlex Williamson     VFIOPCIDevice *vdev = quirk->vdev;
760c00d61d8SAlex Williamson 
761c00d61d8SAlex Williamson     switch (addr) {
762c00d61d8SAlex Williamson     case 4: /* address */
763c00d61d8SAlex Williamson         if ((data & 0x7fff0000) == 0x10000) { /* MSI-X table */
764c00d61d8SAlex Williamson             quirk->data.flags = 1; /* Activate reads */
765c00d61d8SAlex Williamson             quirk->data.address_match = data;
766c00d61d8SAlex Williamson 
767c00d61d8SAlex Williamson             trace_vfio_rtl8168_quirk_write(vdev->vbasedev.name, data);
768c00d61d8SAlex Williamson 
769c00d61d8SAlex Williamson             if (data & 0x80000000U) { /* Do write */
770c00d61d8SAlex Williamson                 if (vdev->pdev.cap_present & QEMU_PCI_CAP_MSIX) {
771c00d61d8SAlex Williamson                     hwaddr offset = data & 0xfff;
772c00d61d8SAlex Williamson                     uint64_t val = quirk->data.address_mask;
773c00d61d8SAlex Williamson 
774c00d61d8SAlex Williamson                     trace_vfio_rtl8168_quirk_msix(vdev->vbasedev.name,
775c00d61d8SAlex Williamson                                                   (uint16_t)offset, val);
776c00d61d8SAlex Williamson 
777c00d61d8SAlex Williamson                     /* Write to the proper guest MSI-X table instead */
778c00d61d8SAlex Williamson                     memory_region_dispatch_write(&vdev->pdev.msix_table_mmio,
779c00d61d8SAlex Williamson                                                  offset, val, size,
780c00d61d8SAlex Williamson                                                  MEMTXATTRS_UNSPECIFIED);
781c00d61d8SAlex Williamson                 }
782c00d61d8SAlex Williamson                 return; /* Do not write guest MSI-X data to hardware */
783c00d61d8SAlex Williamson             }
784c00d61d8SAlex Williamson         } else {
785c00d61d8SAlex Williamson             quirk->data.flags = 0; /* De-activate reads, non-MSI-X */
786c00d61d8SAlex Williamson         }
787c00d61d8SAlex Williamson         break;
788c00d61d8SAlex Williamson     case 0: /* data */
789c00d61d8SAlex Williamson         quirk->data.address_mask = data;
790c00d61d8SAlex Williamson         break;
791c00d61d8SAlex Williamson     }
792c00d61d8SAlex Williamson 
793c00d61d8SAlex Williamson     vfio_region_write(&vdev->bars[quirk->data.bar].region,
794c00d61d8SAlex Williamson                       addr + 0x70, data, size);
795c00d61d8SAlex Williamson }
796c00d61d8SAlex Williamson 
797c00d61d8SAlex Williamson static const MemoryRegionOps vfio_rtl8168_window_quirk = {
798c00d61d8SAlex Williamson     .read = vfio_rtl8168_window_quirk_read,
799c00d61d8SAlex Williamson     .write = vfio_rtl8168_window_quirk_write,
800c00d61d8SAlex Williamson     .valid = {
801c00d61d8SAlex Williamson         .min_access_size = 4,
802c00d61d8SAlex Williamson         .max_access_size = 4,
803c00d61d8SAlex Williamson         .unaligned = false,
804c00d61d8SAlex Williamson     },
805c00d61d8SAlex Williamson     .endianness = DEVICE_LITTLE_ENDIAN,
806c00d61d8SAlex Williamson };
807c00d61d8SAlex Williamson 
808c00d61d8SAlex Williamson static void vfio_probe_rtl8168_bar2_window_quirk(VFIOPCIDevice *vdev, int nr)
809c00d61d8SAlex Williamson {
810c00d61d8SAlex Williamson     PCIDevice *pdev = &vdev->pdev;
811c00d61d8SAlex Williamson     VFIOQuirk *quirk;
812c00d61d8SAlex Williamson 
813c00d61d8SAlex Williamson     if (pci_get_word(pdev->config + PCI_VENDOR_ID) != PCI_VENDOR_ID_REALTEK ||
814c00d61d8SAlex Williamson         pci_get_word(pdev->config + PCI_DEVICE_ID) != 0x8168 || nr != 2) {
815c00d61d8SAlex Williamson         return;
816c00d61d8SAlex Williamson     }
817c00d61d8SAlex Williamson 
818c00d61d8SAlex Williamson     quirk = g_malloc0(sizeof(*quirk));
819c00d61d8SAlex Williamson     quirk->vdev = vdev;
820c00d61d8SAlex Williamson     quirk->data.bar = nr;
821c00d61d8SAlex Williamson 
822c00d61d8SAlex Williamson     memory_region_init_io(&quirk->mem, OBJECT(vdev), &vfio_rtl8168_window_quirk,
823c00d61d8SAlex Williamson                           quirk, "vfio-rtl8168-window-quirk", 8);
824c00d61d8SAlex Williamson     memory_region_add_subregion_overlap(&vdev->bars[nr].region.mem,
825c00d61d8SAlex Williamson                                         0x70, &quirk->mem, 1);
826c00d61d8SAlex Williamson 
827c00d61d8SAlex Williamson     QLIST_INSERT_HEAD(&vdev->bars[nr].quirks, quirk, next);
828c00d61d8SAlex Williamson 
829c00d61d8SAlex Williamson     trace_vfio_rtl8168_quirk_enable(vdev->vbasedev.name);
830c00d61d8SAlex Williamson }
831c00d61d8SAlex Williamson 
832c00d61d8SAlex Williamson /*
833c00d61d8SAlex Williamson  * Common quirk probe entry points.
834c00d61d8SAlex Williamson  */
835c00d61d8SAlex Williamson void vfio_vga_quirk_setup(VFIOPCIDevice *vdev)
836c00d61d8SAlex Williamson {
837c00d61d8SAlex Williamson     vfio_vga_probe_ati_3c3_quirk(vdev);
838c00d61d8SAlex Williamson     vfio_vga_probe_nvidia_3d0_quirk(vdev);
839c00d61d8SAlex Williamson }
840c00d61d8SAlex Williamson 
841c00d61d8SAlex Williamson void vfio_vga_quirk_teardown(VFIOPCIDevice *vdev)
842c00d61d8SAlex Williamson {
843c00d61d8SAlex Williamson     VFIOQuirk *quirk;
844c00d61d8SAlex Williamson     int i;
845c00d61d8SAlex Williamson 
846c00d61d8SAlex Williamson     for (i = 0; i < ARRAY_SIZE(vdev->vga.region); i++) {
847c00d61d8SAlex Williamson         QLIST_FOREACH(quirk, &vdev->vga.region[i].quirks, next) {
848c00d61d8SAlex Williamson             memory_region_del_subregion(&vdev->vga.region[i].mem, &quirk->mem);
849c00d61d8SAlex Williamson         }
850c00d61d8SAlex Williamson     }
851c00d61d8SAlex Williamson }
852c00d61d8SAlex Williamson 
853c00d61d8SAlex Williamson void vfio_vga_quirk_free(VFIOPCIDevice *vdev)
854c00d61d8SAlex Williamson {
855c00d61d8SAlex Williamson     int i;
856c00d61d8SAlex Williamson 
857c00d61d8SAlex Williamson     for (i = 0; i < ARRAY_SIZE(vdev->vga.region); i++) {
858c00d61d8SAlex Williamson         while (!QLIST_EMPTY(&vdev->vga.region[i].quirks)) {
859c00d61d8SAlex Williamson             VFIOQuirk *quirk = QLIST_FIRST(&vdev->vga.region[i].quirks);
860c00d61d8SAlex Williamson             object_unparent(OBJECT(&quirk->mem));
861c00d61d8SAlex Williamson             QLIST_REMOVE(quirk, next);
862c00d61d8SAlex Williamson             g_free(quirk);
863c00d61d8SAlex Williamson         }
864c00d61d8SAlex Williamson     }
865c00d61d8SAlex Williamson }
866c00d61d8SAlex Williamson 
867c00d61d8SAlex Williamson void vfio_bar_quirk_setup(VFIOPCIDevice *vdev, int nr)
868c00d61d8SAlex Williamson {
869c00d61d8SAlex Williamson     vfio_probe_ati_bar4_window_quirk(vdev, nr);
870c00d61d8SAlex Williamson     vfio_probe_ati_bar2_4000_quirk(vdev, nr);
871c00d61d8SAlex Williamson     vfio_probe_nvidia_bar5_window_quirk(vdev, nr);
872c00d61d8SAlex Williamson     vfio_probe_nvidia_bar0_88000_quirk(vdev, nr);
873c00d61d8SAlex Williamson     vfio_probe_nvidia_bar0_1800_quirk(vdev, nr);
874c00d61d8SAlex Williamson     vfio_probe_rtl8168_bar2_window_quirk(vdev, nr);
875c00d61d8SAlex Williamson }
876c00d61d8SAlex Williamson 
877c00d61d8SAlex Williamson void vfio_bar_quirk_teardown(VFIOPCIDevice *vdev, int nr)
878c00d61d8SAlex Williamson {
879c00d61d8SAlex Williamson     VFIOBAR *bar = &vdev->bars[nr];
880c00d61d8SAlex Williamson     VFIOQuirk *quirk;
881c00d61d8SAlex Williamson 
882c00d61d8SAlex Williamson     QLIST_FOREACH(quirk, &bar->quirks, next) {
883c00d61d8SAlex Williamson         memory_region_del_subregion(&bar->region.mem, &quirk->mem);
884c00d61d8SAlex Williamson     }
885c00d61d8SAlex Williamson }
886c00d61d8SAlex Williamson 
887c00d61d8SAlex Williamson void vfio_bar_quirk_free(VFIOPCIDevice *vdev, int nr)
888c00d61d8SAlex Williamson {
889c00d61d8SAlex Williamson     VFIOBAR *bar = &vdev->bars[nr];
890c00d61d8SAlex Williamson 
891c00d61d8SAlex Williamson     while (!QLIST_EMPTY(&bar->quirks)) {
892c00d61d8SAlex Williamson         VFIOQuirk *quirk = QLIST_FIRST(&bar->quirks);
893c00d61d8SAlex Williamson         object_unparent(OBJECT(&quirk->mem));
894c00d61d8SAlex Williamson         QLIST_REMOVE(quirk, next);
895c00d61d8SAlex Williamson         g_free(quirk);
896c00d61d8SAlex Williamson     }
897c00d61d8SAlex Williamson }
898