@@ -23,14 +23,7 @@
/* The cpu_threads array is static and indexed by PIR in
* order to speed up lookup from asm entry points
*/
-struct cpu_stack {
- union {
- uint8_t stack[STACK_SIZE];
- struct cpu_thread cpu;
- };
-} __align(STACK_SIZE);
-
-static struct cpu_stack * const cpu_stacks = (struct cpu_stack *)CPU_STACKS_BASE;
+struct cpu_stack * const cpu_stacks = (struct cpu_stack *)CPU_STACKS_BASE;
unsigned int cpu_thread_count;
unsigned int cpu_max_pir;
struct cpu_thread *boot_cpu;
@@ -371,6 +371,33 @@ static void add_opal_firmware_node(void)
add_opal_firmware_exports_node(firmware);
}
+typedef int64_t (*opal_call_fn)(uint64_t r3, uint64_t r4, uint64_t r5,
+ uint64_t r6, uint64_t r7, uint64_t r8,
+ uint64_t r9);
+
+static int64_t opal_v4_le_entry(uint64_t r3, uint64_t r4, uint64_t r5,
+ uint64_t r6, uint64_t r7, uint64_t r8,
+ uint64_t r9, uint64_t r10)
+{
+ opal_call_fn *fn;
+ uint64_t pir;
+ uint64_t r16;
+
+ pir = mfspr(SPR_PIR);
+ r16 = (uint64_t)__this_cpu;
+ __this_cpu = &cpu_stacks[pir].cpu;
+
+ assert(!(mfmsr() & (MSR_IR|MSR_DR|MSR_EE)));
+
+ fn = (opal_call_fn *)(&opal_branch_table[r3]);
+
+ r3 = (*fn)(r4, r5, r6, r7, r8, r9, r10);
+
+ __this_cpu = (struct cpu_thread *)r16;
+
+ return r3;
+}
+
void add_opal_node(void)
{
uint64_t base, entry, size;
@@ -395,16 +422,24 @@ void add_opal_node(void)
dt_add_property_cells(opal_node, "#address-cells", 0);
dt_add_property_cells(opal_node, "#size-cells", 0);
- if (proc_gen < proc_gen_p9)
+ if (proc_gen < proc_gen_p9) {
dt_add_property_strings(opal_node, "compatible", "ibm,opal-v2",
"ibm,opal-v3");
- else
+ } else if (HAVE_LITTLE_ENDIAN) {
+ dt_add_property_strings(opal_node, "compatible", "ibm,opal-v3",
+ "ibm,opal-v4");
+ } else {
dt_add_property_strings(opal_node, "compatible", "ibm,opal-v3");
+ }
dt_add_property_cells(opal_node, "opal-msg-async-num", OPAL_MAX_ASYNC_COMP);
dt_add_property_cells(opal_node, "opal-msg-size", OPAL_MSG_SIZE);
dt_add_property_u64(opal_node, "opal-base-address", base);
dt_add_property_u64(opal_node, "opal-entry-address", entry);
+ if (HAVE_LITTLE_ENDIAN) {
+ dt_add_property_u64(opal_node, "opal-v4-le-entry-address",
+ (uint64_t)&opal_v4_le_entry);
+ }
dt_add_property_u64(opal_node, "opal-boot-address", (uint64_t)&boot_entry);
dt_add_property_u64(opal_node, "opal-runtime-size", size);
@@ -211,6 +211,15 @@ extern u8 get_available_nr_cores_in_chip(u32 chip_id);
for (core = first_available_core_in_chip(chip_id); core; \
core = next_available_core_in_chip(core, chip_id))
+struct cpu_stack {
+ union {
+ uint8_t stack[STACK_SIZE];
+ struct cpu_thread cpu;
+ };
+} __align(STACK_SIZE);
+
+struct cpu_stack * const cpu_stacks;
+
/* Return the caller CPU (only after init_cpu_threads) */
register struct cpu_thread *__this_cpu asm("r16");
static inline __nomcount struct cpu_thread *this_cpu(void)