mirror of
https://github.com/Motorhead1991/qemu.git
synced 2025-08-04 08:13:54 -06:00
vfio/igd: Move LPC bridge initialization to a separate function
A new option will soon be introduced to decouple the LPC bridge/Host bridge ID quirk from legacy mode. To prepare for this, move the LPC bridge initialization into a separate function. Signed-off-by: Tomita Moeko <tomitamoeko@gmail.com> Reviewed-by: Alex Williamson <alex.williamson@redhat.com> Tested-by: Alex Williamson <alex.williamson@redhat.com> Reviewed-by: Corvin Köhne <c.koehne@beckhoff.com> Link: https://lore.kernel.org/qemu-devel/20250306180131.32970-5-tomitamoeko@gmail.com Signed-off-by: Cédric Le Goater <clg@redhat.com>
This commit is contained in:
parent
ae9d9ec4a6
commit
eabaa7b468
1 changed files with 70 additions and 52 deletions
122
hw/vfio/igd.c
122
hw/vfio/igd.c
|
@ -351,6 +351,72 @@ static int vfio_pci_igd_lpc_init(VFIOPCIDevice *vdev,
|
|||
return ret;
|
||||
}
|
||||
|
||||
static bool vfio_pci_igd_setup_lpc_bridge(VFIOPCIDevice *vdev, Error **errp)
|
||||
{
|
||||
g_autofree struct vfio_region_info *host = NULL;
|
||||
g_autofree struct vfio_region_info *lpc = NULL;
|
||||
PCIDevice *lpc_bridge;
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* Copying IDs or creating new devices are not supported on hotplug
|
||||
*/
|
||||
if (vdev->pdev.qdev.hotplugged) {
|
||||
error_setg(errp, "IGD LPC is not supported on hotplugged device");
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* We need to create an LPC/ISA bridge at PCI bus address 00:1f.0 that we
|
||||
* can stuff host values into, so if there's already one there and it's not
|
||||
* one we can hack on, this quirk is no-go. Sorry Q35.
|
||||
*/
|
||||
lpc_bridge = pci_find_device(pci_device_root_bus(&vdev->pdev),
|
||||
0, PCI_DEVFN(0x1f, 0));
|
||||
if (lpc_bridge && !object_dynamic_cast(OBJECT(lpc_bridge),
|
||||
"vfio-pci-igd-lpc-bridge")) {
|
||||
error_setg(errp,
|
||||
"Cannot create LPC bridge due to existing device at 1f.0");
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check whether we have all the vfio device specific regions to
|
||||
* support LPC quirk (added in Linux v4.6).
|
||||
*/
|
||||
ret = vfio_get_dev_region_info(&vdev->vbasedev,
|
||||
VFIO_REGION_TYPE_PCI_VENDOR_TYPE | PCI_VENDOR_ID_INTEL,
|
||||
VFIO_REGION_SUBTYPE_INTEL_IGD_LPC_CFG, &lpc);
|
||||
if (ret) {
|
||||
error_setg(errp, "IGD LPC bridge access is not supported by kernel");
|
||||
return false;
|
||||
}
|
||||
|
||||
ret = vfio_get_dev_region_info(&vdev->vbasedev,
|
||||
VFIO_REGION_TYPE_PCI_VENDOR_TYPE | PCI_VENDOR_ID_INTEL,
|
||||
VFIO_REGION_SUBTYPE_INTEL_IGD_HOST_CFG, &host);
|
||||
if (ret) {
|
||||
error_setg(errp, "IGD host bridge access is not supported by kernel");
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Create/modify LPC bridge */
|
||||
ret = vfio_pci_igd_lpc_init(vdev, lpc);
|
||||
if (ret) {
|
||||
error_setg(errp, "Failed to create/modify LPC bridge for IGD");
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Stuff some host values into the VM PCI host bridge */
|
||||
ret = vfio_pci_igd_host_init(vdev, host);
|
||||
if (ret) {
|
||||
error_setg(errp, "Failed to modify host bridge for IGD");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#define IGD_GGC_MMIO_OFFSET 0x108040
|
||||
#define IGD_BDSM_MMIO_OFFSET 0x1080C0
|
||||
|
||||
|
@ -419,9 +485,6 @@ void vfio_probe_igd_bar0_quirk(VFIOPCIDevice *vdev, int nr)
|
|||
void vfio_probe_igd_bar4_quirk(VFIOPCIDevice *vdev, int nr)
|
||||
{
|
||||
g_autofree struct vfio_region_info *rom = NULL;
|
||||
g_autofree struct vfio_region_info *host = NULL;
|
||||
g_autofree struct vfio_region_info *lpc = NULL;
|
||||
PCIDevice *lpc_bridge;
|
||||
int ret, gen;
|
||||
uint64_t gms_size;
|
||||
uint64_t *bdsm_size;
|
||||
|
@ -440,20 +503,6 @@ void vfio_probe_igd_bar4_quirk(VFIOPCIDevice *vdev, int nr)
|
|||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* We need to create an LPC/ISA bridge at PCI bus address 00:1f.0 that we
|
||||
* can stuff host values into, so if there's already one there and it's not
|
||||
* one we can hack on, legacy mode is no-go. Sorry Q35.
|
||||
*/
|
||||
lpc_bridge = pci_find_device(pci_device_root_bus(&vdev->pdev),
|
||||
0, PCI_DEVFN(0x1f, 0));
|
||||
if (lpc_bridge && !object_dynamic_cast(OBJECT(lpc_bridge),
|
||||
"vfio-pci-igd-lpc-bridge")) {
|
||||
error_report("IGD device %s cannot support legacy mode due to existing "
|
||||
"devices at address 1f.0", vdev->vbasedev.name);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* IGD is not a standard, they like to change their specs often. We
|
||||
* only attempt to support back to SandBridge and we hope that newer
|
||||
|
@ -490,28 +539,6 @@ void vfio_probe_igd_bar4_quirk(VFIOPCIDevice *vdev, int nr)
|
|||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check whether we have all the vfio device specific regions to
|
||||
* support legacy mode (added in Linux v4.6). If not, bail.
|
||||
*/
|
||||
ret = vfio_get_dev_region_info(&vdev->vbasedev,
|
||||
VFIO_REGION_TYPE_PCI_VENDOR_TYPE | PCI_VENDOR_ID_INTEL,
|
||||
VFIO_REGION_SUBTYPE_INTEL_IGD_HOST_CFG, &host);
|
||||
if (ret) {
|
||||
error_report("IGD device %s does not support host bridge access,"
|
||||
"legacy mode disabled", vdev->vbasedev.name);
|
||||
return;
|
||||
}
|
||||
|
||||
ret = vfio_get_dev_region_info(&vdev->vbasedev,
|
||||
VFIO_REGION_TYPE_PCI_VENDOR_TYPE | PCI_VENDOR_ID_INTEL,
|
||||
VFIO_REGION_SUBTYPE_INTEL_IGD_LPC_CFG, &lpc);
|
||||
if (ret) {
|
||||
error_report("IGD device %s does not support LPC bridge access,"
|
||||
"legacy mode disabled", vdev->vbasedev.name);
|
||||
return;
|
||||
}
|
||||
|
||||
gmch = vfio_pci_read_config(&vdev->pdev, IGD_GMCH, 4);
|
||||
|
||||
/*
|
||||
|
@ -533,19 +560,10 @@ void vfio_probe_igd_bar4_quirk(VFIOPCIDevice *vdev, int nr)
|
|||
return;
|
||||
}
|
||||
|
||||
/* Create our LPC/ISA bridge */
|
||||
ret = vfio_pci_igd_lpc_init(vdev, lpc);
|
||||
if (ret) {
|
||||
error_report("IGD device %s failed to create LPC bridge, "
|
||||
"legacy mode disabled", vdev->vbasedev.name);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Stuff some host values into the VM PCI host bridge */
|
||||
ret = vfio_pci_igd_host_init(vdev, host);
|
||||
if (ret) {
|
||||
error_report("IGD device %s failed to modify host bridge, "
|
||||
"legacy mode disabled", vdev->vbasedev.name);
|
||||
/* Setup LPC bridge / Host bridge PCI IDs */
|
||||
if (!vfio_pci_igd_setup_lpc_bridge(vdev, &err)) {
|
||||
error_append_hint(&err, "IGD legacy mode disabled\n");
|
||||
error_report_err(err);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue