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 <npig...@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