diff mbox series

[4/4] xen/ppc: Implement early serial console on PowerNV

Message ID 3176762c2eb09d01d65a348e296a94cf0356ff46.1690934409.git.sanastasio@raptorengineering.com (mailing list archive)
State New, archived
Headers show
Series xen/ppc: Add PowerNV bare metal support | expand

Commit Message

Shawn Anastasio Aug. 2, 2023, 12:11 a.m. UTC
Implement the OPAL firmware calls required to write to the serial
console on PowerNV systems. Unlike pseries/Open Firmware, the OPAL
firmware interface can be used past early boot and as such the relevant
functions are not marked as __init.

Signed-off-by: Shawn Anastasio <sanastasio@raptorengineering.com>
---
Changed in v2:
  - Include asm-offsets in asm-defns.h
  - Clean up assembly formatting in asm-defns.h
  - Clean up formatting of opal.c
  - Clean up stray semicolon in OPAL_CALL macro in opal-calls.S

 xen/arch/ppc/include/asm/asm-defns.h | 18 ++++++-
 xen/arch/ppc/opal.c                  | 28 +++++++++-
 xen/arch/ppc/ppc64/Makefile          |  1 +
 xen/arch/ppc/ppc64/asm-offsets.c     |  4 ++
 xen/arch/ppc/ppc64/opal-calls.S      | 81 ++++++++++++++++++++++++++++
 5 files changed, 129 insertions(+), 3 deletions(-)
 create mode 100644 xen/arch/ppc/ppc64/opal-calls.S

--
2.30.2

Comments

Jan Beulich Aug. 7, 2023, 3:05 p.m. UTC | #1
On 02.08.2023 02:11, Shawn Anastasio wrote:
> Implement the OPAL firmware calls required to write to the serial
> console on PowerNV systems. Unlike pseries/Open Firmware, the OPAL
> firmware interface can be used past early boot and as such the relevant
> functions are not marked as __init.
> 
> Signed-off-by: Shawn Anastasio <sanastasio@raptorengineering.com>

Constraint as before and with two nits
Acked-by: Jan Beulich <jbeulich@suse.com>

> @@ -20,8 +22,20 @@
>   * Load the address of a symbol from the TOC into the specified GPR.
>   */
>  #define LOAD_REG_ADDR(reg,name)                                              \
> -    addis reg,%r2,name@toc@ha;                                               \
> -    addi  reg,reg,name@toc@l
> +    addis reg, %r2, name@toc@ha;                                             \
> +    addi  reg, reg, name@toc@l
> +
> +/*
> + * Declare a global assembly function with a proper TOC setup prologue
> + */
> +#define _GLOBAL_TOC(name)                                                   \
> +    .balign 4;                                                              \
> +    .type name, @function;                                                  \
> +    .globl name;                                                            \
> +name:                                                                       \
> +0:  addis %r2, %r12, (.TOC.-0b)@ha;                                         \
> +    addi  %r2, %r2, (.TOC.-0b)@l;                                           \

Strictly speaking the - want surrounding by blanks, but I wonder whether
to PPC eyes these constructs look more natural without. Please clarify.

> --- /dev/null
> +++ b/xen/arch/ppc/ppc64/opal-calls.S
> @@ -0,0 +1,81 @@
> +/* SPDX-License-Identifier: GPL-2.0-or-later */
> +/*
> + * Adapted from Linux's arch/powerpc/boot/opal-calls.S
> + *
> + * Copyright (c) 2016 IBM Corporation.
> + * Copyright Raptor Engineering, LLC
> + */
> +
> +#include <asm/asm-defns.h>
> +#include <asm/opal-api.h>
> +#include <asm/msr.h>
> +
> +    .text
> +
> +#define OPAL_CALL(name, token)  \
> +    .globl name;                \
> +name:                           \
> +    li      %r0, token;         \
> +    b       opal_call
> +
> + _GLOBAL_TOC(opal_call)

Any reason for the leading blank here?

Where necessary I again think these small items can be taken care of
while committing.

Jan
Shawn Anastasio Aug. 7, 2023, 4:11 p.m. UTC | #2
On 8/7/23 10:05 AM, Jan Beulich wrote:
> On 02.08.2023 02:11, Shawn Anastasio wrote:
>> Implement the OPAL firmware calls required to write to the serial
>> console on PowerNV systems. Unlike pseries/Open Firmware, the OPAL
>> firmware interface can be used past early boot and as such the relevant
>> functions are not marked as __init.
>>
>> Signed-off-by: Shawn Anastasio <sanastasio@raptorengineering.com>
> 
> Constraint as before and with two nits
> Acked-by: Jan Beulich <jbeulich@suse.com>
> 
>> @@ -20,8 +22,20 @@
>>   * Load the address of a symbol from the TOC into the specified GPR.
>>   */
>>  #define LOAD_REG_ADDR(reg,name)                                              \
>> -    addis reg,%r2,name@toc@ha;                                               \
>> -    addi  reg,reg,name@toc@l
>> +    addis reg, %r2, name@toc@ha;                                             \
>> +    addi  reg, reg, name@toc@l
>> +
>> +/*
>> + * Declare a global assembly function with a proper TOC setup prologue
>> + */
>> +#define _GLOBAL_TOC(name)                                                   \
>> +    .balign 4;                                                              \
>> +    .type name, @function;                                                  \
>> +    .globl name;                                                            \
>> +name:                                                                       \
>> +0:  addis %r2, %r12, (.TOC.-0b)@ha;                                         \
>> +    addi  %r2, %r2, (.TOC.-0b)@l;                                           \
> 
> Strictly speaking the - want surrounding by blanks, but I wonder whether
> to PPC eyes these constructs look more natural without. Please clarify.

This is admittedly very subjective, but to my eyes the code as-is looks
perfectly natural. That said, I wouldn't be opposed to adding spaces if
that's what you prefer.

>> --- /dev/null
>> +++ b/xen/arch/ppc/ppc64/opal-calls.S
>> @@ -0,0 +1,81 @@
>> +/* SPDX-License-Identifier: GPL-2.0-or-later */
>> +/*
>> + * Adapted from Linux's arch/powerpc/boot/opal-calls.S
>> + *
>> + * Copyright (c) 2016 IBM Corporation.
>> + * Copyright Raptor Engineering, LLC
>> + */
>> +
>> +#include <asm/asm-defns.h>
>> +#include <asm/opal-api.h>
>> +#include <asm/msr.h>
>> +
>> +    .text
>> +
>> +#define OPAL_CALL(name, token)  \
>> +    .globl name;                \
>> +name:                           \
>> +    li      %r0, token;         \
>> +    b       opal_call
>> +
>> + _GLOBAL_TOC(opal_call)
> 
> Any reason for the leading blank here?

No -- that was a mistake on my part.

> 
> Where necessary I again think these small items can be taken care of
> while committing.

Sounds good.

> Jan

Thanks,
Shawn
diff mbox series

Patch

diff --git a/xen/arch/ppc/include/asm/asm-defns.h b/xen/arch/ppc/include/asm/asm-defns.h
index 5821f9024d..f1c49808bd 100644
--- a/xen/arch/ppc/include/asm/asm-defns.h
+++ b/xen/arch/ppc/include/asm/asm-defns.h
@@ -2,6 +2,8 @@ 
 #ifndef _ASM_PPC_ASM_DEFNS_H
 #define _ASM_PPC_ASM_DEFNS_H

+#include <asm/asm-offsets.h>
+
 /*
  * Load a 64-bit immediate value into the specified GPR.
  */
@@ -20,8 +22,20 @@ 
  * Load the address of a symbol from the TOC into the specified GPR.
  */
 #define LOAD_REG_ADDR(reg,name)                                              \
-    addis reg,%r2,name@toc@ha;                                               \
-    addi  reg,reg,name@toc@l
+    addis reg, %r2, name@toc@ha;                                             \
+    addi  reg, reg, name@toc@l
+
+/*
+ * Declare a global assembly function with a proper TOC setup prologue
+ */
+#define _GLOBAL_TOC(name)                                                   \
+    .balign 4;                                                              \
+    .type name, @function;                                                  \
+    .globl name;                                                            \
+name:                                                                       \
+0:  addis %r2, %r12, (.TOC.-0b)@ha;                                         \
+    addi  %r2, %r2, (.TOC.-0b)@l;                                           \
+    .localentry name, .-name

 /*
  * Depending on how we were booted, the CPU could be running in either
diff --git a/xen/arch/ppc/opal.c b/xen/arch/ppc/opal.c
index 251de8ac23..1183b7d5ef 100644
--- a/xen/arch/ppc/opal.c
+++ b/xen/arch/ppc/opal.c
@@ -8,9 +8,29 @@ 
 #include <xen/init.h>
 #include <xen/lib.h>

-/* Global OPAL struct containing entrypoint and base */
+/* Global OPAL struct containing entrypoint and base used by opal-calls.S */
 struct opal opal;

+int64_t opal_console_write(int64_t term_number, uint64_t *length,
+                           const void *buffer);
+int64_t opal_console_flush(int64_t term_number);
+int64_t opal_reinit_cpus(uint64_t flags);
+
+static void opal_putchar(char c)
+{
+    uint64_t len;
+
+    if ( c == '\n' )
+    {
+        char buf = '\r';
+        len = cpu_to_be64(1);
+        opal_console_write(0, &len, &buf);
+    }
+    len = cpu_to_be64(1);
+    opal_console_write(0, &len, &c);
+    opal_console_flush(0);
+}
+
 void __init boot_opal_init(const void *fdt)
 {
     int opal_node;
@@ -45,4 +65,10 @@  void __init boot_opal_init(const void *fdt)

     opal.base = be64_to_cpu(*opal_base);
     opal.entry = be64_to_cpu(*opal_entry);
+
+    early_printk_init(opal_putchar);
+
+    /* Ask OPAL to set HID0 for Little Endian interrupts + Radix TLB support */
+    opal_reinit_cpus(OPAL_REINIT_CPUS_HILE_LE | OPAL_REINIT_CPUS_MMU_RADIX |
+                     OPAL_REINIT_CPUS_MMU_HASH);
 }
diff --git a/xen/arch/ppc/ppc64/Makefile b/xen/arch/ppc/ppc64/Makefile
index f4956daaa9..b9a91dc15f 100644
--- a/xen/arch/ppc/ppc64/Makefile
+++ b/xen/arch/ppc/ppc64/Makefile
@@ -1,2 +1,3 @@ 
 obj-y += head.o
 obj-y += of-call.o
+obj-y += opal-calls.o
diff --git a/xen/arch/ppc/ppc64/asm-offsets.c b/xen/arch/ppc/ppc64/asm-offsets.c
index e1129cb0f4..c15c1bf136 100644
--- a/xen/arch/ppc/ppc64/asm-offsets.c
+++ b/xen/arch/ppc/ppc64/asm-offsets.c
@@ -6,6 +6,7 @@ 

 #include <xen/macros.h>
 #include <asm/processor.h>
+#include <asm/boot.h>

 #define DEFINE(_sym, _val)                                                  \
     asm volatile ( "\n.ascii\"==>#define " #_sym " %0 /* " #_val " */<==\"" \
@@ -46,6 +47,9 @@  void __dummy__(void)
     OFFSET(UREGS_cr, struct cpu_user_regs, cr);
     OFFSET(UREGS_fpscr, struct cpu_user_regs, fpscr);
     DEFINE(UREGS_sizeof, sizeof(struct cpu_user_regs));
+
+    OFFSET(OPAL_base, struct opal, base);
+    OFFSET(OPAL_entry, struct opal, entry);
 }

 /*
diff --git a/xen/arch/ppc/ppc64/opal-calls.S b/xen/arch/ppc/ppc64/opal-calls.S
new file mode 100644
index 0000000000..cc5de75c8a
--- /dev/null
+++ b/xen/arch/ppc/ppc64/opal-calls.S
@@ -0,0 +1,81 @@ 
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Adapted from Linux's arch/powerpc/boot/opal-calls.S
+ *
+ * Copyright (c) 2016 IBM Corporation.
+ * Copyright Raptor Engineering, LLC
+ */
+
+#include <asm/asm-defns.h>
+#include <asm/opal-api.h>
+#include <asm/msr.h>
+
+    .text
+
+#define OPAL_CALL(name, token)  \
+    .globl name;                \
+name:                           \
+    li      %r0, token;         \
+    b       opal_call
+
+ _GLOBAL_TOC(opal_call)
+    /* Back up LR, CR, r2 in caller's stack frame */
+    mflr    %r11
+    mfcr    %r12
+    std     %r2, 24(%r1)
+    std     %r11, 16(%r1)
+    stw     %r12, 8(%r1)
+
+    /* Use r14 (non-volatile) to store the virtual address of opal_return_mmu */
+    std     %r14, -8(%r1)
+    stdu    %r1, -48(%r1)
+    LOAD_REG_ADDR(%r14, opal_return_mmu)
+
+    /*
+     * Setup new MSR without LE or MMU. Original MSR will be preserved across
+     * opal call in r13
+     */
+    mfmsr   %r13
+    li      %r11, MSR_LE | MSR_IR | MSR_DR
+    andc    %r12, %r13, %r11
+    mthsrr1 %r12
+
+    LOAD_REG_ADDR(%r11, opal_return_real)
+    mtlr     %r11
+
+    /* Load the opal call entry point and base */
+    LOAD_REG_ADDR(%r11, opal)
+    ld      %r12, OPAL_entry(%r11)
+    ld      %r2, OPAL_base(%r11)
+    mthsrr0 %r12
+    hrfid
+
+opal_return_real:
+    /*
+     * OPAL will always return to us in Big Endian mode. Since we are going
+     * to restore the old MSR with the correct endianness and MMU status set, we
+     * can avoid an unnecessary FIXUP_ENDIAN trampoline by just encoding the
+     * required Big Endian instructions to restore the old MSR direclty.
+     */
+    .long 0xa64bbb7d /* mthsrr1 %r13 (Old MSR) */
+    .long 0xa64bda7d /* mthsrr0 %r14 (Virtual address of opal_return_mmu) */
+    .long 0x2402004c /* hrfid */
+
+opal_return_mmu:
+    /*
+     * We're back in the correct endianness and MMU mode, restore registers
+     * and return
+     */
+    addi    %r1, %r1, 48
+    ld      %r14, -8(%r1)
+    lwz     %r11, 8(%r1)
+    ld      %r12, 16(%r1)
+    ld      %r2, 24(%r1)
+    mtcr    %r11
+    mtlr    %r12
+
+    blr
+
+OPAL_CALL(opal_console_write, OPAL_CONSOLE_WRITE)
+OPAL_CALL(opal_console_flush, OPAL_CONSOLE_FLUSH)
+OPAL_CALL(opal_reinit_cpus, OPAL_REINIT_CPUS)