git: a113f9dd9886 - main - uart: Support EARLY_PRINTF on x86 for port-mapped COM ports

From: Warner Losh <imp_at_FreeBSD.org>
Date: Fri, 20 Oct 2023 22:10:12 UTC
The branch main has been updated by imp:

URL: https://cgit.FreeBSD.org/src/commit/?id=a113f9dd9886e48914ba48b1f02ecf3ad0fc00d3

commit a113f9dd9886e48914ba48b1f02ecf3ad0fc00d3
Author:     Warner Losh <imp@FreeBSD.org>
AuthorDate: 2023-10-20 22:07:03 +0000
Commit:     Warner Losh <imp@FreeBSD.org>
CommitDate: 2023-10-20 22:07:24 +0000

    uart: Support EARLY_PRINTF on x86 for port-mapped COM ports
    
    Support early printf for the ns8250 uart driver. Adding
            options UART_NS8250_EARLY_PORT=0xYYY
            options EARLY_PRINTF
    to your kernel config will enable it. The code is rather simple minded,
    so caveat emptor. This will enable printf before cninit. cninit
    automatically disables this and switches to the real routine. It only
    works for port-mapped COM ports, and only if you know the port's address
    at compile time. It's intended for be a debugging aide, not a general
    purpose thing.
    
    Sponsored by:           Netflix
    Reviewed by:            emaste
    Differential Revision:  https://reviews.freebsd.org/D42306
---
 sys/conf/options.amd64         |  3 +++
 sys/conf/options.i386          |  3 +++
 sys/dev/uart/uart_dev_ns8250.c | 21 +++++++++++++++++++++
 3 files changed, 27 insertions(+)

diff --git a/sys/conf/options.amd64 b/sys/conf/options.amd64
index 8402c89640f7..df18abfa8e1e 100644
--- a/sys/conf/options.amd64
+++ b/sys/conf/options.amd64
@@ -65,3 +65,6 @@ NO_LEGACY_PCIB		opt_cpu.h
 
 # Compatibility with Linux MP table bugs.
 MPTABLE_LINUX_BUG_COMPAT
+
+# x86 specific uart options
+UART_NS8250_EARLY_PORT	opt_uart.h
diff --git a/sys/conf/options.i386 b/sys/conf/options.i386
index c827e0bb7a69..b98591a2a7da 100644
--- a/sys/conf/options.i386
+++ b/sys/conf/options.i386
@@ -109,3 +109,6 @@ NO_LEGACY_PCIB		opt_cpu.h
 
 # Compatibility with Linux MP table bugs.
 MPTABLE_LINUX_BUG_COMPAT
+
+# x86 specific uart options
+UART_NS8250_EARLY_PORT	opt_uart.h
diff --git a/sys/dev/uart/uart_dev_ns8250.c b/sys/dev/uart/uart_dev_ns8250.c
index de9b67c6bef1..3787c6ed4c9b 100644
--- a/sys/dev/uart/uart_dev_ns8250.c
+++ b/sys/dev/uart/uart_dev_ns8250.c
@@ -78,6 +78,27 @@ static int broken_txfifo = 0;
 SYSCTL_INT(_hw, OID_AUTO, broken_txfifo, CTLFLAG_RWTUN,
 	&broken_txfifo, 0, "UART FIFO has QEMU emulation bug");
 
+/*
+ * To use early printf on x86, add the following to your kernel config:
+ *
+ * options UART_NS8250_EARLY_PORT=0x3f8
+ * options EARLY_PRINTF
+*/
+#if defined(EARLY_PRINTF) && (defined(__amd64__) || defined(__i386__))
+static void
+uart_ns8250_early_putc(int c)
+{
+	u_int stat = UART_NS8250_EARLY_PORT + REG_LSR;
+	u_int tx = UART_NS8250_EARLY_PORT + REG_DATA;
+	int limit = 10000; /* 10ms is plenty of time */
+
+	while ((inb(stat) & LSR_THRE) == 0 && --limit > 0)
+		continue;
+	outb(tx, c);
+}
+early_putc_t *early_putc = uart_ns8250_early_putc;
+#endif /* EARLY_PRINTF */
+
 /*
  * Clear pending interrupts. THRE is cleared by reading IIR. Data
  * that may have been received gets lost here.