[SeaBIOS] [RFC PATCH 5/9] acpi_piix4: Implement memory device hotplug registers
Vasilis Liaskovitis
vasilis.liaskovitis at profitbricks.com
Thu Apr 19 16:08:43 CEST 2012
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 (from
BIOS/OSPM perspective). "memslot id add" will immediately populate the new
memslot (a new MemoryRegion is created and attached to system memory), and
then trigger the ACPI hot-add event. "memslot id delete" triggers the ACPI
hot-remove event but needs to wait for OSPM to eject the device. We use a
second set of eject registers to know when OSPM has called the _EJ function
for a particular memslot. A write to these will depopulate the corresponding
memslot i.e. detach and free the MemoryRegion. Only writes to the eject
registers are allowed.
A new property mem_acpi_hotplug should enable these memory hotplug registers
for future machine types (not yet implemented in this version).
Signed-off-by: Vasilis Liaskovitis <vasilis.liaskovitis at profitbricks.com>
---
hw/acpi_piix4.c | 93 ++++++++++++++++++++++++++++++++++++++++++++++++++++--
1 files changed, 89 insertions(+), 4 deletions(-)
diff --git a/hw/acpi_piix4.c b/hw/acpi_piix4.c
index 797ed24..a14dd3c 100644
--- a/hw/acpi_piix4.c
+++ b/hw/acpi_piix4.c
@@ -27,6 +27,8 @@
#include "sysemu.h"
#include "range.h"
#include "ioport.h"
+#include "sysbus.h"
+#include "memslot.h"
//#define DEBUG
@@ -43,9 +45,16 @@
#define PCI_BASE 0xae00
#define PCI_EJ_BASE 0xae08
#define PCI_RMV_BASE 0xae0c
+#define MEM_BASE 0xaf20
+#define MEM_EJ_BASE 0xaf40
+#define PIIX4_MEM_HOTPLUG_STATUS 8
#define PIIX4_PCI_HOTPLUG_STATUS 2
+struct gpe_regs {
+ uint8_t mems_sts[32];
+};
+
struct pci_status {
uint32_t up;
uint32_t down;
@@ -66,6 +75,7 @@ typedef struct PIIX4PMState {
int kvm_enabled;
Notifier machine_ready;
+ struct gpe_regs gpe;
/* for pci hotplug */
struct pci_status pci0_status;
uint32_t pci0_hotplug_enable;
@@ -86,8 +96,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 */
@@ -432,17 +442,34 @@ 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->gpe;
+
+ switch (addr) {
+ case MEM_BASE ... MEM_BASE+31:
+ 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;
}
+static void piix4_memslot_eject(uint32_t addr, uint32_t val);
+
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 ... MEM_EJ_BASE+31:
+ piix4_memslot_eject(addr, val);
+ break;
+ default:
+ acpi_gpe_ioport_writeb(&s->ar, addr, val);
+ }
pm_update_sci(s);
PIIX4_DPRINTF("gpe write %x <== %d\n", addr, val);
@@ -521,9 +548,12 @@ static void pcirmv_write(void *opaque, uint32_t addr, uint32_t val)
static int piix4_device_hotplug(DeviceState *qdev, PCIDevice *dev,
PCIHotplugState state);
+static int piix4_memslot_hotplug(DeviceState *qdev, SysBusDevice *dev, int add);
+
static void piix4_acpi_system_hot_add_init(PCIBus *bus, PIIX4PMState *s)
{
struct pci_status *pci0_status = &s->pci0_status;
+ 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);
@@ -538,6 +568,13 @@ static void piix4_acpi_system_hot_add_init(PCIBus *bus, PIIX4PMState *s)
register_ioport_write(PCI_RMV_BASE, 4, 4, pcirmv_write, s);
register_ioport_read(PCI_RMV_BASE, 4, 4, pcirmv_read, s);
+ register_ioport_read(MEM_BASE, 32, 1, gpe_readb, s);
+ register_ioport_write(MEM_EJ_BASE, 32, 1, gpe_writeb, s);
+ for(i = 0; i < 32; i++) {
+ s->gpe.mems_sts[i] = 0;
+ }
+ memslot_register_hotplug(piix4_memslot_hotplug, &s->dev.qdev);
+
pci_bus_hotplug(bus, piix4_device_hotplug, &s->dev.qdev);
}
@@ -553,6 +590,54 @@ static void disable_device(PIIX4PMState *s, int slot)
s->pci0_status.down |= (1 << slot);
}
+static void enable_mem_device(PIIX4PMState *s, int memdevice)
+{
+ struct gpe_regs *g = &s->gpe;
+ 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->gpe;
+ s->ar.gpe.sts[0] |= PIIX4_MEM_HOTPLUG_STATUS;
+ g->mems_sts[memdevice/8] &= ~(1 << (memdevice%8));
+}
+
+static void piix4_memslot_eject(uint32_t addr, uint32_t val)
+{
+ uint32_t start = 8 * (addr - MEM_EJ_BASE);
+ uint32_t idx = 0;
+ MemSlotState *s;
+ PIIX4_DPRINTF("memej write %x <= %d\n", addr, val);
+ while (val) {
+ if (val & 1) {
+ s = memslot_find_from_idx(start + idx);
+ assert(s != NULL);
+ memslot_depopulate(s);
+ }
+ val = val >> 1;
+ idx++;
+ }
+}
+
+static int piix4_memslot_hotplug(DeviceState *qdev, SysBusDevice *dev, int
+ add)
+{
+ PIIX4PMState *s = DO_UPCAST(PIIX4PMState, dev,
+ PCI_DEVICE(qdev));
+ MemSlotState *slot = MEMSLOT(dev);
+
+ if (add) {
+ enable_mem_device(s, slot->idx);
+ }
+ 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
More information about the SeaBIOS
mailing list