Message ID | 20191212041237.24401-1-npiggin@gmail.com |
---|---|
State | New |
Headers | show |
Series | [RFC] OPAL v4 cpu idle driver skeleton | expand |
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 |
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
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 --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;