1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3 * 4 * Copyright (c) 2011-2012, 2016 Robert N. M. Watson 5 * All rights reserved. 6 * 7 * This software was developed by SRI International and the University of 8 * Cambridge Computer Laboratory under DARPA/AFRL contract (FA8750-10-C-0237) 9 * ("CTSRD"), as part of the DARPA CRASH research programme. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * SUCH DAMAGE. 31 */ 32 33 #include <sys/cdefs.h> 34 __FBSDID("$FreeBSD$"); 35 36 #include <sys/param.h> 37 #include <sys/bus.h> 38 #include <sys/cons.h> 39 #include <sys/endian.h> 40 #include <sys/kdb.h> 41 #include <sys/rman.h> 42 #include <sys/systm.h> 43 #include <sys/kernel.h> 44 #include <sys/reboot.h> 45 #include <sys/sysctl.h> 46 #include <sys/tty.h> 47 48 #include <ddb/ddb.h> 49 50 #include <machine/atomic.h> 51 #include <machine/bus.h> 52 53 #include <dev/altera/jtag_uart/altera_jtag_uart.h> 54 55 /* 56 * If one of the Altera JTAG UARTs is currently the system console, register 57 * it here. 58 */ 59 static struct altera_jtag_uart_softc *aju_cons_sc; 60 61 static tsw_outwakeup_t aju_outwakeup; 62 static void aju_ac_callout(void *); 63 static void aju_io_callout(void *); 64 65 static struct ttydevsw aju_ttydevsw = { 66 .tsw_flags = TF_NOPREFIX, 67 .tsw_outwakeup = aju_outwakeup, 68 }; 69 70 /* 71 * When polling for the AC bit, the number of times we have to not see it 72 * before assuming JTAG has disappeared on us. By default, four seconds. 73 */ 74 #define AJU_JTAG_MAXMISS 20 75 76 /* 77 * Polling intervals for input/output and JTAG connection events. 78 */ 79 #define AJU_IO_POLLINTERVAL (hz/100) 80 #define AJU_AC_POLLINTERVAL (hz/5) 81 82 /* 83 * Statistics on JTAG removal events when sending, for debugging purposes 84 * only. 85 */ 86 static u_int aju_jtag_vanished; 87 SYSCTL_UINT(_debug, OID_AUTO, aju_jtag_vanished, CTLFLAG_RW, 88 &aju_jtag_vanished, 0, "Number of times JTAG has vanished"); 89 90 static u_int aju_jtag_appeared; 91 SYSCTL_UINT(_debug, OID_AUTO, aju_jtag_appeared, CTLFLAG_RW, 92 &aju_jtag_appeared, 0, "Number of times JTAG has appeared"); 93 94 SYSCTL_INT(_debug, OID_AUTO, aju_cons_jtag_present, CTLFLAG_RW, 95 &aju_cons_jtag_present, 0, "JTAG console present flag"); 96 97 SYSCTL_UINT(_debug, OID_AUTO, aju_cons_jtag_missed, CTLFLAG_RW, 98 &aju_cons_jtag_missed, 0, "JTAG console missed counter"); 99 100 /* 101 * Interrupt-related statistics. 102 */ 103 static u_int aju_intr_readable_enabled; 104 SYSCTL_UINT(_debug, OID_AUTO, aju_intr_readable_enabled, CTLFLAG_RW, 105 &aju_intr_readable_enabled, 0, "Number of times read interrupt enabled"); 106 107 static u_int aju_intr_writable_disabled; 108 SYSCTL_UINT(_debug, OID_AUTO, aju_intr_writable_disabled, CTLFLAG_RW, 109 &aju_intr_writable_disabled, 0, 110 "Number of times write interrupt disabled"); 111 112 static u_int aju_intr_writable_enabled; 113 SYSCTL_UINT(_debug, OID_AUTO, aju_intr_writable_enabled, CTLFLAG_RW, 114 &aju_intr_writable_enabled, 0, 115 "Number of times write interrupt enabled"); 116 117 static u_int aju_intr_disabled; 118 SYSCTL_UINT(_debug, OID_AUTO, aju_intr_disabled, CTLFLAG_RW, 119 &aju_intr_disabled, 0, "Number of times write interrupt disabled"); 120 121 static u_int aju_intr_read_count; 122 SYSCTL_UINT(_debug, OID_AUTO, aju_intr_read_count, CTLFLAG_RW, 123 &aju_intr_read_count, 0, "Number of times read interrupt fired"); 124 125 static u_int aju_intr_write_count; 126 SYSCTL_UINT(_debug, OID_AUTO, aju_intr_write_count, CTLFLAG_RW, 127 &aju_intr_write_count, 0, "Number of times write interrupt fired"); 128 129 /* 130 * Low-level read and write register routines; the Altera UART is little 131 * endian, so we byte swap 32-bit reads and writes. 132 */ 133 static inline uint32_t 134 aju_data_read(struct altera_jtag_uart_softc *sc) 135 { 136 137 return (le32toh(bus_read_4(sc->ajus_mem_res, 138 ALTERA_JTAG_UART_DATA_OFF))); 139 } 140 141 static inline void 142 aju_data_write(struct altera_jtag_uart_softc *sc, uint32_t v) 143 { 144 145 bus_write_4(sc->ajus_mem_res, ALTERA_JTAG_UART_DATA_OFF, htole32(v)); 146 } 147 148 static inline uint32_t 149 aju_control_read(struct altera_jtag_uart_softc *sc) 150 { 151 152 return (le32toh(bus_read_4(sc->ajus_mem_res, 153 ALTERA_JTAG_UART_CONTROL_OFF))); 154 } 155 156 static inline void 157 aju_control_write(struct altera_jtag_uart_softc *sc, uint32_t v) 158 { 159 160 bus_write_4(sc->ajus_mem_res, ALTERA_JTAG_UART_CONTROL_OFF, 161 htole32(v)); 162 } 163 164 /* 165 * Slightly higher-level routines aware of buffering and flow control. 166 */ 167 static inline int 168 aju_writable(struct altera_jtag_uart_softc *sc) 169 { 170 171 return ((aju_control_read(sc) & 172 ALTERA_JTAG_UART_CONTROL_WSPACE) != 0); 173 } 174 175 static inline int 176 aju_readable(struct altera_jtag_uart_softc *sc) 177 { 178 uint32_t v; 179 180 AJU_LOCK_ASSERT(sc); 181 182 if (*sc->ajus_buffer_validp) 183 return (1); 184 v = aju_data_read(sc); 185 if ((v & ALTERA_JTAG_UART_DATA_RVALID) != 0) { 186 *sc->ajus_buffer_validp = 1; 187 *sc->ajus_buffer_datap = (v & ALTERA_JTAG_UART_DATA_DATA); 188 return (1); 189 } 190 return (0); 191 } 192 193 static char 194 aju_read(struct altera_jtag_uart_softc *sc) 195 { 196 197 AJU_LOCK_ASSERT(sc); 198 199 while (!aju_readable(sc)); 200 *sc->ajus_buffer_validp = 0; 201 return (*sc->ajus_buffer_datap); 202 } 203 204 /* 205 * Routines for enabling and disabling interrupts for read and write. 206 */ 207 static void 208 aju_intr_readable_enable(struct altera_jtag_uart_softc *sc) 209 { 210 uint32_t v; 211 212 AJU_LOCK_ASSERT(sc); 213 214 atomic_add_int(&aju_intr_readable_enabled, 1); 215 v = aju_control_read(sc); 216 v |= ALTERA_JTAG_UART_CONTROL_RE; 217 aju_control_write(sc, v); 218 } 219 220 static void 221 aju_intr_writable_enable(struct altera_jtag_uart_softc *sc) 222 { 223 uint32_t v; 224 225 AJU_LOCK_ASSERT(sc); 226 227 atomic_add_int(&aju_intr_writable_enabled, 1); 228 v = aju_control_read(sc); 229 v |= ALTERA_JTAG_UART_CONTROL_WE; 230 aju_control_write(sc, v); 231 } 232 233 static void 234 aju_intr_writable_disable(struct altera_jtag_uart_softc *sc) 235 { 236 uint32_t v; 237 238 AJU_LOCK_ASSERT(sc); 239 240 atomic_add_int(&aju_intr_writable_disabled, 1); 241 v = aju_control_read(sc); 242 v &= ~ALTERA_JTAG_UART_CONTROL_WE; 243 aju_control_write(sc, v); 244 } 245 246 static void 247 aju_intr_disable(struct altera_jtag_uart_softc *sc) 248 { 249 uint32_t v; 250 251 AJU_LOCK_ASSERT(sc); 252 253 atomic_add_int(&aju_intr_disabled, 1); 254 v = aju_control_read(sc); 255 v &= ~(ALTERA_JTAG_UART_CONTROL_RE | ALTERA_JTAG_UART_CONTROL_WE); 256 aju_control_write(sc, v); 257 } 258 259 /* 260 * The actual work of checking for, and handling, available reads. This is 261 * used in both polled and interrupt-driven modes, as JTAG UARTs may be hooked 262 * up with, or without, IRQs allocated. 263 */ 264 static void 265 aju_handle_input(struct altera_jtag_uart_softc *sc, struct tty *tp) 266 { 267 int c; 268 269 tty_assert_locked(tp); 270 AJU_LOCK_ASSERT(sc); 271 272 while (aju_readable(sc)) { 273 c = aju_read(sc); 274 AJU_UNLOCK(sc); 275 #ifdef KDB 276 if (sc->ajus_flags & ALTERA_JTAG_UART_FLAG_CONSOLE) 277 kdb_alt_break(c, &sc->ajus_alt_break_state); 278 #endif 279 ttydisc_rint(tp, c, 0); 280 AJU_LOCK(sc); 281 } 282 AJU_UNLOCK(sc); 283 ttydisc_rint_done(tp); 284 AJU_LOCK(sc); 285 } 286 287 /* 288 * Send output to the UART until either there's none left to send, or we run 289 * out of room and need to await an interrupt so that we can start sending 290 * again. 291 * 292 * XXXRW: It would be nice to query WSPACE at the beginning and write to the 293 * FIFO in bugger chunks. 294 */ 295 static void 296 aju_handle_output(struct altera_jtag_uart_softc *sc, struct tty *tp) 297 { 298 uint32_t v; 299 uint8_t ch; 300 301 tty_assert_locked(tp); 302 AJU_LOCK_ASSERT(sc); 303 304 AJU_UNLOCK(sc); 305 while (ttydisc_getc_poll(tp) != 0) { 306 AJU_LOCK(sc); 307 if (*sc->ajus_jtag_presentp == 0) { 308 /* 309 * If JTAG is not present, then we will drop this 310 * character instead of perhaps scheduling an 311 * interrupt to let us know when there is buffer 312 * space. Otherwise we might get a write interrupt 313 * later even though we aren't interested in sending 314 * anymore. Loop to drain TTY-layer buffer. 315 */ 316 AJU_UNLOCK(sc); 317 if (ttydisc_getc(tp, &ch, sizeof(ch)) != 318 sizeof(ch)) 319 panic("%s: ttydisc_getc", __func__); 320 continue; 321 } 322 v = aju_control_read(sc); 323 if ((v & ALTERA_JTAG_UART_CONTROL_WSPACE) == 0) { 324 if (sc->ajus_irq_res != NULL && 325 (v & ALTERA_JTAG_UART_CONTROL_WE) == 0) 326 aju_intr_writable_enable(sc); 327 return; 328 } 329 AJU_UNLOCK(sc); 330 if (ttydisc_getc(tp, &ch, sizeof(ch)) != sizeof(ch)) 331 panic("%s: ttydisc_getc 2", __func__); 332 AJU_LOCK(sc); 333 334 /* 335 * XXXRW: There is a slight race here in which we test for 336 * writability, drop the lock, get the character from the tty 337 * layer, re-acquire the lock, and then write. It's possible 338 * for other code -- specifically, the low-level console -- to 339 * have* written in the mean time, which might mean that there 340 * is no longer space. The BERI memory bus will cause this 341 * write to block, wedging the processor until space is 342 * available -- which could be a while if JTAG is not 343 * attached! 344 * 345 * The 'easy' fix is to drop the character if WSPACE has 346 * become unset. Not sure what the 'hard' fix is. 347 */ 348 aju_data_write(sc, ch); 349 AJU_UNLOCK(sc); 350 } 351 AJU_LOCK(sc); 352 353 /* 354 * If interrupts are configured, and there's no data to write, but we 355 * had previously enabled write interrupts, disable them now. 356 */ 357 v = aju_control_read(sc); 358 if (sc->ajus_irq_res != NULL && (v & ALTERA_JTAG_UART_CONTROL_WE) != 0) 359 aju_intr_writable_disable(sc); 360 } 361 362 static void 363 aju_outwakeup(struct tty *tp) 364 { 365 struct altera_jtag_uart_softc *sc = tty_softc(tp); 366 367 tty_assert_locked(tp); 368 369 AJU_LOCK(sc); 370 aju_handle_output(sc, tp); 371 AJU_UNLOCK(sc); 372 } 373 374 static void 375 aju_io_callout(void *arg) 376 { 377 struct altera_jtag_uart_softc *sc = arg; 378 struct tty *tp = sc->ajus_ttyp; 379 380 tty_lock(tp); 381 AJU_LOCK(sc); 382 383 /* 384 * It would be convenient if we could share code with aju_intr() here 385 * by testing the control register for ALTERA_JTAG_UART_CONTROL_RI and 386 * ALTERA_JTAG_UART_CONTROL_WI. Unfortunately, it's not clear that 387 * this is supported, so do all the work to poll for both input and 388 * output. 389 */ 390 aju_handle_input(sc, tp); 391 aju_handle_output(sc, tp); 392 393 /* 394 * Reschedule next poll attempt. There's some argument that we should 395 * do adaptive polling based on the expectation of I/O: is something 396 * pending in the output buffer, or have we recently had input, but we 397 * don't. 398 */ 399 callout_reset(&sc->ajus_io_callout, AJU_IO_POLLINTERVAL, 400 aju_io_callout, sc); 401 AJU_UNLOCK(sc); 402 tty_unlock(tp); 403 } 404 405 static void 406 aju_ac_callout(void *arg) 407 { 408 struct altera_jtag_uart_softc *sc = arg; 409 struct tty *tp = sc->ajus_ttyp; 410 uint32_t v; 411 412 tty_lock(tp); 413 AJU_LOCK(sc); 414 v = aju_control_read(sc); 415 if (v & ALTERA_JTAG_UART_CONTROL_AC) { 416 v &= ~ALTERA_JTAG_UART_CONTROL_AC; 417 aju_control_write(sc, v); 418 if (*sc->ajus_jtag_presentp == 0) { 419 *sc->ajus_jtag_presentp = 1; 420 atomic_add_int(&aju_jtag_appeared, 1); 421 aju_handle_output(sc, tp); 422 } 423 424 /* Any hit eliminates all recent misses. */ 425 *sc->ajus_jtag_missedp = 0; 426 } else if (*sc->ajus_jtag_presentp != 0) { 427 /* 428 * If we've exceeded our tolerance for misses, mark JTAG as 429 * disconnected and drain output. Otherwise, bump the miss 430 * counter. 431 */ 432 if (*sc->ajus_jtag_missedp > AJU_JTAG_MAXMISS) { 433 *sc->ajus_jtag_presentp = 0; 434 atomic_add_int(&aju_jtag_vanished, 1); 435 aju_handle_output(sc, tp); 436 } else 437 (*sc->ajus_jtag_missedp)++; 438 } 439 callout_reset(&sc->ajus_ac_callout, AJU_AC_POLLINTERVAL, 440 aju_ac_callout, sc); 441 AJU_UNLOCK(sc); 442 tty_unlock(tp); 443 } 444 445 static void 446 aju_intr(void *arg) 447 { 448 struct altera_jtag_uart_softc *sc = arg; 449 struct tty *tp = sc->ajus_ttyp; 450 uint32_t v; 451 452 tty_lock(tp); 453 AJU_LOCK(sc); 454 v = aju_control_read(sc); 455 if (v & ALTERA_JTAG_UART_CONTROL_RI) { 456 atomic_add_int(&aju_intr_read_count, 1); 457 aju_handle_input(sc, tp); 458 } 459 if (v & ALTERA_JTAG_UART_CONTROL_WI) { 460 atomic_add_int(&aju_intr_write_count, 1); 461 aju_handle_output(sc, tp); 462 } 463 AJU_UNLOCK(sc); 464 tty_unlock(tp); 465 } 466 467 int 468 altera_jtag_uart_attach(struct altera_jtag_uart_softc *sc) 469 { 470 struct tty *tp; 471 int error; 472 473 AJU_LOCK_INIT(sc); 474 475 /* 476 * XXXRW: Currently, we detect the console solely based on it using a 477 * reserved address, and borrow console-level locks and buffer if so. 478 * Is there a better way? 479 */ 480 if (rman_get_start(sc->ajus_mem_res) == BERI_UART_BASE) { 481 sc->ajus_lockp = &aju_cons_lock; 482 sc->ajus_buffer_validp = &aju_cons_buffer_valid; 483 sc->ajus_buffer_datap = &aju_cons_buffer_data; 484 sc->ajus_jtag_presentp = &aju_cons_jtag_present; 485 sc->ajus_jtag_missedp = &aju_cons_jtag_missed; 486 sc->ajus_flags |= ALTERA_JTAG_UART_FLAG_CONSOLE; 487 } else { 488 sc->ajus_lockp = &sc->ajus_lock; 489 sc->ajus_buffer_validp = &sc->ajus_buffer_valid; 490 sc->ajus_buffer_datap = &sc->ajus_buffer_data; 491 sc->ajus_jtag_presentp = &sc->ajus_jtag_present; 492 sc->ajus_jtag_missedp = &sc->ajus_jtag_missed; 493 } 494 495 /* 496 * Disable interrupts regardless of whether or not we plan to use 497 * them. We will register an interrupt handler now if they will be 498 * used, but not re-enable intil later once the remainder of the tty 499 * layer is properly initialised, as we're not ready for input yet. 500 */ 501 AJU_LOCK(sc); 502 aju_intr_disable(sc); 503 AJU_UNLOCK(sc); 504 if (sc->ajus_irq_res != NULL) { 505 error = bus_setup_intr(sc->ajus_dev, sc->ajus_irq_res, 506 INTR_ENTROPY | INTR_TYPE_TTY | INTR_MPSAFE, NULL, 507 aju_intr, sc, &sc->ajus_irq_cookie); 508 if (error) { 509 device_printf(sc->ajus_dev, 510 "could not activate interrupt\n"); 511 AJU_LOCK_DESTROY(sc); 512 return (error); 513 } 514 } 515 tp = sc->ajus_ttyp = tty_alloc(&aju_ttydevsw, sc); 516 if (sc->ajus_flags & ALTERA_JTAG_UART_FLAG_CONSOLE) { 517 aju_cons_sc = sc; 518 tty_init_console(tp, 0); 519 } 520 tty_makedev(tp, NULL, "%s%d", AJU_TTYNAME, sc->ajus_unit); 521 522 /* 523 * If we will be using interrupts, enable them now; otherwise, start 524 * polling. From this point onwards, input can arrive. 525 */ 526 if (sc->ajus_irq_res != NULL) { 527 AJU_LOCK(sc); 528 aju_intr_readable_enable(sc); 529 AJU_UNLOCK(sc); 530 } else { 531 callout_init(&sc->ajus_io_callout, 1); 532 callout_reset(&sc->ajus_io_callout, AJU_IO_POLLINTERVAL, 533 aju_io_callout, sc); 534 } 535 callout_init(&sc->ajus_ac_callout, 1); 536 callout_reset(&sc->ajus_ac_callout, AJU_AC_POLLINTERVAL, 537 aju_ac_callout, sc); 538 return (0); 539 } 540 541 void 542 altera_jtag_uart_detach(struct altera_jtag_uart_softc *sc) 543 { 544 struct tty *tp = sc->ajus_ttyp; 545 546 /* 547 * If we're using interrupts, disable and release the interrupt 548 * handler now. Otherwise drain the polling timeout. 549 */ 550 if (sc->ajus_irq_res != NULL) { 551 AJU_LOCK(sc); 552 aju_intr_disable(sc); 553 AJU_UNLOCK(sc); 554 bus_teardown_intr(sc->ajus_dev, sc->ajus_irq_res, 555 sc->ajus_irq_cookie); 556 } else 557 callout_drain(&sc->ajus_io_callout); 558 callout_drain(&sc->ajus_ac_callout); 559 if (sc->ajus_flags & ALTERA_JTAG_UART_FLAG_CONSOLE) 560 aju_cons_sc = NULL; 561 tty_lock(tp); 562 tty_rel_gone(tp); 563 AJU_LOCK_DESTROY(sc); 564 } 565