From patchwork Tue Dec 18 12:41:39 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Vasilis Liaskovitis X-Patchwork-Id: 207136 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (Client did not present a certificate) by ozlabs.org (Postfix) with ESMTPS id 44CC42C0089 for ; Wed, 19 Dec 2012 01:30:59 +1100 (EST) Received: from localhost ([::1]:56558 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1TkwVt-0000S2-G3 for incoming@patchwork.ozlabs.org; Tue, 18 Dec 2012 07:43:13 -0500 Received: from eggs.gnu.org ([208.118.235.92]:46131) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1TkwVC-0007sj-IS for qemu-devel@nongnu.org; Tue, 18 Dec 2012 07:42:31 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1TkwVA-0008St-Pm for qemu-devel@nongnu.org; Tue, 18 Dec 2012 07:42:30 -0500 Received: from mail-bk0-f51.google.com ([209.85.214.51]:60352) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1TkwVA-0008Si-Fv for qemu-devel@nongnu.org; Tue, 18 Dec 2012 07:42:28 -0500 Received: by mail-bk0-f51.google.com with SMTP id ik5so290735bkc.10 for ; Tue, 18 Dec 2012 04:42:27 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20120113; h=x-received:from:to:cc:subject:date:message-id:x-mailer:in-reply-to :references:x-gm-message-state; bh=XDVVr/wxY0BrSrHbXoD2IZpngqqh/Tk4JTDfqoWMamg=; b=cxENzaU4s9gR8Wzy4RmeMjzRUp7cIMSOc4Z9tGTSmrKQFjAD6RMHCZyPJIADLHdA2Z 1Z8wex0ZZIWm68fsBvHaUcZwCOewbf/EpTcKHudv+9PMXpMF/R/cmKIQNXox+v7nbQX/ Uq6vbkgUB5rE9sNQZsNJs0dI84W9S5JXuTIWBtRpoc0t5HZAo+gY6d/1bpfKIh2MfE1I siJ7COiZeSjjm+bLvNrk1JG36ofNVXqYDRIBllzxBGmkmP7yO1xhGylLUarZ3vj904Vj Lis39ekls+YFu6arSYC/3gJUuQ/D4BhtL69o5yPyFE7il7R7R+NgFYJzClobnKPUi0VB iyDA== X-Received: by 10.204.151.7 with SMTP id a7mr694199bkw.8.1355834547323; Tue, 18 Dec 2012 04:42:27 -0800 (PST) Received: from dhcp-192-168-178-175.ri.profitbricks.localdomain ([62.217.45.26]) by mx.google.com with ESMTPS id f24sm1169954bkv.7.2012.12.18.04.42.25 (version=TLSv1/SSLv3 cipher=OTHER); Tue, 18 Dec 2012 04:42:26 -0800 (PST) From: Vasilis Liaskovitis To: qemu-devel@nongnu.org, seabios@seabios.org Date: Tue, 18 Dec 2012 13:41:39 +0100 Message-Id: <1355834518-17989-12-git-send-email-vasilis.liaskovitis@profitbricks.com> X-Mailer: git-send-email 1.7.9 In-Reply-To: <1355834518-17989-1-git-send-email-vasilis.liaskovitis@profitbricks.com> References: <1355834518-17989-1-git-send-email-vasilis.liaskovitis@profitbricks.com> X-Gm-Message-State: ALoCoQmPAUEnV3lC24VHd3HbyQfhir7ye+7I1v1q3B3vNuDne9GU6tHNkfx4KDNbGyvgu4SjO296 X-detected-operating-system: by eggs.gnu.org: GNU/Linux 3.x [fuzzy] X-Received-From: 209.85.214.51 Cc: Vasilis Liaskovitis , pingfank@linux.vnet.ibm.com, gleb@redhat.com, stefanha@gmail.com, jbaron@redhat.com, blauwirbel@gmail.com, kevin@koconnor.net, kraxel@redhat.com, anthony@codemonkey.ws Subject: [Qemu-devel] [RFC PATCH v4 11/30] acpi_piix4 : Implement memory device hotplug registers X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org 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 v3->v4: Removed hot-remove functions, will be added separately. Updated for memory API. Signed-off-by: Vasilis Liaskovitis --- docs/specs/acpi_hotplug.txt | 14 +++++++++ hw/acpi.h | 5 +++ hw/acpi_piix4.c | 65 +++++++++++++++++++++++++++++++++++++++++- 3 files changed, 82 insertions(+), 2 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..8391713 --- /dev/null +++ b/docs/specs/acpi_hotplug.txt @@ -0,0 +1,14 @@ +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. diff --git a/hw/acpi.h b/hw/acpi.h index afda153..dc617d3 100644 --- a/hw/acpi.h +++ b/hw/acpi.h @@ -120,6 +120,11 @@ struct ACPIREGS { Notifier wakeup; }; +#include "dimm.h" +struct gpe_regs { + uint8_t mems_sts[DIMM_BITMAP_BYTES]; +}; + /* PM_TMR */ void acpi_pm_tmr_update(ACPIREGS *ar, bool enable); void acpi_pm_tmr_calc_overflow_time(ACPIREGS *ar); diff --git a/hw/acpi_piix4.c b/hw/acpi_piix4.c index 0b5b0d3..879d8a0 100644 --- a/hw/acpi_piix4.c +++ b/hw/acpi_piix4.c @@ -29,6 +29,8 @@ #include "ioport.h" #include "fw_cfg.h" #include "exec-memory.h" +#include "sysbus.h" +#include "dimm.h" //#define DEBUG @@ -47,7 +49,9 @@ #define PCI_DOWN_BASE 0xae04 #define PCI_EJ_BASE 0xae08 #define PCI_RMV_BASE 0xae0c +#define MEM_BASE 0xaf80 +#define PIIX4_MEM_HOTPLUG_STATUS 8 #define PIIX4_PCI_HOTPLUG_STATUS 2 struct pci_status { @@ -60,6 +64,7 @@ typedef struct PIIX4PMState { MemoryRegion io; MemoryRegion io_gpe; MemoryRegion io_pci; + MemoryRegion io_memhp; ACPIREGS ar; APMState apm; @@ -74,6 +79,7 @@ typedef struct PIIX4PMState { Notifier powerdown_notifier; /* for pci hotplug */ + struct gpe_regs gperegs; struct pci_status pci0_status; uint32_t pci0_hotplug_enable; uint32_t pci0_slot_device_present; @@ -98,8 +104,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 */ @@ -526,6 +532,29 @@ static const MemoryRegionOps piix4_gpe_ops = { .endianness = DEVICE_LITTLE_ENDIAN, }; +static uint32_t memhp_readb(void *opaque, uint32_t addr) +{ + PIIX4PMState *s = opaque; + uint32_t val = 0; + struct gpe_regs *g = &s->gperegs; + if (addr < DIMM_BITMAP_BYTES) { + val = (uint32_t) g->mems_sts[addr]; + } + PIIX4_DPRINTF(stderr, "memhp read %x == %x\n", addr, val); + return val; +} + +static const MemoryRegionOps piix4_memhp_ops = { + .old_portio = (MemoryRegionPortio[]) { + { + .offset = 0, .len = DIMM_BITMAP_BYTES, .size = 1, + .read = memhp_readb, + }, + PORTIO_END_OF_LIST() + }, + .endianness = DEVICE_LITTLE_ENDIAN, +}; + static uint32_t pci_up_read(void *opaque, uint32_t addr) { PIIX4PMState *s = opaque; @@ -592,9 +621,11 @@ static const MemoryRegionOps piix4_pci_ops = { 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; memory_region_init_io(&s->io_gpe, &piix4_gpe_ops, s, "apci-gpe0", GPE_LEN); memory_region_add_subregion(get_system_io(), GPE_BASE, &s->io_gpe); @@ -603,7 +634,16 @@ static void piix4_acpi_system_hot_add_init(PCIBus *bus, PIIX4PMState *s) PCI_HOTPLUG_SIZE); memory_region_add_subregion(get_system_io(), PCI_HOTPLUG_ADDR, &s->io_pci); + memory_region_init_io(&s->io_memhp, &piix4_memhp_ops, s, "apci-memhp0", + DIMM_BITMAP_BYTES); + memory_region_add_subregion(get_system_io(), MEM_BASE, &s->io_memhp); + + 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) @@ -618,6 +658,27 @@ 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 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); + } + pm_update_sci(s); + return 0; +} + static int piix4_device_hotplug(DeviceState *qdev, PCIDevice *dev, PCIHotplugState state) {