diff mbox series

[RFC,v2,4/4] NOT_FOR_MERGE: Add test code to emulate CPPC extension

Message ID 20230323090320.2489167-5-sunilvl@ventanamicro.com
State Superseded
Headers show
Series Add CPPC extension support in OpenSBI | expand

Commit Message

Sunil V L March 23, 2023, 9:03 a.m. UTC
This is a test code to emulate the CPPC extension and it is
not for merge.

Signed-off-by: Sunil V L <sunilvl@ventanamicro.com>
---
 include/sbi/sbi_cppc.h       |   2 +
 platform/generic/objects.mk  |   1 +
 platform/generic/platform.c  |   6 ++
 platform/generic/test_cppc.c | 204 +++++++++++++++++++++++++++++++++++
 4 files changed, 213 insertions(+)
 create mode 100644 platform/generic/test_cppc.c

Comments

Andrew Jones March 23, 2023, 5:02 p.m. UTC | #1
On Thu, Mar 23, 2023 at 02:33:20PM +0530, Sunil V L wrote:
> This is a test code to emulate the CPPC extension and it is
> not for merge.
> 
> Signed-off-by: Sunil V L <sunilvl@ventanamicro.com>
> ---
>  include/sbi/sbi_cppc.h       |   2 +
>  platform/generic/objects.mk  |   1 +
>  platform/generic/platform.c  |   6 ++
>  platform/generic/test_cppc.c | 204 +++++++++++++++++++++++++++++++++++
>  4 files changed, 213 insertions(+)
>  create mode 100644 platform/generic/test_cppc.c
> 
> diff --git a/include/sbi/sbi_cppc.h b/include/sbi/sbi_cppc.h
> index edf73f5..f62d702 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 136853e..d9eb959 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 eeefef4..ef85b70 100644
> --- a/platform/generic/platform.c
> +++ b/platform/generic/platform.c
> @@ -14,6 +14,7 @@
>  #include <sbi/sbi_platform.h>
>  #include <sbi/sbi_string.h>
>  #include <sbi/sbi_system.h>
> +#include <sbi/sbi_cppc.h>
>  #include <sbi_utils/fdt/fdt_domain.h>
>  #include <sbi_utils/fdt/fdt_fixup.h>
>  #include <sbi_utils/fdt/fdt_helper.h>
> @@ -166,6 +167,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 0000000..91ee187
> --- /dev/null
> +++ b/platform/generic/test_cppc.c
> @@ -0,0 +1,204 @@
> +/*
> + * SPDX-License-Identifier: BSD-2-Clause
> + *
> + * Copyright (c) 2023 Ventana Micro Systems Inc.
> + *
> + */
> +
> +#include <sbi/sbi_ecall_interface.h>
> +#include <sbi/sbi_console.h>
> +#include <sbi/sbi_cppc.h>
> +#include <sbi/sbi_error.h>
> +#include <sbi/sbi_scratch.h>
> +#include <sbi/sbi_string.h>
> +#include <sbi/sbi_timer.h>
> +
> +struct perf_channel {
> +	unsigned int	highest_perf;
> +	unsigned int	nominal_perf;
> +	unsigned int	lowest_nonlinear_perf;
> +	unsigned int	lowest_perf;
> +	unsigned int	desired_perf;
> +	unsigned int	perf_limited;
> +	unsigned int	reference_perf;
> +	unsigned int	lowest_freq;
> +	unsigned int	nominal_freq;
> +	unsigned int	transition_latency;
> +};
> +
> +static unsigned long cppc_offset;
> +
> +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_HIGHEST_PERF:
> +		*val = cppc->highest_perf;
> +		break;
> +	case SBI_CPPC_NOMINAL_PERF:
> +		*val = cppc->nominal_perf;
> +		break;
> +	case SBI_CPPC_LOW_NON_LINEAR_PERF:
> +		*val = cppc->lowest_nonlinear_perf;
> +		break;
> +	case SBI_CPPC_LOWEST_PERF:
> +		*val = cppc->lowest_perf;
> +		break;
> +	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_REFERENCE_PERF:
> +		*val = cppc->reference_perf;
> +		break;
> +	case SBI_CPPC_LOWEST_FREQ:
> +		*val = cppc->lowest_freq;
> +		break;
> +	case SBI_CPPC_NOMINAL_FREQ:
> +		*val = cppc->nominal_freq;
> +		break;
> +	case SBI_CPPC_TRANSITION_LATENCY:
> +		*val = cppc->transition_latency;
> +		break;
> +	default:
> +		return -1;
> +	}
> +
> +	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:
> +		return -1;
> +	}
> +
> +	return ret;
> +}
> +
> +static int sbi_cppc_test_probe(unsigned long reg)
> +{
> +	switch (reg) {
> +	case SBI_CPPC_DESIRED_PERF:
> +	case SBI_CPPC_PERF_LIMITED:
> +	case SBI_CPPC_HIGHEST_PERF:
> +	case SBI_CPPC_NOMINAL_PERF:
> +	case SBI_CPPC_LOW_NON_LINEAR_PERF:
> +	case SBI_CPPC_LOWEST_PERF:
> +	case SBI_CPPC_REFERENCE_PERF:
> +	case SBI_CPPC_LOWEST_FREQ:
> +	case SBI_CPPC_NOMINAL_FREQ:
> +	case SBI_CPPC_TRANSITION_LATENCY:
> +		return 32;
> +	case SBI_CPPC_REFERENCE_CTR:
> +	case SBI_CPPC_DELIVERED_CTR:
> +		return 64;
> +	case SBI_CPPC_GUARANTEED_PERF:
> +	case SBI_CPPC_MIN_PERF:
> +	case SBI_CPPC_MAX_PERF:
> +	case SBI_CPPC_PERF_REDUC_TOLERANCE:
> +	case SBI_CPPC_TIME_WINDOW:
> +	case SBI_CPPC_CTR_WRAP_TIME:
> +	case SBI_CPPC_ENABLE:
> +	case SBI_CPPC_AUTO_SEL_ENABLE:
> +	case SBI_CPPC_AUTO_ACT_WINDOW:
> +	case SBI_CPPC_ENERGY_PERF_PREFERENCE:
> +		return 0;
> +	}
> +
> +	return -1;

I think there was a misunderstanding as to what I was suggesting for
probe. I was thinking the common probe could handle everything that
doesn't change from the spec itself. There was also a misunderstanding
on what I was thinking for read/write, since they can still return
SBI errors rather than 0/-1. Here's a patch that applies on top of
this series which illustrates what I'm thinking.

diff --git a/lib/sbi/sbi_cppc.c b/lib/sbi/sbi_cppc.c
index b177c9b5151e..4002eb189852 100644
--- a/lib/sbi/sbi_cppc.c
+++ b/lib/sbi/sbi_cppc.c
@@ -73,8 +73,32 @@ int sbi_cppc_probe(unsigned long reg)
 	ret = cppc_dev->cppc_probe(reg);
 	if (ret >= 0)
 		return ret;
-	else
-		return SBI_ERR_FAILED;
+
+	switch (reg) {
+	case SBI_CPPC_HIGHEST_PERF:
+	case SBI_CPPC_NOMINAL_PERF:
+	case SBI_CPPC_LOW_NON_LINEAR_PERF:
+	case SBI_CPPC_LOWEST_PERF:
+	case SBI_CPPC_GUARANTEED_PERF:
+	case SBI_CPPC_DESIRED_PERF:
+	case SBI_CPPC_MIN_PERF:
+	case SBI_CPPC_MAX_PERF:
+	case SBI_CPPC_PERF_REDUC_TOLERANCE:
+	case SBI_CPPC_TIME_WINDOW:
+	case SBI_CPPC_PERF_LIMITED:
+	case SBI_CPPC_ENABLE:
+	case SBI_CPPC_AUTO_SEL_ENABLE:
+	case SBI_CPPC_AUTO_ACT_WINDOW:
+	case SBI_CPPC_ENERGY_PERF_PREFERENCE:
+	case SBI_CPPC_REFERENCE_PERF:
+	case SBI_CPPC_LOWEST_FREQ:
+	case SBI_CPPC_NOMINAL_FREQ:
+	case SBI_CPPC_TRANSITION_LATENCY:
+	case SBI_CPPC_NON_ACPI_LAST:
+		return 32;
+	}
+
+	return SBI_ERR_FAILED;
 }
 
 int sbi_cppc_read(unsigned long reg, uint64_t *val)
@@ -94,10 +118,7 @@ int sbi_cppc_read(unsigned long reg, uint64_t *val)
 	if (!sbi_cppc_readable(reg))
 		return SBI_ERR_DENIED;
 
-	if (!cppc_dev->cppc_read(reg, val))
-		return SBI_SUCCESS;
-	else
-		return SBI_ERR_FAILED;
+	return cppc_dev->cppc_read(reg, val);
 }
 
 int sbi_cppc_write(unsigned long reg, uint64_t val)
@@ -117,8 +138,5 @@ int sbi_cppc_write(unsigned long reg, uint64_t val)
 	if (!sbi_cppc_writable(reg))
 		return SBI_ERR_DENIED;
 
-	if (!cppc_dev->cppc_write(reg, val))
-		return SBI_SUCCESS;
-	else
-		return SBI_ERR_FAILED;
+	return cppc_dev->cppc_write(reg, val);
 }
diff --git a/platform/generic/test_cppc.c b/platform/generic/test_cppc.c
index 91ee187915e0..0c5e076057b5 100644
--- a/platform/generic/test_cppc.c
+++ b/platform/generic/test_cppc.c
@@ -33,7 +33,6 @@ 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();
 
@@ -82,10 +81,10 @@ static int sbi_cppc_test_read(unsigned long reg, uint64_t *val)
 		*val = cppc->transition_latency;
 		break;
 	default:
-		return -1;
+		return SBI_ERR_FAILED;
 	}
 
-	return ret;
+	return SBI_SUCCESS;
 }
 
 static int sbi_cppc_test_write(unsigned long reg, uint64_t val)
@@ -93,7 +92,6 @@ 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();
 
@@ -108,26 +106,15 @@ static int sbi_cppc_test_write(unsigned long reg, uint64_t val)
 		cppc->perf_limited = val;
 		break;
 	default:
-		return -1;
+		return SBI_ERR_FAILED;
 	}
 
-	return ret;
+	return SBI_SUCCESS;
 }
 
 static int sbi_cppc_test_probe(unsigned long reg)
 {
 	switch (reg) {
-	case SBI_CPPC_DESIRED_PERF:
-	case SBI_CPPC_PERF_LIMITED:
-	case SBI_CPPC_HIGHEST_PERF:
-	case SBI_CPPC_NOMINAL_PERF:
-	case SBI_CPPC_LOW_NON_LINEAR_PERF:
-	case SBI_CPPC_LOWEST_PERF:
-	case SBI_CPPC_REFERENCE_PERF:
-	case SBI_CPPC_LOWEST_FREQ:
-	case SBI_CPPC_NOMINAL_FREQ:
-	case SBI_CPPC_TRANSITION_LATENCY:
-		return 32;
 	case SBI_CPPC_REFERENCE_CTR:
 	case SBI_CPPC_DELIVERED_CTR:
 		return 64;


Thanks,
drew
diff mbox series

Patch

diff --git a/include/sbi/sbi_cppc.h b/include/sbi/sbi_cppc.h
index edf73f5..f62d702 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 136853e..d9eb959 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 eeefef4..ef85b70 100644
--- a/platform/generic/platform.c
+++ b/platform/generic/platform.c
@@ -14,6 +14,7 @@ 
 #include <sbi/sbi_platform.h>
 #include <sbi/sbi_string.h>
 #include <sbi/sbi_system.h>
+#include <sbi/sbi_cppc.h>
 #include <sbi_utils/fdt/fdt_domain.h>
 #include <sbi_utils/fdt/fdt_fixup.h>
 #include <sbi_utils/fdt/fdt_helper.h>
@@ -166,6 +167,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 0000000..91ee187
--- /dev/null
+++ b/platform/generic/test_cppc.c
@@ -0,0 +1,204 @@ 
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2023 Ventana Micro Systems Inc.
+ *
+ */
+
+#include <sbi/sbi_ecall_interface.h>
+#include <sbi/sbi_console.h>
+#include <sbi/sbi_cppc.h>
+#include <sbi/sbi_error.h>
+#include <sbi/sbi_scratch.h>
+#include <sbi/sbi_string.h>
+#include <sbi/sbi_timer.h>
+
+struct perf_channel {
+	unsigned int	highest_perf;
+	unsigned int	nominal_perf;
+	unsigned int	lowest_nonlinear_perf;
+	unsigned int	lowest_perf;
+	unsigned int	desired_perf;
+	unsigned int	perf_limited;
+	unsigned int	reference_perf;
+	unsigned int	lowest_freq;
+	unsigned int	nominal_freq;
+	unsigned int	transition_latency;
+};
+
+static unsigned long cppc_offset;
+
+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_HIGHEST_PERF:
+		*val = cppc->highest_perf;
+		break;
+	case SBI_CPPC_NOMINAL_PERF:
+		*val = cppc->nominal_perf;
+		break;
+	case SBI_CPPC_LOW_NON_LINEAR_PERF:
+		*val = cppc->lowest_nonlinear_perf;
+		break;
+	case SBI_CPPC_LOWEST_PERF:
+		*val = cppc->lowest_perf;
+		break;
+	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_REFERENCE_PERF:
+		*val = cppc->reference_perf;
+		break;
+	case SBI_CPPC_LOWEST_FREQ:
+		*val = cppc->lowest_freq;
+		break;
+	case SBI_CPPC_NOMINAL_FREQ:
+		*val = cppc->nominal_freq;
+		break;
+	case SBI_CPPC_TRANSITION_LATENCY:
+		*val = cppc->transition_latency;
+		break;
+	default:
+		return -1;
+	}
+
+	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:
+		return -1;
+	}
+
+	return ret;
+}
+
+static int sbi_cppc_test_probe(unsigned long reg)
+{
+	switch (reg) {
+	case SBI_CPPC_DESIRED_PERF:
+	case SBI_CPPC_PERF_LIMITED:
+	case SBI_CPPC_HIGHEST_PERF:
+	case SBI_CPPC_NOMINAL_PERF:
+	case SBI_CPPC_LOW_NON_LINEAR_PERF:
+	case SBI_CPPC_LOWEST_PERF:
+	case SBI_CPPC_REFERENCE_PERF:
+	case SBI_CPPC_LOWEST_FREQ:
+	case SBI_CPPC_NOMINAL_FREQ:
+	case SBI_CPPC_TRANSITION_LATENCY:
+		return 32;
+	case SBI_CPPC_REFERENCE_CTR:
+	case SBI_CPPC_DELIVERED_CTR:
+		return 64;
+	case SBI_CPPC_GUARANTEED_PERF:
+	case SBI_CPPC_MIN_PERF:
+	case SBI_CPPC_MAX_PERF:
+	case SBI_CPPC_PERF_REDUC_TOLERANCE:
+	case SBI_CPPC_TIME_WINDOW:
+	case SBI_CPPC_CTR_WRAP_TIME:
+	case SBI_CPPC_ENABLE:
+	case SBI_CPPC_AUTO_SEL_ENABLE:
+	case SBI_CPPC_AUTO_ACT_WINDOW:
+	case SBI_CPPC_ENERGY_PERF_PREFERENCE:
+		return 0;
+	}
+
+	return -1;
+}
+
+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_hartid(); 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->highest_perf = 6;
+			cppc->nominal_perf = 5;
+			cppc->lowest_nonlinear_perf = 2;
+			cppc->lowest_perf = 1;
+			cppc->desired_perf = cppc->nominal_perf;
+			cppc->perf_limited = 0;
+			cppc->reference_perf = 20;
+			cppc->lowest_freq = 20;
+			cppc->nominal_freq = 100;
+			cppc->transition_latency = 20000;
+		}
+	}
+
+	sbi_cppc_test_enable();
+
+	return 0;
+}