blob: e13da5942cb5eeb714102d751489b75b1ccd9eba [file] [log] [blame]
Joel Stanley548b0af2016-08-16 23:09:53 +09301From b31da157b20a30a1de1221755bff5fd68c0da885 Mon Sep 17 00:00:00 2001
Joel Stanley2b0f7b42016-07-19 23:26:28 +09302From: Oliver O'Halloran <oohall@gmail.com>
3Date: Fri, 24 Jun 2016 17:28:43 +1000
Joel Stanley548b0af2016-08-16 23:09:53 +09304Subject: [PATCH 6/9] powerpc/boot: Add OPAL console to epapr wrappers
Joel Stanley2b0f7b42016-07-19 23:26:28 +09305
6This patch adds an OPAL console backend to the powerpc boot wrapper so
7that decompression failures inside the wrapper can be reported to the
8user. This is important since it typically indicates data corruption in
9the firmware and other nasty things.
10
11Currently this only works when building a little endian kernel. When
12compiling a 64 bit BE kernel the wrapper is always build 32 bit to be
13compatible with some 32 bit firmwares. BE support will be added at a
14later date. Another limitation of this is that only the "raw" type of
15OPAL console is supported, however machines that provide a hvsi console
16also provide a raw console so this is not an issue in practice.
17
18Actually-written-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
19Signed-off-by: Oliver O'Halloran <oohall@gmail.com>
20Cc: Stewart Smith <stewart@linux.vnet.ibm.com>
21Signed-off-by: Joel Stanley <joel@jms.id.au>
22---
23 arch/powerpc/boot/Makefile | 4 +-
24 arch/powerpc/boot/opal-calls.S | 58 +++++++++++++++++++++++++
25 arch/powerpc/boot/opal.c | 97 ++++++++++++++++++++++++++++++++++++++++++
26 arch/powerpc/boot/ops.h | 1 +
27 arch/powerpc/boot/ppc_asm.h | 4 ++
28 arch/powerpc/boot/serial.c | 2 +
29 arch/powerpc/boot/types.h | 10 +++++
30 7 files changed, 174 insertions(+), 2 deletions(-)
31 create mode 100644 arch/powerpc/boot/opal-calls.S
32 create mode 100644 arch/powerpc/boot/opal.c
33
34diff --git a/arch/powerpc/boot/Makefile b/arch/powerpc/boot/Makefile
35index 99e4487248ff..321a603f6ae3 100644
36--- a/arch/powerpc/boot/Makefile
37+++ b/arch/powerpc/boot/Makefile
38@@ -70,7 +70,7 @@ $(addprefix $(obj)/,$(zlib) cuboot-c2k.o gunzip_util.o main.o): \
39 libfdt := fdt.c fdt_ro.c fdt_wip.c fdt_sw.c fdt_rw.c fdt_strerror.c
40 libfdtheader := fdt.h libfdt.h libfdt_internal.h
41
42-$(addprefix $(obj)/,$(libfdt) libfdt-wrapper.o simpleboot.o epapr.o): \
43+$(addprefix $(obj)/,$(libfdt) libfdt-wrapper.o simpleboot.o epapr.o opal.o): \
44 $(addprefix $(obj)/,$(libfdtheader))
45
46 src-wlib-y := string.S crt0.S crtsavres.S stdio.c main.c \
47@@ -78,7 +78,7 @@ src-wlib-y := string.S crt0.S crtsavres.S stdio.c main.c \
48 ns16550.c serial.c simple_alloc.c div64.S util.S \
49 gunzip_util.c elf_util.c $(zlib) devtree.c stdlib.c \
50 oflib.c ofconsole.c cuboot.c mpsc.c cpm-serial.c \
51- uartlite.c mpc52xx-psc.c
52+ uartlite.c mpc52xx-psc.c opal.c opal-calls.S
53 src-wlib-$(CONFIG_40x) += 4xx.c planetcore.c
54 src-wlib-$(CONFIG_44x) += 4xx.c ebony.c bamboo.c
55 src-wlib-$(CONFIG_8xx) += mpc8xx.c planetcore.c fsl-soc.c
56diff --git a/arch/powerpc/boot/opal-calls.S b/arch/powerpc/boot/opal-calls.S
57new file mode 100644
58index 000000000000..ff2f1b97bc53
59--- /dev/null
60+++ b/arch/powerpc/boot/opal-calls.S
61@@ -0,0 +1,58 @@
62+/*
63+ * Copyright (c) 2016 IBM Corporation.
64+ *
65+ * This program is free software; you can redistribute it and/or
66+ * modify it under the terms of the GNU General Public License
67+ * as published by the Free Software Foundation; either version
68+ * 2 of the License, or (at your option) any later version.
69+ */
70+
71+#include "ppc_asm.h"
72+#include "../include/asm/opal-api.h"
73+
74+ .text
75+
76+#define OPAL_CALL(name, token) \
77+ .globl name; \
78+name: \
79+ li r0, token; \
80+ b opal_call;
81+
82+opal_call:
83+ mflr r11
84+ std r11,16(r1)
85+ mfcr r12
86+ stw r12,8(r1)
87+ mr r13,r2
88+
89+ /* Set opal return address */
90+ ld r11,opal_return@got(r2)
91+ mtlr r11
92+ mfmsr r12
93+
94+ /* switch to BE when we enter OPAL */
95+ li r11,MSR_LE
96+ andc r12,r12,r11
97+ mtspr SPRN_HSRR1,r12
98+
99+ /* load the opal call entry point and base */
100+ ld r11,opal@got(r2)
101+ ld r12,8(r11)
102+ ld r2,0(r11)
103+ mtspr SPRN_HSRR0,r12
104+ hrfid
105+
106+opal_return:
107+ FIXUP_ENDIAN
108+ mr r2,r13;
109+ lwz r11,8(r1);
110+ ld r12,16(r1)
111+ mtcr r11;
112+ mtlr r12
113+ blr
114+
115+OPAL_CALL(opal_console_write, OPAL_CONSOLE_WRITE);
116+OPAL_CALL(opal_console_read, OPAL_CONSOLE_READ);
117+OPAL_CALL(opal_console_write_buffer_space, OPAL_CONSOLE_WRITE_BUFFER_SPACE);
118+OPAL_CALL(opal_poll_events, OPAL_POLL_EVENTS);
119+OPAL_CALL(opal_console_flush, OPAL_CONSOLE_FLUSH);
120diff --git a/arch/powerpc/boot/opal.c b/arch/powerpc/boot/opal.c
121new file mode 100644
122index 000000000000..3a2ce1e1f048
123--- /dev/null
124+++ b/arch/powerpc/boot/opal.c
125@@ -0,0 +1,97 @@
126+/*
127+ * Copyright (c) 2016 IBM Corporation.
128+ *
129+ * This program is free software; you can redistribute it and/or
130+ * modify it under the terms of the GNU General Public License
131+ * as published by the Free Software Foundation; either version
132+ * 2 of the License, or (at your option) any later version.
133+ */
134+
135+#include "ops.h"
136+#include "stdio.h"
137+#include "io.h"
138+#include <libfdt.h>
139+#include "../include/asm/opal-api.h"
140+
141+/* Global OPAL struct used by opal-call.S */
142+struct opal {
143+ u64 base;
144+ u64 entry;
145+} opal;
146+
147+static u32 opal_con_id;
148+
149+int64_t opal_console_write(int64_t term_number, u64 *length, const u8 *buffer);
150+int64_t opal_console_read(int64_t term_number, uint64_t *length, u8 *buffer);
151+int64_t opal_console_write_buffer_space(uint64_t term_number, uint64_t *length);
152+int64_t opal_console_flush(uint64_t term_number);
153+int64_t opal_poll_events(uint64_t *outstanding_event_mask);
154+
155+static int opal_con_open(void)
156+{
157+ return 0;
158+}
159+
160+static void opal_con_putc(unsigned char c)
161+{
162+ int64_t rc;
163+ uint64_t olen, len;
164+
165+ do {
166+ rc = opal_console_write_buffer_space(opal_con_id, &olen);
167+ len = be64_to_cpu(olen);
168+ if (rc)
169+ return;
170+ opal_poll_events(NULL);
171+ } while (len < 1);
172+
173+
174+ olen = cpu_to_be64(1);
175+ opal_console_write(opal_con_id, &olen, &c);
176+}
177+
178+static void opal_con_close(void)
179+{
180+ opal_console_flush(opal_con_id);
181+}
182+
183+static void opal_init(void)
184+{
185+ void *opal_node;
186+
187+ opal_node = finddevice("/ibm,opal");
188+ if (!opal_node)
189+ return;
190+ if (getprop(opal_node, "opal-base-address", &opal.base, sizeof(u64)) < 0)
191+ return;
192+ opal.base = be64_to_cpu(opal.base);
193+ if (getprop(opal_node, "opal-entry-address", &opal.entry, sizeof(u64)) < 0)
194+ return;
195+ opal.entry = be64_to_cpu(opal.entry);
196+}
197+
198+#ifdef __powerpc64__
199+int opal_console_init(void *devp, struct serial_console_data *scdp)
200+{
201+ opal_init();
202+
203+ if (devp) {
204+ int n = getprop(devp, "reg", &opal_con_id, sizeof(u32));
205+ if (n != sizeof(u32))
206+ return -1;
207+ opal_con_id = be32_to_cpu(opal_con_id);
208+ } else
209+ opal_con_id = 0;
210+
211+ scdp->open = opal_con_open;
212+ scdp->putc = opal_con_putc;
213+ scdp->close = opal_con_close;
214+
215+ return 0;
216+}
217+#else
218+int opal_console_init(void *devp, struct serial_console_data *scdp)
219+{
220+ return -1;
221+}
222+#endif
223diff --git a/arch/powerpc/boot/ops.h b/arch/powerpc/boot/ops.h
224index 5e75e1c5518e..e19b64ef977a 100644
225--- a/arch/powerpc/boot/ops.h
226+++ b/arch/powerpc/boot/ops.h
227@@ -89,6 +89,7 @@ int mpsc_console_init(void *devp, struct serial_console_data *scdp);
228 int cpm_console_init(void *devp, struct serial_console_data *scdp);
229 int mpc5200_psc_console_init(void *devp, struct serial_console_data *scdp);
230 int uartlite_console_init(void *devp, struct serial_console_data *scdp);
231+int opal_console_init(void *devp, struct serial_console_data *scdp);
232 void *simple_alloc_init(char *base, unsigned long heap_size,
233 unsigned long granularity, unsigned long max_allocs);
234 extern void flush_cache(void *, unsigned long);
235diff --git a/arch/powerpc/boot/ppc_asm.h b/arch/powerpc/boot/ppc_asm.h
236index 35ea60c1f070..b03373d8b386 100644
237--- a/arch/powerpc/boot/ppc_asm.h
238+++ b/arch/powerpc/boot/ppc_asm.h
239@@ -61,6 +61,10 @@
240
241 #define SPRN_TBRL 268
242 #define SPRN_TBRU 269
243+#define SPRN_HSRR0 0x13A /* Hypervisor Save/Restore 0 */
244+#define SPRN_HSRR1 0x13B /* Hypervisor Save/Restore 1 */
245+
246+#define MSR_LE 0x0000000000000001
247
248 #define FIXUP_ENDIAN \
249 tdi 0, 0, 0x48; /* Reverse endian of b . + 8 */ \
250diff --git a/arch/powerpc/boot/serial.c b/arch/powerpc/boot/serial.c
251index 167ee9433de6..e04c1e4063ae 100644
252--- a/arch/powerpc/boot/serial.c
253+++ b/arch/powerpc/boot/serial.c
254@@ -132,6 +132,8 @@ int serial_console_init(void)
255 else if (dt_is_compatible(devp, "xlnx,opb-uartlite-1.00.b") ||
256 dt_is_compatible(devp, "xlnx,xps-uartlite-1.00.a"))
257 rc = uartlite_console_init(devp, &serial_cd);
258+ else if (dt_is_compatible(devp, "ibm,opal-console-raw"))
259+ rc = opal_console_init(devp, &serial_cd);
260
261 /* Add other serial console driver calls here */
262
263diff --git a/arch/powerpc/boot/types.h b/arch/powerpc/boot/types.h
264index 31393d17a9c1..85565a89bcc2 100644
265--- a/arch/powerpc/boot/types.h
266+++ b/arch/powerpc/boot/types.h
267@@ -12,6 +12,16 @@ typedef short s16;
268 typedef int s32;
269 typedef long long s64;
270
271+/* required for opal-api.h */
272+typedef u8 uint8_t;
273+typedef u16 uint16_t;
274+typedef u32 uint32_t;
275+typedef u64 uint64_t;
276+typedef s8 int8_t;
277+typedef s16 int16_t;
278+typedef s32 int32_t;
279+typedef s64 int64_t;
280+
281 #define min(x,y) ({ \
282 typeof(x) _x = (x); \
283 typeof(y) _y = (y); \
284--
2852.8.1
286