svn commit: r227033 - in projects/pseries: dev/uart powerpc/pseries
Nathan Whitehorn
nwhitehorn at FreeBSD.org
Wed Nov 2 20:55:56 UTC 2011
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", ®, 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);
+}
More information about the svn-src-projects
mailing list