Skip to content

Commit e021e6c

Browse files
yunxialiawilliam
authored andcommitted
vfio/pci: Expose setup ROM at ROM bar when needed
If ROM bar is missing for any reason, we can fallback to using pdev->rom to expose the ROM content to the guest. This fixes some passthrough use cases where the upstream bridge does not have enough address window. Signed-off-by: Yunxiang Li <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Alex Williamson <[email protected]>
1 parent c5a8b5d commit e021e6c

File tree

3 files changed

+38
-22
lines changed

3 files changed

+38
-22
lines changed

drivers/vfio/pci/vfio_pci_config.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -511,6 +511,10 @@ static void vfio_bar_fixup(struct vfio_pci_core_device *vdev)
511511
mask = ~(pci_resource_len(pdev, PCI_ROM_RESOURCE) - 1);
512512
mask |= PCI_ROM_ADDRESS_ENABLE;
513513
*vbar &= cpu_to_le32((u32)mask);
514+
} else if (pdev->rom && pdev->romlen) {
515+
mask = ~(roundup_pow_of_two(pdev->romlen) - 1);
516+
mask |= PCI_ROM_ADDRESS_ENABLE;
517+
*vbar &= cpu_to_le32((u32)mask);
514518
} else {
515519
*vbar = 0;
516520
}

drivers/vfio/pci/vfio_pci_core.c

Lines changed: 18 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1054,25 +1054,27 @@ static int vfio_pci_ioctl_get_region_info(struct vfio_pci_core_device *vdev,
10541054

10551055
info.offset = VFIO_PCI_INDEX_TO_OFFSET(info.index);
10561056
info.flags = 0;
1057+
info.size = 0;
10571058

1058-
/* Report the BAR size, not the ROM size */
1059-
info.size = pci_resource_len(pdev, info.index);
1060-
if (!info.size)
1061-
break;
1062-
1063-
/*
1064-
* Is it really there? Enable memory decode for implicit access
1065-
* in pci_map_rom().
1066-
*/
1067-
cmd = vfio_pci_memory_lock_and_enable(vdev);
1068-
io = pci_map_rom(pdev, &size);
1069-
if (io) {
1059+
if (pci_resource_start(pdev, PCI_ROM_RESOURCE)) {
1060+
/*
1061+
* Check ROM content is valid. Need to enable memory
1062+
* decode for ROM access in pci_map_rom().
1063+
*/
1064+
cmd = vfio_pci_memory_lock_and_enable(vdev);
1065+
io = pci_map_rom(pdev, &size);
1066+
if (io) {
1067+
info.flags = VFIO_REGION_INFO_FLAG_READ;
1068+
/* Report the BAR size, not the ROM size. */
1069+
info.size = pci_resource_len(pdev, PCI_ROM_RESOURCE);
1070+
pci_unmap_rom(pdev, io);
1071+
}
1072+
vfio_pci_memory_unlock_and_restore(vdev, cmd);
1073+
} else if (pdev->rom && pdev->romlen) {
10701074
info.flags = VFIO_REGION_INFO_FLAG_READ;
1071-
pci_unmap_rom(pdev, io);
1072-
} else {
1073-
info.size = 0;
1075+
/* Report BAR size as power of two. */
1076+
info.size = roundup_pow_of_two(pdev->romlen);
10741077
}
1075-
vfio_pci_memory_unlock_and_restore(vdev, cmd);
10761078

10771079
break;
10781080
}

drivers/vfio/pci/vfio_pci_rdwr.c

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -237,6 +237,8 @@ ssize_t vfio_pci_bar_rw(struct vfio_pci_core_device *vdev, char __user *buf,
237237

238238
if (pci_resource_start(pdev, bar))
239239
end = pci_resource_len(pdev, bar);
240+
else if (bar == PCI_ROM_RESOURCE && pdev->rom && pdev->romlen)
241+
end = roundup_pow_of_two(pdev->romlen);
240242
else
241243
return -EINVAL;
242244

@@ -251,11 +253,14 @@ ssize_t vfio_pci_bar_rw(struct vfio_pci_core_device *vdev, char __user *buf,
251253
* excluded range at the end of the actual ROM. This makes
252254
* filling large ROM BARs much faster.
253255
*/
254-
io = pci_map_rom(pdev, &x_start);
255-
if (!io) {
256-
done = -ENOMEM;
257-
goto out;
256+
if (pci_resource_start(pdev, bar)) {
257+
io = pci_map_rom(pdev, &x_start);
258+
} else {
259+
io = ioremap(pdev->rom, pdev->romlen);
260+
x_start = pdev->romlen;
258261
}
262+
if (!io)
263+
return -ENOMEM;
259264
x_end = end;
260265
} else {
261266
int ret = vfio_pci_core_setup_barmap(vdev, bar);
@@ -278,8 +283,13 @@ ssize_t vfio_pci_bar_rw(struct vfio_pci_core_device *vdev, char __user *buf,
278283
if (done >= 0)
279284
*ppos += done;
280285

281-
if (bar == PCI_ROM_RESOURCE)
282-
pci_unmap_rom(pdev, io);
286+
if (bar == PCI_ROM_RESOURCE) {
287+
if (pci_resource_start(pdev, bar))
288+
pci_unmap_rom(pdev, io);
289+
else
290+
iounmap(io);
291+
}
292+
283293
out:
284294
return done;
285295
}

0 commit comments

Comments
 (0)