mirror of
https://github.com/torvalds/linux.git
synced 2026-05-24 15:12:13 +02:00
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 <Yunxiang.Li@amd.com> Link: https://lore.kernel.org/r/20250102185013.15082-3-Yunxiang.Li@amd.com Signed-off-by: Alex Williamson <alex.williamson@redhat.com>
This commit is contained in:
parent
c5a8b5d740
commit
e021e6cbfb
|
|
@ -511,6 +511,10 @@ static void vfio_bar_fixup(struct vfio_pci_core_device *vdev)
|
|||
mask = ~(pci_resource_len(pdev, PCI_ROM_RESOURCE) - 1);
|
||||
mask |= PCI_ROM_ADDRESS_ENABLE;
|
||||
*vbar &= cpu_to_le32((u32)mask);
|
||||
} else if (pdev->rom && pdev->romlen) {
|
||||
mask = ~(roundup_pow_of_two(pdev->romlen) - 1);
|
||||
mask |= PCI_ROM_ADDRESS_ENABLE;
|
||||
*vbar &= cpu_to_le32((u32)mask);
|
||||
} else {
|
||||
*vbar = 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1054,25 +1054,27 @@ static int vfio_pci_ioctl_get_region_info(struct vfio_pci_core_device *vdev,
|
|||
|
||||
info.offset = VFIO_PCI_INDEX_TO_OFFSET(info.index);
|
||||
info.flags = 0;
|
||||
info.size = 0;
|
||||
|
||||
/* Report the BAR size, not the ROM size */
|
||||
info.size = pci_resource_len(pdev, info.index);
|
||||
if (!info.size)
|
||||
break;
|
||||
|
||||
/*
|
||||
* Is it really there? Enable memory decode for implicit access
|
||||
* in pci_map_rom().
|
||||
*/
|
||||
cmd = vfio_pci_memory_lock_and_enable(vdev);
|
||||
io = pci_map_rom(pdev, &size);
|
||||
if (io) {
|
||||
if (pci_resource_start(pdev, PCI_ROM_RESOURCE)) {
|
||||
/*
|
||||
* Check ROM content is valid. Need to enable memory
|
||||
* decode for ROM access in pci_map_rom().
|
||||
*/
|
||||
cmd = vfio_pci_memory_lock_and_enable(vdev);
|
||||
io = pci_map_rom(pdev, &size);
|
||||
if (io) {
|
||||
info.flags = VFIO_REGION_INFO_FLAG_READ;
|
||||
/* Report the BAR size, not the ROM size. */
|
||||
info.size = pci_resource_len(pdev, PCI_ROM_RESOURCE);
|
||||
pci_unmap_rom(pdev, io);
|
||||
}
|
||||
vfio_pci_memory_unlock_and_restore(vdev, cmd);
|
||||
} else if (pdev->rom && pdev->romlen) {
|
||||
info.flags = VFIO_REGION_INFO_FLAG_READ;
|
||||
pci_unmap_rom(pdev, io);
|
||||
} else {
|
||||
info.size = 0;
|
||||
/* Report BAR size as power of two. */
|
||||
info.size = roundup_pow_of_two(pdev->romlen);
|
||||
}
|
||||
vfio_pci_memory_unlock_and_restore(vdev, cmd);
|
||||
|
||||
break;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -237,6 +237,8 @@ ssize_t vfio_pci_bar_rw(struct vfio_pci_core_device *vdev, char __user *buf,
|
|||
|
||||
if (pci_resource_start(pdev, bar))
|
||||
end = pci_resource_len(pdev, bar);
|
||||
else if (bar == PCI_ROM_RESOURCE && pdev->rom && pdev->romlen)
|
||||
end = roundup_pow_of_two(pdev->romlen);
|
||||
else
|
||||
return -EINVAL;
|
||||
|
||||
|
|
@ -251,11 +253,14 @@ ssize_t vfio_pci_bar_rw(struct vfio_pci_core_device *vdev, char __user *buf,
|
|||
* excluded range at the end of the actual ROM. This makes
|
||||
* filling large ROM BARs much faster.
|
||||
*/
|
||||
io = pci_map_rom(pdev, &x_start);
|
||||
if (!io) {
|
||||
done = -ENOMEM;
|
||||
goto out;
|
||||
if (pci_resource_start(pdev, bar)) {
|
||||
io = pci_map_rom(pdev, &x_start);
|
||||
} else {
|
||||
io = ioremap(pdev->rom, pdev->romlen);
|
||||
x_start = pdev->romlen;
|
||||
}
|
||||
if (!io)
|
||||
return -ENOMEM;
|
||||
x_end = end;
|
||||
} else {
|
||||
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,
|
|||
if (done >= 0)
|
||||
*ppos += done;
|
||||
|
||||
if (bar == PCI_ROM_RESOURCE)
|
||||
pci_unmap_rom(pdev, io);
|
||||
if (bar == PCI_ROM_RESOURCE) {
|
||||
if (pci_resource_start(pdev, bar))
|
||||
pci_unmap_rom(pdev, io);
|
||||
else
|
||||
iounmap(io);
|
||||
}
|
||||
|
||||
out:
|
||||
return done;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user