Message ID | 1396618620-27823-21-git-send-email-imammedo@redhat.com |
---|---|
State | New |
Headers | show |
Hi, On Fri, Apr 04, 2014 at 03:36:45PM +0200, Igor Mammedov wrote: > - implements QEMU hardware part of memory hotplug protocol > described at "docs/specs/acpi_mem_hotplug.txt" > - handles only memory add notification event for now > [...] > + [0x4-0x7] OST event code reported by OSPM > + [0x8-0xb] OST status code reported by OSPM > + 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 */ > + } Are there any patches planned to report _OST notifications to upper management layers? E.g. some older patchseries implemented a queue for these notifications that could be queried with an "info memhp" command. As a more general question for the patchseries: How do we query status/presence of dimms present? Some posssible options could be: - info qtree: If links<> are implemented between dimms and an acpi machine adapter, would the dimms show up in the general device tree? Currently I believe they don't. - info dimm: We could have a new "info dimm" command that shows information for present DIMMs: start-end guest physical address, last _OST notification received for this DIMM, as well as backing memdev object for this dimm. (qemu) info dimm dimm0: range="start_address - end_address" memdev="obj0" _OST="last_OST message" dimm1: range="start_address - end_address" memdev="obj1" _OST="last_OST message" where last_OST message could be "hot-add succesfull", "hot-add failed", "hot-remove failed". Not sure how "hot-remove successful" would be reported though, as the dimm device would be removed (or soon to be removed) from the machine. Unless we have a separate command for OST messages received/queued, as mentioned above. If the guest does not support _OST, the OST entries would remain empty, at least giving management layer a hint that the guest may not have succesfully completed the requested hot-operation. The examples are all in hmp, but there should obviously be qmp support. Thoughts? thanks, - Vasilis
On Mon, 5 May 2014 14:20:25 +0200 Vasilis Liaskovitis <vasilis.liaskovitis@profitbricks.com> wrote: > Hi, > > On Fri, Apr 04, 2014 at 03:36:45PM +0200, Igor Mammedov wrote: > > - implements QEMU hardware part of memory hotplug protocol > > described at "docs/specs/acpi_mem_hotplug.txt" > > - handles only memory add notification event for now > > > [...] > > + [0x4-0x7] OST event code reported by OSPM > > + [0x8-0xb] OST status code reported by OSPM > > + 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 */ > > + } > > Are there any patches planned to report _OST notifications to upper management > layers? E.g. some older patchseries implemented a queue for these notifications > that could be queried with an "info memhp" command. I don't recall seeing patches "info memhp", could you point them to me, please? But I have in mind to add corresponding commands for get OST and sending corresponding QMP events. > > As a more general question for the patchseries: How do we query status/presence > of dimms present? Some posssible options could be: > > - info qtree: If links<> are implemented between dimms and an acpi machine > adapter, would the dimms show up in the general device tree? Currently I believe > they don't. > > - info dimm: We could have a new "info dimm" command that shows information for > present DIMMs: start-end guest physical address, last _OST notification received > for this DIMM, as well as backing memdev object for this dimm. I'd prefer this one for hmp and from QMP side qom-get could be used to enumerate/get properties. > > (qemu) info dimm > dimm0: range="start_address - end_address" memdev="obj0" _OST="last_OST message" > dimm1: range="start_address - end_address" memdev="obj1" _OST="last_OST message" > > where last_OST message could be "hot-add succesfull", "hot-add failed", > "hot-remove failed". Not sure how "hot-remove successful" would be reported > though, as the dimm device would be removed (or soon to be removed) from the > machine. Unless we have a separate command for OST messages received/queued, as > mentioned above. Not much could be done here except of sending QMP event. It's generic hot-unplug issue. > > If the guest does not support _OST, the OST entries would remain empty, > at least giving management layer a hint that the guest may not have succesfully > completed the requested hot-operation. > > The examples are all in hmp, but there should obviously be qmp support. > Thoughts? > > thanks, > > - Vasilis > >
On Tue, May 06, 2014 at 09:13:13AM +0200, Igor Mammedov wrote: > On Mon, 5 May 2014 14:20:25 +0200 > Vasilis Liaskovitis <vasilis.liaskovitis@profitbricks.com> wrote: > > On Fri, Apr 04, 2014 at 03:36:45PM +0200, Igor Mammedov wrote: > > > + if (data == 1) { > > > + /* TODO: handle device insert OST event */ > > > + } else if (data == 3) { > > > + /* TODO: handle device remove OST event */ > > > + } > > > > Are there any patches planned to report _OST notifications to upper management > > layers? E.g. some older patchseries implemented a queue for these notifications > > that could be queried with an "info memhp" command. > I don't recall seeing patches "info memhp", could you point them to me, please? > But I have in mind to add corresponding commands for get OST and sending > corresponding QMP events. Old patch for "info memhp" (or "info memory-hotplug") are here: http://lists.gnu.org/archive/html/qemu-devel/2012-09/msg03539.html not sure if we want a separate command though, or have eveyrhting in "info dimm" > > > > > As a more general question for the patchseries: How do we query status/presence > > of dimms present? Some posssible options could be: > > > > - info qtree: If links<> are implemented between dimms and an acpi machine > > adapter, would the dimms show up in the general device tree? Currently I believe > > they don't. > > > > - info dimm: We could have a new "info dimm" command that shows information for > > present DIMMs: start-end guest physical address, last _OST notification received > > for this DIMM, as well as backing memdev object for this dimm. > I'd prefer this one for hmp and from QMP side qom-get could be used to enumerate/get > properties. I also prefer "info dimm" for hmp. For qmp, how flexible is qom-get? Can we use a single qom-get command to e.g. receive properties of all dimm devices? I think a command that lists all dimm devices and properties could be useful. thanks, - Vasilis
diff --git a/docs/specs/acpi_mem_hotplug.txt b/docs/specs/acpi_mem_hotplug.txt new file mode 100644 index 0000000..1290994 --- /dev/null +++ b/docs/specs/acpi_mem_hotplug.txt @@ -0,0 +1,44 @@ +QEMU<->ACPI BIOS memory hotplug interface +-------------------------------------- + +ACPI BIOS GPE.3 handler is dedicated for notifying OS about memory hot-add +events. + +Memory hot-plug interface (IO port 0xa00-0xa17, 1-4 byte access): +--------------------------------------------------------------- +0xa00: + 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 + [0x10-0x13] Memory device proximity domain + [0x14] Memory device status fields + bits: + 0: Device is enabled and may be used by guest + 1: Device insert event, used to distinguish device for which + no device check event to OSPM was issued. + It's valid only when bit 1 is set. + 2-7: reserved and should be ignored by OSPM + [0x15-0x17] reserved + + write access: + [0x0-0x3] Memory device slot selector, selects active memory device. + All following accesses to other registers in 0xa00-0xa17 + 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 + [0xc-0x13] reserved, writes into it are ignored + [0x14] Memory device control fields + bits: + 0: reserved, OSPM must clear it before writing to register + 1: if set to 1 clears device insert event, set by OSPM + after it has emitted device check event for the + selected memory device + 2-7: reserved, OSPM must clear them before writing to register + +Selecting memory device slot beyond present range has no effect on platform: + - write accesses to memory hot-plug registers not documented above are + ignored + - read accesses to memory hot-plug registers not documented above return + all bits set to 1. diff --git a/hw/acpi/Makefile.objs b/hw/acpi/Makefile.objs index 397d32b..004e1b2 100644 --- a/hw/acpi/Makefile.objs +++ b/hw/acpi/Makefile.objs @@ -1 +1,2 @@ common-obj-$(CONFIG_ACPI) += core.o piix4.o ich9.o pcihp.o cpu_hotplug.o +common-obj-$(CONFIG_ACPI) += memory_hotplug.o diff --git a/hw/acpi/memory_hotplug.c b/hw/acpi/memory_hotplug.c new file mode 100644 index 0000000..b0292c8 --- /dev/null +++ b/hw/acpi/memory_hotplug.c @@ -0,0 +1,144 @@ +#include "hw/acpi/memory_hotplug.h" +#include "hw/acpi/acpi_defs.h" +#include "hw/boards.h" + +static uint64_t acpi_memory_hotplug_read(void *opaque, hwaddr addr, + unsigned int size) +{ + uint32_t val = 0; + MemHotplugState *mem_st = opaque; + 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 = object_property_get_int(OBJECT(mdev->dimm), "start", NULL); + break; + case 0x4: /* Hi part of phys address where DIMM is mapped */ + val = object_property_get_int(OBJECT(mdev->dimm), "start", NULL) >> 32; + break; + case 0x8: /* Lo part of DIMM size */ + val = object_property_get_int(OBJECT(mdev->dimm), "size", NULL); + break; + case 0xc: /* Hi part of DIMM size */ + val = object_property_get_int(OBJECT(mdev->dimm), "size", NULL) >> 32; + break; + case 0x10: /* node proximity for _PXM method */ + val = object_property_get_int(OBJECT(mdev->dimm), "node", NULL); + break; + case 0x14: /* pack and return is_* fields */ + val |= mdev->is_enabled ? 1 : 0; + val |= mdev->is_inserting ? 2 : 0; + break; + default: + val = ~0; + break; + } + return val; +} + +static void acpi_memory_hotplug_write(void *opaque, hwaddr addr, uint64_t data, + unsigned int size) +{ + MemHotplugState *mem_st = opaque; + 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 0x14: + mdev = &mem_st->devs[mem_st->selector]; + if (data & 2) { /* clear insert event */ + mdev->is_inserting = false; + } + break; + } + +} +static const MemoryRegionOps acpi_memory_hotplug_ops = { + .read = acpi_memory_hotplug_read, + .write = acpi_memory_hotplug_write, + .endianness = DEVICE_LITTLE_ENDIAN, + .valid = { + .min_access_size = 1, + .max_access_size = 4, + }, +}; + +void acpi_memory_hotplug_init(MemoryRegion *as, Object *owner, + MemHotplugState *state) +{ + MachineState *machine = MACHINE(qdev_get_machine()); + + state->dev_count = machine->init_args.ram_slots; + if (!state->dev_count) { + return; + } + + state->devs = g_malloc0(sizeof(*state->devs) * state->dev_count); + memory_region_init_io(&state->io, owner, &acpi_memory_hotplug_ops, state, + "apci-mem-hotplug", ACPI_MEMORY_HOTPLUG_IO_LEN); + memory_region_add_subregion(as, ACPI_MEMORY_HOTPLUG_BASE, &state->io); +} + +void acpi_memory_plug_cb(ACPIREGS *ar, qemu_irq irq, MemHotplugState *mem_st, + DeviceState *dev, Error **errp) +{ + MemStatus *mdev; + Error *local_err = NULL; + int slot = object_property_get_int(OBJECT(dev), "slot", &local_err); + + if (local_err) { + error_propagate(errp, local_err); + return; + } + + if (slot >= mem_st->dev_count) { + char *dev_path = object_get_canonical_path(OBJECT(dev)); + error_setg(errp, "acpi_memory_plug_cb: " + "device [%s] returned invalid memory slot[%d]", + dev_path, slot); + g_free(dev_path); + return; + } + + mdev = &mem_st->devs[slot]; + mdev->dimm = dev; + mdev->is_enabled = true; + mdev->is_inserting = true; + + /* do ACPI magic */ + ar->gpe.sts[0] |= ACPI_MEMORY_HOTPLUG_STATUS; + acpi_update_sci(ar, irq); + return; +} diff --git a/include/hw/acpi/acpi_defs.h b/include/hw/acpi/acpi_defs.h index 36b831f..a6e7219 100644 --- a/include/hw/acpi/acpi_defs.h +++ b/include/hw/acpi/acpi_defs.h @@ -29,4 +29,7 @@ #define ICH9_CPU_HOTPLUG_IO_BASE 0x0CD8 #define PIIX4_CPU_HOTPLUG_IO_BASE 0xaf00 +#define ACPI_MEMORY_HOTPLUG_IO_LEN 24 +#define ACPI_MEMORY_HOTPLUG_BASE 0x0a00 + #endif diff --git a/include/hw/acpi/memory_hotplug.h b/include/hw/acpi/memory_hotplug.h new file mode 100644 index 0000000..8f90f72 --- /dev/null +++ b/include/hw/acpi/memory_hotplug.h @@ -0,0 +1,29 @@ +#ifndef QEMU_HW_ACPI_MEMORY_HOTPLUG_H +#define QEMU_HW_ACPI_MEMORY_HOTPLUG_H + +#include "hw/qdev-core.h" +#include "hw/acpi/acpi.h" + +#define ACPI_MEMORY_HOTPLUG_STATUS 8 + +typedef struct MemStatus { + DeviceState *dimm; + bool is_enabled; + bool is_inserting; + uint32_t ost_event; + uint32_t ost_status; +} MemStatus; + +typedef struct MemHotplugState { + MemoryRegion io; + uint32_t selector; + uint32_t dev_count; + MemStatus *devs; +} MemHotplugState; + +void acpi_memory_hotplug_init(MemoryRegion *as, Object *owner, + MemHotplugState *state); + +void acpi_memory_plug_cb(ACPIREGS *ar, qemu_irq irq, MemHotplugState *mem_st, + DeviceState *dev, Error **errp); +#endif
- implements QEMU hardware part of memory hotplug protocol described at "docs/specs/acpi_mem_hotplug.txt" - handles only memory add notification event for now Signed-off-by: Igor Mammedov <imammedo@redhat.com> --- docs/specs/acpi_mem_hotplug.txt | 44 ++++++++++++ hw/acpi/Makefile.objs | 1 + hw/acpi/memory_hotplug.c | 144 +++++++++++++++++++++++++++++++++++++++ include/hw/acpi/acpi_defs.h | 3 + include/hw/acpi/memory_hotplug.h | 29 ++++++++ 5 files changed, 221 insertions(+) create mode 100644 docs/specs/acpi_mem_hotplug.txt create mode 100644 hw/acpi/memory_hotplug.c create mode 100644 include/hw/acpi/memory_hotplug.h