Date: Tue, 6 Mar 2012 00:43:02 GMT From: Robert Watson <rwatson@FreeBSD.org> To: Perforce Change Reviews <perforce@freebsd.org> Subject: PERFORCE change 207486 for review Message-ID: <201203060043.q260h2fJ071551@skunkworks.freebsd.org>
next in thread | raw e-mail | index | archive | help
http://p4web.freebsd.org/@@207486?ac=10 Change 207486 by rwatson@rwatson_svr_ctsrd_mipsbuild on 2012/03/06 00:42:10 Add mocked up high-level TTY driver support to the Altera JTAG UART driver for the FreeBSD/BERI port. This is under-tested as I am currently running into a possible cache bug that prevents me from getting to the point where it might be used. However, low-level console support appears still to be working fine. The driver uses polled input on a timer, as is the case for a number of low-level hypervisor and debugging consoles -- in the longer term, we want to make this interrupt-driven instead, and perhaps hook it up to the uart(4) framework. However, the JTAG UART is .. minimalist .. making much of that framework's functionality moot. Affected files ... .. //depot/projects/ctsrd/beribsd/src/sys/mips/beri/altera_jtag_uart.c#3 edit Differences ... ==== //depot/projects/ctsrd/beribsd/src/sys/mips/beri/altera_jtag_uart.c#3 (text+ko) ==== @@ -34,9 +34,36 @@ #include <sys/param.h> #include <sys/cons.h> #include <sys/endian.h> +#include <sys/kdb.h> #include <sys/systm.h> #include <sys/kernel.h> +#include <sys/tty.h> + +#include <ddb/ddb.h> + +#define AJU_LOCK_INIT() mtx_init(&aj_uart_lock, "aj_uart_lock", \ + NULL, MTX_SPIN) + +#define AJU_LOCK() do { \ + if (!kdb_active) \ + mtx_lock_spin(&aj_uart_lock); \ +} while (0) +#define AJU_LOCK_ASSERT() do { \ + if (!kdb_active) \ + mtx_assert(&aj_uart_lock, MA_OWNED); \ +} while (0) + +#define AJU_UNLOCK() do { \ + if (!kdb_active) \ + mtx_unlock_spin(&aj_uart_lock); \ +} while (0) + +static struct mtx aj_uart_lock; + +/* + * Low-level console driver functions. + */ static cn_probe_t aj_uart_cnprobe; static cn_init_t aj_uart_cninit; static cn_term_t aj_uart_cnterm; @@ -46,6 +73,24 @@ static cn_ungrab_t aj_uart_cnungrab; /* + * TTY-level fields. + */ +static tsw_outwakeup_t aj_uart_outwakeup; + +static struct ttydevsw aj_uart_ttydevsw = { + .tsw_flags = TF_NOPREFIX, + .tsw_outwakeup = aj_uart_outwakeup, +}; + +static struct callout aj_uart_callout; +static u_int aj_uart_polltime = 1; +#ifdef KDB +static int aj_uart_alt_break_state; +#endif + +static void aj_uart_timeout(void *); + +/* * I/O routines lifted from Deimos. * * XXXRW: Should be using FreeBSD's bus routines here. @@ -208,6 +253,8 @@ { uint32_t v; + AJU_LOCK_ASSERT(); + if (buffer_valid) return (1); v = aj_uart_data_read(); @@ -223,6 +270,8 @@ aj_uart_write(char ch) { + AJU_LOCK_ASSERT(); + while (!aj_uart_writable()); aj_uart_data_write(ch); } @@ -231,6 +280,8 @@ aj_uart_read(void) { + AJU_LOCK_ASSERT(); + while (!aj_uart_readable()); buffer_valid = 0; return (buffer_data); @@ -251,6 +302,7 @@ aj_uart_cninit(struct consdev *cp) { + AJU_LOCK_INIT(); } static void @@ -262,15 +314,21 @@ static int aj_uart_cngetc(struct consdev *cp) { + int ret; - return (aj_uart_read()); + AJU_LOCK(); + ret = aj_uart_read(); + AJU_UNLOCK(); + return (ret); } static void aj_uart_cnputc(struct consdev *cp, int c) { + AJU_LOCK(); aj_uart_write(c); + AJU_UNLOCK(); } static void @@ -286,3 +344,66 @@ } CONSOLE_DRIVER(aj_uart); + +/* + * TTY-level functions for aj_uart. + */ +static void +aj_uart_ttyinit(void *unused) +{ + struct tty *tp; + + tp = tty_alloc(&aj_uart_ttydevsw, NULL); + tty_init_console(tp, 0); + tty_makedev(tp, NULL, "%s", "ajuart"); + callout_init(&aj_uart_callout, CALLOUT_MPSAFE); + callout_reset(&aj_uart_callout, aj_uart_polltime, aj_uart_timeout, + tp); +} +SYSINIT(aj_uart_ttyinit, SI_SUB_CONFIGURE, SI_ORDER_MIDDLE, aj_uart_ttyinit, + NULL); + +static void +aj_uart_outwakeup(struct tty *tp) +{ + int len; + u_char ch; + + /* + * XXXRW: Would be nice not to do blocking writes to the UART here, + * rescheduling on our timer tick if work remains to be done. + */ + for (;;) { +#ifdef KDB + kdb_alt_break(ch, &aj_uart_alt_break_state); +#endif + len = ttydisc_getc(tp, &ch, sizeof(ch)); + if (len == 0) + break; + AJU_LOCK(); + aj_uart_write(ch); + AJU_UNLOCK(); + } +} + +static void +aj_uart_timeout(void *v) +{ + struct tty *tp; + int c; + + tp = v; + tty_lock(tp); + AJU_LOCK(); + while (aj_uart_readable()) { + c = aj_uart_read(); + AJU_UNLOCK(); + ttydisc_rint(tp, c, 0); + AJU_LOCK(); + } + AJU_UNLOCK(); + ttydisc_rint_done(tp); + tty_unlock(tp); + callout_reset(&aj_uart_callout, aj_uart_polltime, aj_uart_timeout, + tp); +}
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201203060043.q260h2fJ071551>