On 2025/3/10 15:13, Cédric Le Goater wrote:
> Tomita,
> 
> On 3/7/25 19:37, Tomita Moeko wrote:
>> On 2025/3/7 6:49, Alex Williamson wrote:
>>> On Fri,  7 Mar 2025 02:01:27 +0800
>>> Tomita Moeko <tomitamo...@gmail.com> wrote:
>>>
>>>> So far, IGD-specific quirks all require enabling legacy mode, which is
>>>> toggled by assigning IGD to 00:02.0. However, some quirks, like the BDSM
>>>> and GGC register quirks, should be applied to all supported IGD devices.
>>>> A new config option, x-igd-legacy-mode=[on|off|auto], is introduced to
>>>> control the legacy mode only quirks. The default value is "auto", which
>>>> keeps current behavior that enables legacy mode implicitly and continues
>>>> on error when all following conditions are met.
>>>> * Machine type is i440fx
>>>> * IGD device is at guest BDF 00:02.0
>>>>
>>>> If any one of the conditions above is not met, the default behavior is
>>>> equivalent to "off", QEMU will fail immediately if any error occurs.
>>>>
>>>> Users can also use "on" to force enabling legacy mode. It checks if all
>>>> the conditions above are met and set up legacy mode. QEMU will also fail
>>>> immediately on error in this case.
>>>>
>>>> Additionally, the hotplug check in legacy mode is removed as hotplugging
>>>> IGD device is never supported, and it will be checked when enabling the
>>>> OpRegion quirk.
>>>>
>>>> Signed-off-by: Tomita Moeko <tomitamo...@gmail.com>
>>>> ---
>>>>   hw/vfio/igd.c | 127 +++++++++++++++++++++++++++++---------------------
>>>>   hw/vfio/pci.c |   2 +
>>>>   hw/vfio/pci.h |   1 +
>>>>   3 files changed, 77 insertions(+), 53 deletions(-)
>>>>
>>>> diff --git a/hw/vfio/igd.c b/hw/vfio/igd.c
>>>> index f5e19f1241..ac096e2eb5 100644
>>>> --- a/hw/vfio/igd.c
>>>> +++ b/hw/vfio/igd.c
>>>> @@ -15,6 +15,7 @@
>>>>   #include "qemu/error-report.h"
>>>>   #include "qapi/error.h"
>>>>   #include "qapi/qmp/qerror.h"
>>>> +#include "hw/boards.h"
>>>>   #include "hw/hw.h"
>>>>   #include "hw/nvram/fw_cfg.h"
>>>>   #include "pci.h"
>>>> @@ -432,9 +433,7 @@ void vfio_probe_igd_bar0_quirk(VFIOPCIDevice *vdev, 
>>>> int nr)
>>>>        * bus address.
>>>>        */
>>>>       if (!vfio_pci_is(vdev, PCI_VENDOR_ID_INTEL, PCI_ANY_ID) ||
>>>> -        !vfio_is_vga(vdev) || nr != 0 ||
>>>> -        &vdev->pdev != pci_find_device(pci_device_root_bus(&vdev->pdev),
>>>> -                                       0, PCI_DEVFN(0x2, 0))) {
>>>> +        !vfio_is_vga(vdev) || nr != 0) {
>>>>           return;
>>>>       }
>>>>   @@ -482,14 +481,13 @@ void vfio_probe_igd_bar0_quirk(VFIOPCIDevice 
>>>> *vdev, int nr)
>>>>       QLIST_INSERT_HEAD(&vdev->bars[nr].quirks, bdsm_quirk, next);
>>>>   }
>>>>   -bool vfio_probe_igd_config_quirk(VFIOPCIDevice *vdev,
>>>> -                                 Error **errp G_GNUC_UNUSED)
>>>> +bool vfio_probe_igd_config_quirk(VFIOPCIDevice *vdev, Error **errp)
>>>>   {
>>>> -    g_autofree struct vfio_region_info *rom = NULL;
>>>>       int ret, gen;
>>>>       uint64_t gms_size;
>>>>       uint64_t *bdsm_size;
>>>>       uint32_t gmch;
>>>> +    bool legacy_mode_enabled = false;
>>>>       Error *err = NULL;
>>>>         /*
>>>> @@ -498,9 +496,7 @@ bool vfio_probe_igd_config_quirk(VFIOPCIDevice *vdev,
>>>>        * PCI bus address.
>>>>        */
>>>>       if (!vfio_pci_is(vdev, PCI_VENDOR_ID_INTEL, PCI_ANY_ID) ||
>>>> -        !vfio_is_vga(vdev) ||
>>>> -        &vdev->pdev != pci_find_device(pci_device_root_bus(&vdev->pdev),
>>>> -                                       0, PCI_DEVFN(0x2, 0))) {
>>>> +        !vfio_is_vga(vdev)) {
>>>>           return true;
>>>>       }
>>>>   @@ -516,56 +512,67 @@ bool vfio_probe_igd_config_quirk(VFIOPCIDevice 
>>>> *vdev,
>>>>           return true;
>>>>       }
>>>>   -    /*
>>>> -     * Most of what we're doing here is to enable the ROM to run, so if
>>>> -     * there's no ROM, there's no point in setting up this quirk.
>>>> -     * NB. We only seem to get BIOS ROMs, so a UEFI VM would need CSM 
>>>> support.
>>>> -     */
>>>> -    ret = vfio_get_region_info(&vdev->vbasedev,
>>>> -                               VFIO_PCI_ROM_REGION_INDEX, &rom);
>>>> -    if ((ret || !rom->size) && !vdev->pdev.romfile) {
>>>> -        error_report("IGD device %s has no ROM, legacy mode disabled",
>>>> -                     vdev->vbasedev.name);
>>>> -        return true;
>>>> -    }
>>>> -
>>>> -    /*
>>>> -     * Ignore the hotplug corner case, mark the ROM failed, we can't
>>>> -     * create the devices we need for legacy mode in the hotplug scenario.
>>>> -     */
>>>> -    if (vdev->pdev.qdev.hotplugged) {
>>>> -        error_report("IGD device %s hotplugged, ROM disabled, "
>>>> -                     "legacy mode disabled", vdev->vbasedev.name);
>>>> -        vdev->rom_read_failed = true;
>>>> -        return true;
>>>> -    }
>>>> -
>>>>       gmch = vfio_pci_read_config(&vdev->pdev, IGD_GMCH, 4);
>>>>         /*
>>>> -     * If IGD VGA Disable is clear (expected) and VGA is not already 
>>>> enabled,
>>>> -     * try to enable it.  Probably shouldn't be using legacy mode without 
>>>> VGA,
>>>> -     * but also no point in us enabling VGA if disabled in hardware.
>>>> +     * For backward compatibilty, enable legacy mode when
>>>> +     * - Machine type is i440fx (pc_piix)
>>>> +     * - IGD device is at guest BDF 00:02.0
>>>> +     * - Not manually disabled by x-igd-legacy-mode=off
>>>>        */
>>>> -    if (!(gmch & 0x2) && !vdev->vga && !vfio_populate_vga(vdev, &err)) {
>>>> -        error_reportf_err(err, VFIO_MSG_PREFIX, vdev->vbasedev.name);
>>>> -        error_report("IGD device %s failed to enable VGA access, "
>>>> -                     "legacy mode disabled", vdev->vbasedev.name);
>>>> -        return true;
>>>> -    }
>>>> +    if ((vdev->igd_legacy_mode != ON_OFF_AUTO_OFF) &&
>>>> +        !strcmp(MACHINE_GET_CLASS(qdev_get_machine())->family, "pc_piix") 
>>>> &&
>>>> +        (&vdev->pdev == pci_find_device(pci_device_root_bus(&vdev->pdev),
>>>> +        0, PCI_DEVFN(0x2, 0)))) {
>>>> +        /*
>>>> +         * IGD legacy mode requires:
>>>> +         * - VBIOS in ROM BAR or file
>>>> +         * - VGA IO/MMIO ranges are claimed by IGD
>>>> +         * - OpRegion
>>>> +         * - Same LPC bridge and Host bridge VID/DID/SVID/SSID as host
>>>> +         */
>>>> +        g_autofree struct vfio_region_info *rom = NULL;
>>>> +
>>>> +        legacy_mode_enabled = true;
>>>> +        warn_report("IGD legacy mode enabled, "
>>>> +                    "use x-igd-legacy-mode=off to disable it if 
>>>> unwanted.");
>>>
>>> info_report() maybe?  These aren't great choices for a user, get a
>>> warning for using the intended mode or silence that warning by
>>> requiring experimental options that taint the VM relative to libvirt.
>>
>> Got it. If possible, please help change this to info_report when
>> applying.
> 
> done.
> 
> 
>>
>>> Also, why do we list all the requirements then only test a few of them
>>> before declaring we're using legacy mode?  It seems like the above
>>> should be moved to the end of this branch.
>>
>> Having i440fx machine type and BDF 00:02.0 are the must-have condition
>> for considering enabling legacy mode, while others are the requirements
>> for legacy mode itself. In this verison, legacy mode is equivalent to
>>      romfile=oprom.bin,x-vga=on,x-igd-opregion=on,x-igd-lpc=on
>>
>> BDF being 00:02.0 is a requirement of VBIOS, and hacking the LPC DID
>> currently only works on i440fx. Though for Q35, we can overwrite the
>> existing ICH9 LPC DID to make IGD driver happy, it won't break ACPI PM
>> in recent guest kernel, and maybe later making it an option for Q35,
>> its still too risky to make it an implicit default. That's why I prefer
>> to check the must-have condtions first, then check other requirements
>> when setting up them.
>>
>> Setting the `legacy_mode_enabled` flag here is for error handling, as
>> we have to keep the old "continue on error" behavior for legacy mode.
> 
> A ducomentation update is welcome ! Could you do that before hard-freeze ?
> 
> Thanks,
> 
> C.
> 

Let me try to make it before Mar 18.

Thanks,
Moeko

>>> Given the pending release deadline, maybe these aren't blockers, but
>>> let's follow-up with something that assumes the user wants something
>>> other than what they're doing.  Thanks,
>>>
>>> Alex
>>>
>>
>> Sure.
>>
>> Moeko
>>  
>>>> +
>>>> +        /*
>>>> +         * Most of what we're doing here is to enable the ROM to run, so 
>>>> if
>>>> +         * there's no ROM, there's no point in setting up this quirk.
>>>> +         * NB. We only seem to get BIOS ROMs, so UEFI VM would need CSM 
>>>> support.
>>>> +         */
>>>> +        ret = vfio_get_region_info(&vdev->vbasedev,
>>>> +                                   VFIO_PCI_ROM_REGION_INDEX, &rom);
>>>> +        if ((ret || !rom->size) && !vdev->pdev.romfile) {
>>>> +            error_setg(&err, "Device has no ROM");
>>>> +            goto error;
>>>> +        }
>>>>   -    /* Setup OpRegion access */
>>>> -    if (!vfio_pci_igd_setup_opregion(vdev, &err)) {
>>>> -        error_append_hint(&err, "IGD legacy mode disabled\n");
>>>> -        error_report_err(err);
>>>> -        return true;
>>>> -    }
>>>> +        /*
>>>> +         * If IGD VGA Disable is clear (expected) and VGA is not already
>>>> +         * enabled, try to enable it. Probably shouldn't be using legacy 
>>>> mode
>>>> +         * without VGA, but also no point in us enabling VGA if disabled 
>>>> in
>>>> +         * hardware.
>>>> +         */
>>>> +        if (!(gmch & 0x2) && !vdev->vga && !vfio_populate_vga(vdev, 
>>>> &err)) {
>>>> +            error_setg(&err, "Unable to enable VGA access");
>>>> +            goto error;
>>>> +        }
>>>>   -    /* 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 true;
>>>> +        /* Setup OpRegion access */
>>>> +        if (!vfio_pci_igd_setup_opregion(vdev, &err)) {
>>>> +            goto error;
>>>> +        }
>>>> +
>>>> +        /* Setup LPC bridge / Host bridge PCI IDs */
>>>> +        if (!vfio_pci_igd_setup_lpc_bridge(vdev, &err)) {
>>>> +            goto error;
>>>> +        }
>>>> +    } else if (vdev->igd_legacy_mode == ON_OFF_AUTO_ON) {
>>>> +        error_setg(&err,
>>>> +                   "Machine is not i440fx or assigned BDF is not 
>>>> 00:02.0");
>>>> +        goto error;
>>>>       }
>>>>         /*
>>>> @@ -627,4 +634,18 @@ bool vfio_probe_igd_config_quirk(VFIOPCIDevice *vdev,
>>>>       trace_vfio_pci_igd_bdsm_enabled(vdev->vbasedev.name, (gms_size / 
>>>> MiB));
>>>>         return true;
>>>> +
>>>> +error:
>>>> +    /*
>>>> +     * When legacy mode is implicity enabled, continue on error,
>>>> +     * to keep compatibility
>>>> +     */
>>>> +    if (legacy_mode_enabled && (vdev->igd_legacy_mode == 
>>>> ON_OFF_AUTO_AUTO)) {
>>>> +        error_report_err(err);
>>>> +        error_report("IGD legacy mode disabled");
>>>> +        return true;
>>>> +    }
>>>> +
>>>> +    error_propagate(errp, err);
>>>> +    return false;
>>>>   }
>>>> diff --git a/hw/vfio/pci.c b/hw/vfio/pci.c
>>>> index a58d555934..d5ff8c1ea8 100644
>>>> --- a/hw/vfio/pci.c
>>>> +++ b/hw/vfio/pci.c
>>>> @@ -3363,6 +3363,8 @@ static const Property vfio_pci_dev_properties[] = {
>>>>                       VFIO_FEATURE_ENABLE_REQ_BIT, true),
>>>>       DEFINE_PROP_BIT("x-igd-opregion", VFIOPCIDevice, features,
>>>>                       VFIO_FEATURE_ENABLE_IGD_OPREGION_BIT, false),
>>>> +    DEFINE_PROP_ON_OFF_AUTO("x-igd-legacy-mode", VFIOPCIDevice,
>>>> +                            igd_legacy_mode, ON_OFF_AUTO_AUTO),
>>>>       DEFINE_PROP_ON_OFF_AUTO("enable-migration", VFIOPCIDevice,
>>>>                               vbasedev.enable_migration, ON_OFF_AUTO_AUTO),
>>>>       DEFINE_PROP_BOOL("migration-events", VFIOPCIDevice,
>>>> diff --git a/hw/vfio/pci.h b/hw/vfio/pci.h
>>>> index 2e81f9eb19..aa67ceb346 100644
>>>> --- a/hw/vfio/pci.h
>>>> +++ b/hw/vfio/pci.h
>>>> @@ -158,6 +158,7 @@ struct VFIOPCIDevice {
>>>>       uint32_t display_xres;
>>>>       uint32_t display_yres;
>>>>       int32_t bootindex;
>>>> +    OnOffAuto igd_legacy_mode;
>>>>       uint32_t igd_gms;
>>>>       OffAutoPCIBAR msix_relo;
>>>>       uint8_t pm_cap;
>>>
>>
> 


Reply via email to