diff mbox series

[RFC] OPAL v4 cpu idle driver skeleton

Message ID 20191212041237.24401-1-npiggin@gmail.com
State New
Headers show
Series [RFC] OPAL v4 cpu idle driver skeleton | expand

Checks

Context Check Description
snowpatch_ozlabs/apply_patch warning Failed to apply on branch master (d75e82dbfbb9443efeb3f9a5921ac23605aab469)
snowpatch_ozlabs/apply_patch fail Failed to apply to any branch

Commit Message

Nicholas Piggin Dec. 12, 2019, 4:12 a.m. UTC
With OPAL using the same endianness, same stack, and with OS
callbacks, it looks relatively easy to provide a CPU idle driver.

The Linux sreset interrupt won't have to change, if it registers
almost like isa300_idle_stop_mayloss as the os_stop function,
then skiboot will call that to stop, and it will return like a
normal function call returning the srr1 wakeup value.

This allows the firmware to deal with supported stop states and
psscr and consequences for saving and restoring various resources,
and the kernel can implement a simple OPAL idle driver which has
some interface like wakeup latency requested or something.

Calls in and out of OPAL (once it's running with MMU=on) are not
much more expensive calling a function in a kernel module, so
performance should be okay. Kernel can still choose to implement
an optimised CPU specific driver as it does today.

The patch is just a hack with no actual policy or SPR saving in
it at the moment and only does stop0, but illustrates the mechanism.

Thanks,
Nick
---
 core/Makefile.inc       |  2 +-
 core/opal.c             |  3 +++
 core/stop.c             | 35 +++++++++++++++++++++++++++++++++++
 include/opal-api.h      | 10 ++++++----
 include/opal-internal.h |  1 +
 5 files changed, 46 insertions(+), 5 deletions(-)
 create mode 100644 core/stop.c

Comments

Abhishek Goel Jan. 30, 2020, 6:54 a.m. UTC | #1
Hi Nicholas,

On 12/12/2019 09:42 AM, Nicholas Piggin wrote:
> With OPAL using the same endianness, same stack, and with OS
> callbacks, it looks relatively easy to provide a CPU idle driver.
>
> The Linux sreset interrupt won't have to change, if it registers
> almost like isa300_idle_stop_mayloss as the os_stop function,
> then skiboot will call that to stop, and it will return like a
> normal function call returning the srr1 wakeup value.
>
> This allows the firmware to deal with supported stop states and
> psscr and consequences for saving and restoring various resources,
> and the kernel can implement a simple OPAL idle driver which has
> some interface like wakeup latency requested or something.

Governor will request a stop state based on historic idle value.
And the cpuidle driver will call the platform idle code with psscr set
based on stop state requested.
I am not sure of using wakeup latency. Am I missing something
here?
>
> Calls in and out of OPAL (once it's running with MMU=on) are not
> much more expensive calling a function in a kernel module, so
> performance should be okay. Kernel can still choose to implement
> an optimised CPU specific driver as it does today.
>
> The patch is just a hack with no actual policy or SPR saving in
> it at the moment and only does stop0, but illustrates the mechanism.
>
> Thanks,
> Nick
> ---

Thanks,
Abhishek
Nicholas Piggin Feb. 19, 2020, 10:57 a.m. UTC | #2
Abhishek's on January 30, 2020 4:54 pm:
> Hi Nicholas,
> 
> On 12/12/2019 09:42 AM, Nicholas Piggin wrote:
>> With OPAL using the same endianness, same stack, and with OS
>> callbacks, it looks relatively easy to provide a CPU idle driver.
>>
>> The Linux sreset interrupt won't have to change, if it registers
>> almost like isa300_idle_stop_mayloss as the os_stop function,
>> then skiboot will call that to stop, and it will return like a
>> normal function call returning the srr1 wakeup value.
>>
>> This allows the firmware to deal with supported stop states and
>> psscr and consequences for saving and restoring various resources,
>> and the kernel can implement a simple OPAL idle driver which has
>> some interface like wakeup latency requested or something.
> 
> Governor will request a stop state based on historic idle value.
> And the cpuidle driver will call the platform idle code with psscr set
> based on stop state requested.
> I am not sure of using wakeup latency. Am I missing something
> here?

Was on vacation, thanks for waiting.

A Linux cpuidle driver for this OPAL API would not set PSSCR, it
would just use latencies based on historic idle values. We could
expose a little more information about levels or latencies or
change the API slightly, but the idea would be to hide all details
of PSSCR.

Thanks,
Nick
diff mbox series

Patch

diff --git a/core/Makefile.inc b/core/Makefile.inc
index cc90fb958..653ca544e 100644
--- a/core/Makefile.inc
+++ b/core/Makefile.inc
@@ -7,7 +7,7 @@  CORE_OBJS = relocate.o console.o stack.o init.o chip.o mem_region.o vm.o
 CORE_OBJS += malloc.o lock.o cpu.o utils.o fdt.o opal.o interrupts.o timebase.o
 CORE_OBJS += opal-msg.o pci.o pci-virt.o pci-slot.o pcie-slot.o
 CORE_OBJS += pci-opal.o fast-reboot.o device.o exceptions.o trace.o affinity.o
-CORE_OBJS += vpd.o platform.o nvram.o nvram-format.o hmi.o mce.o
+CORE_OBJS += vpd.o platform.o nvram.o nvram-format.o hmi.o mce.o stop.o
 CORE_OBJS += console-log.o ipmi.o time-utils.o pel.o pool.o errorlog.o
 CORE_OBJS += timer.o i2c.o rtc.o flash.o sensor.o ipmi-opal.o
 CORE_OBJS += flash-subpartition.o bitmap.o buddy.o pci-quirk.o powercap.o psr.o
diff --git a/core/opal.c b/core/opal.c
index bb88d7710..d5c1d057b 100644
--- a/core/opal.c
+++ b/core/opal.c
@@ -444,6 +444,9 @@  static int64_t opal_register_opal_ops(struct opal_os_ops *__os_ops)
 	/* v4 must provide printf */
 	os_ops.os_printf = (void *)be64_to_cpu(__os_ops->os_printf);
 
+	/* v4 may provide stop (or NULL) */
+	os_ops.os_stop = (void *)be64_to_cpu(__os_ops->os_stop);
+
 	set_opal_console_to_raw();
 
 	checksum_romem();
diff --git a/core/stop.c b/core/stop.c
new file mode 100644
index 000000000..6d98d68e6
--- /dev/null
+++ b/core/stop.c
@@ -0,0 +1,35 @@ 
+// SPDX-License-Identifier: Apache-2.0
+/*
+ * Stop idle driver
+ *
+ * Copyright 2019 IBM Corp.
+ */
+
+#define pr_fmt(fmt)	"IDLE: " fmt
+
+#include <skiboot.h>
+#include <opal.h>
+#include <processor.h>
+#include <cpu.h>
+#include <cpu.h>
+
+static int64_t opal_cpu_idle(uint64_t latency, bool radix, __be64 *srr1)
+{
+	uint64_t psscr;
+
+	if (!os_ops.os_stop)
+		return OPAL_UNSUPPORTED;
+
+	if (proc_gen != proc_gen_p9)
+		return OPAL_UNSUPPORTED;
+
+	(void)latency;
+	(void)radix;
+	psscr = OPAL_PM_PSSCR_RL(0) \
+		 | OPAL_PM_PSSCR_MTL(3) \
+		 | OPAL_PM_PSSCR_TR(3);
+	*srr1 = os_ops.os_stop(psscr, true);
+
+	return OPAL_SUCCESS;
+}
+opal_call(OPAL_CPU_IDLE, opal_cpu_idle, 3);
diff --git a/include/opal-api.h b/include/opal-api.h
index 169061a26..03f323628 100644
--- a/include/opal-api.h
+++ b/include/opal-api.h
@@ -231,6 +231,7 @@ 
 #define OPAL_LOOKUP_SYMBOL			182
 #define OPAL_REGISTER_OS_OPS			183
 #define OPAL_HANDLE_MCE				184
+#define OPAL_CPU_IDLE				185
 #define OPAL_LAST				184
 
 #define QUIESCE_HOLD			1 /* Spin all calls at entry */
@@ -1259,10 +1260,11 @@  struct opal_mpipl_fadump {
 };
 
 struct opal_os_ops {
-        __be16  version;
-        __be16  reserved0;
-        __be32  reserved1;
-        __be64  os_printf;      /* void printf(int32_t level, const char *str) */
+	__be16  version;
+	__be16  reserved0;
+	__be32  reserved1;
+	__be64  os_printf;	/* void printf(int32_t level, const char *str) */
+	__be64	os_stop;	/* uint64_t stop(uint64_t psscr, bool save_gprs) */
 };
 
 #define MCE_HANDLE_CORRECT		0x0001	/* Attempt to correct */
diff --git a/include/opal-internal.h b/include/opal-internal.h
index cd968a0fe..2baf79a53 100644
--- a/include/opal-internal.h
+++ b/include/opal-internal.h
@@ -20,6 +20,7 @@  struct opal_table_entry {
 
 struct os_ops {
         void (*os_printf)(uint32_t log_level, const char *str);
+	uint64_t (*os_stop)(uint64_t psscr, bool save_gprs);
 };
 
 extern bool opal_v4_os;