qemu/arm64-Add-the-cpufreq-device-to-show-cpufreq-info-to.patch

616 lines
18 KiB
Diff
Raw Permalink Normal View History

QEMU update to version 8.2.0-5 - vfio/migration: Add support for manual clear vfio dirty log - vfio: Maintain DMA mapping range for the container - linux-headers: update against 5.10 and manual clear vfio dirty log series - arm/acpi: Fix when make qemu-system-aarch64 at x86_64 host bios_tables_test fail reason: __aarch64__ macro let build_pptt at x86_64 and aarch64 host build different function that let bios_tables_test fail. - pl031: support rtc-timer property for pl031 - feature: Add logs for vm start and destroy - feature: Add log for each modules - log: Add log at boot & cpu init for aarch64 - bugfix: irq: Avoid covering object refcount of qemu_irq - i386: cache passthrough: Update AMD 8000_001D.EAX[25:14] based on vCPU topo - freeclock: set rtc_date_diff for X86 - freeclock: set rtc_date_diff for arm - freeclock: add qmp command to get time offset of vm in seconds - tests: Disable filemonitor testcase - shadow_dev: introduce shadow dev for virtio-net device - pl011: reset read FIFO when UARTTIMSC=0 & UARTICR=0xffff - tests: virt: Update expected ACPI tables for virt test(update BinDir) - arm64: Add the cpufreq device to show cpufreq info to guest - hw/arm64: add vcpu cache info support - tests: virt: Allow changes to PPTT test table - cpu: add Cortex-A72 processor kvm target support - cpu: add Kunpeng-920 cpu support - net: eepro100: validate various address valuesi(CVE-2021-20255) - ide: ahci: add check to avoid null dereference (CVE-2019-12067) - vdpa: set vring enable only if the vring address has already been set - docs: Add generic vhost-vdpa device documentation - vdpa: don't suspend/resume device when vdpa device not started - vdpa: correct param passed in when unregister save - vdpa: suspend function return 0 when the vdpa device is stopped - vdpa: support vdpa device suspend/resume - vdpa: move memory listener to the realize stage - vdpa: implement vdpa device migration - vhost: implement migration state notifier for vdpa device - vhost: implement post resume bh - vhost: implement savevm_handler for vdpa device - vhost: implement vhost_vdpa_device_suspend/resume - vhost: implement vhost-vdpa suspend/resume - vhost: add vhost_dev_suspend/resume_op - vhost: introduce bytemap for vhost backend logging - vhost-vdpa: add migration log ops for VhostOps - vhost-vdpa: add VHOST_BACKEND_F_BYTEMAPLOG - hw/usb: reduce the vpcu cost of UHCI when VNC disconnect - virtio-net: update the default and max of rx/tx_queue_size - virtio-net: set the max of queue size to 4096 - virtio-net: fix max vring buf size when set ring num - virtio-net: bugfix: do not delete netdev before virtio net - monitor: Discard BLOCK_IO_ERROR event when VM rebooted - vhost-user: add unregister_savevm when vhost-user cleanup - vhost-user: add vhost_set_mem_table when vm load_setup at destination - vhost-user: quit infinite loop while used memslots is more than the backend limit - fix qemu-core when vhost-user-net config with server mode - vhost-user: Add support reconnect vhost-user socket - vhost-user: Set the acked_features to vm's featrue - i6300esb watchdog: bugfix: Add a runstate transition - hw/net/rocker_of_dpa: fix double free bug of rocker device - net/dump.c: Suppress spurious compiler warning - pcie: Add pcie-root-port fast plug/unplug feature - pcie: Compat with devices which do not support Link Width, such as ioh3420 - qdev/monitors: Fix reundant error_setg of qdev_add_device - qemu-nbd: set timeout to qemu-nbd socket - qemu-nbd: make native as the default aio mode - nbd/server.c: fix invalid read after client was already free - virtio-scsi: bugfix: fix qemu crash for hotplug scsi disk with dataplane - virtio: bugfix: check the value of caches before accessing it - virtio: print the guest virtio_net features that host does not support - virtio: bugfix: add rcu_read_lock when vring_avail_idx is called - virtio: check descriptor numbers - migration: report multiFd related thread pid to libvirt - migration: report migration related thread pid to libvirt - cpu/features: fix bug for memory leakage - doc: Update multi-thread compression doc - migration: Add compress_level sanity check - migration: Add zstd support in multi-thread compression - migration: Add multi-thread compress ops - migration: Refactoring multi-thread compress migration - migration: Add multi-thread compress method - migration: skip cache_drop for bios bootloader and nvram template - oslib-posix: optimise vm startup time for 1G hugepage - monitor/qmp: drop inflight rsp if qmp client broken - ps2: fix oob in ps2 kbd - Currently, while kvm and qemu can not handle some kvm exit, qemu will do vm_stop, which will make vm in pause state. This action make vm unrecoverable, so send guest panic to libvirt instead. - vhost: cancel migration when vhost-user restarted during migraiton Signed-off-by: Jiabo Feng <fengjiabo1@huawei.com>
2024-04-07 10:21:31 +08:00
From ebe05c34a66969e4cacc4d6c030dfe93ace89cb2 Mon Sep 17 00:00:00 2001
From: Ying Fang <fangying1@huawei.com>
Date: Tue, 19 Mar 2024 14:35:55 +0800
Subject: [PATCH] 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 <fangying1@huawei.com>
Signed-off-by: Yanan Wang <wangyanan55@huawei.com>
Signed-off-by: Yuan Zhang <zhangyuan162@huawei.com>
---
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 | 79 +++++-
hw/arm/virt.c | 13 +
hw/char/Kconfig | 4 +
include/hw/acpi/acpi-defs.h | 40 +++
include/hw/acpi/aml-build.h | 3 +
include/hw/arm/virt.h | 1 +
10 files changed, 444 insertions(+), 3 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 f82a04c27d..8d66d0f1af 100644
--- a/configs/devices/aarch64-softmmu/default.mak
+++ b/configs/devices/aarch64-softmmu/default.mak
@@ -8,3 +8,4 @@ include ../arm-softmmu/default.mak
# CONFIG_XLNX_ZYNQMP_ARM=n
# CONFIG_XLNX_VERSAL=n
# CONFIG_SBSA_REF=n
+# CONFIG_CPUFREQ=n
diff --git a/hw/acpi/aml-build.c b/hw/acpi/aml-build.c
index 2968df5562..714498165a 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 <http://www.gnu.org/licenses/>.
+ */
+
+#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 fc1b952379..d36b10ea3c 100644
--- a/hw/acpi/meson.build
+++ b/hw/acpi/meson.build
@@ -27,6 +27,7 @@ acpi_ss.add(when: 'CONFIG_ACPI_ICH9', if_true: files('ich9.c', 'ich9_tco.c'))
acpi_ss.add(when: 'CONFIG_ACPI_ERST', if_true: files('erst.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_CPUFREQ', if_true: files('cpufreq.c'))
if have_tpm
acpi_ss.add(files('tpm.c'))
endif
diff --git a/hw/arm/virt-acpi-build.c b/hw/arm/virt-acpi-build.c
index 8bc35a483c..3cb50bdc65 100644
--- a/hw/arm/virt-acpi-build.c
+++ b/hw/arm/virt-acpi-build.c
@@ -63,7 +63,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;
@@ -72,7 +133,19 @@ 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)));
- aml_append(scope, dev);
+
+ /*
+ * 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 b82bd1b8c8..c19cacec8b 100644
--- a/hw/arm/virt.c
+++ b/hw/arm/virt.c
@@ -157,6 +157,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 },
@@ -980,6 +981,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;
@@ -2346,6 +2357,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 2b42e4192b..b1f389fb4b 100644
--- a/include/hw/acpi/acpi-defs.h
+++ b/include/hw/acpi/acpi-defs.h
@@ -93,4 +93,44 @@ 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
+ *
+ * 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 84ded2ecd3..200cb113de 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, ...) G_GNUC_PRINTF(1, 2);
diff --git a/include/hw/arm/virt.h b/include/hw/arm/virt.h
index f69239850e..e944d434c4 100644
--- a/include/hw/arm/virt.h
+++ b/include/hw/arm/virt.h
@@ -60,6 +60,7 @@ enum {
VIRT_GIC_REDIST,
VIRT_SMMU,
VIRT_UART,
+ VIRT_CPUFREQ,
VIRT_MMIO,
VIRT_RTC,
VIRT_FW_CFG,
--
2.27.0