[RFC PATCH 09/10] powerpc/powernv: OPAL V4 OS services
Nicholas Piggin
npiggin at gmail.com
Sat May 2 21:19:13 AEST 2020
This implements OPAL_REGISTER_OS_OPS and implements the printf
service.
When this API is called, OPAL switches to V4 mode which requires
the OS to subsequently handle its program interrupts and printf
calls.
Signed-off-by: Nicholas Piggin <npiggin at gmail.com>
---
arch/powerpc/include/asm/opal-api.h | 7 ++++-
arch/powerpc/include/asm/opal.h | 1 +
arch/powerpc/platforms/powernv/opal-call.c | 1 +
arch/powerpc/platforms/powernv/opal.c | 36 ++++++++++++++++++++++
4 files changed, 44 insertions(+), 1 deletion(-)
diff --git a/arch/powerpc/include/asm/opal-api.h b/arch/powerpc/include/asm/opal-api.h
index 0be5ff4e51b5..1b2f176677fc 100644
--- a/arch/powerpc/include/asm/opal-api.h
+++ b/arch/powerpc/include/asm/opal-api.h
@@ -218,7 +218,8 @@
#define OPAL_SYM_TO_ADDR 182
#define OPAL_REPORT_TRAP 183
#define OPAL_FIND_VM_AREA 184
-#define OPAL_LAST 184
+#define OPAL_REGISTER_OS_OPS 185
+#define OPAL_LAST 185
#define QUIESCE_HOLD 1 /* Spin all calls at entry */
#define QUIESCE_REJECT 2 /* Fail all calls with OPAL_BUSY */
@@ -1202,6 +1203,10 @@ struct opal_vm_area {
__be64 vm_flags;
};
+struct opal_os_ops {
+ __be64 os_printf; /* void printf(int32_t level, const char *str) */
+};
+
#endif /* __ASSEMBLY__ */
#endif /* __OPAL_API_H */
diff --git a/arch/powerpc/include/asm/opal.h b/arch/powerpc/include/asm/opal.h
index 199b5582b700..09985b7718b3 100644
--- a/arch/powerpc/include/asm/opal.h
+++ b/arch/powerpc/include/asm/opal.h
@@ -406,6 +406,7 @@ void opal_psr_init(void);
void opal_sensor_groups_init(void);
int64_t opal_find_vm_area(uint64_t addr, struct opal_vm_area *opal_vm_area);
+int64_t opal_register_os_ops(struct opal_os_ops *ops, uint64_t size);
#endif /* __ASSEMBLY__ */
diff --git a/arch/powerpc/platforms/powernv/opal-call.c b/arch/powerpc/platforms/powernv/opal-call.c
index 4bdad3d2fa18..11f419e76059 100644
--- a/arch/powerpc/platforms/powernv/opal-call.c
+++ b/arch/powerpc/platforms/powernv/opal-call.c
@@ -350,3 +350,4 @@ OPAL_CALL(opal_addr_to_sym, OPAL_ADDR_TO_SYM);
OPAL_CALL(opal_sym_to_addr, OPAL_SYM_TO_ADDR);
OPAL_CALL(opal_report_trap, OPAL_REPORT_TRAP);
OPAL_CALL(opal_find_vm_area, OPAL_FIND_VM_AREA);
+OPAL_CALL(opal_register_os_ops, OPAL_REGISTER_OS_OPS);
diff --git a/arch/powerpc/platforms/powernv/opal.c b/arch/powerpc/platforms/powernv/opal.c
index 98d6d7fc5411..0fbfcd088c58 100644
--- a/arch/powerpc/platforms/powernv/opal.c
+++ b/arch/powerpc/platforms/powernv/opal.c
@@ -47,6 +47,7 @@ static LIST_HEAD(msg_list);
struct mm_struct *opal_mm __read_mostly;
bool opal_v4_present __read_mostly;
+bool opal_v4_enabled __read_mostly;
bool opal_mm_enabled __read_mostly;
/* /sys/firmware/opal */
@@ -152,6 +153,8 @@ unsigned long arch_symbol_lookup_name(const char *name)
return be64_to_cpu(addr);
}
+static void os_printf(int32_t level, const char *str);
+
int __init early_init_dt_scan_opal(unsigned long node,
const char *uname, int depth, void *data)
{
@@ -1045,6 +1048,28 @@ static void opal_init_heartbeat(void)
kopald_tsk = kthread_run(kopald, NULL, "kopald");
}
+static void os_printf(int32_t level, const char *str)
+{
+ const char *l;
+
+ /* Assuming printk does not work in real mode */
+ if (WARN_ON_ONCE(!(mfmsr() & (MSR_IR|MSR_DR))))
+ return;
+
+ switch (level) {
+ case 0: l = KERN_EMERG; break;
+ case 1: l = KERN_ALERT; break;
+ case 2: l = KERN_CRIT; break;
+ case 3: l = KERN_ERR; break;
+ case 4: l = KERN_WARNING; break;
+ case 5: l = KERN_NOTICE; break;
+ case 6: l = KERN_INFO; break;
+ case 7: l = KERN_DEBUG; break;
+ default: l = KERN_ERR;
+ }
+ printk("%s[OPAL] %s", l, str);
+}
+
static pgprot_t opal_vm_flags_to_prot(uint64_t flags)
{
pgprot_t prot;
@@ -1137,6 +1162,8 @@ static int __init opal_init_early(void)
int rc;
if (opal_v4_present) {
+ struct opal_os_ops opal_os_ops;
+
if (radix_enabled()) {
/* Hash can't resolve SLB faults to the switched mm */
rc = opal_init_mm();
@@ -1144,6 +1171,15 @@ static int __init opal_init_early(void)
pr_warn("OPAL virtual memory init failed, firmware will run in real-mode.\n");
}
}
+
+ memset(&opal_os_ops, 0, sizeof(opal_os_ops));
+ opal_os_ops.os_printf = cpu_to_be64(&os_printf);
+ if (opal_register_os_ops(&opal_os_ops, sizeof(opal_os_ops))) {
+ pr_warn("OPAL register OS ops failed, firmware will run in v3 mode.\n");
+ } else {
+ opal_v4_enabled = true;
+ pr_warn("OPAL running in v4 mode!\n");
+ }
}
return 0;
--
2.23.0
More information about the Linuxppc-dev
mailing list