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 uint8_t data; /* Data register (R/W) */
87 uint8_t ier; /* Interrupt enable register (R/W) */
88 uint8_t lcr; /* Line control register (R/W) */
89 uint8_t mcr; /* Modem control register (R/W) */
90 uint8_t lsr; /* Line status register (R/W) */
91 uint8_t msr; /* Modem status register (R/W) */
92 uint8_t fcr; /* FIFO control register (W) */
93 uint8_t scr; /* Scratch register (R/W) */
94
95 uint8_t dll; /* Baudrate divisor latch LSB */
96 uint8_t dlh; /* Baudrate divisor latch MSB */
97
98 bool thre_int_pending; /* THRE interrupt pending */
99
100 void *arg;
101 uart_intr_func_t intr_assert;
102 uart_intr_func_t intr_deassert;
103 };
104
105 static uint8_t
modem_status(uint8_t mcr)106 modem_status(uint8_t mcr)
107 {
108 uint8_t msr;
109
110 if (mcr & MCR_LOOPBACK) {
111 /*
112 * In the loopback mode certain bits from the MCR are
113 * reflected back into MSR.
114 */
115 msr = 0;
116 if (mcr & MCR_RTS)
117 msr |= MSR_CTS;
118 if (mcr & MCR_DTR)
119 msr |= MSR_DSR;
120 if (mcr & MCR_OUT1)
121 msr |= MSR_RI;
122 if (mcr & MCR_OUT2)
123 msr |= MSR_DCD;
124 } else {
125 /*
126 * Always assert DCD and DSR so tty open doesn't block
127 * even if CLOCAL is turned off.
128 */
129 msr = MSR_DCD | MSR_DSR;
130 }
131 assert((msr & MSR_DELTA_MASK) == 0);
132
133 return (msr);
134 }
135
136 /*
137 * The IIR returns a prioritized interrupt reason:
138 * - receive data available
139 * - transmit holding register empty
140 * - modem status change
141 *
142 * Return an interrupt reason if one is available.
143 */
144 static int
uart_intr_reason(struct uart_ns16550_softc * sc)145 uart_intr_reason(struct uart_ns16550_softc *sc)
146 {
147
148 if ((sc->lsr & LSR_OE) != 0 && (sc->ier & IER_ERLS) != 0)
149 return (IIR_RLS);
150 else if (uart_rxfifo_numchars(sc->backend) > 0 &&
151 (sc->ier & IER_ERXRDY) != 0)
152 return (IIR_RXTOUT);
153 else if (sc->thre_int_pending && (sc->ier & IER_ETXRDY) != 0)
154 return (IIR_TXRDY);
155 else if ((sc->msr & MSR_DELTA_MASK) != 0 && (sc->ier & IER_EMSC) != 0)
156 return (IIR_MLSC);
157 else
158 return (IIR_NOPEND);
159 }
160
161 static void
uart_reset(struct uart_ns16550_softc * sc)162 uart_reset(struct uart_ns16550_softc *sc)
163 {
164 uint16_t divisor;
165
166 divisor = DEFAULT_RCLK / DEFAULT_BAUD / 16;
167 sc->dll = divisor;
168 sc->dlh = divisor >> 16;
169 sc->msr = modem_status(sc->mcr);
170
171 uart_rxfifo_reset(sc->backend, 1);
172 }
173
174 /*
175 * Toggle the COM port's intr pin depending on whether or not we have an
176 * interrupt condition to report to the processor.
177 */
178 static void
uart_toggle_intr(struct uart_ns16550_softc * sc)179 uart_toggle_intr(struct uart_ns16550_softc *sc)
180 {
181 uint8_t intr_reason;
182
183 intr_reason = uart_intr_reason(sc);
184
185 if (intr_reason == IIR_NOPEND)
186 (*sc->intr_deassert)(sc->arg);
187 else
188 (*sc->intr_assert)(sc->arg);
189 }
190
191 static void
uart_drain(int fd __unused,enum ev_type ev,void * arg)192 uart_drain(int fd __unused, enum ev_type ev, void *arg)
193 {
194 struct uart_ns16550_softc *sc;
195 bool loopback;
196
197 sc = arg;
198
199 assert(ev == EVF_READ);
200
201 /*
202 * This routine is called in the context of the mevent thread
203 * to take out the softc lock to protect against concurrent
204 * access from a vCPU i/o exit
205 */
206 uart_softc_lock(sc->backend);
207
208 loopback = (sc->mcr & MCR_LOOPBACK) != 0;
209 uart_rxfifo_drain(sc->backend, loopback);
210 if (!loopback)
211 uart_toggle_intr(sc);
212
213 uart_softc_unlock(sc->backend);
214 }
215
216 void
uart_ns16550_write(struct uart_ns16550_softc * sc,int offset,uint8_t value)217 uart_ns16550_write(struct uart_ns16550_softc *sc, int offset, uint8_t value)
218 {
219 int fifosz;
220 uint8_t msr;
221
222 uart_softc_lock(sc->backend);
223
224 /*
225 * Take care of the special case DLAB accesses first
226 */
227 if ((sc->lcr & LCR_DLAB) != 0) {
228 if (offset == REG_DLL) {
229 sc->dll = value;
230 goto done;
231 }
232
233 if (offset == REG_DLH) {
234 sc->dlh = value;
235 goto done;
236 }
237 }
238
239 switch (offset) {
240 case REG_DATA:
241 if (uart_rxfifo_putchar(sc->backend, value,
242 (sc->mcr & MCR_LOOPBACK) != 0))
243 sc->lsr |= LSR_OE;
244 sc->thre_int_pending = true;
245 break;
246 case REG_IER:
247 /* Set pending when IER_ETXRDY is raised (edge-triggered). */
248 if ((sc->ier & IER_ETXRDY) == 0 && (value & IER_ETXRDY) != 0)
249 sc->thre_int_pending = true;
250 /*
251 * Apply mask so that bits 4-7 are 0
252 * Also enables bits 0-3 only if they're 1
253 */
254 sc->ier = value & 0x0F;
255 break;
256 case REG_FCR:
257 /*
258 * When moving from FIFO and 16450 mode and vice versa,
259 * the FIFO contents are reset.
260 */
261 if ((sc->fcr & FCR_ENABLE) ^ (value & FCR_ENABLE)) {
262 fifosz = (value & FCR_ENABLE) ?
263 uart_rxfifo_size(sc->backend) : 1;
264 uart_rxfifo_reset(sc->backend, fifosz);
265 }
266
267 /*
268 * The FCR_ENABLE bit must be '1' for the programming
269 * of other FCR bits to be effective.
270 */
271 if ((value & FCR_ENABLE) == 0) {
272 sc->fcr = 0;
273 } else {
274 if ((value & FCR_RCV_RST) != 0)
275 uart_rxfifo_reset(sc->backend,
276 uart_rxfifo_size(sc->backend));
277
278 sc->fcr = value &
279 (FCR_ENABLE | FCR_DMA | FCR_RX_MASK);
280 }
281 break;
282 case REG_LCR:
283 sc->lcr = value;
284 break;
285 case REG_MCR:
286 /* Apply mask so that bits 5-7 are 0 */
287 sc->mcr = value & 0x1F;
288 msr = modem_status(sc->mcr);
289
290 /*
291 * Detect if there has been any change between the
292 * previous and the new value of MSR. If there is
293 * then assert the appropriate MSR delta bit.
294 */
295 if ((msr & MSR_CTS) ^ (sc->msr & MSR_CTS))
296 sc->msr |= MSR_DCTS;
297 if ((msr & MSR_DSR) ^ (sc->msr & MSR_DSR))
298 sc->msr |= MSR_DDSR;
299 if ((msr & MSR_DCD) ^ (sc->msr & MSR_DCD))
300 sc->msr |= MSR_DDCD;
301 if ((sc->msr & MSR_RI) != 0 && (msr & MSR_RI) == 0)
302 sc->msr |= MSR_TERI;
303
304 /*
305 * Update the value of MSR while retaining the delta
306 * bits.
307 */
308 sc->msr &= MSR_DELTA_MASK;
309 sc->msr |= msr;
310 break;
311 case REG_LSR:
312 /*
313 * Line status register is not meant to be written to
314 * during normal operation.
315 */
316 break;
317 case REG_MSR:
318 /*
319 * As far as I can tell MSR is a read-only register.
320 */
321 break;
322 case REG_SCR:
323 sc->scr = value;
324 break;
325 default:
326 break;
327 }
328
329 done:
330 uart_toggle_intr(sc);
331 uart_softc_unlock(sc->backend);
332 }
333
334 uint8_t
uart_ns16550_read(struct uart_ns16550_softc * sc,int offset)335 uart_ns16550_read(struct uart_ns16550_softc *sc, int offset)
336 {
337 uint8_t iir, intr_reason, reg;
338
339 uart_softc_lock(sc->backend);
340
341 /*
342 * Take care of the special case DLAB accesses first
343 */
344 if ((sc->lcr & LCR_DLAB) != 0) {
345 if (offset == REG_DLL) {
346 reg = sc->dll;
347 goto done;
348 }
349
350 if (offset == REG_DLH) {
351 reg = sc->dlh;
352 goto done;
353 }
354 }
355
356 switch (offset) {
357 case REG_DATA:
358 reg = uart_rxfifo_getchar(sc->backend);
359 break;
360 case REG_IER:
361 reg = sc->ier;
362 break;
363 case REG_IIR:
364 iir = (sc->fcr & FCR_ENABLE) ? IIR_FIFO_MASK : 0;
365
366 intr_reason = uart_intr_reason(sc);
367
368 /*
369 * Deal with side effects of reading the IIR register
370 */
371 if (intr_reason == IIR_TXRDY)
372 sc->thre_int_pending = false;
373
374 iir |= intr_reason;
375
376 reg = iir;
377 break;
378 case REG_LCR:
379 reg = sc->lcr;
380 break;
381 case REG_MCR:
382 reg = sc->mcr;
383 break;
384 case REG_LSR:
385 /* Transmitter is always ready for more data */
386 sc->lsr |= LSR_TEMT | LSR_THRE;
387
388 /* Check for new receive data */
389 if (uart_rxfifo_numchars(sc->backend) > 0)
390 sc->lsr |= LSR_RXRDY;
391 else
392 sc->lsr &= ~LSR_RXRDY;
393
394 reg = sc->lsr;
395
396 /* The LSR_OE bit is cleared on LSR read */
397 sc->lsr &= ~LSR_OE;
398 break;
399 case REG_MSR:
400 /*
401 * MSR delta bits are cleared on read
402 */
403 reg = sc->msr;
404 sc->msr &= ~MSR_DELTA_MASK;
405 break;
406 case REG_SCR:
407 reg = sc->scr;
408 break;
409 default:
410 reg = 0xFF;
411 break;
412 }
413
414 done:
415 uart_toggle_intr(sc);
416 uart_softc_unlock(sc->backend);
417
418 return (reg);
419 }
420
421 int
uart_legacy_alloc(int which,int * baseaddr,int * irq)422 uart_legacy_alloc(int which, int *baseaddr, int *irq)
423 {
424
425 if (which < 0 || which >= (int)UART_NLDEVS || uart_lres[which].inuse)
426 return (-1);
427
428 uart_lres[which].inuse = true;
429 *baseaddr = uart_lres[which].baseaddr;
430 *irq = uart_lres[which].irq;
431
432 return (0);
433 }
434
435 struct uart_ns16550_softc *
uart_ns16550_init(uart_intr_func_t intr_assert,uart_intr_func_t intr_deassert,void * arg)436 uart_ns16550_init(uart_intr_func_t intr_assert, uart_intr_func_t intr_deassert,
437 void *arg)
438 {
439 struct uart_ns16550_softc *sc;
440
441 sc = calloc(1, sizeof(struct uart_ns16550_softc));
442
443 sc->arg = arg;
444 sc->intr_assert = intr_assert;
445 sc->intr_deassert = intr_deassert;
446 sc->backend = uart_init();
447
448 uart_reset(sc);
449
450 return (sc);
451 }
452
453 int
uart_ns16550_tty_open(struct uart_ns16550_softc * sc,const char * device)454 uart_ns16550_tty_open(struct uart_ns16550_softc *sc, const char *device)
455 {
456 return (uart_tty_open(sc->backend, device, uart_drain, sc));
457 }
458
459 #ifdef BHYVE_SNAPSHOT
460 int
uart_ns16550_snapshot(struct uart_ns16550_softc * sc,struct vm_snapshot_meta * meta)461 uart_ns16550_snapshot(struct uart_ns16550_softc *sc,
462 struct vm_snapshot_meta *meta)
463 {
464 int ret;
465
466 SNAPSHOT_VAR_OR_LEAVE(sc->data, meta, ret, done);
467 SNAPSHOT_VAR_OR_LEAVE(sc->ier, meta, ret, done);
468 SNAPSHOT_VAR_OR_LEAVE(sc->lcr, meta, ret, done);
469 SNAPSHOT_VAR_OR_LEAVE(sc->mcr, meta, ret, done);
470 SNAPSHOT_VAR_OR_LEAVE(sc->lsr, meta, ret, done);
471 SNAPSHOT_VAR_OR_LEAVE(sc->msr, meta, ret, done);
472 SNAPSHOT_VAR_OR_LEAVE(sc->fcr, meta, ret, done);
473 SNAPSHOT_VAR_OR_LEAVE(sc->scr, meta, ret, done);
474
475 SNAPSHOT_VAR_OR_LEAVE(sc->dll, meta, ret, done);
476 SNAPSHOT_VAR_OR_LEAVE(sc->dlh, meta, ret, done);
477
478 ret = uart_rxfifo_snapshot(sc->backend, meta);
479
480 sc->thre_int_pending = 1;
481
482 done:
483 return (ret);
484 }
485 #endif
486