1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 3 * 4 * Copyright (c) 2012 NetApp, Inc. 5 * Copyright (c) 2013 Neel Natu <neel@freebsd.org> 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND 18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 * ARE DISCLAIMED. IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE 21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 */ 29 30 #include <sys/types.h> 31 #include <dev/ic/ns16550.h> 32 33 #include <machine/vmm_snapshot.h> 34 35 #include <assert.h> 36 #include <stdio.h> 37 #include <stdlib.h> 38 #include <errno.h> 39 #include <unistd.h> 40 #include <stdbool.h> 41 #include <string.h> 42 #include <pthread.h> 43 44 #include "uart_backend.h" 45 #include "uart_emul.h" 46 47 #define COM1_BASE 0x3F8 48 #define COM1_IRQ 4 49 #define COM2_BASE 0x2F8 50 #define COM2_IRQ 3 51 #define COM3_BASE 0x3E8 52 #define COM3_IRQ 4 53 #define COM4_BASE 0x2E8 54 #define COM4_IRQ 3 55 56 #define DEFAULT_RCLK 1843200 57 #define DEFAULT_BAUD 115200 58 59 #define FCR_RX_MASK 0xC0 60 61 #define MCR_OUT1 0x04 62 #define MCR_OUT2 0x08 63 64 #define MSR_DELTA_MASK 0x0f 65 66 #ifndef REG_SCR 67 #define REG_SCR com_scr 68 #endif 69 70 static struct { 71 int baseaddr; 72 int irq; 73 bool inuse; 74 } uart_lres[] = { 75 { COM1_BASE, COM1_IRQ, false}, 76 { COM2_BASE, COM2_IRQ, false}, 77 { COM3_BASE, COM3_IRQ, false}, 78 { COM4_BASE, COM4_IRQ, false}, 79 }; 80 81 #define UART_NLDEVS (sizeof(uart_lres) / sizeof(uart_lres[0])) 82 83 struct uart_ns16550_softc { 84 struct uart_softc *backend; 85 86 pthread_mutex_t mtx; /* protects all softc elements */ 87 uint8_t data; /* Data register (R/W) */ 88 uint8_t ier; /* Interrupt enable register (R/W) */ 89 uint8_t lcr; /* Line control register (R/W) */ 90 uint8_t mcr; /* Modem control register (R/W) */ 91 uint8_t lsr; /* Line status register (R/W) */ 92 uint8_t msr; /* Modem status register (R/W) */ 93 uint8_t fcr; /* FIFO control register (W) */ 94 uint8_t scr; /* Scratch register (R/W) */ 95 96 uint8_t dll; /* Baudrate divisor latch LSB */ 97 uint8_t dlh; /* Baudrate divisor latch MSB */ 98 99 bool thre_int_pending; /* THRE interrupt pending */ 100 101 void *arg; 102 uart_intr_func_t intr_assert; 103 uart_intr_func_t intr_deassert; 104 }; 105 106 static uint8_t 107 modem_status(uint8_t mcr) 108 { 109 uint8_t msr; 110 111 if (mcr & MCR_LOOPBACK) { 112 /* 113 * In the loopback mode certain bits from the MCR are 114 * reflected back into MSR. 115 */ 116 msr = 0; 117 if (mcr & MCR_RTS) 118 msr |= MSR_CTS; 119 if (mcr & MCR_DTR) 120 msr |= MSR_DSR; 121 if (mcr & MCR_OUT1) 122 msr |= MSR_RI; 123 if (mcr & MCR_OUT2) 124 msr |= MSR_DCD; 125 } else { 126 /* 127 * Always assert DCD and DSR so tty open doesn't block 128 * even if CLOCAL is turned off. 129 */ 130 msr = MSR_DCD | MSR_DSR; 131 } 132 assert((msr & MSR_DELTA_MASK) == 0); 133 134 return (msr); 135 } 136 137 /* 138 * The IIR returns a prioritized interrupt reason: 139 * - receive data available 140 * - transmit holding register empty 141 * - modem status change 142 * 143 * Return an interrupt reason if one is available. 144 */ 145 static int 146 uart_intr_reason(struct uart_ns16550_softc *sc) 147 { 148 149 if ((sc->lsr & LSR_OE) != 0 && (sc->ier & IER_ERLS) != 0) 150 return (IIR_RLS); 151 else if (uart_rxfifo_numchars(sc->backend) > 0 && 152 (sc->ier & IER_ERXRDY) != 0) 153 return (IIR_RXTOUT); 154 else if (sc->thre_int_pending && (sc->ier & IER_ETXRDY) != 0) 155 return (IIR_TXRDY); 156 else if ((sc->msr & MSR_DELTA_MASK) != 0 && (sc->ier & IER_EMSC) != 0) 157 return (IIR_MLSC); 158 else 159 return (IIR_NOPEND); 160 } 161 162 static void 163 uart_reset(struct uart_ns16550_softc *sc) 164 { 165 uint16_t divisor; 166 167 divisor = DEFAULT_RCLK / DEFAULT_BAUD / 16; 168 sc->dll = divisor; 169 sc->dlh = divisor >> 16; 170 sc->msr = modem_status(sc->mcr); 171 172 uart_rxfifo_reset(sc->backend, 1); 173 } 174 175 /* 176 * Toggle the COM port's intr pin depending on whether or not we have an 177 * interrupt condition to report to the processor. 178 */ 179 static void 180 uart_toggle_intr(struct uart_ns16550_softc *sc) 181 { 182 uint8_t intr_reason; 183 184 intr_reason = uart_intr_reason(sc); 185 186 if (intr_reason == IIR_NOPEND) 187 (*sc->intr_deassert)(sc->arg); 188 else 189 (*sc->intr_assert)(sc->arg); 190 } 191 192 static void 193 uart_drain(int fd __unused, enum ev_type ev, void *arg) 194 { 195 struct uart_ns16550_softc *sc; 196 bool loopback; 197 198 sc = arg; 199 200 assert(ev == EVF_READ); 201 202 /* 203 * This routine is called in the context of the mevent thread 204 * to take out the softc lock to protect against concurrent 205 * access from a vCPU i/o exit 206 */ 207 pthread_mutex_lock(&sc->mtx); 208 209 loopback = (sc->mcr & MCR_LOOPBACK) != 0; 210 uart_rxfifo_drain(sc->backend, loopback); 211 if (!loopback) 212 uart_toggle_intr(sc); 213 214 pthread_mutex_unlock(&sc->mtx); 215 } 216 217 void 218 uart_ns16550_write(struct uart_ns16550_softc *sc, int offset, uint8_t value) 219 { 220 int fifosz; 221 uint8_t msr; 222 223 pthread_mutex_lock(&sc->mtx); 224 225 /* 226 * Take care of the special case DLAB accesses first 227 */ 228 if ((sc->lcr & LCR_DLAB) != 0) { 229 if (offset == REG_DLL) { 230 sc->dll = value; 231 goto done; 232 } 233 234 if (offset == REG_DLH) { 235 sc->dlh = value; 236 goto done; 237 } 238 } 239 240 switch (offset) { 241 case REG_DATA: 242 if (uart_rxfifo_putchar(sc->backend, value, 243 (sc->mcr & MCR_LOOPBACK) != 0)) 244 sc->lsr |= LSR_OE; 245 sc->thre_int_pending = true; 246 break; 247 case REG_IER: 248 /* Set pending when IER_ETXRDY is raised (edge-triggered). */ 249 if ((sc->ier & IER_ETXRDY) == 0 && (value & IER_ETXRDY) != 0) 250 sc->thre_int_pending = true; 251 /* 252 * Apply mask so that bits 4-7 are 0 253 * Also enables bits 0-3 only if they're 1 254 */ 255 sc->ier = value & 0x0F; 256 break; 257 case REG_FCR: 258 /* 259 * When moving from FIFO and 16450 mode and vice versa, 260 * the FIFO contents are reset. 261 */ 262 if ((sc->fcr & FCR_ENABLE) ^ (value & FCR_ENABLE)) { 263 fifosz = (value & FCR_ENABLE) ? 264 uart_rxfifo_size(sc->backend) : 1; 265 uart_rxfifo_reset(sc->backend, fifosz); 266 } 267 268 /* 269 * The FCR_ENABLE bit must be '1' for the programming 270 * of other FCR bits to be effective. 271 */ 272 if ((value & FCR_ENABLE) == 0) { 273 sc->fcr = 0; 274 } else { 275 if ((value & FCR_RCV_RST) != 0) 276 uart_rxfifo_reset(sc->backend, 277 uart_rxfifo_size(sc->backend)); 278 279 sc->fcr = value & 280 (FCR_ENABLE | FCR_DMA | FCR_RX_MASK); 281 } 282 break; 283 case REG_LCR: 284 sc->lcr = value; 285 break; 286 case REG_MCR: 287 /* Apply mask so that bits 5-7 are 0 */ 288 sc->mcr = value & 0x1F; 289 msr = modem_status(sc->mcr); 290 291 /* 292 * Detect if there has been any change between the 293 * previous and the new value of MSR. If there is 294 * then assert the appropriate MSR delta bit. 295 */ 296 if ((msr & MSR_CTS) ^ (sc->msr & MSR_CTS)) 297 sc->msr |= MSR_DCTS; 298 if ((msr & MSR_DSR) ^ (sc->msr & MSR_DSR)) 299 sc->msr |= MSR_DDSR; 300 if ((msr & MSR_DCD) ^ (sc->msr & MSR_DCD)) 301 sc->msr |= MSR_DDCD; 302 if ((sc->msr & MSR_RI) != 0 && (msr & MSR_RI) == 0) 303 sc->msr |= MSR_TERI; 304 305 /* 306 * Update the value of MSR while retaining the delta 307 * bits. 308 */ 309 sc->msr &= MSR_DELTA_MASK; 310 sc->msr |= msr; 311 break; 312 case REG_LSR: 313 /* 314 * Line status register is not meant to be written to 315 * during normal operation. 316 */ 317 break; 318 case REG_MSR: 319 /* 320 * As far as I can tell MSR is a read-only register. 321 */ 322 break; 323 case REG_SCR: 324 sc->scr = value; 325 break; 326 default: 327 break; 328 } 329 330 done: 331 uart_toggle_intr(sc); 332 pthread_mutex_unlock(&sc->mtx); 333 } 334 335 uint8_t 336 uart_ns16550_read(struct uart_ns16550_softc *sc, int offset) 337 { 338 uint8_t iir, intr_reason, reg; 339 340 pthread_mutex_lock(&sc->mtx); 341 342 /* 343 * Take care of the special case DLAB accesses first 344 */ 345 if ((sc->lcr & LCR_DLAB) != 0) { 346 if (offset == REG_DLL) { 347 reg = sc->dll; 348 goto done; 349 } 350 351 if (offset == REG_DLH) { 352 reg = sc->dlh; 353 goto done; 354 } 355 } 356 357 switch (offset) { 358 case REG_DATA: 359 reg = uart_rxfifo_getchar(sc->backend); 360 break; 361 case REG_IER: 362 reg = sc->ier; 363 break; 364 case REG_IIR: 365 iir = (sc->fcr & FCR_ENABLE) ? IIR_FIFO_MASK : 0; 366 367 intr_reason = uart_intr_reason(sc); 368 369 /* 370 * Deal with side effects of reading the IIR register 371 */ 372 if (intr_reason == IIR_TXRDY) 373 sc->thre_int_pending = false; 374 375 iir |= intr_reason; 376 377 reg = iir; 378 break; 379 case REG_LCR: 380 reg = sc->lcr; 381 break; 382 case REG_MCR: 383 reg = sc->mcr; 384 break; 385 case REG_LSR: 386 /* Transmitter is always ready for more data */ 387 sc->lsr |= LSR_TEMT | LSR_THRE; 388 389 /* Check for new receive data */ 390 if (uart_rxfifo_numchars(sc->backend) > 0) 391 sc->lsr |= LSR_RXRDY; 392 else 393 sc->lsr &= ~LSR_RXRDY; 394 395 reg = sc->lsr; 396 397 /* The LSR_OE bit is cleared on LSR read */ 398 sc->lsr &= ~LSR_OE; 399 break; 400 case REG_MSR: 401 /* 402 * MSR delta bits are cleared on read 403 */ 404 reg = sc->msr; 405 sc->msr &= ~MSR_DELTA_MASK; 406 break; 407 case REG_SCR: 408 reg = sc->scr; 409 break; 410 default: 411 reg = 0xFF; 412 break; 413 } 414 415 done: 416 uart_toggle_intr(sc); 417 pthread_mutex_unlock(&sc->mtx); 418 419 return (reg); 420 } 421 422 int 423 uart_legacy_alloc(int which, int *baseaddr, int *irq) 424 { 425 426 if (which < 0 || which >= (int)UART_NLDEVS || uart_lres[which].inuse) 427 return (-1); 428 429 uart_lres[which].inuse = true; 430 *baseaddr = uart_lres[which].baseaddr; 431 *irq = uart_lres[which].irq; 432 433 return (0); 434 } 435 436 struct uart_ns16550_softc * 437 uart_ns16550_init(uart_intr_func_t intr_assert, uart_intr_func_t intr_deassert, 438 void *arg) 439 { 440 struct uart_ns16550_softc *sc; 441 442 sc = calloc(1, sizeof(struct uart_ns16550_softc)); 443 444 sc->arg = arg; 445 sc->intr_assert = intr_assert; 446 sc->intr_deassert = intr_deassert; 447 sc->backend = uart_init(); 448 449 pthread_mutex_init(&sc->mtx, NULL); 450 451 uart_reset(sc); 452 453 return (sc); 454 } 455 456 int 457 uart_ns16550_tty_open(struct uart_ns16550_softc *sc, const char *device) 458 { 459 return (uart_tty_open(sc->backend, device, uart_drain, sc)); 460 } 461 462 #ifdef BHYVE_SNAPSHOT 463 int 464 uart_ns16550_snapshot(struct uart_ns16550_softc *sc, 465 struct vm_snapshot_meta *meta) 466 { 467 int ret; 468 469 SNAPSHOT_VAR_OR_LEAVE(sc->data, meta, ret, done); 470 SNAPSHOT_VAR_OR_LEAVE(sc->ier, meta, ret, done); 471 SNAPSHOT_VAR_OR_LEAVE(sc->lcr, meta, ret, done); 472 SNAPSHOT_VAR_OR_LEAVE(sc->mcr, meta, ret, done); 473 SNAPSHOT_VAR_OR_LEAVE(sc->lsr, meta, ret, done); 474 SNAPSHOT_VAR_OR_LEAVE(sc->msr, meta, ret, done); 475 SNAPSHOT_VAR_OR_LEAVE(sc->fcr, meta, ret, done); 476 SNAPSHOT_VAR_OR_LEAVE(sc->scr, meta, ret, done); 477 478 SNAPSHOT_VAR_OR_LEAVE(sc->dll, meta, ret, done); 479 SNAPSHOT_VAR_OR_LEAVE(sc->dlh, meta, ret, done); 480 481 ret = uart_rxfifo_snapshot(sc->backend, meta); 482 483 sc->thre_int_pending = 1; 484 485 done: 486 return (ret); 487 } 488 #endif 489