[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-devel] [PATCH 13/16] acpi/piix4: introduce memory hot-plug interfa
From: |
Igor Mammedov |
Subject: |
[Qemu-devel] [PATCH 13/16] acpi/piix4: introduce memory hot-plug interface QEMU<->ACPI BIOS |
Date: |
Tue, 23 Jul 2013 18:23:09 +0200 |
- implements QEMU part of memory hotplug protocol described at
docs/specs/acpi_mem_hotplug.txt
- handles memory add notification event.
Signed-off-by: Igor Mammedov <address@hidden>
---
docs/specs/acpi_mem_hotplug.txt | 38 +++++++++
hw/acpi/piix4.c | 170 ++++++++++++++++++++++++++++++++++++++-
2 files changed, 207 insertions(+), 1 deletions(-)
create mode 100644 docs/specs/acpi_mem_hotplug.txt
diff --git a/docs/specs/acpi_mem_hotplug.txt b/docs/specs/acpi_mem_hotplug.txt
new file mode 100644
index 0000000..33b7aa0
--- /dev/null
+++ b/docs/specs/acpi_mem_hotplug.txt
@@ -0,0 +1,38 @@
+QEMU<->ACPI BIOS memory hotplug interface
+--------------------------------------
+
+ACPI BIOS GPE.3 handler is dedicated for notifying OS of memory hot-add
+or hot-remove events. Read-only.
+
+Memory Dimm hot-plug interface (IO port 0xaf80-0xaf97, 1-4 byte access):
+---------------------------------------------------------------
+0xaf80:
+ read access:
+ [0x0-0x3] Lo part of memory device phys address
+ [0x4-0x7] Hi part of memory device phys address
+ [0x8-0xb] Lo part of memory device size in bytes
+ [0xc-0xf] Hi part of memory device size in bytes
+ [0x14] Memory hot-plug interface version
+ [0x15] Memory device status fields
+ bits:
+ 1: device is enabled, end may be used by guest code
+ 2: device insert event, used by ACPI BIOS to distinguish
+ device for which no device check event to OSPM was issued
+ [0x16-0x17] reserved
+
+ write access:
+ [0x0-0x3] Memory device slot selector, selects active memory device.
+ All following accesses to other registers in 0xaf80-0xaf97
+ region will read/store data from/to selected memory device.
+ [0x4-0x7] OST event code reported by OSPM
+ [0x8-0xb] OST status code reported by OSPM
+ [0x15] Memory device status fields
+ bits:
+ 2: if set to 1 clears device insert event, set by ACPI BIOS
+ after it has sent device check event to OSPM for
+ seleted memory device
+
+Selecting memory device slot beyond present range has no effect on platform:
+ - following write access to memory hot-plug registers except of
+ [0x0-0x3] is ignored;
+ - following read access to memory hot-plug registers returns 0
diff --git a/hw/acpi/piix4.c b/hw/acpi/piix4.c
index c077a7a..f58a5bf 100644
--- a/hw/acpi/piix4.c
+++ b/hw/acpi/piix4.c
@@ -29,6 +29,8 @@
#include "exec/ioport.h"
#include "hw/nvram/fw_cfg.h"
#include "exec/address-spaces.h"
+#include "hw/mem-hotplug/dimm.h"
+#include "qemu/config-file.h"
//#define DEBUG
@@ -50,9 +52,12 @@
#define PIIX4_PROC_BASE 0xaf00
#define PIIX4_PROC_LEN 32
+#define PIIX4_MEM_BASE 0xaf80
+#define PIIX4_MEM_LEN 24
#define PIIX4_PCI_HOTPLUG_STATUS 2
#define PIIX4_CPU_HOTPLUG_STATUS 4
+#define PIIX4_MEM_HOTPLUG_STATUS 8
struct pci_status {
uint32_t up; /* deprecated, maintained for migration compatibility */
@@ -63,6 +68,20 @@ typedef struct CPUStatus {
uint8_t sts[PIIX4_PROC_LEN];
} CPUStatus;
+typedef struct MemStatus {
+ DimmDevice *dimm;
+ bool is_enabled;
+ bool is_inserting;
+ uint32_t ost_event;
+ uint32_t ost_status;
+} MemStatus;
+
+typedef struct mem_hotplug_state {
+ uint32_t selector;
+ uint32_t dev_count;
+ MemStatus *devs;
+} mem_hotplug_state;
+
typedef struct PIIX4PMState {
PCIDevice dev;
@@ -70,6 +89,7 @@ typedef struct PIIX4PMState {
MemoryRegion io_gpe;
MemoryRegion io_pci;
MemoryRegion io_cpu;
+ MemoryRegion io_mem;
ACPIREGS ar;
APMState apm;
@@ -96,6 +116,9 @@ typedef struct PIIX4PMState {
Notifier cpu_added_notifier;
PcGuestInfo *guest_info;
+
+ Notifier mem_added_notifier;
+ mem_hotplug_state gpe_mem;
} PIIX4PMState;
static void piix4_acpi_system_hot_add_init(MemoryRegion *parent,
@@ -115,7 +138,8 @@ static void pm_update_sci(PIIX4PMState *s)
ACPI_BITMASK_GLOBAL_LOCK_ENABLE |
ACPI_BITMASK_TIMER_ENABLE)) != 0) ||
(((s->ar.gpe.sts[0] & s->ar.gpe.en[0]) &
- (PIIX4_PCI_HOTPLUG_STATUS | PIIX4_CPU_HOTPLUG_STATUS)) != 0);
+ (PIIX4_PCI_HOTPLUG_STATUS | PIIX4_CPU_HOTPLUG_STATUS |
+ PIIX4_MEM_HOTPLUG_STATUS)) != 0);
qemu_set_irq(s->irq, sci_level);
/* schedule a timer interruption if needed */
@@ -706,6 +730,143 @@ static void piix4_init_cpu_status(CPUState *cpu, void
*data)
g->sts[id / 8] |= (1 << (id % 8));
}
+static uint64_t piix4_hp_mem_read(void *opaque, hwaddr addr, unsigned int size)
+{
+ PIIX4PMState *s = opaque;
+ uint32_t val = 0;
+ mem_hotplug_state *mem_st = &s->gpe_mem;
+ MemStatus *mdev;
+
+ if (mem_st->selector >= mem_st->dev_count) {
+ return 0;
+ }
+
+ mdev = &mem_st->devs[mem_st->selector];
+ switch (addr) {
+ case 0x0: /* Lo part of phys address where DIMM is mapped */
+ val = mdev->dimm->start;
+ break;
+ case 0x4: /* Hi part of phys address where DIMM is mapped */
+ val = mdev->dimm->start >> 32;
+ break;
+ case 0x8: /* Lo part of DIMM size */
+ val = mdev->dimm->size;
+ break;
+ case 0xc: /* Hi part of DIMM size */
+ val = mdev->dimm->size >> 32;
+ break;
+ case 0x10: /* node proximity for _PXM method */
+ val = mdev->dimm->node;
+ break;
+ case 0x14: /* intf version */
+ val = 1;
+ break;
+ case 0x15: /* pack and return is_* fields */
+ val |= mdev->is_enabled ? 1 : 0;
+ val |= mdev->is_inserting ? 2 : 0;
+ break;
+ }
+ return val;
+}
+
+static void piix4_hp_mem_write(void *opaque, hwaddr addr, uint64_t data,
+ unsigned int size)
+{
+ PIIX4PMState *s = opaque;
+ mem_hotplug_state *mem_st = &s->gpe_mem;
+ MemStatus *mdev;
+
+ if (!mem_st->dev_count) {
+ return;
+ }
+
+ if (addr) {
+ if (mem_st->selector >= mem_st->dev_count) {
+ return;
+ }
+ }
+
+ switch (addr) {
+ case 0x0: /* DIMM slot selector */
+ mem_st->selector = data;
+ break;
+ case 0x4: /* _OST event */
+ mdev = &mem_st->devs[mem_st->selector];
+ if (data == 1) {
+ /* TODO: handle device insert OST event */
+ } else if (data == 3) {
+ /* TODO: handle device remove OST event */
+ }
+ mdev->ost_event = data;
+ break;
+ case 0x8: /* _OST status */
+ mdev = &mem_st->devs[mem_st->selector];
+ mdev->ost_status = data;
+ /* TODO: report async error */
+ /* TODO: implement memory removal on guest signal */
+ break;
+ case 0x15:
+ mdev = &mem_st->devs[mem_st->selector];
+ if (data & 2) { /* clear insert event */
+ mdev->is_inserting = false;
+ }
+ break;
+ }
+
+}
+static const MemoryRegionOps mem_hotplug_ops = {
+ .read = piix4_hp_mem_read,
+ .write = piix4_hp_mem_write,
+ .endianness = DEVICE_LITTLE_ENDIAN,
+ .valid = {
+ .min_access_size = 1,
+ .max_access_size = 4,
+ },
+};
+
+static void piix4_init_mem_status(PIIX4PMState *s)
+{
+ mem_hotplug_state *mem_st = &s->gpe_mem;
+ QemuOpts *opts = qemu_opts_find(qemu_find_opts("memory-opts"), NULL);
+
+ if (!opts) { /* no -m x,... was passed to cmd line so no men hotplug */
+ return;
+ }
+
+ mem_st->dev_count = qemu_opt_get_number(opts, "slots", 0);
+
+ if (!mem_st->dev_count) {
+ return;
+ }
+
+ mem_st->devs = g_malloc0(sizeof(MemStatus) * mem_st->dev_count);
+}
+
+static void piix4_mem_added_req(Notifier *n, void *opaque)
+{
+ PIIX4PMState *s = container_of(n, PIIX4PMState, mem_added_notifier);
+ DeviceState *dev = DEVICE(opaque);
+ DimmDevice *dimm = DIMM(dev);
+ mem_hotplug_state *mem_st = &s->gpe_mem;
+ MemStatus *mdev;
+
+ if (dimm->slot >= mem_st->dev_count) {
+ return;
+ }
+
+ mdev = &mem_st->devs[dimm->slot];
+ object_property_add_link(OBJECT(s), dev->id, TYPE_DIMM,
+ (Object **) &mdev->dimm, NULL);
+ object_property_set_link(OBJECT(s), OBJECT(dimm), dev->id, NULL);
+
+ mdev->is_enabled = true;
+ mdev->is_inserting = true;
+
+ /* do ACPI magic */
+ s->ar.gpe.sts[0] |= PIIX4_MEM_HOTPLUG_STATUS;
+ pm_update_sci(s);
+}
+
static int piix4_device_hotplug(DeviceState *qdev, PCIDevice *dev,
PCIHotplugState state);
@@ -728,6 +889,13 @@ static void piix4_acpi_system_hot_add_init(MemoryRegion
*parent,
memory_region_add_subregion(parent, PIIX4_PROC_BASE, &s->io_cpu);
s->cpu_added_notifier.notify = piix4_cpu_added_req;
qemu_register_cpu_added_notifier(&s->cpu_added_notifier);
+
+ piix4_init_mem_status(s);
+ memory_region_init_io(&s->io_mem, &mem_hotplug_ops, s,
+ "apci-mem-hotplug", PIIX4_MEM_LEN);
+ memory_region_add_subregion(parent, PIIX4_MEM_BASE, &s->io_mem);
+ s->mem_added_notifier.notify = piix4_mem_added_req;
+ qemu_register_mem_added_notifier(&s->mem_added_notifier);
}
static void enable_device(PIIX4PMState *s, int slot)
--
1.7.1
- [Qemu-devel] [PATCH 06/16] dimm: implement dimm device abstraction, (continued)
- [Qemu-devel] [PATCH 06/16] dimm: implement dimm device abstraction, Igor Mammedov, 2013/07/23
- [Qemu-devel] [PATCH 07/16] dimm: map DimmDevice into DimBus provided address space, Igor Mammedov, 2013/07/23
- [Qemu-devel] [PATCH 08/16] pc: piix: make hotplug memory gap in high memory, Igor Mammedov, 2013/07/23
- [Qemu-devel] [PATCH 09/16] pc: i440fx: add DimmBus to chipset and map it into hotplug memory region, Igor Mammedov, 2013/07/23
- [Qemu-devel] [PATCH 10/16] dimm: add busy slot check and slot auto-allocation, Igor Mammedov, 2013/07/23
- [Qemu-devel] [PATCH 11/16] dimm: add busy address check and address auto-allocation, Igor Mammedov, 2013/07/23
- [Qemu-devel] [PATCH 12/16] dimm: introduce memory added notifier, Igor Mammedov, 2013/07/23
- [Qemu-devel] [PATCH 13/16] acpi/piix4: introduce memory hot-plug interface QEMU<->ACPI BIOS,
Igor Mammedov <=
- [Qemu-devel] [PATCH 14/16] pc: ACPI BIOS: implement memory hotplug interface, Igor Mammedov, 2013/07/23
- [Qemu-devel] [PATCH 15/16] pc: update acpi-dsdt.hex.generated and add ssdt-mem.hex.generated, Igor Mammedov, 2013/07/23
- [Qemu-devel] [PATCH 16/16] pc: ACPI BIOS: reserve SRAT entry for hotplug mem hole, Igor Mammedov, 2013/07/23
- Re: [Qemu-devel] [PATCH 00/16 RFC v6] ACPI memory hotplug, Hu Tao, 2013/07/24