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