From patchwork Wed Jul 11 10:31:52 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Vasilis Liaskovitis X-Patchwork-Id: 1181361 Return-Path: X-Original-To: patchwork-kvm@patchwork.kernel.org Delivered-To: patchwork-process-083081@patchwork1.kernel.org Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by patchwork1.kernel.org (Postfix) with ESMTP id 1D83B3FC8F for ; Wed, 11 Jul 2012 10:32:24 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1757164Ab2GKKcU (ORCPT ); Wed, 11 Jul 2012 06:32:20 -0400 Received: from mail-bk0-f46.google.com ([209.85.214.46]:40424 "EHLO mail-bk0-f46.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1753145Ab2GKKcQ (ORCPT ); Wed, 11 Jul 2012 06:32:16 -0400 Received: by mail-bk0-f46.google.com with SMTP id j10so891613bkw.19 for ; Wed, 11 Jul 2012 03:32:16 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20120113; h=from:to:cc:subject:date:message-id:x-mailer:in-reply-to:references :x-gm-message-state; bh=PDPkGobNfhTweBKfhRnVdGktW3XIu4QQJab8/v90CUI=; b=IUYuS/+IoQoCmG8A2Qo433zFqr6XjXhbfwAB4zvBsvG0OCeqrItT6yedtX+vtsgVd/ 7RMpi9fkw9dOcfUffwO27f+2tH8nO9LgIXHL5KWHabT3PuN2RjghF+ke5RSD7ut1Tb+h LXX0Dp5JhcS3jbOVCwHymE8lQwvzZuzhaslP9vvPLHNJHlVvwHof4Zsx51UhohjQtACN TDZrjorFzRJr2zVhPhKeo4esuVL4k8PTDwrNvcvnSKUHAzx/f3zRhIkttIQ1EhbhmspM S4gx/klUODIQcc4ivW4U540I/h6h5xyjwaFDgqio3enbiNZRQ+oiAHcKW7rsoqTg+6We G8Qw== Received: by 10.204.156.217 with SMTP id y25mr23505780bkw.65.1342002735700; Wed, 11 Jul 2012 03:32:15 -0700 (PDT) Received: from dhcp-192-168-178-175.ri.profitbricks.localdomain ([62.217.45.26]) by mx.google.com with ESMTPS id e20sm794740bkv.10.2012.07.11.03.32.15 (version=TLSv1/SSLv3 cipher=OTHER); Wed, 11 Jul 2012 03:32:15 -0700 (PDT) From: Vasilis Liaskovitis To: qemu-devel@nongnu.org, kvm@vger.kernel.org, seabios@seabios.org Cc: avi@redhat.com, anthony@codemonkey.ws, gleb@redhat.com, imammedo@redhat.com, kevin@koconnor.net, wency@cn.fujitsu.com, Vasilis Liaskovitis Subject: [RFC PATCH v2 07/21] acpi_piix4: Implement memory device hotplug registers Date: Wed, 11 Jul 2012 12:31:52 +0200 Message-Id: <1342002726-18258-8-git-send-email-vasilis.liaskovitis@profitbricks.com> X-Mailer: git-send-email 1.7.9 In-Reply-To: <1342002726-18258-1-git-send-email-vasilis.liaskovitis@profitbricks.com> References: <1342002726-18258-1-git-send-email-vasilis.liaskovitis@profitbricks.com> X-Gm-Message-State: ALoCoQkAX3vt/wSp76auuTNxaQfvc/bycbc0PNDmm3MAj+l82/n6Mq0N2Oow8+/H4LPnDhogMiQw Sender: kvm-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: kvm@vger.kernel.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 Signed-off-by: Vasilis Liaskovitis --- 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 0aace60..b988597 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 { + 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, SysBusDevice *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_register_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, SysBusDevice *dev, int + add) +{ + PCIDevice *pci_dev = DO_UPCAST(PCIDevice, qdev, qdev); + PIIX4PMState *s = DO_UPCAST(PIIX4PMState, dev, pci_dev); + DimmState *slot = DIMM(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) {