diff --git a/BinDir.tar.gz b/BinDir.tar.gz index 8871e65e7210a81648b066bfb5560c4f6e9a6f0e..3800e9d831a8166f7d9fbffa7f59fffb394dd0e6 100644 Binary files a/BinDir.tar.gz and b/BinDir.tar.gz differ diff --git a/arm64-Add-the-cpufreq-device-to-show-cpufreq-info-to.patch b/arm64-Add-the-cpufreq-device-to-show-cpufreq-info-to.patch new file mode 100644 index 0000000000000000000000000000000000000000..005ac1e8d8ba2b927c4a4e5644d26cb83a3e50d6 --- /dev/null +++ b/arm64-Add-the-cpufreq-device-to-show-cpufreq-info-to.patch @@ -0,0 +1,616 @@ +From e7e28e79988eb671051d0d2af0eb010314c83d41 Mon Sep 17 00:00:00 2001 +From: Ying Fang +Date: Tue, 8 Feb 2022 21:01:09 +0800 +Subject: [PATCH 24/24] arm64: Add the cpufreq device to show cpufreq info to + guest + +On ARM64 platform, cpu frequency is retrieved via ACPI CPPC. +A virtual cpufreq device based on ACPI CPPC is created to +present cpu frequency info to the guest. + +The default frequency is set to host cpu nominal frequency, +which is obtained from the host CPPC sysfs. Other performance +data are set to the same value, since we don't support guest +performance scaling here. + +Performance counters are also not emulated and they simply +return 1 if read, and guest should fallback to use desired +performance value as the current performance. + +Guest kernel version above 4.18 is required to make it work. + +This series is backported from: +https://patchwork.kernel.org/cover/11379943/ + +Signed-off-by: Ying Fang +Signed-off-by: Yanan Wang +--- + configs/devices/aarch64-softmmu/default.mak | 1 + + hw/acpi/aml-build.c | 22 ++ + hw/acpi/cpufreq.c | 283 ++++++++++++++++++++ + hw/acpi/meson.build | 1 + + hw/arm/virt-acpi-build.c | 77 +++++- + hw/arm/virt.c | 13 + + hw/char/Kconfig | 4 + + include/hw/acpi/acpi-defs.h | 38 +++ + include/hw/acpi/aml-build.h | 3 + + include/hw/arm/virt.h | 1 + + tests/data/acpi/virt/DSDT | Bin 5196 -> 5669 bytes + tests/data/acpi/virt/DSDT.memhp | Bin 6557 -> 7030 bytes + tests/data/acpi/virt/DSDT.numamem | Bin 5196 -> 5669 bytes + tests/data/acpi/virt/DSDT.pxb | Bin 7679 -> 8152 bytes + 14 files changed, 441 insertions(+), 2 deletions(-) + create mode 100644 hw/acpi/cpufreq.c + +diff --git a/configs/devices/aarch64-softmmu/default.mak b/configs/devices/aarch64-softmmu/default.mak +index cf43ac8da1..c7a710a0f1 100644 +--- a/configs/devices/aarch64-softmmu/default.mak ++++ b/configs/devices/aarch64-softmmu/default.mak +@@ -6,3 +6,4 @@ include ../arm-softmmu/default.mak + CONFIG_XLNX_ZYNQMP_ARM=y + CONFIG_XLNX_VERSAL=y + CONFIG_SBSA_REF=y ++CONFIG_CPUFREQ=y +diff --git a/hw/acpi/aml-build.c b/hw/acpi/aml-build.c +index bebf49622b..c4edaafa4a 100644 +--- a/hw/acpi/aml-build.c ++++ b/hw/acpi/aml-build.c +@@ -1554,6 +1554,28 @@ Aml *aml_sleep(uint64_t msec) + return var; + } + ++/* ACPI 5.0b: 6.4.3.7 Generic Register Descriptor */ ++Aml *aml_generic_register(AmlRegionSpace rs, uint8_t reg_width, ++ uint8_t reg_offset, AmlAccessType type, uint64_t addr) ++{ ++ int i; ++ Aml *var = aml_alloc(); ++ build_append_byte(var->buf, 0x82); /* Generic Register Descriptor */ ++ build_append_byte(var->buf, 0x0C); /* Length, bits[7:0] value = 0x0C */ ++ build_append_byte(var->buf, 0); /* Length, bits[15:8] value = 0 */ ++ build_append_byte(var->buf, rs); /* Address Space ID */ ++ build_append_byte(var->buf, reg_width); /* Register Bit Width */ ++ build_append_byte(var->buf, reg_offset); /* Register Bit Offset */ ++ build_append_byte(var->buf, type); /* Access Size */ ++ ++ /* Register address */ ++ for (i = 0; i < 8; i++) { ++ build_append_byte(var->buf, extract64(addr, i * 8, 8)); ++ } ++ ++ return var; ++} ++ + static uint8_t Hex2Byte(const char *src) + { + int hi, lo; +diff --git a/hw/acpi/cpufreq.c b/hw/acpi/cpufreq.c +new file mode 100644 +index 0000000000..a84db490b3 +--- /dev/null ++++ b/hw/acpi/cpufreq.c +@@ -0,0 +1,283 @@ ++/* ++ * ACPI CPPC register device ++ * ++ * Support for showing CPU frequency in guest OS. ++ * ++ * Copyright (c) 2019 HUAWEI TECHNOLOGIES CO.,LTD. ++ * ++ * 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 . ++ */ ++ ++#include "qemu/osdep.h" ++#include "hw/sysbus.h" ++#include "chardev/char.h" ++#include "qemu/log.h" ++#include "trace.h" ++#include "qemu/option.h" ++#include "sysemu/sysemu.h" ++#include "hw/acpi/acpi-defs.h" ++#include "qemu/cutils.h" ++#include "qemu/error-report.h" ++#include "hw/boards.h" ++ ++#define TYPE_CPUFREQ "cpufreq" ++#define CPUFREQ(obj) OBJECT_CHECK(CpuhzState, (obj), TYPE_CPUFREQ) ++#define NOMINAL_FREQ_FILE "/sys/devices/system/cpu/cpu0/acpi_cppc/nominal_freq" ++#define CPU_MAX_FREQ_FILE "/sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_max_freq" ++#define HZ_MAX_LENGTH 1024 ++#define MAX_SUPPORT_SPACE 0x10000 ++ ++/* ++ * Since Hi1616 will not support CPPC, we simply use its nominal frequency as ++ * the default. ++ */ ++#define DEFAULT_HZ 2400 ++ ++int cppc_regs_offset[CPPC_REG_COUNT] = { ++ [HIGHEST_PERF] = 0, ++ [NOMINAL_PERF] = 4, ++ [LOW_NON_LINEAR_PERF] = 8, ++ [LOWEST_PERF] = 12, ++ [GUARANTEED_PERF] = 16, ++ [DESIRED_PERF] = 20, ++ [MIN_PERF] = -1, ++ [MAX_PERF] = -1, ++ [PERF_REDUC_TOLERANCE] = -1, ++ [TIME_WINDOW] = -1, ++ [CTR_WRAP_TIME] = -1, ++ [REFERENCE_CTR] = 24, ++ [DELIVERED_CTR] = 32, ++ [PERF_LIMITED] = 40, ++ [ENABLE] = -1, ++ [AUTO_SEL_ENABLE] = -1, ++ [AUTO_ACT_WINDOW] = -1, ++ [ENERGY_PERF] = -1, ++ [REFERENCE_PERF] = -1, ++ [LOWEST_FREQ] = 44, ++ [NOMINAL_FREQ] = 48, ++}; ++ ++typedef struct CpuhzState { ++ SysBusDevice parent_obj; ++ ++ MemoryRegion iomem; ++ uint32_t HighestPerformance; ++ uint32_t NominalPerformance; ++ uint32_t LowestNonlinearPerformance; ++ uint32_t LowestPerformance; ++ uint32_t GuaranteedPerformance; ++ uint32_t DesiredPerformance; ++ uint64_t ReferencePerformanceCounter; ++ uint64_t DeliveredPerformanceCounter; ++ uint32_t PerformanceLimited; ++ uint32_t LowestFreq; ++ uint32_t NominalFreq; ++ uint32_t reg_size; ++} CpuhzState; ++ ++ ++static uint64_t cpufreq_read(void *opaque, hwaddr offset, unsigned size) ++{ ++ CpuhzState *s = (CpuhzState *)opaque; ++ uint64_t r; ++ uint64_t n; ++ ++ MachineState *ms = MACHINE(qdev_get_machine()); ++ unsigned int smp_cpus = ms->smp.cpus; ++ ++ if (offset >= smp_cpus * CPPC_REG_PER_CPU_STRIDE) { ++ warn_report("cpufreq_read: offset 0x%lx out of range", offset); ++ return 0; ++ } ++ ++ n = offset % CPPC_REG_PER_CPU_STRIDE; ++ switch (n) { ++ case 0: ++ r = s->HighestPerformance; ++ break; ++ case 4: ++ r = s->NominalPerformance; ++ break; ++ case 8: ++ r = s->LowestNonlinearPerformance; ++ break; ++ case 12: ++ r = s->LowestPerformance; ++ break; ++ case 16: ++ r = s->GuaranteedPerformance; ++ break; ++ case 20: ++ r = s->DesiredPerformance; ++ break; ++ /* ++ * We don't have real counters and it is hard to emulate, so always set the ++ * counter value to 1 to rely on Linux to use the DesiredPerformance value ++ * directly. ++ */ ++ case 24: ++ r = s->ReferencePerformanceCounter; ++ break; ++ /* ++ * Guest may still access the register by 32bit; add the process to ++ * eliminate unnecessary warnings. ++ */ ++ case 28: ++ r = s->ReferencePerformanceCounter >> 32; ++ break; ++ case 32: ++ r = s->DeliveredPerformanceCounter; ++ break; ++ case 36: ++ r = s->DeliveredPerformanceCounter >> 32; ++ break; ++ ++ case 40: ++ r = s->PerformanceLimited; ++ break; ++ case 44: ++ r = s->LowestFreq; ++ break; ++ case 48: ++ r = s->NominalFreq; ++ break; ++ default: ++ error_printf("cpufreq_read: Bad offset 0x%lx\n", offset); ++ r = 0; ++ break; ++ } ++ return r; ++} ++ ++static void cpufreq_write(void *opaque, hwaddr offset, ++ uint64_t value, unsigned size) ++{ ++ uint64_t n; ++ MachineState *ms = MACHINE(qdev_get_machine()); ++ unsigned int smp_cpus = ms->smp.cpus; ++ ++ if (offset >= smp_cpus * CPPC_REG_PER_CPU_STRIDE) { ++ error_printf("cpufreq_write: offset 0x%lx out of range", offset); ++ return; ++ } ++ ++ n = offset % CPPC_REG_PER_CPU_STRIDE; ++ ++ switch (n) { ++ case 20: ++ break; ++ default: ++ error_printf("cpufreq_write: Bad offset 0x%lx\n", offset); ++ } ++} ++ ++static uint32_t CPPC_Read(const char *hostpath) ++{ ++ int fd; ++ char buffer[HZ_MAX_LENGTH] = { 0 }; ++ uint64_t hz; ++ int len; ++ const char *endptr = NULL; ++ int ret; ++ ++ fd = qemu_open_old(hostpath, O_RDONLY); ++ if (fd < 0) { ++ return 0; ++ } ++ ++ len = read(fd, buffer, HZ_MAX_LENGTH); ++ qemu_close(fd); ++ if (len <= 0) { ++ return 0; ++ } ++ ret = qemu_strtoul(buffer, &endptr, 0, &hz); ++ if (ret < 0) { ++ return 0; ++ } ++ return (uint32_t)hz; ++} ++ ++static const MemoryRegionOps cpufreq_ops = { ++ .read = cpufreq_read, ++ .write = cpufreq_write, ++ .endianness = DEVICE_NATIVE_ENDIAN, ++}; ++ ++static void hz_init(CpuhzState *s) ++{ ++ uint32_t hz; ++ ++ hz = CPPC_Read(NOMINAL_FREQ_FILE); ++ if (hz == 0) { ++ hz = CPPC_Read(CPU_MAX_FREQ_FILE); ++ if (hz == 0) { ++ hz = DEFAULT_HZ; ++ } else { ++ /* Value in CpuMaxFrequency is in KHz unit; convert to MHz */ ++ hz = hz / 1000; ++ } ++ } ++ ++ s->HighestPerformance = hz; ++ s->NominalPerformance = hz; ++ s->LowestNonlinearPerformance = hz; ++ s->LowestPerformance = hz; ++ s->GuaranteedPerformance = hz; ++ s->DesiredPerformance = hz; ++ s->ReferencePerformanceCounter = 1; ++ s->DeliveredPerformanceCounter = 1; ++ s->PerformanceLimited = 0; ++ s->LowestFreq = hz; ++ s->NominalFreq = hz; ++} ++ ++static void cpufreq_init(Object *obj) ++{ ++ SysBusDevice *sbd = SYS_BUS_DEVICE(obj); ++ CpuhzState *s = CPUFREQ(obj); ++ ++ MachineState *ms = MACHINE(qdev_get_machine()); ++ unsigned int smp_cpus = ms->smp.cpus; ++ ++ s->reg_size = smp_cpus * CPPC_REG_PER_CPU_STRIDE; ++ if (s->reg_size > MAX_SUPPORT_SPACE) { ++ error_report("Required space 0x%x excesses the max support 0x%x", ++ s->reg_size, MAX_SUPPORT_SPACE); ++ goto err_end; ++ } ++ ++ memory_region_init_io(&s->iomem, OBJECT(s), &cpufreq_ops, s, "cpufreq", ++ s->reg_size); ++ sysbus_init_mmio(sbd, &s->iomem); ++ hz_init(s); ++ return; ++ ++err_end: ++ /* Set desired perf register offset to -1 to indicate no support for CPPC */ ++ cppc_regs_offset[DESIRED_PERF] = -1; ++} ++ ++static const TypeInfo cpufreq_arm_info = { ++ .name = TYPE_CPUFREQ, ++ .parent = TYPE_SYS_BUS_DEVICE, ++ .instance_size = sizeof(CpuhzState), ++ .instance_init = cpufreq_init, ++}; ++ ++static void cpufreq_register_types(void) ++{ ++ type_register_static(&cpufreq_arm_info); ++} ++ ++type_init(cpufreq_register_types) +diff --git a/hw/acpi/meson.build b/hw/acpi/meson.build +index adf6347bc4..448ea6afb4 100644 +--- a/hw/acpi/meson.build ++++ b/hw/acpi/meson.build +@@ -25,6 +25,7 @@ acpi_ss.add(when: 'CONFIG_ACPI_X86_ICH', if_true: files('ich9.c', 'tco.c')) + acpi_ss.add(when: 'CONFIG_IPMI', if_true: files('ipmi.c'), if_false: files('ipmi-stub.c')) + acpi_ss.add(when: 'CONFIG_PC', if_false: files('acpi-x86-stub.c')) + acpi_ss.add(when: 'CONFIG_TPM', if_true: files('tpm.c')) ++acpi_ss.add(when: 'CONFIG_CPUFREQ', if_true: files('cpufreq.c')) + softmmu_ss.add(when: 'CONFIG_ACPI', if_false: files('acpi-stub.c', 'aml-build-stub.c', 'ghes-stub.c')) + softmmu_ss.add_all(when: 'CONFIG_ACPI', if_true: acpi_ss) + softmmu_ss.add(when: 'CONFIG_ALL', if_true: files('acpi-stub.c', 'aml-build-stub.c', +diff --git a/hw/arm/virt-acpi-build.c b/hw/arm/virt-acpi-build.c +index 674f902652..1ca705654b 100644 +--- a/hw/arm/virt-acpi-build.c ++++ b/hw/arm/virt-acpi-build.c +@@ -60,7 +60,68 @@ + + #define ACPI_BUILD_TABLE_SIZE 0x20000 + +-static void acpi_dsdt_add_cpus(Aml *scope, VirtMachineState *vms) ++static void acpi_dsdt_add_psd(Aml *dev, int cpus) ++{ ++ Aml *pkg; ++ Aml *sub; ++ ++ sub = aml_package(5); ++ aml_append(sub, aml_int(5)); ++ aml_append(sub, aml_int(0)); ++ /* Assume all vCPUs belong to the same domain */ ++ aml_append(sub, aml_int(0)); ++ /* SW_ANY: OSPM coordinate, initiate on any processor */ ++ aml_append(sub, aml_int(0xFD)); ++ aml_append(sub, aml_int(cpus)); ++ ++ pkg = aml_package(1); ++ aml_append(pkg, sub); ++ ++ aml_append(dev, aml_name_decl("_PSD", pkg)); ++} ++ ++static void acpi_dsdt_add_cppc(Aml *dev, uint64_t cpu_base, int *regs_offset) ++{ ++ Aml *cpc; ++ int i; ++ ++ /* Use version 3 of CPPC table from ACPI 6.3 */ ++ cpc = aml_package(23); ++ aml_append(cpc, aml_int(23)); ++ aml_append(cpc, aml_int(3)); ++ ++ for (i = 0; i < CPPC_REG_COUNT; i++) { ++ Aml *res; ++ uint8_t reg_width; ++ uint8_t acc_type; ++ uint64_t addr; ++ ++ if (regs_offset[i] == -1) { ++ reg_width = 0; ++ acc_type = AML_ANY_ACC; ++ addr = 0; ++ } else { ++ addr = cpu_base + regs_offset[i]; ++ if (i == REFERENCE_CTR || i == DELIVERED_CTR) { ++ reg_width = 64; ++ acc_type = AML_QWORD_ACC; ++ } else { ++ reg_width = 32; ++ acc_type = AML_DWORD_ACC; ++ } ++ } ++ ++ res = aml_resource_template(); ++ aml_append(res, aml_generic_register(AML_SYSTEM_MEMORY, reg_width, 0, ++ acc_type, addr)); ++ aml_append(cpc, res); ++ } ++ ++ aml_append(dev, aml_name_decl("_CPC", cpc)); ++} ++ ++static void acpi_dsdt_add_cpus(Aml *scope, VirtMachineState *vms, ++ const MemMapEntry *cppc_memmap) + { + MachineState *ms = MACHINE(vms); + uint16_t i; +@@ -69,6 +130,18 @@ static void acpi_dsdt_add_cpus(Aml *scope, VirtMachineState *vms) + Aml *dev = aml_device("C%.03X", i); + aml_append(dev, aml_name_decl("_HID", aml_string("ACPI0007"))); + aml_append(dev, aml_name_decl("_UID", aml_int(i))); ++ ++ /* ++ * Append _CPC and _PSD to support CPU frequence show ++ * Check CPPC available by DESIRED_PERF register ++ */ ++ if (cppc_regs_offset[DESIRED_PERF] != -1) { ++ acpi_dsdt_add_cppc(dev, ++ cppc_memmap->base + i * CPPC_REG_PER_CPU_STRIDE, ++ cppc_regs_offset); ++ acpi_dsdt_add_psd(dev, ms->smp.cpus); ++ } ++ + aml_append(scope, dev); + } + } +@@ -858,7 +931,7 @@ build_dsdt(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms) + * the RTC ACPI device at all when using UEFI. + */ + scope = aml_scope("\\_SB"); +- acpi_dsdt_add_cpus(scope, vms); ++ acpi_dsdt_add_cpus(scope, vms, &memmap[VIRT_CPUFREQ]); + acpi_dsdt_add_uart(scope, &memmap[VIRT_UART], + (irqmap[VIRT_UART] + ARM_SPI_BASE)); + if (vmc->acpi_expose_flash) { +diff --git a/hw/arm/virt.c b/hw/arm/virt.c +index 529c0d38b6..0538d258fa 100644 +--- a/hw/arm/virt.c ++++ b/hw/arm/virt.c +@@ -154,6 +154,7 @@ static const MemMapEntry base_memmap[] = { + [VIRT_PVTIME] = { 0x090a0000, 0x00010000 }, + [VIRT_SECURE_GPIO] = { 0x090b0000, 0x00001000 }, + [VIRT_MMIO] = { 0x0a000000, 0x00000200 }, ++ [VIRT_CPUFREQ] = { 0x0b000000, 0x00010000 }, + /* ...repeating for a total of NUM_VIRTIO_TRANSPORTS, each of that size */ + [VIRT_PLATFORM_BUS] = { 0x0c000000, 0x02000000 }, + [VIRT_SECURE_MEM] = { 0x0e000000, 0x01000000 }, +@@ -931,6 +932,16 @@ static void create_uart(const VirtMachineState *vms, int uart, + g_free(nodename); + } + ++static void create_cpufreq(const VirtMachineState *vms, MemoryRegion *mem) ++{ ++ hwaddr base = vms->memmap[VIRT_CPUFREQ].base; ++ DeviceState *dev = qdev_new("cpufreq"); ++ SysBusDevice *s = SYS_BUS_DEVICE(dev); ++ ++ sysbus_realize_and_unref(s, &error_fatal); ++ memory_region_add_subregion(mem, base, sysbus_mmio_get_region(s, 0)); ++} ++ + static void create_rtc(const VirtMachineState *vms) + { + char *nodename; +@@ -2190,6 +2201,8 @@ static void machvirt_init(MachineState *machine) + + create_uart(vms, VIRT_UART, sysmem, serial_hd(0)); + ++ create_cpufreq(vms, sysmem); ++ + if (vms->secure) { + create_secure_ram(vms, secure_sysmem, secure_tag_sysmem); + create_uart(vms, VIRT_SECURE_UART, secure_sysmem, serial_hd(1)); +diff --git a/hw/char/Kconfig b/hw/char/Kconfig +index 6b6cf2fc1d..335a60c2c1 100644 +--- a/hw/char/Kconfig ++++ b/hw/char/Kconfig +@@ -71,3 +71,7 @@ config GOLDFISH_TTY + + config SHAKTI_UART + bool ++ ++config CPUFREQ ++ bool ++ default y +diff --git a/include/hw/acpi/acpi-defs.h b/include/hw/acpi/acpi-defs.h +index c97e8633ad..ab86583228 100644 +--- a/include/hw/acpi/acpi-defs.h ++++ b/include/hw/acpi/acpi-defs.h +@@ -92,4 +92,42 @@ typedef struct AcpiFadtData { + #define ACPI_FADT_ARM_PSCI_COMPLIANT (1 << 0) + #define ACPI_FADT_ARM_PSCI_USE_HVC (1 << 1) + ++/* ++ * CPPC register definition from kernel header ++ * include/acpi/cppc_acpi.h ++ * The last element is newly added for easy use ++ */ ++enum cppc_regs { ++ HIGHEST_PERF, ++ NOMINAL_PERF, ++ LOW_NON_LINEAR_PERF, ++ LOWEST_PERF, ++ GUARANTEED_PERF, ++ DESIRED_PERF, ++ MIN_PERF, ++ MAX_PERF, ++ PERF_REDUC_TOLERANCE, ++ TIME_WINDOW, ++ CTR_WRAP_TIME, ++ REFERENCE_CTR, ++ DELIVERED_CTR, ++ PERF_LIMITED, ++ ENABLE, ++ AUTO_SEL_ENABLE, ++ AUTO_ACT_WINDOW, ++ ENERGY_PERF, ++ REFERENCE_PERF, ++ LOWEST_FREQ, ++ NOMINAL_FREQ, ++ CPPC_REG_COUNT, ++}; ++ ++#define CPPC_REG_PER_CPU_STRIDE 0x40 ++ ++/* ++ * Offset for each CPPC register; -1 for unavailable ++ * The whole register space is unavailable if desired perf offset is -1. ++ */ ++extern int cppc_regs_offset[CPPC_REG_COUNT]; ++ + #endif +diff --git a/include/hw/acpi/aml-build.h b/include/hw/acpi/aml-build.h +index 8e8ad8029e..2e00d2e208 100644 +--- a/include/hw/acpi/aml-build.h ++++ b/include/hw/acpi/aml-build.h +@@ -429,6 +429,9 @@ Aml *aml_dma(AmlDmaType typ, AmlDmaBusMaster bm, AmlTransferSize sz, + uint8_t channel); + Aml *aml_sleep(uint64_t msec); + Aml *aml_i2c_serial_bus_device(uint16_t address, const char *resource_source); ++Aml *aml_generic_register(AmlRegionSpace rs, uint8_t reg_width, ++ uint8_t reg_offset, AmlAccessType type, ++ uint64_t addr); + + /* Block AML object primitives */ + Aml *aml_scope(const char *name_format, ...) GCC_FMT_ATTR(1, 2); +diff --git a/include/hw/arm/virt.h b/include/hw/arm/virt.h +index dc6b66ffc8..a4356cf736 100644 +--- a/include/hw/arm/virt.h ++++ b/include/hw/arm/virt.h +@@ -70,6 +70,7 @@ enum { + VIRT_GIC_REDIST, + VIRT_SMMU, + VIRT_UART, ++ VIRT_CPUFREQ, + VIRT_MMIO, + VIRT_RTC, + VIRT_FW_CFG, + +-- +2.27.0 + diff --git a/hw-acpi-aml-build-Improve-scalability-of-PPTT-genera.patch b/hw-acpi-aml-build-Improve-scalability-of-PPTT-genera.patch new file mode 100644 index 0000000000000000000000000000000000000000..0525989485e8ce7ea6180b3d8b933ab70dfe74ef --- /dev/null +++ b/hw-acpi-aml-build-Improve-scalability-of-PPTT-genera.patch @@ -0,0 +1,113 @@ +From 66c935b435d90ef9c1ae4446c5edc07cbd8ba0ed Mon Sep 17 00:00:00 2001 +From: Yanan Wang +Date: Fri, 7 Jan 2022 16:32:29 +0800 +Subject: [PATCH 17/24] hw/acpi/aml-build: Improve scalability of PPTT + generation + +Use g_queue APIs to reduce the nested loops and code indentation +with the processor hierarchy levels increasing. Consenquently, +it's more scalable to add new topology level to build_pptt. + +No functional change intended. + +Signed-off-by: Yanan Wang +Reviewed-by: Andrew Jones +Message-id: 20220107083232.16256-4-wangyanan55@huawei.com +Signed-off-by: Peter Maydell +--- + hw/acpi/aml-build.c | 50 +++++++++++++++++++++++++++++---------------- + 1 file changed, 32 insertions(+), 18 deletions(-) + +diff --git a/hw/acpi/aml-build.c b/hw/acpi/aml-build.c +index b3b3310df3..6aaedca2e5 100644 +--- a/hw/acpi/aml-build.c ++++ b/hw/acpi/aml-build.c +@@ -2001,7 +2001,10 @@ static void build_processor_hierarchy_node(GArray *tbl, uint32_t flags, + void build_pptt(GArray *table_data, BIOSLinker *linker, MachineState *ms, + const char *oem_id, const char *oem_table_id) + { +- int pptt_start = table_data->len; ++ GQueue *list = g_queue_new(); ++ guint pptt_start = table_data->len; ++ guint parent_offset; ++ guint length, i; + int uid = 0; + int socket; + AcpiTable table = { .sig = "PPTT", .rev = 2, +@@ -2010,9 +2013,8 @@ void build_pptt(GArray *table_data, BIOSLinker *linker, MachineState *ms, + acpi_table_begin(&table, table_data); + + for (socket = 0; socket < ms->smp.sockets; socket++) { +- uint32_t socket_offset = table_data->len - pptt_start; +- int core; +- ++ g_queue_push_tail(list, ++ GUINT_TO_POINTER(table_data->len - pptt_start)); + build_processor_hierarchy_node( + table_data, + /* +@@ -2021,35 +2023,47 @@ void build_pptt(GArray *table_data, BIOSLinker *linker, MachineState *ms, + */ + (1 << 0), + 0, socket, NULL, 0); ++ } + +- for (core = 0; core < ms->smp.cores; core++) { +- uint32_t core_offset = table_data->len - pptt_start; +- int thread; ++ length = g_queue_get_length(list); ++ for (i = 0; i < length; i++) { ++ int core; + ++ parent_offset = GPOINTER_TO_UINT(g_queue_pop_head(list)); ++ for (core = 0; core < ms->smp.cores; core++) { + if (ms->smp.threads > 1) { ++ g_queue_push_tail(list, ++ GUINT_TO_POINTER(table_data->len - pptt_start)); + build_processor_hierarchy_node( + table_data, + (0 << 0), /* not a physical package */ +- socket_offset, core, NULL, 0); +- +- for (thread = 0; thread < ms->smp.threads; thread++) { +- build_processor_hierarchy_node( +- table_data, +- (1 << 1) | /* ACPI Processor ID valid */ +- (1 << 2) | /* Processor is a Thread */ +- (1 << 3), /* Node is a Leaf */ +- core_offset, uid++, NULL, 0); +- } ++ parent_offset, core, NULL, 0); + } else { + build_processor_hierarchy_node( + table_data, + (1 << 1) | /* ACPI Processor ID valid */ + (1 << 3), /* Node is a Leaf */ +- socket_offset, uid++, NULL, 0); ++ parent_offset, uid++, NULL, 0); + } + } + } + ++ length = g_queue_get_length(list); ++ for (i = 0; i < length; i++) { ++ int thread; ++ ++ parent_offset = GPOINTER_TO_UINT(g_queue_pop_head(list)); ++ for (thread = 0; thread < ms->smp.threads; thread++) { ++ build_processor_hierarchy_node( ++ table_data, ++ (1 << 1) | /* ACPI Processor ID valid */ ++ (1 << 2) | /* Processor is a Thread */ ++ (1 << 3), /* Node is a Leaf */ ++ parent_offset, uid++, NULL, 0); ++ } ++ } ++ ++ g_queue_free(list); + acpi_table_end(linker, &table); + } + +-- +2.27.0 + diff --git a/hw-acpi-aml-build-Support-cluster-level-in-PPTT-gene.patch b/hw-acpi-aml-build-Support-cluster-level-in-PPTT-gene.patch new file mode 100644 index 0000000000000000000000000000000000000000..17542a05a23ab3037961b1d4e970d9b1d32efd34 --- /dev/null +++ b/hw-acpi-aml-build-Support-cluster-level-in-PPTT-gene.patch @@ -0,0 +1,56 @@ +From 9c16924ba0a77c34246b69e8b1faee219f266445 Mon Sep 17 00:00:00 2001 +From: Yanan Wang +Date: Fri, 7 Jan 2022 16:32:31 +0800 +Subject: [PATCH 19/24] hw/acpi/aml-build: Support cluster level in PPTT + generation + +Support CPU cluster topology level in generation of ACPI +Processor Properties Topology Table (PPTT). + +Signed-off-by: Yanan Wang +Reviewed-by: Andrew Jones +Message-id: 20220107083232.16256-6-wangyanan55@huawei.com +Signed-off-by: Peter Maydell +--- + hw/acpi/aml-build.c | 18 ++++++++++++++++++ + 1 file changed, 18 insertions(+) + +diff --git a/hw/acpi/aml-build.c b/hw/acpi/aml-build.c +index 6aaedca2e5..bb2cad63b5 100644 +--- a/hw/acpi/aml-build.c ++++ b/hw/acpi/aml-build.c +@@ -2001,6 +2001,7 @@ static void build_processor_hierarchy_node(GArray *tbl, uint32_t flags, + void build_pptt(GArray *table_data, BIOSLinker *linker, MachineState *ms, + const char *oem_id, const char *oem_table_id) + { ++ MachineClass *mc = MACHINE_GET_CLASS(ms); + GQueue *list = g_queue_new(); + guint pptt_start = table_data->len; + guint parent_offset; +@@ -2025,6 +2026,23 @@ void build_pptt(GArray *table_data, BIOSLinker *linker, MachineState *ms, + 0, socket, NULL, 0); + } + ++ if (mc->smp_props.clusters_supported) { ++ length = g_queue_get_length(list); ++ for (i = 0; i < length; i++) { ++ int cluster; ++ ++ parent_offset = GPOINTER_TO_UINT(g_queue_pop_head(list)); ++ for (cluster = 0; cluster < ms->smp.clusters; cluster++) { ++ g_queue_push_tail(list, ++ GUINT_TO_POINTER(table_data->len - pptt_start)); ++ build_processor_hierarchy_node( ++ table_data, ++ (0 << 0), /* not a physical package */ ++ parent_offset, cluster, NULL, 0); ++ } ++ } ++ } ++ + length = g_queue_get_length(list); + for (i = 0; i < length; i++) { + int core; +-- +2.27.0 + diff --git a/hw-arm-virt-Support-CPU-cluster-on-ARM-virt-machine.patch b/hw-arm-virt-Support-CPU-cluster-on-ARM-virt-machine.patch new file mode 100644 index 0000000000000000000000000000000000000000..cd3241f25dc6a437d65bfeb4a3017b189440dd9b --- /dev/null +++ b/hw-arm-virt-Support-CPU-cluster-on-ARM-virt-machine.patch @@ -0,0 +1,69 @@ +From 1fab7ee365c8daccedd19d3a1be56babe36afcc6 Mon Sep 17 00:00:00 2001 +From: Yanan Wang +Date: Fri, 7 Jan 2022 16:32:27 +0800 +Subject: [PATCH 15/24] hw/arm/virt: Support CPU cluster on ARM virt machine + +ARM64 machines like Kunpeng Family Server Chips have a level +of hardware topology in which a group of CPU cores share L3 +cache tag or L2 cache. For example, Kunpeng 920 typically +has 6 or 8 clusters in each NUMA node (also represent range +of CPU die), and each cluster has 4 CPU cores. All clusters +share L3 cache data, but CPU cores in each cluster share a +local L3 tag. + +Running a guest kernel with Cluster-Aware Scheduling on the +Hosts which have physical clusters, if we can design a vCPU +topology with cluster level for guest kernel and then have +a dedicated vCPU pinning, the guest will gain scheduling +performance improvement from cache affinity of CPU cluster. + +So let's enable the support for this new parameter on ARM +virt machines. After this patch, we can define a 4-level +CPU hierarchy like: cpus=*,maxcpus=*,sockets=*,clusters=*, +cores=*,threads=*. + +Signed-off-by: Yanan Wang +Reviewed-by: Andrew Jones +Message-id: 20220107083232.16256-2-wangyanan55@huawei.com +Signed-off-by: Peter Maydell +--- + hw/arm/virt.c | 1 + + qemu-options.hx | 10 ++++++++++ + 2 files changed, 11 insertions(+) + +diff --git a/hw/arm/virt.c b/hw/arm/virt.c +index 3c972fdab0..6ca9cbe2cf 100644 +--- a/hw/arm/virt.c ++++ b/hw/arm/virt.c +@@ -2704,6 +2704,7 @@ static void virt_machine_class_init(ObjectClass *oc, void *data) + hc->unplug_request = virt_machine_device_unplug_request_cb; + hc->unplug = virt_machine_device_unplug_cb; + mc->nvdimm_supported = true; ++ mc->smp_props.clusters_supported = true; + mc->auto_enable_numa_with_memhp = true; + mc->auto_enable_numa_with_memdev = true; + mc->default_ram_id = "mach-virt.ram"; +diff --git a/qemu-options.hx b/qemu-options.hx +index 0f26f7dad7..74d335e4c3 100644 +--- a/qemu-options.hx ++++ b/qemu-options.hx +@@ -277,6 +277,16 @@ SRST + + -smp 16,sockets=2,dies=2,cores=2,threads=2,maxcpus=16 + ++ The following sub-option defines a CPU topology hierarchy (2 sockets ++ totally on the machine, 2 clusters per socket, 2 cores per cluster, ++ 2 threads per core) for ARM virt machines which support sockets/clusters ++ /cores/threads. Some members of the option can be omitted but their values ++ will be automatically computed: ++ ++ :: ++ ++ -smp 16,sockets=2,clusters=2,cores=2,threads=2,maxcpus=16 ++ + Historically preference was given to the coarsest topology parameters + when computing missing values (ie sockets preferred over cores, which + were preferred over threads), however, this behaviour is considered +-- +2.27.0 + diff --git a/hw-arm-virt-Support-cluster-level-in-DT-cpu-map.patch b/hw-arm-virt-Support-cluster-level-in-DT-cpu-map.patch new file mode 100644 index 0000000000000000000000000000000000000000..2d43030f818bee075d09e0403e7e29410f406a92 --- /dev/null +++ b/hw-arm-virt-Support-cluster-level-in-DT-cpu-map.patch @@ -0,0 +1,57 @@ +From 38d9ae59b9344f13198e6b4de03b04787bd6b89d Mon Sep 17 00:00:00 2001 +From: Yanan Wang +Date: Fri, 7 Jan 2022 16:32:28 +0800 +Subject: [PATCH 16/24] hw/arm/virt: Support cluster level in DT cpu-map + +Support one cluster level between core and physical package in the +cpu-map of Arm/virt devicetree. This is also consistent with Linux +Doc "Documentation/devicetree/bindings/cpu/cpu-topology.txt". + +Signed-off-by: Yanan Wang +Reviewed-by: Andrew Jones +Message-id: 20220107083232.16256-3-wangyanan55@huawei.com +Signed-off-by: Peter Maydell +--- + hw/arm/virt.c | 15 ++++++++------- + 1 file changed, 8 insertions(+), 7 deletions(-) + +diff --git a/hw/arm/virt.c b/hw/arm/virt.c +index 6ca9cbe2cf..ddcb73f714 100644 +--- a/hw/arm/virt.c ++++ b/hw/arm/virt.c +@@ -434,9 +434,8 @@ static void fdt_add_cpu_nodes(const VirtMachineState *vms) + * can contain several layers of clustering within a single physical + * package and cluster nodes can be contained in parent cluster nodes. + * +- * Given that cluster is not yet supported in the vCPU topology, +- * we currently generate one cluster node within each socket node +- * by default. ++ * Note: currently we only support one layer of clustering within ++ * each physical package. + */ + qemu_fdt_add_subnode(ms->fdt, "/cpus/cpu-map"); + +@@ -446,14 +445,16 @@ static void fdt_add_cpu_nodes(const VirtMachineState *vms) + + if (ms->smp.threads > 1) { + map_path = g_strdup_printf( +- "/cpus/cpu-map/socket%d/cluster0/core%d/thread%d", +- cpu / (ms->smp.cores * ms->smp.threads), ++ "/cpus/cpu-map/socket%d/cluster%d/core%d/thread%d", ++ cpu / (ms->smp.clusters * ms->smp.cores * ms->smp.threads), ++ (cpu / (ms->smp.cores * ms->smp.threads)) % ms->smp.clusters, + (cpu / ms->smp.threads) % ms->smp.cores, + cpu % ms->smp.threads); + } else { + map_path = g_strdup_printf( +- "/cpus/cpu-map/socket%d/cluster0/core%d", +- cpu / ms->smp.cores, ++ "/cpus/cpu-map/socket%d/cluster%d/core%d", ++ cpu / (ms->smp.clusters * ms->smp.cores), ++ (cpu / ms->smp.cores) % ms->smp.clusters, + cpu % ms->smp.cores); + } + qemu_fdt_add_path(ms->fdt, map_path); +-- +2.27.0 + diff --git a/hw-arm64-add-vcpu-cache-info-support.patch b/hw-arm64-add-vcpu-cache-info-support.patch new file mode 100644 index 0000000000000000000000000000000000000000..3e8c82e626cca3592709f99af77a7092eddc3207 --- /dev/null +++ b/hw-arm64-add-vcpu-cache-info-support.patch @@ -0,0 +1,353 @@ +From c5cd762bb7513b6df07e26f4eb619dccbd1918b7 Mon Sep 17 00:00:00 2001 +From: Ying Fang +Date: Tue, 8 Feb 2022 11:31:15 +0800 +Subject: [PATCH 23/24] hw/arm64: add vcpu cache info support + +Support VCPU Cache info by dtb and PPTT table, including L1, L2 and L3 Cache. + +Signed-off-by: zhanghailiang +Signed-off-by: Honghao +Signed-off-by: Ying Fang +Signed-off-by: Yanan Wang +--- + hw/acpi/aml-build.c | 158 ++++++++++++++++++++++++++++++++++++ + hw/arm/virt.c | 72 ++++++++++++++++ + include/hw/acpi/aml-build.h | 47 +++++++++++ + tests/data/acpi/virt/PPTT | Bin 96 -> 208 bytes + 4 files changed, 277 insertions(+) + +diff --git a/hw/acpi/aml-build.c b/hw/acpi/aml-build.c +index bb2cad63b5..bebf49622b 100644 +--- a/hw/acpi/aml-build.c ++++ b/hw/acpi/aml-build.c +@@ -1994,6 +1994,163 @@ static void build_processor_hierarchy_node(GArray *tbl, uint32_t flags, + } + } + ++#ifdef __aarch64__ ++/* ++ * ACPI spec, Revision 6.3 ++ * 5.2.29.2 Cache Type Structure (Type 1) ++ */ ++static void build_cache_hierarchy_node(GArray *tbl, uint32_t next_level, ++ uint32_t cache_type) ++{ ++ build_append_byte(tbl, 1); ++ build_append_byte(tbl, 24); ++ build_append_int_noprefix(tbl, 0, 2); ++ build_append_int_noprefix(tbl, 127, 4); ++ build_append_int_noprefix(tbl, next_level, 4); ++ ++ switch (cache_type) { ++ case ARM_L1D_CACHE: /* L1 dcache info */ ++ build_append_int_noprefix(tbl, ARM_L1DCACHE_SIZE, 4); ++ build_append_int_noprefix(tbl, ARM_L1DCACHE_SETS, 4); ++ build_append_byte(tbl, ARM_L1DCACHE_ASSOCIATIVITY); ++ build_append_byte(tbl, ARM_L1DCACHE_ATTRIBUTES); ++ build_append_int_noprefix(tbl, ARM_L1DCACHE_LINE_SIZE, 2); ++ break; ++ case ARM_L1I_CACHE: /* L1 icache info */ ++ build_append_int_noprefix(tbl, ARM_L1ICACHE_SIZE, 4); ++ build_append_int_noprefix(tbl, ARM_L1ICACHE_SETS, 4); ++ build_append_byte(tbl, ARM_L1ICACHE_ASSOCIATIVITY); ++ build_append_byte(tbl, ARM_L1ICACHE_ATTRIBUTES); ++ build_append_int_noprefix(tbl, ARM_L1ICACHE_LINE_SIZE, 2); ++ break; ++ case ARM_L2_CACHE: /* L2 cache info */ ++ build_append_int_noprefix(tbl, ARM_L2CACHE_SIZE, 4); ++ build_append_int_noprefix(tbl, ARM_L2CACHE_SETS, 4); ++ build_append_byte(tbl, ARM_L2CACHE_ASSOCIATIVITY); ++ build_append_byte(tbl, ARM_L2CACHE_ATTRIBUTES); ++ build_append_int_noprefix(tbl, ARM_L2CACHE_LINE_SIZE, 2); ++ break; ++ case ARM_L3_CACHE: /* L3 cache info */ ++ build_append_int_noprefix(tbl, ARM_L3CACHE_SIZE, 4); ++ build_append_int_noprefix(tbl, ARM_L3CACHE_SETS, 4); ++ build_append_byte(tbl, ARM_L3CACHE_ASSOCIATIVITY); ++ build_append_byte(tbl, ARM_L3CACHE_ATTRIBUTES); ++ build_append_int_noprefix(tbl, ARM_L3CACHE_LINE_SIZE, 2); ++ break; ++ default: ++ build_append_int_noprefix(tbl, 0, 4); ++ build_append_int_noprefix(tbl, 0, 4); ++ build_append_byte(tbl, 0); ++ build_append_byte(tbl, 0); ++ build_append_int_noprefix(tbl, 0, 2); ++ } ++} ++ ++/* ++ * ACPI spec, Revision 6.3 ++ * 5.2.29 Processor Properties Topology Table (PPTT) ++ */ ++void build_pptt(GArray *table_data, BIOSLinker *linker, MachineState *ms, ++ const char *oem_id, const char *oem_table_id) ++{ ++ MachineClass *mc = MACHINE_GET_CLASS(ms); ++ GQueue *list = g_queue_new(); ++ guint pptt_start = table_data->len; ++ guint parent_offset; ++ guint length, i; ++ int uid = 0; ++ int socket; ++ AcpiTable table = { .sig = "PPTT", .rev = 2, ++ .oem_id = oem_id, .oem_table_id = oem_table_id }; ++ ++ acpi_table_begin(&table, table_data); ++ ++ for (socket = 0; socket < ms->smp.sockets; socket++) { ++ uint32_t l3_cache_offset = table_data->len - pptt_start; ++ build_cache_hierarchy_node(table_data, 0, ARM_L3_CACHE); ++ ++ g_queue_push_tail(list, ++ GUINT_TO_POINTER(table_data->len - pptt_start)); ++ build_processor_hierarchy_node( ++ table_data, ++ /* ++ * Physical package - represents the boundary ++ * of a physical package ++ */ ++ (1 << 0), ++ 0, socket, &l3_cache_offset, 1); ++ } ++ ++ if (mc->smp_props.clusters_supported) { ++ length = g_queue_get_length(list); ++ for (i = 0; i < length; i++) { ++ int cluster; ++ ++ parent_offset = GPOINTER_TO_UINT(g_queue_pop_head(list)); ++ for (cluster = 0; cluster < ms->smp.clusters; cluster++) { ++ g_queue_push_tail(list, ++ GUINT_TO_POINTER(table_data->len - pptt_start)); ++ build_processor_hierarchy_node( ++ table_data, ++ (0 << 0), /* not a physical package */ ++ parent_offset, cluster, NULL, 0); ++ } ++ } ++ } ++ ++ length = g_queue_get_length(list); ++ for (i = 0; i < length; i++) { ++ int core; ++ ++ parent_offset = GPOINTER_TO_UINT(g_queue_pop_head(list)); ++ for (core = 0; core < ms->smp.cores; core++) { ++ uint32_t priv_rsrc[3] = {}; ++ priv_rsrc[0] = table_data->len - pptt_start; /* L2 cache offset */ ++ build_cache_hierarchy_node(table_data, 0, ARM_L2_CACHE); ++ ++ priv_rsrc[1] = table_data->len - pptt_start; /* L1 dcache offset */ ++ build_cache_hierarchy_node(table_data, priv_rsrc[0], ARM_L1D_CACHE); ++ ++ priv_rsrc[2] = table_data->len - pptt_start; /* L1 icache offset */ ++ build_cache_hierarchy_node(table_data, priv_rsrc[0], ARM_L1I_CACHE); ++ ++ if (ms->smp.threads > 1) { ++ g_queue_push_tail(list, ++ GUINT_TO_POINTER(table_data->len - pptt_start)); ++ build_processor_hierarchy_node( ++ table_data, ++ (0 << 0), /* not a physical package */ ++ parent_offset, core, priv_rsrc, 3); ++ } else { ++ build_processor_hierarchy_node( ++ table_data, ++ (1 << 1) | /* ACPI Processor ID valid */ ++ (1 << 3), /* Node is a Leaf */ ++ parent_offset, uid++, priv_rsrc, 3); ++ } ++ } ++ } ++ ++ length = g_queue_get_length(list); ++ for (i = 0; i < length; i++) { ++ int thread; ++ ++ parent_offset = GPOINTER_TO_UINT(g_queue_pop_head(list)); ++ for (thread = 0; thread < ms->smp.threads; thread++) { ++ build_processor_hierarchy_node( ++ table_data, ++ (1 << 1) | /* ACPI Processor ID valid */ ++ (1 << 2) | /* Processor is a Thread */ ++ (1 << 3), /* Node is a Leaf */ ++ parent_offset, uid++, NULL, 0); ++ } ++ } ++ ++ g_queue_free(list); ++ acpi_table_end(linker, &table); ++} ++ ++#else + /* + * ACPI spec, Revision 6.3 + * 5.2.29 Processor Properties Topology Table (PPTT) +@@ -2084,6 +2241,7 @@ void build_pptt(GArray *table_data, BIOSLinker *linker, MachineState *ms, + g_queue_free(list); + acpi_table_end(linker, &table); + } ++#endif + + /* build rev1/rev3/rev5.1 FADT */ + void build_fadt(GArray *tbl, BIOSLinker *linker, const AcpiFadtData *f, +diff --git a/hw/arm/virt.c b/hw/arm/virt.c +index ddcb73f714..529c0d38b6 100644 +--- a/hw/arm/virt.c ++++ b/hw/arm/virt.c +@@ -350,6 +350,72 @@ static void fdt_add_timer_nodes(const VirtMachineState *vms) + GIC_FDT_IRQ_TYPE_PPI, ARCH_TIMER_NS_EL2_IRQ, irqflags); + } + ++static void fdt_add_l3cache_nodes(const VirtMachineState *vms) ++{ ++ int i; ++ const MachineState *ms = MACHINE(vms); ++ int cpus_per_socket = ms->smp.clusters * ms->smp.cores * ms->smp.threads; ++ int sockets = (ms->smp.cpus + cpus_per_socket - 1) / cpus_per_socket; ++ ++ for (i = 0; i < sockets; i++) { ++ char *nodename = g_strdup_printf("/cpus/l3-cache%d", i); ++ ++ qemu_fdt_add_subnode(ms->fdt, nodename); ++ qemu_fdt_setprop_string(ms->fdt, nodename, "compatible", "cache"); ++ qemu_fdt_setprop_string(ms->fdt, nodename, "cache-unified", "true"); ++ qemu_fdt_setprop_cell(ms->fdt, nodename, "cache-level", 3); ++ qemu_fdt_setprop_cell(ms->fdt, nodename, "cache-size", 0x2000000); ++ qemu_fdt_setprop_cell(ms->fdt, nodename, "cache-line-size", 128); ++ qemu_fdt_setprop_cell(ms->fdt, nodename, "cache-sets", 2048); ++ qemu_fdt_setprop_cell(ms->fdt, nodename, "phandle", ++ qemu_fdt_alloc_phandle(ms->fdt)); ++ g_free(nodename); ++ } ++} ++ ++static void fdt_add_l2cache_nodes(const VirtMachineState *vms) ++{ ++ const MachineState *ms = MACHINE(vms); ++ int cpus_per_socket = ms->smp.clusters * ms->smp.cores * ms->smp.threads; ++ int cpu; ++ ++ for (cpu = 0; cpu < ms->smp.cpus; cpu++) { ++ char *next_path = g_strdup_printf("/cpus/l3-cache%d", ++ cpu / cpus_per_socket); ++ char *nodename = g_strdup_printf("/cpus/l2-cache%d", cpu); ++ ++ qemu_fdt_add_subnode(ms->fdt, nodename); ++ qemu_fdt_setprop_string(ms->fdt, nodename, "compatible", "cache"); ++ qemu_fdt_setprop_cell(ms->fdt, nodename, "cache-size", 0x80000); ++ qemu_fdt_setprop_cell(ms->fdt, nodename, "cache-line-size", 64); ++ qemu_fdt_setprop_cell(ms->fdt, nodename, "cache-sets", 1024); ++ qemu_fdt_setprop_phandle(ms->fdt, nodename, "next-level-cache", ++ next_path); ++ qemu_fdt_setprop_cell(ms->fdt, nodename, "phandle", ++ qemu_fdt_alloc_phandle(ms->fdt)); ++ ++ g_free(next_path); ++ g_free(nodename); ++ } ++} ++ ++static void fdt_add_l1cache_prop(const VirtMachineState *vms, ++ char *nodename, int cpu) ++{ ++ const MachineState *ms = MACHINE(vms); ++ char *cachename = g_strdup_printf("/cpus/l2-cache%d", cpu); ++ ++ qemu_fdt_setprop_cell(ms->fdt, nodename, "d-cache-size", 0x10000); ++ qemu_fdt_setprop_cell(ms->fdt, nodename, "d-cache-line-size", 64); ++ qemu_fdt_setprop_cell(ms->fdt, nodename, "d-cache-sets", 256); ++ qemu_fdt_setprop_cell(ms->fdt, nodename, "i-cache-size", 0x10000); ++ qemu_fdt_setprop_cell(ms->fdt, nodename, "i-cache-line-size", 64); ++ qemu_fdt_setprop_cell(ms->fdt, nodename, "i-cache-sets", 256); ++ qemu_fdt_setprop_phandle(ms->fdt, nodename, "next-level-cache", ++ cachename); ++ g_free(cachename); ++} ++ + static void fdt_add_cpu_nodes(const VirtMachineState *vms) + { + int cpu; +@@ -384,6 +450,11 @@ static void fdt_add_cpu_nodes(const VirtMachineState *vms) + qemu_fdt_setprop_cell(ms->fdt, "/cpus", "#address-cells", addr_cells); + qemu_fdt_setprop_cell(ms->fdt, "/cpus", "#size-cells", 0x0); + ++ if (!vmc->no_cpu_topology) { ++ fdt_add_l3cache_nodes(vms); ++ fdt_add_l2cache_nodes(vms); ++ } ++ + for (cpu = smp_cpus - 1; cpu >= 0; cpu--) { + char *nodename = g_strdup_printf("/cpus/cpu@%d", cpu); + ARMCPU *armcpu = ARM_CPU(qemu_get_cpu(cpu)); +@@ -413,6 +484,7 @@ static void fdt_add_cpu_nodes(const VirtMachineState *vms) + } + + if (!vmc->no_cpu_topology) { ++ fdt_add_l1cache_prop(vms, nodename, cpu); + qemu_fdt_setprop_cell(ms->fdt, nodename, "phandle", + qemu_fdt_alloc_phandle(ms->fdt)); + } +diff --git a/include/hw/acpi/aml-build.h b/include/hw/acpi/aml-build.h +index 8346003a22..8e8ad8029e 100644 +--- a/include/hw/acpi/aml-build.h ++++ b/include/hw/acpi/aml-build.h +@@ -221,6 +221,53 @@ struct AcpiBuildTables { + BIOSLinker *linker; + } AcpiBuildTables; + ++#ifdef __aarch64__ ++/* Definitions of the hardcoded cache info*/ ++ ++typedef enum { ++ ARM_L1D_CACHE, ++ ARM_L1I_CACHE, ++ ARM_L2_CACHE, ++ ARM_L3_CACHE ++} ArmCacheType; ++ ++/* L1 data cache: */ ++#define ARM_L1DCACHE_SIZE 65536 ++#define ARM_L1DCACHE_SETS 256 ++#define ARM_L1DCACHE_ASSOCIATIVITY 4 ++#define ARM_L1DCACHE_ATTRIBUTES 2 ++#define ARM_L1DCACHE_LINE_SIZE 64 ++ ++/* L1 instruction cache: */ ++#define ARM_L1ICACHE_SIZE 65536 ++#define ARM_L1ICACHE_SETS 256 ++#define ARM_L1ICACHE_ASSOCIATIVITY 4 ++#define ARM_L1ICACHE_ATTRIBUTES 4 ++#define ARM_L1ICACHE_LINE_SIZE 64 ++ ++/* Level 2 unified cache: */ ++#define ARM_L2CACHE_SIZE 524288 ++#define ARM_L2CACHE_SETS 1024 ++#define ARM_L2CACHE_ASSOCIATIVITY 8 ++#define ARM_L2CACHE_ATTRIBUTES 10 ++#define ARM_L2CACHE_LINE_SIZE 64 ++ ++/* Level 3 unified cache: */ ++#define ARM_L3CACHE_SIZE 33554432 ++#define ARM_L3CACHE_SETS 2048 ++#define ARM_L3CACHE_ASSOCIATIVITY 15 ++#define ARM_L3CACHE_ATTRIBUTES 10 ++#define ARM_L3CACHE_LINE_SIZE 128 ++ ++struct offset_status { ++ uint32_t parent; ++ uint32_t l2_offset; ++ uint32_t l1d_offset; ++ uint32_t l1i_offset; ++}; ++ ++#endif ++ + typedef + struct CrsRangeEntry { + uint64_t base; + +-- +2.27.0 + diff --git a/hw-core-Rename-smp_parse-machine_parse_smp_config.patch b/hw-core-Rename-smp_parse-machine_parse_smp_config.patch new file mode 100644 index 0000000000000000000000000000000000000000..8537cc6adec12daacbd87f61ab6e36656117c8b0 --- /dev/null +++ b/hw-core-Rename-smp_parse-machine_parse_smp_config.patch @@ -0,0 +1,114 @@ +From 2ce1daae407033e689a559b7346523b18651ee0a Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= +Date: Thu, 11 Nov 2021 10:21:23 +0100 +Subject: [PATCH 09/24] hw/core: Rename smp_parse() -> + machine_parse_smp_config() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +All methods related to MachineState are prefixed with "machine_". +smp_parse() does not need to be an exception. Rename it and +const'ify the SMPConfiguration argument, since it doesn't need +to be modified. + +Reviewed-by: Andrew Jones +Reviewed-by: Richard Henderson +Reviewed-by: Yanan Wang +Tested-by: Yanan Wang +Signed-off-by: Philippe Mathieu-Daudé +Message-Id: <20211216132015.815493-9-philmd@redhat.com> +--- + hw/core/machine-smp.c | 6 ++++-- + hw/core/machine.c | 2 +- + include/hw/boards.h | 3 ++- + tests/unit/test-smp-parse.c | 8 ++++---- + 4 files changed, 11 insertions(+), 8 deletions(-) + +diff --git a/hw/core/machine-smp.c b/hw/core/machine-smp.c +index 116a0cbbfa..2cbfd57429 100644 +--- a/hw/core/machine-smp.c ++++ b/hw/core/machine-smp.c +@@ -44,7 +44,8 @@ static char *cpu_hierarchy_to_string(MachineState *ms) + } + + /* +- * smp_parse - Generic function used to parse the given SMP configuration ++ * machine_parse_smp_config: Generic function used to parse the given ++ * SMP configuration + * + * Any missing parameter in "cpus/maxcpus/sockets/cores/threads" will be + * automatically computed based on the provided ones. +@@ -63,7 +64,8 @@ static char *cpu_hierarchy_to_string(MachineState *ms) + * introduced topology members which are likely to be target specific should + * be directly set as 1 if they are omitted (e.g. dies for PC since 4.1). + */ +-void smp_parse(MachineState *ms, SMPConfiguration *config, Error **errp) ++void machine_parse_smp_config(MachineState *ms, ++ const SMPConfiguration *config, Error **errp) + { + MachineClass *mc = MACHINE_GET_CLASS(ms); + unsigned cpus = config->has_cpus ? config->cpus : 0; +diff --git a/hw/core/machine.c b/hw/core/machine.c +index 53a99abc56..3993c534b9 100644 +--- a/hw/core/machine.c ++++ b/hw/core/machine.c +@@ -761,7 +761,7 @@ static void machine_set_smp(Object *obj, Visitor *v, const char *name, + return; + } + +- smp_parse(ms, config, errp); ++ machine_parse_smp_config(ms, config, errp); + } + + static void machine_class_init(ObjectClass *oc, void *data) +diff --git a/include/hw/boards.h b/include/hw/boards.h +index 9c1c190104..7597cec440 100644 +--- a/include/hw/boards.h ++++ b/include/hw/boards.h +@@ -34,7 +34,8 @@ HotpluggableCPUList *machine_query_hotpluggable_cpus(MachineState *machine); + void machine_set_cpu_numa_node(MachineState *machine, + const CpuInstanceProperties *props, + Error **errp); +-void smp_parse(MachineState *ms, SMPConfiguration *config, Error **errp); ++void machine_parse_smp_config(MachineState *ms, ++ const SMPConfiguration *config, Error **errp); + + /** + * machine_class_allow_dynamic_sysbus_dev: Add type to list of valid devices +diff --git a/tests/unit/test-smp-parse.c b/tests/unit/test-smp-parse.c +index 0f98c9509e..b6df8137fc 100644 +--- a/tests/unit/test-smp-parse.c ++++ b/tests/unit/test-smp-parse.c +@@ -337,7 +337,7 @@ static const struct SMPTestData data_with_dies_invalid[] = { + }, + }; + +-static char *smp_config_to_string(SMPConfiguration *config) ++static char *smp_config_to_string(const SMPConfiguration *config) + { + return g_strdup_printf( + "(SMPConfiguration) {\n" +@@ -371,7 +371,7 @@ static char *cpu_topology_to_string(const CpuTopology *topo) + topo->cores, topo->threads, topo->max_cpus); + } + +-static void check_parse(MachineState *ms, SMPConfiguration *config, ++static void check_parse(MachineState *ms, const SMPConfiguration *config, + const CpuTopology *expect_topo, const char *expect_err, + bool is_valid) + { +@@ -380,8 +380,8 @@ static void check_parse(MachineState *ms, SMPConfiguration *config, + g_autofree char *output_topo_str = NULL; + Error *err = NULL; + +- /* call the generic parser smp_parse() */ +- smp_parse(ms, config, &err); ++ /* call the generic parser */ ++ machine_parse_smp_config(ms, config, &err); + + output_topo_str = cpu_topology_to_string(&ms->smp); + +-- +2.27.0 + diff --git a/hw-core-machine-Introduce-CPU-cluster-topology-suppo.patch b/hw-core-machine-Introduce-CPU-cluster-topology-suppo.patch new file mode 100644 index 0000000000000000000000000000000000000000..39956fbd8ae741e31fdf2c4a2eca362a6ec9f891 --- /dev/null +++ b/hw-core-machine-Introduce-CPU-cluster-topology-suppo.patch @@ -0,0 +1,283 @@ +From bf4a20a82bd4804842dd2960db30e0be7ecb2d32 Mon Sep 17 00:00:00 2001 +From: Yanan Wang +Date: Tue, 28 Dec 2021 17:22:09 +0800 +Subject: [PATCH 11/24] hw/core/machine: Introduce CPU cluster topology support +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The new Cluster-Aware Scheduling support has landed in Linux 5.16, +which has been proved to benefit the scheduling performance (e.g. +load balance and wake_affine strategy) on both x86_64 and AArch64. + +So now in Linux 5.16 we have four-level arch-neutral CPU topology +definition like below and a new scheduler level for clusters. +struct cpu_topology { + int thread_id; + int core_id; + int cluster_id; + int package_id; + int llc_id; + cpumask_t thread_sibling; + cpumask_t core_sibling; + cpumask_t cluster_sibling; + cpumask_t llc_sibling; +} + +A cluster generally means a group of CPU cores which share L2 cache +or other mid-level resources, and it is the shared resources that +is used to improve scheduler's behavior. From the point of view of +the size range, it's between CPU die and CPU core. For example, on +some ARM64 Kunpeng servers, we have 6 clusters in each NUMA node, +and 4 CPU cores in each cluster. The 4 CPU cores share a separate +L2 cache and a L3 cache tag, which brings cache affinity advantage. + +In virtualization, on the Hosts which have pClusters (physical +clusters), if we can design a vCPU topology with cluster level for +guest kernel and have a dedicated vCPU pinning. A Cluster-Aware +Guest kernel can also make use of the cache affinity of CPU clusters +to gain similar scheduling performance. + +This patch adds infrastructure for CPU cluster level topology +configuration and parsing, so that the user can specify cluster +parameter if their machines support it. + +Signed-off-by: Yanan Wang +Message-Id: <20211228092221.21068-3-wangyanan55@huawei.com> +Reviewed-by: Philippe Mathieu-Daudé +[PMD: Added '(since 7.0)' to @clusters in qapi/machine.json] +Signed-off-by: Philippe Mathieu-Daudé +--- + hw/core/machine-smp.c | 26 +++++++++++++++++++------- + hw/core/machine.c | 3 +++ + include/hw/boards.h | 6 +++++- + qapi/machine.json | 5 ++++- + qemu-options.hx | 7 ++++--- + softmmu/vl.c | 3 +++ + 6 files changed, 38 insertions(+), 12 deletions(-) + +diff --git a/hw/core/machine-smp.c b/hw/core/machine-smp.c +index 2cbfd57429..b39ed21e65 100644 +--- a/hw/core/machine-smp.c ++++ b/hw/core/machine-smp.c +@@ -37,6 +37,10 @@ static char *cpu_hierarchy_to_string(MachineState *ms) + g_string_append_printf(s, " * dies (%u)", ms->smp.dies); + } + ++ if (mc->smp_props.clusters_supported) { ++ g_string_append_printf(s, " * clusters (%u)", ms->smp.clusters); ++ } ++ + g_string_append_printf(s, " * cores (%u)", ms->smp.cores); + g_string_append_printf(s, " * threads (%u)", ms->smp.threads); + +@@ -71,6 +75,7 @@ void machine_parse_smp_config(MachineState *ms, + unsigned cpus = config->has_cpus ? config->cpus : 0; + unsigned sockets = config->has_sockets ? config->sockets : 0; + unsigned dies = config->has_dies ? config->dies : 0; ++ unsigned clusters = config->has_clusters ? config->clusters : 0; + unsigned cores = config->has_cores ? config->cores : 0; + unsigned threads = config->has_threads ? config->threads : 0; + unsigned maxcpus = config->has_maxcpus ? config->maxcpus : 0; +@@ -82,6 +87,7 @@ void machine_parse_smp_config(MachineState *ms, + if ((config->has_cpus && config->cpus == 0) || + (config->has_sockets && config->sockets == 0) || + (config->has_dies && config->dies == 0) || ++ (config->has_clusters && config->clusters == 0) || + (config->has_cores && config->cores == 0) || + (config->has_threads && config->threads == 0) || + (config->has_maxcpus && config->maxcpus == 0)) { +@@ -97,8 +103,13 @@ void machine_parse_smp_config(MachineState *ms, + error_setg(errp, "dies not supported by this machine's CPU topology"); + return; + } ++ if (!mc->smp_props.clusters_supported && clusters > 1) { ++ error_setg(errp, "clusters not supported by this machine's CPU topology"); ++ return; ++ } + + dies = dies > 0 ? dies : 1; ++ clusters = clusters > 0 ? clusters : 1; + + /* compute missing values based on the provided ones */ + if (cpus == 0 && maxcpus == 0) { +@@ -113,41 +124,42 @@ void machine_parse_smp_config(MachineState *ms, + if (sockets == 0) { + cores = cores > 0 ? cores : 1; + threads = threads > 0 ? threads : 1; +- sockets = maxcpus / (dies * cores * threads); ++ sockets = maxcpus / (dies * clusters * cores * threads); + } else if (cores == 0) { + threads = threads > 0 ? threads : 1; +- cores = maxcpus / (sockets * dies * threads); ++ cores = maxcpus / (sockets * dies * clusters * threads); + } + } else { + /* prefer cores over sockets since 6.2 */ + if (cores == 0) { + sockets = sockets > 0 ? sockets : 1; + threads = threads > 0 ? threads : 1; +- cores = maxcpus / (sockets * dies * threads); ++ cores = maxcpus / (sockets * dies * clusters * threads); + } else if (sockets == 0) { + threads = threads > 0 ? threads : 1; +- sockets = maxcpus / (dies * cores * threads); ++ sockets = maxcpus / (dies * clusters * cores * threads); + } + } + + /* try to calculate omitted threads at last */ + if (threads == 0) { +- threads = maxcpus / (sockets * dies * cores); ++ threads = maxcpus / (sockets * dies * clusters * cores); + } + } + +- maxcpus = maxcpus > 0 ? maxcpus : sockets * dies * cores * threads; ++ maxcpus = maxcpus > 0 ? maxcpus : sockets * dies * clusters * cores * threads; + cpus = cpus > 0 ? cpus : maxcpus; + + ms->smp.cpus = cpus; + ms->smp.sockets = sockets; + ms->smp.dies = dies; ++ ms->smp.clusters = clusters; + ms->smp.cores = cores; + ms->smp.threads = threads; + ms->smp.max_cpus = maxcpus; + + /* sanity-check of the computed topology */ +- if (sockets * dies * cores * threads != maxcpus) { ++ if (sockets * dies * clusters * cores * threads != maxcpus) { + g_autofree char *topo_msg = cpu_hierarchy_to_string(ms); + error_setg(errp, "Invalid CPU topology: " + "product of the hierarchy must match maxcpus: " +diff --git a/hw/core/machine.c b/hw/core/machine.c +index 3993c534b9..a4a2df405f 100644 +--- a/hw/core/machine.c ++++ b/hw/core/machine.c +@@ -742,10 +742,12 @@ static void machine_get_smp(Object *obj, Visitor *v, const char *name, + .has_cpus = true, .cpus = ms->smp.cpus, + .has_sockets = true, .sockets = ms->smp.sockets, + .has_dies = true, .dies = ms->smp.dies, ++ .has_clusters = true, .clusters = ms->smp.clusters, + .has_cores = true, .cores = ms->smp.cores, + .has_threads = true, .threads = ms->smp.threads, + .has_maxcpus = true, .maxcpus = ms->smp.max_cpus, + }; ++ + if (!visit_type_SMPConfiguration(v, name, &config, &error_abort)) { + return; + } +@@ -932,6 +934,7 @@ static void machine_initfn(Object *obj) + ms->smp.max_cpus = mc->default_cpus; + ms->smp.sockets = 1; + ms->smp.dies = 1; ++ ms->smp.clusters = 1; + ms->smp.cores = 1; + ms->smp.threads = 1; + } +diff --git a/include/hw/boards.h b/include/hw/boards.h +index 7597cec440..f49a2578ea 100644 +--- a/include/hw/boards.h ++++ b/include/hw/boards.h +@@ -129,10 +129,12 @@ typedef struct { + * SMPCompatProps: + * @prefer_sockets - whether sockets are preferred over cores in smp parsing + * @dies_supported - whether dies are supported by the machine ++ * @clusters_supported - whether clusters are supported by the machine + */ + typedef struct { + bool prefer_sockets; + bool dies_supported; ++ bool clusters_supported; + } SMPCompatProps; + + /** +@@ -299,7 +301,8 @@ typedef struct DeviceMemoryState { + * @cpus: the number of present logical processors on the machine + * @sockets: the number of sockets on the machine + * @dies: the number of dies in one socket +- * @cores: the number of cores in one die ++ * @clusters: the number of clusters in one die ++ * @cores: the number of cores in one cluster + * @threads: the number of threads in one core + * @max_cpus: the maximum number of logical processors on the machine + */ +@@ -307,6 +310,7 @@ typedef struct CpuTopology { + unsigned int cpus; + unsigned int sockets; + unsigned int dies; ++ unsigned int clusters; + unsigned int cores; + unsigned int threads; + unsigned int max_cpus; +diff --git a/qapi/machine.json b/qapi/machine.json +index f1839acf20..8faa51074e 100644 +--- a/qapi/machine.json ++++ b/qapi/machine.json +@@ -1396,7 +1396,9 @@ + # + # @dies: number of dies per socket in the CPU topology + # +-# @cores: number of cores per die in the CPU topology ++# @clusters: number of clusters per die in the CPU topology (since 7.0) ++# ++# @cores: number of cores per cluster in the CPU topology + # + # @threads: number of threads per core in the CPU topology + # +@@ -1408,6 +1410,7 @@ + '*cpus': 'int', + '*sockets': 'int', + '*dies': 'int', ++ '*clusters': 'int', + '*cores': 'int', + '*threads': 'int', + '*maxcpus': 'int' } } +diff --git a/qemu-options.hx b/qemu-options.hx +index 7a59db7764..0f26f7dad7 100644 +--- a/qemu-options.hx ++++ b/qemu-options.hx +@@ -206,13 +206,14 @@ SRST + ERST + + DEF("smp", HAS_ARG, QEMU_OPTION_smp, +- "-smp [[cpus=]n][,maxcpus=maxcpus][,sockets=sockets][,dies=dies][,cores=cores][,threads=threads]\n" ++ "-smp [[cpus=]n][,maxcpus=maxcpus][,sockets=sockets][,dies=dies][,clusters=clusters][,cores=cores][,threads=threads]\n" + " set the number of initial CPUs to 'n' [default=1]\n" + " maxcpus= maximum number of total CPUs, including\n" + " offline CPUs for hotplug, etc\n" + " sockets= number of sockets on the machine board\n" + " dies= number of dies in one socket\n" +- " cores= number of cores in one die\n" ++ " clusters= number of clusters in one die\n" ++ " cores= number of cores in one cluster\n" + " threads= number of threads in one core\n" + "Note: Different machines may have different subsets of the CPU topology\n" + " parameters supported, so the actual meaning of the supported parameters\n" +@@ -228,7 +229,7 @@ DEF("smp", HAS_ARG, QEMU_OPTION_smp, + " must be set as 1 in the purpose of correct parsing.\n", + QEMU_ARCH_ALL) + SRST +-``-smp [[cpus=]n][,maxcpus=maxcpus][,sockets=sockets][,dies=dies][,cores=cores][,threads=threads]`` ++``-smp [[cpus=]n][,maxcpus=maxcpus][,sockets=sockets][,dies=dies][,clusters=clusters][,cores=cores][,threads=threads]`` + Simulate a SMP system with '\ ``n``\ ' CPUs initially present on + the machine type board. On boards supporting CPU hotplug, the optional + '\ ``maxcpus``\ ' parameter can be set to enable further CPUs to be +diff --git a/softmmu/vl.c b/softmmu/vl.c +index 620a1f1367..d9e4c619d3 100644 +--- a/softmmu/vl.c ++++ b/softmmu/vl.c +@@ -726,6 +726,9 @@ static QemuOptsList qemu_smp_opts = { + }, { + .name = "dies", + .type = QEMU_OPT_NUMBER, ++ }, { ++ .name = "clusters", ++ .type = QEMU_OPT_NUMBER, + }, { + .name = "cores", + .type = QEMU_OPT_NUMBER, +-- +2.27.0 + diff --git a/qapi-machine.json-Fix-incorrect-description-for-die-.patch b/qapi-machine.json-Fix-incorrect-description-for-die-.patch new file mode 100644 index 0000000000000000000000000000000000000000..a5e605aca092a558d266b46771b4020a81c4a33c --- /dev/null +++ b/qapi-machine.json-Fix-incorrect-description-for-die-.patch @@ -0,0 +1,35 @@ +From b04e92ed13e49f666f62c8f3daa5746109caf17b Mon Sep 17 00:00:00 2001 +From: Yanan Wang +Date: Mon, 22 Nov 2021 11:26:51 +0800 +Subject: [PATCH 01/24] qapi/machine.json: Fix incorrect description for die-id + +In terms of scope, die-id should mean "the die number within +socket the CPU belongs to" instead of "the die number within +node/board the CPU belongs to". Fix it to avoid confusing +the Doc reader. + +Fixes: 176d2cda0d ("i386/cpu: Consolidate die-id validity in smp context") +Signed-off-by: Yanan Wang +Reviewed-by: Eric Blake +Message-Id: <20211122032651.16064-1-wangyanan55@huawei.com> +Signed-off-by: Paolo Bonzini +--- + qapi/machine.json | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/qapi/machine.json b/qapi/machine.json +index 067e3f5378..f1839acf20 100644 +--- a/qapi/machine.json ++++ b/qapi/machine.json +@@ -867,7 +867,7 @@ + # + # @node-id: NUMA node ID the CPU belongs to + # @socket-id: socket number within node/board the CPU belongs to +-# @die-id: die number within node/board the CPU belongs to (Since 4.1) ++# @die-id: die number within socket the CPU belongs to (since 4.1) + # @core-id: core number within die the CPU belongs to + # @thread-id: thread number within core the CPU belongs to + # +-- +2.27.0 + diff --git a/qemu-options-Improve-readability-of-SMP-related-Docs.patch b/qemu-options-Improve-readability-of-SMP-related-Docs.patch new file mode 100644 index 0000000000000000000000000000000000000000..63dc895ac31d7be9be0de1a0390a039a7f66b6f3 --- /dev/null +++ b/qemu-options-Improve-readability-of-SMP-related-Docs.patch @@ -0,0 +1,146 @@ +From 07991b049fc9ebdb62c311eda1535ad4831625e5 Mon Sep 17 00:00:00 2001 +From: Yanan Wang +Date: Tue, 28 Dec 2021 17:22:08 +0800 +Subject: [PATCH 10/24] qemu-options: Improve readability of SMP related Docs +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +We have a description in qemu-options.hx for each CPU topology +parameter to explain what it exactly means, and also an extra +declaration for the target-specific one, e.g. "for PC only" +when describing "dies", and "for PC, it's on one die" when +describing "cores". + +Now we are going to introduce one more non-generic parameter +"clusters", it will make the Doc less readable and if we still +continue to use the legacy way to describe it. + +So let's at first make two tweaks of the Docs to improve the +readability and also scalability: +1) In the -help text: Delete the extra specific declaration and + describe each topology parameter level by level. Then add a + note to declare that different machines may support different + subsets and the actual meaning of the supported parameters + will vary accordingly. +2) In the rST text: List all the sub-hierarchies currently + supported in QEMU, and correspondingly give an example of + -smp configuration for each of them. + +Signed-off-by: Yanan Wang +Reviewed-by: Philippe Mathieu-Daudé +Message-Id: <20211228092221.21068-2-wangyanan55@huawei.com> +Signed-off-by: Philippe Mathieu-Daudé +--- + qemu-options.hx | 76 ++++++++++++++++++++++++++++++++++++++----------- + 1 file changed, 59 insertions(+), 17 deletions(-) + +diff --git a/qemu-options.hx b/qemu-options.hx +index ae2c6dbbfc..7a59db7764 100644 +--- a/qemu-options.hx ++++ b/qemu-options.hx +@@ -207,14 +207,26 @@ ERST + + DEF("smp", HAS_ARG, QEMU_OPTION_smp, + "-smp [[cpus=]n][,maxcpus=maxcpus][,sockets=sockets][,dies=dies][,cores=cores][,threads=threads]\n" +- " set the number of CPUs to 'n' [default=1]\n" ++ " set the number of initial CPUs to 'n' [default=1]\n" + " maxcpus= maximum number of total CPUs, including\n" + " offline CPUs for hotplug, etc\n" +- " sockets= number of discrete sockets in the system\n" +- " dies= number of CPU dies on one socket (for PC only)\n" +- " cores= number of CPU cores on one socket (for PC, it's on one die)\n" +- " threads= number of threads on one CPU core\n", +- QEMU_ARCH_ALL) ++ " sockets= number of sockets on the machine board\n" ++ " dies= number of dies in one socket\n" ++ " cores= number of cores in one die\n" ++ " threads= number of threads in one core\n" ++ "Note: Different machines may have different subsets of the CPU topology\n" ++ " parameters supported, so the actual meaning of the supported parameters\n" ++ " will vary accordingly. For example, for a machine type that supports a\n" ++ " three-level CPU hierarchy of sockets/cores/threads, the parameters will\n" ++ " sequentially mean as below:\n" ++ " sockets means the number of sockets on the machine board\n" ++ " cores means the number of cores in one socket\n" ++ " threads means the number of threads in one core\n" ++ " For a particular machine type board, an expected CPU topology hierarchy\n" ++ " can be defined through the supported sub-option. Unsupported parameters\n" ++ " can also be provided in addition to the sub-option, but their values\n" ++ " must be set as 1 in the purpose of correct parsing.\n", ++ QEMU_ARCH_ALL) + SRST + ``-smp [[cpus=]n][,maxcpus=maxcpus][,sockets=sockets][,dies=dies][,cores=cores][,threads=threads]`` + Simulate a SMP system with '\ ``n``\ ' CPUs initially present on +@@ -225,27 +237,57 @@ SRST + initial CPU count will match the maximum number. When only one of them + is given then the omitted one will be set to its counterpart's value. + Both parameters may be specified, but the maximum number of CPUs must +- be equal to or greater than the initial CPU count. Both parameters are +- subject to an upper limit that is determined by the specific machine +- type chosen. +- +- To control reporting of CPU topology information, the number of sockets, +- dies per socket, cores per die, and threads per core can be specified. +- The sum `` sockets * cores * dies * threads `` must be equal to the +- maximum CPU count. CPU targets may only support a subset of the topology +- parameters. Where a CPU target does not support use of a particular +- topology parameter, its value should be assumed to be 1 for the purpose +- of computing the CPU maximum count. ++ be equal to or greater than the initial CPU count. Product of the ++ CPU topology hierarchy must be equal to the maximum number of CPUs. ++ Both parameters are subject to an upper limit that is determined by ++ the specific machine type chosen. ++ ++ To control reporting of CPU topology information, values of the topology ++ parameters can be specified. Machines may only support a subset of the ++ parameters and different machines may have different subsets supported ++ which vary depending on capacity of the corresponding CPU targets. So ++ for a particular machine type board, an expected topology hierarchy can ++ be defined through the supported sub-option. Unsupported parameters can ++ also be provided in addition to the sub-option, but their values must be ++ set as 1 in the purpose of correct parsing. + + Either the initial CPU count, or at least one of the topology parameters + must be specified. The specified parameters must be greater than zero, + explicit configuration like "cpus=0" is not allowed. Values for any + omitted parameters will be computed from those which are given. ++ ++ For example, the following sub-option defines a CPU topology hierarchy ++ (2 sockets totally on the machine, 2 cores per socket, 2 threads per ++ core) for a machine that only supports sockets/cores/threads. ++ Some members of the option can be omitted but their values will be ++ automatically computed: ++ ++ :: ++ ++ -smp 8,sockets=2,cores=2,threads=2,maxcpus=8 ++ ++ The following sub-option defines a CPU topology hierarchy (2 sockets ++ totally on the machine, 2 dies per socket, 2 cores per die, 2 threads ++ per core) for PC machines which support sockets/dies/cores/threads. ++ Some members of the option can be omitted but their values will be ++ automatically computed: ++ ++ :: ++ ++ -smp 16,sockets=2,dies=2,cores=2,threads=2,maxcpus=16 ++ + Historically preference was given to the coarsest topology parameters + when computing missing values (ie sockets preferred over cores, which + were preferred over threads), however, this behaviour is considered + liable to change. Prior to 6.2 the preference was sockets over cores + over threads. Since 6.2 the preference is cores over sockets over threads. ++ ++ For example, the following option defines a machine board with 2 sockets ++ of 1 core before 6.2 and 1 socket of 2 cores after 6.2: ++ ++ :: ++ ++ -smp 2 + ERST + + DEF("numa", HAS_ARG, QEMU_OPTION_numa, +-- +2.27.0 + diff --git a/qemu.spec b/qemu.spec index 5b292556d95e5198b7d13d45fc53e5de073433e3..45cb002f33c3b185ee67d2d70b5bb88615a6f020 100644 --- a/qemu.spec +++ b/qemu.spec @@ -1,6 +1,6 @@ Name: qemu Version: 6.2.0 -Release: 18 +Release: 19 Epoch: 2 Summary: QEMU is a generic and open source machine emulator and virtualizer License: GPLv2 and BSD and MIT and CC-BY-SA-4.0 @@ -173,6 +173,30 @@ Patch0159: seabios-add-check-to-avoid-dereference-NULL-pointer.patch Patch0160: qemu-img-add-qemu-img-direct-create.patch Patch0161: log-Delete-redudant-qemu_log.patch Patch0162: bios-tables-test-Update-expected-q35-SSDT.dimmpxm-fi.patch +Patch0163: qapi-machine.json-Fix-incorrect-description-for-die-.patch +Patch0164: tests-unit-test-smp-parse-Pass-machine-type-as-argum.patch +Patch0165: tests-unit-test-smp-parse-Split-the-generic-test-in-.patch +Patch0166: tests-unit-test-smp-parse-Add-smp-with-dies-machine-.patch +Patch0167: tests-unit-test-smp-parse-Add-smp-generic-invalid-ma.patch +Patch0168: tests-unit-test-smp-parse-Add-smp-generic-valid-mach.patch +Patch0169: tests-unit-test-smp-parse-Simplify-pointer-to-compou.patch +Patch0170: tests-unit-test-smp-parse-Constify-some-pointer-stru.patch +Patch0171: hw-core-Rename-smp_parse-machine_parse_smp_config.patch +Patch0172: qemu-options-Improve-readability-of-SMP-related-Docs.patch +Patch0173: hw-core-machine-Introduce-CPU-cluster-topology-suppo.patch +Patch0174: tests-unit-test-smp-parse-Add-testcases-for-CPU-clus.patch +Patch0175: tests-unit-test-smp-parse-No-need-to-explicitly-zero.patch +Patch0176: tests-unit-test-smp-parse-Keep-default-MIN-MAX-CPUs-.patch +Patch0177: hw-arm-virt-Support-CPU-cluster-on-ARM-virt-machine.patch +Patch0178: hw-arm-virt-Support-cluster-level-in-DT-cpu-map.patch +Patch0179: hw-acpi-aml-build-Improve-scalability-of-PPTT-genera.patch +Patch0180: tests-acpi-bios-tables-test-Allow-changes-to-virt-PP.patch +Patch0181: hw-acpi-aml-build-Support-cluster-level-in-PPTT-gene.patch +Patch0182: tests-acpi-bios-table-test-Update-expected-virt-PPTT.patch +Patch0183: softmmu-device_tree-Silence-compiler-warning-with-en.patch +Patch0184: softmmu-device_tree-Remove-redundant-pointer-assignm.patch +Patch0185: hw-arm64-add-vcpu-cache-info-support.patch +Patch0186: arm64-Add-the-cpufreq-device-to-show-cpufreq-info-to.patch BuildRequires: flex BuildRequires: gcc @@ -620,6 +644,35 @@ getent passwd qemu >/dev/null || \ %endif %changelog +* Thu Feb 17 2022 imxcc +- qapi/machine.json: Fix incorrect description for die-id +- tests/unit/test-smp-parse: Pass machine type as +- tests/unit/test-smp-parse: Split the 'generic' test in +- tests/unit/test-smp-parse: Add 'smp-with-dies' machine +- tests/unit/test-smp-parse: Add 'smp-generic-invalid' +- tests/unit/test-smp-parse: Add 'smp-generic-valid' +- tests/unit/test-smp-parse: Simplify pointer to compound +- tests/unit/test-smp-parse: Constify some pointer/struct +- hw/core: Rename smp_parse() -> +- qemu-options: Improve readability of SMP related Docs +- hw/core/machine: Introduce CPU cluster topology support +- tests/unit/test-smp-parse: Add testcases for CPU +- tests/unit/test-smp-parse: No need to explicitly zero +- tests/unit/test-smp-parse: Keep default MIN/MAX CPUs in +- hw/arm/virt: Support CPU cluster on ARM virt machine +- hw/arm/virt: Support cluster level in DT cpu-map +- hw/acpi/aml-build: Improve scalability of PPTT +- tests/acpi/bios-tables-test: Allow changes to virt/PPTT +- hw/acpi/aml-build: Support cluster level in PPTT +- tests/acpi/bios-table-test: Update expected virt/PPTT +- update BinDir +- softmmu/device_tree: Silence compiler warning with +- softmmu/device_tree: Remove redundant pointer +- hw/arm64: add vcpu cache info support +- update BinDir +- arm64: Add the cpufreq device to show cpufreq info to +- update BinDir + * Thu Feb 17 2022 imxcc - bios-tables-test: Update expected q35/SSDT.dimmpxm file - spec: add BinDir diff --git a/softmmu-device_tree-Remove-redundant-pointer-assignm.patch b/softmmu-device_tree-Remove-redundant-pointer-assignm.patch new file mode 100644 index 0000000000000000000000000000000000000000..c98a0588cbc31d5ff36d2e5216c8fd6d3f50d508 --- /dev/null +++ b/softmmu-device_tree-Remove-redundant-pointer-assignm.patch @@ -0,0 +1,58 @@ +From ebf1ac6c0ead3d6fbc32466028c286588333c1ea Mon Sep 17 00:00:00 2001 +From: Yanan Wang +Date: Tue, 11 Jan 2022 11:27:58 +0800 +Subject: [PATCH 22/24] softmmu/device_tree: Remove redundant pointer + assignment + +The pointer assignment "const char *p = path;" in function +qemu_fdt_add_path is unnecessary. Let's remove it and just +use the "path" passed in. No functional change. + +Suggested-by: Richard Henderson +Signed-off-by: Yanan Wang +Reviewed-by: Andrew Jones +Reviewed-by: Alistair Francis +Reviewed-by: Thomas Huth +Message-id: 20220111032758.27804-1-wangyanan55@huawei.com +Signed-off-by: Alistair Francis +--- + softmmu/device_tree.c | 9 ++++----- + 1 file changed, 4 insertions(+), 5 deletions(-) + +diff --git a/softmmu/device_tree.c b/softmmu/device_tree.c +index 9e96f5ecd5..8897c79ea4 100644 +--- a/softmmu/device_tree.c ++++ b/softmmu/device_tree.c +@@ -556,7 +556,6 @@ int qemu_fdt_add_subnode(void *fdt, const char *name) + int qemu_fdt_add_path(void *fdt, const char *path) + { + const char *name; +- const char *p = path; + int namelen, retval; + int parent = 0; + +@@ -565,9 +564,9 @@ int qemu_fdt_add_path(void *fdt, const char *path) + } + + do { +- name = p + 1; +- p = strchr(name, '/'); +- namelen = p != NULL ? p - name : strlen(name); ++ name = path + 1; ++ path = strchr(name, '/'); ++ namelen = path != NULL ? path - name : strlen(name); + + retval = fdt_subnode_offset_namelen(fdt, parent, name, namelen); + if (retval < 0 && retval != -FDT_ERR_NOTFOUND) { +@@ -584,7 +583,7 @@ int qemu_fdt_add_path(void *fdt, const char *path) + } + + parent = retval; +- } while (p); ++ } while (path); + + return retval; + } +-- +2.27.0 + diff --git a/softmmu-device_tree-Silence-compiler-warning-with-en.patch b/softmmu-device_tree-Silence-compiler-warning-with-en.patch new file mode 100644 index 0000000000000000000000000000000000000000..68030155312cb20beca50b0e133e4c4b2ab536f4 --- /dev/null +++ b/softmmu-device_tree-Silence-compiler-warning-with-en.patch @@ -0,0 +1,60 @@ +From ecc0eb93e8856321ad940a85970f0db14ab9f146 Mon Sep 17 00:00:00 2001 +From: Thomas Huth +Date: Fri, 7 Jan 2022 14:38:44 +0100 +Subject: [PATCH 21/24] softmmu/device_tree: Silence compiler warning with + --enable-sanitizers +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +If I configure my build with --enable-sanitizers, my GCC (v8.5.0) +complains: + +.../softmmu/device_tree.c: In function ‘qemu_fdt_add_path’: +.../softmmu/device_tree.c:560:18: error: ‘retval’ may be used uninitialized + in this function [-Werror=maybe-uninitialized] + int namelen, retval; + ^~~~~~ + +It's a false warning since the while loop is always executed at least +once (p has to be non-NULL, otherwise the derefence in the if-statement +earlier will crash). Thus let's switch to a do-while loop here instead +to make the compiler happy in all cases. + +Signed-off-by: Thomas Huth +Reviewed-by: Andrew Jones +Reviewed-by: Philippe Mathieu-Daudé +Reviewed-by: Richard Henderson +Reviewed-by: Alistair Francis +Reviewed-by: Yanan Wang +Message-id: 20220107133844.145039-1-thuth@redhat.com +Signed-off-by: Alistair Francis +--- + softmmu/device_tree.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/softmmu/device_tree.c b/softmmu/device_tree.c +index 3965c834ca..9e96f5ecd5 100644 +--- a/softmmu/device_tree.c ++++ b/softmmu/device_tree.c +@@ -564,7 +564,7 @@ int qemu_fdt_add_path(void *fdt, const char *path) + return -1; + } + +- while (p) { ++ do { + name = p + 1; + p = strchr(name, '/'); + namelen = p != NULL ? p - name : strlen(name); +@@ -584,7 +584,7 @@ int qemu_fdt_add_path(void *fdt, const char *path) + } + + parent = retval; +- } ++ } while (p); + + return retval; + } +-- +2.27.0 + diff --git a/tests-acpi-bios-table-test-Update-expected-virt-PPTT.patch b/tests-acpi-bios-table-test-Update-expected-virt-PPTT.patch new file mode 100644 index 0000000000000000000000000000000000000000..8f1de286e32e21794adfb2f054ea79278def18f4 --- /dev/null +++ b/tests-acpi-bios-table-test-Update-expected-virt-PPTT.patch @@ -0,0 +1,110 @@ +From 6f89f06e686a61acf681038ac06732facc6e7b93 Mon Sep 17 00:00:00 2001 +From: Yanan Wang +Date: Fri, 7 Jan 2022 16:32:32 +0800 +Subject: [PATCH 20/24] tests/acpi/bios-table-test: Update expected virt/PPTT + file + +Run ./tests/data/acpi/rebuild-expected-aml.sh from build directory +to update PPTT binary. Also empty bios-tables-test-allowed-diff.h. + +The disassembled differences between actual and expected PPTT: + + /* + * Intel ACPI Component Architecture + * AML/ASL+ Disassembler version 20200528 (64-bit version) + * Copyright (c) 2000 - 2020 Intel Corporation + * +- * Disassembly of tests/data/acpi/virt/PPTT, Tue Jan 4 12:51:11 2022 ++ * Disassembly of /tmp/aml-2ZGOF1, Tue Jan 4 12:51:11 2022 + * + * ACPI Data Table [PPTT] + * + * Format: [HexOffset DecimalOffset ByteLength] FieldName : FieldValue + */ + + [000h 0000 4] Signature : "PPTT" [Processor Properties Topology Table] +-[004h 0004 4] Table Length : 0000004C ++[004h 0004 4] Table Length : 00000060 + [008h 0008 1] Revision : 02 +-[009h 0009 1] Checksum : A8 ++[009h 0009 1] Checksum : 48 + [00Ah 0010 6] Oem ID : "BOCHS " + [010h 0016 8] Oem Table ID : "BXPC " + [018h 0024 4] Oem Revision : 00000001 + [01Ch 0028 4] Asl Compiler ID : "BXPC" + [020h 0032 4] Asl Compiler Revision : 00000001 + + [024h 0036 1] Subtable Type : 00 [Processor Hierarchy Node] + [025h 0037 1] Length : 14 + [026h 0038 2] Reserved : 0000 + [028h 0040 4] Flags (decoded below) : 00000001 + Physical package : 1 + ACPI Processor ID valid : 0 + Processor is a thread : 0 + Node is a leaf : 0 + Identical Implementation : 0 + [02Ch 0044 4] Parent : 00000000 + [030h 0048 4] ACPI Processor ID : 00000000 + [034h 0052 4] Private Resource Number : 00000000 + + [038h 0056 1] Subtable Type : 00 [Processor Hierarchy Node] + [039h 0057 1] Length : 14 + [03Ah 0058 2] Reserved : 0000 +-[03Ch 0060 4] Flags (decoded below) : 0000000A ++[03Ch 0060 4] Flags (decoded below) : 00000000 + Physical package : 0 +- ACPI Processor ID valid : 1 ++ ACPI Processor ID valid : 0 + Processor is a thread : 0 +- Node is a leaf : 1 ++ Node is a leaf : 0 + Identical Implementation : 0 + [040h 0064 4] Parent : 00000024 + [044h 0068 4] ACPI Processor ID : 00000000 + [048h 0072 4] Private Resource Number : 00000000 + +-Raw Table Data: Length 76 (0x4C) ++[04Ch 0076 1] Subtable Type : 00 [Processor Hierarchy Node] ++[04Dh 0077 1] Length : 14 ++[04Eh 0078 2] Reserved : 0000 ++[050h 0080 4] Flags (decoded below) : 0000000A ++ Physical package : 0 ++ ACPI Processor ID valid : 1 ++ Processor is a thread : 0 ++ Node is a leaf : 1 ++ Identical Implementation : 0 ++[054h 0084 4] Parent : 00000038 ++[058h 0088 4] ACPI Processor ID : 00000000 ++[05Ch 0092 4] Private Resource Number : 00000000 ++ ++Raw Table Data: Length 96 (0x60) + +- 0000: 50 50 54 54 4C 00 00 00 02 A8 42 4F 43 48 53 20 // PPTTL.....BOCHS ++ 0000: 50 50 54 54 60 00 00 00 02 48 42 4F 43 48 53 20 // PPTT`....HBOCHS + 0010: 42 58 50 43 20 20 20 20 01 00 00 00 42 58 50 43 // BXPC ....BXPC + 0020: 01 00 00 00 00 14 00 00 01 00 00 00 00 00 00 00 // ................ +- 0030: 00 00 00 00 00 00 00 00 00 14 00 00 0A 00 00 00 // ................ +- 0040: 24 00 00 00 00 00 00 00 00 00 00 00 // $........... ++ 0030: 00 00 00 00 00 00 00 00 00 14 00 00 00 00 00 00 // ................ ++ 0040: 24 00 00 00 00 00 00 00 00 00 00 00 00 14 00 00 // $............... ++ 0050: 0A 00 00 00 38 00 00 00 00 00 00 00 00 00 00 00 // ....8........... + +Signed-off-by: Yanan Wang +Reviewed-by: Ani Sinha +Message-id: 20220107083232.16256-7-wangyanan55@huawei.com +Signed-off-by: Peter Maydell +--- + tests/data/acpi/virt/PPTT | Bin 76 -> 96 bytes + tests/qtest/bios-tables-test-allowed-diff.h | 1 - + 2 files changed, 1 deletion(-) + +diff --git a/tests/qtest/bios-tables-test-allowed-diff.h b/tests/qtest/bios-tables-test-allowed-diff.h +index cb143a55a6..dfb8523c8b 100644 +--- a/tests/qtest/bios-tables-test-allowed-diff.h ++++ b/tests/qtest/bios-tables-test-allowed-diff.h +@@ -1,2 +1 @@ + /* List of comma-separated changed AML files to ignore */ +-"tests/data/acpi/virt/PPTT", +-- +2.27.0 + diff --git a/tests-acpi-bios-tables-test-Allow-changes-to-virt-PP.patch b/tests-acpi-bios-tables-test-Allow-changes-to-virt-PP.patch new file mode 100644 index 0000000000000000000000000000000000000000..a4801e55cd027f94f9e929f5dc86dcc5780620c6 --- /dev/null +++ b/tests-acpi-bios-tables-test-Allow-changes-to-virt-PP.patch @@ -0,0 +1,27 @@ +From 225034a72c803b8e3819cec22bc6fb8bfc9e7366 Mon Sep 17 00:00:00 2001 +From: Yanan Wang +Date: Fri, 7 Jan 2022 16:32:30 +0800 +Subject: [PATCH 18/24] tests/acpi/bios-tables-test: Allow changes to virt/PPTT + file + +List test/data/acpi/virt/PPTT as the expected files allowed to +be changed in tests/qtest/bios-tables-test-allowed-diff.h + +Signed-off-by: Yanan Wang +Acked-by: Ani Sinha +Message-id: 20220107083232.16256-5-wangyanan55@huawei.com +Signed-off-by: Peter Maydell +--- + tests/qtest/bios-tables-test-allowed-diff.h | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/tests/qtest/bios-tables-test-allowed-diff.h b/tests/qtest/bios-tables-test-allowed-diff.h +index dfb8523c8b..cb143a55a6 100644 +--- a/tests/qtest/bios-tables-test-allowed-diff.h ++++ b/tests/qtest/bios-tables-test-allowed-diff.h +@@ -1 +1,2 @@ + /* List of comma-separated changed AML files to ignore */ ++"tests/data/acpi/virt/PPTT", +-- +2.27.0 + diff --git a/tests-unit-test-smp-parse-Add-smp-generic-invalid-ma.patch b/tests-unit-test-smp-parse-Add-smp-generic-invalid-ma.patch new file mode 100644 index 0000000000000000000000000000000000000000..5ea0e6cd48e1d0df115b00da2711627375e7b5fd --- /dev/null +++ b/tests-unit-test-smp-parse-Add-smp-generic-invalid-ma.patch @@ -0,0 +1,87 @@ +From 9a98659dcb37c81e69f54d8f6cbe5116ceba5a36 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= +Date: Mon, 15 Nov 2021 15:44:07 +0100 +Subject: [PATCH 05/24] tests/unit/test-smp-parse: Add 'smp-generic-invalid' + machine type +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Avoid modifying the MachineClass internals by adding the +'smp-generic-invalid' machine, which inherits from TYPE_MACHINE. + +Reviewed-by: Richard Henderson +Signed-off-by: Philippe Mathieu-Daudé +Reviewed-by: Yanan Wang +Message-Id: <20211216132015.815493-5-philmd@redhat.com> +--- + tests/unit/test-smp-parse.c | 25 ++++++++++++++++--------- + 1 file changed, 16 insertions(+), 9 deletions(-) + +diff --git a/tests/unit/test-smp-parse.c b/tests/unit/test-smp-parse.c +index f66cf7bb59..47e11089e2 100644 +--- a/tests/unit/test-smp-parse.c ++++ b/tests/unit/test-smp-parse.c +@@ -487,6 +487,17 @@ static void machine_base_class_init(ObjectClass *oc, void *data) + mc->name = g_strdup(SMP_MACHINE_NAME); + } + ++static void machine_generic_invalid_class_init(ObjectClass *oc, void *data) ++{ ++ MachineClass *mc = MACHINE_CLASS(oc); ++ ++ /* Force invalid min CPUs and max CPUs */ ++ mc->min_cpus = 2; ++ mc->max_cpus = 511; ++ ++ mc->smp_props.dies_supported = false; ++} ++ + static void machine_with_dies_class_init(ObjectClass *oc, void *data) + { + MachineClass *mc = MACHINE_CLASS(oc); +@@ -530,10 +541,6 @@ static void test_generic_invalid(const void *opaque) + SMPTestData *data = &(SMPTestData){}; + int i; + +- /* Force invalid min CPUs and max CPUs */ +- mc->min_cpus = 2; +- mc->max_cpus = 511; +- + for (i = 0; i < ARRAY_SIZE(data_generic_invalid); i++) { + *data = data_generic_invalid[i]; + unsupported_params_init(mc, data); +@@ -541,10 +548,6 @@ static void test_generic_invalid(const void *opaque) + smp_parse_test(ms, data, false); + } + +- /* Reset the supported min CPUs and max CPUs */ +- mc->min_cpus = MIN_CPUS; +- mc->max_cpus = MAX_CPUS; +- + object_unref(obj); + } + +@@ -606,6 +609,10 @@ static const TypeInfo smp_machine_types[] = { + .class_init = machine_base_class_init, + .class_size = sizeof(MachineClass), + .instance_size = sizeof(MachineState), ++ }, { ++ .name = MACHINE_TYPE_NAME("smp-generic-invalid"), ++ .parent = TYPE_MACHINE, ++ .class_init = machine_generic_invalid_class_init, + }, { + .name = MACHINE_TYPE_NAME("smp-with-dies"), + .parent = TYPE_MACHINE, +@@ -625,7 +632,7 @@ int main(int argc, char *argv[]) + TYPE_MACHINE, + test_generic_valid); + g_test_add_data_func("/test-smp-parse/generic/invalid", +- TYPE_MACHINE, ++ MACHINE_TYPE_NAME("smp-generic-invalid"), + test_generic_invalid); + g_test_add_data_func("/test-smp-parse/with_dies", + MACHINE_TYPE_NAME("smp-with-dies"), +-- +2.27.0 + diff --git a/tests-unit-test-smp-parse-Add-smp-generic-valid-mach.patch b/tests-unit-test-smp-parse-Add-smp-generic-valid-mach.patch new file mode 100644 index 0000000000000000000000000000000000000000..a8b17e751a578f914102e7911b820888227dbe54 --- /dev/null +++ b/tests-unit-test-smp-parse-Add-smp-generic-valid-mach.patch @@ -0,0 +1,75 @@ +From c33c7dd51eebf5ae7b7ece1e829b0a5ffdcebfe1 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= +Date: Mon, 15 Nov 2021 15:49:59 +0100 +Subject: [PATCH 06/24] tests/unit/test-smp-parse: Add 'smp-generic-valid' + machine type +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Keep the common TYPE_MACHINE class initialization in +machine_base_class_init(), make it abstract, and move +the non-common code to a new class: "smp-generic-valid". + +Reviewed-by: Richard Henderson +Signed-off-by: Philippe Mathieu-Daudé +Reviewed-by: Yanan Wang +Message-Id: <20211216132015.815493-6-philmd@redhat.com> +--- + tests/unit/test-smp-parse.c | 19 +++++++++++++++---- + 1 file changed, 15 insertions(+), 4 deletions(-) + +diff --git a/tests/unit/test-smp-parse.c b/tests/unit/test-smp-parse.c +index 47e11089e2..b20bf2c235 100644 +--- a/tests/unit/test-smp-parse.c ++++ b/tests/unit/test-smp-parse.c +@@ -478,13 +478,19 @@ static void machine_base_class_init(ObjectClass *oc, void *data) + { + MachineClass *mc = MACHINE_CLASS(oc); + ++ mc->smp_props.prefer_sockets = true; ++ ++ mc->name = g_strdup(SMP_MACHINE_NAME); ++} ++ ++static void machine_generic_valid_class_init(ObjectClass *oc, void *data) ++{ ++ MachineClass *mc = MACHINE_CLASS(oc); ++ + mc->min_cpus = MIN_CPUS; + mc->max_cpus = MAX_CPUS; + +- mc->smp_props.prefer_sockets = true; + mc->smp_props.dies_supported = false; +- +- mc->name = g_strdup(SMP_MACHINE_NAME); + } + + static void machine_generic_invalid_class_init(ObjectClass *oc, void *data) +@@ -606,9 +612,14 @@ static const TypeInfo smp_machine_types[] = { + { + .name = TYPE_MACHINE, + .parent = TYPE_OBJECT, ++ .abstract = true, + .class_init = machine_base_class_init, + .class_size = sizeof(MachineClass), + .instance_size = sizeof(MachineState), ++ }, { ++ .name = MACHINE_TYPE_NAME("smp-generic-valid"), ++ .parent = TYPE_MACHINE, ++ .class_init = machine_generic_valid_class_init, + }, { + .name = MACHINE_TYPE_NAME("smp-generic-invalid"), + .parent = TYPE_MACHINE, +@@ -629,7 +640,7 @@ int main(int argc, char *argv[]) + g_test_init(&argc, &argv, NULL); + + g_test_add_data_func("/test-smp-parse/generic/valid", +- TYPE_MACHINE, ++ MACHINE_TYPE_NAME("smp-generic-valid"), + test_generic_valid); + g_test_add_data_func("/test-smp-parse/generic/invalid", + MACHINE_TYPE_NAME("smp-generic-invalid"), +-- +2.27.0 + diff --git a/tests-unit-test-smp-parse-Add-smp-with-dies-machine-.patch b/tests-unit-test-smp-parse-Add-smp-with-dies-machine-.patch new file mode 100644 index 0000000000000000000000000000000000000000..1d779fc274a8d8140d71c76d165fd0ca5e0644da --- /dev/null +++ b/tests-unit-test-smp-parse-Add-smp-with-dies-machine-.patch @@ -0,0 +1,85 @@ +From 4981e75623db6ca681d13719ffcf61b0cfac3edc Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= +Date: Mon, 15 Nov 2021 12:39:12 +0100 +Subject: [PATCH 04/24] tests/unit/test-smp-parse: Add 'smp-with-dies' machine + type +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Avoid modifying the MachineClass internals by adding the +'smp-with-dies' machine, which inherits from TYPE_MACHINE. + +Reviewed-by: Richard Henderson +Reviewed-by: Yanan Wang +Tested-by: Yanan Wang +Signed-off-by: Philippe Mathieu-Daudé +Message-Id: <20211216132015.815493-4-philmd@redhat.com> +--- + tests/unit/test-smp-parse.c | 22 +++++++++++++++------- + 1 file changed, 15 insertions(+), 7 deletions(-) + +diff --git a/tests/unit/test-smp-parse.c b/tests/unit/test-smp-parse.c +index 425ed6b6b9..f66cf7bb59 100644 +--- a/tests/unit/test-smp-parse.c ++++ b/tests/unit/test-smp-parse.c +@@ -487,6 +487,16 @@ static void machine_base_class_init(ObjectClass *oc, void *data) + mc->name = g_strdup(SMP_MACHINE_NAME); + } + ++static void machine_with_dies_class_init(ObjectClass *oc, void *data) ++{ ++ MachineClass *mc = MACHINE_CLASS(oc); ++ ++ mc->min_cpus = MIN_CPUS; ++ mc->max_cpus = MAX_CPUS; ++ ++ mc->smp_props.dies_supported = true; ++} ++ + static void test_generic_valid(const void *opaque) + { + const char *machine_type = opaque; +@@ -548,9 +558,6 @@ static void test_with_dies(const void *opaque) + unsigned int num_dies = 2; + int i; + +- /* Force the SMP compat properties */ +- mc->smp_props.dies_supported = true; +- + for (i = 0; i < ARRAY_SIZE(data_generic_valid); i++) { + *data = data_generic_valid[i]; + unsupported_params_init(mc, data); +@@ -588,9 +595,6 @@ static void test_with_dies(const void *opaque) + smp_parse_test(ms, data, false); + } + +- /* Restore the SMP compat properties */ +- mc->smp_props.dies_supported = false; +- + object_unref(obj); + } + +@@ -602,6 +606,10 @@ static const TypeInfo smp_machine_types[] = { + .class_init = machine_base_class_init, + .class_size = sizeof(MachineClass), + .instance_size = sizeof(MachineState), ++ }, { ++ .name = MACHINE_TYPE_NAME("smp-with-dies"), ++ .parent = TYPE_MACHINE, ++ .class_init = machine_with_dies_class_init, + } + }; + +@@ -620,7 +628,7 @@ int main(int argc, char *argv[]) + TYPE_MACHINE, + test_generic_invalid); + g_test_add_data_func("/test-smp-parse/with_dies", +- TYPE_MACHINE, ++ MACHINE_TYPE_NAME("smp-with-dies"), + test_with_dies); + + g_test_run(); +-- +2.27.0 + diff --git a/tests-unit-test-smp-parse-Add-testcases-for-CPU-clus.patch b/tests-unit-test-smp-parse-Add-testcases-for-CPU-clus.patch new file mode 100644 index 0000000000000000000000000000000000000000..e9c9aefbb230a5b0fb05a8e7f9f03f2bf6592158 --- /dev/null +++ b/tests-unit-test-smp-parse-Add-testcases-for-CPU-clus.patch @@ -0,0 +1,254 @@ +From 5e8a39a560ea58308f66d47639c0d5d2e704997f Mon Sep 17 00:00:00 2001 +From: Yanan Wang +Date: Tue, 28 Dec 2021 17:22:11 +0800 +Subject: [PATCH 12/24] tests/unit/test-smp-parse: Add testcases for CPU + clusters +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Add testcases for parsing of the four-level CPU topology hierarchy, +ie sockets/clusters/cores/threads, which will be supported on ARM +virt machines. + +Signed-off-by: Yanan Wang +Reviewed-by: Philippe Mathieu-Daudé +Message-Id: <20211228092221.21068-5-wangyanan55@huawei.com> +Signed-off-by: Philippe Mathieu-Daudé +--- + tests/unit/test-smp-parse.c | 130 ++++++++++++++++++++++++++++++++++-- + 1 file changed, 123 insertions(+), 7 deletions(-) + +diff --git a/tests/unit/test-smp-parse.c b/tests/unit/test-smp-parse.c +index b6df8137fc..331719bbc4 100644 +--- a/tests/unit/test-smp-parse.c ++++ b/tests/unit/test-smp-parse.c +@@ -61,6 +61,20 @@ + .has_maxcpus = hf, .maxcpus = f, \ + } + ++/* ++ * Currently a 4-level topology hierarchy is supported on ARM virt machines ++ * -sockets/clusters/cores/threads ++ */ ++#define SMP_CONFIG_WITH_CLUSTERS(ha, a, hb, b, hc, c, hd, d, he, e, hf, f) \ ++ { \ ++ .has_cpus = ha, .cpus = a, \ ++ .has_sockets = hb, .sockets = b, \ ++ .has_clusters = hc, .clusters = c, \ ++ .has_cores = hd, .cores = d, \ ++ .has_threads = he, .threads = e, \ ++ .has_maxcpus = hf, .maxcpus = f, \ ++ } ++ + /** + * @config - the given SMP configuration + * @expect_prefer_sockets - the expected parsing result for the +@@ -290,6 +304,10 @@ static const struct SMPTestData data_generic_invalid[] = { + /* config: -smp 2,dies=2 */ + .config = SMP_CONFIG_WITH_DIES(T, 2, F, 0, T, 2, F, 0, F, 0, F, 0), + .expect_error = "dies not supported by this machine's CPU topology", ++ }, { ++ /* config: -smp 2,clusters=2 */ ++ .config = SMP_CONFIG_WITH_CLUSTERS(T, 2, F, 0, T, 2, F, 0, F, 0, F, 0), ++ .expect_error = "clusters not supported by this machine's CPU topology", + }, { + /* config: -smp 8,sockets=2,cores=4,threads=2,maxcpus=8 */ + .config = SMP_CONFIG_GENERIC(T, 8, T, 2, T, 4, T, 2, T, 8), +@@ -337,20 +355,40 @@ static const struct SMPTestData data_with_dies_invalid[] = { + }, + }; + ++static const struct SMPTestData data_with_clusters_invalid[] = { ++ { ++ /* config: -smp 16,sockets=2,clusters=2,cores=4,threads=2,maxcpus=16 */ ++ .config = SMP_CONFIG_WITH_CLUSTERS(T, 16, T, 2, T, 2, T, 4, T, 2, T, 16), ++ .expect_error = "Invalid CPU topology: " ++ "product of the hierarchy must match maxcpus: " ++ "sockets (2) * clusters (2) * cores (4) * threads (2) " ++ "!= maxcpus (16)", ++ }, { ++ /* config: -smp 34,sockets=2,clusters=2,cores=4,threads=2,maxcpus=32 */ ++ .config = SMP_CONFIG_WITH_CLUSTERS(T, 34, T, 2, T, 2, T, 4, T, 2, T, 32), ++ .expect_error = "Invalid CPU topology: " ++ "maxcpus must be equal to or greater than smp: " ++ "sockets (2) * clusters (2) * cores (4) * threads (2) " ++ "== maxcpus (32) < smp_cpus (34)", ++ }, ++}; ++ + static char *smp_config_to_string(const SMPConfiguration *config) + { + return g_strdup_printf( + "(SMPConfiguration) {\n" +- " .has_cpus = %5s, cpus = %" PRId64 ",\n" +- " .has_sockets = %5s, sockets = %" PRId64 ",\n" +- " .has_dies = %5s, dies = %" PRId64 ",\n" +- " .has_cores = %5s, cores = %" PRId64 ",\n" +- " .has_threads = %5s, threads = %" PRId64 ",\n" +- " .has_maxcpus = %5s, maxcpus = %" PRId64 ",\n" ++ " .has_cpus = %5s, cpus = %" PRId64 ",\n" ++ " .has_sockets = %5s, sockets = %" PRId64 ",\n" ++ " .has_dies = %5s, dies = %" PRId64 ",\n" ++ " .has_clusters = %5s, clusters = %" PRId64 ",\n" ++ " .has_cores = %5s, cores = %" PRId64 ",\n" ++ " .has_threads = %5s, threads = %" PRId64 ",\n" ++ " .has_maxcpus = %5s, maxcpus = %" PRId64 ",\n" + "}", + config->has_cpus ? "true" : "false", config->cpus, + config->has_sockets ? "true" : "false", config->sockets, + config->has_dies ? "true" : "false", config->dies, ++ config->has_clusters ? "true" : "false", config->clusters, + config->has_cores ? "true" : "false", config->cores, + config->has_threads ? "true" : "false", config->threads, + config->has_maxcpus ? "true" : "false", config->maxcpus); +@@ -363,11 +401,12 @@ static char *cpu_topology_to_string(const CpuTopology *topo) + " .cpus = %u,\n" + " .sockets = %u,\n" + " .dies = %u,\n" ++ " .clusters = %u,\n" + " .cores = %u,\n" + " .threads = %u,\n" + " .max_cpus = %u,\n" + "}", +- topo->cpus, topo->sockets, topo->dies, ++ topo->cpus, topo->sockets, topo->dies, topo->clusters, + topo->cores, topo->threads, topo->max_cpus); + } + +@@ -391,6 +430,7 @@ static void check_parse(MachineState *ms, const SMPConfiguration *config, + (ms->smp.cpus == expect_topo->cpus) && + (ms->smp.sockets == expect_topo->sockets) && + (ms->smp.dies == expect_topo->dies) && ++ (ms->smp.clusters == expect_topo->clusters) && + (ms->smp.cores == expect_topo->cores) && + (ms->smp.threads == expect_topo->threads) && + (ms->smp.max_cpus == expect_topo->max_cpus)) { +@@ -472,6 +512,11 @@ static void unsupported_params_init(const MachineClass *mc, SMPTestData *data) + data->expect_prefer_sockets.dies = 1; + data->expect_prefer_cores.dies = 1; + } ++ ++ if (!mc->smp_props.clusters_supported) { ++ data->expect_prefer_sockets.clusters = 1; ++ data->expect_prefer_cores.clusters = 1; ++ } + } + + static void machine_base_class_init(ObjectClass *oc, void *data) +@@ -491,6 +536,7 @@ static void machine_generic_valid_class_init(ObjectClass *oc, void *data) + mc->max_cpus = MAX_CPUS; + + mc->smp_props.dies_supported = false; ++ mc->smp_props.clusters_supported = false; + } + + static void machine_generic_invalid_class_init(ObjectClass *oc, void *data) +@@ -502,6 +548,7 @@ static void machine_generic_invalid_class_init(ObjectClass *oc, void *data) + mc->max_cpus = 511; + + mc->smp_props.dies_supported = false; ++ mc->smp_props.clusters_supported = false; + } + + static void machine_with_dies_class_init(ObjectClass *oc, void *data) +@@ -512,6 +559,18 @@ static void machine_with_dies_class_init(ObjectClass *oc, void *data) + mc->max_cpus = MAX_CPUS; + + mc->smp_props.dies_supported = true; ++ mc->smp_props.clusters_supported = false; ++} ++ ++static void machine_with_clusters_class_init(ObjectClass *oc, void *data) ++{ ++ MachineClass *mc = MACHINE_CLASS(oc); ++ ++ mc->min_cpus = MIN_CPUS; ++ mc->max_cpus = MAX_CPUS; ++ ++ mc->smp_props.clusters_supported = true; ++ mc->smp_props.dies_supported = false; + } + + static void test_generic_valid(const void *opaque) +@@ -607,6 +666,56 @@ static void test_with_dies(const void *opaque) + object_unref(obj); + } + ++static void test_with_clusters(const void *opaque) ++{ ++ const char *machine_type = opaque; ++ Object *obj = object_new(machine_type); ++ MachineState *ms = MACHINE(obj); ++ MachineClass *mc = MACHINE_GET_CLASS(obj); ++ SMPTestData data = {}; ++ unsigned int num_clusters = 2; ++ int i; ++ ++ for (i = 0; i < ARRAY_SIZE(data_generic_valid); i++) { ++ data = data_generic_valid[i]; ++ unsupported_params_init(mc, &data); ++ ++ /* when clusters parameter is omitted, it will be set as 1 */ ++ data.expect_prefer_sockets.clusters = 1; ++ data.expect_prefer_cores.clusters = 1; ++ ++ smp_parse_test(ms, &data, true); ++ ++ /* when clusters parameter is specified */ ++ data.config.has_clusters = true; ++ data.config.clusters = num_clusters; ++ if (data.config.has_cpus) { ++ data.config.cpus *= num_clusters; ++ } ++ if (data.config.has_maxcpus) { ++ data.config.maxcpus *= num_clusters; ++ } ++ ++ data.expect_prefer_sockets.clusters = num_clusters; ++ data.expect_prefer_sockets.cpus *= num_clusters; ++ data.expect_prefer_sockets.max_cpus *= num_clusters; ++ data.expect_prefer_cores.clusters = num_clusters; ++ data.expect_prefer_cores.cpus *= num_clusters; ++ data.expect_prefer_cores.max_cpus *= num_clusters; ++ ++ smp_parse_test(ms, &data, true); ++ } ++ ++ for (i = 0; i < ARRAY_SIZE(data_with_clusters_invalid); i++) { ++ data = data_with_clusters_invalid[i]; ++ unsupported_params_init(mc, &data); ++ ++ smp_parse_test(ms, &data, false); ++ } ++ ++ object_unref(obj); ++} ++ + /* Type info of the tested machine */ + static const TypeInfo smp_machine_types[] = { + { +@@ -628,6 +737,10 @@ static const TypeInfo smp_machine_types[] = { + .name = MACHINE_TYPE_NAME("smp-with-dies"), + .parent = TYPE_MACHINE, + .class_init = machine_with_dies_class_init, ++ }, { ++ .name = MACHINE_TYPE_NAME("smp-with-clusters"), ++ .parent = TYPE_MACHINE, ++ .class_init = machine_with_clusters_class_init, + } + }; + +@@ -648,6 +761,9 @@ int main(int argc, char *argv[]) + g_test_add_data_func("/test-smp-parse/with_dies", + MACHINE_TYPE_NAME("smp-with-dies"), + test_with_dies); ++ g_test_add_data_func("/test-smp-parse/with_clusters", ++ MACHINE_TYPE_NAME("smp-with-clusters"), ++ test_with_clusters); + + g_test_run(); + +-- +2.27.0 + diff --git a/tests-unit-test-smp-parse-Constify-some-pointer-stru.patch b/tests-unit-test-smp-parse-Constify-some-pointer-stru.patch new file mode 100644 index 0000000000000000000000000000000000000000..85a56a425c7be042146bc96406b52e162a5544da --- /dev/null +++ b/tests-unit-test-smp-parse-Constify-some-pointer-stru.patch @@ -0,0 +1,82 @@ +From bcf4b802bd8971c0c5a255e606b15900cd47c6b6 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= +Date: Thu, 11 Nov 2021 10:23:06 +0100 +Subject: [PATCH 08/24] tests/unit/test-smp-parse: Constify some pointer/struct +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Declare structures const when we don't need to modify +them at runtime. + +Reviewed-by: Andrew Jones +Reviewed-by: Richard Henderson +Reviewed-by: Yanan Wang +Tested-by: Yanan Wang +Signed-off-by: Philippe Mathieu-Daudé +Message-Id: <20211216132015.815493-8-philmd@redhat.com> +--- + tests/unit/test-smp-parse.c | 12 ++++++------ + 1 file changed, 6 insertions(+), 6 deletions(-) + +diff --git a/tests/unit/test-smp-parse.c b/tests/unit/test-smp-parse.c +index 395929b66c..0f98c9509e 100644 +--- a/tests/unit/test-smp-parse.c ++++ b/tests/unit/test-smp-parse.c +@@ -83,7 +83,7 @@ typedef struct SMPTestData { + * then test the automatic calculation algorithm of the missing + * values in the parser. + */ +-static struct SMPTestData data_generic_valid[] = { ++static const struct SMPTestData data_generic_valid[] = { + { + /* config: no configuration provided + * expect: cpus=1,sockets=1,cores=1,threads=1,maxcpus=1 */ +@@ -285,7 +285,7 @@ static struct SMPTestData data_generic_valid[] = { + }, + }; + +-static struct SMPTestData data_generic_invalid[] = { ++static const struct SMPTestData data_generic_invalid[] = { + { + /* config: -smp 2,dies=2 */ + .config = SMP_CONFIG_WITH_DIES(T, 2, F, 0, T, 2, F, 0, F, 0, F, 0), +@@ -319,7 +319,7 @@ static struct SMPTestData data_generic_invalid[] = { + }, + }; + +-static struct SMPTestData data_with_dies_invalid[] = { ++static const struct SMPTestData data_with_dies_invalid[] = { + { + /* config: -smp 16,sockets=2,dies=2,cores=4,threads=2,maxcpus=16 */ + .config = SMP_CONFIG_WITH_DIES(T, 16, T, 2, T, 2, T, 4, T, 2, T, 16), +@@ -356,7 +356,7 @@ static char *smp_config_to_string(SMPConfiguration *config) + config->has_maxcpus ? "true" : "false", config->maxcpus); + } + +-static char *cpu_topology_to_string(CpuTopology *topo) ++static char *cpu_topology_to_string(const CpuTopology *topo) + { + return g_strdup_printf( + "(CpuTopology) {\n" +@@ -372,7 +372,7 @@ static char *cpu_topology_to_string(CpuTopology *topo) + } + + static void check_parse(MachineState *ms, SMPConfiguration *config, +- CpuTopology *expect_topo, const char *expect_err, ++ const CpuTopology *expect_topo, const char *expect_err, + bool is_valid) + { + g_autofree char *config_str = smp_config_to_string(config); +@@ -466,7 +466,7 @@ static void smp_parse_test(MachineState *ms, SMPTestData *data, bool is_valid) + } + + /* The parsed results of the unsupported parameters should be 1 */ +-static void unsupported_params_init(MachineClass *mc, SMPTestData *data) ++static void unsupported_params_init(const MachineClass *mc, SMPTestData *data) + { + if (!mc->smp_props.dies_supported) { + data->expect_prefer_sockets.dies = 1; +-- +2.27.0 + diff --git a/tests-unit-test-smp-parse-Keep-default-MIN-MAX-CPUs-.patch b/tests-unit-test-smp-parse-Keep-default-MIN-MAX-CPUs-.patch new file mode 100644 index 0000000000000000000000000000000000000000..6e343576fdca6a1ef4713535849d6d9375c71cd9 --- /dev/null +++ b/tests-unit-test-smp-parse-Keep-default-MIN-MAX-CPUs-.patch @@ -0,0 +1,76 @@ +From 214511b1799b94cfd514a222d087bb888ed808ba Mon Sep 17 00:00:00 2001 +From: Yanan Wang +Date: Tue, 28 Dec 2021 17:22:13 +0800 +Subject: [PATCH 14/24] tests/unit/test-smp-parse: Keep default MIN/MAX CPUs in + machine_base_class_init +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Most machine types in test-smp-parse will be OK to have the default +MIN/MAX CPUs except "smp-generic-invalid", let's keep the default +values in machine_base_class_init which will be inherited. And if +we hope a different value for a specific machine, modify it in its +own initialization function. + +Signed-off-by: Yanan Wang +Reviewed-by: Philippe Mathieu-Daudé +Message-Id: <20211228092221.21068-7-wangyanan55@huawei.com> +Signed-off-by: Philippe Mathieu-Daudé +--- + tests/unit/test-smp-parse.c | 16 ++-------------- + 1 file changed, 2 insertions(+), 14 deletions(-) + +diff --git a/tests/unit/test-smp-parse.c b/tests/unit/test-smp-parse.c +index 72d83d1bbc..fdc39a846c 100644 +--- a/tests/unit/test-smp-parse.c ++++ b/tests/unit/test-smp-parse.c +@@ -523,15 +523,10 @@ static void machine_base_class_init(ObjectClass *oc, void *data) + { + MachineClass *mc = MACHINE_CLASS(oc); + +- mc->name = g_strdup(SMP_MACHINE_NAME); +-} +- +-static void machine_generic_valid_class_init(ObjectClass *oc, void *data) +-{ +- MachineClass *mc = MACHINE_CLASS(oc); +- + mc->min_cpus = MIN_CPUS; + mc->max_cpus = MAX_CPUS; ++ ++ mc->name = g_strdup(SMP_MACHINE_NAME); + } + + static void machine_generic_invalid_class_init(ObjectClass *oc, void *data) +@@ -547,9 +542,6 @@ static void machine_with_dies_class_init(ObjectClass *oc, void *data) + { + MachineClass *mc = MACHINE_CLASS(oc); + +- mc->min_cpus = MIN_CPUS; +- mc->max_cpus = MAX_CPUS; +- + mc->smp_props.dies_supported = true; + } + +@@ -557,9 +549,6 @@ static void machine_with_clusters_class_init(ObjectClass *oc, void *data) + { + MachineClass *mc = MACHINE_CLASS(oc); + +- mc->min_cpus = MIN_CPUS; +- mc->max_cpus = MAX_CPUS; +- + mc->smp_props.clusters_supported = true; + } + +@@ -718,7 +707,6 @@ static const TypeInfo smp_machine_types[] = { + }, { + .name = MACHINE_TYPE_NAME("smp-generic-valid"), + .parent = TYPE_MACHINE, +- .class_init = machine_generic_valid_class_init, + }, { + .name = MACHINE_TYPE_NAME("smp-generic-invalid"), + .parent = TYPE_MACHINE, +-- +2.27.0 + diff --git a/tests-unit-test-smp-parse-No-need-to-explicitly-zero.patch b/tests-unit-test-smp-parse-No-need-to-explicitly-zero.patch new file mode 100644 index 0000000000000000000000000000000000000000..59157169c32a498e5ae0455aaaf6dd1312c4b17f --- /dev/null +++ b/tests-unit-test-smp-parse-No-need-to-explicitly-zero.patch @@ -0,0 +1,75 @@ +From 77bca7d51e99f8ba4d11635ff9f51615739f4d55 Mon Sep 17 00:00:00 2001 +From: Yanan Wang +Date: Tue, 28 Dec 2021 17:22:12 +0800 +Subject: [PATCH 13/24] tests/unit/test-smp-parse: No need to explicitly zero + MachineClass members +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The default value of the MachineClass members is 0, which +means we don't have to explicitly zero them. Also the value +of "mc->smp_props.prefer_sockets" will be taken care of by +smp_parse_test(), we don't necessarily need the statement +in machine_base_class_init() either. + +Signed-off-by: Yanan Wang +Reviewed-by: Philippe Mathieu-Daudé +Message-Id: <20211228092221.21068-6-wangyanan55@huawei.com> +Signed-off-by: Philippe Mathieu-Daudé +--- + tests/unit/test-smp-parse.c | 10 ---------- + 1 file changed, 10 deletions(-) + +diff --git a/tests/unit/test-smp-parse.c b/tests/unit/test-smp-parse.c +index 331719bbc4..72d83d1bbc 100644 +--- a/tests/unit/test-smp-parse.c ++++ b/tests/unit/test-smp-parse.c +@@ -523,8 +523,6 @@ static void machine_base_class_init(ObjectClass *oc, void *data) + { + MachineClass *mc = MACHINE_CLASS(oc); + +- mc->smp_props.prefer_sockets = true; +- + mc->name = g_strdup(SMP_MACHINE_NAME); + } + +@@ -534,9 +532,6 @@ static void machine_generic_valid_class_init(ObjectClass *oc, void *data) + + mc->min_cpus = MIN_CPUS; + mc->max_cpus = MAX_CPUS; +- +- mc->smp_props.dies_supported = false; +- mc->smp_props.clusters_supported = false; + } + + static void machine_generic_invalid_class_init(ObjectClass *oc, void *data) +@@ -546,9 +541,6 @@ static void machine_generic_invalid_class_init(ObjectClass *oc, void *data) + /* Force invalid min CPUs and max CPUs */ + mc->min_cpus = 2; + mc->max_cpus = 511; +- +- mc->smp_props.dies_supported = false; +- mc->smp_props.clusters_supported = false; + } + + static void machine_with_dies_class_init(ObjectClass *oc, void *data) +@@ -559,7 +551,6 @@ static void machine_with_dies_class_init(ObjectClass *oc, void *data) + mc->max_cpus = MAX_CPUS; + + mc->smp_props.dies_supported = true; +- mc->smp_props.clusters_supported = false; + } + + static void machine_with_clusters_class_init(ObjectClass *oc, void *data) +@@ -570,7 +561,6 @@ static void machine_with_clusters_class_init(ObjectClass *oc, void *data) + mc->max_cpus = MAX_CPUS; + + mc->smp_props.clusters_supported = true; +- mc->smp_props.dies_supported = false; + } + + static void test_generic_valid(const void *opaque) +-- +2.27.0 + diff --git a/tests-unit-test-smp-parse-Pass-machine-type-as-argum.patch b/tests-unit-test-smp-parse-Pass-machine-type-as-argum.patch new file mode 100644 index 0000000000000000000000000000000000000000..d30509c63c2344dd3d7f27352b874426505be9c6 --- /dev/null +++ b/tests-unit-test-smp-parse-Pass-machine-type-as-argum.patch @@ -0,0 +1,69 @@ +From d8b2aee4fd6ccd8eb621522b647c392c1dd7955c Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= +Date: Mon, 15 Nov 2021 12:32:09 +0100 +Subject: [PATCH 02/24] tests/unit/test-smp-parse: Pass machine type as + argument to tests +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Use g_test_add_data_func() instead of g_test_add_func() so we can +pass the machine type to the tests (we will soon have different +machine types). + +Reviewed-by: Richard Henderson +Reviewed-by: Yanan Wang +Signed-off-by: Philippe Mathieu-Daudé +Message-Id: <20211216132015.815493-2-philmd@redhat.com> +--- + tests/unit/test-smp-parse.c | 18 ++++++++++++------ + 1 file changed, 12 insertions(+), 6 deletions(-) + +diff --git a/tests/unit/test-smp-parse.c b/tests/unit/test-smp-parse.c +index b02450e25a..37c6b4981d 100644 +--- a/tests/unit/test-smp-parse.c ++++ b/tests/unit/test-smp-parse.c +@@ -487,9 +487,10 @@ static void machine_base_class_init(ObjectClass *oc, void *data) + mc->name = g_strdup(SMP_MACHINE_NAME); + } + +-static void test_generic(void) ++static void test_generic(const void *opaque) + { +- Object *obj = object_new(TYPE_MACHINE); ++ const char *machine_type = opaque; ++ Object *obj = object_new(machine_type); + MachineState *ms = MACHINE(obj); + MachineClass *mc = MACHINE_GET_CLASS(obj); + SMPTestData *data = &(SMPTestData){{ }}; +@@ -525,9 +526,10 @@ static void test_generic(void) + object_unref(obj); + } + +-static void test_with_dies(void) ++static void test_with_dies(const void *opaque) + { +- Object *obj = object_new(TYPE_MACHINE); ++ const char *machine_type = opaque; ++ Object *obj = object_new(machine_type); + MachineState *ms = MACHINE(obj); + MachineClass *mc = MACHINE_GET_CLASS(obj); + SMPTestData *data = &(SMPTestData){{ }}; +@@ -599,8 +601,12 @@ int main(int argc, char *argv[]) + + g_test_init(&argc, &argv, NULL); + +- g_test_add_func("/test-smp-parse/generic", test_generic); +- g_test_add_func("/test-smp-parse/with_dies", test_with_dies); ++ g_test_add_data_func("/test-smp-parse/generic", ++ TYPE_MACHINE, ++ test_generic); ++ g_test_add_data_func("/test-smp-parse/with_dies", ++ TYPE_MACHINE, ++ test_with_dies); + + g_test_run(); + +-- +2.27.0 + diff --git a/tests-unit-test-smp-parse-Simplify-pointer-to-compou.patch b/tests-unit-test-smp-parse-Simplify-pointer-to-compou.patch new file mode 100644 index 0000000000000000000000000000000000000000..68cc318f4b2054ce0adf70d4d66b2a4d09ce16e0 --- /dev/null +++ b/tests-unit-test-smp-parse-Simplify-pointer-to-compou.patch @@ -0,0 +1,143 @@ +From 964965721bbed1941bf77e5a748efc1274b7c289 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= +Date: Thu, 11 Nov 2021 08:58:40 +0100 +Subject: [PATCH 07/24] tests/unit/test-smp-parse: Simplify pointer to compound + literal use +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +We can simply use a local variable (and pass its pointer) instead +of a pointer to a compound literal. + +Reviewed-by: Andrew Jones +Reviewed-by: Richard Henderson +Reviewed-by: Yanan Wang +Tested-by: Yanan Wang +Signed-off-by: Philippe Mathieu-Daudé +Message-Id: <20211216132015.815493-7-philmd@redhat.com> +--- + tests/unit/test-smp-parse.c | 66 ++++++++++++++++++------------------- + 1 file changed, 33 insertions(+), 33 deletions(-) + +diff --git a/tests/unit/test-smp-parse.c b/tests/unit/test-smp-parse.c +index b20bf2c235..395929b66c 100644 +--- a/tests/unit/test-smp-parse.c ++++ b/tests/unit/test-smp-parse.c +@@ -520,19 +520,19 @@ static void test_generic_valid(const void *opaque) + Object *obj = object_new(machine_type); + MachineState *ms = MACHINE(obj); + MachineClass *mc = MACHINE_GET_CLASS(obj); +- SMPTestData *data = &(SMPTestData){{ }}; ++ SMPTestData data = {}; + int i; + + for (i = 0; i < ARRAY_SIZE(data_generic_valid); i++) { +- *data = data_generic_valid[i]; +- unsupported_params_init(mc, data); ++ data = data_generic_valid[i]; ++ unsupported_params_init(mc, &data); + +- smp_parse_test(ms, data, true); ++ smp_parse_test(ms, &data, true); + + /* Unsupported parameters can be provided with their values as 1 */ +- data->config.has_dies = true; +- data->config.dies = 1; +- smp_parse_test(ms, data, true); ++ data.config.has_dies = true; ++ data.config.dies = 1; ++ smp_parse_test(ms, &data, true); + } + + object_unref(obj); +@@ -544,14 +544,14 @@ static void test_generic_invalid(const void *opaque) + Object *obj = object_new(machine_type); + MachineState *ms = MACHINE(obj); + MachineClass *mc = MACHINE_GET_CLASS(obj); +- SMPTestData *data = &(SMPTestData){}; ++ SMPTestData data = {}; + int i; + + for (i = 0; i < ARRAY_SIZE(data_generic_invalid); i++) { +- *data = data_generic_invalid[i]; +- unsupported_params_init(mc, data); ++ data = data_generic_invalid[i]; ++ unsupported_params_init(mc, &data); + +- smp_parse_test(ms, data, false); ++ smp_parse_test(ms, &data, false); + } + + object_unref(obj); +@@ -563,45 +563,45 @@ static void test_with_dies(const void *opaque) + Object *obj = object_new(machine_type); + MachineState *ms = MACHINE(obj); + MachineClass *mc = MACHINE_GET_CLASS(obj); +- SMPTestData *data = &(SMPTestData){{ }}; ++ SMPTestData data = {}; + unsigned int num_dies = 2; + int i; + + for (i = 0; i < ARRAY_SIZE(data_generic_valid); i++) { +- *data = data_generic_valid[i]; +- unsupported_params_init(mc, data); ++ data = data_generic_valid[i]; ++ unsupported_params_init(mc, &data); + + /* when dies parameter is omitted, it will be set as 1 */ +- data->expect_prefer_sockets.dies = 1; +- data->expect_prefer_cores.dies = 1; ++ data.expect_prefer_sockets.dies = 1; ++ data.expect_prefer_cores.dies = 1; + +- smp_parse_test(ms, data, true); ++ smp_parse_test(ms, &data, true); + + /* when dies parameter is specified */ +- data->config.has_dies = true; +- data->config.dies = num_dies; +- if (data->config.has_cpus) { +- data->config.cpus *= num_dies; ++ data.config.has_dies = true; ++ data.config.dies = num_dies; ++ if (data.config.has_cpus) { ++ data.config.cpus *= num_dies; + } +- if (data->config.has_maxcpus) { +- data->config.maxcpus *= num_dies; ++ if (data.config.has_maxcpus) { ++ data.config.maxcpus *= num_dies; + } + +- data->expect_prefer_sockets.dies = num_dies; +- data->expect_prefer_sockets.cpus *= num_dies; +- data->expect_prefer_sockets.max_cpus *= num_dies; +- data->expect_prefer_cores.dies = num_dies; +- data->expect_prefer_cores.cpus *= num_dies; +- data->expect_prefer_cores.max_cpus *= num_dies; ++ data.expect_prefer_sockets.dies = num_dies; ++ data.expect_prefer_sockets.cpus *= num_dies; ++ data.expect_prefer_sockets.max_cpus *= num_dies; ++ data.expect_prefer_cores.dies = num_dies; ++ data.expect_prefer_cores.cpus *= num_dies; ++ data.expect_prefer_cores.max_cpus *= num_dies; + +- smp_parse_test(ms, data, true); ++ smp_parse_test(ms, &data, true); + } + + for (i = 0; i < ARRAY_SIZE(data_with_dies_invalid); i++) { +- *data = data_with_dies_invalid[i]; +- unsupported_params_init(mc, data); ++ data = data_with_dies_invalid[i]; ++ unsupported_params_init(mc, &data); + +- smp_parse_test(ms, data, false); ++ smp_parse_test(ms, &data, false); + } + + object_unref(obj); +-- +2.27.0 + diff --git a/tests-unit-test-smp-parse-Split-the-generic-test-in-.patch b/tests-unit-test-smp-parse-Split-the-generic-test-in-.patch new file mode 100644 index 0000000000000000000000000000000000000000..dc13f6dfd02c8d576d0674a8ce577b5ed17c6588 --- /dev/null +++ b/tests-unit-test-smp-parse-Split-the-generic-test-in-.patch @@ -0,0 +1,71 @@ +From fad259cf9996dbc4001cb94ec3c846d649401027 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= +Date: Mon, 15 Nov 2021 12:35:43 +0100 +Subject: [PATCH 03/24] tests/unit/test-smp-parse: Split the 'generic' test in + valid / invalid +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Split the 'generic' test in two tests: 'valid' and 'invalid'. +This will allow us to remove the hack which modifies the +MachineClass internal state. + +Reviewed-by: Richard Henderson +Reviewed-by: Yanan Wang +Signed-off-by: Philippe Mathieu-Daudé +Message-Id: <20211216132015.815493-3-philmd@redhat.com> +--- + tests/unit/test-smp-parse.c | 21 ++++++++++++++++++--- + 1 file changed, 18 insertions(+), 3 deletions(-) + +diff --git a/tests/unit/test-smp-parse.c b/tests/unit/test-smp-parse.c +index 37c6b4981d..425ed6b6b9 100644 +--- a/tests/unit/test-smp-parse.c ++++ b/tests/unit/test-smp-parse.c +@@ -487,7 +487,7 @@ static void machine_base_class_init(ObjectClass *oc, void *data) + mc->name = g_strdup(SMP_MACHINE_NAME); + } + +-static void test_generic(const void *opaque) ++static void test_generic_valid(const void *opaque) + { + const char *machine_type = opaque; + Object *obj = object_new(machine_type); +@@ -508,6 +508,18 @@ static void test_generic(const void *opaque) + smp_parse_test(ms, data, true); + } + ++ object_unref(obj); ++} ++ ++static void test_generic_invalid(const void *opaque) ++{ ++ const char *machine_type = opaque; ++ Object *obj = object_new(machine_type); ++ MachineState *ms = MACHINE(obj); ++ MachineClass *mc = MACHINE_GET_CLASS(obj); ++ SMPTestData *data = &(SMPTestData){}; ++ int i; ++ + /* Force invalid min CPUs and max CPUs */ + mc->min_cpus = 2; + mc->max_cpus = 511; +@@ -601,9 +613,12 @@ int main(int argc, char *argv[]) + + g_test_init(&argc, &argv, NULL); + +- g_test_add_data_func("/test-smp-parse/generic", ++ g_test_add_data_func("/test-smp-parse/generic/valid", ++ TYPE_MACHINE, ++ test_generic_valid); ++ g_test_add_data_func("/test-smp-parse/generic/invalid", + TYPE_MACHINE, +- test_generic); ++ test_generic_invalid); + g_test_add_data_func("/test-smp-parse/with_dies", + TYPE_MACHINE, + test_with_dies); +-- +2.27.0 +