From e23cda47158626f96e5992db00efaaac5dab31b0 Mon Sep 17 00:00:00 2001 From: Sunil V L Date: Tue, 19 Mar 2024 15:43:52 +0530 Subject: [PATCH] NOT_FOR_MERGE: Add test code to emulate CPPC extension Signed-off-by: Sunil V L --- include/sbi/sbi_cppc.h | 2 + platform/generic/objects.mk | 1 + platform/generic/platform.c | 6 ++ platform/generic/test_cppc.c | 160 +++++++++++++++++++++++++++++++++++ 4 files changed, 169 insertions(+) create mode 100644 platform/generic/test_cppc.c diff --git a/include/sbi/sbi_cppc.h b/include/sbi/sbi_cppc.h index edf73f52a..f62d7029b 100644 --- a/include/sbi/sbi_cppc.h +++ b/include/sbi/sbi_cppc.h @@ -32,4 +32,6 @@ int sbi_cppc_write(unsigned long reg, uint64_t val); const struct sbi_cppc_device *sbi_cppc_get_device(void); void sbi_cppc_set_device(const struct sbi_cppc_device *dev); +int test_cppc_init(void); + #endif diff --git a/platform/generic/objects.mk b/platform/generic/objects.mk index 85aa723a5..a3377ed3b 100644 --- a/platform/generic/objects.mk +++ b/platform/generic/objects.mk @@ -20,6 +20,7 @@ platform-runcmd = qemu-system-riscv$(PLATFORM_RISCV_XLEN) -M virt -m 256M \ # Objects to build platform-objs-y += platform.o platform-objs-y += platform_override_modules.o +platform-objs-$(CONFIG_SBI_ECALL_CPPC) += test_cppc.o # Blobs to build FW_TEXT_START=0x80000000 diff --git a/platform/generic/platform.c b/platform/generic/platform.c index 1f46b76c4..783b1b923 100644 --- a/platform/generic/platform.c +++ b/platform/generic/platform.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -244,6 +245,11 @@ static int generic_final_init(bool cold_boot) if (!cold_boot) return 0; +#ifdef CONFIG_SBI_ECALL_CPPC + if (!generic_plat) + test_cppc_init(); +#endif + fdt = fdt_get_address(); fdt_cpu_fixup(fdt); diff --git a/platform/generic/test_cppc.c b/platform/generic/test_cppc.c new file mode 100644 index 000000000..db658af8b --- /dev/null +++ b/platform/generic/test_cppc.c @@ -0,0 +1,160 @@ +/* + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2023 Ventana Micro Systems Inc. + * + */ + +#include +#include +#include +#include +#include +#include +#include + +struct perf_channel { + unsigned int desired_perf; + unsigned int perf_limited; + unsigned int transition_latency; +}; + +static unsigned long cppc_offset; + +static int sbi_cppc_test_probe(unsigned long reg) +{ + switch (reg) { + case SBI_CPPC_REFERENCE_CTR: + case SBI_CPPC_DELIVERED_CTR: + return 64; + case SBI_CPPC_DESIRED_PERF: + case SBI_CPPC_PERF_LIMITED: + case SBI_CPPC_TRANSITION_LATENCY: + return 32; + default: + /* Unimplemented */ + return 0; + } +} + +static int sbi_cppc_test_read(unsigned long reg, uint64_t *val) +{ + struct sbi_scratch *scratch; + struct perf_channel *cppc; + unsigned long hartid; + int ret = SBI_SUCCESS; + + hartid = current_hartid(); + + scratch = sbi_hartid_to_scratch(hartid); + cppc = sbi_scratch_offset_ptr(scratch, cppc_offset); + + switch (reg) { + case SBI_CPPC_DESIRED_PERF: + *val = cppc->desired_perf; + break; + case SBI_CPPC_REFERENCE_CTR: + *val = sbi_timer_value(); + break; + case SBI_CPPC_DELIVERED_CTR: + /* + * Can't use CYCLE CSR properly in qemu, so just return + * TIME itself so that delta(delivered) / delta(ref) = 1 + */ + *val = sbi_timer_value(); + break; + case SBI_CPPC_PERF_LIMITED: + *val = cppc->perf_limited; + break; + case SBI_CPPC_TRANSITION_LATENCY: + *val = cppc->transition_latency; + break; + default: + /* + * Common read should have checked for unimplemented, + * reserved or write-only registers. + */ + ret = SBI_ERR_FAILED; + } + + return ret; +} + +static int sbi_cppc_test_write(unsigned long reg, uint64_t val) +{ + struct sbi_scratch *scratch; + struct perf_channel *cppc; + unsigned long hartid; + int ret = SBI_SUCCESS; + + hartid = current_hartid(); + + scratch = sbi_hartid_to_scratch(hartid); + cppc = sbi_scratch_offset_ptr(scratch, cppc_offset); + + switch (reg) { + case SBI_CPPC_DESIRED_PERF: + cppc->desired_perf = val; + break; + case SBI_CPPC_PERF_LIMITED: + cppc->perf_limited = val; + break; + default: + /* + * Common read should have checked for unimplemented, + * reserved or write-only registers. + */ + ret = SBI_ERR_FAILED; + } + + return ret; +} + +static struct sbi_cppc_device sbi_system_cppc_test = { + .name = "cppc-test", + .cppc_read = sbi_cppc_test_read, + .cppc_write = sbi_cppc_test_write, + .cppc_probe = sbi_cppc_test_probe, +}; + +static void sbi_cppc_test_enable(void) +{ + sbi_cppc_set_device(&sbi_system_cppc_test); +} + +/* + * Allocate scratch space as the channel memory to emulate the SBI CPPC + * extension. + */ +int test_cppc_init() +{ + u32 i; + struct sbi_scratch *rscratch; + struct perf_channel *cppc; + + cppc_offset = sbi_scratch_alloc_offset(sizeof(*cppc)); + if (!cppc_offset) + return SBI_ENOMEM; + + /* Initialize hart state data for every hart */ + for (i = 0; i <= sbi_scratch_last_hartindex(); i++) { + rscratch = sbi_hartid_to_scratch(i); + if (!rscratch) + continue; + + cppc = sbi_scratch_offset_ptr(rscratch, + cppc_offset); + if (cppc) { + sbi_memset(cppc, 0, sizeof(*cppc)); + + /* Initialize sample values */ + cppc->desired_perf = 5; + cppc->perf_limited = 0; + cppc->transition_latency = 20000; + } + } + + sbi_cppc_test_enable(); + + return 0; +}