[SeaBIOS] [RFC PATCH v3 07/19] acpi_piix4: Implement memory device hotplug registers

Blue Swirl blauwirbel at gmail.com
Sat Sep 22 15:49:05 CEST 2012


On Fri, Sep 21, 2012 at 11:17 AM, Vasilis Liaskovitis
<vasilis.liaskovitis at profitbricks.com> 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 at profitbricks.com>
> ---
>  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
>



More information about the SeaBIOS mailing list