2 * Copyright (c) 2012 NetApp, Inc.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 #include <sys/cdefs.h>
30 __FBSDID("$FreeBSD$");
32 #include <sys/types.h>
33 #include <sys/select.h>
34 #include <dev/ic/ns16550.h>
49 #define COM1_BASE 0x3F8
51 #define COM2_BASE 0x2F8
54 #define DEFAULT_RCLK 1843200
55 #define DEFAULT_BAUD 9600
57 #define FCR_RX_MASK 0xC0
62 #define MSR_DELTA_MASK 0x0f
65 #define REG_SCR com_scr
71 * Pick a PCI vid/did of a chip with a single uart at
72 * BAR0, that most versions of FreeBSD can understand:
73 * Siig CyberSerial 1-port.
75 #define COM_VENDOR 0x131f
76 #define COM_DEV 0x2000
78 static int pci_uart_stdio; /* stdio in use for i/o */
80 static int pci_uart_nldevs; /* number of legacy devices - 2 max */
86 { COM1_BASE, COM1_IRQ},
87 { COM2_BASE, COM2_IRQ},
93 int rindex; /* index to read from */
94 int windex; /* index to write to */
95 int num; /* number of characters in the fifo */
96 int size; /* size of the fifo */
99 struct pci_uart_softc {
100 struct pci_devinst *pi;
101 pthread_mutex_t mtx; /* protects all softc elements */
102 uint8_t data; /* Data register (R/W) */
103 uint8_t ier; /* Interrupt enable register (R/W) */
104 uint8_t lcr; /* Line control register (R/W) */
105 uint8_t mcr; /* Modem control register (R/W) */
106 uint8_t lsr; /* Line status register (R/W) */
107 uint8_t msr; /* Modem status register (R/W) */
108 uint8_t fcr; /* FIFO control register (W) */
109 uint8_t scr; /* Scratch register (R/W) */
111 uint8_t dll; /* Baudrate divisor latch LSB */
112 uint8_t dlh; /* Baudrate divisor latch MSB */
118 bool thre_int_pending; /* THRE interrupt pending */
121 static void pci_uart_drain(int fd, enum ev_type ev, void *arg);
123 static struct termios tio_orig, tio_new; /* I/O Terminals */
128 tcsetattr(STDIN_FILENO, TCSANOW, &tio_orig);
134 tcgetattr(STDIN_FILENO, &tio_orig);
137 tcsetattr(STDIN_FILENO, TCSANOW, &tio_new);
143 tty_char_available(void)
149 FD_SET(STDIN_FILENO, &rfds);
152 if (select(STDIN_FILENO + 1, &rfds, NULL, NULL, &tv) > 0 ) {
164 if (tty_char_available()) {
165 read(STDIN_FILENO, &rb, 1);
173 ttywrite(unsigned char wb)
175 (void) write(STDIN_FILENO, &wb, 1);
179 fifo_reset(struct fifo *fifo, int size)
181 bzero(fifo, sizeof(struct fifo));
186 fifo_putchar(struct fifo *fifo, uint8_t ch)
189 if (fifo->num < fifo->size) {
190 fifo->buf[fifo->windex] = ch;
191 fifo->windex = (fifo->windex + 1) % fifo->size;
199 fifo_getchar(struct fifo *fifo)
204 c = fifo->buf[fifo->rindex];
205 fifo->rindex = (fifo->rindex + 1) % fifo->size;
213 fifo_numchars(struct fifo *fifo)
220 fifo_available(struct fifo *fifo)
223 return (fifo->num < fifo->size);
227 pci_uart_opentty(struct pci_uart_softc *sc)
231 assert(sc->opened == 0);
235 mev = mevent_add(STDIN_FILENO, EVF_READ, pci_uart_drain, sc);
240 pci_uart_legacy_res(uint64_t *bar, int *ivec)
242 if (pci_uart_lres[pci_uart_nldevs].baddr != 0) {
243 *bar = pci_uart_lres[pci_uart_nldevs].baddr;
244 *ivec = pci_uart_lres[pci_uart_nldevs].vector;
247 /* TODO: print warning ? */
254 * The IIR returns a prioritized interrupt reason:
255 * - receive data available
256 * - transmit holding register empty
257 * - modem status change
259 * Return an interrupt reason if one is available.
262 pci_uart_intr_reason(struct pci_uart_softc *sc)
265 if ((sc->lsr & LSR_OE) != 0 && (sc->ier & IER_ERLS) != 0)
267 else if (fifo_numchars(&sc->rxfifo) > 0 && (sc->ier & IER_ERXRDY) != 0)
269 else if (sc->thre_int_pending && (sc->ier & IER_ETXRDY) != 0)
271 else if ((sc->msr & MSR_DELTA_MASK) != 0 && (sc->ier & IER_EMSC) != 0)
278 pci_uart_reset(struct pci_uart_softc *sc)
282 divisor = DEFAULT_RCLK / DEFAULT_BAUD / 16;
284 sc->dlh = divisor >> 16;
286 fifo_reset(&sc->rxfifo, 1); /* no fifo until enabled by software */
290 * Toggle the COM port's intr pin depending on whether or not we have an
291 * interrupt condition to report to the processor.
294 pci_uart_toggle_intr(struct pci_uart_softc *sc)
298 intr_reason = pci_uart_intr_reason(sc);
300 if (intr_reason == IIR_NOPEND)
301 pci_lintr_deassert(sc->pi);
303 pci_lintr_assert(sc->pi);
307 pci_uart_drain(int fd, enum ev_type ev, void *arg)
309 struct pci_uart_softc *sc;
314 assert(fd == STDIN_FILENO);
315 assert(ev == EVF_READ);
318 * This routine is called in the context of the mevent thread
319 * to take out the softc lock to protect against concurrent
320 * access from a vCPU i/o exit
322 pthread_mutex_lock(&sc->mtx);
324 if ((sc->mcr & MCR_LOOPBACK) != 0) {
327 while (fifo_available(&sc->rxfifo) &&
328 ((ch = ttyread()) != -1)) {
329 fifo_putchar(&sc->rxfifo, ch);
331 pci_uart_toggle_intr(sc);
334 pthread_mutex_unlock(&sc->mtx);
338 pci_uart_write(struct vmctx *ctx, int vcpu, struct pci_devinst *pi,
339 int baridx, uint64_t offset, int size, uint64_t value)
341 struct pci_uart_softc *sc;
351 if (!sc->opened && sc->stdio) {
352 pci_uart_opentty(sc);
356 pthread_mutex_lock(&sc->mtx);
359 * Take care of the special case DLAB accesses first
361 if ((sc->lcr & LCR_DLAB) != 0) {
362 if (offset == REG_DLL) {
367 if (offset == REG_DLH) {
375 if (sc->mcr & MCR_LOOPBACK) {
376 if (fifo_putchar(&sc->rxfifo, value) != 0)
378 } else if (sc->stdio) {
380 } /* else drop on floor */
381 sc->thre_int_pending = true;
385 * Apply mask so that bits 4-7 are 0
386 * Also enables bits 0-3 only if they're 1
388 sc->ier = value & 0x0F;
392 * When moving from FIFO and 16450 mode and vice versa,
393 * the FIFO contents are reset.
395 if ((sc->fcr & FCR_ENABLE) ^ (value & FCR_ENABLE)) {
396 fifosz = (value & FCR_ENABLE) ? FIFOSZ : 1;
397 fifo_reset(&sc->rxfifo, fifosz);
401 * The FCR_ENABLE bit must be '1' for the programming
402 * of other FCR bits to be effective.
404 if ((value & FCR_ENABLE) == 0) {
407 if ((value & FCR_RCV_RST) != 0)
408 fifo_reset(&sc->rxfifo, FIFOSZ);
411 (FCR_ENABLE | FCR_DMA | FCR_RX_MASK);
418 /* Apply mask so that bits 5-7 are 0 */
419 sc->mcr = value & 0x1F;
422 if (sc->mcr & MCR_LOOPBACK) {
424 * In the loopback mode certain bits from the
425 * MCR are reflected back into MSR
427 if (sc->mcr & MCR_RTS)
429 if (sc->mcr & MCR_DTR)
431 if (sc->mcr & MCR_OUT1)
433 if (sc->mcr & MCR_OUT2)
438 * Detect if there has been any change between the
439 * previous and the new value of MSR. If there is
440 * then assert the appropriate MSR delta bit.
442 if ((msr & MSR_CTS) ^ (sc->msr & MSR_CTS))
444 if ((msr & MSR_DSR) ^ (sc->msr & MSR_DSR))
446 if ((msr & MSR_DCD) ^ (sc->msr & MSR_DCD))
448 if ((sc->msr & MSR_RI) != 0 && (msr & MSR_RI) == 0)
452 * Update the value of MSR while retaining the delta
455 sc->msr &= MSR_DELTA_MASK;
460 * Line status register is not meant to be written to
461 * during normal operation.
466 * As far as I can tell MSR is a read-only register.
477 pci_uart_toggle_intr(sc);
478 pthread_mutex_unlock(&sc->mtx);
482 pci_uart_read(struct vmctx *ctx, int vcpu, struct pci_devinst *pi,
483 int baridx, uint64_t offset, int size)
485 struct pci_uart_softc *sc;
486 uint8_t iir, intr_reason;
495 if (!sc->opened && sc->stdio) {
496 pci_uart_opentty(sc);
500 pthread_mutex_lock(&sc->mtx);
503 * Take care of the special case DLAB accesses first
505 if ((sc->lcr & LCR_DLAB) != 0) {
506 if (offset == REG_DLL) {
511 if (offset == REG_DLH) {
519 reg = fifo_getchar(&sc->rxfifo);
525 iir = (sc->fcr & FCR_ENABLE) ? IIR_FIFO_MASK : 0;
527 intr_reason = pci_uart_intr_reason(sc);
530 * Deal with side effects of reading the IIR register
532 if (intr_reason == IIR_TXRDY)
533 sc->thre_int_pending = false;
546 /* Transmitter is always ready for more data */
547 sc->lsr |= LSR_TEMT | LSR_THRE;
549 /* Check for new receive data */
550 if (fifo_numchars(&sc->rxfifo) > 0)
551 sc->lsr |= LSR_RXRDY;
553 sc->lsr &= ~LSR_RXRDY;
557 /* The LSR_OE bit is cleared on LSR read */
562 * MSR delta bits are cleared on read
565 sc->msr &= ~MSR_DELTA_MASK;
576 pci_uart_toggle_intr(sc);
577 pthread_mutex_unlock(&sc->mtx);
583 pci_uart_init(struct vmctx *ctx, struct pci_devinst *pi, char *opts)
585 struct pci_uart_softc *sc;
589 sc = malloc(sizeof(struct pci_uart_softc));
590 memset(sc, 0, sizeof(struct pci_uart_softc));
595 pthread_mutex_init(&sc->mtx, NULL);
597 /* initialize config space */
598 pci_set_cfgdata16(pi, PCIR_DEVICE, COM_DEV);
599 pci_set_cfgdata16(pi, PCIR_VENDOR, COM_VENDOR);
600 pci_set_cfgdata8(pi, PCIR_CLASS, PCIC_SIMPLECOMM);
601 if (pci_is_legacy(pi)) {
602 pci_uart_legacy_res(&bar, &ivec);
603 pci_emul_alloc_pbar(pi, 0, bar, PCIBAR_IO, 8);
606 pci_emul_alloc_bar(pi, 0, PCIBAR_IO, 8);
608 pci_lintr_request(pi, ivec);
610 if (opts != NULL && !strcmp("stdio", opts) && !pci_uart_stdio) {
620 struct pci_devemu pci_de_com = {
622 .pe_init = pci_uart_init,
623 .pe_barwrite = pci_uart_write,
624 .pe_barread = pci_uart_read
626 PCI_EMUL_SET(pci_de_com);