From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from eggs.gnu.org ([2001:4830:134:3::10]:42078) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1V1fO6-0006yz-7l for qemu-devel@nongnu.org; Tue, 23 Jul 2013 12:24:38 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1V1fO2-0007AW-MP for qemu-devel@nongnu.org; Tue, 23 Jul 2013 12:24:34 -0400 Received: from mx1.redhat.com ([209.132.183.28]:29455) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1V1fO2-0007AF-B1 for qemu-devel@nongnu.org; Tue, 23 Jul 2013 12:24:30 -0400 From: Igor Mammedov Date: Tue, 23 Jul 2013 18:23:10 +0200 Message-Id: <1374596592-7027-15-git-send-email-imammedo@redhat.com> In-Reply-To: <1374596592-7027-1-git-send-email-imammedo@redhat.com> References: <1374596592-7027-1-git-send-email-imammedo@redhat.com> Subject: [Qemu-devel] [PATCH 14/16] pc: ACPI BIOS: implement memory hotplug interface List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: qemu-devel@nongnu.org Cc: vasilis.liaskovitis@profitbricks.com, hutao@cn.fujitsu.com, pbonzini@redhat.com - provides static DSDT object for memory hotplug - SSDT template for memory devices and runtime generator of them in SSDT table. Signed-off-by: Vasilis Liaskovitis Signed-off-by: Igor Mammedov --- hw/i386/Makefile.objs | 2 +- hw/i386/acpi-build.c | 33 +++++++++ hw/i386/acpi-dsdt-mem-hotplug.dsl | 144 +++++++++++++++++++++++++++++++++++++ hw/i386/acpi-dsdt.dsl | 5 +- hw/i386/ssdt-mem.dsl | 76 +++++++++++++++++++ 5 files changed, 258 insertions(+), 2 deletions(-) create mode 100644 hw/i386/acpi-dsdt-mem-hotplug.dsl create mode 100644 hw/i386/ssdt-mem.dsl diff --git a/hw/i386/Makefile.objs b/hw/i386/Makefile.objs index 2ab2572..fa919e6 100644 --- a/hw/i386/Makefile.objs +++ b/hw/i386/Makefile.objs @@ -6,7 +6,7 @@ obj-$(CONFIG_XEN) += xen_domainbuild.o xen_machine_pv.o obj-y += kvmvapic.o obj-y += acpi-build.o obj-y += bios-linker-loader.o -hw/i386/acpi-build.o: hw/i386/acpi-build.c hw/i386/acpi-dsdt.hex hw/i386/ssdt-proc.hex hw/i386/ssdt-pcihp.hex hw/i386/ssdt-misc.hex hw/i386/q35-acpi-dsdt.hex +hw/i386/acpi-build.o: hw/i386/acpi-build.c hw/i386/acpi-dsdt.hex hw/i386/ssdt-proc.hex hw/i386/ssdt-pcihp.hex hw/i386/ssdt-misc.hex hw/i386/q35-acpi-dsdt.hex hw/i386/ssdt-mem.hex hw/i386/pc_piix.o: hw/i386/pc_piix.c hw/i386/acpi-dsdt.hex hw/i386/pc_q35.o: hw/i386/pc_q35.c hw/i386/q35-acpi-dsdt.hex diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c index bc44f95..7d7fa1f 100644 --- a/hw/i386/acpi-build.c +++ b/hw/i386/acpi-build.c @@ -35,6 +35,7 @@ #include "hw/nvram/fw_cfg.h" #include "hw/i386/bios-linker-loader.h" #include "hw/loader.h" +#include "qemu/config-file.h" #define ACPI_BUILD_APPNAME "Bochs" #define ACPI_BUILD_APPNAME6 "BOCHS " @@ -267,6 +268,17 @@ acpi_encode_len(uint8_t *ssdt_ptr, int length, int bytes) #define ACPI_PCIHP_SIZEOF (*ssdt_pcihp_end - *ssdt_pcihp_start) #define ACPI_PCIHP_AML (ssdp_pcihp_aml + *ssdt_pcihp_start) +#include "hw/i386/ssdt-mem.hex" + +/* 0x5B 0x82 DeviceOp PkgLength NameString DimmID */ +#define ACPI_MEM_AML (ssdm_mem_aml + *ssdt_mem_start) +#define ACPI_MEM_SIZEOF (*ssdt_mem_end - *ssdt_mem_start) +#define ACPI_MEM_OFFSET_HEX (*ssdt_mem_name - *ssdt_mem_start + 2) +#define ACPI_MEM_OFFSET_ID (*ssdt_mem_id - *ssdt_mem_start + 7) +#define ACPI_MEM_DEV_COUNT_OBJ (ssdm_mem_aml + *ssdt_mem_count_name - 1) +#define ACPI_MEM_DEV_COUNT_OFFSET (*ssdt_mem_count - *ssdt_mem_count_name + 1) +#define ACPI_MEM_DEV_COUNT_SIZE (*ssdt_mem_start - *ssdt_mem_count_name + 1) + #define ACPI_SSDT_SIGNATURE 0x54445353 /* SSDT */ #define ACPI_SSDT_HEADER_LENGTH 36 @@ -326,11 +338,16 @@ build_ssdt(GArray *table_data, GArray *linker, FWCfgState *fw_cfg, PcGuestInfo *guest_info) { int acpi_cpus = MIN(0xff, guest_info->apic_id_limit); + QemuOpts *opts = qemu_opts_find(qemu_find_opts("memory-opts"), NULL); + uint32_t acpi_mem_devs = opts ? qemu_opt_get_number(opts, "slots", 0) : 0; int length = (sizeof(ssdp_misc_aml) /* _S3_ / _S4_ / _S5_ */ + (1+3+4) /* Scope(_SB_) */ + (acpi_cpus * ACPI_PROC_SIZEOF) /* procs */ + (1+2+5+(12*acpi_cpus)) /* NTFY */ + (6+2+1+(1*acpi_cpus)) /* CPON */ + + (1+2+5+(12*acpi_mem_devs)) /* MTFY */ + + ACPI_MEM_DEV_COUNT_SIZE /* MDNR const */ + + (acpi_mem_devs * ACPI_MEM_SIZEOF) /* mem devices */ + (1+3+4) /* Scope(PCI0) */ + ((PCI_SLOT_MAX - 1) * ACPI_PCIHP_SIZEOF) /* slots */ + (1+2+5+(12*(PCI_SLOT_MAX - 1)))); /* PCNT */ @@ -407,6 +424,22 @@ build_ssdt(GArray *table_data, GArray *linker, for (i=0; ifound_cpus)) ? 0x01 : 0x00; + /* set number of mem devices. i.e. declare Name(MDNR, nb_memdevs) */ + memcpy(ssdt_ptr, ACPI_MEM_DEV_COUNT_OBJ, ACPI_MEM_DEV_COUNT_SIZE); + memcpy(ssdt_ptr + ACPI_MEM_DEV_COUNT_OFFSET, &acpi_mem_devs, 4); + ssdt_ptr += ACPI_MEM_DEV_COUNT_SIZE; + + /* build mem devices and notifiers for them */ + for (i = 0; i < acpi_mem_devs; i++) { + char id[5]; + snprintf(id, sizeof(id), "%02x", i); + memcpy(ssdt_ptr, ACPI_MEM_AML, ACPI_MEM_SIZEOF); + memcpy(ssdt_ptr + ACPI_MEM_OFFSET_HEX, id, 2); + memcpy(ssdt_ptr + ACPI_MEM_OFFSET_ID, id, 2); + ssdt_ptr += ACPI_MEM_SIZEOF; + } + ssdt_ptr = build_notify(ssdt_ptr, "MTFY", 0, acpi_mem_devs, "MP00", 2); + /* build Scope(PCI0) opcode */ *(ssdt_ptr++) = 0x10; /* ScopeOp */ ssdt_ptr = acpi_encode_len(ssdt_ptr, length - (ssdt_ptr - ssdt), 3); diff --git a/hw/i386/acpi-dsdt-mem-hotplug.dsl b/hw/i386/acpi-dsdt-mem-hotplug.dsl new file mode 100644 index 0000000..3803edb --- /dev/null +++ b/hw/i386/acpi-dsdt-mem-hotplug.dsl @@ -0,0 +1,144 @@ +/* + * Memory hotplug ACPI DSDT static objects definitions + * + * Copyright (C) 2013 Red Hat Inc + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see + */ + +Scope(\_SB) { + /* Objects provided by run-time generated SSDT */ + External(MTFY, MethodObj) + External(MDNR, IntObj) + + /* Memory hotplug IO registers */ + OperationRegion(HPMR, SystemIO, 0xaf80, 24) + Field (HPMR, DWordAcc, NoLock, Preserve) + { + MRBL, 32, // DIMM start addr Low word, read only + MRBH, 32, // DIMM start addr Hi word, read only + MRLL, 32, // DIMM size Low word, read only + MRLH, 32, // DIMM size Hi word, read only + MPX, 32, // DIMM node proximity, read only + } + Field (HPMR, ByteAcc, NoLock, Preserve) + { + Offset(20), + MVER, 8, // Interface version + MES, 1, // 1 if DIMM enabled for _STA, read only + MINS, 1, // (read) 1 if DIMM has a insert event. (write) 1 after MTFY() + MRMV, 1, // 1 if DIMM has a remove request, read only + } + + Mutex (MLCK, 0) + Field (HPMR, DWordAcc, NoLock, Preserve) + { + MSEL, 32, // DIMM selector, write only + MOEV, 32, // _OST event code, write only + MOSC, 32, // _OST status code, write only + } + + Method(MESC, 0) { + Store(Zero, Local0) // Mem devs iterrator + + Acquire(MLCK, 0xFFFF) + while (LLess(Local0, MDNR)) { + Store(Local0, MSEL) // select Local0 DIMM + If (LEqual(MINS, One)) { // Memory device needs check + \_SB.MTFY(Local0, 1) + Store(1, MINS) + } + If (LEqual(MRMV, One)) { // Ejection request + \_SB.MTFY(Local0, 3) + } + Add(Local0, One, Local0) // goto next DIMM + } + Release(MLCK) + Return(One) + } + + Method (MRST, 1) { + Store(Zero, Local0) + + Acquire(MLCK, 0xFFFF) + Store(ToInteger(Arg0), MSEL) // select DIMM + + If (LEqual(MES, One)) { + Store(0xF, Local0) + } + + Release(MLCK) + Return(Local0) + } + + Method(MCRS, 1) { + Acquire(MLCK, 0xFFFF) + Store(ToInteger(Arg0), MSEL) // select DIMM + + Name(MR64, ResourceTemplate() { + QWordMemory(ResourceProducer, PosDecode, MinFixed, MaxFixed, + Cacheable, ReadWrite, + 0x0000000000000000, // Address Space Granularity + 0x0000000000000000, // Address Range Minimum + 0xFFFFFFFFFFFFFFFE, // Address Range Maximum + 0x0000000000000000, // Address Translation Offset + 0xFFFFFFFFFFFFFFFF, // Address Length + ,, MW64, AddressRangeMemory, TypeStatic) + }) + + CreateDWordField(MR64, 14, MINL) + CreateDWordField(MR64, 18, MINH) + CreateDWordField(MR64, 38, LENL) + CreateDWordField(MR64, 42, LENH) + CreateDWordField(MR64, 22, MAXL) + CreateDWordField(MR64, 26, MAXH) + + Store(MRBH, MINH) + Store(MRBL, MINL) + Store(MRLH, LENH) + Store(MRLL, LENL) + + // 64-bit math: MAX = MIN + LEN - 1 + Add(MINL, LENL, MAXL) + Add(MINH, LENH, MAXH) + If (Or(LLess(MAXL, MINL), LLess(MAXL, LENL))) { + Add(MAXH, 1, MAXH) + } + If (LEqual(MAXL, Zero)) { + Subtract(MAXH, One, MAXH) + Store(0xFFFFFFFF, MAXL) + } Else { + Subtract(MAXL, One, MAXL) + } + + Release(MLCK) + Return(MR64) + } + + Method (MPXM, 1) { + Acquire(MLCK, 0xFFFF) + Store(ToInteger(Arg0), MSEL) // select DIMM + Store(MPX, Local0) + Release(MLCK) + Return(Local0) + } + + Method(MOST, 4) { + Acquire(MLCK, 0xFFFF) + Store(ToInteger(Arg0), MSEL) // select DIMM + Store(Arg1, MOEV) + Store(Arg2, MOSC) + Release(MLCK) + } +} diff --git a/hw/i386/acpi-dsdt.dsl b/hw/i386/acpi-dsdt.dsl index 90efce0..726332f 100644 --- a/hw/i386/acpi-dsdt.dsl +++ b/hw/i386/acpi-dsdt.dsl @@ -294,6 +294,7 @@ DefinitionBlock ( } #include "acpi-dsdt-cpu-hotplug.dsl" +#include "acpi-dsdt-mem-hotplug.dsl" /**************************************************************** @@ -313,7 +314,9 @@ DefinitionBlock ( // CPU hotplug event \_SB.PRSC() } - Method(_L03) { + Method(_E03) { + // Memory hotplug event + \_SB.MESC() } Method(_L04) { } diff --git a/hw/i386/ssdt-mem.dsl b/hw/i386/ssdt-mem.dsl new file mode 100644 index 0000000..c70aa1b --- /dev/null +++ b/hw/i386/ssdt-mem.dsl @@ -0,0 +1,76 @@ +/* + * Memory hotplug ACPI DSDT static objects definitions + * + * Copyright ProfitBricks GmbH 2012 + * Copyright (C) 2013 Red Hat Inc + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see + */ + +/* This file is the basis for the ssdt_mem[] variable in src/acpi.c. + * It defines the contents of the memory device object. At + * runtime, a dynamically generated SSDT will contain one copy of this + * AML snippet for every possible memory device in the system. The + * objects will be placed in the \_SB_ namespace. + * + * In addition to the aml code generated from this file, the + * src/acpi.c file creates a MTFY method with an entry for each memdevice: + * Method(MTFY, 2) { + * If (LEqual(Arg0, 0x00)) { Notify(MP00, Arg1) } + * If (LEqual(Arg0, 0x01)) { Notify(MP01, Arg1) } + * ... + * } + */ +ACPI_EXTRACT_ALL_CODE ssdm_mem_aml + +DefinitionBlock ("ssdt-mem.aml", "SSDT", 0x02, "BXPC", "CSSDT", 0x1) +/* v------------------ DO NOT EDIT ------------------v */ +{ + ACPI_EXTRACT_NAME_STRING ssdt_mem_count_name + ACPI_EXTRACT_NAME_DWORD_CONST ssdt_mem_count + Name(MDNR, 0xFFFFFFFF) + + ACPI_EXTRACT_DEVICE_START ssdt_mem_start + ACPI_EXTRACT_DEVICE_END ssdt_mem_end + ACPI_EXTRACT_DEVICE_STRING ssdt_mem_name + Device(MPAA) { + ACPI_EXTRACT_NAME_STRING ssdt_mem_id + Name(_UID, "0xAA") +/* ^------------------ DO NOT EDIT ------------------^ + * Don't change the above without also updating the C code. + */ + Name(_HID, EISAID("PNP0C80")) + + External(MCRS, MethodObj) + External(MRST, MethodObj) + External(MOST, MethodObj) + External(MPXM, MethodObj) + + Method(_CRS, 0) { + Return (MCRS(_UID)) + } + + Method (_STA, 0) { + Return (MRST(_UID)) + } + + Method (_PXM, 0) { + Return (MPXM(_UID)) + } + + Method (_OST, 3) { + MOST(_UID, Arg0, Arg1, Arg2) + } + } +} -- 1.7.1