diff options
author | Igor Mammedov <imammedo@redhat.com> | 2021-03-15 14:00:59 -0400 |
---|---|---|
committer | Michael S. Tsirkin <mst@redhat.com> | 2021-03-22 18:58:19 -0400 |
commit | 4fd7da4c0336c8fd822cd808d62f7ff8c9936aef (patch) | |
tree | 30dcb1d94e127f24f4b1a0041d1aebb50b79b7e2 /hw/acpi/pcihp.c | |
parent | b32bd763a1ca929677e22ae1c51cb3920921bdce (diff) |
pci: acpi: ensure that acpi-index is unique
it helps to avoid device naming conflicts when guest OS is
configured to use acpi-index for naming.
Spec ialso says so:
PCI Firmware Specification Revision 3.2
4.6.7. _DSM for Naming a PCI or PCI Express Device Under Operating Systems
"
Instance number must be unique under \_SB scope. This instance number does not have to
be sequential in a given system configuration.
"
Signed-off-by: Igor Mammedov <imammedo@redhat.com>
Message-Id: <20210315180102.3008391-4-imammedo@redhat.com>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
Diffstat (limited to 'hw/acpi/pcihp.c')
-rw-r--r-- | hw/acpi/pcihp.c | 46 |
1 files changed, 46 insertions, 0 deletions
diff --git a/hw/acpi/pcihp.c b/hw/acpi/pcihp.c index ceab287bd3..f4cb3c979d 100644 --- a/hw/acpi/pcihp.c +++ b/hw/acpi/pcihp.c @@ -52,6 +52,21 @@ typedef struct AcpiPciHpFind { PCIBus *bus; } AcpiPciHpFind; +static gint g_cmp_uint32(gconstpointer a, gconstpointer b, gpointer user_data) +{ + return a - b; +} + +static GSequence *pci_acpi_index_list(void) +{ + static GSequence *used_acpi_index_list; + + if (!used_acpi_index_list) { + used_acpi_index_list = g_sequence_new(NULL); + } + return used_acpi_index_list; +} + static int acpi_pcihp_get_bsel(PCIBus *bus) { Error *local_err = NULL; @@ -277,6 +292,23 @@ void acpi_pcihp_device_pre_plug_cb(HotplugHandler *hotplug_dev, ONBOARD_INDEX_MAX); return; } + + /* + * make sure that acpi-index is unique across all present PCI devices + */ + if (pdev->acpi_index) { + GSequence *used_indexes = pci_acpi_index_list(); + + if (g_sequence_lookup(used_indexes, GINT_TO_POINTER(pdev->acpi_index), + g_cmp_uint32, NULL)) { + error_setg(errp, "a PCI device with acpi-index = %" PRIu32 + " already exist", pdev->acpi_index); + return; + } + g_sequence_insert_sorted(used_indexes, + GINT_TO_POINTER(pdev->acpi_index), + g_cmp_uint32, NULL); + } } void acpi_pcihp_device_plug_cb(HotplugHandler *hotplug_dev, AcpiPciHpState *s, @@ -315,8 +347,22 @@ void acpi_pcihp_device_plug_cb(HotplugHandler *hotplug_dev, AcpiPciHpState *s, void acpi_pcihp_device_unplug_cb(HotplugHandler *hotplug_dev, AcpiPciHpState *s, DeviceState *dev, Error **errp) { + PCIDevice *pdev = PCI_DEVICE(dev); + trace_acpi_pci_unplug(PCI_SLOT(PCI_DEVICE(dev)->devfn), acpi_pcihp_get_bsel(pci_get_bus(PCI_DEVICE(dev)))); + + /* + * clean up acpi-index so it could reused by another device + */ + if (pdev->acpi_index) { + GSequence *used_indexes = pci_acpi_index_list(); + + g_sequence_remove(g_sequence_lookup(used_indexes, + GINT_TO_POINTER(pdev->acpi_index), + g_cmp_uint32, NULL)); + } + qdev_unrealize(dev); } |