This series adds memory devices and related methods to support ACPI memory hotplug.
This series works with qemu counterpart. See qemu series for a detailed description.
Hu Tao (2): set psize to 0 when romfile_loadfile failed acpi: generate hotplug memory devices
Vasilis Liaskovitis (5): Add ACPI_EXTRACT_DEVICE* macros Add SSDT memory device support acpi-dsdt: Implement functions for memory hotplug q35: Add memory hotplug handler pci: Use paravirt interface for pcimem_start and pcimem64_start
Makefile | 2 +- src/acpi-dsdt-mem-hotplug.dsl | 57 ++++++++++++++++ src/acpi-dsdt.dsl | 5 +- src/acpi.c | 151 ++++++++++++++++++++++++++++++++++++++++-- src/paravirt.c | 15 +++++ src/paravirt.h | 1 + src/pciinit.c | 9 +++ src/q35-acpi-dsdt.dsl | 6 +- src/romfile.c | 13 ++-- src/ssdt-mem.dsl | 61 +++++++++++++++++ tools/acpi_extract.py | 28 ++++++++ 11 files changed, 333 insertions(+), 15 deletions(-) create mode 100644 src/acpi-dsdt-mem-hotplug.dsl create mode 100644 src/ssdt-mem.dsl
From: Vasilis Liaskovitis vasilis.liaskovitis@profitbricks.com
This allows to extract the beginning, end and name of a Device object.
Signed-off-by: Vasilis Liaskovitis vasilis.liaskovitis@profitbricks.com --- tools/acpi_extract.py | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+)
diff --git a/tools/acpi_extract.py b/tools/acpi_extract.py index ab8ced6..8ad15d3 100755 --- a/tools/acpi_extract.py +++ b/tools/acpi_extract.py @@ -230,6 +230,28 @@ def aml_package_start(offset): offset += 1 return offset + aml_pkglen_bytes(offset) + 1
+def aml_device_start(offset): + #0x5B 0x82 DeviceOp PkgLength NameString ProcID + if ((aml[offset] != 0x5B) or (aml[offset + 1] != 0x82)): + die( "Name offset 0x%x: expected 0x5B 0x83 actual 0x%x 0x%x" % + (offset, aml[offset], aml[offset + 1])); + return offset + +def aml_device_string(offset): + #0x5B 0x82 DeviceOp PkgLength NameString ProcID + start = aml_device_start(offset) + offset += 2 + pkglenbytes = aml_pkglen_bytes(offset) + offset += pkglenbytes + return offset + +def aml_device_end(offset): + start = aml_device_start(offset) + offset += 2 + pkglenbytes = aml_pkglen_bytes(offset) + pkglen = aml_pkglen(offset) + return offset + pkglen + lineno = 0 for line in fileinput.input(): # Strip trailing newline @@ -322,6 +344,12 @@ for i in range(len(asl)): offset = aml_processor_end(offset) elif (directive == "ACPI_EXTRACT_PKG_START"): offset = aml_package_start(offset) + elif (directive == "ACPI_EXTRACT_DEVICE_START"): + offset = aml_device_start(offset) + elif (directive == "ACPI_EXTRACT_DEVICE_STRING"): + offset = aml_device_string(offset) + elif (directive == "ACPI_EXTRACT_DEVICE_END"): + offset = aml_device_end(offset) else: die("Unsupported directive %s" % directive)
From: Vasilis Liaskovitis vasilis.liaskovitis@profitbricks.com
Define SSDT hotplug-able memory devices in _SB namespace. The dynamically generated SSDT includes per memory device hotplug methods. These methods just call methods defined in the DSDT. Also dynamically generate a MTFY method and a MEON array of the online/available memory devices. ACPI extraction macros are used to place the AML code in variables later used by src/acpi. The design is taken from SSDT cpu generation.
Signed-off-by: Vasilis Liaskovitis vasilis.liaskovitis@profitbricks.com --- Makefile | 2 +- src/ssdt-mem.dsl | 61 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 62 insertions(+), 1 deletion(-) create mode 100644 src/ssdt-mem.dsl
diff --git a/Makefile b/Makefile index 759bbbb..b88fb90 100644 --- a/Makefile +++ b/Makefile @@ -223,7 +223,7 @@ $(OUT)%.hex: src/%.dsl ./tools/acpi_extract_preprocess.py ./tools/acpi_extract.p $(Q)$(PYTHON) ./tools/acpi_extract.py $(OUT)$*.lst > $(OUT)$*.off $(Q)cat $(OUT)$*.off > $@
-$(OUT)acpi.o: $(OUT)acpi-dsdt.hex $(OUT)ssdt-proc.hex $(OUT)ssdt-pcihp.hex $(OUT)ssdt-misc.hex $(OUT)q35-acpi-dsdt.hex +$(OUT)acpi.o: $(OUT)acpi-dsdt.hex $(OUT)ssdt-proc.hex $(OUT)ssdt-pcihp.hex $(OUT)ssdt-misc.hex $(OUT)q35-acpi-dsdt.hex $(OUT)ssdt-mem.hex
################ Kconfig rules
diff --git a/src/ssdt-mem.dsl b/src/ssdt-mem.dsl new file mode 100644 index 0000000..d0f6203 --- /dev/null +++ b/src/ssdt-mem.dsl @@ -0,0 +1,61 @@ +/* This file is the basis for the ssdt_mem[] variable in src/acpi.c. + * It is similar in design to the ssdt_proc variable. + * It defines the contents of the per-dimm QWordMemory() 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) } + * ... + * } + * and a MEON array with the list of active and inactive memory devices: + * Name(MEON, Package() { One, One, ..., Zero, Zero, ... }) + */ +ACPI_EXTRACT_ALL_CODE ssdm_mem_aml + +DefinitionBlock ("ssdt-mem.aml", "SSDT", 0x02, "BXPC", "CSSDT", 0x1) +/* v------------------ DO NOT EDIT ------------------v */ +{ + 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_BYTE_CONST ssdt_mem_id + Name(ID, 0xAA) +/* ^------------------ DO NOT EDIT ------------------^ + * + * The src/acpi.c code requires the above layout so that it can update + * MPAA and 0xAA with the appropriate MEMDEVICE id (see + * SD_OFFSET_MEMHEX/MEMID1/MEMID2). Don't change the above without + * also updating the C code. + */ + Name(_HID, EISAID("PNP0C80")) + Name(_PXM, 0xAA) + + External(CMST, MethodObj) + External(MPEJ, MethodObj) + + Name(_CRS, ResourceTemplate() { + QwordMemory( + ResourceConsumer, + , // _DEC + MinFixed, // _MIF + MaxFixed, // _MAF + Cacheable, // _MEM + ReadWrite, // _RW + 0x0, // _GRA + 0xDEADBEEF, // _MIN + 0xE6ADBEEE, // _MAX + 0x00000000, // _TRA + 0x08000000, // _LEN + ) + }) + Method (_STA, 0) { + Return(CMST(ID)) + } + } +}
From: Vasilis Liaskovitis vasilis.liaskovitis@profitbricks.com
Extend the DSDT to include methods for handling memory hot-add and hot-remove notifications and memory device status requests. These functions are called from the memory device SSDT methods.
Signed-off-by: Vasilis Liaskovitis vasilis.liaskovitis@profitbricks.com --- src/acpi-dsdt-mem-hotplug.dsl | 57 +++++++++++++++++++++++++++++++++++++++++++ src/acpi-dsdt.dsl | 5 +++- 2 files changed, 61 insertions(+), 1 deletion(-) create mode 100644 src/acpi-dsdt-mem-hotplug.dsl
diff --git a/src/acpi-dsdt-mem-hotplug.dsl b/src/acpi-dsdt-mem-hotplug.dsl new file mode 100644 index 0000000..1d82532 --- /dev/null +++ b/src/acpi-dsdt-mem-hotplug.dsl @@ -0,0 +1,57 @@ +/**************************************************************** + * Memory hotplug + ****************************************************************/ + +Scope(_SB) { + /* Objects filled in by run-time generated SSDT */ + External(MTFY, MethodObj) + External(MEON, PkgObj) + + Method (CMST, 1, NotSerialized) { + // _STA method - return ON status of memdevice + // Local0 = MEON flag for this cpu + Store(DerefOf(Index(MEON, Arg0)), Local0) + If (Local0) { Return(0xF) } Else { Return(0x0) } + } + + /* Memory hotplug notify array */ + OperationRegion(MEST, SystemIO, 0xaf80, 32) + Field (MEST, ByteAcc, NoLock, Preserve) + { + MES, 256 + } + + Method(MESC, 0) { + // Local5 = active memdevice bitmap + Store (MES, Local5) + // Local2 = last read byte from bitmap + Store (Zero, Local2) + // Local0 = memory device iterator + Store (Zero, Local0) + While (LLess(Local0, SizeOf(MEON))) { + // Local1 = MEON flag for this memory device + Store(DerefOf(Index(MEON, Local0)), Local1) + If (And(Local0, 0x07)) { + // Shift down previously read bitmap byte + ShiftRight(Local2, 1, Local2) + } Else { + // Read next byte from memdevice bitmap + Store(DerefOf(Index(Local5, ShiftRight(Local0, 3))), Local2) + } + // Local3 = active state for this memory device + Store(And(Local2, 1), Local3) + + If (LNotEqual(Local1, Local3)) { + // State change - update MEON with new state + Store(Local3, Index(MEON, Local0)) + // Do MEM notify + If (LEqual(Local3, 1)) { + MTFY(Local0, 1) + } + } + Increment(Local0) + } + Return(One) + } + +} diff --git a/src/acpi-dsdt.dsl b/src/acpi-dsdt.dsl index 158f6b4..98c9413 100644 --- a/src/acpi-dsdt.dsl +++ b/src/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) { }
Signed-off-by: Hu Tao hutao@cn.fujitsu.com --- src/romfile.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-)
diff --git a/src/romfile.c b/src/romfile.c index ea71d1f..b1b89bb 100644 --- a/src/romfile.c +++ b/src/romfile.c @@ -51,28 +51,33 @@ romfile_loadfile(const char *name, int *psize) { struct romfile_s *file = romfile_find(name); if (!file) - return NULL; + goto failed;
int filesize = file->size; if (!filesize) - return NULL; + goto failed;
char *data = malloc_tmphigh(filesize+1); if (!data) { warn_noalloc(); - return NULL; + goto failed; }
dprintf(5, "Copying romfile '%s' (len %d)\n", name, filesize); int ret = file->copy(file, data, filesize); if (ret < 0) { free(data); - return NULL; + goto failed; } if (psize) *psize = filesize; data[filesize] = '\0'; return data; + +failed: + if (psize) + *psize = 0; + return NULL; }
// Attempt to load an integer from the given file - return 'defval'
The memory device generation is guided by qemu paravirt info. Seabios uses the info to setup SRAT entries for the hotplug-able memory slots, and to generate appropriate memory device objects. One memory device (and corresponding SRAT entry) is generated for each hotplug-able qemu memslot. Currently no SSDT memory device is created for initial system memory.
We only support up to 255 DIMMs for now (PackageOp used for the MEON array can only describe an array of at most 255 elements. VarPackageOp would be needed to support more than 255 devices)
Signed-off-by: Vasilis Liaskovitis vasilis.liaskovitis@profitbricks.com Signed-off-by: Hu Tao hutao@cn.fujitsu.com --- src/acpi.c | 151 ++++++++++++++++++++++++++++++++++++++++++++++++++++++--- src/paravirt.c | 8 +++ 2 files changed, 152 insertions(+), 7 deletions(-)
diff --git a/src/acpi.c b/src/acpi.c index ce988e0..e9a0326 100644 --- a/src/acpi.c +++ b/src/acpi.c @@ -15,6 +15,8 @@ #include "config.h" // CONFIG_* #include "paravirt.h" // RamSize #include "dev-q35.h" +#include "memmap.h" +#include "paravirt.h"
#include "acpi-dsdt.hex"
@@ -250,11 +252,23 @@ encodeLen(u8 *ssdt_ptr, int length, int bytes) #define PCIHP_AML (ssdp_pcihp_aml + *ssdt_pcihp_start) #define PCI_SLOTS 32
+/* 0x5B 0x82 DeviceOp PkgLength NameString DimmID */ +#define MEM_BASE 0xaf80 +#define MEM_AML (ssdm_mem_aml + *ssdt_mem_start) +#define MEM_SIZEOF (*ssdt_mem_end - *ssdt_mem_start) +#define MEM_OFFSET_HEX (*ssdt_mem_name - *ssdt_mem_start + 2) +#define MEM_OFFSET_ID (*ssdt_mem_id - *ssdt_mem_start) +#define MEM_OFFSET_PXM 31 +#define MEM_OFFSET_START 55 +#define MEM_OFFSET_END 63 +#define MEM_OFFSET_SIZE 79 + #define SSDT_SIGNATURE 0x54445353 // SSDT #define SSDT_HEADER_LENGTH 36
#include "ssdt-misc.hex" #include "ssdt-pcihp.hex" +#include "ssdt-mem.hex"
#define PCI_RMV_BASE 0xae0c
@@ -306,9 +320,100 @@ static void patch_pcihp(int slot, u8 *ssdt_ptr, u32 eject) } }
+static void build_memdev(u8 *ssdt_ptr, int i, u64 mem_base, u64 mem_len, u8 node) +{ + memcpy(ssdt_ptr, MEM_AML, MEM_SIZEOF); + ssdt_ptr[MEM_OFFSET_HEX] = getHex(i >> 4); + ssdt_ptr[MEM_OFFSET_HEX+1] = getHex(i); + ssdt_ptr[MEM_OFFSET_ID] = i; + ssdt_ptr[MEM_OFFSET_PXM] = node; + *(u64*)(ssdt_ptr + MEM_OFFSET_START) = cpu_to_le64(mem_base); + *(u64*)(ssdt_ptr + MEM_OFFSET_END) = cpu_to_le64(mem_base + mem_len); + *(u64*)(ssdt_ptr + MEM_OFFSET_SIZE) = cpu_to_le64(mem_len); +} + +static u8 *build_memssdt(u8 *ssdt_ptr, int memssdt_len, + u64 *numadimmsmap, int nb_memdevs) +{ + u64 mem_base, mem_len; + u64 *dimm = numadimmsmap; + int node; + int i; + + // build Scope(_SB_) header + *(ssdt_ptr++) = 0x10; // ScopeOp + ssdt_ptr = encodeLen(ssdt_ptr, memssdt_len, 3); + *(ssdt_ptr++) = '_'; + *(ssdt_ptr++) = 'S'; + *(ssdt_ptr++) = 'B'; + *(ssdt_ptr++) = '_'; + + for (i = 0; i < nb_memdevs; i++) { + mem_base = *dimm++; + mem_len = *dimm++; + node = *dimm++; + build_memdev(ssdt_ptr, i, mem_base, mem_len, node); + ssdt_ptr += MEM_SIZEOF; + } + + // build "Method(MTFY, 2) {If (LEqual(Arg0, 0x00)) {Notify(CM00, Arg1)} ...}" + *(ssdt_ptr++) = 0x14; // MethodOp + ssdt_ptr = encodeLen(ssdt_ptr, 2+5+(12*nb_memdevs), 2); + *(ssdt_ptr++) = 'M'; + *(ssdt_ptr++) = 'T'; + *(ssdt_ptr++) = 'F'; + *(ssdt_ptr++) = 'Y'; + *(ssdt_ptr++) = 0x02; + for (i=0; i<nb_memdevs; i++) { + *(ssdt_ptr++) = 0xA0; // IfOp + ssdt_ptr = encodeLen(ssdt_ptr, 11, 1); + *(ssdt_ptr++) = 0x93; // LEqualOp + *(ssdt_ptr++) = 0x68; // Arg0Op + *(ssdt_ptr++) = 0x0A; // BytePrefix + *(ssdt_ptr++) = i; + *(ssdt_ptr++) = 0x86; // NotifyOp + *(ssdt_ptr++) = 'M'; + *(ssdt_ptr++) = 'P'; + *(ssdt_ptr++) = getHex(i >> 4); + *(ssdt_ptr++) = getHex(i); + *(ssdt_ptr++) = 0x69; // Arg1Op + } + + // build "Name(MEON, Package() { One, One, ..., Zero, Zero, ... })" + *(ssdt_ptr++) = 0x08; // NameOp + *(ssdt_ptr++) = 'M'; + *(ssdt_ptr++) = 'E'; + *(ssdt_ptr++) = 'O'; + *(ssdt_ptr++) = 'N'; + *(ssdt_ptr++) = 0x12; // PackageOp + ssdt_ptr = encodeLen(ssdt_ptr, 2+1+(1*nb_memdevs), 2); + *(ssdt_ptr++) = nb_memdevs; + + dimm = numadimmsmap; + u8 memslot_status = 0, enabled; + + for (i = 0; i < nb_memdevs; i++) { + enabled = 0; + if (i % 8 == 0) + memslot_status = inb(MEM_BASE + i/8); + enabled = memslot_status & 1; + mem_base = *dimm++; + mem_len = *dimm++; + dimm++; // node + *(ssdt_ptr++) = enabled ? 0x01 : 0x00; + if (enabled) + add_e820(mem_base, mem_len, E820_RAM); + memslot_status = memslot_status >> 1; + } + + return ssdt_ptr; +} + static void* build_ssdt(void) { + int nb_memdevs; + u64 *numadimmsmap; int acpi_cpus = MaxCountCPUs > 0xff ? 0xff : MaxCountCPUs; int length = (sizeof(ssdp_misc_aml) // _S3_ / _S4_ / _S5_ + (1+3+4) // Scope(_SB_) @@ -318,9 +423,20 @@ build_ssdt(void) + (1+3+4) // Scope(PCI0) + ((PCI_SLOTS - 1) * PCIHP_SIZEOF) // slots + (1+2+5+(12*(PCI_SLOTS - 1)))); // PCNT - u8 *ssdt = malloc_high(length); + + numadimmsmap = romfile_loadfile("etc/numa-dimm-map", &nb_memdevs); + nb_memdevs /= 3 * sizeof(u64); + + // for build_memssdt + int memssdt_length = (1+3+4) + + (nb_memdevs * MEM_SIZEOF) + + (1+2+5+(12*nb_memdevs)) + + (6+2+1+(1*nb_memdevs)); + + u8 *ssdt = malloc_high(length + memssdt_length); if (! ssdt) { warn_noalloc(); + free(numadimmsmap); return NULL; } u8 *ssdt_ptr = ssdt; @@ -411,10 +527,13 @@ build_ssdt(void)
ssdt_ptr = build_notify(ssdt_ptr, "PCNT", 1, PCI_SLOTS, "S00_", 1);
+ ssdt_ptr = build_memssdt(ssdt_ptr, memssdt_length, numadimmsmap, nb_memdevs); + build_header((void*)ssdt, SSDT_SIGNATURE, ssdt_ptr - ssdt, 1);
//hexdump(ssdt, ssdt_ptr - ssdt);
+ free(numadimmsmap); return ssdt; }
@@ -458,7 +577,7 @@ acpi_build_srat_memory(struct srat_memory_affinity *numamem, numamem->length = sizeof(*numamem); memset(numamem->proximity, 0, 4); numamem->proximity[0] = node; - numamem->flags = cpu_to_le32(!!enabled); + numamem->flags = cpu_to_le32(!!enabled) | cpu_to_le32(0x2); numamem->base_addr = cpu_to_le64(base); numamem->range_length = cpu_to_le64(len); } @@ -466,18 +585,22 @@ acpi_build_srat_memory(struct srat_memory_affinity *numamem, static void * build_srat(void) { - int numadatasize, numacpusize; + int numadatasize, numacpusize, nb_numa_dimms; + u64 *numadimmsmap; u64 *numadata = romfile_loadfile("etc/numa-nodes", &numadatasize); u64 *numacpumap = romfile_loadfile("etc/numa-cpu-map", &numacpusize); - if (!numadata || !numacpumap) - goto fail; + int max_cpu = numacpusize / sizeof(u64); int nb_numa_nodes = numadatasize / sizeof(u64);
+ numadimmsmap = romfile_loadfile("etc/numa-dimm-map", &nb_numa_dimms); + + nb_numa_dimms /= 3 * sizeof(u64); + struct system_resource_affinity_table *srat; int srat_size = sizeof(*srat) + sizeof(struct srat_processor_affinity) * max_cpu + - sizeof(struct srat_memory_affinity) * (nb_numa_nodes + 2); + sizeof(struct srat_memory_affinity) * (nb_numa_nodes + nb_numa_dimms + 2);
srat = malloc_high(srat_size); if (!srat) { @@ -512,6 +635,7 @@ build_srat(void) */ struct srat_memory_affinity *numamem = (void*)core; int slots = 0; + int node; u64 mem_len, mem_base, next_base = 0;
acpi_build_srat_memory(numamem, 0, 640*1024, 0, 1); @@ -541,7 +665,18 @@ build_srat(void) numamem++; slots++; } - for (; slots < nb_numa_nodes + 2; slots++) { + if (nb_numa_dimms) { + for (i = 1; i < nb_numa_dimms + 1; ++i) { + mem_base = *numadimmsmap++; + mem_len = *numadimmsmap++; + node = *numadimmsmap++; + acpi_build_srat_memory(numamem, mem_base, mem_len, node, 1); + numamem++; + slots++; + } + } + + for (; slots < nb_numa_nodes + nb_numa_dimms + 2; slots++) { acpi_build_srat_memory(numamem, 0, 0, 0, 0); numamem++; } @@ -550,10 +685,12 @@ build_srat(void)
free(numadata); free(numacpumap); + free(numadimmsmap); return srat; fail: free(numadata); free(numacpumap); + free(numadimmsmap); return NULL; }
diff --git a/src/paravirt.c b/src/paravirt.c index d1a5d3e..5925c63 100644 --- a/src/paravirt.c +++ b/src/paravirt.c @@ -240,6 +240,14 @@ qemu_cfg_legacy(void) , sizeof(numacount) + max_cpu*sizeof(u64) , numacount*sizeof(u64));
+ u64 dimm_count; + qemu_cfg_select(QEMU_CFG_NUMA); + qemu_cfg_skip((1 + max_cpu + numacount) * sizeof(u64)); + qemu_cfg_read(&dimm_count, sizeof(dimm_count)); + qemu_romfile_add("etc/numa-dimm-map", QEMU_CFG_NUMA + , (2 + max_cpu + numacount) * sizeof(u64), + dimm_count * 3 * sizeof(u64)); + // e820 data u32 count32; qemu_cfg_read_entry(&count32, QEMU_CFG_E820_TABLE, sizeof(count32));
From: Vasilis Liaskovitis vasilis.liaskovitis@profitbricks.com
Signed-off-by: Vasilis Liaskovitis vasilis.liaskovitis@profitbricks.com --- src/q35-acpi-dsdt.dsl | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/src/q35-acpi-dsdt.dsl b/src/q35-acpi-dsdt.dsl index c031d83..5b28d72 100644 --- a/src/q35-acpi-dsdt.dsl +++ b/src/q35-acpi-dsdt.dsl @@ -403,7 +403,7 @@ DefinitionBlock ( }
#include "acpi-dsdt-cpu-hotplug.dsl" - +#include "acpi-dsdt-mem-hotplug.dsl"
/**************************************************************** * General purpose events @@ -418,7 +418,9 @@ DefinitionBlock ( // CPU hotplug event _SB.PRSC() } - Method(_L02) { + Method(_E02) { + // Memory hotplug event + _SB.MESC() } Method(_L03) { }
From: Vasilis Liaskovitis vasilis.liaskovitis@profitbricks.com
Initialize the 32-bit and 64-bit pci starting offsets from values passed in by the qemu paravirt interface QEMU_CFG_PCI_WINDOW. Qemu calculates the starting offsets based on initial memory and hotplug-able dimms. It's possible to avoid the new paravirt interface, and calculate pci ranges from srat entries. But the code changes are ugly, see: http://lists.gnu.org/archive/html/qemu-devel/2012-09/msg03548.html
Signed-off-by: Vasilis Liaskovitis vasilis.liaskovitis@profitbricks.com --- src/paravirt.c | 7 +++++++ src/paravirt.h | 1 + src/pciinit.c | 9 +++++++++ 3 files changed, 17 insertions(+)
diff --git a/src/paravirt.c b/src/paravirt.c index 5925c63..9c1e511 100644 --- a/src/paravirt.c +++ b/src/paravirt.c @@ -134,6 +134,7 @@ qemu_platform_setup(void) #define QEMU_CFG_BOOT_MENU 0x0e #define QEMU_CFG_MAX_CPUS 0x0f #define QEMU_CFG_FILE_DIR 0x19 +#define QEMU_CFG_PCI_WINDOW 0x1a #define QEMU_CFG_ARCH_LOCAL 0x8000 #define QEMU_CFG_ACPI_TABLES (QEMU_CFG_ARCH_LOCAL + 0) #define QEMU_CFG_SMBIOS_ENTRIES (QEMU_CFG_ARCH_LOCAL + 1) @@ -339,3 +340,9 @@ void qemu_cfg_init(void) , 0, be32_to_cpu(qfile.size)); } } + +void qemu_cfg_get_pci_offsets(u64 *pcimem_start, u64 *pcimem64_start) +{ + qemu_cfg_read_entry(pcimem_start, QEMU_CFG_PCI_WINDOW, sizeof(u64)); + qemu_cfg_read((u8*)(pcimem64_start), sizeof(u64)); +} diff --git a/src/paravirt.h b/src/paravirt.h index fce5af9..2c37d0d 100644 --- a/src/paravirt.h +++ b/src/paravirt.h @@ -27,5 +27,6 @@ static inline int runningOnKVM(void) { void qemu_preinit(void); void qemu_platform_setup(void); void qemu_cfg_init(void); +void qemu_cfg_get_pci_offsets(u64 *pcimem_start, u64 *pcimem64_start);
#endif diff --git a/src/pciinit.c b/src/pciinit.c index 8370b96..7e63c5e 100644 --- a/src/pciinit.c +++ b/src/pciinit.c @@ -805,6 +805,7 @@ static void pci_bios_map_devices(struct pci_bus *busses) void pci_setup(void) { + u64 pv_pcimem_start, pv_pcimem64_start; if (!CONFIG_QEMU) return;
@@ -837,6 +838,14 @@ pci_setup(void)
pci_bios_init_devices();
+ /* if qemu gives us other pci window values, it means there are hotplug-able + * dimms. Adjust accordingly */ + qemu_cfg_get_pci_offsets(&pv_pcimem_start, &pv_pcimem64_start); + if (pv_pcimem_start > pcimem_start) + pcimem_start = pv_pcimem_start; + if (pv_pcimem64_start > pcimem64_start) + pcimem64_start = pv_pcimem64_start; + free(busses);
pci_enable_default_vga();
On Wed, Jun 26, 2013 at 05:14:58PM +0800, Hu Tao wrote:
This series adds memory devices and related methods to support ACPI memory hotplug.
This series works with qemu counterpart. See qemu series for a detailed description.
Hu Tao (2): set psize to 0 when romfile_loadfile failed acpi: generate hotplug memory devices
Vasilis Liaskovitis (5): Add ACPI_EXTRACT_DEVICE* macros Add SSDT memory device support acpi-dsdt: Implement functions for memory hotplug q35: Add memory hotplug handler pci: Use paravirt interface for pcimem_start and pcimem64_start
Makefile | 2 +- src/acpi-dsdt-mem-hotplug.dsl | 57 ++++++++++++++++ src/acpi-dsdt.dsl | 5 +- src/acpi.c | 151 ++++++++++++++++++++++++++++++++++++++++-- src/paravirt.c | 15 +++++ src/paravirt.h | 1 + src/pciinit.c | 9 +++ src/q35-acpi-dsdt.dsl | 6 +- src/romfile.c | 13 ++-- src/ssdt-mem.dsl | 61 +++++++++++++++++ tools/acpi_extract.py | 28 ++++++++ 11 files changed, 333 insertions(+), 15 deletions(-) create mode 100644 src/acpi-dsdt-mem-hotplug.dsl create mode 100644 src/ssdt-mem.dsl
We were looking for a new feature to use the acpi tables in qemu. Could you use that instead of adding code to seabios?
You can find the latest bits here:
git://git.kernel.org/pub/scm/virt/kvm/mst/qemu.git acpi
-- 1.8.3.1