[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