Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 2 Nov 2011 20:55:56 +0000 (UTC)
From:      Nathan Whitehorn <nwhitehorn@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-projects@freebsd.org
Subject:   svn commit: r227033 - in projects/pseries: dev/uart powerpc/pseries
Message-ID:  <201111022055.pA2KtuoW037948@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: nwhitehorn
Date: Wed Nov  2 20:55:55 2011
New Revision: 227033
URL: http://svn.freebsd.org/changeset/base/227033

Log:
  Turn the POWER hypervisor console into a kind of uart(4). When controlling
  actual serial ports via the hvterm-protocol interface, it has support for
  regular UARTy things like baud rates and flow control.

Modified:
  projects/pseries/dev/uart/uart_cpu_powerpc.c
  projects/pseries/powerpc/pseries/phyp_console.c

Modified: projects/pseries/dev/uart/uart_cpu_powerpc.c
==============================================================================
--- projects/pseries/dev/uart/uart_cpu_powerpc.c	Wed Nov  2 20:45:44 2011	(r227032)
+++ projects/pseries/dev/uart/uart_cpu_powerpc.c	Wed Nov  2 20:55:55 2011	(r227033)
@@ -42,11 +42,18 @@ __FBSDID("$FreeBSD$");
 bus_space_tag_t uart_bus_space_io = &bs_le_tag;
 bus_space_tag_t uart_bus_space_mem = &bs_le_tag;
 
+extern struct uart_class uart_phyp_class __attribute__((weak));
+
 int
 uart_cpu_eqres(struct uart_bas *b1, struct uart_bas *b2)
 {
-
-	return ((pmap_kextract(b1->bsh) == pmap_kextract(b2->bsh)) ? 1 : 0);
+	if (b1->bst == NULL && b2->bst == NULL)
+		return ((b1->bsh == b2->bsh) ? 1 : 0);
+	else if (b1->bst != NULL && b2->bst != NULL)
+		return ((pmap_kextract(b1->bsh) == pmap_kextract(b2->bsh)) ?
+		    1 : 0);
+	else
+		return (0);
 }
 
 static int
@@ -54,16 +61,21 @@ ofw_get_uart_console(phandle_t opts, pha
     const char *outputdev)
 {
 	char buf[64];
-	phandle_t input;
+	phandle_t input, output;
 
+	*result = -1;
 	if (OF_getprop(opts, inputdev, buf, sizeof(buf)) == -1)
-		return (ENXIO);
+		return (ENOENT);
 	input = OF_finddevice(buf);
 	if (input == -1)
-		return (ENXIO);
+		return (ENOENT);
 	if (OF_getprop(opts, outputdev, buf, sizeof(buf)) == -1)
-		return (ENXIO);
-	if (OF_finddevice(buf) != input)
+		return (ENOENT);
+	output = OF_finddevice(buf);
+	if (output == -1)
+		return (ENOENT);
+
+	if (input != output) /* UARTs are bidirectional */
 		return (ENXIO);
 
 	*result = input;
@@ -75,28 +87,42 @@ uart_cpu_getdev(int devtype, struct uart
 {
 	char buf[64];
 	struct uart_class *class;
-	phandle_t input, opts;
+	ihandle_t stdout;
+	phandle_t input, opts, chosen;
+	cell_t reg;
 	int error;
 
-	class = &uart_z8530_class;
-	if (class == NULL)
-		return (ENXIO);
-
 	if ((opts = OF_finddevice("/options")) == -1)
 		return (ENXIO);
+	if ((chosen = OF_finddevice("/chosen")) == -1)
+		return (ENXIO);
 	switch (devtype) {
 	case UART_DEV_CONSOLE:
-		if (ofw_get_uart_console(opts, &input, "input-device",
-		    "output-device")) {
+		do {
+			/* Check if OF has an active stdin/stdout */
+			input = -1;
+			if (OF_getprop(chosen, "stdout", &stdout,
+			    sizeof(stdout)) == sizeof(stdout) && stdout != 0)
+				input = OF_instance_to_package(stdout);
+			if (input != -1)
+				break;
+
+			/* Guess what OF would have done had it had such */
+			if (ofw_get_uart_console(opts, &input, "input-device",
+			    "output-device") == 0)
+				break;
+
 			/*
 			 * At least some G5 Xserves require that we
 			 * probe input-device-1 as well
 			 */
-	
 			if (ofw_get_uart_console(opts, &input, "input-device-1",
-			    "output-device-1"))
-				return (ENXIO);
-		}
+			    "output-device-1") == 0)
+				break;
+		} while (0);
+
+		if (input == -1)
+			return (ENXIO);
 		break;
 	case UART_DEV_DBGPORT:
 		if (!getenv_string("hw.uart.dbgport", buf, sizeof(buf)))
@@ -124,12 +150,24 @@ uart_cpu_getdev(int devtype, struct uart
 		class = &uart_ns8250_class;
 		di->bas.regshft = 0;
 		di->bas.chan = 0;
+	} else if (strcmp(buf,"vty") == 0) {
+		class = &uart_phyp_class;
+		di->bas.regshft = 0;
+		di->bas.chan = input;
 	} else
 		return (ENXIO);
 
-	error = OF_decode_addr(input, 0, &di->bas.bst, &di->bas.bsh);
-	if (error)
-		return (error);
+	if (strcmp(buf,"vty") == 0) {
+		if (OF_getproplen(input, "reg") != sizeof(reg))
+			return (ENXIO);
+		OF_getprop(input, "reg", &reg, sizeof(reg));
+		di->bas.bsh = reg;
+		di->bas.bst = NULL;
+	} else {
+		error = OF_decode_addr(input, 0, &di->bas.bst, &di->bas.bsh);
+		if (error)
+			return (error);
+	}
 
 	di->ops = uart_getops(class);
 

Modified: projects/pseries/powerpc/pseries/phyp_console.c
==============================================================================
--- projects/pseries/powerpc/pseries/phyp_console.c	Wed Nov  2 20:45:44 2011	(r227032)
+++ projects/pseries/powerpc/pseries/phyp_console.c	Wed Nov  2 20:55:55 2011	(r227033)
@@ -25,8 +25,6 @@
 #include <sys/cdefs.h>
 __FBSDID("$FreeBSD: projects/pseries/powerpc/phyp/phyp_console.c 214348 2010-10-25 15:41:12Z nwhitehorn $");
 
-#include "opt_comconsole.h"
-
 #include <sys/param.h>
 #include <sys/kdb.h>
 #include <sys/kernel.h>
@@ -39,178 +37,133 @@ __FBSDID("$FreeBSD: projects/pseries/pow
 #include <sys/tty.h>
 
 #include <dev/ofw/openfirm.h>
-
-#include <ddb/ddb.h>
+#include <dev/uart/uart.h>
+#include <dev/uart/uart_cpu.h>
+#include <dev/uart/uart_bus.h>
 
 #include "phyp-hvcall.h"
+#include "uart_if.h"
 
-static tsw_outwakeup_t phyptty_outwakeup;
-
-static struct ttydevsw phyp_ttydevsw = {
-	.tsw_flags	= TF_NOPREFIX,
-	.tsw_outwakeup	= phyptty_outwakeup,
-};
-
-static int			polltime;
-static cell_t			termno;
-static struct callout		phyp_callout;
 static union {
 	uint64_t u64[2];
 	char str[16];
 } phyp_inbuf;
 static uint64_t			phyp_inbuflen = 0;
-static struct tty 		*tp = NULL;
-
-#if defined(KDB) && defined(ALT_BREAK_TO_DEBUGGER)
-static int			alt_break_state;
-#endif
-
-static void	phyp_timeout(void *);
-
-static cn_probe_t	phyp_cnprobe;
-static cn_init_t	phyp_cninit;
-static cn_term_t	phyp_cnterm;
-static cn_getc_t	phyp_cngetc;
-static cn_putc_t	phyp_cnputc;
-
-CONSOLE_DRIVER(phyp);
-
-static void
-cn_drvinit(void *unused)
-{
-	phandle_t dev;
 
-	if (phyp_consdev.cn_pri != CN_DEAD &&
-	    phyp_consdev.cn_name[0] != '\0') {
-		dev = OF_finddevice("/vdevice/vty");
-		if (dev == -1)
-			return;
-
-		OF_getprop(dev, "reg", &termno, sizeof(termno));
-		tp = tty_alloc(&phyp_ttydevsw, NULL);
-		tty_init_console(tp, 0);
-		tty_makedev(tp, NULL, "%s", "phypvty");
-
-		polltime = 1;
-
-		callout_init(&phyp_callout, CALLOUT_MPSAFE);
-		callout_reset(&phyp_callout, polltime, phyp_timeout, NULL);
-	}
-}
-
-SYSINIT(cndev, SI_SUB_CONFIGURE, SI_ORDER_MIDDLE, cn_drvinit, NULL);
-
-static void
-phyptty_outwakeup(struct tty *tp)
-{
-	int len, err;
-	uint64_t buf[2];
-
-	for (;;) {
-		len = ttydisc_getc(tp, buf, sizeof buf);
-		if (len == 0)
-			break;
-
-		do {
-			err = phyp_hcall(H_PUT_TERM_CHAR, termno,
-			    (register_t)len, buf[0], buf[1]);
-		} while (err == H_BUSY);
-	}
-}
-
-static void
-phyp_timeout(void *v)
-{
-	int 	c;
+enum {
+	HVTERM1, HVTERMPROT
+};
 
-	tty_lock(tp);
-	while ((c = phyp_cngetc(NULL)) != -1)
-		ttydisc_rint(tp, c, 0);
-	ttydisc_rint_done(tp);
-	tty_unlock(tp);
+/*
+ * Low-level UART interface
+ */
+static int phyp_uart_probe(struct uart_bas *bas);
+static void phyp_uart_init(struct uart_bas *bas, int baudrate, int databits,
+    int stopbits, int parity);
+static void phyp_uart_term(struct uart_bas *bas);
+static void phyp_uart_putc(struct uart_bas *bas, int c);
+static int phyp_uart_rxready(struct uart_bas *bas);
+static int phyp_uart_getc(struct uart_bas *bas, struct mtx *hwmtx);
+
+static struct uart_ops phyp_uart_ops = {
+	.probe = phyp_uart_probe,
+	.init = phyp_uart_init,
+	.term = phyp_uart_term,
+	.putc = phyp_uart_putc,
+	.rxready = phyp_uart_rxready,
+	.getc = phyp_uart_getc,
+};
 
-	callout_reset(&phyp_callout, polltime, phyp_timeout, NULL);
-}
+struct uart_class uart_phyp_class = {
+	"uart",
+	NULL,
+	sizeof(struct uart_softc),
+	.uc_ops = &phyp_uart_ops,
+	.uc_range = 1,
+	.uc_rclk = 0x5bbc
+};
 
-static void
-phyp_cnprobe(struct consdev *cp)
+static int
+phyp_uart_probe(struct uart_bas *bas)
 {
-	phandle_t dev;
-
-	dev = OF_finddevice("/vdevice/vty");
+	phandle_t node = bas->chan;
+	char buf[64];
 
-	if (dev == -1) {
-		cp->cn_pri = CN_DEAD;
-		return;
+	if (OF_getprop(node, "name", buf, sizeof(buf)) <= 0)
+		return (ENXIO);
+	if (strcmp(buf, "vty") != 0)
+		return (ENXIO);
+
+	if (OF_getprop(node, "device_type", buf, sizeof(buf)) <= 0)
+		return (ENXIO);
+	if (strcmp(buf, "serial") != 0)
+		return (ENXIO);
+
+	if (OF_getprop(node, "compatible", buf, sizeof(buf)) <= 0)
+		return (ENXIO);
+	if (strcmp(buf, "hvterm1") == 0) {
+		bas->regshft = HVTERM1;
+		return (0);
+	} else if (strcmp(buf, "hvterm-protocol") == 0) {
+		bas->regshft = HVTERMPROT;
+		return (0);
 	}
-
-	OF_getprop(dev, "reg", &termno, sizeof(termno));
-	cp->cn_pri = CN_NORMAL;
+		
+	return (ENXIO);
 }
 
 static void
-phyp_cninit(struct consdev *cp)
+phyp_uart_init(struct uart_bas *bas, int baudrate __unused,
+    int databits __unused, int stopbits __unused, int parity __unused)
 {
-
-	/* XXX: This is the alias, but that should be good enough */
-	strcpy(cp->cn_name, "phypcons");
 }
 
 static void
-phyp_cnterm(struct consdev *cp)
+phyp_uart_term(struct uart_bas *bas __unused)
 {
 }
 
 static int
-phyp_cngetc(struct consdev *cp)
+phyp_uart_getc(struct uart_bas *bas, struct mtx *hwmtx)
 {
 	int ch, err;
-#if defined(KDB) && defined(ALT_BREAK_TO_DEBUGGER)
-	int kdb_brk;
-#endif
 
-	/* XXX: thread safety */
+	uart_lock(hwmtx);
 	if (phyp_inbuflen == 0) {
-		err = phyp_pft_hcall(H_GET_TERM_CHAR, termno, 0, 0, 0,
-		    &phyp_inbuflen, &phyp_inbuf.u64[0], &phyp_inbuf.u64[1]);
-		if (err != H_SUCCESS)
+		err = phyp_pft_hcall(H_GET_TERM_CHAR, (uint64_t)bas->bsh,
+		    0, 0, 0, &phyp_inbuflen, &phyp_inbuf.u64[0],
+		    &phyp_inbuf.u64[1]);
+		if (err != H_SUCCESS) {
+			uart_unlock(hwmtx);
 			return (-1);
+		}
 	}
 
-	if (phyp_inbuflen == 0)
+	if (phyp_inbuflen == 0) {
+		uart_unlock(hwmtx);
 		return (-1);
+	}
 
 	ch = phyp_inbuf.str[0];
 	phyp_inbuflen--;
 	if (phyp_inbuflen > 0)
 		memcpy(&phyp_inbuf.str[0], &phyp_inbuf.str[1], phyp_inbuflen);
 
-#if defined(KDB) && defined(ALT_BREAK_TO_DEBUGGER)
-	if ((kdb_brk = kdb_alt_break(ch, &alt_break_state)) != 0) {
-		switch (kdb_brk) {
-		case KDB_REQ_DEBUGGER:
-			kdb_enter(KDB_WHY_BREAK,
-			    "Break sequence on console");
-			break;
-		case KDB_REQ_PANIC:
-			kdb_panic("Panic sequence on console");
-			break;
-		case KDB_REQ_REBOOT:
-			kdb_reboot();
-			break;
-
-		}
-	}
-#endif
+	uart_unlock(hwmtx);
 	return (ch);
 }
 
 static void
-phyp_cnputc(struct consdev *cp, int c)
+phyp_uart_putc(struct uart_bas *bas, int c)
 {
 	uint64_t cbuf;
 
 	cbuf = (uint64_t)c << 56;
-	phyp_hcall(H_PUT_TERM_CHAR, termno, 1UL, cbuf, 0);
+	phyp_hcall(H_PUT_TERM_CHAR, (uint64_t)bas->bsh, 1UL, cbuf, 0);
 }
 
+static int
+phyp_uart_rxready(struct uart_bas *bas)
+{
+	return (1);
+}



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201111022055.pA2KtuoW037948>