1899fe063SPekka Enberg #include "kvm/8250-serial.h" 213a7760fSPekka Enberg 38eb47d29SSasha Levin #include "kvm/read-write.h" 413a7760fSPekka Enberg #include "kvm/ioport.h" 54ef0f4d6SPekka Enberg #include "kvm/mutex.h" 646aa8d69SPekka Enberg #include "kvm/util.h" 705d1a2a6SAsias He #include "kvm/term.h" 8e557eef9SPekka Enberg #include "kvm/kvm.h" 9d28abb58SWill Deacon #include "kvm/fdt.h" 1013a7760fSPekka Enberg 113fdf659dSSasha Levin #include <linux/types.h> 124e49b05bSCyrill Gorcunov #include <linux/serial_reg.h> 134e49b05bSCyrill Gorcunov 142932c9ebSPekka Enberg #include <pthread.h> 1513a7760fSPekka Enberg 16*45b4968eSAndre Przywara #if defined(CONFIG_ARM) || defined(CONFIG_ARM64) 17*45b4968eSAndre Przywara #define serial_iobase(nr) (ARM_UART_MMIO_BASE + (nr) * 0x1000) 18*45b4968eSAndre Przywara #define serial_irq(nr) (32 + (nr)) 19*45b4968eSAndre Przywara #define SERIAL8250_BUS_TYPE DEVICE_BUS_MMIO 20*45b4968eSAndre Przywara #else 21*45b4968eSAndre Przywara #define serial_iobase_0 (KVM_IOPORT_AREA + 0x3f8) 22*45b4968eSAndre Przywara #define serial_iobase_1 (KVM_IOPORT_AREA + 0x2f8) 23*45b4968eSAndre Przywara #define serial_iobase_2 (KVM_IOPORT_AREA + 0x3e8) 24*45b4968eSAndre Przywara #define serial_iobase_3 (KVM_IOPORT_AREA + 0x2e8) 25*45b4968eSAndre Przywara #define serial_irq_0 4 26*45b4968eSAndre Przywara #define serial_irq_1 3 27*45b4968eSAndre Przywara #define serial_irq_2 4 28*45b4968eSAndre Przywara #define serial_irq_3 3 29*45b4968eSAndre Przywara #define serial_iobase(nr) serial_iobase_##nr 30*45b4968eSAndre Przywara #define serial_irq(nr) serial_irq_##nr 31*45b4968eSAndre Przywara #define SERIAL8250_BUS_TYPE DEVICE_BUS_IOPORT 32*45b4968eSAndre Przywara #endif 33*45b4968eSAndre Przywara 34d4b02a37SThomas Gleixner /* 35d4b02a37SThomas Gleixner * This fakes a U6_16550A. The fifo len needs to be 64 as the kernel 36d4b02a37SThomas Gleixner * expects that for autodetection. 37d4b02a37SThomas Gleixner */ 38d4b02a37SThomas Gleixner #define FIFO_LEN 64 39d4b02a37SThomas Gleixner #define FIFO_MASK (FIFO_LEN - 1) 40d4b02a37SThomas Gleixner 41d4b02a37SThomas Gleixner #define UART_IIR_TYPE_BITS 0xc0 42d4b02a37SThomas Gleixner 4346aa8d69SPekka Enberg struct serial8250_device { 44a81be31eSAndre Przywara struct device_header dev_hdr; 45d3476f7dSSasha Levin struct mutex mutex; 461add4b76SSasha Levin u8 id; 472932c9ebSPekka Enberg 48*45b4968eSAndre Przywara u32 iobase; 493fdf659dSSasha Levin u8 irq; 50f6b8ccc1SThomas Gleixner u8 irq_state; 518dfae8beSThomas Gleixner int txcnt; 52d4b02a37SThomas Gleixner int rxcnt; 53d4b02a37SThomas Gleixner int rxdone; 54d4b02a37SThomas Gleixner char txbuf[FIFO_LEN]; 55d4b02a37SThomas Gleixner char rxbuf[FIFO_LEN]; 5676b4a122SPekka Enberg 573fdf659dSSasha Levin u8 dll; 583fdf659dSSasha Levin u8 dlm; 593fdf659dSSasha Levin u8 iir; 603fdf659dSSasha Levin u8 ier; 613fdf659dSSasha Levin u8 fcr; 623fdf659dSSasha Levin u8 lcr; 633fdf659dSSasha Levin u8 mcr; 643fdf659dSSasha Levin u8 lsr; 653fdf659dSSasha Levin u8 msr; 663fdf659dSSasha Levin u8 scr; 6746aa8d69SPekka Enberg }; 6846aa8d69SPekka Enberg 69f3efa592SLiming Wang #define SERIAL_REGS_SETTING \ 70f3efa592SLiming Wang .iir = UART_IIR_NO_INT, \ 71f3efa592SLiming Wang .lsr = UART_LSR_TEMT | UART_LSR_THRE, \ 72f3efa592SLiming Wang .msr = UART_MSR_DCD | UART_MSR_DSR | UART_MSR_CTS, \ 73f3efa592SLiming Wang .mcr = UART_MCR_OUT2, 74f3efa592SLiming Wang 75a81be31eSAndre Przywara #ifdef CONFIG_HAS_LIBFDT 76a81be31eSAndre Przywara static 77a81be31eSAndre Przywara void serial8250_generate_fdt_node(void *fdt, struct device_header *dev_hdr, 78a81be31eSAndre Przywara fdt_irq_fn irq_fn); 79a81be31eSAndre Przywara #else 80a81be31eSAndre Przywara #define serial8250_generate_fdt_node NULL 81a81be31eSAndre Przywara #endif 82e62c18deSPekka Enberg static struct serial8250_device devices[] = { 83c6a69c61SPekka Enberg /* ttyS0 */ 84c6a69c61SPekka Enberg [0] = { 85a81be31eSAndre Przywara .dev_hdr = { 86*45b4968eSAndre Przywara .bus_type = SERIAL8250_BUS_TYPE, 87a81be31eSAndre Przywara .data = serial8250_generate_fdt_node, 88a81be31eSAndre Przywara }, 89d3476f7dSSasha Levin .mutex = MUTEX_INITIALIZER, 902932c9ebSPekka Enberg 911add4b76SSasha Levin .id = 0, 92*45b4968eSAndre Przywara .iobase = serial_iobase(0), 93*45b4968eSAndre Przywara .irq = serial_irq(0), 94e557eef9SPekka Enberg 95f3efa592SLiming Wang SERIAL_REGS_SETTING 96c6a69c61SPekka Enberg }, 97e62c18deSPekka Enberg /* ttyS1 */ 98e62c18deSPekka Enberg [1] = { 99a81be31eSAndre Przywara .dev_hdr = { 100*45b4968eSAndre Przywara .bus_type = SERIAL8250_BUS_TYPE, 101a81be31eSAndre Przywara .data = serial8250_generate_fdt_node, 102a81be31eSAndre Przywara }, 103d3476f7dSSasha Levin .mutex = MUTEX_INITIALIZER, 1042932c9ebSPekka Enberg 1051add4b76SSasha Levin .id = 1, 106*45b4968eSAndre Przywara .iobase = serial_iobase(1), 107*45b4968eSAndre Przywara .irq = serial_irq(1), 108133bedc1SPekka Enberg 109f3efa592SLiming Wang SERIAL_REGS_SETTING 110e62c18deSPekka Enberg }, 111e62c18deSPekka Enberg /* ttyS2 */ 112e62c18deSPekka Enberg [2] = { 113a81be31eSAndre Przywara .dev_hdr = { 114*45b4968eSAndre Przywara .bus_type = SERIAL8250_BUS_TYPE, 115a81be31eSAndre Przywara .data = serial8250_generate_fdt_node, 116a81be31eSAndre Przywara }, 117d3476f7dSSasha Levin .mutex = MUTEX_INITIALIZER, 1182932c9ebSPekka Enberg 1191add4b76SSasha Levin .id = 2, 120*45b4968eSAndre Przywara .iobase = serial_iobase(2), 121*45b4968eSAndre Przywara .irq = serial_irq(2), 122133bedc1SPekka Enberg 123f3efa592SLiming Wang SERIAL_REGS_SETTING 124e62c18deSPekka Enberg }, 125bf459c83SPekka Enberg /* ttyS3 */ 126bf459c83SPekka Enberg [3] = { 127a81be31eSAndre Przywara .dev_hdr = { 128*45b4968eSAndre Przywara .bus_type = SERIAL8250_BUS_TYPE, 129a81be31eSAndre Przywara .data = serial8250_generate_fdt_node, 130a81be31eSAndre Przywara }, 131d3476f7dSSasha Levin .mutex = MUTEX_INITIALIZER, 132bf459c83SPekka Enberg 1331add4b76SSasha Levin .id = 3, 134*45b4968eSAndre Przywara .iobase = serial_iobase(3), 135*45b4968eSAndre Przywara .irq = serial_irq(3), 136bf459c83SPekka Enberg 137f3efa592SLiming Wang SERIAL_REGS_SETTING 138bf459c83SPekka Enberg }, 13946aa8d69SPekka Enberg }; 14046aa8d69SPekka Enberg 1412651ea58SSasha Levin static void serial8250_flush_tx(struct kvm *kvm, struct serial8250_device *dev) 142d4b02a37SThomas Gleixner { 143d4b02a37SThomas Gleixner dev->lsr |= UART_LSR_TEMT | UART_LSR_THRE; 144d4b02a37SThomas Gleixner 145d4b02a37SThomas Gleixner if (dev->txcnt) { 1462651ea58SSasha Levin term_putc(dev->txbuf, dev->txcnt, dev->id); 147d4b02a37SThomas Gleixner dev->txcnt = 0; 148d4b02a37SThomas Gleixner } 149d4b02a37SThomas Gleixner } 150d4b02a37SThomas Gleixner 151f6b8ccc1SThomas Gleixner static void serial8250_update_irq(struct kvm *kvm, struct serial8250_device *dev) 152f6b8ccc1SThomas Gleixner { 153f6b8ccc1SThomas Gleixner u8 iir = 0; 154f6b8ccc1SThomas Gleixner 155d4b02a37SThomas Gleixner /* Handle clear rx */ 156d4b02a37SThomas Gleixner if (dev->lcr & UART_FCR_CLEAR_RCVR) { 157d4b02a37SThomas Gleixner dev->lcr &= ~UART_FCR_CLEAR_RCVR; 158d4b02a37SThomas Gleixner dev->rxcnt = dev->rxdone = 0; 159d4b02a37SThomas Gleixner dev->lsr &= ~UART_LSR_DR; 160d4b02a37SThomas Gleixner } 161d4b02a37SThomas Gleixner 162d4b02a37SThomas Gleixner /* Handle clear tx */ 163d4b02a37SThomas Gleixner if (dev->lcr & UART_FCR_CLEAR_XMIT) { 164d4b02a37SThomas Gleixner dev->lcr &= ~UART_FCR_CLEAR_XMIT; 165d4b02a37SThomas Gleixner dev->txcnt = 0; 166d4b02a37SThomas Gleixner dev->lsr |= UART_LSR_TEMT | UART_LSR_THRE; 167d4b02a37SThomas Gleixner } 168d4b02a37SThomas Gleixner 169f6b8ccc1SThomas Gleixner /* Data ready and rcv interrupt enabled ? */ 170f6b8ccc1SThomas Gleixner if ((dev->ier & UART_IER_RDI) && (dev->lsr & UART_LSR_DR)) 171f6b8ccc1SThomas Gleixner iir |= UART_IIR_RDI; 172f6b8ccc1SThomas Gleixner 173f6b8ccc1SThomas Gleixner /* Transmitter empty and interrupt enabled ? */ 174f6b8ccc1SThomas Gleixner if ((dev->ier & UART_IER_THRI) && (dev->lsr & UART_LSR_TEMT)) 175f6b8ccc1SThomas Gleixner iir |= UART_IIR_THRI; 176f6b8ccc1SThomas Gleixner 177f6b8ccc1SThomas Gleixner /* Now update the irq line, if necessary */ 178f6b8ccc1SThomas Gleixner if (!iir) { 179f6b8ccc1SThomas Gleixner dev->iir = UART_IIR_NO_INT; 180f6b8ccc1SThomas Gleixner if (dev->irq_state) 181f6b8ccc1SThomas Gleixner kvm__irq_line(kvm, dev->irq, 0); 182f6b8ccc1SThomas Gleixner } else { 183f6b8ccc1SThomas Gleixner dev->iir = iir; 184f6b8ccc1SThomas Gleixner if (!dev->irq_state) 185f6b8ccc1SThomas Gleixner kvm__irq_line(kvm, dev->irq, 1); 186f6b8ccc1SThomas Gleixner } 187f6b8ccc1SThomas Gleixner dev->irq_state = iir; 1888dfae8beSThomas Gleixner 1898dfae8beSThomas Gleixner /* 1908dfae8beSThomas Gleixner * If the kernel disabled the tx interrupt, we know that there 1918dfae8beSThomas Gleixner * is nothing more to transmit, so we can reset our tx logic 1928dfae8beSThomas Gleixner * here. 1938dfae8beSThomas Gleixner */ 194d4b02a37SThomas Gleixner if (!(dev->ier & UART_IER_THRI)) 1952651ea58SSasha Levin serial8250_flush_tx(kvm, dev); 196f6b8ccc1SThomas Gleixner } 197f6b8ccc1SThomas Gleixner 198a428f72eSPekka Enberg #define SYSRQ_PENDING_NONE 0 199a428f72eSPekka Enberg 200a428f72eSPekka Enberg static int sysrq_pending; 201a428f72eSPekka Enberg 20243835ac9SSasha Levin static void serial8250__sysrq(struct kvm *kvm, struct serial8250_device *dev) 203a428f72eSPekka Enberg { 204a428f72eSPekka Enberg dev->lsr |= UART_LSR_DR | UART_LSR_BI; 205226e727bSSasha Levin dev->rxbuf[dev->rxcnt++] = sysrq_pending; 206a428f72eSPekka Enberg sysrq_pending = SYSRQ_PENDING_NONE; 207a428f72eSPekka Enberg } 208a428f72eSPekka Enberg 209d4b02a37SThomas Gleixner static void serial8250__receive(struct kvm *kvm, struct serial8250_device *dev, 210d4b02a37SThomas Gleixner bool handle_sysrq) 211251cf9a6SPekka Enberg { 212251cf9a6SPekka Enberg int c; 213251cf9a6SPekka Enberg 214d4b02a37SThomas Gleixner if (dev->mcr & UART_MCR_LOOP) 215db34045cSPekka Enberg return; 216db34045cSPekka Enberg 217d4b02a37SThomas Gleixner if ((dev->lsr & UART_LSR_DR) || dev->rxcnt) 218d4b02a37SThomas Gleixner return; 219d4b02a37SThomas Gleixner 220d4b02a37SThomas Gleixner if (handle_sysrq && sysrq_pending) { 22143835ac9SSasha Levin serial8250__sysrq(kvm, dev); 222a428f72eSPekka Enberg return; 223a428f72eSPekka Enberg } 224a428f72eSPekka Enberg 2252651ea58SSasha Levin if (kvm->cfg.active_console != CONSOLE_8250) 2262651ea58SSasha Levin return; 2272651ea58SSasha Levin 2282651ea58SSasha Levin while (term_readable(dev->id) && 229d4b02a37SThomas Gleixner dev->rxcnt < FIFO_LEN) { 230251cf9a6SPekka Enberg 2314346fd8fSSasha Levin c = term_getc(kvm, dev->id); 23205d1a2a6SAsias He 233251cf9a6SPekka Enberg if (c < 0) 234d4b02a37SThomas Gleixner break; 235d4b02a37SThomas Gleixner dev->rxbuf[dev->rxcnt++] = c; 236251cf9a6SPekka Enberg dev->lsr |= UART_LSR_DR; 237251cf9a6SPekka Enberg } 238d4b02a37SThomas Gleixner } 239251cf9a6SPekka Enberg 240f6b8ccc1SThomas Gleixner void serial8250__update_consoles(struct kvm *kvm) 2418bb34e0dSPekka Enberg { 242479de16fSCyrill Gorcunov unsigned int i; 2431add4b76SSasha Levin 244479de16fSCyrill Gorcunov for (i = 0; i < ARRAY_SIZE(devices); i++) { 2451add4b76SSasha Levin struct serial8250_device *dev = &devices[i]; 246934c193bSPekka Enberg 2474ef0f4d6SPekka Enberg mutex_lock(&dev->mutex); 2482932c9ebSPekka Enberg 249d4b02a37SThomas Gleixner /* Restrict sysrq injection to the first port */ 250d4b02a37SThomas Gleixner serial8250__receive(kvm, dev, i == 0); 251251cf9a6SPekka Enberg 252f6b8ccc1SThomas Gleixner serial8250_update_irq(kvm, dev); 2532932c9ebSPekka Enberg 2544ef0f4d6SPekka Enberg mutex_unlock(&dev->mutex); 2558bb34e0dSPekka Enberg } 2561add4b76SSasha Levin } 2578bb34e0dSPekka Enberg 258226e727bSSasha Levin void serial8250__inject_sysrq(struct kvm *kvm, char sysrq) 259a428f72eSPekka Enberg { 260226e727bSSasha Levin sysrq_pending = sysrq; 261a428f72eSPekka Enberg } 262a428f72eSPekka Enberg 26347a51060SAndre Przywara static bool serial8250_out(struct serial8250_device *dev, struct kvm_cpu *vcpu, 26447a51060SAndre Przywara u16 offset, void *data) 26513a7760fSPekka Enberg { 2662932c9ebSPekka Enberg bool ret = true; 267d4b02a37SThomas Gleixner char *addr = data; 26846aa8d69SPekka Enberg 2694ef0f4d6SPekka Enberg mutex_lock(&dev->mutex); 2702932c9ebSPekka Enberg 27146aa8d69SPekka Enberg switch (offset) { 272c59fa0c4SThomas Gleixner case UART_TX: 273d4b02a37SThomas Gleixner if (dev->lcr & UART_LCR_DLAB) { 274c59fa0c4SThomas Gleixner dev->dll = ioport__read8(data); 275d4b02a37SThomas Gleixner break; 276d4b02a37SThomas Gleixner } 277d4b02a37SThomas Gleixner 278d4b02a37SThomas Gleixner /* Loopback mode */ 279d4b02a37SThomas Gleixner if (dev->mcr & UART_MCR_LOOP) { 280d4b02a37SThomas Gleixner if (dev->rxcnt < FIFO_LEN) { 281d4b02a37SThomas Gleixner dev->rxbuf[dev->rxcnt++] = *addr; 282d4b02a37SThomas Gleixner dev->lsr |= UART_LSR_DR; 283d4b02a37SThomas Gleixner } 284d4b02a37SThomas Gleixner break; 285d4b02a37SThomas Gleixner } 286d4b02a37SThomas Gleixner 287d4b02a37SThomas Gleixner if (dev->txcnt < FIFO_LEN) { 288d4b02a37SThomas Gleixner dev->txbuf[dev->txcnt++] = *addr; 289d4b02a37SThomas Gleixner dev->lsr &= ~UART_LSR_TEMT; 290d4b02a37SThomas Gleixner if (dev->txcnt == FIFO_LEN / 2) 291d4b02a37SThomas Gleixner dev->lsr &= ~UART_LSR_THRE; 2924123ca55SMarc Zyngier serial8250_flush_tx(vcpu->kvm, dev); 293d4b02a37SThomas Gleixner } else { 294d4b02a37SThomas Gleixner /* Should never happpen */ 295d4b02a37SThomas Gleixner dev->lsr &= ~(UART_LSR_TEMT | UART_LSR_THRE); 29646aa8d69SPekka Enberg } 297369c01c0SPekka Enberg break; 2984e49b05bSCyrill Gorcunov case UART_IER: 299f6b8ccc1SThomas Gleixner if (!(dev->lcr & UART_LCR_DLAB)) 300d4b02a37SThomas Gleixner dev->ier = ioport__read8(data) & 0x0f; 301f6b8ccc1SThomas Gleixner else 302c59fa0c4SThomas Gleixner dev->dlm = ioport__read8(data); 303c59fa0c4SThomas Gleixner break; 304c59fa0c4SThomas Gleixner case UART_FCR: 305c59fa0c4SThomas Gleixner dev->fcr = ioport__read8(data); 30646aa8d69SPekka Enberg break; 307369c01c0SPekka Enberg case UART_LCR: 308369c01c0SPekka Enberg dev->lcr = ioport__read8(data); 309369c01c0SPekka Enberg break; 310369c01c0SPekka Enberg case UART_MCR: 311369c01c0SPekka Enberg dev->mcr = ioport__read8(data); 312369c01c0SPekka Enberg break; 313369c01c0SPekka Enberg case UART_LSR: 314369c01c0SPekka Enberg /* Factory test */ 315369c01c0SPekka Enberg break; 316369c01c0SPekka Enberg case UART_MSR: 317369c01c0SPekka Enberg /* Not used */ 318369c01c0SPekka Enberg break; 319369c01c0SPekka Enberg case UART_SCR: 320369c01c0SPekka Enberg dev->scr = ioport__read8(data); 321369c01c0SPekka Enberg break; 322369c01c0SPekka Enberg default: 3232932c9ebSPekka Enberg ret = false; 324d2ea115dSThomas Gleixner break; 32546aa8d69SPekka Enberg } 3262932c9ebSPekka Enberg 3274123ca55SMarc Zyngier serial8250_update_irq(vcpu->kvm, dev); 328f6b8ccc1SThomas Gleixner 3294ef0f4d6SPekka Enberg mutex_unlock(&dev->mutex); 3302932c9ebSPekka Enberg 3312932c9ebSPekka Enberg return ret; 33213a7760fSPekka Enberg } 33313a7760fSPekka Enberg 334d4b02a37SThomas Gleixner static void serial8250_rx(struct serial8250_device *dev, void *data) 335d4b02a37SThomas Gleixner { 336d4b02a37SThomas Gleixner if (dev->rxdone == dev->rxcnt) 337d4b02a37SThomas Gleixner return; 338d4b02a37SThomas Gleixner 339d4b02a37SThomas Gleixner /* Break issued ? */ 340d4b02a37SThomas Gleixner if (dev->lsr & UART_LSR_BI) { 341d4b02a37SThomas Gleixner dev->lsr &= ~UART_LSR_BI; 342d4b02a37SThomas Gleixner ioport__write8(data, 0); 343d4b02a37SThomas Gleixner return; 344d4b02a37SThomas Gleixner } 345d4b02a37SThomas Gleixner 346d4b02a37SThomas Gleixner ioport__write8(data, dev->rxbuf[dev->rxdone++]); 347d4b02a37SThomas Gleixner if (dev->rxcnt == dev->rxdone) { 348d4b02a37SThomas Gleixner dev->lsr &= ~UART_LSR_DR; 349d4b02a37SThomas Gleixner dev->rxcnt = dev->rxdone = 0; 350d4b02a37SThomas Gleixner } 351d4b02a37SThomas Gleixner } 352d4b02a37SThomas Gleixner 35347a51060SAndre Przywara static bool serial8250_in(struct serial8250_device *dev, struct kvm_cpu *vcpu, 35447a51060SAndre Przywara u16 offset, void *data) 35525af6674SPekka Enberg { 3562932c9ebSPekka Enberg bool ret = true; 35746aa8d69SPekka Enberg 3584ef0f4d6SPekka Enberg mutex_lock(&dev->mutex); 3592932c9ebSPekka Enberg 36046aa8d69SPekka Enberg switch (offset) { 361251cf9a6SPekka Enberg case UART_RX: 362d4b02a37SThomas Gleixner if (dev->lcr & UART_LCR_DLAB) 363c59fa0c4SThomas Gleixner ioport__write8(data, dev->dll); 364d4b02a37SThomas Gleixner else 365d4b02a37SThomas Gleixner serial8250_rx(dev, data); 366369c01c0SPekka Enberg break; 367c59fa0c4SThomas Gleixner case UART_IER: 368c59fa0c4SThomas Gleixner if (dev->lcr & UART_LCR_DLAB) 369c59fa0c4SThomas Gleixner ioport__write8(data, dev->dlm); 370c59fa0c4SThomas Gleixner else 371c59fa0c4SThomas Gleixner ioport__write8(data, dev->ier); 372c59fa0c4SThomas Gleixner break; 373f6b8ccc1SThomas Gleixner case UART_IIR: 374d4b02a37SThomas Gleixner ioport__write8(data, dev->iir | UART_IIR_TYPE_BITS); 37546aa8d69SPekka Enberg break; 3764e49b05bSCyrill Gorcunov case UART_LCR: 377c6a69c61SPekka Enberg ioport__write8(data, dev->lcr); 37846aa8d69SPekka Enberg break; 3794e49b05bSCyrill Gorcunov case UART_MCR: 380c6a69c61SPekka Enberg ioport__write8(data, dev->mcr); 38146aa8d69SPekka Enberg break; 3824e49b05bSCyrill Gorcunov case UART_LSR: 383c6a69c61SPekka Enberg ioport__write8(data, dev->lsr); 38446aa8d69SPekka Enberg break; 3854e49b05bSCyrill Gorcunov case UART_MSR: 386369c01c0SPekka Enberg ioport__write8(data, dev->msr); 38746aa8d69SPekka Enberg break; 3884e49b05bSCyrill Gorcunov case UART_SCR: 389369c01c0SPekka Enberg ioport__write8(data, dev->scr); 39046aa8d69SPekka Enberg break; 391369c01c0SPekka Enberg default: 3922932c9ebSPekka Enberg ret = false; 393c59fa0c4SThomas Gleixner break; 39425af6674SPekka Enberg } 395f6b8ccc1SThomas Gleixner 3964123ca55SMarc Zyngier serial8250_update_irq(vcpu->kvm, dev); 397f6b8ccc1SThomas Gleixner 3984ef0f4d6SPekka Enberg mutex_unlock(&dev->mutex); 3992932c9ebSPekka Enberg 4002932c9ebSPekka Enberg return ret; 40113a7760fSPekka Enberg } 40213a7760fSPekka Enberg 40347a51060SAndre Przywara static void serial8250_mmio(struct kvm_cpu *vcpu, u64 addr, u8 *data, u32 len, 40447a51060SAndre Przywara u8 is_write, void *ptr) 40547a51060SAndre Przywara { 40647a51060SAndre Przywara struct serial8250_device *dev = ptr; 40747a51060SAndre Przywara 40847a51060SAndre Przywara if (is_write) 40947a51060SAndre Przywara serial8250_out(dev, vcpu, addr - dev->iobase, data); 41047a51060SAndre Przywara else 41147a51060SAndre Przywara serial8250_in(dev, vcpu, addr - dev->iobase, data); 41247a51060SAndre Przywara } 41347a51060SAndre Przywara 414d28abb58SWill Deacon #ifdef CONFIG_HAS_LIBFDT 41556e45ea4SAndre Przywara 41656e45ea4SAndre Przywara char *fdt_stdout_path = NULL; 41756e45ea4SAndre Przywara 418e5965f36SMarc Zyngier #define DEVICE_NAME_MAX_LEN 32 4192bfd9ac3SAndre Przywara static 420a81be31eSAndre Przywara void serial8250_generate_fdt_node(void *fdt, struct device_header *dev_hdr, 421a81be31eSAndre Przywara fdt_irq_fn irq_fn) 422d28abb58SWill Deacon { 423e5965f36SMarc Zyngier char dev_name[DEVICE_NAME_MAX_LEN]; 424a81be31eSAndre Przywara struct serial8250_device *dev = container_of(dev_hdr, 425a81be31eSAndre Przywara struct serial8250_device, 426a81be31eSAndre Przywara dev_hdr); 427a81be31eSAndre Przywara 428*45b4968eSAndre Przywara u64 addr = dev->iobase; 429d28abb58SWill Deacon u64 reg_prop[] = { 430e5965f36SMarc Zyngier cpu_to_fdt64(addr), 431d28abb58SWill Deacon cpu_to_fdt64(8), 432d28abb58SWill Deacon }; 433d28abb58SWill Deacon 434e5965f36SMarc Zyngier snprintf(dev_name, DEVICE_NAME_MAX_LEN, "U6_16550A@%llx", addr); 435e5965f36SMarc Zyngier 43656e45ea4SAndre Przywara if (!fdt_stdout_path) { 43756e45ea4SAndre Przywara fdt_stdout_path = malloc(strlen(dev_name) + 2); 43856e45ea4SAndre Przywara /* Assumes that this node is a child of the root node. */ 43956e45ea4SAndre Przywara sprintf(fdt_stdout_path, "/%s", dev_name); 44056e45ea4SAndre Przywara } 44156e45ea4SAndre Przywara 442e5965f36SMarc Zyngier _FDT(fdt_begin_node(fdt, dev_name)); 443d28abb58SWill Deacon _FDT(fdt_property_string(fdt, "compatible", "ns16550a")); 444d28abb58SWill Deacon _FDT(fdt_property(fdt, "reg", reg_prop, sizeof(reg_prop))); 445a81be31eSAndre Przywara irq_fn(fdt, dev->irq, IRQ_TYPE_LEVEL_HIGH); 446d28abb58SWill Deacon _FDT(fdt_property_cell(fdt, "clock-frequency", 1843200)); 447d28abb58SWill Deacon _FDT(fdt_end_node(fdt)); 448d28abb58SWill Deacon } 449d28abb58SWill Deacon #endif 450d28abb58SWill Deacon 451a81be31eSAndre Przywara static int serial8250__device_init(struct kvm *kvm, 452a81be31eSAndre Przywara struct serial8250_device *dev) 453bc4b0ffeSPekka Enberg { 45420715a22SSasha Levin int r; 45520715a22SSasha Levin 456a81be31eSAndre Przywara r = device__register(&dev->dev_hdr); 457a81be31eSAndre Przywara if (r < 0) 458a81be31eSAndre Przywara return r; 459a81be31eSAndre Przywara 460206c41f4SWill Deacon ioport__map_irq(&dev->irq); 461*45b4968eSAndre Przywara r = kvm__register_iotrap(kvm, dev->iobase, 8, serial8250_mmio, dev, 462*45b4968eSAndre Przywara SERIAL8250_BUS_TYPE); 46320715a22SSasha Levin 46420715a22SSasha Levin return r; 465bc4b0ffeSPekka Enberg } 466bc4b0ffeSPekka Enberg 46720715a22SSasha Levin int serial8250__init(struct kvm *kvm) 46813a7760fSPekka Enberg { 46920715a22SSasha Levin unsigned int i, j; 47020715a22SSasha Levin int r = 0; 471c6a69c61SPekka Enberg 472c6a69c61SPekka Enberg for (i = 0; i < ARRAY_SIZE(devices); i++) { 473c6a69c61SPekka Enberg struct serial8250_device *dev = &devices[i]; 474c6a69c61SPekka Enberg 47520715a22SSasha Levin r = serial8250__device_init(kvm, dev); 47620715a22SSasha Levin if (r < 0) 47720715a22SSasha Levin goto cleanup; 478c6a69c61SPekka Enberg } 47920715a22SSasha Levin 48020715a22SSasha Levin return r; 48120715a22SSasha Levin cleanup: 48220715a22SSasha Levin for (j = 0; j <= i; j++) { 48320715a22SSasha Levin struct serial8250_device *dev = &devices[j]; 48420715a22SSasha Levin 485*45b4968eSAndre Przywara kvm__deregister_iotrap(kvm, dev->iobase, SERIAL8250_BUS_TYPE); 486a81be31eSAndre Przywara device__unregister(&dev->dev_hdr); 48720715a22SSasha Levin } 48820715a22SSasha Levin 48920715a22SSasha Levin return r; 49020715a22SSasha Levin } 49149a8afd1SSasha Levin dev_init(serial8250__init); 49220715a22SSasha Levin 49320715a22SSasha Levin int serial8250__exit(struct kvm *kvm) 49420715a22SSasha Levin { 49520715a22SSasha Levin unsigned int i; 49620715a22SSasha Levin int r; 49720715a22SSasha Levin 49820715a22SSasha Levin for (i = 0; i < ARRAY_SIZE(devices); i++) { 49920715a22SSasha Levin struct serial8250_device *dev = &devices[i]; 50020715a22SSasha Levin 501*45b4968eSAndre Przywara r = kvm__deregister_iotrap(kvm, dev->iobase, 502*45b4968eSAndre Przywara SERIAL8250_BUS_TYPE); 50320715a22SSasha Levin if (r < 0) 50420715a22SSasha Levin return r; 505a81be31eSAndre Przywara device__unregister(&dev->dev_hdr); 50620715a22SSasha Levin } 50720715a22SSasha Levin 50820715a22SSasha Levin return 0; 50913a7760fSPekka Enberg } 51049a8afd1SSasha Levin dev_exit(serial8250__exit); 511