Skip to content

Commit ce19b17

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 527a73d commit ce19b17

3 files changed

Lines changed: 29 additions & 9 deletions

File tree

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -482,7 +482,7 @@ nvgrace_gpu_map_and_read(struct nvgrace_gpu_pci_core_device *nvdev,
482482
ret = vfio_pci_core_do_io_rw(&nvdev->core_device, false,
483483
nvdev->resmem.ioaddr,
484484
buf, offset, mem_count,
485-
0, 0, false);
485+
0, 0, false, VFIO_PCI_IO_WIDTH_8);
486486
}
487487

488488
return ret;
@@ -600,7 +600,7 @@ nvgrace_gpu_map_and_write(struct nvgrace_gpu_pci_core_device *nvdev,
600600
ret = vfio_pci_core_do_io_rw(&nvdev->core_device, false,
601601
nvdev->resmem.ioaddr,
602602
(char __user *)buf, pos, mem_count,
603-
0, 0, true);
603+
0, 0, true, VFIO_PCI_IO_WIDTH_8);
604604
}
605605

606606
return ret;

drivers/vfio/pci/vfio_pci_rdwr.c

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,8 @@ VFIO_IORDWR(64)
141141
ssize_t vfio_pci_core_do_io_rw(struct vfio_pci_core_device *vdev, bool test_mem,
142142
void __iomem *io, char __user *buf,
143143
loff_t off, size_t count, size_t x_start,
144-
size_t x_end, bool iswrite)
144+
size_t x_end, bool iswrite,
145+
enum vfio_pci_io_width max_width)
145146
{
146147
ssize_t done = 0;
147148
int ret;
@@ -157,21 +158,21 @@ ssize_t vfio_pci_core_do_io_rw(struct vfio_pci_core_device *vdev, bool test_mem,
157158
fillable = 0;
158159

159160
#if defined(ioread64) && defined(iowrite64)
160-
if (fillable >= 8 && !(off % 8)) {
161+
if (fillable >= 8 && !(off % 8) && max_width >= 8) {
161162
ret = vfio_pci_iordwr64(vdev, iswrite, test_mem,
162163
io, buf, off, &filled);
163164
if (ret)
164165
return ret;
165166

166167
} else
167168
#endif
168-
if (fillable >= 4 && !(off % 4)) {
169+
if (fillable >= 4 && !(off % 4) && max_width >= 4) {
169170
ret = vfio_pci_iordwr32(vdev, iswrite, test_mem,
170171
io, buf, off, &filled);
171172
if (ret)
172173
return ret;
173174

174-
} else if (fillable >= 2 && !(off % 2)) {
175+
} else if (fillable >= 2 && !(off % 2) && max_width >= 2) {
175176
ret = vfio_pci_iordwr16(vdev, iswrite, test_mem,
176177
io, buf, off, &filled);
177178
if (ret)
@@ -242,6 +243,7 @@ ssize_t vfio_pci_bar_rw(struct vfio_pci_core_device *vdev, char __user *buf,
242243
void __iomem *io;
243244
struct resource *res = &vdev->pdev->resource[bar];
244245
ssize_t done;
246+
enum vfio_pci_io_width max_width = VFIO_PCI_IO_WIDTH_8;
245247

246248
if (pci_resource_start(pdev, bar))
247249
end = pci_resource_len(pdev, bar);
@@ -268,6 +270,16 @@ ssize_t vfio_pci_bar_rw(struct vfio_pci_core_device *vdev, char __user *buf,
268270
goto out;
269271
}
270272
x_end = end;
273+
274+
/*
275+
* Certain devices (e.g. Intel X710) don't support qword
276+
* access to the ROM bar. Otherwise PCI AER errors might be
277+
* triggered.
278+
*
279+
* Disable qword access to the ROM bar universally, which
280+
* worked reliably for years before qword access is enabled.
281+
*/
282+
max_width = VFIO_PCI_IO_WIDTH_4;
271283
} else {
272284
int ret = vfio_pci_core_setup_barmap(vdev, bar);
273285
if (ret) {
@@ -284,7 +296,7 @@ ssize_t vfio_pci_bar_rw(struct vfio_pci_core_device *vdev, char __user *buf,
284296
}
285297

286298
done = vfio_pci_core_do_io_rw(vdev, res->flags & IORESOURCE_MEM, io, buf, pos,
287-
count, x_start, x_end, iswrite);
299+
count, x_start, x_end, iswrite, max_width);
288300

289301
if (done >= 0)
290302
*ppos += done;
@@ -353,7 +365,7 @@ ssize_t vfio_pci_vga_rw(struct vfio_pci_core_device *vdev, char __user *buf,
353365
* to the memory enable bit in the command register.
354366
*/
355367
done = vfio_pci_core_do_io_rw(vdev, false, iomem, buf, off, count,
356-
0, 0, iswrite);
368+
0, 0, iswrite, VFIO_PCI_IO_WIDTH_8);
357369

358370
vga_put(vdev->pdev, rsrc);
359371

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,
@@ -137,7 +144,8 @@ pci_ers_result_t vfio_pci_core_aer_err_detected(struct pci_dev *pdev,
137144
ssize_t vfio_pci_core_do_io_rw(struct vfio_pci_core_device *vdev, bool test_mem,
138145
void __iomem *io, char __user *buf,
139146
loff_t off, size_t count, size_t x_start,
140-
size_t x_end, bool iswrite);
147+
size_t x_end, bool iswrite,
148+
enum vfio_pci_io_width max_width);
141149
bool vfio_pci_core_range_intersect_range(loff_t buf_start, size_t buf_cnt,
142150
loff_t reg_start, size_t reg_cnt,
143151
loff_t *buf_offset,

0 commit comments

Comments
 (0)