This will allow us to update dimm state on OSPM-initiated eject operations e.g. with "echo 1 > /sys/bus/acpi/devices/PNP0C80:00/eject"
v3->v4: Add support for ich9 --- docs/specs/acpi_hotplug.txt | 7 +++++++ hw/acpi_ich9.c | 7 +++++-- hw/acpi_ich9.h | 1 + hw/acpi_piix4.c | 9 ++++++--- hw/dimm.c | 4 ++++ hw/dimm.h | 3 ++- 6 files changed, 25 insertions(+), 6 deletions(-)
diff --git a/docs/specs/acpi_hotplug.txt b/docs/specs/acpi_hotplug.txt index 536da16..69868fe 100644 --- a/docs/specs/acpi_hotplug.txt +++ b/docs/specs/acpi_hotplug.txt @@ -45,3 +45,10 @@ insertion failed. Written by ACPI memory device _OST method to notify qemu of failed hot-add. Write-only.
+Memory Dimm _PS3 power-off initiated by OSPM (IO port 0xafa4, 1-byte access): +--------------------------------------------------------------- +Dimm hot-add _PS3 initiated by OSPM. Byte value indicates Dimm slot which +entered D3 state. + +Written by ACPI memory device _PS3 method to notify qemu of power-off state for +the dimm. Write-only. diff --git a/hw/acpi_ich9.c b/hw/acpi_ich9.c index 2705230..5e7fca6 100644 --- a/hw/acpi_ich9.c +++ b/hw/acpi_ich9.c @@ -120,6 +120,9 @@ static void memhp_writeb(void *opaque, uint32_t addr, uint32_t val) case ICH9_MEM_OST_ADD_FAIL - ICH9_MEM_BASE: dimm_notify(val, DIMM_ADD_FAIL); break; + case ICH9_MEM_PS3 - ICH9_MEM_BASE: + dimm_notify(val, DIMM_OSPM_POWEROFF); + break; default: ICH9_DEBUG("memhp write invalid %x <== %d\n", addr, val); } @@ -134,7 +137,7 @@ static const MemoryRegionOps ich9_memhp_ops = { }, { .offset = ICH9_MEM_EJ_BASE - ICH9_MEM_BASE, - .len = 4, .size = 1, + .len = 5, .size = 1, .write = memhp_writeb, }, PORTIO_END_OF_LIST() @@ -321,7 +324,7 @@ void ich9_pm_init(void *device, qemu_irq sci_irq, qemu_irq cmos_s3) memory_region_add_subregion(&pm->io, ICH9_PMIO_SMI_EN, &pm->io_smi);
memory_region_init_io(&pm->io_memhp, &ich9_memhp_ops, pm, "apci-memhp0", - DIMM_BITMAP_BYTES + 4); + DIMM_BITMAP_BYTES + 5); memory_region_add_subregion(get_system_io(), ICH9_MEM_BASE, &pm->io_memhp);
dimm_bus_hotplug(ich9_dimm_hotplug, ich9_dimm_revert, &lpc->d.qdev); diff --git a/hw/acpi_ich9.h b/hw/acpi_ich9.h index 8f57cd8..816d453 100644 --- a/hw/acpi_ich9.h +++ b/hw/acpi_ich9.h @@ -29,6 +29,7 @@ #define ICH9_MEM_OST_REMOVE_FAIL 0xafa1 #define ICH9_MEM_OST_ADD_SUCCESS 0xafa2 #define ICH9_MEM_OST_ADD_FAIL 0xafa3 +#define ICH9_MEM_PS3 0xafa4
typedef struct ICH9LPCPMRegs { /* diff --git a/hw/acpi_piix4.c b/hw/acpi_piix4.c index 70aa480..6c953c2 100644 --- a/hw/acpi_piix4.c +++ b/hw/acpi_piix4.c @@ -54,6 +54,7 @@ #define MEM_OST_REMOVE_FAIL 0xafa1 #define MEM_OST_ADD_SUCCESS 0xafa2 #define MEM_OST_ADD_FAIL 0xafa3 +#define MEM_PS3 0xafa4
#define PIIX4_MEM_HOTPLUG_STATUS 8 #define PIIX4_PCI_HOTPLUG_STATUS 2 @@ -564,6 +565,9 @@ static void memhp_writeb(void *opaque, uint32_t addr, uint32_t val) case MEM_OST_ADD_FAIL - MEM_BASE: dimm_notify(val, DIMM_ADD_FAIL); break; + case MEM_PS3 - MEM_BASE: + dimm_notify(val, DIMM_OSPM_POWEROFF); + break; default: PIIX4_DPRINTF("memhp write invalid %x <== %d\n", addr, val); } @@ -577,7 +581,7 @@ static const MemoryRegionOps piix4_memhp_ops = { .read = memhp_readb, }, { - .offset = MEM_EJ_BASE - MEM_BASE, .len = 4, + .offset = MEM_EJ_BASE - MEM_BASE, .len = 5, .size = 1, .write = memhp_writeb, }, @@ -666,7 +670,7 @@ static void piix4_acpi_system_hot_add_init(PCIBus *bus, PIIX4PMState *s) memory_region_add_subregion(get_system_io(), PCI_HOTPLUG_ADDR, &s->io_pci); memory_region_init_io(&s->io_memhp, &piix4_memhp_ops, s, "apci-memhp0", - DIMM_BITMAP_BYTES + 4); + DIMM_BITMAP_BYTES + 5); memory_region_add_subregion(get_system_io(), MEM_BASE, &s->io_memhp);
for (i = 0; i < DIMM_BITMAP_BYTES; i++) { @@ -726,7 +730,6 @@ static int piix4_dimm_revert(DeviceState *qdev, DimmDevice *dev, int add) struct gpe_regs *g = &s->gperegs; DimmDevice *slot = DIMM(dev); int idx = slot->idx; - if (add) { g->mems_sts[idx/8] &= ~(1 << (idx%8)); } else { diff --git a/hw/dimm.c b/hw/dimm.c index 69b97b6..2454e38 100644 --- a/hw/dimm.c +++ b/hw/dimm.c @@ -407,6 +407,10 @@ void dimm_notify(uint32_t idx, uint32_t event) qdev_unplug_complete((DeviceState *)slot, NULL); QTAILQ_REMOVE(&bus->dimmlist, slot, nextdimm); QTAILQ_INSERT_TAIL(&bus->dimm_hp_result_queue, result, next); + case DIMM_OSPM_POWEROFF: + if (bus->dimm_revert) { + bus->dimm_revert(bus->dimm_hotplug_qdev, slot, 1); + } default: g_free(result); break; diff --git a/hw/dimm.h b/hw/dimm.h index f43f745..081f2db 100644 --- a/hw/dimm.h +++ b/hw/dimm.h @@ -15,7 +15,8 @@ typedef enum { DIMM_REMOVE_SUCCESS = 0, DIMM_REMOVE_FAIL = 1, DIMM_ADD_SUCCESS = 2, - DIMM_ADD_FAIL = 3 + DIMM_ADD_FAIL = 3, + DIMM_OSPM_POWEROFF = 4 } dimm_hp_result_code;
typedef enum {