htif_console.c revision 296614
1/*- 2 * Copyright (c) 2015-2016 Ruslan Bukin <br@bsdpad.com> 3 * All rights reserved. 4 * 5 * Portions of this software were developed by SRI International and the 6 * University of Cambridge Computer Laboratory under DARPA/AFRL contract 7 * FA8750-10-C-0237 ("CTSRD"), as part of the DARPA CRASH research programme. 8 * 9 * Portions of this software were developed by the University of Cambridge 10 * Computer Laboratory as part of the CTSRD Project, with support from the 11 * UK Higher Education Innovation Fund (HEIF). 12 * 13 * Redistribution and use in source and binary forms, with or without 14 * modification, are permitted provided that the following conditions 15 * are met: 16 * 1. Redistributions of source code must retain the above copyright 17 * notice, this list of conditions and the following disclaimer. 18 * 2. Redistributions in binary form must reproduce the above copyright 19 * notice, this list of conditions and the following disclaimer in the 20 * documentation and/or other materials provided with the distribution. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 * SUCH DAMAGE. 33 */ 34 35#include <sys/cdefs.h> 36__FBSDID("$FreeBSD: head/sys/riscv/htif/htif_console.c 296614 2016-03-10 15:51:43Z br $"); 37 38#include <sys/param.h> 39#include <sys/kdb.h> 40#include <sys/kernel.h> 41#include <sys/priv.h> 42#include <sys/systm.h> 43#include <sys/types.h> 44#include <sys/conf.h> 45#include <sys/cons.h> 46#include <sys/consio.h> 47#include <sys/tty.h> 48#include <sys/bus.h> 49#include <sys/module.h> 50 51#include <machine/bus.h> 52#include <machine/trap.h> 53 54#include "htif.h" 55 56#include <dev/ofw/openfirm.h> 57 58#include <ddb/ddb.h> 59 60extern uint64_t console_intr; 61 62static tsw_outwakeup_t riscvtty_outwakeup; 63 64static struct ttydevsw riscv_ttydevsw = { 65 .tsw_flags = TF_NOPREFIX, 66 .tsw_outwakeup = riscvtty_outwakeup, 67}; 68 69static int polltime; 70static struct callout riscv_callout; 71static struct tty *tp = NULL; 72 73#if defined(KDB) 74static int alt_break_state; 75#endif 76 77static void riscv_timeout(void *); 78 79static cn_probe_t riscv_cnprobe; 80static cn_init_t riscv_cninit; 81static cn_term_t riscv_cnterm; 82static cn_getc_t riscv_cngetc; 83static cn_putc_t riscv_cnputc; 84static cn_grab_t riscv_cngrab; 85static cn_ungrab_t riscv_cnungrab; 86 87CONSOLE_DRIVER(riscv); 88 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