Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

vfio/pci: Disable qword access to the PCI ROM bar

Commit 2b938e3db335 ("vfio/pci: Enable iowrite64 and ioread64 for vfio
pci") enables qword access to the PCI bar resources. However certain
devices (e.g. Intel X710) are observed with problem upon qword accesses
to the rom bar, e.g. triggering PCI aer errors.

This is triggered by Qemu which caches the rom content by simply does a
pread() of the remaining size until it gets the full contents. The other
bars would only perform operations at the same access width as their
guest drivers.

Instead of trying to identify all broken devices, universally disable
qword access to the rom bar i.e. going back to the old way which worked
reliably for years.

Reported-by: Farrah Chen <farrah.chen@intel.com>
Closes: https://bugzilla.kernel.org/show_bug.cgi?id=220740
Fixes: 2b938e3db335 ("vfio/pci: Enable iowrite64 and ioread64 for vfio pci")
Cc: stable@vger.kernel.org
Signed-off-by: Kevin Tian <kevin.tian@intel.com>
Tested-by: Farrah Chen <farrah.chen@intel.com>
Link: https://lore.kernel.org/r/20251218081650.555015-2-kevin.tian@intel.com
Signed-off-by: Alex Williamson <alex@shazbot.org>

authored by

Kevin Tian and committed by
Alex Williamson
dc85a469 9448598b

+29 -10
+2 -2
drivers/vfio/pci/nvgrace-gpu/main.c
··· 561 561 ret = vfio_pci_core_do_io_rw(&nvdev->core_device, false, 562 562 nvdev->resmem.ioaddr, 563 563 buf, offset, mem_count, 564 - 0, 0, false); 564 + 0, 0, false, VFIO_PCI_IO_WIDTH_8); 565 565 } 566 566 567 567 return ret; ··· 693 693 ret = vfio_pci_core_do_io_rw(&nvdev->core_device, false, 694 694 nvdev->resmem.ioaddr, 695 695 (char __user *)buf, pos, mem_count, 696 - 0, 0, true); 696 + 0, 0, true, VFIO_PCI_IO_WIDTH_8); 697 697 } 698 698 699 699 return ret;
+18 -7
drivers/vfio/pci/vfio_pci_rdwr.c
··· 135 135 ssize_t vfio_pci_core_do_io_rw(struct vfio_pci_core_device *vdev, bool test_mem, 136 136 void __iomem *io, char __user *buf, 137 137 loff_t off, size_t count, size_t x_start, 138 - size_t x_end, bool iswrite) 138 + size_t x_end, bool iswrite, 139 + enum vfio_pci_io_width max_width) 139 140 { 140 141 ssize_t done = 0; 141 142 int ret; ··· 151 150 else 152 151 fillable = 0; 153 152 154 - if (fillable >= 8 && !(off % 8)) { 153 + if (fillable >= 8 && !(off % 8) && max_width >= 8) { 155 154 ret = vfio_pci_iordwr64(vdev, iswrite, test_mem, 156 155 io, buf, off, &filled); 157 156 if (ret) 158 157 return ret; 159 158 160 - } else 161 - if (fillable >= 4 && !(off % 4)) { 159 + } else if (fillable >= 4 && !(off % 4) && max_width >= 4) { 162 160 ret = vfio_pci_iordwr32(vdev, iswrite, test_mem, 163 161 io, buf, off, &filled); 164 162 if (ret) 165 163 return ret; 166 164 167 - } else if (fillable >= 2 && !(off % 2)) { 165 + } else if (fillable >= 2 && !(off % 2) && max_width >= 2) { 168 166 ret = vfio_pci_iordwr16(vdev, iswrite, test_mem, 169 167 io, buf, off, &filled); 170 168 if (ret) ··· 234 234 void __iomem *io; 235 235 struct resource *res = &vdev->pdev->resource[bar]; 236 236 ssize_t done; 237 + enum vfio_pci_io_width max_width = VFIO_PCI_IO_WIDTH_8; 237 238 238 239 if (pci_resource_start(pdev, bar)) 239 240 end = pci_resource_len(pdev, bar); ··· 263 262 if (!io) 264 263 return -ENOMEM; 265 264 x_end = end; 265 + 266 + /* 267 + * Certain devices (e.g. Intel X710) don't support qword 268 + * access to the ROM bar. Otherwise PCI AER errors might be 269 + * triggered. 270 + * 271 + * Disable qword access to the ROM bar universally, which 272 + * worked reliably for years before qword access is enabled. 273 + */ 274 + max_width = VFIO_PCI_IO_WIDTH_4; 266 275 } else { 267 276 int ret = vfio_pci_core_setup_barmap(vdev, bar); 268 277 if (ret) { ··· 289 278 } 290 279 291 280 done = vfio_pci_core_do_io_rw(vdev, res->flags & IORESOURCE_MEM, io, buf, pos, 292 - count, x_start, x_end, iswrite); 281 + count, x_start, x_end, iswrite, max_width); 293 282 294 283 if (done >= 0) 295 284 *ppos += done; ··· 363 352 * to the memory enable bit in the command register. 364 353 */ 365 354 done = vfio_pci_core_do_io_rw(vdev, false, iomem, buf, off, count, 366 - 0, 0, iswrite); 355 + 0, 0, iswrite, VFIO_PCI_IO_WIDTH_8); 367 356 368 357 vga_put(vdev->pdev, rsrc); 369 358
+9 -1
include/linux/vfio_pci_core.h
··· 145 145 struct list_head dmabufs; 146 146 }; 147 147 148 + enum vfio_pci_io_width { 149 + VFIO_PCI_IO_WIDTH_1 = 1, 150 + VFIO_PCI_IO_WIDTH_2 = 2, 151 + VFIO_PCI_IO_WIDTH_4 = 4, 152 + VFIO_PCI_IO_WIDTH_8 = 8, 153 + }; 154 + 148 155 /* Will be exported for vfio pci drivers usage */ 149 156 int vfio_pci_core_register_dev_region(struct vfio_pci_core_device *vdev, 150 157 unsigned int type, unsigned int subtype, ··· 195 188 ssize_t vfio_pci_core_do_io_rw(struct vfio_pci_core_device *vdev, bool test_mem, 196 189 void __iomem *io, char __user *buf, 197 190 loff_t off, size_t count, size_t x_start, 198 - size_t x_end, bool iswrite); 191 + size_t x_end, bool iswrite, 192 + enum vfio_pci_io_width max_width); 199 193 bool __vfio_pci_memory_enabled(struct vfio_pci_core_device *vdev); 200 194 bool vfio_pci_core_range_intersect_range(loff_t buf_start, size_t buf_cnt, 201 195 loff_t reg_start, size_t reg_cnt,