htif_console.c revision 303975
1259698Sdim/*-
2259698Sdim * Copyright (c) 2015-2016 Ruslan Bukin <br@bsdpad.com>
3259698Sdim * All rights reserved.
4259698Sdim *
5259698Sdim * Portions of this software were developed by SRI International and the
6259698Sdim * University of Cambridge Computer Laboratory under DARPA/AFRL contract
7259698Sdim * FA8750-10-C-0237 ("CTSRD"), as part of the DARPA CRASH research programme.
8259698Sdim *
9259698Sdim * Portions of this software were developed by the University of Cambridge
10259698Sdim * Computer Laboratory as part of the CTSRD Project, with support from the
11259698Sdim * UK Higher Education Innovation Fund (HEIF).
12259698Sdim *
13259698Sdim * Redistribution and use in source and binary forms, with or without
14259698Sdim * modification, are permitted provided that the following conditions
15259698Sdim * are met:
16259698Sdim * 1. Redistributions of source code must retain the above copyright
17259698Sdim *    notice, this list of conditions and the following disclaimer.
18259698Sdim * 2. Redistributions in binary form must reproduce the above copyright
19259698Sdim *    notice, this list of conditions and the following disclaimer in the
20259698Sdim *    documentation and/or other materials provided with the distribution.
21259698Sdim *
22259698Sdim * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
23259698Sdim * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24259698Sdim * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25259698Sdim * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
26259698Sdim * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27259698Sdim * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28259698Sdim * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29259698Sdim * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30259698Sdim * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31259698Sdim * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32259698Sdim * SUCH DAMAGE.
33259698Sdim */
34259698Sdim
35259698Sdim#include <sys/cdefs.h>
36259698Sdim__FBSDID("$FreeBSD: releng/11.0/sys/riscv/htif/htif_console.c 296614 2016-03-10 15:51:43Z br $");
37259698Sdim
38259698Sdim#include <sys/param.h>
39259698Sdim#include <sys/kdb.h>
40259698Sdim#include <sys/kernel.h>
41259698Sdim#include <sys/priv.h>
42259698Sdim#include <sys/systm.h>
43259698Sdim#include <sys/types.h>
44259698Sdim#include <sys/conf.h>
45259698Sdim#include <sys/cons.h>
46259698Sdim#include <sys/consio.h>
47259698Sdim#include <sys/tty.h>
48259698Sdim#include <sys/bus.h>
49259698Sdim#include <sys/module.h>
50259698Sdim
51259698Sdim#include <machine/bus.h>
52259698Sdim#include <machine/trap.h>
53259698Sdim
54259698Sdim#include "htif.h"
55259698Sdim
56259698Sdim#include <dev/ofw/openfirm.h>
57259698Sdim
58259698Sdim#include <ddb/ddb.h>
59259698Sdim
60259698Sdimextern uint64_t console_intr;
61259698Sdim
62259698Sdimstatic tsw_outwakeup_t riscvtty_outwakeup;
63259698Sdim
64259698Sdimstatic struct ttydevsw riscv_ttydevsw = {
65259698Sdim	.tsw_flags	= TF_NOPREFIX,
66259698Sdim	.tsw_outwakeup	= riscvtty_outwakeup,
67259698Sdim};
68259698Sdim
69259698Sdimstatic int			polltime;
70259698Sdimstatic struct callout		riscv_callout;
71259698Sdimstatic struct tty 		*tp = NULL;
72259698Sdim
73259698Sdim#if defined(KDB)
74259698Sdimstatic int			alt_break_state;
75259698Sdim#endif
76259698Sdim
77259698Sdimstatic void	riscv_timeout(void *);
78259698Sdim
79259698Sdimstatic cn_probe_t	riscv_cnprobe;
80259698Sdimstatic cn_init_t	riscv_cninit;
81259698Sdimstatic cn_term_t	riscv_cnterm;
82259698Sdimstatic cn_getc_t	riscv_cngetc;
83259698Sdimstatic cn_putc_t	riscv_cnputc;
84259698Sdimstatic cn_grab_t	riscv_cngrab;
85259698Sdimstatic cn_ungrab_t	riscv_cnungrab;
86259698Sdim
87259698SdimCONSOLE_DRIVER(riscv);
88259698Sdim
89#define	MAX_BURST_LEN		1
90#define	QUEUE_SIZE		256
91#define	CONSOLE_DEFAULT_ID	1ul
92#define	SPIN_IN_MACHINE_MODE	1
93
94struct queue_entry {
95	uint64_t data;
96	uint64_t used;
97	struct queue_entry *next;
98};
99
100struct queue_entry cnqueue[QUEUE_SIZE];
101struct queue_entry *entry_last;
102struct queue_entry *entry_served;
103
104static void
105htif_putc(int c)
106{
107	uint64_t cmd;
108
109	cmd = (HTIF_CMD_WRITE << HTIF_CMD_SHIFT);
110	cmd |= (CONSOLE_DEFAULT_ID << HTIF_DEV_ID_SHIFT);
111	cmd |= c;
112
113#ifdef SPIN_IN_MACHINE_MODE
114	machine_command(ECALL_HTIF_LOWPUTC, cmd);
115#else
116	htif_command(cmd);
117#endif
118
119}
120
121static uint8_t
122htif_getc(void)
123{
124	uint64_t cmd;
125	uint8_t res;
126
127	cmd = (HTIF_CMD_READ << HTIF_CMD_SHIFT);
128	cmd |= (CONSOLE_DEFAULT_ID << HTIF_DEV_ID_SHIFT);
129
130	res = htif_command(cmd);
131
132	return (res);
133}
134
135static void
136riscv_putc(int c)
137{
138	uint64_t counter;
139	uint64_t *cc;
140	uint64_t val;
141
142	val = 0;
143	counter = 0;
144
145	cc = (uint64_t*)&console_intr;
146	*cc = 0;
147
148	htif_putc(c);
149
150#ifndef SPIN_IN_MACHINE_MODE
151	/* Wait for an interrupt */
152	__asm __volatile(
153		"li	%0, 1\n"	/* counter = 1 */
154		"slli	%0, %0, 12\n"	/* counter <<= 12 */
155	"1:"
156		"addi	%0, %0, -1\n"	/* counter -= 1 */
157		"beqz	%0, 2f\n"	/* counter == 0 ? finish */
158		"ld	%1, 0(%2)\n"	/* val = *cc */
159		"beqz	%1, 1b\n"	/* val == 0 ? repeat */
160	"2:"
161		: "=&r"(counter), "=&r"(val) : "r"(cc)
162	);
163#endif
164}
165
166#ifdef EARLY_PRINTF
167early_putc_t *early_putc = riscv_putc;
168#endif
169
170static void
171cn_drvinit(void *unused)
172{
173
174	if (riscv_consdev.cn_pri != CN_DEAD &&
175	    riscv_consdev.cn_name[0] != '\0') {
176		tp = tty_alloc(&riscv_ttydevsw, NULL);
177		tty_init_console(tp, 0);
178		tty_makedev(tp, NULL, "%s", "rcons");
179
180		polltime = 1;
181
182		callout_init(&riscv_callout, 1);
183		callout_reset(&riscv_callout, polltime, riscv_timeout, NULL);
184	}
185}
186
187SYSINIT(cndev, SI_SUB_CONFIGURE, SI_ORDER_MIDDLE, cn_drvinit, NULL);
188
189static void
190riscvtty_outwakeup(struct tty *tp)
191{
192	u_char buf[MAX_BURST_LEN];
193	int len;
194	int i;
195
196	for (;;) {
197		len = ttydisc_getc(tp, buf, sizeof(buf));
198		if (len == 0)
199			break;
200
201		KASSERT(len == 1, ("tty error"));
202
203		for (i = 0; i < len; i++)
204			riscv_putc(buf[i]);
205	}
206}
207
208static void
209riscv_timeout(void *v)
210{
211	int c;
212
213	tty_lock(tp);
214	while ((c = riscv_cngetc(NULL)) != -1)
215		ttydisc_rint(tp, c, 0);
216	ttydisc_rint_done(tp);
217	tty_unlock(tp);
218
219	callout_reset(&riscv_callout, polltime, riscv_timeout, NULL);
220}
221
222static void
223riscv_cnprobe(struct consdev *cp)
224{
225
226	cp->cn_pri = CN_NORMAL;
227}
228
229static void
230riscv_cninit(struct consdev *cp)
231{
232	int i;
233
234	strcpy(cp->cn_name, "rcons");
235
236	for (i = 0; i < QUEUE_SIZE; i++) {
237		if (i == (QUEUE_SIZE - 1))
238			cnqueue[i].next = &cnqueue[0];
239		else
240			cnqueue[i].next = &cnqueue[i+1];
241		cnqueue[i].data = 0;
242		cnqueue[i].used = 0;
243	}
244
245	entry_last = &cnqueue[0];
246	entry_served = &cnqueue[0];
247}
248
249static void
250riscv_cnterm(struct consdev *cp)
251{
252
253}
254
255static void
256riscv_cngrab(struct consdev *cp)
257{
258
259}
260
261static void
262riscv_cnungrab(struct consdev *cp)
263{
264
265}
266
267static int
268riscv_cngetc(struct consdev *cp)
269{
270#if defined(KDB)
271	uint64_t devcmd;
272	uint64_t entry;
273	uint64_t devid;
274#endif
275	uint8_t data;
276	int ch;
277
278	htif_getc();
279
280#if defined(KDB)
281	if (kdb_active) {
282		entry = machine_command(ECALL_HTIF_GET_ENTRY, 0);
283		while (entry) {
284			devid = HTIF_DEV_ID(entry);
285			devcmd = HTIF_DEV_CMD(entry);
286			data = HTIF_DEV_DATA(entry);
287
288			if (devid == CONSOLE_DEFAULT_ID && devcmd == 0) {
289				entry_last->data = data;
290				entry_last->used = 1;
291				entry_last = entry_last->next;
292			} else {
293				printf("Lost interrupt: devid %d\n",
294				    devid);
295			}
296
297			entry = machine_command(ECALL_HTIF_GET_ENTRY, 0);
298		}
299	}
300#endif
301
302	if (entry_served->used == 1) {
303		data = entry_served->data;
304		entry_served->used = 0;
305		entry_served = entry_served->next;
306		ch = (data & 0xff);
307		if (ch > 0 && ch < 0xff) {
308#if defined(KDB)
309			kdb_alt_break(ch, &alt_break_state);
310#endif
311			return (ch);
312		}
313	}
314
315	return (-1);
316}
317
318static void
319riscv_cnputc(struct consdev *cp, int c)
320{
321
322	riscv_putc(c);
323}
324
325/*
326 * Bus interface.
327 */
328
329struct htif_console_softc {
330	device_t	dev;
331	int		running;
332	int		intr_chan;
333	int		cmd_done;
334	int		curtag;
335	int		index;
336};
337
338static void
339htif_console_intr(void *arg, uint64_t entry)
340{
341	struct htif_console_softc *sc;
342	uint8_t devcmd;
343	uint64_t data;
344
345	sc = arg;
346
347	devcmd = HTIF_DEV_CMD(entry);
348	data = HTIF_DEV_DATA(entry);
349
350	if (devcmd == 0) {
351		entry_last->data = data;
352		entry_last->used = 1;
353		entry_last = entry_last->next;
354	}
355}
356
357static int
358htif_console_probe(device_t dev)
359{
360
361	return (0);
362}
363
364static int
365htif_console_attach(device_t dev)
366{
367	struct htif_console_softc *sc;
368
369	sc = device_get_softc(dev);
370	sc->dev = dev;
371
372	sc->index = htif_get_index(dev);
373	if (sc->index < 0)
374		return (EINVAL);
375
376	htif_setup_intr(sc->index, htif_console_intr, sc);
377
378	return (0);
379}
380
381static device_method_t htif_console_methods[] = {
382	DEVMETHOD(device_probe,		htif_console_probe),
383	DEVMETHOD(device_attach,	htif_console_attach),
384	DEVMETHOD_END
385};
386
387static driver_t htif_console_driver = {
388	"htif_console",
389	htif_console_methods,
390	sizeof(struct htif_console_softc)
391};
392
393static devclass_t htif_console_devclass;
394
395DRIVER_MODULE(htif_console, htif, htif_console_driver,
396    htif_console_devclass, 0, 0);
397