[Skiboot] [RFC PATCH 1/2] opal: provide a "raw" console mode

Nicholas Piggin npiggin at gmail.com
Tue Dec 10 22:29:07 AEDT 2019


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 the subsequent patch, but it allows the OS
to own the console rather than be arbitrated via the OPAL console
layer.

This can also be achieved by advertising the uart device to Linux
in the dt at boot, but that has a problem that it's a boot time
config option and can't be changed depending on what the OS supports.
---
 core/console.c            | 83 +++++++++++++++++++++++++++++++++------
 core/opal.c               |  1 -
 hw/lpc-uart.c             | 83 +++++++++++++++++++++++++++++++++++++++
 include/console.h         |  3 ++
 platforms/mambo/console.c | 60 ++++++++++++++++++++++++++++
 5 files changed, 217 insertions(+), 13 deletions(-)

diff --git a/core/console.c b/core/console.c
index 030c1d918..d72c0c879 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/core/opal.c b/core/opal.c
index 2420dedbe..44345bcae 100644
--- a/core/opal.c
+++ b/core/opal.c
@@ -666,7 +666,6 @@ void opal_run_pollers(void)
 
 static int64_t opal_poll_events(__be64 *outstanding_event_mask)
 {
-
 	if (!opal_addr_valid(outstanding_event_mask))
 		return OPAL_PARAMETER;
 
diff --git a/hw/lpc-uart.c b/hw/lpc-uart.c
index eada52e06..9f237ddb8 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 61448e28e..aa85ddd09 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 4a601faef..f3a8844f3 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