Skip to content

Commit a9040ea

Browse files
ktian1gregkh
authored andcommitted
vfio/pci: Disable qword access to the PCI ROM bar
[ Upstream commit dc85a46 ] Commit 2b938e3 ("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: 2b938e3 ("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> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1 parent e7a7d7e commit a9040ea

3 files changed

Lines changed: 29 additions & 10 deletions

File tree

drivers/vfio/pci/nvgrace-gpu/main.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -491,7 +491,7 @@ nvgrace_gpu_map_and_read(struct nvgrace_gpu_pci_core_device *nvdev,
491491
ret = vfio_pci_core_do_io_rw(&nvdev->core_device, false,
492492
nvdev->resmem.ioaddr,
493493
buf, offset, mem_count,
494-
0, 0, false);
494+
0, 0, false, VFIO_PCI_IO_WIDTH_8);
495495
}
496496

497497
return ret;
@@ -609,7 +609,7 @@ nvgrace_gpu_map_and_write(struct nvgrace_gpu_pci_core_device *nvdev,
609609
ret = vfio_pci_core_do_io_rw(&nvdev->core_device, false,
610610
nvdev->resmem.ioaddr,
611611
(char __user *)buf, pos, mem_count,
612-
0, 0, true);
612+
0, 0, true, VFIO_PCI_IO_WIDTH_8);
613613
}
614614

615615
return ret;

drivers/vfio/pci/vfio_pci_rdwr.c

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,8 @@ VFIO_IORDWR(64)
135135
ssize_t vfio_pci_core_do_io_rw(struct vfio_pci_core_device *vdev, bool test_mem,
136136
void __iomem *io, char __user *buf,
137137
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)
139140
{
140141
ssize_t done = 0;
141142
int ret;
@@ -150,20 +151,19 @@ ssize_t vfio_pci_core_do_io_rw(struct vfio_pci_core_device *vdev, bool test_mem,
150151
else
151152
fillable = 0;
152153

153-
if (fillable >= 8 && !(off % 8)) {
154+
if (fillable >= 8 && !(off % 8) && max_width >= 8) {
154155
ret = vfio_pci_iordwr64(vdev, iswrite, test_mem,
155156
io, buf, off, &filled);
156157
if (ret)
157158
return ret;
158159

159-
} else
160-
if (fillable >= 4 && !(off % 4)) {
160+
} else if (fillable >= 4 && !(off % 4) && max_width >= 4) {
161161
ret = vfio_pci_iordwr32(vdev, iswrite, test_mem,
162162
io, buf, off, &filled);
163163
if (ret)
164164
return ret;
165165

166-
} else if (fillable >= 2 && !(off % 2)) {
166+
} else if (fillable >= 2 && !(off % 2) && max_width >= 2) {
167167
ret = vfio_pci_iordwr16(vdev, iswrite, test_mem,
168168
io, buf, off, &filled);
169169
if (ret)
@@ -234,6 +234,7 @@ ssize_t vfio_pci_bar_rw(struct vfio_pci_core_device *vdev, char __user *buf,
234234
void __iomem *io;
235235
struct resource *res = &vdev->pdev->resource[bar];
236236
ssize_t done;
237+
enum vfio_pci_io_width max_width = VFIO_PCI_IO_WIDTH_8;
237238

238239
if (pci_resource_start(pdev, bar))
239240
end = pci_resource_len(pdev, bar);
@@ -262,6 +263,16 @@ ssize_t vfio_pci_bar_rw(struct vfio_pci_core_device *vdev, char __user *buf,
262263
if (!io)
263264
return -ENOMEM;
264265
x_end = end;
266+
267+
/*
268+
* Certain devices (e.g. Intel X710) don't support qword
269+
* access to the ROM bar. Otherwise PCI AER errors might be
270+
* triggered.
271+
*
272+
* Disable qword access to the ROM bar universally, which
273+
* worked reliably for years before qword access is enabled.
274+
*/
275+
max_width = VFIO_PCI_IO_WIDTH_4;
265276
} else {
266277
int ret = vfio_pci_core_setup_barmap(vdev, bar);
267278
if (ret) {
@@ -278,7 +289,7 @@ ssize_t vfio_pci_bar_rw(struct vfio_pci_core_device *vdev, char __user *buf,
278289
}
279290

280291
done = vfio_pci_core_do_io_rw(vdev, res->flags & IORESOURCE_MEM, io, buf, pos,
281-
count, x_start, x_end, iswrite);
292+
count, x_start, x_end, iswrite, max_width);
282293

283294
if (done >= 0)
284295
*ppos += done;
@@ -352,7 +363,7 @@ ssize_t vfio_pci_vga_rw(struct vfio_pci_core_device *vdev, char __user *buf,
352363
* to the memory enable bit in the command register.
353364
*/
354365
done = vfio_pci_core_do_io_rw(vdev, false, iomem, buf, off, count,
355-
0, 0, iswrite);
366+
0, 0, iswrite, VFIO_PCI_IO_WIDTH_8);
356367

357368
vga_put(vdev->pdev, rsrc);
358369

include/linux/vfio_pci_core.h

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,13 @@ struct vfio_pci_core_device {
102102
struct rw_semaphore memory_lock;
103103
};
104104

105+
enum vfio_pci_io_width {
106+
VFIO_PCI_IO_WIDTH_1 = 1,
107+
VFIO_PCI_IO_WIDTH_2 = 2,
108+
VFIO_PCI_IO_WIDTH_4 = 4,
109+
VFIO_PCI_IO_WIDTH_8 = 8,
110+
};
111+
105112
/* Will be exported for vfio pci drivers usage */
106113
int vfio_pci_core_register_dev_region(struct vfio_pci_core_device *vdev,
107114
unsigned int type, unsigned int subtype,
@@ -139,7 +146,8 @@ pci_ers_result_t vfio_pci_core_aer_err_detected(struct pci_dev *pdev,
139146
ssize_t vfio_pci_core_do_io_rw(struct vfio_pci_core_device *vdev, bool test_mem,
140147
void __iomem *io, char __user *buf,
141148
loff_t off, size_t count, size_t x_start,
142-
size_t x_end, bool iswrite);
149+
size_t x_end, bool iswrite,
150+
enum vfio_pci_io_width max_width);
143151
bool vfio_pci_core_range_intersect_range(loff_t buf_start, size_t buf_cnt,
144152
loff_t reg_start, size_t reg_cnt,
145153
loff_t *buf_offset,

0 commit comments

Comments
 (0)