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