htif_console.c revision 295041
1/*- 2 * Copyright (c) 2015 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 295041 2016-01-29 15:12:31Z 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 93struct queue_entry { 94 uint64_t data; 95 uint64_t used; 96 struct queue_entry *next; 97}; 98 99struct queue_entry cnqueue[QUEUE_SIZE]; 100struct queue_entry *entry_last; 101struct queue_entry *entry_served; 102 103static void 104htif_putc(int c) 105{ 106 uint64_t cmd; 107 108 cmd = (HTIF_CMD_WRITE << HTIF_CMD_SHIFT); 109 cmd |= (CONSOLE_DEFAULT_ID << HTIF_DEV_ID_SHIFT); 110 cmd |= c; 111 112 htif_command(cmd); 113} 114 115static uint8_t 116htif_getc(void) 117{ 118 uint64_t cmd; 119 uint8_t res; 120 121 cmd = (HTIF_CMD_READ << HTIF_CMD_SHIFT); 122 cmd |= (CONSOLE_DEFAULT_ID << HTIF_DEV_ID_SHIFT); 123 124 res = htif_command(cmd); 125 126 return (res); 127} 128 129static void 130riscv_putc(int c) 131{ 132 uint64_t counter; 133 uint64_t *cc; 134 uint64_t val; 135 136 val = 0; 137 counter = 0; 138 139 cc = (uint64_t*)&console_intr; 140 *cc = 0; 141 142 htif_putc(c); 143 144 /* Wait for an interrupt */ 145 __asm __volatile( 146 "li %0, 1\n" /* counter = 1 */ 147 "slli %0, %0, 12\n" /* counter <<= 12 */ 148 "1:" 149 "addi %0, %0, -1\n" /* counter -= 1 */ 150 "beqz %0, 2f\n" /* counter == 0 ? finish */ 151 "ld %1, 0(%2)\n" /* val = *cc */ 152 "beqz %1, 1b\n" /* val == 0 ? repeat */ 153 "2:" 154 : "=&r"(counter), "=&r"(val) : "r"(cc) 155 ); 156} 157 158#ifdef EARLY_PRINTF 159early_putc_t *early_putc = riscv_putc; 160#endif 161 162static void 163cn_drvinit(void *unused) 164{ 165 166 if (riscv_consdev.cn_pri != CN_DEAD && 167 riscv_consdev.cn_name[0] != '\0') { 168 tp = tty_alloc(&riscv_ttydevsw, NULL); 169 tty_init_console(tp, 0); 170 tty_makedev(tp, NULL, "%s", "rcons"); 171 172 polltime = 1; 173 174 callout_init(&riscv_callout, 1); 175 callout_reset(&riscv_callout, polltime, riscv_timeout, NULL); 176 } 177} 178 179SYSINIT(cndev, SI_SUB_CONFIGURE, SI_ORDER_MIDDLE, cn_drvinit, NULL); 180 181static void 182riscvtty_outwakeup(struct tty *tp) 183{ 184 u_char buf[MAX_BURST_LEN]; 185 int len; 186 int i; 187 188 for (;;) { 189 len = ttydisc_getc(tp, buf, sizeof(buf)); 190 if (len == 0) 191 break; 192 193 KASSERT(len == 1, ("tty error")); 194 195 for (i = 0; i < len; i++) 196 riscv_putc(buf[i]); 197 } 198} 199 200static void 201riscv_timeout(void *v) 202{ 203 int c; 204 205 tty_lock(tp); 206 while ((c = riscv_cngetc(NULL)) != -1) 207 ttydisc_rint(tp, c, 0); 208 ttydisc_rint_done(tp); 209 tty_unlock(tp); 210 211 callout_reset(&riscv_callout, polltime, riscv_timeout, NULL); 212} 213 214static void 215riscv_cnprobe(struct consdev *cp) 216{ 217 218 cp->cn_pri = CN_NORMAL; 219} 220 221static void 222riscv_cninit(struct consdev *cp) 223{ 224 int i; 225 226 strcpy(cp->cn_name, "rcons"); 227 228 for (i = 0; i < QUEUE_SIZE; i++) { 229 if (i == (QUEUE_SIZE - 1)) 230 cnqueue[i].next = &cnqueue[0]; 231 else 232 cnqueue[i].next = &cnqueue[i+1]; 233 cnqueue[i].data = 0; 234 cnqueue[i].used = 0; 235 } 236 237 entry_last = &cnqueue[0]; 238 entry_served = &cnqueue[0]; 239} 240 241static void 242riscv_cnterm(struct consdev *cp) 243{ 244 245} 246 247static void 248riscv_cngrab(struct consdev *cp) 249{ 250 251} 252 253static void 254riscv_cnungrab(struct consdev *cp) 255{ 256 257} 258 259static int 260riscv_cngetc(struct consdev *cp) 261{ 262 uint8_t data; 263 int ch; 264 265 ch = htif_getc(); 266 267 if (entry_served->used == 1) { 268 data = entry_served->data; 269 entry_served->used = 0; 270 entry_served = entry_served->next; 271 ch = (data & 0xff); 272 if (ch > 0 && ch < 0xff) { 273#if defined(KDB) 274 kdb_alt_break(ch, &alt_break_state); 275#endif 276 return (ch); 277 } 278 } 279 280 return (-1); 281} 282 283static void 284riscv_cnputc(struct consdev *cp, int c) 285{ 286 287 riscv_putc(c); 288} 289 290/* 291 * Bus interface. 292 */ 293 294struct htif_console_softc { 295 device_t dev; 296 int running; 297 int intr_chan; 298 int cmd_done; 299 int curtag; 300 int index; 301}; 302 303static void 304htif_console_intr(void *arg, uint64_t entry) 305{ 306 struct htif_console_softc *sc; 307 uint8_t devcmd; 308 uint64_t data; 309 310 sc = arg; 311 312 devcmd = HTIF_DEV_CMD(entry); 313 data = HTIF_DEV_DATA(entry); 314 315 if (devcmd == 0) { 316 entry_last->data = data; 317 entry_last->used = 1; 318 entry_last = entry_last->next; 319 } 320} 321 322static int 323htif_console_probe(device_t dev) 324{ 325 326 return (0); 327} 328 329static int 330htif_console_attach(device_t dev) 331{ 332 struct htif_console_softc *sc; 333 334 sc = device_get_softc(dev); 335 sc->dev = dev; 336 337 sc->index = htif_get_index(dev); 338 if (sc->index < 0) 339 return (EINVAL); 340 341 htif_setup_intr(sc->index, htif_console_intr, sc); 342 343 return (0); 344} 345 346static device_method_t htif_console_methods[] = { 347 DEVMETHOD(device_probe, htif_console_probe), 348 DEVMETHOD(device_attach, htif_console_attach), 349 DEVMETHOD_END 350}; 351 352static driver_t htif_console_driver = { 353 "htif_console", 354 htif_console_methods, 355 sizeof(struct htif_console_softc) 356}; 357 358static devclass_t htif_console_devclass; 359 360DRIVER_MODULE(htif_console, htif, htif_console_driver, 361 htif_console_devclass, 0, 0); 362