* Contributions after 2012-01-13 are licensed under the terms of the
* GNU GPL, version 2 or (at your option) any later version.
*/
+#include "qemu/osdep.h"
#include "hw/hw.h"
#include "hw/i386/pc.h"
#include "hw/isa/apm.h"
#include "exec/ioport.h"
#include "hw/nvram/fw_cfg.h"
#include "exec/address-spaces.h"
+#include "hw/acpi/piix4.h"
+#include "hw/acpi/pcihp.h"
+#include "hw/acpi/cpu_hotplug.h"
+#include "hw/hotplug.h"
+#include "hw/mem/pc-dimm.h"
+#include "hw/acpi/memory_hotplug.h"
+#include "hw/acpi/acpi_dev_interface.h"
+#include "hw/xen/xen.h"
//#define DEBUG
#define GPE_BASE 0xafe0
#define GPE_LEN 4
-#define PCI_HOTPLUG_ADDR 0xae00
-#define PCI_HOTPLUG_SIZE 0x000f
-#define PCI_UP_BASE 0xae00
-#define PCI_DOWN_BASE 0xae04
-#define PCI_EJ_BASE 0xae08
-#define PCI_RMV_BASE 0xae0c
-
-#define PIIX4_PCI_HOTPLUG_STATUS 2
-
struct pci_status {
uint32_t up; /* deprecated, maintained for migration compatibility */
uint32_t down;
};
typedef struct PIIX4PMState {
- PCIDevice dev;
+ /*< private >*/
+ PCIDevice parent_obj;
+ /*< public >*/
MemoryRegion io;
+ uint32_t io_base;
+
MemoryRegion io_gpe;
- MemoryRegion io_pci;
ACPIREGS ar;
APMState apm;
qemu_irq irq;
qemu_irq smi_irq;
- int kvm_enabled;
+ int smm_enabled;
Notifier machine_ready;
Notifier powerdown_notifier;
- /* for pci hotplug */
- struct pci_status pci0_status;
- uint32_t pci0_hotplug_enable;
- uint32_t pci0_slot_device_present;
+ AcpiPciHpState acpi_pci_hotplug;
+ bool use_acpi_pci_hotplug;
uint8_t disable_s3;
uint8_t disable_s4;
uint8_t s4_val;
+
+ AcpiCpuHotplug gpe_cpu;
+
+ MemHotplugState acpi_memory_hotplug;
} PIIX4PMState;
+#define TYPE_PIIX4_PM "PIIX4_PM"
+
+#define PIIX4_PM(obj) \
+ OBJECT_CHECK(PIIX4PMState, (obj), TYPE_PIIX4_PM)
+
static void piix4_acpi_system_hot_add_init(MemoryRegion *parent,
PCIBus *bus, PIIX4PMState *s);
#define ACPI_ENABLE 0xf1
#define ACPI_DISABLE 0xf0
-static void pm_update_sci(PIIX4PMState *s)
-{
- int sci_level, pmsts;
-
- pmsts = acpi_pm1_evt_get_sts(&s->ar);
- sci_level = (((pmsts & s->ar.pm1.evt.en) &
- (ACPI_BITMASK_RT_CLOCK_ENABLE |
- ACPI_BITMASK_POWER_BUTTON_ENABLE |
- ACPI_BITMASK_GLOBAL_LOCK_ENABLE |
- ACPI_BITMASK_TIMER_ENABLE)) != 0) ||
- (((s->ar.gpe.sts[0] & s->ar.gpe.en[0])
- & PIIX4_PCI_HOTPLUG_STATUS) != 0);
-
- qemu_set_irq(s->irq, sci_level);
- /* schedule a timer interruption if needed */
- acpi_pm_tmr_update(&s->ar, (s->ar.pm1.evt.en & ACPI_BITMASK_TIMER_ENABLE) &&
- !(pmsts & ACPI_BITMASK_TIMER_STATUS));
-}
-
static void pm_tmr_timer(ACPIREGS *ar)
{
PIIX4PMState *s = container_of(ar, PIIX4PMState, ar);
- pm_update_sci(s);
+ acpi_update_sci(&s->ar, s->irq);
}
static void apm_ctrl_changed(uint32_t val, void *arg)
{
PIIX4PMState *s = arg;
+ PCIDevice *d = PCI_DEVICE(s);
/* ACPI specs 3.0, 4.7.2.5 */
acpi_pm1_cnt_update(&s->ar, val == ACPI_ENABLE, val == ACPI_DISABLE);
+ if (val == ACPI_ENABLE || val == ACPI_DISABLE) {
+ return;
+ }
- if (s->dev.config[0x5b] & (1 << 1)) {
+ if (d->config[0x5b] & (1 << 1)) {
if (s->smi_irq) {
qemu_irq_raise(s->smi_irq);
}
static void pm_io_space_update(PIIX4PMState *s)
{
- uint32_t pm_io_base;
+ PCIDevice *d = PCI_DEVICE(s);
- pm_io_base = le32_to_cpu(*(uint32_t *)(s->dev.config + 0x40));
- pm_io_base &= 0xffc0;
+ s->io_base = le32_to_cpu(*(uint32_t *)(d->config + 0x40));
+ s->io_base &= 0xffc0;
memory_region_transaction_begin();
- memory_region_set_enabled(&s->io, s->dev.config[0x80] & 1);
- memory_region_set_address(&s->io, pm_io_base);
+ memory_region_set_enabled(&s->io, d->config[0x80] & 1);
+ memory_region_set_address(&s->io, s->io_base);
memory_region_transaction_commit();
}
static void smbus_io_space_update(PIIX4PMState *s)
{
- s->smb_io_base = le32_to_cpu(*(uint32_t *)(s->dev.config + 0x90));
+ PCIDevice *d = PCI_DEVICE(s);
+
+ s->smb_io_base = le32_to_cpu(*(uint32_t *)(d->config + 0x90));
s->smb_io_base &= 0xffc0;
memory_region_transaction_begin();
- memory_region_set_enabled(&s->smb.io, s->dev.config[0xd2] & 1);
+ memory_region_set_enabled(&s->smb.io, d->config[0xd2] & 1);
memory_region_set_address(&s->smb.io, s->smb_io_base);
memory_region_transaction_commit();
}
}
}
-static void vmstate_pci_status_pre_save(void *opaque)
-{
- struct pci_status *pci0_status = opaque;
- PIIX4PMState *s = container_of(pci0_status, PIIX4PMState, pci0_status);
-
- /* We no longer track up, so build a safe value for migrating
- * to a version that still does... of course these might get lost
- * by an old buggy implementation, but we try. */
- pci0_status->up = s->pci0_slot_device_present & s->pci0_hotplug_enable;
-}
-
static int vmstate_acpi_post_load(void *opaque, int version_id)
{
PIIX4PMState *s = opaque;
.name = "gpe",
.version_id = 1,
.minimum_version_id = 1,
- .minimum_version_id_old = 1,
- .fields = (VMStateField []) {
+ .fields = (VMStateField[]) {
VMSTATE_GPE_ARRAY(sts, ACPIGPE),
VMSTATE_GPE_ARRAY(en, ACPIGPE),
VMSTATE_END_OF_LIST()
.name = "pci_status",
.version_id = 1,
.minimum_version_id = 1,
- .minimum_version_id_old = 1,
- .pre_save = vmstate_pci_status_pre_save,
- .fields = (VMStateField []) {
- VMSTATE_UINT32(up, struct pci_status),
- VMSTATE_UINT32(down, struct pci_status),
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT32(up, struct AcpiPciHpPciStatus),
+ VMSTATE_UINT32(down, struct AcpiPciHpPciStatus),
VMSTATE_END_OF_LIST()
}
};
int ret, i;
uint16_t temp;
- ret = pci_device_load(&s->dev, f);
+ ret = pci_device_load(PCI_DEVICE(s), f);
if (ret < 0) {
return ret;
}
return ret;
}
- qemu_get_timer(f, s->ar.tmr.timer);
+ timer_get(f, s->ar.tmr.timer);
qemu_get_sbe64s(f, &s->ar.tmr.overflow_time);
qemu_get_be16s(f, (uint16_t *)s->ar.gpe.sts);
qemu_get_be16s(f, &temp);
}
- ret = vmstate_load_state(f, &vmstate_pci_status, &s->pci0_status, 1);
+ ret = vmstate_load_state(f, &vmstate_pci_status,
+ &s->acpi_pci_hotplug.acpi_pcihp_pci_status[ACPI_PCIHP_BSEL_DEFAULT], 1);
return ret;
}
+static bool vmstate_test_use_acpi_pci_hotplug(void *opaque, int version_id)
+{
+ PIIX4PMState *s = opaque;
+ return s->use_acpi_pci_hotplug;
+}
+
+static bool vmstate_test_no_use_acpi_pci_hotplug(void *opaque, int version_id)
+{
+ PIIX4PMState *s = opaque;
+ return !s->use_acpi_pci_hotplug;
+}
+
+static bool vmstate_test_use_memhp(void *opaque)
+{
+ PIIX4PMState *s = opaque;
+ return s->acpi_memory_hotplug.is_enabled;
+}
+
+static const VMStateDescription vmstate_memhp_state = {
+ .name = "piix4_pm/memhp",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .minimum_version_id_old = 1,
+ .needed = vmstate_test_use_memhp,
+ .fields = (VMStateField[]) {
+ VMSTATE_MEMORY_HOTPLUG(acpi_memory_hotplug, PIIX4PMState),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
/* qemu-kvm 1.2 uses version 3 but advertised as 2
* To support incoming qemu-kvm 1.2 migration, change version_id
* and minimum_version_id to 2 below (which breaks migration from
.minimum_version_id_old = 1,
.load_state_old = acpi_load_old,
.post_load = vmstate_acpi_post_load,
- .fields = (VMStateField []) {
- VMSTATE_PCI_DEVICE(dev, PIIX4PMState),
+ .fields = (VMStateField[]) {
+ VMSTATE_PCI_DEVICE(parent_obj, PIIX4PMState),
VMSTATE_UINT16(ar.pm1.evt.sts, PIIX4PMState),
VMSTATE_UINT16(ar.pm1.evt.en, PIIX4PMState),
VMSTATE_UINT16(ar.pm1.cnt.cnt, PIIX4PMState),
VMSTATE_STRUCT(apm, PIIX4PMState, 0, vmstate_apm, APMState),
- VMSTATE_TIMER(ar.tmr.timer, PIIX4PMState),
+ VMSTATE_TIMER_PTR(ar.tmr.timer, PIIX4PMState),
VMSTATE_INT64(ar.tmr.overflow_time, PIIX4PMState),
VMSTATE_STRUCT(ar.gpe, PIIX4PMState, 2, vmstate_gpe, ACPIGPE),
- VMSTATE_STRUCT(pci0_status, PIIX4PMState, 2, vmstate_pci_status,
- struct pci_status),
+ VMSTATE_STRUCT_TEST(
+ acpi_pci_hotplug.acpi_pcihp_pci_status[ACPI_PCIHP_BSEL_DEFAULT],
+ PIIX4PMState,
+ vmstate_test_no_use_acpi_pci_hotplug,
+ 2, vmstate_pci_status,
+ struct AcpiPciHpPciStatus),
+ VMSTATE_PCI_HOTPLUG(acpi_pci_hotplug, PIIX4PMState,
+ vmstate_test_use_acpi_pci_hotplug),
VMSTATE_END_OF_LIST()
+ },
+ .subsections = (const VMStateDescription*[]) {
+ &vmstate_memhp_state,
+ NULL
}
};
-static void acpi_piix_eject_slot(PIIX4PMState *s, unsigned slots)
-{
- BusChild *kid, *next;
- BusState *bus = qdev_get_parent_bus(&s->dev.qdev);
- int slot = ffs(slots) - 1;
- bool slot_free = true;
-
- /* Mark request as complete */
- s->pci0_status.down &= ~(1U << slot);
-
- QTAILQ_FOREACH_SAFE(kid, &bus->children, sibling, next) {
- DeviceState *qdev = kid->child;
- PCIDevice *dev = PCI_DEVICE(qdev);
- PCIDeviceClass *pc = PCI_DEVICE_GET_CLASS(dev);
- if (PCI_SLOT(dev->devfn) == slot) {
- if (pc->no_hotplug) {
- slot_free = false;
- } else {
- qdev_free(qdev);
- }
- }
- }
- if (slot_free) {
- s->pci0_slot_device_present &= ~(1U << slot);
- }
-}
-
-static void piix4_update_hotplug(PIIX4PMState *s)
-{
- PCIDevice *dev = &s->dev;
- BusState *bus = qdev_get_parent_bus(&dev->qdev);
- BusChild *kid, *next;
-
- /* Execute any pending removes during reset */
- while (s->pci0_status.down) {
- acpi_piix_eject_slot(s, s->pci0_status.down);
- }
-
- s->pci0_hotplug_enable = ~0;
- s->pci0_slot_device_present = 0;
-
- QTAILQ_FOREACH_SAFE(kid, &bus->children, sibling, next) {
- DeviceState *qdev = kid->child;
- PCIDevice *pdev = PCI_DEVICE(qdev);
- PCIDeviceClass *pc = PCI_DEVICE_GET_CLASS(pdev);
- int slot = PCI_SLOT(pdev->devfn);
-
- if (pc->no_hotplug) {
- s->pci0_hotplug_enable &= ~(1U << slot);
- }
-
- s->pci0_slot_device_present |= (1U << slot);
- }
-}
-
static void piix4_reset(void *opaque)
{
PIIX4PMState *s = opaque;
- uint8_t *pci_conf = s->dev.config;
+ PCIDevice *d = PCI_DEVICE(s);
+ uint8_t *pci_conf = d->config;
pci_conf[0x58] = 0;
pci_conf[0x59] = 0;
pci_conf[0x40] = 0x01; /* PM io base read only bit */
pci_conf[0x80] = 0;
- if (s->kvm_enabled) {
+ if (!s->smm_enabled) {
/* Mark SMM as already inited (until KVM supports SMM). */
pci_conf[0x5B] = 0x02;
}
- piix4_update_hotplug(s);
+ pm_io_space_update(s);
+ acpi_pcihp_reset(&s->acpi_pci_hotplug);
}
static void piix4_pm_powerdown_req(Notifier *n, void *opaque)
acpi_pm1_evt_power_down(&s->ar);
}
+static void piix4_device_plug_cb(HotplugHandler *hotplug_dev,
+ DeviceState *dev, Error **errp)
+{
+ PIIX4PMState *s = PIIX4_PM(hotplug_dev);
+
+ if (s->acpi_memory_hotplug.is_enabled &&
+ object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) {
+ acpi_memory_plug_cb(&s->ar, s->irq, &s->acpi_memory_hotplug, dev, errp);
+ } else if (object_dynamic_cast(OBJECT(dev), TYPE_PCI_DEVICE)) {
+ acpi_pcihp_device_plug_cb(&s->ar, s->irq, &s->acpi_pci_hotplug, dev,
+ errp);
+ } else if (object_dynamic_cast(OBJECT(dev), TYPE_CPU)) {
+ acpi_cpu_plug_cb(&s->ar, s->irq, &s->gpe_cpu, dev, errp);
+ } else {
+ error_setg(errp, "acpi: device plug request for not supported device"
+ " type: %s", object_get_typename(OBJECT(dev)));
+ }
+}
+
+static void piix4_device_unplug_request_cb(HotplugHandler *hotplug_dev,
+ DeviceState *dev, Error **errp)
+{
+ PIIX4PMState *s = PIIX4_PM(hotplug_dev);
+
+ if (s->acpi_memory_hotplug.is_enabled &&
+ object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) {
+ acpi_memory_unplug_request_cb(&s->ar, s->irq, &s->acpi_memory_hotplug,
+ dev, errp);
+ } else if (object_dynamic_cast(OBJECT(dev), TYPE_PCI_DEVICE)) {
+ acpi_pcihp_device_unplug_cb(&s->ar, s->irq, &s->acpi_pci_hotplug, dev,
+ errp);
+ } else {
+ error_setg(errp, "acpi: device unplug request for not supported device"
+ " type: %s", object_get_typename(OBJECT(dev)));
+ }
+}
+
+static void piix4_device_unplug_cb(HotplugHandler *hotplug_dev,
+ DeviceState *dev, Error **errp)
+{
+ PIIX4PMState *s = PIIX4_PM(hotplug_dev);
+
+ if (s->acpi_memory_hotplug.is_enabled &&
+ object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) {
+ acpi_memory_unplug_cb(&s->acpi_memory_hotplug, dev, errp);
+ } else {
+ error_setg(errp, "acpi: device unplug for not supported device"
+ " type: %s", object_get_typename(OBJECT(dev)));
+ }
+}
+
+static void piix4_update_bus_hotplug(PCIBus *pci_bus, void *opaque)
+{
+ PIIX4PMState *s = opaque;
+
+ qbus_set_hotplug_handler(BUS(pci_bus), DEVICE(s), &error_abort);
+}
+
static void piix4_pm_machine_ready(Notifier *n, void *opaque)
{
PIIX4PMState *s = container_of(n, PIIX4PMState, machine_ready);
+ PCIDevice *d = PCI_DEVICE(s);
+ MemoryRegion *io_as = pci_address_space_io(d);
uint8_t *pci_conf;
- pci_conf = s->dev.config;
- pci_conf[0x5f] = (isa_is_ioport_assigned(0x378) ? 0x80 : 0) | 0x10;
+ pci_conf = d->config;
+ pci_conf[0x5f] = 0x10 |
+ (memory_region_present(io_as, 0x378) ? 0x80 : 0);
pci_conf[0x63] = 0x60;
- pci_conf[0x67] = (isa_is_ioport_assigned(0x3f8) ? 0x08 : 0) |
- (isa_is_ioport_assigned(0x2f8) ? 0x90 : 0);
+ pci_conf[0x67] = (memory_region_present(io_as, 0x3f8) ? 0x08 : 0) |
+ (memory_region_present(io_as, 0x2f8) ? 0x90 : 0);
+
+ if (s->use_acpi_pci_hotplug) {
+ pci_for_each_bus(d->bus, piix4_update_bus_hotplug, s);
+ } else {
+ piix4_update_bus_hotplug(d->bus, s);
+ }
+}
+static void piix4_pm_add_propeties(PIIX4PMState *s)
+{
+ static const uint8_t acpi_enable_cmd = ACPI_ENABLE;
+ static const uint8_t acpi_disable_cmd = ACPI_DISABLE;
+ static const uint32_t gpe0_blk = GPE_BASE;
+ static const uint32_t gpe0_blk_len = GPE_LEN;
+ static const uint16_t sci_int = 9;
+
+ object_property_add_uint8_ptr(OBJECT(s), ACPI_PM_PROP_ACPI_ENABLE_CMD,
+ &acpi_enable_cmd, NULL);
+ object_property_add_uint8_ptr(OBJECT(s), ACPI_PM_PROP_ACPI_DISABLE_CMD,
+ &acpi_disable_cmd, NULL);
+ object_property_add_uint32_ptr(OBJECT(s), ACPI_PM_PROP_GPE0_BLK,
+ &gpe0_blk, NULL);
+ object_property_add_uint32_ptr(OBJECT(s), ACPI_PM_PROP_GPE0_BLK_LEN,
+ &gpe0_blk_len, NULL);
+ object_property_add_uint16_ptr(OBJECT(s), ACPI_PM_PROP_SCI_INT,
+ &sci_int, NULL);
+ object_property_add_uint32_ptr(OBJECT(s), ACPI_PM_PROP_PM_IO_BASE,
+ &s->io_base, NULL);
}
-static int piix4_pm_initfn(PCIDevice *dev)
+static void piix4_pm_realize(PCIDevice *dev, Error **errp)
{
- PIIX4PMState *s = DO_UPCAST(PIIX4PMState, dev, dev);
+ PIIX4PMState *s = PIIX4_PM(dev);
uint8_t *pci_conf;
- pci_conf = s->dev.config;
+ pci_conf = dev->config;
pci_conf[0x06] = 0x80;
pci_conf[0x07] = 0x02;
pci_conf[0x09] = 0x00;
/* APM */
apm_init(dev, &s->apm, apm_ctrl_changed, s);
- if (s->kvm_enabled) {
+ if (!s->smm_enabled) {
/* Mark SMM as already inited to prevent SMM from running. KVM does not
* support SMM mode. */
pci_conf[0x5B] = 0x02;
pci_conf[0x90] = s->smb_io_base | 1;
pci_conf[0x91] = s->smb_io_base >> 8;
pci_conf[0xd2] = 0x09;
- pm_smbus_init(&s->dev.qdev, &s->smb);
+ pm_smbus_init(DEVICE(dev), &s->smb);
memory_region_set_enabled(&s->smb.io, pci_conf[0xd2] & 1);
memory_region_add_subregion(pci_address_space_io(dev),
s->smb_io_base, &s->smb.io);
- memory_region_init(&s->io, "piix4-pm", 64);
+ memory_region_init(&s->io, OBJECT(s), "piix4-pm", 64);
memory_region_set_enabled(&s->io, false);
memory_region_add_subregion(pci_address_space_io(dev),
0, &s->io);
acpi_pm_tmr_init(&s->ar, pm_tmr_timer, &s->io);
acpi_pm1_evt_init(&s->ar, pm_tmr_timer, &s->io);
- acpi_pm1_cnt_init(&s->ar, &s->io, s->s4_val);
+ acpi_pm1_cnt_init(&s->ar, &s->io, s->disable_s3, s->disable_s4, s->s4_val);
acpi_gpe_init(&s->ar, GPE_LEN);
s->powerdown_notifier.notify = piix4_pm_powerdown_req;
piix4_acpi_system_hot_add_init(pci_address_space_io(dev), dev->bus, s);
- return 0;
+ piix4_pm_add_propeties(s);
}
-i2c_bus *piix4_pm_init(PCIBus *bus, int devfn, uint32_t smb_io_base,
- qemu_irq sci_irq, qemu_irq smi_irq,
- int kvm_enabled, void *fw_cfg)
+Object *piix4_pm_find(void)
{
- PCIDevice *dev;
- PIIX4PMState *s;
-
- dev = pci_create(bus, devfn, "PIIX4_PM");
- qdev_prop_set_uint32(&dev->qdev, "smb_io_base", smb_io_base);
-
- s = DO_UPCAST(PIIX4PMState, dev, dev);
- s->irq = sci_irq;
- s->smi_irq = smi_irq;
- s->kvm_enabled = kvm_enabled;
-
- qdev_init_nofail(&dev->qdev);
+ bool ambig;
+ Object *o = object_resolve_path_type("", TYPE_PIIX4_PM, &ambig);
- if (fw_cfg) {
- uint8_t suspend[6] = {128, 0, 0, 129, 128, 128};
- suspend[3] = 1 | ((!s->disable_s3) << 7);
- suspend[4] = s->s4_val | ((!s->disable_s4) << 7);
-
- fw_cfg_add_file(fw_cfg, "etc/system-states", g_memdup(suspend, 6), 6);
+ if (ambig || !o) {
+ return NULL;
}
-
- return s->smb.smbus;
+ return o;
}
-static Property piix4_pm_properties[] = {
- DEFINE_PROP_UINT32("smb_io_base", PIIX4PMState, smb_io_base, 0),
- DEFINE_PROP_UINT8("disable_s3", PIIX4PMState, disable_s3, 0),
- DEFINE_PROP_UINT8("disable_s4", PIIX4PMState, disable_s4, 0),
- DEFINE_PROP_UINT8("s4_val", PIIX4PMState, s4_val, 2),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void piix4_pm_class_init(ObjectClass *klass, void *data)
+I2CBus *piix4_pm_init(PCIBus *bus, int devfn, uint32_t smb_io_base,
+ qemu_irq sci_irq, qemu_irq smi_irq,
+ int smm_enabled, DeviceState **piix4_pm)
{
- DeviceClass *dc = DEVICE_CLASS(klass);
- PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+ DeviceState *dev;
+ PIIX4PMState *s;
- k->no_hotplug = 1;
- k->init = piix4_pm_initfn;
- k->config_write = pm_write_config;
- k->vendor_id = PCI_VENDOR_ID_INTEL;
- k->device_id = PCI_DEVICE_ID_INTEL_82371AB_3;
- k->revision = 0x03;
- k->class_id = PCI_CLASS_BRIDGE_OTHER;
- dc->desc = "PM";
- dc->no_user = 1;
- dc->vmsd = &vmstate_acpi;
- dc->props = piix4_pm_properties;
-}
+ dev = DEVICE(pci_create(bus, devfn, TYPE_PIIX4_PM));
+ qdev_prop_set_uint32(dev, "smb_io_base", smb_io_base);
+ if (piix4_pm) {
+ *piix4_pm = dev;
+ }
-static const TypeInfo piix4_pm_info = {
- .name = "PIIX4_PM",
- .parent = TYPE_PCI_DEVICE,
- .instance_size = sizeof(PIIX4PMState),
- .class_init = piix4_pm_class_init,
-};
+ s = PIIX4_PM(dev);
+ s->irq = sci_irq;
+ s->smi_irq = smi_irq;
+ s->smm_enabled = smm_enabled;
+ if (xen_enabled()) {
+ s->use_acpi_pci_hotplug = false;
+ }
-static void piix4_pm_register_types(void)
-{
- type_register_static(&piix4_pm_info);
-}
+ qdev_init_nofail(dev);
-type_init(piix4_pm_register_types)
+ return s->smb.smbus;
+}
static uint64_t gpe_readb(void *opaque, hwaddr addr, unsigned width)
{
PIIX4PMState *s = opaque;
uint32_t val = acpi_gpe_ioport_readb(&s->ar, addr);
- PIIX4_DPRINTF("gpe read %x == %x\n", addr, val);
+ PIIX4_DPRINTF("gpe read %" HWADDR_PRIx " == %" PRIu32 "\n", addr, val);
return val;
}
PIIX4PMState *s = opaque;
acpi_gpe_ioport_writeb(&s->ar, addr, val);
- pm_update_sci(s);
+ acpi_update_sci(&s->ar, s->irq);
- PIIX4_DPRINTF("gpe write %x <== %d\n", addr, val);
+ PIIX4_DPRINTF("gpe write %" HWADDR_PRIx " <== %" PRIu64 "\n", addr, val);
}
static const MemoryRegionOps piix4_gpe_ops = {
.endianness = DEVICE_LITTLE_ENDIAN,
};
-static uint64_t pci_read(void *opaque, hwaddr addr, unsigned int size)
+static void piix4_acpi_system_hot_add_init(MemoryRegion *parent,
+ PCIBus *bus, PIIX4PMState *s)
{
- PIIX4PMState *s = opaque;
- uint32_t val = 0;
-
- switch (addr) {
- case PCI_UP_BASE - PCI_HOTPLUG_ADDR:
- /* Manufacture an "up" value to cause a device check on any hotplug
- * slot with a device. Extra device checks are harmless. */
- val = s->pci0_slot_device_present & s->pci0_hotplug_enable;
- PIIX4_DPRINTF("pci_up_read %x\n", val);
- break;
- case PCI_DOWN_BASE - PCI_HOTPLUG_ADDR:
- val = s->pci0_status.down;
- PIIX4_DPRINTF("pci_down_read %x\n", val);
- break;
- case PCI_EJ_BASE - PCI_HOTPLUG_ADDR:
- /* No feature defined yet */
- PIIX4_DPRINTF("pci_features_read %x\n", val);
- break;
- case PCI_RMV_BASE - PCI_HOTPLUG_ADDR:
- val = s->pci0_hotplug_enable;
- break;
- default:
- break;
- }
+ memory_region_init_io(&s->io_gpe, OBJECT(s), &piix4_gpe_ops, s,
+ "acpi-gpe0", GPE_LEN);
+ memory_region_add_subregion(parent, GPE_BASE, &s->io_gpe);
- return val;
-}
+ acpi_pcihp_init(OBJECT(s), &s->acpi_pci_hotplug, bus, parent,
+ s->use_acpi_pci_hotplug);
-static void pci_write(void *opaque, hwaddr addr, uint64_t data,
- unsigned int size)
-{
- switch (addr) {
- case PCI_EJ_BASE - PCI_HOTPLUG_ADDR:
- acpi_piix_eject_slot(opaque, (uint32_t)data);
- PIIX4_DPRINTF("pciej write %" HWADDR_PRIx " <== % " PRIu64 "\n",
- addr, data);
- break;
- default:
- break;
+ acpi_cpu_hotplug_init(parent, OBJECT(s), &s->gpe_cpu,
+ PIIX4_CPU_HOTPLUG_IO_BASE);
+
+ if (s->acpi_memory_hotplug.is_enabled) {
+ acpi_memory_hotplug_init(parent, OBJECT(s), &s->acpi_memory_hotplug);
}
}
-static const MemoryRegionOps piix4_pci_ops = {
- .read = pci_read,
- .write = pci_write,
- .endianness = DEVICE_LITTLE_ENDIAN,
- .valid = {
- .min_access_size = 4,
- .max_access_size = 4,
- },
-};
-
-static int piix4_device_hotplug(DeviceState *qdev, PCIDevice *dev,
- PCIHotplugState state);
-
-static void piix4_acpi_system_hot_add_init(MemoryRegion *parent,
- PCIBus *bus, PIIX4PMState *s)
+static void piix4_ospm_status(AcpiDeviceIf *adev, ACPIOSTInfoList ***list)
{
- memory_region_init_io(&s->io_gpe, &piix4_gpe_ops, s, "apci-gpe0",
- GPE_LEN);
- memory_region_add_subregion(parent, GPE_BASE, &s->io_gpe);
+ PIIX4PMState *s = PIIX4_PM(adev);
- memory_region_init_io(&s->io_pci, &piix4_pci_ops, s, "apci-pci-hotplug",
- PCI_HOTPLUG_SIZE);
- memory_region_add_subregion(parent, PCI_HOTPLUG_ADDR,
- &s->io_pci);
- pci_bus_hotplug(bus, piix4_device_hotplug, &s->dev.qdev);
+ acpi_memory_ospm_status(&s->acpi_memory_hotplug, list);
}
-static void enable_device(PIIX4PMState *s, int slot)
-{
- s->ar.gpe.sts[0] |= PIIX4_PCI_HOTPLUG_STATUS;
- s->pci0_slot_device_present |= (1U << slot);
-}
+static Property piix4_pm_properties[] = {
+ DEFINE_PROP_UINT32("smb_io_base", PIIX4PMState, smb_io_base, 0),
+ DEFINE_PROP_UINT8(ACPI_PM_PROP_S3_DISABLED, PIIX4PMState, disable_s3, 0),
+ DEFINE_PROP_UINT8(ACPI_PM_PROP_S4_DISABLED, PIIX4PMState, disable_s4, 0),
+ DEFINE_PROP_UINT8(ACPI_PM_PROP_S4_VAL, PIIX4PMState, s4_val, 2),
+ DEFINE_PROP_BOOL("acpi-pci-hotplug-with-bridge-support", PIIX4PMState,
+ use_acpi_pci_hotplug, true),
+ DEFINE_PROP_BOOL("memory-hotplug-support", PIIX4PMState,
+ acpi_memory_hotplug.is_enabled, true),
+ DEFINE_PROP_END_OF_LIST(),
+};
-static void disable_device(PIIX4PMState *s, int slot)
+static void piix4_pm_class_init(ObjectClass *klass, void *data)
{
- s->ar.gpe.sts[0] |= PIIX4_PCI_HOTPLUG_STATUS;
- s->pci0_status.down |= (1U << slot);
-}
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+ HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(klass);
+ AcpiDeviceIfClass *adevc = ACPI_DEVICE_IF_CLASS(klass);
-static int piix4_device_hotplug(DeviceState *qdev, PCIDevice *dev,
- PCIHotplugState state)
-{
- int slot = PCI_SLOT(dev->devfn);
- PIIX4PMState *s = DO_UPCAST(PIIX4PMState, dev,
- PCI_DEVICE(qdev));
-
- /* Don't send event when device is enabled during qemu machine creation:
- * it is present on boot, no hotplug event is necessary. We do send an
- * event when the device is disabled later. */
- if (state == PCI_COLDPLUG_ENABLED) {
- s->pci0_slot_device_present |= (1U << slot);
- return 0;
- }
+ k->realize = piix4_pm_realize;
+ k->config_write = pm_write_config;
+ k->vendor_id = PCI_VENDOR_ID_INTEL;
+ k->device_id = PCI_DEVICE_ID_INTEL_82371AB_3;
+ k->revision = 0x03;
+ k->class_id = PCI_CLASS_BRIDGE_OTHER;
+ dc->desc = "PM";
+ dc->vmsd = &vmstate_acpi;
+ dc->props = piix4_pm_properties;
+ /*
+ * Reason: part of PIIX4 southbridge, needs to be wired up,
+ * e.g. by mips_malta_init()
+ */
+ dc->cannot_instantiate_with_device_add_yet = true;
+ dc->hotpluggable = false;
+ hc->plug = piix4_device_plug_cb;
+ hc->unplug_request = piix4_device_unplug_request_cb;
+ hc->unplug = piix4_device_unplug_cb;
+ adevc->ospm_status = piix4_ospm_status;
+}
- if (state == PCI_HOTPLUG_ENABLED) {
- enable_device(s, slot);
- } else {
- disable_device(s, slot);
+static const TypeInfo piix4_pm_info = {
+ .name = TYPE_PIIX4_PM,
+ .parent = TYPE_PCI_DEVICE,
+ .instance_size = sizeof(PIIX4PMState),
+ .class_init = piix4_pm_class_init,
+ .interfaces = (InterfaceInfo[]) {
+ { TYPE_HOTPLUG_HANDLER },
+ { TYPE_ACPI_DEVICE_IF },
+ { }
}
+};
- pm_update_sci(s);
-
- return 0;
+static void piix4_pm_register_types(void)
+{
+ type_register_static(&piix4_pm_info);
}
+
+type_init(piix4_pm_register_types)