Commit e021e6cb authored by Yunxiang Li's avatar Yunxiang Li Committed by Alex Williamson
Browse files

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: default avatarYunxiang Li <Yunxiang.Li@amd.com>
Link: https://lore.kernel.org/r/20250102185013.15082-3-Yunxiang.Li@amd.com


Signed-off-by: default avatarAlex Williamson <alex.williamson@redhat.com>
parent c5a8b5d7
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -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;
	}
+18 −16
Original line number Diff line number Diff line
@@ -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;

		if (pci_resource_start(pdev, PCI_ROM_RESOURCE)) {
			/*
		 * Is it really there?  Enable memory decode for implicit access
		 * in pci_map_rom().
			 * 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);
		} else {
			info.size = 0;
			}
			vfio_pci_memory_unlock_and_restore(vdev, cmd);
		} else if (pdev->rom && pdev->romlen) {
			info.flags = VFIO_REGION_INFO_FLAG_READ;
			/* Report BAR size as power of two. */
			info.size = roundup_pow_of_two(pdev->romlen);
		}

		break;
	}
+16 −6
Original line number Diff line number Diff line
@@ -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.
		 */
		if (pci_resource_start(pdev, bar)) {
			io = pci_map_rom(pdev, &x_start);
		if (!io) {
			done = -ENOMEM;
			goto out;
		} 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)
	if (bar == PCI_ROM_RESOURCE) {
		if (pci_resource_start(pdev, bar))
			pci_unmap_rom(pdev, io);
		else
			iounmap(io);
	}

out:
	return done;
}