|
@@ -39,12 +39,13 @@
|
|
|
#include "trace.h"
|
|
|
|
|
|
#define ACPI_PCIHP_ADDR 0xae00
|
|
|
-#define ACPI_PCIHP_SIZE 0x0014
|
|
|
+#define ACPI_PCIHP_SIZE 0x0018
|
|
|
#define PCI_UP_BASE 0x0000
|
|
|
#define PCI_DOWN_BASE 0x0004
|
|
|
#define PCI_EJ_BASE 0x0008
|
|
|
#define PCI_RMV_BASE 0x000c
|
|
|
#define PCI_SEL_BASE 0x0010
|
|
|
+#define PCI_AIDX_BASE 0x0014
|
|
|
|
|
|
typedef struct AcpiPciHpFind {
|
|
|
int bsel;
|
|
@@ -251,9 +252,13 @@ void acpi_pcihp_reset(AcpiPciHpState *s, bool acpihp_root_off)
|
|
|
acpi_pcihp_update(s);
|
|
|
}
|
|
|
|
|
|
+#define ONBOARD_INDEX_MAX (16 * 1024 - 1)
|
|
|
+
|
|
|
void acpi_pcihp_device_pre_plug_cb(HotplugHandler *hotplug_dev,
|
|
|
DeviceState *dev, Error **errp)
|
|
|
{
|
|
|
+ PCIDevice *pdev = PCI_DEVICE(dev);
|
|
|
+
|
|
|
/* Only hotplugged devices need the hotplug capability. */
|
|
|
if (dev->hotplugged &&
|
|
|
acpi_pcihp_get_bsel(pci_get_bus(PCI_DEVICE(dev))) < 0) {
|
|
@@ -261,6 +266,17 @@ void acpi_pcihp_device_pre_plug_cb(HotplugHandler *hotplug_dev,
|
|
|
ACPI_PCIHP_PROP_BSEL "' set");
|
|
|
return;
|
|
|
}
|
|
|
+
|
|
|
+ /*
|
|
|
+ * capped by systemd (see: udev-builtin-net_id.c)
|
|
|
+ * as it's the only known user honor it to avoid users
|
|
|
+ * misconfigure QEMU and then wonder why acpi-index doesn't work
|
|
|
+ */
|
|
|
+ if (pdev->acpi_index > ONBOARD_INDEX_MAX) {
|
|
|
+ error_setg(errp, "acpi-index should be less or equal to %u",
|
|
|
+ ONBOARD_INDEX_MAX);
|
|
|
+ return;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
void acpi_pcihp_device_plug_cb(HotplugHandler *hotplug_dev, AcpiPciHpState *s,
|
|
@@ -347,7 +363,6 @@ static uint64_t pci_read(void *opaque, hwaddr addr, unsigned int size)
|
|
|
trace_acpi_pci_down_read(val);
|
|
|
break;
|
|
|
case PCI_EJ_BASE:
|
|
|
- /* No feature defined yet */
|
|
|
trace_acpi_pci_features_read(val);
|
|
|
break;
|
|
|
case PCI_RMV_BASE:
|
|
@@ -357,6 +372,12 @@ static uint64_t pci_read(void *opaque, hwaddr addr, unsigned int size)
|
|
|
case PCI_SEL_BASE:
|
|
|
val = s->hotplug_select;
|
|
|
trace_acpi_pci_sel_read(val);
|
|
|
+ break;
|
|
|
+ case PCI_AIDX_BASE:
|
|
|
+ val = s->acpi_index;
|
|
|
+ s->acpi_index = 0;
|
|
|
+ trace_acpi_pci_acpi_index_read(val);
|
|
|
+ break;
|
|
|
default:
|
|
|
break;
|
|
|
}
|
|
@@ -367,8 +388,35 @@ static uint64_t pci_read(void *opaque, hwaddr addr, unsigned int size)
|
|
|
static void pci_write(void *opaque, hwaddr addr, uint64_t data,
|
|
|
unsigned int size)
|
|
|
{
|
|
|
+ int slot;
|
|
|
+ PCIBus *bus;
|
|
|
+ BusChild *kid, *next;
|
|
|
AcpiPciHpState *s = opaque;
|
|
|
+
|
|
|
+ s->acpi_index = 0;
|
|
|
switch (addr) {
|
|
|
+ case PCI_AIDX_BASE:
|
|
|
+ /*
|
|
|
+ * fetch acpi-index for specified slot so that follow up read from
|
|
|
+ * PCI_AIDX_BASE can return it to guest
|
|
|
+ */
|
|
|
+ slot = ctz32(data);
|
|
|
+
|
|
|
+ if (s->hotplug_select >= ACPI_PCIHP_MAX_HOTPLUG_BUS) {
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ bus = acpi_pcihp_find_hotplug_bus(s, s->hotplug_select);
|
|
|
+ QTAILQ_FOREACH_SAFE(kid, &bus->qbus.children, sibling, next) {
|
|
|
+ Object *o = OBJECT(kid->child);
|
|
|
+ PCIDevice *dev = PCI_DEVICE(o);
|
|
|
+ if (PCI_SLOT(dev->devfn) == slot) {
|
|
|
+ s->acpi_index = object_property_get_uint(o, "acpi-index", NULL);
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ trace_acpi_pci_acpi_index_write(s->hotplug_select, slot, s->acpi_index);
|
|
|
+ break;
|
|
|
case PCI_EJ_BASE:
|
|
|
if (s->hotplug_select >= ACPI_PCIHP_MAX_HOTPLUG_BUS) {
|
|
|
break;
|
|
@@ -413,6 +461,12 @@ void acpi_pcihp_init(Object *owner, AcpiPciHpState *s, PCIBus *root_bus,
|
|
|
OBJ_PROP_FLAG_READ);
|
|
|
}
|
|
|
|
|
|
+bool vmstate_acpi_pcihp_use_acpi_index(void *opaque, int version_id)
|
|
|
+{
|
|
|
+ AcpiPciHpState *s = opaque;
|
|
|
+ return s->acpi_index;
|
|
|
+}
|
|
|
+
|
|
|
const VMStateDescription vmstate_acpi_pcihp_pci_status = {
|
|
|
.name = "acpi_pcihp_pci_status",
|
|
|
.version_id = 1,
|