]>
Commit | Line | Data |
---|---|---|
c00d61d8 AW |
1 | /* |
2 | * device quirks for PCI devices | |
3 | * | |
4 | * Copyright Red Hat, Inc. 2012-2015 | |
5 | * | |
6 | * Authors: | |
7 | * Alex Williamson <alex.williamson@redhat.com> | |
8 | * | |
9 | * This work is licensed under the terms of the GNU GPL, version 2. See | |
10 | * the COPYING file in the top-level directory. | |
11 | */ | |
12 | ||
13 | #include "pci.h" | |
14 | #include "trace.h" | |
15 | #include "qemu/range.h" | |
16 | ||
056dfcb6 AW |
17 | #define PCI_ANY_ID (~0) |
18 | ||
19 | /* Use uin32_t for vendor & device so PCI_ANY_ID expands and cannot match hw */ | |
20 | static bool vfio_pci_is(VFIOPCIDevice *vdev, uint32_t vendor, uint32_t device) | |
21 | { | |
22 | PCIDevice *pdev = &vdev->pdev; | |
23 | ||
24 | return (vendor == PCI_ANY_ID || | |
25 | vendor == pci_get_word(pdev->config + PCI_VENDOR_ID)) && | |
26 | (device == PCI_ANY_ID || | |
27 | device == pci_get_word(pdev->config + PCI_DEVICE_ID)); | |
28 | } | |
29 | ||
0d38fb1c AW |
30 | static bool vfio_is_vga(VFIOPCIDevice *vdev) |
31 | { | |
32 | PCIDevice *pdev = &vdev->pdev; | |
33 | uint16_t class = pci_get_word(pdev->config + PCI_CLASS_DEVICE); | |
34 | ||
35 | return class == PCI_CLASS_DISPLAY_VGA; | |
36 | } | |
37 | ||
c00d61d8 AW |
38 | /* |
39 | * List of device ids/vendor ids for which to disable | |
40 | * option rom loading. This avoids the guest hangs during rom | |
41 | * execution as noticed with the BCM 57810 card for lack of a | |
42 | * more better way to handle such issues. | |
43 | * The user can still override by specifying a romfile or | |
44 | * rombar=1. | |
45 | * Please see https://bugs.launchpad.net/qemu/+bug/1284874 | |
46 | * for an analysis of the 57810 card hang. When adding | |
47 | * a new vendor id/device id combination below, please also add | |
48 | * your card/environment details and information that could | |
49 | * help in debugging to the bug tracking this issue | |
50 | */ | |
056dfcb6 AW |
51 | static const struct { |
52 | uint32_t vendor; | |
53 | uint32_t device; | |
54 | } romblacklist[] = { | |
55 | { 0x14e4, 0x168e }, /* Broadcom BCM 57810 */ | |
c00d61d8 AW |
56 | }; |
57 | ||
58 | bool vfio_blacklist_opt_rom(VFIOPCIDevice *vdev) | |
59 | { | |
056dfcb6 | 60 | int i; |
c00d61d8 | 61 | |
056dfcb6 AW |
62 | for (i = 0 ; i < ARRAY_SIZE(romblacklist); i++) { |
63 | if (vfio_pci_is(vdev, romblacklist[i].vendor, romblacklist[i].device)) { | |
64 | trace_vfio_quirk_rom_blacklisted(vdev->vbasedev.name, | |
65 | romblacklist[i].vendor, | |
66 | romblacklist[i].device); | |
67 | return true; | |
c00d61d8 | 68 | } |
c00d61d8 | 69 | } |
c00d61d8 AW |
70 | return false; |
71 | } | |
72 | ||
73 | /* | |
0e54f24a | 74 | * Device specific region quirks (mostly backdoors to PCI config space) |
c00d61d8 AW |
75 | */ |
76 | ||
0e54f24a AW |
77 | /* |
78 | * The generic window quirks operate on an address and data register, | |
79 | * vfio_generic_window_address_quirk handles the address register and | |
80 | * vfio_generic_window_data_quirk handles the data register. These ops | |
81 | * pass reads and writes through to hardware until a value matching the | |
82 | * stored address match/mask is written. When this occurs, the data | |
83 | * register access emulated PCI config space for the device rather than | |
84 | * passing through accesses. This enables devices where PCI config space | |
85 | * is accessible behind a window register to maintain the virtualization | |
86 | * provided through vfio. | |
87 | */ | |
88 | typedef struct VFIOConfigWindowMatch { | |
89 | uint32_t match; | |
90 | uint32_t mask; | |
91 | } VFIOConfigWindowMatch; | |
92 | ||
93 | typedef struct VFIOConfigWindowQuirk { | |
94 | struct VFIOPCIDevice *vdev; | |
95 | ||
96 | uint32_t address_val; | |
97 | ||
98 | uint32_t address_offset; | |
99 | uint32_t data_offset; | |
100 | ||
101 | bool window_enabled; | |
102 | uint8_t bar; | |
103 | ||
104 | MemoryRegion *addr_mem; | |
105 | MemoryRegion *data_mem; | |
106 | ||
107 | uint32_t nr_matches; | |
108 | VFIOConfigWindowMatch matches[]; | |
109 | } VFIOConfigWindowQuirk; | |
110 | ||
111 | static uint64_t vfio_generic_window_quirk_address_read(void *opaque, | |
112 | hwaddr addr, | |
113 | unsigned size) | |
114 | { | |
115 | VFIOConfigWindowQuirk *window = opaque; | |
116 | VFIOPCIDevice *vdev = window->vdev; | |
117 | ||
118 | return vfio_region_read(&vdev->bars[window->bar].region, | |
119 | addr + window->address_offset, size); | |
120 | } | |
121 | ||
122 | static void vfio_generic_window_quirk_address_write(void *opaque, hwaddr addr, | |
123 | uint64_t data, | |
124 | unsigned size) | |
125 | { | |
126 | VFIOConfigWindowQuirk *window = opaque; | |
127 | VFIOPCIDevice *vdev = window->vdev; | |
128 | int i; | |
129 | ||
130 | window->window_enabled = false; | |
131 | ||
132 | vfio_region_write(&vdev->bars[window->bar].region, | |
133 | addr + window->address_offset, data, size); | |
134 | ||
135 | for (i = 0; i < window->nr_matches; i++) { | |
136 | if ((data & ~window->matches[i].mask) == window->matches[i].match) { | |
137 | window->window_enabled = true; | |
138 | window->address_val = data & window->matches[i].mask; | |
139 | trace_vfio_quirk_generic_window_address_write(vdev->vbasedev.name, | |
140 | memory_region_name(window->addr_mem), data); | |
141 | break; | |
142 | } | |
143 | } | |
144 | } | |
145 | ||
146 | static const MemoryRegionOps vfio_generic_window_address_quirk = { | |
147 | .read = vfio_generic_window_quirk_address_read, | |
148 | .write = vfio_generic_window_quirk_address_write, | |
149 | .endianness = DEVICE_LITTLE_ENDIAN, | |
150 | }; | |
151 | ||
152 | static uint64_t vfio_generic_window_quirk_data_read(void *opaque, | |
153 | hwaddr addr, unsigned size) | |
154 | { | |
155 | VFIOConfigWindowQuirk *window = opaque; | |
156 | VFIOPCIDevice *vdev = window->vdev; | |
157 | uint64_t data; | |
158 | ||
159 | /* Always read data reg, discard if window enabled */ | |
160 | data = vfio_region_read(&vdev->bars[window->bar].region, | |
161 | addr + window->data_offset, size); | |
162 | ||
163 | if (window->window_enabled) { | |
164 | data = vfio_pci_read_config(&vdev->pdev, window->address_val, size); | |
165 | trace_vfio_quirk_generic_window_data_read(vdev->vbasedev.name, | |
166 | memory_region_name(window->data_mem), data); | |
167 | } | |
168 | ||
169 | return data; | |
170 | } | |
171 | ||
172 | static void vfio_generic_window_quirk_data_write(void *opaque, hwaddr addr, | |
173 | uint64_t data, unsigned size) | |
174 | { | |
175 | VFIOConfigWindowQuirk *window = opaque; | |
176 | VFIOPCIDevice *vdev = window->vdev; | |
177 | ||
178 | if (window->window_enabled) { | |
179 | vfio_pci_write_config(&vdev->pdev, window->address_val, data, size); | |
180 | trace_vfio_quirk_generic_window_data_write(vdev->vbasedev.name, | |
181 | memory_region_name(window->data_mem), data); | |
182 | return; | |
183 | } | |
184 | ||
185 | vfio_region_write(&vdev->bars[window->bar].region, | |
186 | addr + window->data_offset, data, size); | |
187 | } | |
188 | ||
189 | static const MemoryRegionOps vfio_generic_window_data_quirk = { | |
190 | .read = vfio_generic_window_quirk_data_read, | |
191 | .write = vfio_generic_window_quirk_data_write, | |
192 | .endianness = DEVICE_LITTLE_ENDIAN, | |
193 | }; | |
194 | ||
0d38fb1c AW |
195 | /* |
196 | * The generic mirror quirk handles devices which expose PCI config space | |
197 | * through a region within a BAR. When enabled, reads and writes are | |
198 | * redirected through to emulated PCI config space. XXX if PCI config space | |
199 | * used memory regions, this could just be an alias. | |
200 | */ | |
201 | typedef struct VFIOConfigMirrorQuirk { | |
202 | struct VFIOPCIDevice *vdev; | |
203 | uint32_t offset; | |
204 | uint8_t bar; | |
205 | MemoryRegion *mem; | |
206 | } VFIOConfigMirrorQuirk; | |
207 | ||
208 | static uint64_t vfio_generic_quirk_mirror_read(void *opaque, | |
209 | hwaddr addr, unsigned size) | |
210 | { | |
211 | VFIOConfigMirrorQuirk *mirror = opaque; | |
212 | VFIOPCIDevice *vdev = mirror->vdev; | |
213 | uint64_t data; | |
214 | ||
215 | /* Read and discard in case the hardware cares */ | |
216 | (void)vfio_region_read(&vdev->bars[mirror->bar].region, | |
217 | addr + mirror->offset, size); | |
218 | ||
219 | data = vfio_pci_read_config(&vdev->pdev, addr, size); | |
220 | trace_vfio_quirk_generic_mirror_read(vdev->vbasedev.name, | |
221 | memory_region_name(mirror->mem), | |
222 | addr, data); | |
223 | return data; | |
224 | } | |
225 | ||
226 | static void vfio_generic_quirk_mirror_write(void *opaque, hwaddr addr, | |
227 | uint64_t data, unsigned size) | |
228 | { | |
229 | VFIOConfigMirrorQuirk *mirror = opaque; | |
230 | VFIOPCIDevice *vdev = mirror->vdev; | |
231 | ||
232 | vfio_pci_write_config(&vdev->pdev, addr, data, size); | |
233 | trace_vfio_quirk_generic_mirror_write(vdev->vbasedev.name, | |
234 | memory_region_name(mirror->mem), | |
235 | addr, data); | |
236 | } | |
237 | ||
238 | static const MemoryRegionOps vfio_generic_mirror_quirk = { | |
239 | .read = vfio_generic_quirk_mirror_read, | |
240 | .write = vfio_generic_quirk_mirror_write, | |
241 | .endianness = DEVICE_LITTLE_ENDIAN, | |
242 | }; | |
243 | ||
c00d61d8 AW |
244 | /* Is range1 fully contained within range2? */ |
245 | static bool vfio_range_contained(uint64_t first1, uint64_t len1, | |
246 | uint64_t first2, uint64_t len2) { | |
247 | return (first1 >= first2 && first1 + len1 <= first2 + len2); | |
248 | } | |
249 | ||
c00d61d8 AW |
250 | #define PCI_VENDOR_ID_ATI 0x1002 |
251 | ||
252 | /* | |
253 | * Radeon HD cards (HD5450 & HD7850) report the upper byte of the I/O port BAR | |
254 | * through VGA register 0x3c3. On newer cards, the I/O port BAR is always | |
255 | * BAR4 (older cards like the X550 used BAR1, but we don't care to support | |
256 | * those). Note that on bare metal, a read of 0x3c3 doesn't always return the | |
257 | * I/O port BAR address. Originally this was coded to return the virtual BAR | |
258 | * address only if the physical register read returns the actual BAR address, | |
259 | * but users have reported greater success if we return the virtual address | |
260 | * unconditionally. | |
261 | */ | |
262 | static uint64_t vfio_ati_3c3_quirk_read(void *opaque, | |
263 | hwaddr addr, unsigned size) | |
264 | { | |
b946d286 | 265 | VFIOPCIDevice *vdev = opaque; |
c00d61d8 | 266 | uint64_t data = vfio_pci_read_config(&vdev->pdev, |
b946d286 AW |
267 | PCI_BASE_ADDRESS_4 + 1, size); |
268 | ||
269 | trace_vfio_quirk_ati_3c3_read(vdev->vbasedev.name, data); | |
c00d61d8 AW |
270 | |
271 | return data; | |
272 | } | |
273 | ||
274 | static const MemoryRegionOps vfio_ati_3c3_quirk = { | |
275 | .read = vfio_ati_3c3_quirk_read, | |
276 | .endianness = DEVICE_LITTLE_ENDIAN, | |
277 | }; | |
278 | ||
279 | static void vfio_vga_probe_ati_3c3_quirk(VFIOPCIDevice *vdev) | |
280 | { | |
c00d61d8 | 281 | VFIOQuirk *quirk; |
c00d61d8 AW |
282 | |
283 | /* | |
284 | * As long as the BAR is >= 256 bytes it will be aligned such that the | |
285 | * lower byte is always zero. Filter out anything else, if it exists. | |
286 | */ | |
b946d286 AW |
287 | if (!vfio_pci_is(vdev, PCI_VENDOR_ID_ATI, PCI_ANY_ID) || |
288 | !vdev->bars[4].ioport || vdev->bars[4].region.size < 256) { | |
c00d61d8 AW |
289 | return; |
290 | } | |
291 | ||
292 | quirk = g_malloc0(sizeof(*quirk)); | |
b946d286 | 293 | quirk->mem = g_malloc0_n(sizeof(MemoryRegion), 1); |
8c4f2348 | 294 | quirk->nr_mem = 1; |
c00d61d8 | 295 | |
b946d286 | 296 | memory_region_init_io(quirk->mem, OBJECT(vdev), &vfio_ati_3c3_quirk, vdev, |
c00d61d8 AW |
297 | "vfio-ati-3c3-quirk", 1); |
298 | memory_region_add_subregion(&vdev->vga.region[QEMU_PCI_VGA_IO_HI].mem, | |
8c4f2348 | 299 | 3 /* offset 3 bytes from 0x3c0 */, quirk->mem); |
c00d61d8 AW |
300 | |
301 | QLIST_INSERT_HEAD(&vdev->vga.region[QEMU_PCI_VGA_IO_HI].quirks, | |
302 | quirk, next); | |
303 | ||
b946d286 | 304 | trace_vfio_quirk_ati_3c3_probe(vdev->vbasedev.name); |
c00d61d8 AW |
305 | } |
306 | ||
307 | /* | |
0e54f24a | 308 | * Newer ATI/AMD devices, including HD5450 and HD7850, have a mirror to PCI |
c00d61d8 AW |
309 | * config space through MMIO BAR2 at offset 0x4000. Nothing seems to access |
310 | * the MMIO space directly, but a window to this space is provided through | |
311 | * I/O port BAR4. Offset 0x0 is the address register and offset 0x4 is the | |
312 | * data register. When the address is programmed to a range of 0x4000-0x4fff | |
313 | * PCI configuration space is available. Experimentation seems to indicate | |
0e54f24a | 314 | * that read-only may be provided by hardware. |
c00d61d8 | 315 | */ |
0e54f24a | 316 | static void vfio_probe_ati_bar4_quirk(VFIOPCIDevice *vdev, int nr) |
c00d61d8 | 317 | { |
c00d61d8 | 318 | VFIOQuirk *quirk; |
0e54f24a | 319 | VFIOConfigWindowQuirk *window; |
c00d61d8 | 320 | |
0e54f24a AW |
321 | /* This windows doesn't seem to be used except by legacy VGA code */ |
322 | if (!vfio_pci_is(vdev, PCI_VENDOR_ID_ATI, PCI_ANY_ID) || | |
323 | !vdev->has_vga || nr != 4) { | |
c00d61d8 AW |
324 | return; |
325 | } | |
326 | ||
327 | quirk = g_malloc0(sizeof(*quirk)); | |
0e54f24a AW |
328 | quirk->mem = g_malloc0_n(sizeof(MemoryRegion), 2); |
329 | quirk->nr_mem = 2; | |
330 | window = quirk->data = g_malloc0(sizeof(*window) + | |
331 | sizeof(VFIOConfigWindowMatch)); | |
332 | window->vdev = vdev; | |
333 | window->address_offset = 0; | |
334 | window->data_offset = 4; | |
335 | window->nr_matches = 1; | |
336 | window->matches[0].match = 0x4000; | |
337 | window->matches[0].mask = PCIE_CONFIG_SPACE_SIZE - 1; | |
338 | window->bar = nr; | |
339 | window->addr_mem = &quirk->mem[0]; | |
340 | window->data_mem = &quirk->mem[1]; | |
341 | ||
342 | memory_region_init_io(window->addr_mem, OBJECT(vdev), | |
343 | &vfio_generic_window_address_quirk, window, | |
344 | "vfio-ati-bar4-window-address-quirk", 4); | |
345 | memory_region_add_subregion_overlap(&vdev->bars[nr].region.mem, | |
346 | window->address_offset, | |
347 | window->addr_mem, 1); | |
8c4f2348 | 348 | |
0e54f24a AW |
349 | memory_region_init_io(window->data_mem, OBJECT(vdev), |
350 | &vfio_generic_window_data_quirk, window, | |
351 | "vfio-ati-bar4-window-data-quirk", 4); | |
c00d61d8 | 352 | memory_region_add_subregion_overlap(&vdev->bars[nr].region.mem, |
0e54f24a AW |
353 | window->data_offset, |
354 | window->data_mem, 1); | |
c00d61d8 AW |
355 | |
356 | QLIST_INSERT_HEAD(&vdev->bars[nr].quirks, quirk, next); | |
357 | ||
0e54f24a | 358 | trace_vfio_quirk_ati_bar4_probe(vdev->vbasedev.name); |
c00d61d8 AW |
359 | } |
360 | ||
361 | /* | |
0d38fb1c | 362 | * Trap the BAR2 MMIO mirror to config space as well. |
c00d61d8 | 363 | */ |
0d38fb1c | 364 | static void vfio_probe_ati_bar2_quirk(VFIOPCIDevice *vdev, int nr) |
c00d61d8 | 365 | { |
c00d61d8 | 366 | VFIOQuirk *quirk; |
0d38fb1c | 367 | VFIOConfigMirrorQuirk *mirror; |
c00d61d8 AW |
368 | |
369 | /* Only enable on newer devices where BAR2 is 64bit */ | |
0d38fb1c AW |
370 | if (!vfio_pci_is(vdev, PCI_VENDOR_ID_ATI, PCI_ANY_ID) || |
371 | !vdev->has_vga || nr != 2 || !vdev->bars[2].mem64) { | |
c00d61d8 AW |
372 | return; |
373 | } | |
374 | ||
375 | quirk = g_malloc0(sizeof(*quirk)); | |
0d38fb1c AW |
376 | mirror = quirk->data = g_malloc0(sizeof(*mirror)); |
377 | mirror->mem = quirk->mem = g_malloc0_n(sizeof(MemoryRegion), 1); | |
8c4f2348 | 378 | quirk->nr_mem = 1; |
0d38fb1c AW |
379 | mirror->vdev = vdev; |
380 | mirror->offset = 0x4000; | |
381 | mirror->bar = nr; | |
382 | ||
383 | memory_region_init_io(mirror->mem, OBJECT(vdev), | |
384 | &vfio_generic_mirror_quirk, mirror, | |
385 | "vfio-ati-bar2-4000-quirk", PCI_CONFIG_SPACE_SIZE); | |
c00d61d8 | 386 | memory_region_add_subregion_overlap(&vdev->bars[nr].region.mem, |
0d38fb1c | 387 | mirror->offset, mirror->mem, 1); |
c00d61d8 AW |
388 | |
389 | QLIST_INSERT_HEAD(&vdev->bars[nr].quirks, quirk, next); | |
390 | ||
0d38fb1c | 391 | trace_vfio_quirk_ati_bar2_probe(vdev->vbasedev.name); |
c00d61d8 AW |
392 | } |
393 | ||
394 | /* | |
395 | * Older ATI/AMD cards like the X550 have a similar window to that above. | |
396 | * I/O port BAR1 provides a window to a mirror of PCI config space located | |
397 | * in BAR2 at offset 0xf00. We don't care to support such older cards, but | |
398 | * note it for future reference. | |
399 | */ | |
400 | ||
401 | #define PCI_VENDOR_ID_NVIDIA 0x10de | |
402 | ||
403 | /* | |
404 | * Nvidia has several different methods to get to config space, the | |
405 | * nouveu project has several of these documented here: | |
406 | * https://github.com/pathscale/envytools/tree/master/hwdocs | |
407 | * | |
408 | * The first quirk is actually not documented in envytools and is found | |
409 | * on 10de:01d1 (NVIDIA Corporation G72 [GeForce 7300 LE]). This is an | |
410 | * NV46 chipset. The backdoor uses the legacy VGA I/O ports to access | |
411 | * the mirror of PCI config space found at BAR0 offset 0x1800. The access | |
412 | * sequence first writes 0x338 to I/O port 0x3d4. The target offset is | |
413 | * then written to 0x3d0. Finally 0x538 is written for a read and 0x738 | |
414 | * is written for a write to 0x3d4. The BAR0 offset is then accessible | |
415 | * through 0x3d0. This quirk doesn't seem to be necessary on newer cards | |
416 | * that use the I/O port BAR5 window but it doesn't hurt to leave it. | |
417 | */ | |
6029a424 AW |
418 | typedef enum {NONE = 0, SELECT, WINDOW, READ, WRITE} VFIONvidia3d0State; |
419 | static const char *nv3d0_states[] = { "NONE", "SELECT", | |
420 | "WINDOW", "READ", "WRITE" }; | |
c00d61d8 | 421 | |
6029a424 AW |
422 | typedef struct VFIONvidia3d0Quirk { |
423 | VFIOPCIDevice *vdev; | |
424 | VFIONvidia3d0State state; | |
425 | uint32_t offset; | |
426 | } VFIONvidia3d0Quirk; | |
427 | ||
428 | static uint64_t vfio_nvidia_3d4_quirk_read(void *opaque, | |
c00d61d8 AW |
429 | hwaddr addr, unsigned size) |
430 | { | |
6029a424 | 431 | VFIONvidia3d0Quirk *quirk = opaque; |
c00d61d8 | 432 | VFIOPCIDevice *vdev = quirk->vdev; |
c00d61d8 | 433 | |
6029a424 | 434 | quirk->state = NONE; |
c00d61d8 | 435 | |
6029a424 AW |
436 | return vfio_vga_read(&vdev->vga.region[QEMU_PCI_VGA_IO_HI], |
437 | addr + 0x14, size); | |
c00d61d8 AW |
438 | } |
439 | ||
6029a424 | 440 | static void vfio_nvidia_3d4_quirk_write(void *opaque, hwaddr addr, |
c00d61d8 AW |
441 | uint64_t data, unsigned size) |
442 | { | |
6029a424 | 443 | VFIONvidia3d0Quirk *quirk = opaque; |
c00d61d8 | 444 | VFIOPCIDevice *vdev = quirk->vdev; |
6029a424 | 445 | VFIONvidia3d0State old_state = quirk->state; |
c00d61d8 | 446 | |
6029a424 AW |
447 | quirk->state = NONE; |
448 | ||
449 | switch (data) { | |
450 | case 0x338: | |
451 | if (old_state == NONE) { | |
452 | quirk->state = SELECT; | |
453 | trace_vfio_quirk_nvidia_3d0_state(vdev->vbasedev.name, | |
454 | nv3d0_states[quirk->state]); | |
c00d61d8 AW |
455 | } |
456 | break; | |
6029a424 AW |
457 | case 0x538: |
458 | if (old_state == WINDOW) { | |
459 | quirk->state = READ; | |
460 | trace_vfio_quirk_nvidia_3d0_state(vdev->vbasedev.name, | |
461 | nv3d0_states[quirk->state]); | |
c00d61d8 AW |
462 | } |
463 | break; | |
6029a424 AW |
464 | case 0x738: |
465 | if (old_state == WINDOW) { | |
466 | quirk->state = WRITE; | |
467 | trace_vfio_quirk_nvidia_3d0_state(vdev->vbasedev.name, | |
468 | nv3d0_states[quirk->state]); | |
c00d61d8 AW |
469 | } |
470 | break; | |
6029a424 AW |
471 | } |
472 | ||
473 | vfio_vga_write(&vdev->vga.region[QEMU_PCI_VGA_IO_HI], | |
474 | addr + 0x14, data, size); | |
475 | } | |
476 | ||
477 | static const MemoryRegionOps vfio_nvidia_3d4_quirk = { | |
478 | .read = vfio_nvidia_3d4_quirk_read, | |
479 | .write = vfio_nvidia_3d4_quirk_write, | |
480 | .endianness = DEVICE_LITTLE_ENDIAN, | |
481 | }; | |
482 | ||
483 | static uint64_t vfio_nvidia_3d0_quirk_read(void *opaque, | |
484 | hwaddr addr, unsigned size) | |
485 | { | |
486 | VFIONvidia3d0Quirk *quirk = opaque; | |
487 | VFIOPCIDevice *vdev = quirk->vdev; | |
488 | VFIONvidia3d0State old_state = quirk->state; | |
489 | uint64_t data = vfio_vga_read(&vdev->vga.region[QEMU_PCI_VGA_IO_HI], | |
490 | addr + 0x10, size); | |
491 | ||
492 | quirk->state = NONE; | |
493 | ||
494 | if (old_state == READ && | |
495 | (quirk->offset & ~(PCI_CONFIG_SPACE_SIZE - 1)) == 0x1800) { | |
496 | uint8_t offset = quirk->offset & (PCI_CONFIG_SPACE_SIZE - 1); | |
497 | ||
498 | data = vfio_pci_read_config(&vdev->pdev, offset, size); | |
499 | trace_vfio_quirk_nvidia_3d0_read(vdev->vbasedev.name, | |
500 | offset, size, data); | |
501 | } | |
502 | ||
503 | return data; | |
504 | } | |
505 | ||
506 | static void vfio_nvidia_3d0_quirk_write(void *opaque, hwaddr addr, | |
507 | uint64_t data, unsigned size) | |
508 | { | |
509 | VFIONvidia3d0Quirk *quirk = opaque; | |
510 | VFIOPCIDevice *vdev = quirk->vdev; | |
511 | VFIONvidia3d0State old_state = quirk->state; | |
512 | ||
513 | quirk->state = NONE; | |
514 | ||
515 | if (old_state == SELECT) { | |
516 | quirk->offset = (uint32_t)data; | |
517 | quirk->state = WINDOW; | |
518 | trace_vfio_quirk_nvidia_3d0_state(vdev->vbasedev.name, | |
519 | nv3d0_states[quirk->state]); | |
520 | } else if (old_state == WRITE) { | |
521 | if ((quirk->offset & ~(PCI_CONFIG_SPACE_SIZE - 1)) == 0x1800) { | |
522 | uint8_t offset = quirk->offset & (PCI_CONFIG_SPACE_SIZE - 1); | |
523 | ||
524 | vfio_pci_write_config(&vdev->pdev, offset, data, size); | |
525 | trace_vfio_quirk_nvidia_3d0_write(vdev->vbasedev.name, | |
526 | offset, data, size); | |
c00d61d8 AW |
527 | return; |
528 | } | |
c00d61d8 AW |
529 | } |
530 | ||
531 | vfio_vga_write(&vdev->vga.region[QEMU_PCI_VGA_IO_HI], | |
6029a424 | 532 | addr + 0x10, data, size); |
c00d61d8 AW |
533 | } |
534 | ||
535 | static const MemoryRegionOps vfio_nvidia_3d0_quirk = { | |
536 | .read = vfio_nvidia_3d0_quirk_read, | |
537 | .write = vfio_nvidia_3d0_quirk_write, | |
538 | .endianness = DEVICE_LITTLE_ENDIAN, | |
539 | }; | |
540 | ||
541 | static void vfio_vga_probe_nvidia_3d0_quirk(VFIOPCIDevice *vdev) | |
542 | { | |
c00d61d8 | 543 | VFIOQuirk *quirk; |
6029a424 | 544 | VFIONvidia3d0Quirk *data; |
c00d61d8 | 545 | |
6029a424 | 546 | if (!vfio_pci_is(vdev, PCI_VENDOR_ID_NVIDIA, PCI_ANY_ID) || |
c00d61d8 AW |
547 | !vdev->bars[1].region.size) { |
548 | return; | |
549 | } | |
550 | ||
551 | quirk = g_malloc0(sizeof(*quirk)); | |
6029a424 AW |
552 | quirk->data = data = g_malloc0(sizeof(*data)); |
553 | quirk->mem = g_malloc0_n(sizeof(MemoryRegion), 2); | |
554 | quirk->nr_mem = 2; | |
555 | data->vdev = vdev; | |
556 | ||
557 | memory_region_init_io(&quirk->mem[0], OBJECT(vdev), &vfio_nvidia_3d4_quirk, | |
558 | data, "vfio-nvidia-3d4-quirk", 2); | |
559 | memory_region_add_subregion(&vdev->vga.region[QEMU_PCI_VGA_IO_HI].mem, | |
560 | 0x14 /* 0x3c0 + 0x14 */, &quirk->mem[0]); | |
8c4f2348 | 561 | |
6029a424 AW |
562 | memory_region_init_io(&quirk->mem[1], OBJECT(vdev), &vfio_nvidia_3d0_quirk, |
563 | data, "vfio-nvidia-3d0-quirk", 2); | |
c00d61d8 | 564 | memory_region_add_subregion(&vdev->vga.region[QEMU_PCI_VGA_IO_HI].mem, |
6029a424 | 565 | 0x10 /* 0x3c0 + 0x10 */, &quirk->mem[1]); |
c00d61d8 AW |
566 | |
567 | QLIST_INSERT_HEAD(&vdev->vga.region[QEMU_PCI_VGA_IO_HI].quirks, | |
568 | quirk, next); | |
569 | ||
6029a424 | 570 | trace_vfio_quirk_nvidia_3d0_probe(vdev->vbasedev.name); |
c00d61d8 AW |
571 | } |
572 | ||
573 | /* | |
574 | * The second quirk is documented in envytools. The I/O port BAR5 is just | |
575 | * a set of address/data ports to the MMIO BARs. The BAR we care about is | |
576 | * again BAR0. This backdoor is apparently a bit newer than the one above | |
577 | * so we need to not only trap 256 bytes @0x1800, but all of PCI config | |
578 | * space, including extended space is available at the 4k @0x88000. | |
579 | */ | |
0e54f24a AW |
580 | typedef struct VFIONvidiaBAR5Quirk { |
581 | uint32_t master; | |
582 | uint32_t enable; | |
583 | MemoryRegion *addr_mem; | |
584 | MemoryRegion *data_mem; | |
585 | bool enabled; | |
586 | VFIOConfigWindowQuirk window; /* last for match data */ | |
587 | } VFIONvidiaBAR5Quirk; | |
588 | ||
589 | static void vfio_nvidia_bar5_enable(VFIONvidiaBAR5Quirk *bar5) | |
590 | { | |
591 | VFIOPCIDevice *vdev = bar5->window.vdev; | |
592 | ||
593 | if (((bar5->master & bar5->enable) & 0x1) == bar5->enabled) { | |
594 | return; | |
595 | } | |
596 | ||
597 | bar5->enabled = !bar5->enabled; | |
598 | trace_vfio_quirk_nvidia_bar5_state(vdev->vbasedev.name, | |
599 | bar5->enabled ? "Enable" : "Disable"); | |
600 | memory_region_set_enabled(bar5->addr_mem, bar5->enabled); | |
601 | memory_region_set_enabled(bar5->data_mem, bar5->enabled); | |
602 | } | |
603 | ||
604 | static uint64_t vfio_nvidia_bar5_quirk_master_read(void *opaque, | |
605 | hwaddr addr, unsigned size) | |
606 | { | |
607 | VFIONvidiaBAR5Quirk *bar5 = opaque; | |
608 | VFIOPCIDevice *vdev = bar5->window.vdev; | |
609 | ||
610 | return vfio_region_read(&vdev->bars[5].region, addr, size); | |
611 | } | |
612 | ||
613 | static void vfio_nvidia_bar5_quirk_master_write(void *opaque, hwaddr addr, | |
614 | uint64_t data, unsigned size) | |
615 | { | |
616 | VFIONvidiaBAR5Quirk *bar5 = opaque; | |
617 | VFIOPCIDevice *vdev = bar5->window.vdev; | |
618 | ||
619 | vfio_region_write(&vdev->bars[5].region, addr, data, size); | |
620 | ||
621 | bar5->master = data; | |
622 | vfio_nvidia_bar5_enable(bar5); | |
623 | } | |
624 | ||
625 | static const MemoryRegionOps vfio_nvidia_bar5_quirk_master = { | |
626 | .read = vfio_nvidia_bar5_quirk_master_read, | |
627 | .write = vfio_nvidia_bar5_quirk_master_write, | |
628 | .endianness = DEVICE_LITTLE_ENDIAN, | |
c00d61d8 AW |
629 | }; |
630 | ||
0e54f24a AW |
631 | static uint64_t vfio_nvidia_bar5_quirk_enable_read(void *opaque, |
632 | hwaddr addr, unsigned size) | |
633 | { | |
634 | VFIONvidiaBAR5Quirk *bar5 = opaque; | |
635 | VFIOPCIDevice *vdev = bar5->window.vdev; | |
636 | ||
637 | return vfio_region_read(&vdev->bars[5].region, addr + 4, size); | |
638 | } | |
639 | ||
640 | static void vfio_nvidia_bar5_quirk_enable_write(void *opaque, hwaddr addr, | |
c00d61d8 AW |
641 | uint64_t data, unsigned size) |
642 | { | |
0e54f24a AW |
643 | VFIONvidiaBAR5Quirk *bar5 = opaque; |
644 | VFIOPCIDevice *vdev = bar5->window.vdev; | |
c00d61d8 | 645 | |
0e54f24a | 646 | vfio_region_write(&vdev->bars[5].region, addr + 4, data, size); |
c00d61d8 | 647 | |
0e54f24a AW |
648 | bar5->enable = data; |
649 | vfio_nvidia_bar5_enable(bar5); | |
c00d61d8 AW |
650 | } |
651 | ||
0e54f24a AW |
652 | static const MemoryRegionOps vfio_nvidia_bar5_quirk_enable = { |
653 | .read = vfio_nvidia_bar5_quirk_enable_read, | |
654 | .write = vfio_nvidia_bar5_quirk_enable_write, | |
c00d61d8 AW |
655 | .endianness = DEVICE_LITTLE_ENDIAN, |
656 | }; | |
657 | ||
0e54f24a | 658 | static void vfio_probe_nvidia_bar5_quirk(VFIOPCIDevice *vdev, int nr) |
c00d61d8 | 659 | { |
c00d61d8 | 660 | VFIOQuirk *quirk; |
0e54f24a AW |
661 | VFIONvidiaBAR5Quirk *bar5; |
662 | VFIOConfigWindowQuirk *window; | |
c00d61d8 | 663 | |
0e54f24a AW |
664 | if (!vfio_pci_is(vdev, PCI_VENDOR_ID_NVIDIA, PCI_ANY_ID) || |
665 | !vdev->has_vga || nr != 5) { | |
c00d61d8 AW |
666 | return; |
667 | } | |
668 | ||
669 | quirk = g_malloc0(sizeof(*quirk)); | |
0e54f24a AW |
670 | quirk->mem = g_malloc0_n(sizeof(MemoryRegion), 4); |
671 | quirk->nr_mem = 4; | |
672 | bar5 = quirk->data = g_malloc0(sizeof(*bar5) + | |
673 | (sizeof(VFIOConfigWindowMatch) * 2)); | |
674 | window = &bar5->window; | |
675 | ||
676 | window->vdev = vdev; | |
677 | window->address_offset = 0x8; | |
678 | window->data_offset = 0xc; | |
679 | window->nr_matches = 2; | |
680 | window->matches[0].match = 0x1800; | |
681 | window->matches[0].mask = PCI_CONFIG_SPACE_SIZE - 1; | |
682 | window->matches[1].match = 0x88000; | |
683 | window->matches[1].mask = PCIE_CONFIG_SPACE_SIZE - 1; | |
684 | window->bar = nr; | |
685 | window->addr_mem = bar5->addr_mem = &quirk->mem[0]; | |
686 | window->data_mem = bar5->data_mem = &quirk->mem[1]; | |
687 | ||
688 | memory_region_init_io(window->addr_mem, OBJECT(vdev), | |
689 | &vfio_generic_window_address_quirk, window, | |
690 | "vfio-nvidia-bar5-window-address-quirk", 4); | |
691 | memory_region_add_subregion_overlap(&vdev->bars[nr].region.mem, | |
692 | window->address_offset, | |
693 | window->addr_mem, 1); | |
694 | memory_region_set_enabled(window->addr_mem, false); | |
695 | ||
696 | memory_region_init_io(window->data_mem, OBJECT(vdev), | |
697 | &vfio_generic_window_data_quirk, window, | |
698 | "vfio-nvidia-bar5-window-data-quirk", 4); | |
699 | memory_region_add_subregion_overlap(&vdev->bars[nr].region.mem, | |
700 | window->data_offset, | |
701 | window->data_mem, 1); | |
702 | memory_region_set_enabled(window->data_mem, false); | |
703 | ||
704 | memory_region_init_io(&quirk->mem[2], OBJECT(vdev), | |
705 | &vfio_nvidia_bar5_quirk_master, bar5, | |
706 | "vfio-nvidia-bar5-master-quirk", 4); | |
707 | memory_region_add_subregion_overlap(&vdev->bars[nr].region.mem, | |
708 | 0, &quirk->mem[2], 1); | |
8c4f2348 | 709 | |
0e54f24a AW |
710 | memory_region_init_io(&quirk->mem[3], OBJECT(vdev), |
711 | &vfio_nvidia_bar5_quirk_enable, bar5, | |
712 | "vfio-nvidia-bar5-enable-quirk", 4); | |
c00d61d8 | 713 | memory_region_add_subregion_overlap(&vdev->bars[nr].region.mem, |
0e54f24a | 714 | 4, &quirk->mem[3], 1); |
c00d61d8 AW |
715 | |
716 | QLIST_INSERT_HEAD(&vdev->bars[nr].quirks, quirk, next); | |
717 | ||
0e54f24a | 718 | trace_vfio_quirk_nvidia_bar5_probe(vdev->vbasedev.name); |
c00d61d8 AW |
719 | } |
720 | ||
0d38fb1c AW |
721 | /* |
722 | * Finally, BAR0 itself. We want to redirect any accesses to either | |
723 | * 0x1800 or 0x88000 through the PCI config space access functions. | |
724 | */ | |
725 | static void vfio_nvidia_quirk_mirror_write(void *opaque, hwaddr addr, | |
726 | uint64_t data, unsigned size) | |
c00d61d8 | 727 | { |
0d38fb1c AW |
728 | VFIOConfigMirrorQuirk *mirror = opaque; |
729 | VFIOPCIDevice *vdev = mirror->vdev; | |
c00d61d8 | 730 | PCIDevice *pdev = &vdev->pdev; |
c00d61d8 | 731 | |
0d38fb1c | 732 | vfio_generic_quirk_mirror_write(opaque, addr, data, size); |
c00d61d8 AW |
733 | |
734 | /* | |
735 | * Nvidia seems to acknowledge MSI interrupts by writing 0xff to the | |
736 | * MSI capability ID register. Both the ID and next register are | |
737 | * read-only, so we allow writes covering either of those to real hw. | |
c00d61d8 AW |
738 | */ |
739 | if ((pdev->cap_present & QEMU_PCI_CAP_MSI) && | |
740 | vfio_range_contained(addr, size, pdev->msi_cap, PCI_MSI_FLAGS)) { | |
0d38fb1c AW |
741 | vfio_region_write(&vdev->bars[mirror->bar].region, |
742 | addr + mirror->offset, data, size); | |
743 | trace_vfio_quirk_nvidia_bar0_msi_ack(vdev->vbasedev.name); | |
c00d61d8 AW |
744 | } |
745 | } | |
746 | ||
0d38fb1c AW |
747 | static const MemoryRegionOps vfio_nvidia_mirror_quirk = { |
748 | .read = vfio_generic_quirk_mirror_read, | |
749 | .write = vfio_nvidia_quirk_mirror_write, | |
c00d61d8 AW |
750 | .endianness = DEVICE_LITTLE_ENDIAN, |
751 | }; | |
752 | ||
0d38fb1c | 753 | static void vfio_probe_nvidia_bar0_quirk(VFIOPCIDevice *vdev, int nr) |
c00d61d8 | 754 | { |
c00d61d8 | 755 | VFIOQuirk *quirk; |
0d38fb1c | 756 | VFIOConfigMirrorQuirk *mirror; |
c00d61d8 | 757 | |
0d38fb1c AW |
758 | if (!vfio_pci_is(vdev, PCI_VENDOR_ID_NVIDIA, PCI_ANY_ID) || |
759 | !vfio_is_vga(vdev) || nr != 0) { | |
c00d61d8 AW |
760 | return; |
761 | } | |
762 | ||
763 | quirk = g_malloc0(sizeof(*quirk)); | |
0d38fb1c AW |
764 | mirror = quirk->data = g_malloc0(sizeof(*mirror)); |
765 | mirror->mem = quirk->mem = g_malloc0_n(sizeof(MemoryRegion), 1); | |
8c4f2348 | 766 | quirk->nr_mem = 1; |
0d38fb1c AW |
767 | mirror->vdev = vdev; |
768 | mirror->offset = 0x88000; | |
769 | mirror->bar = nr; | |
770 | ||
771 | memory_region_init_io(mirror->mem, OBJECT(vdev), | |
772 | &vfio_nvidia_mirror_quirk, mirror, | |
773 | "vfio-nvidia-bar0-88000-mirror-quirk", | |
774 | PCIE_CONFIG_SPACE_SIZE); | |
c00d61d8 | 775 | memory_region_add_subregion_overlap(&vdev->bars[nr].region.mem, |
0d38fb1c | 776 | mirror->offset, mirror->mem, 1); |
c00d61d8 AW |
777 | |
778 | QLIST_INSERT_HEAD(&vdev->bars[nr].quirks, quirk, next); | |
779 | ||
0d38fb1c AW |
780 | /* The 0x1800 offset mirror only seems to get used by legacy VGA */ |
781 | if (vdev->has_vga) { | |
782 | quirk = g_malloc0(sizeof(*quirk)); | |
783 | mirror = quirk->data = g_malloc0(sizeof(*mirror)); | |
784 | mirror->mem = quirk->mem = g_malloc0_n(sizeof(MemoryRegion), 1); | |
785 | quirk->nr_mem = 1; | |
786 | mirror->vdev = vdev; | |
787 | mirror->offset = 0x1800; | |
788 | mirror->bar = nr; | |
789 | ||
790 | memory_region_init_io(mirror->mem, OBJECT(vdev), | |
791 | &vfio_nvidia_mirror_quirk, mirror, | |
792 | "vfio-nvidia-bar0-1800-mirror-quirk", | |
793 | PCI_CONFIG_SPACE_SIZE); | |
794 | memory_region_add_subregion_overlap(&vdev->bars[nr].region.mem, | |
795 | mirror->offset, mirror->mem, 1); | |
796 | ||
797 | QLIST_INSERT_HEAD(&vdev->bars[nr].quirks, quirk, next); | |
c00d61d8 AW |
798 | } |
799 | ||
0d38fb1c | 800 | trace_vfio_quirk_nvidia_bar0_probe(vdev->vbasedev.name); |
c00d61d8 AW |
801 | } |
802 | ||
803 | /* | |
804 | * TODO - Some Nvidia devices provide config access to their companion HDA | |
805 | * device and even to their parent bridge via these config space mirrors. | |
806 | * Add quirks for those regions. | |
807 | */ | |
808 | ||
809 | #define PCI_VENDOR_ID_REALTEK 0x10ec | |
810 | ||
811 | /* | |
812 | * RTL8168 devices have a backdoor that can access the MSI-X table. At BAR2 | |
813 | * offset 0x70 there is a dword data register, offset 0x74 is a dword address | |
814 | * register. According to the Linux r8169 driver, the MSI-X table is addressed | |
815 | * when the "type" portion of the address register is set to 0x1. This appears | |
816 | * to be bits 16:30. Bit 31 is both a write indicator and some sort of | |
817 | * "address latched" indicator. Bits 12:15 are a mask field, which we can | |
818 | * ignore because the MSI-X table should always be accessed as a dword (full | |
819 | * mask). Bits 0:11 is offset within the type. | |
820 | * | |
821 | * Example trace: | |
822 | * | |
823 | * Read from MSI-X table offset 0 | |
824 | * vfio: vfio_bar_write(0000:05:00.0:BAR2+0x74, 0x1f000, 4) // store read addr | |
825 | * vfio: vfio_bar_read(0000:05:00.0:BAR2+0x74, 4) = 0x8001f000 // latch | |
826 | * vfio: vfio_bar_read(0000:05:00.0:BAR2+0x70, 4) = 0xfee00398 // read data | |
827 | * | |
828 | * Write 0xfee00000 to MSI-X table offset 0 | |
829 | * vfio: vfio_bar_write(0000:05:00.0:BAR2+0x70, 0xfee00000, 4) // write data | |
830 | * vfio: vfio_bar_write(0000:05:00.0:BAR2+0x74, 0x8001f000, 4) // do write | |
831 | * vfio: vfio_bar_read(0000:05:00.0:BAR2+0x74, 4) = 0x1f000 // complete | |
832 | */ | |
954258a5 AW |
833 | typedef struct VFIOrtl8168Quirk { |
834 | VFIOPCIDevice *vdev; | |
835 | uint32_t addr; | |
836 | uint32_t data; | |
837 | bool enabled; | |
838 | } VFIOrtl8168Quirk; | |
c00d61d8 | 839 | |
954258a5 AW |
840 | static uint64_t vfio_rtl8168_quirk_address_read(void *opaque, |
841 | hwaddr addr, unsigned size) | |
842 | { | |
843 | VFIOrtl8168Quirk *rtl = opaque; | |
844 | VFIOPCIDevice *vdev = rtl->vdev; | |
845 | uint64_t data = vfio_region_read(&vdev->bars[2].region, addr + 0x74, size); | |
c00d61d8 | 846 | |
954258a5 AW |
847 | if (rtl->enabled) { |
848 | data = rtl->addr ^ 0x80000000U; /* latch/complete */ | |
849 | trace_vfio_quirk_rtl8168_fake_latch(vdev->vbasedev.name, data); | |
c00d61d8 AW |
850 | } |
851 | ||
954258a5 | 852 | return data; |
c00d61d8 AW |
853 | } |
854 | ||
954258a5 AW |
855 | static void vfio_rtl8168_quirk_address_write(void *opaque, hwaddr addr, |
856 | uint64_t data, unsigned size) | |
c00d61d8 | 857 | { |
954258a5 AW |
858 | VFIOrtl8168Quirk *rtl = opaque; |
859 | VFIOPCIDevice *vdev = rtl->vdev; | |
c00d61d8 | 860 | |
954258a5 AW |
861 | rtl->enabled = false; |
862 | ||
863 | if ((data & 0x7fff0000) == 0x10000) { /* MSI-X table */ | |
864 | rtl->enabled = true; | |
865 | rtl->addr = (uint32_t)data; | |
866 | ||
867 | if (data & 0x80000000U) { /* Do write */ | |
868 | if (vdev->pdev.cap_present & QEMU_PCI_CAP_MSIX) { | |
869 | hwaddr offset = data & 0xfff; | |
870 | uint64_t val = rtl->data; | |
871 | ||
872 | trace_vfio_quirk_rtl8168_msix_write(vdev->vbasedev.name, | |
873 | (uint16_t)offset, val); | |
874 | ||
875 | /* Write to the proper guest MSI-X table instead */ | |
876 | memory_region_dispatch_write(&vdev->pdev.msix_table_mmio, | |
877 | offset, val, size, | |
878 | MEMTXATTRS_UNSPECIFIED); | |
c00d61d8 | 879 | } |
954258a5 | 880 | return; /* Do not write guest MSI-X data to hardware */ |
c00d61d8 | 881 | } |
c00d61d8 AW |
882 | } |
883 | ||
954258a5 | 884 | vfio_region_write(&vdev->bars[2].region, addr + 0x74, data, size); |
c00d61d8 AW |
885 | } |
886 | ||
954258a5 AW |
887 | static const MemoryRegionOps vfio_rtl_address_quirk = { |
888 | .read = vfio_rtl8168_quirk_address_read, | |
889 | .write = vfio_rtl8168_quirk_address_write, | |
c00d61d8 AW |
890 | .valid = { |
891 | .min_access_size = 4, | |
892 | .max_access_size = 4, | |
893 | .unaligned = false, | |
894 | }, | |
895 | .endianness = DEVICE_LITTLE_ENDIAN, | |
896 | }; | |
897 | ||
954258a5 AW |
898 | static uint64_t vfio_rtl8168_quirk_data_read(void *opaque, |
899 | hwaddr addr, unsigned size) | |
900 | { | |
901 | VFIOrtl8168Quirk *rtl = opaque; | |
902 | VFIOPCIDevice *vdev = rtl->vdev; | |
903 | uint64_t data = vfio_region_read(&vdev->bars[2].region, addr + 0x74, size); | |
904 | ||
905 | if (rtl->enabled && (vdev->pdev.cap_present & QEMU_PCI_CAP_MSIX)) { | |
906 | hwaddr offset = rtl->addr & 0xfff; | |
907 | memory_region_dispatch_read(&vdev->pdev.msix_table_mmio, offset, | |
908 | &data, size, MEMTXATTRS_UNSPECIFIED); | |
909 | trace_vfio_quirk_rtl8168_msix_read(vdev->vbasedev.name, offset, data); | |
910 | } | |
911 | ||
912 | return data; | |
913 | } | |
914 | ||
915 | static void vfio_rtl8168_quirk_data_write(void *opaque, hwaddr addr, | |
916 | uint64_t data, unsigned size) | |
917 | { | |
918 | VFIOrtl8168Quirk *rtl = opaque; | |
919 | VFIOPCIDevice *vdev = rtl->vdev; | |
920 | ||
921 | rtl->data = (uint32_t)data; | |
922 | ||
923 | vfio_region_write(&vdev->bars[2].region, addr + 0x70, data, size); | |
924 | } | |
925 | ||
926 | static const MemoryRegionOps vfio_rtl_data_quirk = { | |
927 | .read = vfio_rtl8168_quirk_data_read, | |
928 | .write = vfio_rtl8168_quirk_data_write, | |
929 | .valid = { | |
930 | .min_access_size = 4, | |
931 | .max_access_size = 4, | |
932 | .unaligned = false, | |
933 | }, | |
934 | .endianness = DEVICE_LITTLE_ENDIAN, | |
935 | }; | |
936 | ||
937 | static void vfio_probe_rtl8168_bar2_quirk(VFIOPCIDevice *vdev, int nr) | |
c00d61d8 | 938 | { |
c00d61d8 | 939 | VFIOQuirk *quirk; |
954258a5 | 940 | VFIOrtl8168Quirk *rtl; |
c00d61d8 | 941 | |
954258a5 | 942 | if (!vfio_pci_is(vdev, PCI_VENDOR_ID_REALTEK, 0x8168) || nr != 2) { |
c00d61d8 AW |
943 | return; |
944 | } | |
945 | ||
946 | quirk = g_malloc0(sizeof(*quirk)); | |
954258a5 AW |
947 | quirk->mem = g_malloc0_n(sizeof(MemoryRegion), 2); |
948 | quirk->nr_mem = 2; | |
949 | quirk->data = rtl = g_malloc0(sizeof(*rtl)); | |
950 | rtl->vdev = vdev; | |
951 | ||
952 | memory_region_init_io(&quirk->mem[0], OBJECT(vdev), | |
953 | &vfio_rtl_address_quirk, rtl, | |
954 | "vfio-rtl8168-window-address-quirk", 4); | |
955 | memory_region_add_subregion_overlap(&vdev->bars[nr].region.mem, | |
956 | 0x74, &quirk->mem[0], 1); | |
8c4f2348 | 957 | |
954258a5 AW |
958 | memory_region_init_io(&quirk->mem[1], OBJECT(vdev), |
959 | &vfio_rtl_data_quirk, rtl, | |
960 | "vfio-rtl8168-window-data-quirk", 4); | |
c00d61d8 | 961 | memory_region_add_subregion_overlap(&vdev->bars[nr].region.mem, |
954258a5 | 962 | 0x70, &quirk->mem[1], 1); |
c00d61d8 AW |
963 | |
964 | QLIST_INSERT_HEAD(&vdev->bars[nr].quirks, quirk, next); | |
965 | ||
954258a5 | 966 | trace_vfio_quirk_rtl8168_probe(vdev->vbasedev.name); |
c00d61d8 AW |
967 | } |
968 | ||
969 | /* | |
970 | * Common quirk probe entry points. | |
971 | */ | |
972 | void vfio_vga_quirk_setup(VFIOPCIDevice *vdev) | |
973 | { | |
974 | vfio_vga_probe_ati_3c3_quirk(vdev); | |
975 | vfio_vga_probe_nvidia_3d0_quirk(vdev); | |
976 | } | |
977 | ||
978 | void vfio_vga_quirk_teardown(VFIOPCIDevice *vdev) | |
979 | { | |
980 | VFIOQuirk *quirk; | |
8c4f2348 | 981 | int i, j; |
c00d61d8 AW |
982 | |
983 | for (i = 0; i < ARRAY_SIZE(vdev->vga.region); i++) { | |
984 | QLIST_FOREACH(quirk, &vdev->vga.region[i].quirks, next) { | |
8c4f2348 AW |
985 | for (j = 0; j < quirk->nr_mem; j++) { |
986 | memory_region_del_subregion(&vdev->vga.region[i].mem, | |
987 | &quirk->mem[j]); | |
988 | } | |
c00d61d8 AW |
989 | } |
990 | } | |
991 | } | |
992 | ||
993 | void vfio_vga_quirk_free(VFIOPCIDevice *vdev) | |
994 | { | |
8c4f2348 | 995 | int i, j; |
c00d61d8 AW |
996 | |
997 | for (i = 0; i < ARRAY_SIZE(vdev->vga.region); i++) { | |
998 | while (!QLIST_EMPTY(&vdev->vga.region[i].quirks)) { | |
999 | VFIOQuirk *quirk = QLIST_FIRST(&vdev->vga.region[i].quirks); | |
c00d61d8 | 1000 | QLIST_REMOVE(quirk, next); |
8c4f2348 AW |
1001 | for (j = 0; j < quirk->nr_mem; j++) { |
1002 | object_unparent(OBJECT(&quirk->mem[j])); | |
1003 | } | |
1004 | g_free(quirk->mem); | |
1005 | g_free(quirk->data); | |
c00d61d8 AW |
1006 | g_free(quirk); |
1007 | } | |
1008 | } | |
1009 | } | |
1010 | ||
1011 | void vfio_bar_quirk_setup(VFIOPCIDevice *vdev, int nr) | |
1012 | { | |
0e54f24a | 1013 | vfio_probe_ati_bar4_quirk(vdev, nr); |
0d38fb1c | 1014 | vfio_probe_ati_bar2_quirk(vdev, nr); |
0e54f24a | 1015 | vfio_probe_nvidia_bar5_quirk(vdev, nr); |
0d38fb1c | 1016 | vfio_probe_nvidia_bar0_quirk(vdev, nr); |
954258a5 | 1017 | vfio_probe_rtl8168_bar2_quirk(vdev, nr); |
c00d61d8 AW |
1018 | } |
1019 | ||
1020 | void vfio_bar_quirk_teardown(VFIOPCIDevice *vdev, int nr) | |
1021 | { | |
1022 | VFIOBAR *bar = &vdev->bars[nr]; | |
1023 | VFIOQuirk *quirk; | |
8c4f2348 | 1024 | int i; |
c00d61d8 AW |
1025 | |
1026 | QLIST_FOREACH(quirk, &bar->quirks, next) { | |
8c4f2348 AW |
1027 | for (i = 0; i < quirk->nr_mem; i++) { |
1028 | memory_region_del_subregion(&bar->region.mem, &quirk->mem[i]); | |
1029 | } | |
c00d61d8 AW |
1030 | } |
1031 | } | |
1032 | ||
1033 | void vfio_bar_quirk_free(VFIOPCIDevice *vdev, int nr) | |
1034 | { | |
1035 | VFIOBAR *bar = &vdev->bars[nr]; | |
8c4f2348 | 1036 | int i; |
c00d61d8 AW |
1037 | |
1038 | while (!QLIST_EMPTY(&bar->quirks)) { | |
1039 | VFIOQuirk *quirk = QLIST_FIRST(&bar->quirks); | |
c00d61d8 | 1040 | QLIST_REMOVE(quirk, next); |
8c4f2348 AW |
1041 | for (i = 0; i < quirk->nr_mem; i++) { |
1042 | object_unparent(OBJECT(&quirk->mem[i])); | |
1043 | } | |
1044 | g_free(quirk->mem); | |
1045 | g_free(quirk->data); | |
c00d61d8 AW |
1046 | g_free(quirk); |
1047 | } | |
1048 | } |