xref: /freebsd/sys/powerpc/pseries/phyp_console.c (revision 90653c1c5c2d2c94a1b6bc6b61a3f2ad3a099390)
17a8d25c0SNathan Whitehorn /*-
27a8d25c0SNathan Whitehorn  * Copyright (C) 2011 by Nathan Whitehorn. All rights reserved.
37a8d25c0SNathan Whitehorn  *
47a8d25c0SNathan Whitehorn  * Redistribution and use in source and binary forms, with or without
57a8d25c0SNathan Whitehorn  * modification, are permitted provided that the following conditions
67a8d25c0SNathan Whitehorn  * are met:
77a8d25c0SNathan Whitehorn  * 1. Redistributions of source code must retain the above copyright
87a8d25c0SNathan Whitehorn  *    notice, this list of conditions and the following disclaimer.
97a8d25c0SNathan Whitehorn  * 2. Redistributions in binary form must reproduce the above copyright
107a8d25c0SNathan Whitehorn  *    notice, this list of conditions and the following disclaimer in the
117a8d25c0SNathan Whitehorn  *    documentation and/or other materials provided with the distribution.
127a8d25c0SNathan Whitehorn  *
137a8d25c0SNathan Whitehorn  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
147a8d25c0SNathan Whitehorn  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
157a8d25c0SNathan Whitehorn  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
167a8d25c0SNathan Whitehorn  * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
177a8d25c0SNathan Whitehorn  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
187a8d25c0SNathan Whitehorn  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
197a8d25c0SNathan Whitehorn  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
207a8d25c0SNathan Whitehorn  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
217a8d25c0SNathan Whitehorn  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
227a8d25c0SNathan Whitehorn  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
237a8d25c0SNathan Whitehorn  */
247a8d25c0SNathan Whitehorn 
257a8d25c0SNathan Whitehorn #include <sys/cdefs.h>
267a8d25c0SNathan Whitehorn __FBSDID("$FreeBSD$");
277a8d25c0SNathan Whitehorn 
287a8d25c0SNathan Whitehorn #include <sys/param.h>
297a8d25c0SNathan Whitehorn #include <sys/kdb.h>
307a8d25c0SNathan Whitehorn #include <sys/kernel.h>
317a8d25c0SNathan Whitehorn #include <sys/priv.h>
327a8d25c0SNathan Whitehorn #include <sys/systm.h>
337a8d25c0SNathan Whitehorn #include <sys/module.h>
347a8d25c0SNathan Whitehorn #include <sys/types.h>
357a8d25c0SNathan Whitehorn #include <sys/conf.h>
367a8d25c0SNathan Whitehorn #include <sys/cons.h>
377a8d25c0SNathan Whitehorn #include <sys/tty.h>
387a8d25c0SNathan Whitehorn #include <machine/bus.h>
397a8d25c0SNathan Whitehorn 
407a8d25c0SNathan Whitehorn #include <dev/ofw/openfirm.h>
417a8d25c0SNathan Whitehorn #include <dev/ofw/ofw_bus.h>
427a8d25c0SNathan Whitehorn #include <dev/ofw/ofw_bus_subr.h>
437a8d25c0SNathan Whitehorn #include <dev/uart/uart.h>
447a8d25c0SNathan Whitehorn #include <dev/uart/uart_cpu.h>
457a8d25c0SNathan Whitehorn #include <dev/uart/uart_bus.h>
467a8d25c0SNathan Whitehorn 
477a8d25c0SNathan Whitehorn #include "phyp-hvcall.h"
487a8d25c0SNathan Whitehorn #include "uart_if.h"
497a8d25c0SNathan Whitehorn 
507a8d25c0SNathan Whitehorn struct uart_phyp_softc {
517a8d25c0SNathan Whitehorn 	device_t dev;
527a8d25c0SNathan Whitehorn 	phandle_t node;
537a8d25c0SNathan Whitehorn 	int vtermid;
547a8d25c0SNathan Whitehorn 
557a8d25c0SNathan Whitehorn 	struct tty *tp;
567a8d25c0SNathan Whitehorn 	struct resource *irqres;
577a8d25c0SNathan Whitehorn 	int irqrid;
587a8d25c0SNathan Whitehorn 	struct callout callout;
597a8d25c0SNathan Whitehorn 	void *sc_icookie;
607a8d25c0SNathan Whitehorn 	int polltime;
617a8d25c0SNathan Whitehorn 
627a8d25c0SNathan Whitehorn 	struct mtx sc_mtx;
637a8d25c0SNathan Whitehorn 	int protocol;
647a8d25c0SNathan Whitehorn 
657a8d25c0SNathan Whitehorn 	union {
667a8d25c0SNathan Whitehorn 		uint64_t u64[2];
677a8d25c0SNathan Whitehorn 		char str[16];
687a8d25c0SNathan Whitehorn 	} phyp_inbuf;
697a8d25c0SNathan Whitehorn 	uint64_t inbuflen;
707a8d25c0SNathan Whitehorn 	uint8_t outseqno;
717a8d25c0SNathan Whitehorn };
727a8d25c0SNathan Whitehorn 
737a8d25c0SNathan Whitehorn static struct uart_phyp_softc	*console_sc = NULL;
747a8d25c0SNathan Whitehorn #if defined(KDB)
757a8d25c0SNathan Whitehorn static int			alt_break_state;
767a8d25c0SNathan Whitehorn #endif
777a8d25c0SNathan Whitehorn 
787a8d25c0SNathan Whitehorn enum {
797a8d25c0SNathan Whitehorn 	HVTERM1, HVTERMPROT
807a8d25c0SNathan Whitehorn };
817a8d25c0SNathan Whitehorn 
827a8d25c0SNathan Whitehorn #define VS_DATA_PACKET_HEADER		0xff
837a8d25c0SNathan Whitehorn #define VS_CONTROL_PACKET_HEADER	0xfe
847a8d25c0SNathan Whitehorn #define  VSV_SET_MODEM_CTL		0x01
857a8d25c0SNathan Whitehorn #define  VSV_MODEM_CTL_UPDATE		0x02
867a8d25c0SNathan Whitehorn #define  VSV_RENEGOTIATE_CONNECTION	0x03
877a8d25c0SNathan Whitehorn #define VS_QUERY_PACKET_HEADER		0xfd
887a8d25c0SNathan Whitehorn #define  VSV_SEND_VERSION_NUMBER	0x01
897a8d25c0SNathan Whitehorn #define  VSV_SEND_MODEM_CTL_STATUS	0x02
907a8d25c0SNathan Whitehorn #define VS_QUERY_RESPONSE_PACKET_HEADER	0xfc
917a8d25c0SNathan Whitehorn 
927a8d25c0SNathan Whitehorn static int uart_phyp_probe(device_t dev);
937a8d25c0SNathan Whitehorn static int uart_phyp_attach(device_t dev);
947a8d25c0SNathan Whitehorn static void uart_phyp_intr(void *v);
957a8d25c0SNathan Whitehorn 
967a8d25c0SNathan Whitehorn static device_method_t uart_phyp_methods[] = {
977a8d25c0SNathan Whitehorn 	/* Device interface */
987a8d25c0SNathan Whitehorn 	DEVMETHOD(device_probe,		uart_phyp_probe),
997a8d25c0SNathan Whitehorn 	DEVMETHOD(device_attach,	uart_phyp_attach),
1007a8d25c0SNathan Whitehorn 
1017a8d25c0SNathan Whitehorn 	DEVMETHOD_END
1027a8d25c0SNathan Whitehorn };
1037a8d25c0SNathan Whitehorn 
1047a8d25c0SNathan Whitehorn static driver_t uart_phyp_driver = {
1057a8d25c0SNathan Whitehorn 	"uart",
1067a8d25c0SNathan Whitehorn 	uart_phyp_methods,
1077a8d25c0SNathan Whitehorn 	sizeof(struct uart_phyp_softc),
1087a8d25c0SNathan Whitehorn };
1097a8d25c0SNathan Whitehorn 
1107a8d25c0SNathan Whitehorn DRIVER_MODULE(uart_phyp, vdevice, uart_phyp_driver, uart_devclass, 0, 0);
1117a8d25c0SNathan Whitehorn 
1127a8d25c0SNathan Whitehorn static cn_probe_t uart_phyp_cnprobe;
1137a8d25c0SNathan Whitehorn static cn_init_t uart_phyp_cninit;
1147a8d25c0SNathan Whitehorn static cn_term_t uart_phyp_cnterm;
1157a8d25c0SNathan Whitehorn static cn_getc_t uart_phyp_cngetc;
1167a8d25c0SNathan Whitehorn static cn_putc_t uart_phyp_cnputc;
1177a8d25c0SNathan Whitehorn static cn_grab_t uart_phyp_cngrab;
1187a8d25c0SNathan Whitehorn static cn_ungrab_t uart_phyp_cnungrab;
1197a8d25c0SNathan Whitehorn 
1207a8d25c0SNathan Whitehorn CONSOLE_DRIVER(uart_phyp);
1217a8d25c0SNathan Whitehorn 
1227a8d25c0SNathan Whitehorn static void uart_phyp_ttyoutwakeup(struct tty *tp);
1237a8d25c0SNathan Whitehorn 
1247a8d25c0SNathan Whitehorn static struct ttydevsw uart_phyp_tty_class = {
1257a8d25c0SNathan Whitehorn 	.tsw_flags	= TF_INITLOCK|TF_CALLOUT,
1267a8d25c0SNathan Whitehorn 	.tsw_outwakeup	= uart_phyp_ttyoutwakeup,
1277a8d25c0SNathan Whitehorn };
1287a8d25c0SNathan Whitehorn 
1297a8d25c0SNathan Whitehorn static int
1307a8d25c0SNathan Whitehorn uart_phyp_probe_node(struct uart_phyp_softc *sc)
1317a8d25c0SNathan Whitehorn {
1327a8d25c0SNathan Whitehorn 	phandle_t node = sc->node;
1337a8d25c0SNathan Whitehorn 	uint32_t reg;
1347a8d25c0SNathan Whitehorn 	char buf[64];
1357a8d25c0SNathan Whitehorn 
1367a8d25c0SNathan Whitehorn 	sc->inbuflen = 0;
1377a8d25c0SNathan Whitehorn 	sc->outseqno = 0;
1387a8d25c0SNathan Whitehorn 
1397a8d25c0SNathan Whitehorn 	if (OF_getprop(node, "name", buf, sizeof(buf)) <= 0)
1407a8d25c0SNathan Whitehorn 		return (ENXIO);
1417a8d25c0SNathan Whitehorn 	if (strcmp(buf, "vty") != 0)
1427a8d25c0SNathan Whitehorn 		return (ENXIO);
1437a8d25c0SNathan Whitehorn 
1447a8d25c0SNathan Whitehorn 	if (OF_getprop(node, "device_type", buf, sizeof(buf)) <= 0)
1457a8d25c0SNathan Whitehorn 		return (ENXIO);
1467a8d25c0SNathan Whitehorn 	if (strcmp(buf, "serial") != 0)
1477a8d25c0SNathan Whitehorn 		return (ENXIO);
1487a8d25c0SNathan Whitehorn 
1497a8d25c0SNathan Whitehorn 	reg = -1;
1507a8d25c0SNathan Whitehorn 	OF_getprop(node, "reg", &reg, sizeof(reg));
1517a8d25c0SNathan Whitehorn 	if (reg == -1)
1527a8d25c0SNathan Whitehorn 		return (ENXIO);
153145341e9SNathan Whitehorn 	sc->vtermid = reg;
1547a8d25c0SNathan Whitehorn 	sc->node = node;
1557a8d25c0SNathan Whitehorn 
1567a8d25c0SNathan Whitehorn 	if (OF_getprop(node, "compatible", buf, sizeof(buf)) <= 0)
1577a8d25c0SNathan Whitehorn 		return (ENXIO);
1587a8d25c0SNathan Whitehorn 	if (strcmp(buf, "hvterm1") == 0) {
1597a8d25c0SNathan Whitehorn 		sc->protocol = HVTERM1;
1607a8d25c0SNathan Whitehorn 		return (0);
1617a8d25c0SNathan Whitehorn 	} else if (strcmp(buf, "hvterm-protocol") == 0) {
1627a8d25c0SNathan Whitehorn 		sc->protocol = HVTERMPROT;
1637a8d25c0SNathan Whitehorn 		return (0);
1647a8d25c0SNathan Whitehorn 	}
1657a8d25c0SNathan Whitehorn 
1667a8d25c0SNathan Whitehorn 	return (ENXIO);
1677a8d25c0SNathan Whitehorn }
1687a8d25c0SNathan Whitehorn 
1697a8d25c0SNathan Whitehorn static int
1707a8d25c0SNathan Whitehorn uart_phyp_probe(device_t dev)
1717a8d25c0SNathan Whitehorn {
1727a8d25c0SNathan Whitehorn 	const char *name;
1737a8d25c0SNathan Whitehorn 	struct uart_phyp_softc sc;
1747a8d25c0SNathan Whitehorn 	int err;
1757a8d25c0SNathan Whitehorn 
1767a8d25c0SNathan Whitehorn 	name = ofw_bus_get_name(dev);
1777a8d25c0SNathan Whitehorn 	if (name == NULL || strcmp(name, "vty") != 0)
1787a8d25c0SNathan Whitehorn 		return (ENXIO);
1797a8d25c0SNathan Whitehorn 
1807a8d25c0SNathan Whitehorn 	sc.node = ofw_bus_get_node(dev);
1817a8d25c0SNathan Whitehorn 	err = uart_phyp_probe_node(&sc);
1827a8d25c0SNathan Whitehorn 	if (err != 0)
1837a8d25c0SNathan Whitehorn 		return (err);
1847a8d25c0SNathan Whitehorn 
1857a8d25c0SNathan Whitehorn 	device_set_desc(dev, "POWER Hypervisor Virtual Serial Port");
1867a8d25c0SNathan Whitehorn 
1877a8d25c0SNathan Whitehorn 	return (err);
1887a8d25c0SNathan Whitehorn }
1897a8d25c0SNathan Whitehorn 
1907a8d25c0SNathan Whitehorn static void
1917a8d25c0SNathan Whitehorn uart_phyp_cnprobe(struct consdev *cp)
1927a8d25c0SNathan Whitehorn {
1937a8d25c0SNathan Whitehorn 	char buf[64];
1947a8d25c0SNathan Whitehorn 	ihandle_t stdout;
1957a8d25c0SNathan Whitehorn 	phandle_t input, opts, chosen;
1967a8d25c0SNathan Whitehorn 	static struct uart_phyp_softc sc;
1977a8d25c0SNathan Whitehorn 
1987a8d25c0SNathan Whitehorn 	if ((opts = OF_finddevice("/options")) == -1)
1997a8d25c0SNathan Whitehorn 		goto fail;
2007a8d25c0SNathan Whitehorn 	if ((chosen = OF_finddevice("/chosen")) == -1)
2017a8d25c0SNathan Whitehorn 		goto fail;
2027a8d25c0SNathan Whitehorn 
2037a8d25c0SNathan Whitehorn 	/* Check if OF has an active stdin/stdout */
2047a8d25c0SNathan Whitehorn 	input = -1;
2057a8d25c0SNathan Whitehorn 	if (OF_getprop(chosen, "stdout", &stdout,
2067a8d25c0SNathan Whitehorn 	    sizeof(stdout)) == sizeof(stdout) && stdout != 0)
2077a8d25c0SNathan Whitehorn 		input = OF_instance_to_package(stdout);
2087a8d25c0SNathan Whitehorn 	if (input == -1)
2097a8d25c0SNathan Whitehorn 		goto fail;
2107a8d25c0SNathan Whitehorn 
2117a8d25c0SNathan Whitehorn 	if (OF_getprop(input, "device_type", buf, sizeof(buf)) == -1)
2127a8d25c0SNathan Whitehorn 		goto fail;
2137a8d25c0SNathan Whitehorn 	if (strcmp(buf, "serial") != 0)
2147a8d25c0SNathan Whitehorn 		goto fail;
2157a8d25c0SNathan Whitehorn 
2167a8d25c0SNathan Whitehorn 	sc.node = input;
2177a8d25c0SNathan Whitehorn 	if (uart_phyp_probe_node(&sc) != 0)
2187a8d25c0SNathan Whitehorn 		goto fail;
2197a8d25c0SNathan Whitehorn 	mtx_init(&sc.sc_mtx, "uart_phyp", NULL, MTX_SPIN | MTX_QUIET |
2207a8d25c0SNathan Whitehorn 	    MTX_NOWITNESS);
2217a8d25c0SNathan Whitehorn 
2227a8d25c0SNathan Whitehorn 	cp->cn_pri = CN_NORMAL;
2237a8d25c0SNathan Whitehorn 	console_sc = &sc;
2247a8d25c0SNathan Whitehorn 	return;
2257a8d25c0SNathan Whitehorn 
2267a8d25c0SNathan Whitehorn fail:
2277a8d25c0SNathan Whitehorn 	cp->cn_pri = CN_DEAD;
2287a8d25c0SNathan Whitehorn 	return;
2297a8d25c0SNathan Whitehorn }
2307a8d25c0SNathan Whitehorn 
2317a8d25c0SNathan Whitehorn static int
2327a8d25c0SNathan Whitehorn uart_phyp_attach(device_t dev)
2337a8d25c0SNathan Whitehorn {
2347a8d25c0SNathan Whitehorn 	struct uart_phyp_softc *sc;
2357a8d25c0SNathan Whitehorn 	int unit;
2367a8d25c0SNathan Whitehorn 
2377a8d25c0SNathan Whitehorn 	sc = device_get_softc(dev);
2387a8d25c0SNathan Whitehorn 	sc->dev = dev;
2397a8d25c0SNathan Whitehorn 	sc->node = ofw_bus_get_node(dev);
2407a8d25c0SNathan Whitehorn 	uart_phyp_probe_node(sc);
2417a8d25c0SNathan Whitehorn 
2427a8d25c0SNathan Whitehorn 	unit = device_get_unit(dev);
2437a8d25c0SNathan Whitehorn 	sc->tp = tty_alloc(&uart_phyp_tty_class, sc);
2447a8d25c0SNathan Whitehorn 	mtx_init(&sc->sc_mtx, device_get_nameunit(dev), NULL,
2457a8d25c0SNathan Whitehorn 	    MTX_SPIN | MTX_QUIET | MTX_NOWITNESS);
2467a8d25c0SNathan Whitehorn 
2477a8d25c0SNathan Whitehorn 	if (console_sc != NULL && console_sc->vtermid == sc->vtermid) {
2487a8d25c0SNathan Whitehorn 		sc->outseqno = console_sc->outseqno;
2497a8d25c0SNathan Whitehorn 		console_sc = sc;
2507a8d25c0SNathan Whitehorn 		sprintf(uart_phyp_consdev.cn_name, "ttyu%r", unit);
2517a8d25c0SNathan Whitehorn 		tty_init_console(sc->tp, 0);
2527a8d25c0SNathan Whitehorn 	}
2537a8d25c0SNathan Whitehorn 
2547a8d25c0SNathan Whitehorn 	sc->irqrid = 0;
2557a8d25c0SNathan Whitehorn 	sc->irqres = bus_alloc_resource_any(dev, SYS_RES_IRQ, &sc->irqrid,
2567a8d25c0SNathan Whitehorn 	    RF_ACTIVE | RF_SHAREABLE);
2577a8d25c0SNathan Whitehorn 	if (sc->irqres != NULL) {
2587a8d25c0SNathan Whitehorn 		bus_setup_intr(dev, sc->irqres, INTR_TYPE_TTY | INTR_MPSAFE,
2597a8d25c0SNathan Whitehorn 		    NULL, uart_phyp_intr, sc, &sc->sc_icookie);
2607a8d25c0SNathan Whitehorn 	} else {
2617a8d25c0SNathan Whitehorn 		callout_init(&sc->callout, CALLOUT_MPSAFE);
2627a8d25c0SNathan Whitehorn 		sc->polltime = hz / 20;
2637a8d25c0SNathan Whitehorn 		if (sc->polltime < 1)
2647a8d25c0SNathan Whitehorn 			sc->polltime = 1;
2657a8d25c0SNathan Whitehorn 		callout_reset(&sc->callout, sc->polltime, uart_phyp_intr, sc);
2667a8d25c0SNathan Whitehorn 	}
2677a8d25c0SNathan Whitehorn 
2687a8d25c0SNathan Whitehorn 	tty_makedev(sc->tp, NULL, "u%r", unit);
2697a8d25c0SNathan Whitehorn 
2707a8d25c0SNathan Whitehorn 	return (0);
2717a8d25c0SNathan Whitehorn }
2727a8d25c0SNathan Whitehorn 
2737a8d25c0SNathan Whitehorn static void
2747a8d25c0SNathan Whitehorn uart_phyp_cninit(struct consdev *cp)
2757a8d25c0SNathan Whitehorn {
2767a8d25c0SNathan Whitehorn 
2777a8d25c0SNathan Whitehorn 	strcpy(cp->cn_name, "phypcons");
2787a8d25c0SNathan Whitehorn }
2797a8d25c0SNathan Whitehorn 
2807a8d25c0SNathan Whitehorn static void
2817a8d25c0SNathan Whitehorn uart_phyp_cnterm(struct consdev *cp)
2827a8d25c0SNathan Whitehorn {
2837a8d25c0SNathan Whitehorn }
2847a8d25c0SNathan Whitehorn 
2857a8d25c0SNathan Whitehorn static int
2867a8d25c0SNathan Whitehorn uart_phyp_get(struct uart_phyp_softc *sc, void *buffer, size_t bufsize)
2877a8d25c0SNathan Whitehorn {
2887a8d25c0SNathan Whitehorn 	int err;
289*90653c1cSAndreas Tobler 	int hdr = 0;
2907a8d25c0SNathan Whitehorn 
2917a8d25c0SNathan Whitehorn 	uart_lock(&sc->sc_mtx);
2927a8d25c0SNathan Whitehorn 	if (sc->inbuflen == 0) {
2937a8d25c0SNathan Whitehorn 		err = phyp_pft_hcall(H_GET_TERM_CHAR, sc->vtermid,
2947a8d25c0SNathan Whitehorn 		    0, 0, 0, &sc->inbuflen, &sc->phyp_inbuf.u64[0],
2957a8d25c0SNathan Whitehorn 		    &sc->phyp_inbuf.u64[1]);
2967a8d25c0SNathan Whitehorn 		if (err != H_SUCCESS) {
2977a8d25c0SNathan Whitehorn 			uart_unlock(&sc->sc_mtx);
2987a8d25c0SNathan Whitehorn 			return (-1);
2997a8d25c0SNathan Whitehorn 		}
300*90653c1cSAndreas Tobler 		hdr = 1;
3017a8d25c0SNathan Whitehorn 	}
3027a8d25c0SNathan Whitehorn 
3037a8d25c0SNathan Whitehorn 	if (sc->inbuflen == 0) {
3047a8d25c0SNathan Whitehorn 		uart_unlock(&sc->sc_mtx);
3057a8d25c0SNathan Whitehorn 		return (0);
3067a8d25c0SNathan Whitehorn 	}
3077a8d25c0SNathan Whitehorn 
3087a8d25c0SNathan Whitehorn 	if (bufsize > sc->inbuflen)
3097a8d25c0SNathan Whitehorn 		bufsize = sc->inbuflen;
310*90653c1cSAndreas Tobler 
311*90653c1cSAndreas Tobler 	if ((sc->protocol == HVTERMPROT) && (hdr == 1)) {
312*90653c1cSAndreas Tobler 		sc->inbuflen = sc->inbuflen - 4;
313*90653c1cSAndreas Tobler 		/* The VTERM protocol has a 4 byte header, skip it here. */
314*90653c1cSAndreas Tobler 		memmove(&sc->phyp_inbuf.str[0], &sc->phyp_inbuf.str[4],
315*90653c1cSAndreas Tobler 		    sc->inbuflen);
316*90653c1cSAndreas Tobler 	}
317*90653c1cSAndreas Tobler 
3187a8d25c0SNathan Whitehorn 	memcpy(buffer, sc->phyp_inbuf.str, bufsize);
3197a8d25c0SNathan Whitehorn 	sc->inbuflen -= bufsize;
3207a8d25c0SNathan Whitehorn 	if (sc->inbuflen > 0)
3217a8d25c0SNathan Whitehorn 		memmove(&sc->phyp_inbuf.str[0], &sc->phyp_inbuf.str[bufsize],
3227a8d25c0SNathan Whitehorn 		    sc->inbuflen);
3237a8d25c0SNathan Whitehorn 
3247a8d25c0SNathan Whitehorn 	uart_unlock(&sc->sc_mtx);
3257a8d25c0SNathan Whitehorn 	return (bufsize);
3267a8d25c0SNathan Whitehorn }
3277a8d25c0SNathan Whitehorn 
3287a8d25c0SNathan Whitehorn static int
3297a8d25c0SNathan Whitehorn uart_phyp_put(struct uart_phyp_softc *sc, void *buffer, size_t bufsize)
3307a8d25c0SNathan Whitehorn {
3317a8d25c0SNathan Whitehorn 	uint16_t seqno;
3327a8d25c0SNathan Whitehorn 	uint64_t len = 0;
333*90653c1cSAndreas Tobler 	int	err;
334*90653c1cSAndreas Tobler 
3357a8d25c0SNathan Whitehorn 	union {
336*90653c1cSAndreas Tobler 		uint64_t u64[2];
337*90653c1cSAndreas Tobler 		char bytes[16];
3387a8d25c0SNathan Whitehorn 	} cbuf;
3397a8d25c0SNathan Whitehorn 
3407a8d25c0SNathan Whitehorn 	uart_lock(&sc->sc_mtx);
3417a8d25c0SNathan Whitehorn 	switch (sc->protocol) {
3427a8d25c0SNathan Whitehorn 	case HVTERM1:
343*90653c1cSAndreas Tobler 		if (bufsize > 16)
344*90653c1cSAndreas Tobler 			bufsize = 16;
3457a8d25c0SNathan Whitehorn 		memcpy(&cbuf, buffer, bufsize);
3467a8d25c0SNathan Whitehorn 		len = bufsize;
3477a8d25c0SNathan Whitehorn 		break;
3487a8d25c0SNathan Whitehorn 	case HVTERMPROT:
349*90653c1cSAndreas Tobler 		if (bufsize > 12)
350*90653c1cSAndreas Tobler 			bufsize = 12;
3517a8d25c0SNathan Whitehorn 		seqno = sc->outseqno++;
3527a8d25c0SNathan Whitehorn 		cbuf.bytes[0] = VS_DATA_PACKET_HEADER;
353*90653c1cSAndreas Tobler 		cbuf.bytes[1] = 4 + bufsize; /* total length, max 16 bytes */
3547a8d25c0SNathan Whitehorn 		cbuf.bytes[2] = (seqno >> 8) & 0xff;
3557a8d25c0SNathan Whitehorn 		cbuf.bytes[3] = seqno & 0xff;
3567a8d25c0SNathan Whitehorn 		memcpy(&cbuf.bytes[4], buffer, bufsize);
3577a8d25c0SNathan Whitehorn 		len = 4 + bufsize;
3587a8d25c0SNathan Whitehorn 		break;
3597a8d25c0SNathan Whitehorn 	}
360*90653c1cSAndreas Tobler 
361*90653c1cSAndreas Tobler 	do {
362*90653c1cSAndreas Tobler 	    err = phyp_hcall(H_PUT_TERM_CHAR, sc->vtermid, len, cbuf.u64[0],
363*90653c1cSAndreas Tobler 			    cbuf.u64[1]);
364*90653c1cSAndreas Tobler 		DELAY(100);
365*90653c1cSAndreas Tobler 	} while (err == H_BUSY);
366*90653c1cSAndreas Tobler 
3677a8d25c0SNathan Whitehorn 	uart_unlock(&sc->sc_mtx);
3687a8d25c0SNathan Whitehorn 
3697a8d25c0SNathan Whitehorn 	return (bufsize);
3707a8d25c0SNathan Whitehorn }
3717a8d25c0SNathan Whitehorn 
3727a8d25c0SNathan Whitehorn static int
3737a8d25c0SNathan Whitehorn uart_phyp_cngetc(struct consdev *cp)
3747a8d25c0SNathan Whitehorn {
3757a8d25c0SNathan Whitehorn 	unsigned char c;
3767a8d25c0SNathan Whitehorn 	int retval;
3777a8d25c0SNathan Whitehorn 
3787a8d25c0SNathan Whitehorn 	retval = uart_phyp_get(console_sc, &c, 1);
3797a8d25c0SNathan Whitehorn 	if (retval != 1)
3807a8d25c0SNathan Whitehorn 		return (-1);
3817a8d25c0SNathan Whitehorn #if defined(KDB)
3827a8d25c0SNathan Whitehorn 	kdb_alt_break(c, &alt_break_state);
3837a8d25c0SNathan Whitehorn #endif
3847a8d25c0SNathan Whitehorn 
3857a8d25c0SNathan Whitehorn 	return (c);
3867a8d25c0SNathan Whitehorn }
3877a8d25c0SNathan Whitehorn 
3887a8d25c0SNathan Whitehorn static void
3897a8d25c0SNathan Whitehorn uart_phyp_cnputc(struct consdev *cp, int c)
3907a8d25c0SNathan Whitehorn {
3917a8d25c0SNathan Whitehorn 	unsigned char ch = c;
3927a8d25c0SNathan Whitehorn 	uart_phyp_put(console_sc, &ch, 1);
3937a8d25c0SNathan Whitehorn }
3947a8d25c0SNathan Whitehorn 
3957a8d25c0SNathan Whitehorn static void
3967a8d25c0SNathan Whitehorn uart_phyp_cngrab(struct consdev *cp)
3977a8d25c0SNathan Whitehorn {
3987a8d25c0SNathan Whitehorn }
3997a8d25c0SNathan Whitehorn 
4007a8d25c0SNathan Whitehorn static void
4017a8d25c0SNathan Whitehorn uart_phyp_cnungrab(struct consdev *cp)
4027a8d25c0SNathan Whitehorn {
4037a8d25c0SNathan Whitehorn }
4047a8d25c0SNathan Whitehorn 
4057a8d25c0SNathan Whitehorn static void
4067a8d25c0SNathan Whitehorn uart_phyp_ttyoutwakeup(struct tty *tp)
4077a8d25c0SNathan Whitehorn {
4087a8d25c0SNathan Whitehorn 	struct uart_phyp_softc *sc;
4097a8d25c0SNathan Whitehorn 	char buffer[8];
4107a8d25c0SNathan Whitehorn 	int len;
4117a8d25c0SNathan Whitehorn 
4127a8d25c0SNathan Whitehorn 	sc = tty_softc(tp);
4137a8d25c0SNathan Whitehorn 
4147a8d25c0SNathan Whitehorn 	while ((len = ttydisc_getc(tp, buffer, sizeof(buffer))) != 0)
4157a8d25c0SNathan Whitehorn 		uart_phyp_put(sc, buffer, len);
4167a8d25c0SNathan Whitehorn }
4177a8d25c0SNathan Whitehorn 
4187a8d25c0SNathan Whitehorn static void
4197a8d25c0SNathan Whitehorn uart_phyp_intr(void *v)
4207a8d25c0SNathan Whitehorn {
4217a8d25c0SNathan Whitehorn 	struct uart_phyp_softc *sc = v;
4227a8d25c0SNathan Whitehorn 	struct tty *tp = sc->tp;
4237a8d25c0SNathan Whitehorn 	unsigned char c;
4247a8d25c0SNathan Whitehorn 	int len;
4257a8d25c0SNathan Whitehorn 
4267a8d25c0SNathan Whitehorn 	tty_lock(tp);
4277a8d25c0SNathan Whitehorn 	while ((len = uart_phyp_get(sc, &c, 1)) > 0)
4287a8d25c0SNathan Whitehorn 		ttydisc_rint(tp, c, 0);
4297a8d25c0SNathan Whitehorn 	ttydisc_rint_done(tp);
4307a8d25c0SNathan Whitehorn 	tty_unlock(tp);
4317a8d25c0SNathan Whitehorn 
4327a8d25c0SNathan Whitehorn 	if (sc->irqres == NULL)
4337a8d25c0SNathan Whitehorn 		callout_reset(&sc->callout, sc->polltime, uart_phyp_intr, sc);
4347a8d25c0SNathan Whitehorn }
4357a8d25c0SNathan Whitehorn 
436