[Skiboot] [RFC PATCH 4/9] opal: provide a "raw" console mode

Nicholas Piggin npiggin at gmail.com
Sat May 2 21:36:44 AEST 2020


This allows the console drivers to be switched to a "raw" mode (maybe OS
mode is a better name) which exposes the console hardware driver
directly via the OPAL APIs, and does not allow OPAL to use it.

This is not used until a subsequent patch, but it allows the OS to own
the console rather than be arbitrated via the OPAL console layer. The
OS then provides console services to OPAL.

This can not really be achieved by advertising the UART to the OS in the
DT at boot, because there is no way to coordinate the switch to the OS
owning the console.

Signed-off-by: Nicholas Piggin <npiggin at gmail.com>
---
 core/console.c            | 83 +++++++++++++++++++++++++++++++++------
 hw/lpc-uart.c             | 83 +++++++++++++++++++++++++++++++++++++++
 include/console.h         |  3 ++
 platforms/mambo/console.c | 60 ++++++++++++++++++++++++++++
 4 files changed, 217 insertions(+), 12 deletions(-)

diff --git a/core/console.c b/core/console.c
index 2a1509025..336dda7a1 100644
--- a/core/console.c
+++ b/core/console.c
@@ -19,12 +19,15 @@ static char *con_buf = (char *)INMEM_CON_START;
 static size_t con_in;
 static size_t con_out;
 static bool con_wrapped;
+static bool con_raw;
 
 /* Internal console driver ops */
 static struct con_ops *con_driver;
 
 /* External (OPAL) console driver ops */
 static struct opal_con_ops *opal_con_driver = &dummy_opal_con;
+static struct opal_con_ops *opal_raw_con_driver = NULL;
+static struct opal_con_ops *opal_cooked_con_driver = &dummy_opal_con;
 
 static struct lock con_lock = LOCK_UNLOCKED;
 
@@ -167,6 +170,9 @@ bool flush_console(void)
 {
 	bool ret;
 
+	if (!con_driver)
+		return false;
+
 	lock(&con_lock);
 	ret = __flush_console(true, true);
 	unlock(&con_lock);
@@ -232,9 +238,12 @@ ssize_t console_write(bool flush_to_drivers, const void *buf, size_t count)
 	/* We use recursive locking here as we can get called
 	 * from fairly deep debug path
 	 */
-	bool need_unlock = lock_recursive(&con_lock);
+	bool need_unlock;
 	const char *cbuf = buf;
 
+	assert(!con_raw);
+	need_unlock = lock_recursive(&con_lock);
+
 	while(count--) {
 		char c = *(cbuf++);
 		if (c == '\n')
@@ -260,6 +269,8 @@ ssize_t read(int fd __unused, void *buf, size_t req_count)
 	bool need_unlock = lock_recursive(&con_lock);
 	size_t count = 0;
 
+	assert(!con_raw);
+
 	if (con_driver && con_driver->read)
 		count = con_driver->read(buf, req_count);
 	if (!count)
@@ -272,17 +283,22 @@ ssize_t read(int fd __unused, void *buf, size_t req_count)
 /* Helper function to perform a full synchronous flush */
 void console_complete_flush(void)
 {
-	/*
-	 * Using term 0 here is a dumb hack that works because the UART
-	 * only has term 0 and the FSP doesn't have an explicit flush method.
-	 */
-	int64_t ret = opal_con_driver->flush(0);
-
-	if (ret == OPAL_UNSUPPORTED || ret == OPAL_PARAMETER)
-		return;
-
-	while (ret != OPAL_SUCCESS) {
-		ret = opal_con_driver->flush(0);
+	if (con_raw) {
+		opal_raw_con_driver->flush(0);
+	} else {
+		/*
+		 * Using term 0 here is a dumb hack that works because the UART
+		 * only has term 0 and the FSP doesn't have an explicit flush
+		 * method.
+		 */
+		int64_t ret = opal_con_driver->flush(0);
+
+		if (ret == OPAL_UNSUPPORTED || ret == OPAL_PARAMETER)
+			return;
+
+		while (ret != OPAL_SUCCESS) {
+			ret = opal_con_driver->flush(0);
+		}
 	}
 }
 
@@ -311,9 +327,51 @@ static bool opal_cons_init = false;
 void set_opal_console(struct opal_con_ops *driver)
 {
 	assert(!opal_cons_init);
+	opal_cooked_con_driver = driver;
 	opal_con_driver = driver;
 }
 
+void set_opal_raw_console(struct opal_con_ops *driver)
+{
+	assert(!opal_cons_init);
+	opal_raw_con_driver = driver;
+}
+
+void set_opal_console_to_raw(void)
+{
+	if (!opal_raw_con_driver)
+		return;
+
+	console_complete_flush();
+
+	opal_con_driver = opal_raw_con_driver;
+	if (opal_cons_init) {
+		opal_register(OPAL_CONSOLE_READ, opal_con_driver->read, 3);
+		opal_register(OPAL_CONSOLE_WRITE, opal_con_driver->write, 3);
+		opal_register(OPAL_CONSOLE_FLUSH, opal_con_driver->flush, 1);
+		opal_register(OPAL_CONSOLE_WRITE_BUFFER_SPACE,
+				opal_con_driver->space, 2);
+	}
+
+	opal_con_driver = NULL;
+	con_raw = true;
+}
+
+void set_opal_console_to_cooked(void)
+{
+	console_complete_flush();
+
+	opal_con_driver = opal_cooked_con_driver;
+	if (opal_cons_init) {
+		opal_register(OPAL_CONSOLE_READ, opal_con_driver->read, 3);
+		opal_register(OPAL_CONSOLE_WRITE, opal_con_driver->write, 3);
+		opal_register(OPAL_CONSOLE_FLUSH, opal_con_driver->flush, 1);
+		opal_register(OPAL_CONSOLE_WRITE_BUFFER_SPACE,
+				opal_con_driver->space, 2);
+	}
+	con_raw = false;
+}
+
 void init_opal_console(void)
 {
 	assert(!opal_cons_init);
@@ -324,6 +382,7 @@ void init_opal_console(void)
 		      opal_con_driver->name);
 
 		opal_con_driver = &dummy_opal_con;
+		opal_cooked_con_driver = &dummy_opal_con;
 	}
 
 	prlog(PR_INFO, "OPAL: Using %s\n", opal_con_driver->name);
diff --git a/hw/lpc-uart.c b/hw/lpc-uart.c
index 898fc4b1c..549aad49f 100644
--- a/hw/lpc-uart.c
+++ b/hw/lpc-uart.c
@@ -183,6 +183,89 @@ static struct con_ops uart_con_driver = {
  * OPAL console driver
  */
 
+static int64_t uart_opal_raw_write(int64_t term_number, __be64 *__length,
+			       const uint8_t *buffer)
+{
+	size_t written = 0, len = be64_to_cpu(*__length);
+
+	if (term_number != 0)
+		return OPAL_PARAMETER;
+
+	if (!lpc_ok() && !mmio_uart_base)
+		return OPAL_HARDWARE;
+
+	while (written < len) {
+		if (tx_room == 0) {
+			uart_check_tx_room();
+			if (tx_room == 0)
+				break;
+		}
+		uart_write(REG_THR, buffer[written++]);
+		tx_room--;
+	}
+
+	*__length = cpu_to_be64(written);
+
+	return OPAL_SUCCESS;
+}
+
+static int64_t uart_opal_raw_write_buffer_space(int64_t term_number,
+					    __be64 *__length)
+{
+	if (term_number != 0)
+		return OPAL_PARAMETER;
+
+	uart_check_tx_room();
+	*__length = cpu_to_be64(tx_room);
+
+	return OPAL_SUCCESS;
+}
+
+static int64_t uart_opal_raw_read(int64_t term_number, __be64 *__length,
+			      uint8_t *buffer)
+{
+	size_t req_count = be64_to_cpu(*__length), read_cnt = 0;
+	uint8_t lsr = 0;
+
+	if (term_number != 0)
+		return OPAL_PARAMETER;
+
+	while (req_count) {
+		lsr = uart_read(REG_LSR);
+		if ((lsr & LSR_DR) == 0)
+			break;
+		buffer[read_cnt++] = uart_read(REG_RBR);
+		req_count--;
+	}
+
+	*__length = cpu_to_be64(read_cnt);
+	return OPAL_SUCCESS;
+}
+
+static int64_t uart_opal_raw_flush(int64_t term_number)
+{
+	if (term_number != 0)
+		return OPAL_PARAMETER;
+
+	while (tx_room != 16)
+		uart_check_tx_room();
+
+	return OPAL_SUCCESS;
+}
+
+static void uart_init_opal_raw_console(void)
+{
+}
+
+struct opal_con_ops uart_opal_raw_con = {
+	.name = "OPAL UART raw console",
+	.init = uart_init_opal_raw_console,
+	.read = uart_opal_raw_read,
+	.write = uart_opal_raw_write,
+	.space = uart_opal_raw_write_buffer_space,
+	.flush = uart_opal_raw_flush,
+};
+
 /*
  * We implement a simple buffer to buffer input data as some bugs in
  * Linux make it fail to read fast enough after we get an interrupt.
diff --git a/include/console.h b/include/console.h
index 02fc7a4b6..54ddd6718 100644
--- a/include/console.h
+++ b/include/console.h
@@ -65,6 +65,9 @@ extern bool flush_console(void);
 
 extern void set_console(struct con_ops *driver);
 extern void set_opal_console(struct opal_con_ops *driver);
+extern void set_opal_raw_console(struct opal_con_ops *driver);
+extern void set_opal_console_to_raw(void);
+extern void set_opal_console_to_cooked(void);
 extern void init_opal_console(void);
 
 extern void console_complete_flush(void);
diff --git a/platforms/mambo/console.c b/platforms/mambo/console.c
index 6d5b20b56..f2a0ad675 100644
--- a/platforms/mambo/console.c
+++ b/platforms/mambo/console.c
@@ -3,6 +3,7 @@
 
 #include <skiboot.h>
 #include <console.h>
+#include <opal-api.h>
 
 #include "mambo.h"
 
@@ -48,10 +49,69 @@ static struct con_ops mambo_con_driver = {
 	.write = mambo_console_write,
 };
 
+static int64_t mambo_opal_raw_write(int64_t term_number, __be64 *__length,
+			       const uint8_t *buffer)
+{
+	size_t len = be64_to_cpu(*__length);
+
+	if (term_number != 0)
+		return OPAL_PARAMETER;
+
+	mambo_console_write(buffer, len);
+
+	return OPAL_SUCCESS;
+}
+
+static int64_t mambo_opal_raw_write_buffer_space(int64_t term_number,
+					    __be64 *__length)
+{
+	if (term_number != 0)
+		return OPAL_PARAMETER;
+
+	*__length = cpu_to_be64(256);
+
+	return OPAL_SUCCESS;
+}
+
+static int64_t mambo_opal_raw_read(int64_t term_number, __be64 *__length,
+			      uint8_t *buffer)
+{
+	size_t req_count = be64_to_cpu(*__length), read_cnt = 0;
+
+	if (term_number != 0)
+		return OPAL_PARAMETER;
+
+	read_cnt = mambo_console_read(buffer, req_count);
+	*__length = cpu_to_be64(read_cnt);
+
+	return OPAL_SUCCESS;
+}
+
+static int64_t mambo_opal_raw_flush(int64_t term_number)
+{
+	if (term_number != 0)
+		return OPAL_PARAMETER;
+	return OPAL_SUCCESS;
+}
+
+static void mambo_init_opal_raw_console(void)
+{
+}
+
+struct opal_con_ops mambo_opal_raw_con = {
+	.name = "OPAL Mambo raw console",
+	.init = mambo_init_opal_raw_console,
+	.read = mambo_opal_raw_read,
+	.write = mambo_opal_raw_write,
+	.space = mambo_opal_raw_write_buffer_space,
+	.flush = mambo_opal_raw_flush,
+};
+
 void enable_mambo_console(void)
 {
 	prlog(PR_NOTICE, "Enabling Mambo console\n");
 	set_console(&mambo_con_driver);
+	set_opal_raw_console(&mambo_opal_raw_con);
 }
 
 /*
-- 
2.23.0



More information about the Skiboot mailing list