On Fri, Sep 21, 2012 at 11:17 AM, Vasilis Liaskovitis <vasilis.liaskovitis@xxxxxxxxxxxxxxxx> wrote: > A 32-byte register is used to present up to 256 hotplug-able memory devices > to BIOS and OSPM. Hot-add and hot-remove functions trigger an ACPI hotplug > event through these. Only reads are allowed from these registers. > > An ACPI hot-remove event but needs to wait for OSPM to eject the device. > We use a single-byte register to know when OSPM has called the _EJ function > for a particular dimm. A write to this byte will depopulate the respective dimm. > Only writes are allowed to this byte. > > v1->v2: > mems_sts address moved from 0xaf20 to 0xaf80 (to accomodate more space for > cpu-hotplugging in the future). > _EJ array is reduced to a single byte. > Add documentation in docs/specs/acpi_hotplug.txt > > v2->v3: > minor name changes > > Signed-off-by: Vasilis Liaskovitis <vasilis.liaskovitis@xxxxxxxxxxxxxxxx> > --- > docs/specs/acpi_hotplug.txt | 22 +++++++++++++ > hw/acpi_piix4.c | 73 ++++++++++++++++++++++++++++++++++++++++-- > 2 files changed, 91 insertions(+), 4 deletions(-) > create mode 100644 docs/specs/acpi_hotplug.txt > > diff --git a/docs/specs/acpi_hotplug.txt b/docs/specs/acpi_hotplug.txt > new file mode 100644 > index 0000000..cf86242 > --- /dev/null > +++ b/docs/specs/acpi_hotplug.txt > @@ -0,0 +1,22 @@ > +QEMU<->ACPI BIOS hotplug interface > +-------------------------------------- > +This document describes the interface between QEMU and the ACPI BIOS for non-PCI > +space. For the PCI interface please look at docs/specs/acpi_pci_hotplug.txt > + > +QEMU<->ACPI BIOS memory hotplug interface > +-------------------------------------- > + > +Memory Dimm status array (IO port 0xaf80-0xaf9f, 1-byte access): > +--------------------------------------------------------------- > +Dimm hot-plug notification pending. One bit per slot. > + > +Read by ACPI BIOS GPE.3 handler to notify OS of memory hot-add or hot-remove > +events. Read-only. > + > +Memory Dimm ejection success notification (IO port 0xafa0, 1-byte access): > +--------------------------------------------------------------- > +Dimm hot-remove _EJ0 notification. Byte value indicates Dimm slot that was > +ejected. > + > +Written by ACPI memory device _EJ0 method to notify qemu of successfull > +hot-removal. Write-only. > diff --git a/hw/acpi_piix4.c b/hw/acpi_piix4.c > index c56220b..8776669 100644 > --- a/hw/acpi_piix4.c > +++ b/hw/acpi_piix4.c > @@ -28,6 +28,8 @@ > #include "range.h" > #include "ioport.h" > #include "fw_cfg.h" > +#include "sysbus.h" > +#include "dimm.h" > > //#define DEBUG > > @@ -45,9 +47,15 @@ > #define PCI_DOWN_BASE 0xae04 > #define PCI_EJ_BASE 0xae08 > #define PCI_RMV_BASE 0xae0c > +#define MEM_BASE 0xaf80 > +#define MEM_EJ_BASE 0xafa0 > > +#define PIIX4_MEM_HOTPLUG_STATUS 8 > #define PIIX4_PCI_HOTPLUG_STATUS 2 > > +struct gpe_regs { GPERegs > + uint8_t mems_sts[DIMM_BITMAP_BYTES]; > +}; > struct pci_status { > uint32_t up; /* deprecated, maintained for migration compatibility */ > uint32_t down; > @@ -69,6 +77,7 @@ typedef struct PIIX4PMState { > Notifier machine_ready; > > /* for pci hotplug */ > + struct gpe_regs gperegs; > struct pci_status pci0_status; > uint32_t pci0_hotplug_enable; > uint32_t pci0_slot_device_present; > @@ -93,8 +102,8 @@ static void pm_update_sci(PIIX4PMState *s) > 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); > + (((s->ar.gpe.sts[0] & s->ar.gpe.en[0]) & > + (PIIX4_PCI_HOTPLUG_STATUS | PIIX4_MEM_HOTPLUG_STATUS)) != 0); > > qemu_set_irq(s->irq, sci_level); > /* schedule a timer interruption if needed */ > @@ -499,7 +508,16 @@ type_init(piix4_pm_register_types) > static uint32_t gpe_readb(void *opaque, uint32_t addr) > { > PIIX4PMState *s = opaque; > - uint32_t val = acpi_gpe_ioport_readb(&s->ar, addr); > + uint32_t val = 0; > + struct gpe_regs *g = &s->gperegs; > + > + switch (addr) { > + case MEM_BASE ... MEM_BASE+DIMM_BITMAP_BYTES: > + val = g->mems_sts[addr - MEM_BASE]; > + break; > + default: > + val = acpi_gpe_ioport_readb(&s->ar, addr); > + } > > PIIX4_DPRINTF("gpe read %x == %x\n", addr, val); > return val; > @@ -509,7 +527,13 @@ static void gpe_writeb(void *opaque, uint32_t addr, uint32_t val) > { > PIIX4PMState *s = opaque; > > - acpi_gpe_ioport_writeb(&s->ar, addr, val); > + switch (addr) { > + case MEM_EJ_BASE: > + dimm_notify(val, DIMM_REMOVE_SUCCESS); > + break; > + default: > + acpi_gpe_ioport_writeb(&s->ar, addr, val); > + } > pm_update_sci(s); > > PIIX4_DPRINTF("gpe write %x <== %d\n", addr, val); > @@ -560,9 +584,11 @@ static uint32_t pcirmv_read(void *opaque, uint32_t addr) > > static int piix4_device_hotplug(DeviceState *qdev, PCIDevice *dev, > PCIHotplugState state); > +static int piix4_dimm_hotplug(DeviceState *qdev, DimmDevice *dev, int add); > > static void piix4_acpi_system_hot_add_init(PCIBus *bus, PIIX4PMState *s) > { > + int i = 0; > > register_ioport_write(GPE_BASE, GPE_LEN, 1, gpe_writeb, s); > register_ioport_read(GPE_BASE, GPE_LEN, 1, gpe_readb, s); > @@ -576,7 +602,15 @@ static void piix4_acpi_system_hot_add_init(PCIBus *bus, PIIX4PMState *s) > > register_ioport_read(PCI_RMV_BASE, 4, 4, pcirmv_read, s); > > + register_ioport_read(MEM_BASE, DIMM_BITMAP_BYTES, 1, gpe_readb, s); > + register_ioport_write(MEM_EJ_BASE, 1, 1, gpe_writeb, s); > + > + for(i = 0; i < DIMM_BITMAP_BYTES; i++) { > + s->gperegs.mems_sts[i] = 0; > + } > + > pci_bus_hotplug(bus, piix4_device_hotplug, &s->dev.qdev); > + dimm_bus_hotplug(piix4_dimm_hotplug, &s->dev.qdev); > } > > static void enable_device(PIIX4PMState *s, int slot) > @@ -591,6 +625,37 @@ static void disable_device(PIIX4PMState *s, int slot) > s->pci0_status.down |= (1U << slot); > } > > +static void enable_mem_device(PIIX4PMState *s, int memdevice) > +{ > + struct gpe_regs *g = &s->gperegs; > + s->ar.gpe.sts[0] |= PIIX4_MEM_HOTPLUG_STATUS; > + g->mems_sts[memdevice/8] |= (1 << (memdevice%8)); > +} > + > +static void disable_mem_device(PIIX4PMState *s, int memdevice) > +{ > + struct gpe_regs *g = &s->gperegs; > + s->ar.gpe.sts[0] |= PIIX4_MEM_HOTPLUG_STATUS; > + g->mems_sts[memdevice/8] &= ~(1 << (memdevice%8)); > +} > + > +static int piix4_dimm_hotplug(DeviceState *qdev, DimmDevice *dev, int > + add) > +{ > + PCIDevice *pci_dev = DO_UPCAST(PCIDevice, qdev, qdev); > + PIIX4PMState *s = DO_UPCAST(PIIX4PMState, dev, pci_dev); > + DimmDevice *slot = DIMM(dev); > + > + if (add) { > + enable_mem_device(s, slot->idx); > + } > + else { } else { > + disable_mem_device(s, slot->idx); > + } > + pm_update_sci(s); > + return 0; > +} > + > static int piix4_device_hotplug(DeviceState *qdev, PCIDevice *dev, > PCIHotplugState state) > { > -- > 1.7.9 > -- To unsubscribe from this list: send the line "unsubscribe kvm" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html