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