[RFC PATCH 06/10] powerpc/powernv: opal use new opal call entry point if it exists
Nicholas Piggin
npiggin at gmail.com
Sat May 2 21:19:10 AEST 2020
OPAL may advertise new endian-specific entry point which has different
calling conventions including using the caller's stack, but otherwise
provides the standard OPAL call API without any changes required to
the OS.
Signed-off-by: Nicholas Piggin <npiggin at gmail.com>
---
arch/powerpc/boot/opal.c | 5 +++
arch/powerpc/platforms/powernv/opal-call.c | 36 ++++++++++++++++++++++
arch/powerpc/platforms/powernv/opal.c | 30 +++++++++++-------
3 files changed, 60 insertions(+), 11 deletions(-)
diff --git a/arch/powerpc/boot/opal.c b/arch/powerpc/boot/opal.c
index b69818ce592b..8b006a0282ac 100644
--- a/arch/powerpc/boot/opal.c
+++ b/arch/powerpc/boot/opal.c
@@ -13,6 +13,7 @@
struct opal {
u64 base;
u64 entry;
+ u64 v4_le_entry;
} opal;
static u32 opal_con_id;
@@ -75,6 +76,10 @@ static void opal_init(void)
if (getprop(opal_node, "opal-entry-address", &opal.entry, sizeof(u64)) < 0)
return;
opal.entry = be64_to_cpu(opal.entry);
+
+ if (getprop(opal_node, "opal-v4-le-entry-address", &opal.v4_le_entry, sizeof(u64)) < 0)
+ return;
+ opal.v4_le_entry = be64_to_cpu(opal.v4_le_entry);
}
int opal_console_init(void *devp, struct serial_console_data *scdp)
diff --git a/arch/powerpc/platforms/powernv/opal-call.c b/arch/powerpc/platforms/powernv/opal-call.c
index 506b1798081a..32857254d268 100644
--- a/arch/powerpc/platforms/powernv/opal-call.c
+++ b/arch/powerpc/platforms/powernv/opal-call.c
@@ -92,6 +92,18 @@ static s64 __opal_call_trace(s64 a0, s64 a1, s64 a2, s64 a3,
#define DO_TRACE false
#endif /* CONFIG_TRACEPOINTS */
+struct opal {
+ u64 base;
+ u64 entry;
+ u64 size;
+ u64 v4_le_entry;
+};
+extern struct opal opal;
+
+typedef int64_t (*opal_v4_le_entry_fn)(uint64_t r3, uint64_t r4, uint64_t r5,
+ uint64_t r6, uint64_t r7, uint64_t r8,
+ uint64_t r9, uint64_t r10);
+
static int64_t opal_call(int64_t a0, int64_t a1, int64_t a2, int64_t a3,
int64_t a4, int64_t a5, int64_t a6, int64_t a7, int64_t opcode)
{
@@ -99,6 +111,30 @@ static int64_t opal_call(int64_t a0, int64_t a1, int64_t a2, int64_t a3,
unsigned long msr = mfmsr();
bool mmu = (msr & (MSR_IR|MSR_DR));
int64_t ret;
+ opal_v4_le_entry_fn fn;
+
+ if (IS_ENABLED(CONFIG_CPU_LITTLE_ENDIAN))
+ fn = (opal_v4_le_entry_fn)(opal.v4_le_entry);
+
+ if (fn) {
+ if (!mmu) {
+ BUG_ON(msr & MSR_EE);
+ ret = fn(opcode, a0, a1, a2, a3, a4, a5, a6);
+ return ret;
+ }
+
+ local_irq_save(flags);
+ hard_irq_disable(); /* XXX r13 */
+ msr &= ~MSR_EE;
+ mtmsr(msr & ~(MSR_IR|MSR_DR));
+
+ ret = fn(opcode, a0, a1, a2, a3, a4, a5, a6);
+
+ mtmsr(msr);
+ local_irq_restore(flags);
+
+ return ret;
+ }
msr &= ~MSR_EE;
diff --git a/arch/powerpc/platforms/powernv/opal.c b/arch/powerpc/platforms/powernv/opal.c
index a0e9808237b2..d00772d40680 100644
--- a/arch/powerpc/platforms/powernv/opal.c
+++ b/arch/powerpc/platforms/powernv/opal.c
@@ -46,13 +46,14 @@ static DEFINE_SPINLOCK(msg_list_lock);
static LIST_HEAD(msg_list);
/* /sys/firmware/opal */
-struct kobject *opal_kobj;
+struct kobject *opal_kobj __read_mostly;
struct opal {
u64 base;
u64 entry;
u64 size;
-} opal;
+ u64 v4_le_entry;
+} opal __read_mostly;
struct mcheck_recoverable_range {
u64 start_addr;
@@ -150,14 +151,15 @@ unsigned long arch_symbol_lookup_name(const char *name)
int __init early_init_dt_scan_opal(unsigned long node,
const char *uname, int depth, void *data)
{
- const void *basep, *entryp, *sizep;
- int basesz, entrysz, runtimesz;
+ const void *basep, *entryp, *v4_le_entryp, *sizep;
+ int basesz, entrysz, v4_le_entrysz, runtimesz;
if (depth != 1 || strcmp(uname, "ibm,opal") != 0)
return 0;
basep = of_get_flat_dt_prop(node, "opal-base-address", &basesz);
entryp = of_get_flat_dt_prop(node, "opal-entry-address", &entrysz);
+ v4_le_entryp = of_get_flat_dt_prop(node, "opal-v4-le-entry-address", &v4_le_entrysz);
sizep = of_get_flat_dt_prop(node, "opal-runtime-size", &runtimesz);
if (!basep || !entryp || !sizep)
@@ -166,19 +168,25 @@ int __init early_init_dt_scan_opal(unsigned long node,
opal.base = of_read_number(basep, basesz/4);
opal.entry = of_read_number(entryp, entrysz/4);
opal.size = of_read_number(sizep, runtimesz/4);
+ opal.v4_le_entry = of_read_number(v4_le_entryp, v4_le_entrysz/4);
+
+ if (of_flat_dt_is_compatible(node, "ibm,opal-v3")) {
+ powerpc_firmware_features |= FW_FEATURE_OPAL;
+ pr_debug("OPAL detected !\n");
+ } else {
+ panic("OPAL v3 compatible firmware not detected, can not continue.\n");
+ }
pr_debug("OPAL Base = 0x%llx (basep=%p basesz=%d)\n",
opal.base, basep, basesz);
- pr_debug("OPAL Entry = 0x%llx (entryp=%p basesz=%d)\n",
+ pr_debug("OPAL Entry = 0x%llx (entryp=%p entrysz=%d)\n",
opal.entry, entryp, entrysz);
- pr_debug("OPAL Entry = 0x%llx (sizep=%p runtimesz=%d)\n",
+ pr_debug("OPAL Size = 0x%llx (sizep=%p runtimesz=%d)\n",
opal.size, sizep, runtimesz);
+ if (IS_ENABLED(CONFIG_CPU_LITTLE_ENDIAN) && v4_le_entryp) {
- if (of_flat_dt_is_compatible(node, "ibm,opal-v3")) {
- powerpc_firmware_features |= FW_FEATURE_OPAL;
- pr_debug("OPAL detected !\n");
- } else {
- panic("OPAL != V3 detected, no longer supported.\n");
+ pr_debug("OPAL v4 Entry = 0x%llx (v4_le_entryp=%p v4_le_entrysz=%d)\n",
+ opal.v4_le_entry, v4_le_entryp, v4_le_entrysz);
}
return 1;
--
2.23.0
More information about the Linuxppc-dev
mailing list