mirror of
https://github.com/izzy2lost/xemu.git
synced 2026-07-06 00:20:22 -07:00
Merge remote-tracking branch 'remotes/mst/tags/for_upstream' into staging
pc, pci, misc bugfixes A bunch of bugfixes for 2.2. Signed-off-by: Michael S. Tsirkin <mst@redhat.com> # gpg: Signature made Mon 24 Nov 2014 18:59:47 GMT using RSA key ID D28D5469 # gpg: Good signature from "Michael S. Tsirkin <mst@kernel.org>" # gpg: aka "Michael S. Tsirkin <mst@redhat.com>" * remotes/mst/tags/for_upstream: pc: acpi: mark all possible CPUs as enabled in SRAT pcie: fix improper use of negative value pcie: fix typo in pcie_cap_deverr_init() target-i386: move generic memory hotplug methods to DSDTs acpi-build: mark RAM dirty on table update hw/pci: fix crash on shpc error flow pc: count in 1Gb hugepage alignment when sizing hotplug-memory container pc: explicitly check maxmem limit when adding DIMM pc: pc-dimm: use backend alignment during address auto allocation pc: align DIMM's address/size by backend's alignment value memory: expose alignment used for allocating RAM as MemoryRegion API pc: limit DIMM address and size to page aligned values pc: make pc_dimm_plug() more readble pc: kvm: check if KVM has free memory slots to avoid abort() qemu-char: fix tcp_get_fds Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
@@ -909,14 +909,15 @@ static int subpage_register (subpage_t *mmio, uint32_t start, uint32_t end,
|
||||
uint16_t section);
|
||||
static subpage_t *subpage_init(AddressSpace *as, hwaddr base);
|
||||
|
||||
static void *(*phys_mem_alloc)(size_t size) = qemu_anon_ram_alloc;
|
||||
static void *(*phys_mem_alloc)(size_t size, uint64_t *align) =
|
||||
qemu_anon_ram_alloc;
|
||||
|
||||
/*
|
||||
* Set a custom physical guest memory alloator.
|
||||
* Accelerators with unusual needs may need this. Hopefully, we can
|
||||
* get rid of it eventually.
|
||||
*/
|
||||
void phys_mem_set_alloc(void *(*alloc)(size_t))
|
||||
void phys_mem_set_alloc(void *(*alloc)(size_t, uint64_t *align))
|
||||
{
|
||||
phys_mem_alloc = alloc;
|
||||
}
|
||||
@@ -1098,6 +1099,7 @@ static void *file_ram_alloc(RAMBlock *block,
|
||||
error_propagate(errp, local_err);
|
||||
goto error;
|
||||
}
|
||||
block->mr->align = hpagesize;
|
||||
|
||||
if (memory < hpagesize) {
|
||||
error_setg(errp, "memory size 0x" RAM_ADDR_FMT " must be equal to "
|
||||
@@ -1309,7 +1311,8 @@ static ram_addr_t ram_block_add(RAMBlock *new_block, Error **errp)
|
||||
if (xen_enabled()) {
|
||||
xen_ram_alloc(new_block->offset, new_block->length, new_block->mr);
|
||||
} else {
|
||||
new_block->host = phys_mem_alloc(new_block->length);
|
||||
new_block->host = phys_mem_alloc(new_block->length,
|
||||
&new_block->mr->align);
|
||||
if (!new_block->host) {
|
||||
error_setg_errno(errp, errno,
|
||||
"cannot set up guest memory '%s'",
|
||||
|
||||
+5
-3
@@ -811,12 +811,12 @@ err:
|
||||
return -1;
|
||||
}
|
||||
|
||||
void *rom_add_blob(const char *name, const void *blob, size_t len,
|
||||
ram_addr_t rom_add_blob(const char *name, const void *blob, size_t len,
|
||||
hwaddr addr, const char *fw_file_name,
|
||||
FWCfgReadCallback fw_callback, void *callback_opaque)
|
||||
{
|
||||
Rom *rom;
|
||||
void *data = NULL;
|
||||
ram_addr_t ret = RAM_ADDR_MAX;
|
||||
|
||||
rom = g_malloc0(sizeof(*rom));
|
||||
rom->name = g_strdup(name);
|
||||
@@ -828,11 +828,13 @@ void *rom_add_blob(const char *name, const void *blob, size_t len,
|
||||
rom_insert(rom);
|
||||
if (fw_file_name && fw_cfg) {
|
||||
char devpath[100];
|
||||
void *data;
|
||||
|
||||
snprintf(devpath, sizeof(devpath), "/rom@%s", fw_file_name);
|
||||
|
||||
if (rom_file_has_mr) {
|
||||
data = rom_set_mr(rom, OBJECT(fw_cfg), devpath);
|
||||
ret = memory_region_get_ram_addr(rom->mr);
|
||||
} else {
|
||||
data = rom->data;
|
||||
}
|
||||
@@ -841,7 +843,7 @@ void *rom_add_blob(const char *name, const void *blob, size_t len,
|
||||
fw_callback, callback_opaque,
|
||||
data, rom->romsize);
|
||||
}
|
||||
return data;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* This function is specific for elf program because we don't need to allocate
|
||||
|
||||
+11
-11
@@ -56,6 +56,7 @@
|
||||
|
||||
#include "qapi/qmp/qint.h"
|
||||
#include "qom/qom-qobject.h"
|
||||
#include "exec/ram_addr.h"
|
||||
|
||||
/* These are used to size the ACPI tables for -M pc-i440fx-1.7 and
|
||||
* -M pc-i440fx-2.0. Even if the actual amount of AML generated grows
|
||||
@@ -1269,8 +1270,7 @@ acpi_build_srat_memory(AcpiSratMemoryAffinity *numamem, uint64_t base,
|
||||
}
|
||||
|
||||
static void
|
||||
build_srat(GArray *table_data, GArray *linker,
|
||||
AcpiCpuInfo *cpu, PcGuestInfo *guest_info)
|
||||
build_srat(GArray *table_data, GArray *linker, PcGuestInfo *guest_info)
|
||||
{
|
||||
AcpiSystemResourceAffinityTable *srat;
|
||||
AcpiSratProcessorAffinity *core;
|
||||
@@ -1300,11 +1300,7 @@ build_srat(GArray *table_data, GArray *linker,
|
||||
core->proximity_lo = curnode;
|
||||
memset(core->proximity_hi, 0, 3);
|
||||
core->local_sapic_eid = 0;
|
||||
if (test_bit(i, cpu->found_cpus)) {
|
||||
core->flags = cpu_to_le32(1);
|
||||
} else {
|
||||
core->flags = cpu_to_le32(0);
|
||||
}
|
||||
core->flags = cpu_to_le32(1);
|
||||
}
|
||||
|
||||
|
||||
@@ -1511,7 +1507,7 @@ static inline void acpi_build_tables_cleanup(AcpiBuildTables *tables, bool mfre)
|
||||
typedef
|
||||
struct AcpiBuildState {
|
||||
/* Copy of table in RAM (for patching). */
|
||||
uint8_t *table_ram;
|
||||
ram_addr_t table_ram;
|
||||
uint32_t table_size;
|
||||
/* Is table patched? */
|
||||
uint8_t patched;
|
||||
@@ -1622,7 +1618,7 @@ void acpi_build(PcGuestInfo *guest_info, AcpiBuildTables *tables)
|
||||
}
|
||||
if (guest_info->numa_nodes) {
|
||||
acpi_add_table(table_offsets, tables->table_data);
|
||||
build_srat(tables->table_data, tables->linker, &cpu, guest_info);
|
||||
build_srat(tables->table_data, tables->linker, guest_info);
|
||||
}
|
||||
if (acpi_get_mcfg(&mcfg)) {
|
||||
acpi_add_table(table_offsets, tables->table_data);
|
||||
@@ -1716,9 +1712,12 @@ static void acpi_build_update(void *build_opaque, uint32_t offset)
|
||||
acpi_build(build_state->guest_info, &tables);
|
||||
|
||||
assert(acpi_data_len(tables.table_data) == build_state->table_size);
|
||||
memcpy(build_state->table_ram, tables.table_data->data,
|
||||
memcpy(qemu_get_ram_ptr(build_state->table_ram), tables.table_data->data,
|
||||
build_state->table_size);
|
||||
|
||||
cpu_physical_memory_set_dirty_range_nocode(build_state->table_ram,
|
||||
build_state->table_size);
|
||||
|
||||
acpi_build_tables_cleanup(&tables, true);
|
||||
}
|
||||
|
||||
@@ -1728,7 +1727,7 @@ static void acpi_build_reset(void *build_opaque)
|
||||
build_state->patched = 0;
|
||||
}
|
||||
|
||||
static void *acpi_add_rom_blob(AcpiBuildState *build_state, GArray *blob,
|
||||
static ram_addr_t acpi_add_rom_blob(AcpiBuildState *build_state, GArray *blob,
|
||||
const char *name)
|
||||
{
|
||||
return rom_add_blob(name, blob->data, acpi_data_len(blob), -1, name,
|
||||
@@ -1777,6 +1776,7 @@ void acpi_setup(PcGuestInfo *guest_info)
|
||||
/* Now expose it all to Guest */
|
||||
build_state->table_ram = acpi_add_rom_blob(build_state, tables.table_data,
|
||||
ACPI_BUILD_TABLE_FILE);
|
||||
assert(build_state->table_ram != RAM_ADDR_MAX);
|
||||
build_state->table_size = acpi_data_len(tables.table_data);
|
||||
|
||||
acpi_add_rom_blob(NULL, tables.linker, "etc/table-loader");
|
||||
|
||||
@@ -0,0 +1,176 @@
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
|
||||
* This program 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 General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
External(MEMORY_SLOT_NOTIFY_METHOD, MethodObj)
|
||||
|
||||
Scope(\_SB.PCI0) {
|
||||
Device(MEMORY_HOTPLUG_DEVICE) {
|
||||
Name(_HID, "PNP0A06")
|
||||
Name(_UID, "Memory hotplug resources")
|
||||
External(MEMORY_SLOTS_NUMBER, IntObj)
|
||||
|
||||
/* Memory hotplug IO registers */
|
||||
OperationRegion(MEMORY_HOTPLUG_IO_REGION, SystemIO,
|
||||
ACPI_MEMORY_HOTPLUG_BASE,
|
||||
ACPI_MEMORY_HOTPLUG_IO_LEN)
|
||||
|
||||
Name(_CRS, ResourceTemplate() {
|
||||
IO(Decode16, ACPI_MEMORY_HOTPLUG_BASE, ACPI_MEMORY_HOTPLUG_BASE,
|
||||
0, ACPI_MEMORY_HOTPLUG_IO_LEN, IO)
|
||||
})
|
||||
|
||||
Method(_STA, 0) {
|
||||
If (LEqual(MEMORY_SLOTS_NUMBER, Zero)) {
|
||||
Return(0x0)
|
||||
}
|
||||
/* present, functioning, decoding, not shown in UI */
|
||||
Return(0xB)
|
||||
}
|
||||
|
||||
Field(MEMORY_HOTPLUG_IO_REGION, DWordAcc, NoLock, Preserve) {
|
||||
MEMORY_SLOT_ADDR_LOW, 32, // read only
|
||||
MEMORY_SLOT_ADDR_HIGH, 32, // read only
|
||||
MEMORY_SLOT_SIZE_LOW, 32, // read only
|
||||
MEMORY_SLOT_SIZE_HIGH, 32, // read only
|
||||
MEMORY_SLOT_PROXIMITY, 32, // read only
|
||||
}
|
||||
Field(MEMORY_HOTPLUG_IO_REGION, ByteAcc, NoLock, Preserve) {
|
||||
Offset(20),
|
||||
MEMORY_SLOT_ENABLED, 1, // 1 if enabled, read only
|
||||
MEMORY_SLOT_INSERT_EVENT, 1, // (read) 1 if has a insert event. (write) 1 to clear event
|
||||
}
|
||||
|
||||
Mutex (MEMORY_SLOT_LOCK, 0)
|
||||
Field (MEMORY_HOTPLUG_IO_REGION, DWordAcc, NoLock, Preserve) {
|
||||
MEMORY_SLOT_SLECTOR, 32, // DIMM selector, write only
|
||||
MEMORY_SLOT_OST_EVENT, 32, // _OST event code, write only
|
||||
MEMORY_SLOT_OST_STATUS, 32, // _OST status code, write only
|
||||
}
|
||||
|
||||
Method(MEMORY_SLOT_SCAN_METHOD, 0) {
|
||||
If (LEqual(MEMORY_SLOTS_NUMBER, Zero)) {
|
||||
Return(Zero)
|
||||
}
|
||||
|
||||
Store(Zero, Local0) // Mem devs iterrator
|
||||
Acquire(MEMORY_SLOT_LOCK, 0xFFFF)
|
||||
while (LLess(Local0, MEMORY_SLOTS_NUMBER)) {
|
||||
Store(Local0, MEMORY_SLOT_SLECTOR) // select Local0 DIMM
|
||||
If (LEqual(MEMORY_SLOT_INSERT_EVENT, One)) { // Memory device needs check
|
||||
MEMORY_SLOT_NOTIFY_METHOD(Local0, 1)
|
||||
Store(1, MEMORY_SLOT_INSERT_EVENT)
|
||||
}
|
||||
// TODO: handle memory eject request
|
||||
Add(Local0, One, Local0) // goto next DIMM
|
||||
}
|
||||
Release(MEMORY_SLOT_LOCK)
|
||||
Return(One)
|
||||
}
|
||||
|
||||
Method(MEMORY_SLOT_STATUS_METHOD, 1) {
|
||||
Store(Zero, Local0)
|
||||
|
||||
Acquire(MEMORY_SLOT_LOCK, 0xFFFF)
|
||||
Store(ToInteger(Arg0), MEMORY_SLOT_SLECTOR) // select DIMM
|
||||
|
||||
If (LEqual(MEMORY_SLOT_ENABLED, One)) {
|
||||
Store(0xF, Local0)
|
||||
}
|
||||
|
||||
Release(MEMORY_SLOT_LOCK)
|
||||
Return(Local0)
|
||||
}
|
||||
|
||||
Method(MEMORY_SLOT_CRS_METHOD, 1, Serialized) {
|
||||
Acquire(MEMORY_SLOT_LOCK, 0xFFFF)
|
||||
Store(ToInteger(Arg0), MEMORY_SLOT_SLECTOR) // 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(MEMORY_SLOT_ADDR_HIGH, MINH)
|
||||
Store(MEMORY_SLOT_ADDR_LOW, MINL)
|
||||
Store(MEMORY_SLOT_SIZE_HIGH, LENH)
|
||||
Store(MEMORY_SLOT_SIZE_LOW, LENL)
|
||||
|
||||
// 64-bit math: MAX = MIN + LEN - 1
|
||||
Add(MINL, LENL, MAXL)
|
||||
Add(MINH, LENH, MAXH)
|
||||
If (LLess(MAXL, MINL)) {
|
||||
Add(MAXH, One, MAXH)
|
||||
}
|
||||
If (LLess(MAXL, One)) {
|
||||
Subtract(MAXH, One, MAXH)
|
||||
}
|
||||
Subtract(MAXL, One, MAXL)
|
||||
|
||||
If (LEqual(MAXH, Zero)){
|
||||
Name(MR32, ResourceTemplate() {
|
||||
DWordMemory(ResourceProducer, PosDecode, MinFixed, MaxFixed,
|
||||
Cacheable, ReadWrite,
|
||||
0x00000000, // Address Space Granularity
|
||||
0x00000000, // Address Range Minimum
|
||||
0xFFFFFFFE, // Address Range Maximum
|
||||
0x00000000, // Address Translation Offset
|
||||
0xFFFFFFFF, // Address Length
|
||||
,, MW32, AddressRangeMemory, TypeStatic)
|
||||
})
|
||||
CreateDWordField(MR32, MW32._MIN, MIN)
|
||||
CreateDWordField(MR32, MW32._MAX, MAX)
|
||||
CreateDWordField(MR32, MW32._LEN, LEN)
|
||||
Store(MINL, MIN)
|
||||
Store(MAXL, MAX)
|
||||
Store(LENL, LEN)
|
||||
|
||||
Release(MEMORY_SLOT_LOCK)
|
||||
Return(MR32)
|
||||
}
|
||||
|
||||
Release(MEMORY_SLOT_LOCK)
|
||||
Return(MR64)
|
||||
}
|
||||
|
||||
Method(MEMORY_SLOT_PROXIMITY_METHOD, 1) {
|
||||
Acquire(MEMORY_SLOT_LOCK, 0xFFFF)
|
||||
Store(ToInteger(Arg0), MEMORY_SLOT_SLECTOR) // select DIMM
|
||||
Store(MEMORY_SLOT_PROXIMITY, Local0)
|
||||
Release(MEMORY_SLOT_LOCK)
|
||||
Return(Local0)
|
||||
}
|
||||
|
||||
Method(MEMORY_SLOT_OST_METHOD, 4) {
|
||||
Acquire(MEMORY_SLOT_LOCK, 0xFFFF)
|
||||
Store(ToInteger(Arg0), MEMORY_SLOT_SLECTOR) // select DIMM
|
||||
Store(Arg1, MEMORY_SLOT_OST_EVENT)
|
||||
Store(Arg2, MEMORY_SLOT_OST_STATUS)
|
||||
Release(MEMORY_SLOT_LOCK)
|
||||
}
|
||||
} // Device()
|
||||
} // Scope()
|
||||
@@ -297,13 +297,12 @@ DefinitionBlock (
|
||||
#include "hw/acpi/pc-hotplug.h"
|
||||
#define CPU_STATUS_BASE PIIX4_CPU_HOTPLUG_IO_BASE
|
||||
#include "acpi-dsdt-cpu-hotplug.dsl"
|
||||
#include "acpi-dsdt-mem-hotplug.dsl"
|
||||
|
||||
|
||||
/****************************************************************
|
||||
* General purpose events
|
||||
****************************************************************/
|
||||
External(\_SB.PCI0.MEMORY_HOTPLUG_DEVICE.MEMORY_SLOT_SCAN_METHOD, MethodObj)
|
||||
|
||||
Scope(\_GPE) {
|
||||
Name(_HID, "ACPI0006")
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
+77
-3
@@ -1247,6 +1247,11 @@ FWCfgState *pc_memory_init(MachineState *machine,
|
||||
pcms->hotplug_memory_base =
|
||||
ROUND_UP(0x100000000ULL + above_4g_mem_size, 1ULL << 30);
|
||||
|
||||
if (pcms->enforce_aligned_dimm) {
|
||||
/* size hotplug region assuming 1G page max alignment per slot */
|
||||
hotplug_mem_size += (1ULL << 30) * machine->ram_slots;
|
||||
}
|
||||
|
||||
if ((pcms->hotplug_memory_base + hotplug_mem_size) <
|
||||
hotplug_mem_size) {
|
||||
error_report("unsupported amount of maximum memory: " RAM_ADDR_FMT,
|
||||
@@ -1545,6 +1550,37 @@ void qemu_register_pc_machine(QEMUMachine *m)
|
||||
g_free(name);
|
||||
}
|
||||
|
||||
static int pc_dimm_count(Object *obj, void *opaque)
|
||||
{
|
||||
int *count = opaque;
|
||||
|
||||
if (object_dynamic_cast(obj, TYPE_PC_DIMM)) {
|
||||
(*count)++;
|
||||
}
|
||||
|
||||
object_child_foreach(obj, pc_dimm_count, opaque);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pc_existing_dimms_capacity(Object *obj, void *opaque)
|
||||
{
|
||||
Error *local_err = NULL;
|
||||
uint64_t *size = opaque;
|
||||
|
||||
if (object_dynamic_cast(obj, TYPE_PC_DIMM)) {
|
||||
(*size) += object_property_get_int(obj, PC_DIMM_SIZE_PROP, &local_err);
|
||||
|
||||
if (local_err) {
|
||||
qerror_report_err(local_err);
|
||||
error_free(local_err);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
object_child_foreach(obj, pc_dimm_count, opaque);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void pc_dimm_plug(HotplugHandler *hotplug_dev,
|
||||
DeviceState *dev, Error **errp)
|
||||
{
|
||||
@@ -1556,20 +1592,40 @@ static void pc_dimm_plug(HotplugHandler *hotplug_dev,
|
||||
PCDIMMDevice *dimm = PC_DIMM(dev);
|
||||
PCDIMMDeviceClass *ddc = PC_DIMM_GET_CLASS(dimm);
|
||||
MemoryRegion *mr = ddc->get_memory_region(dimm);
|
||||
uint64_t addr = object_property_get_int(OBJECT(dimm), PC_DIMM_ADDR_PROP,
|
||||
&local_err);
|
||||
uint64_t existing_dimms_capacity = 0;
|
||||
uint64_t align = TARGET_PAGE_SIZE;
|
||||
uint64_t addr;
|
||||
|
||||
addr = object_property_get_int(OBJECT(dimm), PC_DIMM_ADDR_PROP, &local_err);
|
||||
if (local_err) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (memory_region_get_alignment(mr) && pcms->enforce_aligned_dimm) {
|
||||
align = memory_region_get_alignment(mr);
|
||||
}
|
||||
|
||||
addr = pc_dimm_get_free_addr(pcms->hotplug_memory_base,
|
||||
memory_region_size(&pcms->hotplug_memory),
|
||||
!addr ? NULL : &addr,
|
||||
!addr ? NULL : &addr, align,
|
||||
memory_region_size(mr), &local_err);
|
||||
if (local_err) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (pc_existing_dimms_capacity(OBJECT(machine), &existing_dimms_capacity)) {
|
||||
error_setg(&local_err, "failed to get total size of existing DIMMs");
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (existing_dimms_capacity + memory_region_size(mr) >
|
||||
machine->maxram_size - machine->ram_size) {
|
||||
error_setg(&local_err, "not enough space, currently 0x%" PRIx64
|
||||
" in use of total 0x" RAM_ADDR_FMT,
|
||||
existing_dimms_capacity, machine->maxram_size);
|
||||
goto out;
|
||||
}
|
||||
|
||||
object_property_set_int(OBJECT(dev), addr, PC_DIMM_ADDR_PROP, &local_err);
|
||||
if (local_err) {
|
||||
goto out;
|
||||
@@ -1598,6 +1654,11 @@ static void pc_dimm_plug(HotplugHandler *hotplug_dev,
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (kvm_enabled() && !kvm_has_free_slot(machine)) {
|
||||
error_setg(&local_err, "hypervisor has no free memory slots left");
|
||||
goto out;
|
||||
}
|
||||
|
||||
memory_region_add_subregion(&pcms->hotplug_memory,
|
||||
addr - pcms->hotplug_memory_base, mr);
|
||||
vmstate_register_ram(mr, dev);
|
||||
@@ -1725,6 +1786,13 @@ static void pc_machine_set_vmport(Object *obj, bool value, Error **errp)
|
||||
pcms->vmport = value;
|
||||
}
|
||||
|
||||
static bool pc_machine_get_aligned_dimm(Object *obj, Error **errp)
|
||||
{
|
||||
PCMachineState *pcms = PC_MACHINE(obj);
|
||||
|
||||
return pcms->enforce_aligned_dimm;
|
||||
}
|
||||
|
||||
static void pc_machine_initfn(Object *obj)
|
||||
{
|
||||
PCMachineState *pcms = PC_MACHINE(obj);
|
||||
@@ -1737,11 +1805,17 @@ static void pc_machine_initfn(Object *obj)
|
||||
pc_machine_get_max_ram_below_4g,
|
||||
pc_machine_set_max_ram_below_4g,
|
||||
NULL, NULL, NULL);
|
||||
|
||||
pcms->vmport = !xen_enabled();
|
||||
object_property_add_bool(obj, PC_MACHINE_VMPORT,
|
||||
pc_machine_get_vmport,
|
||||
pc_machine_set_vmport,
|
||||
NULL);
|
||||
|
||||
pcms->enforce_aligned_dimm = true;
|
||||
object_property_add_bool(obj, PC_MACHINE_ENFORCE_ALIGNED_DIMM,
|
||||
pc_machine_get_aligned_dimm,
|
||||
NULL, NULL);
|
||||
}
|
||||
|
||||
static void pc_machine_class_init(ObjectClass *oc, void *data)
|
||||
|
||||
@@ -305,10 +305,12 @@ static void pc_init_pci(MachineState *machine)
|
||||
|
||||
static void pc_compat_2_1(MachineState *machine)
|
||||
{
|
||||
PCMachineState *pcms = PC_MACHINE(machine);
|
||||
smbios_uuid_encoded = false;
|
||||
x86_cpu_compat_set_features("coreduo", FEAT_1_ECX, CPUID_EXT_VMX, 0);
|
||||
x86_cpu_compat_set_features("core2duo", FEAT_1_ECX, CPUID_EXT_VMX, 0);
|
||||
x86_cpu_compat_kvm_no_autodisable(FEAT_8000_0001_ECX, CPUID_EXT3_SVM);
|
||||
pcms->enforce_aligned_dimm = false;
|
||||
}
|
||||
|
||||
static void pc_compat_2_0(MachineState *machine)
|
||||
|
||||
@@ -284,6 +284,9 @@ static void pc_q35_init(MachineState *machine)
|
||||
|
||||
static void pc_compat_2_1(MachineState *machine)
|
||||
{
|
||||
PCMachineState *pcms = PC_MACHINE(machine);
|
||||
|
||||
pcms->enforce_aligned_dimm = false;
|
||||
smbios_uuid_encoded = false;
|
||||
x86_cpu_compat_set_features("coreduo", FEAT_1_ECX, CPUID_EXT_VMX, 0);
|
||||
x86_cpu_compat_set_features("core2duo", FEAT_1_ECX, CPUID_EXT_VMX, 0);
|
||||
|
||||
@@ -405,13 +405,12 @@ DefinitionBlock (
|
||||
#include "hw/acpi/pc-hotplug.h"
|
||||
#define CPU_STATUS_BASE ICH9_CPU_HOTPLUG_IO_BASE
|
||||
#include "acpi-dsdt-cpu-hotplug.dsl"
|
||||
#include "acpi-dsdt-mem-hotplug.dsl"
|
||||
|
||||
|
||||
/****************************************************************
|
||||
* General purpose events
|
||||
****************************************************************/
|
||||
External(\_SB.PCI0.MEMORY_HOTPLUG_DEVICE.MEMORY_SLOT_SCAN_METHOD, MethodObj)
|
||||
|
||||
Scope(\_GPE) {
|
||||
Name(_HID, "ACPI0006")
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -11,7 +11,7 @@ static unsigned char ssdm_mem_aml[] = {
|
||||
0x0,
|
||||
0x0,
|
||||
0x2,
|
||||
0x71,
|
||||
0x66,
|
||||
0x42,
|
||||
0x58,
|
||||
0x50,
|
||||
@@ -34,9 +34,9 @@ static unsigned char ssdm_mem_aml[] = {
|
||||
0x4e,
|
||||
0x54,
|
||||
0x4c,
|
||||
0x15,
|
||||
0x11,
|
||||
0x13,
|
||||
0x28,
|
||||
0x8,
|
||||
0x14,
|
||||
0x20,
|
||||
0x10,
|
||||
0x42,
|
||||
|
||||
+2
-163
@@ -36,6 +36,8 @@ DefinitionBlock ("ssdt-misc.aml", "SSDT", 0x01, "BXPC", "BXSSDTSUSP", 0x1)
|
||||
Name(P1E, Buffer() { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 })
|
||||
ACPI_EXTRACT_NAME_BUFFER8 acpi_pci64_length
|
||||
Name(P1L, Buffer() { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 })
|
||||
ACPI_EXTRACT_NAME_DWORD_CONST ssdt_mctrl_nr_slots
|
||||
Name(MEMORY_SLOTS_NUMBER, 0x12345678)
|
||||
}
|
||||
|
||||
|
||||
@@ -117,167 +119,4 @@ DefinitionBlock ("ssdt-misc.aml", "SSDT", 0x01, "BXPC", "BXSSDTSUSP", 0x1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
External(MEMORY_SLOT_NOTIFY_METHOD, MethodObj)
|
||||
Scope(\_SB.PCI0) {
|
||||
Device(MEMORY_HOTPLUG_DEVICE) {
|
||||
Name(_HID, "PNP0A06")
|
||||
Name(_UID, "Memory hotplug resources")
|
||||
|
||||
ACPI_EXTRACT_NAME_DWORD_CONST ssdt_mctrl_nr_slots
|
||||
Name(MEMORY_SLOTS_NUMBER, 0x12345678)
|
||||
|
||||
/* Memory hotplug IO registers */
|
||||
OperationRegion(MEMORY_HOTPLUG_IO_REGION, SystemIO,
|
||||
ACPI_MEMORY_HOTPLUG_BASE,
|
||||
ACPI_MEMORY_HOTPLUG_IO_LEN)
|
||||
|
||||
Name(_CRS, ResourceTemplate() {
|
||||
IO(Decode16, ACPI_MEMORY_HOTPLUG_BASE, ACPI_MEMORY_HOTPLUG_BASE,
|
||||
0, ACPI_MEMORY_HOTPLUG_IO_LEN, IO)
|
||||
})
|
||||
|
||||
Method(_STA, 0) {
|
||||
If (LEqual(MEMORY_SLOTS_NUMBER, Zero)) {
|
||||
Return(0x0)
|
||||
}
|
||||
/* present, functioning, decoding, not shown in UI */
|
||||
Return(0xB)
|
||||
}
|
||||
|
||||
Field(MEMORY_HOTPLUG_IO_REGION, DWordAcc, NoLock, Preserve) {
|
||||
MEMORY_SLOT_ADDR_LOW, 32, // read only
|
||||
MEMORY_SLOT_ADDR_HIGH, 32, // read only
|
||||
MEMORY_SLOT_SIZE_LOW, 32, // read only
|
||||
MEMORY_SLOT_SIZE_HIGH, 32, // read only
|
||||
MEMORY_SLOT_PROXIMITY, 32, // read only
|
||||
}
|
||||
Field(MEMORY_HOTPLUG_IO_REGION, ByteAcc, NoLock, Preserve) {
|
||||
Offset(20),
|
||||
MEMORY_SLOT_ENABLED, 1, // 1 if enabled, read only
|
||||
MEMORY_SLOT_INSERT_EVENT, 1, // (read) 1 if has a insert event. (write) 1 to clear event
|
||||
}
|
||||
|
||||
Mutex (MEMORY_SLOT_LOCK, 0)
|
||||
Field (MEMORY_HOTPLUG_IO_REGION, DWordAcc, NoLock, Preserve) {
|
||||
MEMORY_SLOT_SLECTOR, 32, // DIMM selector, write only
|
||||
MEMORY_SLOT_OST_EVENT, 32, // _OST event code, write only
|
||||
MEMORY_SLOT_OST_STATUS, 32, // _OST status code, write only
|
||||
}
|
||||
|
||||
Method(MEMORY_SLOT_SCAN_METHOD, 0) {
|
||||
If (LEqual(MEMORY_SLOTS_NUMBER, Zero)) {
|
||||
Return(Zero)
|
||||
}
|
||||
|
||||
Store(Zero, Local0) // Mem devs iterrator
|
||||
Acquire(MEMORY_SLOT_LOCK, 0xFFFF)
|
||||
while (LLess(Local0, MEMORY_SLOTS_NUMBER)) {
|
||||
Store(Local0, MEMORY_SLOT_SLECTOR) // select Local0 DIMM
|
||||
If (LEqual(MEMORY_SLOT_INSERT_EVENT, One)) { // Memory device needs check
|
||||
MEMORY_SLOT_NOTIFY_METHOD(Local0, 1)
|
||||
Store(1, MEMORY_SLOT_INSERT_EVENT)
|
||||
}
|
||||
// TODO: handle memory eject request
|
||||
Add(Local0, One, Local0) // goto next DIMM
|
||||
}
|
||||
Release(MEMORY_SLOT_LOCK)
|
||||
Return(One)
|
||||
}
|
||||
|
||||
Method(MEMORY_SLOT_STATUS_METHOD, 1) {
|
||||
Store(Zero, Local0)
|
||||
|
||||
Acquire(MEMORY_SLOT_LOCK, 0xFFFF)
|
||||
Store(ToInteger(Arg0), MEMORY_SLOT_SLECTOR) // select DIMM
|
||||
|
||||
If (LEqual(MEMORY_SLOT_ENABLED, One)) {
|
||||
Store(0xF, Local0)
|
||||
}
|
||||
|
||||
Release(MEMORY_SLOT_LOCK)
|
||||
Return(Local0)
|
||||
}
|
||||
|
||||
Method(MEMORY_SLOT_CRS_METHOD, 1, Serialized) {
|
||||
Acquire(MEMORY_SLOT_LOCK, 0xFFFF)
|
||||
Store(ToInteger(Arg0), MEMORY_SLOT_SLECTOR) // 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(MEMORY_SLOT_ADDR_HIGH, MINH)
|
||||
Store(MEMORY_SLOT_ADDR_LOW, MINL)
|
||||
Store(MEMORY_SLOT_SIZE_HIGH, LENH)
|
||||
Store(MEMORY_SLOT_SIZE_LOW, LENL)
|
||||
|
||||
// 64-bit math: MAX = MIN + LEN - 1
|
||||
Add(MINL, LENL, MAXL)
|
||||
Add(MINH, LENH, MAXH)
|
||||
If (LLess(MAXL, MINL)) {
|
||||
Add(MAXH, One, MAXH)
|
||||
}
|
||||
If (LLess(MAXL, One)) {
|
||||
Subtract(MAXH, One, MAXH)
|
||||
}
|
||||
Subtract(MAXL, One, MAXL)
|
||||
|
||||
If (LEqual(MAXH, Zero)){
|
||||
Name(MR32, ResourceTemplate() {
|
||||
DWordMemory(ResourceProducer, PosDecode, MinFixed, MaxFixed,
|
||||
Cacheable, ReadWrite,
|
||||
0x00000000, // Address Space Granularity
|
||||
0x00000000, // Address Range Minimum
|
||||
0xFFFFFFFE, // Address Range Maximum
|
||||
0x00000000, // Address Translation Offset
|
||||
0xFFFFFFFF, // Address Length
|
||||
,, MW32, AddressRangeMemory, TypeStatic)
|
||||
})
|
||||
CreateDWordField(MR32, MW32._MIN, MIN)
|
||||
CreateDWordField(MR32, MW32._MAX, MAX)
|
||||
CreateDWordField(MR32, MW32._LEN, LEN)
|
||||
Store(MINL, MIN)
|
||||
Store(MAXL, MAX)
|
||||
Store(LENL, LEN)
|
||||
|
||||
Release(MEMORY_SLOT_LOCK)
|
||||
Return(MR32)
|
||||
}
|
||||
|
||||
Release(MEMORY_SLOT_LOCK)
|
||||
Return(MR64)
|
||||
}
|
||||
|
||||
Method(MEMORY_SLOT_PROXIMITY_METHOD, 1) {
|
||||
Acquire(MEMORY_SLOT_LOCK, 0xFFFF)
|
||||
Store(ToInteger(Arg0), MEMORY_SLOT_SLECTOR) // select DIMM
|
||||
Store(MEMORY_SLOT_PROXIMITY, Local0)
|
||||
Release(MEMORY_SLOT_LOCK)
|
||||
Return(Local0)
|
||||
}
|
||||
|
||||
Method(MEMORY_SLOT_OST_METHOD, 4) {
|
||||
Acquire(MEMORY_SLOT_LOCK, 0xFFFF)
|
||||
Store(ToInteger(Arg0), MEMORY_SLOT_SLECTOR) // select DIMM
|
||||
Store(Arg1, MEMORY_SLOT_OST_EVENT)
|
||||
Store(Arg2, MEMORY_SLOT_OST_STATUS)
|
||||
Release(MEMORY_SLOT_LOCK)
|
||||
}
|
||||
} // Device()
|
||||
} // Scope()
|
||||
}
|
||||
|
||||
+24
-810
File diff suppressed because it is too large
Load Diff
+17
-2
@@ -139,19 +139,34 @@ static int pc_dimm_built_list(Object *obj, void *opaque)
|
||||
|
||||
uint64_t pc_dimm_get_free_addr(uint64_t address_space_start,
|
||||
uint64_t address_space_size,
|
||||
uint64_t *hint, uint64_t size,
|
||||
uint64_t *hint, uint64_t align, uint64_t size,
|
||||
Error **errp)
|
||||
{
|
||||
GSList *list = NULL, *item;
|
||||
uint64_t new_addr, ret = 0;
|
||||
uint64_t address_space_end = address_space_start + address_space_size;
|
||||
|
||||
g_assert(QEMU_ALIGN_UP(address_space_start, align) == address_space_start);
|
||||
g_assert(QEMU_ALIGN_UP(address_space_size, align) == address_space_size);
|
||||
|
||||
if (!address_space_size) {
|
||||
error_setg(errp, "memory hotplug is not enabled, "
|
||||
"please add maxmem option");
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (hint && QEMU_ALIGN_UP(*hint, align) != *hint) {
|
||||
error_setg(errp, "address must be aligned to 0x%" PRIx64 " bytes",
|
||||
align);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (QEMU_ALIGN_UP(size, align) != size) {
|
||||
error_setg(errp, "backend memory size must be multiple of 0x%"
|
||||
PRIx64, align);
|
||||
goto out;
|
||||
}
|
||||
|
||||
assert(address_space_end > address_space_start);
|
||||
object_child_foreach(qdev_get_machine(), pc_dimm_built_list, &list);
|
||||
|
||||
@@ -177,7 +192,7 @@ uint64_t pc_dimm_get_free_addr(uint64_t address_space_start,
|
||||
error_setg(errp, "address range conflicts with '%s'", d->id);
|
||||
goto out;
|
||||
}
|
||||
new_addr = dimm->addr + dimm_size;
|
||||
new_addr = QEMU_ALIGN_UP(dimm->addr + dimm_size, align);
|
||||
}
|
||||
}
|
||||
ret = new_addr;
|
||||
|
||||
+2
-2
@@ -145,7 +145,7 @@ void pcie_cap_deverr_init(PCIDevice *dev)
|
||||
PCI_EXP_DEVCTL_FERE | PCI_EXP_DEVCTL_URRE);
|
||||
pci_long_test_and_set_mask(dev->w1cmask + pos + PCI_EXP_DEVSTA,
|
||||
PCI_EXP_DEVSTA_CED | PCI_EXP_DEVSTA_NFED |
|
||||
PCI_EXP_DEVSTA_URD | PCI_EXP_DEVSTA_URD);
|
||||
PCI_EXP_DEVSTA_FED | PCI_EXP_DEVSTA_URD);
|
||||
}
|
||||
|
||||
void pcie_cap_deverr_reset(PCIDevice *dev)
|
||||
@@ -229,7 +229,7 @@ static void pcie_cap_slot_hotplug_common(PCIDevice *hotplug_dev,
|
||||
/* the slot is electromechanically locked.
|
||||
* This error is propagated up to qdev and then to HMP/QMP.
|
||||
*/
|
||||
error_setg_errno(errp, -EBUSY, "slot is electromechanically locked");
|
||||
error_setg_errno(errp, EBUSY, "slot is electromechanically locked");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -663,6 +663,7 @@ void shpc_cleanup(PCIDevice *d, MemoryRegion *bar)
|
||||
SHPCDevice *shpc = d->shpc;
|
||||
d->cap_present &= ~QEMU_PCI_CAP_SHPC;
|
||||
memory_region_del_subregion(bar, &shpc->mmio);
|
||||
object_unparent(OBJECT(&shpc->mmio));
|
||||
/* TODO: cleanup config space changes? */
|
||||
g_free(shpc->config);
|
||||
g_free(shpc->cmask);
|
||||
|
||||
@@ -333,7 +333,7 @@ extern uintptr_t tci_tb_ptr;
|
||||
|
||||
#if !defined(CONFIG_USER_ONLY)
|
||||
|
||||
void phys_mem_set_alloc(void *(*alloc)(size_t));
|
||||
void phys_mem_set_alloc(void *(*alloc)(size_t, uint64_t *align));
|
||||
|
||||
struct MemoryRegion *iotlb_to_region(AddressSpace *as, hwaddr index);
|
||||
bool io_mem_read(struct MemoryRegion *mr, hwaddr addr,
|
||||
|
||||
@@ -146,6 +146,7 @@ struct MemoryRegion {
|
||||
hwaddr addr;
|
||||
void (*destructor)(MemoryRegion *mr);
|
||||
ram_addr_t ram_addr;
|
||||
uint64_t align;
|
||||
bool subpage;
|
||||
bool terminates;
|
||||
bool romd_mode;
|
||||
@@ -838,6 +839,7 @@ void memory_region_add_subregion_overlap(MemoryRegion *mr,
|
||||
*/
|
||||
ram_addr_t memory_region_get_ram_addr(MemoryRegion *mr);
|
||||
|
||||
uint64_t memory_region_get_alignment(const MemoryRegion *mr);
|
||||
/**
|
||||
* memory_region_del_subregion: Remove a subregion.
|
||||
*
|
||||
|
||||
@@ -24,6 +24,8 @@
|
||||
* address space begins.
|
||||
* @hotplug_memory: hotplug memory addess space container
|
||||
* @acpi_dev: link to ACPI PM device that performs ACPI hotplug handling
|
||||
* @enforce_aligned_dimm: check that DIMM's address/size is aligned by
|
||||
* backend's alignment value if provided
|
||||
*/
|
||||
struct PCMachineState {
|
||||
/*< private >*/
|
||||
@@ -38,12 +40,14 @@ struct PCMachineState {
|
||||
|
||||
uint64_t max_ram_below_4g;
|
||||
bool vmport;
|
||||
bool enforce_aligned_dimm;
|
||||
};
|
||||
|
||||
#define PC_MACHINE_ACPI_DEVICE_PROP "acpi-device"
|
||||
#define PC_MACHINE_MEMHP_REGION_SIZE "hotplug-memory-region-size"
|
||||
#define PC_MACHINE_MAX_RAM_BELOW_4G "max-ram-below-4g"
|
||||
#define PC_MACHINE_VMPORT "vmport"
|
||||
#define PC_MACHINE_ENFORCE_ALIGNED_DIMM "enforce-aligned-dimm"
|
||||
|
||||
/**
|
||||
* PCMachineClass:
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user