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 16d4b02a37SThomas Gleixner /* 17d4b02a37SThomas Gleixner * This fakes a U6_16550A. The fifo len needs to be 64 as the kernel 18d4b02a37SThomas Gleixner * expects that for autodetection. 19d4b02a37SThomas Gleixner */ 20d4b02a37SThomas Gleixner #define FIFO_LEN 64 21d4b02a37SThomas Gleixner #define FIFO_MASK (FIFO_LEN - 1) 22d4b02a37SThomas Gleixner 23d4b02a37SThomas Gleixner #define UART_IIR_TYPE_BITS 0xc0 24d4b02a37SThomas Gleixner 2546aa8d69SPekka Enberg struct serial8250_device { 26a81be31eSAndre Przywara struct device_header dev_hdr; 27d3476f7dSSasha Levin struct mutex mutex; 281add4b76SSasha Levin u8 id; 292932c9ebSPekka Enberg 303fdf659dSSasha Levin u16 iobase; 313fdf659dSSasha Levin u8 irq; 32f6b8ccc1SThomas Gleixner u8 irq_state; 338dfae8beSThomas Gleixner int txcnt; 34d4b02a37SThomas Gleixner int rxcnt; 35d4b02a37SThomas Gleixner int rxdone; 36d4b02a37SThomas Gleixner char txbuf[FIFO_LEN]; 37d4b02a37SThomas Gleixner char rxbuf[FIFO_LEN]; 3876b4a122SPekka Enberg 393fdf659dSSasha Levin u8 dll; 403fdf659dSSasha Levin u8 dlm; 413fdf659dSSasha Levin u8 iir; 423fdf659dSSasha Levin u8 ier; 433fdf659dSSasha Levin u8 fcr; 443fdf659dSSasha Levin u8 lcr; 453fdf659dSSasha Levin u8 mcr; 463fdf659dSSasha Levin u8 lsr; 473fdf659dSSasha Levin u8 msr; 483fdf659dSSasha Levin u8 scr; 4946aa8d69SPekka Enberg }; 5046aa8d69SPekka Enberg 51f3efa592SLiming Wang #define SERIAL_REGS_SETTING \ 52f3efa592SLiming Wang .iir = UART_IIR_NO_INT, \ 53f3efa592SLiming Wang .lsr = UART_LSR_TEMT | UART_LSR_THRE, \ 54f3efa592SLiming Wang .msr = UART_MSR_DCD | UART_MSR_DSR | UART_MSR_CTS, \ 55f3efa592SLiming Wang .mcr = UART_MCR_OUT2, 56f3efa592SLiming Wang 57a81be31eSAndre Przywara #ifdef CONFIG_HAS_LIBFDT 58a81be31eSAndre Przywara static 59a81be31eSAndre Przywara void serial8250_generate_fdt_node(void *fdt, struct device_header *dev_hdr, 60a81be31eSAndre Przywara fdt_irq_fn irq_fn); 61a81be31eSAndre Przywara #else 62a81be31eSAndre Przywara #define serial8250_generate_fdt_node NULL 63a81be31eSAndre Przywara #endif 64e62c18deSPekka Enberg static struct serial8250_device devices[] = { 65c6a69c61SPekka Enberg /* ttyS0 */ 66c6a69c61SPekka Enberg [0] = { 67a81be31eSAndre Przywara .dev_hdr = { 68a81be31eSAndre Przywara .bus_type = DEVICE_BUS_IOPORT, 69a81be31eSAndre Przywara .data = serial8250_generate_fdt_node, 70a81be31eSAndre Przywara }, 71d3476f7dSSasha Levin .mutex = MUTEX_INITIALIZER, 722932c9ebSPekka Enberg 731add4b76SSasha Levin .id = 0, 74c6a69c61SPekka Enberg .iobase = 0x3f8, 75e557eef9SPekka Enberg .irq = 4, 76e557eef9SPekka Enberg 77f3efa592SLiming Wang SERIAL_REGS_SETTING 78c6a69c61SPekka Enberg }, 79e62c18deSPekka Enberg /* ttyS1 */ 80e62c18deSPekka Enberg [1] = { 81a81be31eSAndre Przywara .dev_hdr = { 82a81be31eSAndre Przywara .bus_type = DEVICE_BUS_IOPORT, 83a81be31eSAndre Przywara .data = serial8250_generate_fdt_node, 84a81be31eSAndre Przywara }, 85d3476f7dSSasha Levin .mutex = MUTEX_INITIALIZER, 862932c9ebSPekka Enberg 871add4b76SSasha Levin .id = 1, 88e62c18deSPekka Enberg .iobase = 0x2f8, 89e62c18deSPekka Enberg .irq = 3, 90133bedc1SPekka Enberg 91f3efa592SLiming Wang SERIAL_REGS_SETTING 92e62c18deSPekka Enberg }, 93e62c18deSPekka Enberg /* ttyS2 */ 94e62c18deSPekka Enberg [2] = { 95a81be31eSAndre Przywara .dev_hdr = { 96a81be31eSAndre Przywara .bus_type = DEVICE_BUS_IOPORT, 97a81be31eSAndre Przywara .data = serial8250_generate_fdt_node, 98a81be31eSAndre Przywara }, 99d3476f7dSSasha Levin .mutex = MUTEX_INITIALIZER, 1002932c9ebSPekka Enberg 1011add4b76SSasha Levin .id = 2, 102e62c18deSPekka Enberg .iobase = 0x3e8, 103e62c18deSPekka Enberg .irq = 4, 104133bedc1SPekka Enberg 105f3efa592SLiming Wang SERIAL_REGS_SETTING 106e62c18deSPekka Enberg }, 107bf459c83SPekka Enberg /* ttyS3 */ 108bf459c83SPekka Enberg [3] = { 109a81be31eSAndre Przywara .dev_hdr = { 110a81be31eSAndre Przywara .bus_type = DEVICE_BUS_IOPORT, 111a81be31eSAndre Przywara .data = serial8250_generate_fdt_node, 112a81be31eSAndre Przywara }, 113d3476f7dSSasha Levin .mutex = MUTEX_INITIALIZER, 114bf459c83SPekka Enberg 1151add4b76SSasha Levin .id = 3, 116bf459c83SPekka Enberg .iobase = 0x2e8, 117bf459c83SPekka Enberg .irq = 3, 118bf459c83SPekka Enberg 119f3efa592SLiming Wang SERIAL_REGS_SETTING 120bf459c83SPekka Enberg }, 12146aa8d69SPekka Enberg }; 12246aa8d69SPekka Enberg 1232651ea58SSasha Levin static void serial8250_flush_tx(struct kvm *kvm, struct serial8250_device *dev) 124d4b02a37SThomas Gleixner { 125d4b02a37SThomas Gleixner dev->lsr |= UART_LSR_TEMT | UART_LSR_THRE; 126d4b02a37SThomas Gleixner 127d4b02a37SThomas Gleixner if (dev->txcnt) { 1282651ea58SSasha Levin term_putc(dev->txbuf, dev->txcnt, dev->id); 129d4b02a37SThomas Gleixner dev->txcnt = 0; 130d4b02a37SThomas Gleixner } 131d4b02a37SThomas Gleixner } 132d4b02a37SThomas Gleixner 133f6b8ccc1SThomas Gleixner static void serial8250_update_irq(struct kvm *kvm, struct serial8250_device *dev) 134f6b8ccc1SThomas Gleixner { 135f6b8ccc1SThomas Gleixner u8 iir = 0; 136f6b8ccc1SThomas Gleixner 137d4b02a37SThomas Gleixner /* Handle clear rx */ 138d4b02a37SThomas Gleixner if (dev->lcr & UART_FCR_CLEAR_RCVR) { 139d4b02a37SThomas Gleixner dev->lcr &= ~UART_FCR_CLEAR_RCVR; 140d4b02a37SThomas Gleixner dev->rxcnt = dev->rxdone = 0; 141d4b02a37SThomas Gleixner dev->lsr &= ~UART_LSR_DR; 142d4b02a37SThomas Gleixner } 143d4b02a37SThomas Gleixner 144d4b02a37SThomas Gleixner /* Handle clear tx */ 145d4b02a37SThomas Gleixner if (dev->lcr & UART_FCR_CLEAR_XMIT) { 146d4b02a37SThomas Gleixner dev->lcr &= ~UART_FCR_CLEAR_XMIT; 147d4b02a37SThomas Gleixner dev->txcnt = 0; 148d4b02a37SThomas Gleixner dev->lsr |= UART_LSR_TEMT | UART_LSR_THRE; 149d4b02a37SThomas Gleixner } 150d4b02a37SThomas Gleixner 151f6b8ccc1SThomas Gleixner /* Data ready and rcv interrupt enabled ? */ 152f6b8ccc1SThomas Gleixner if ((dev->ier & UART_IER_RDI) && (dev->lsr & UART_LSR_DR)) 153f6b8ccc1SThomas Gleixner iir |= UART_IIR_RDI; 154f6b8ccc1SThomas Gleixner 155f6b8ccc1SThomas Gleixner /* Transmitter empty and interrupt enabled ? */ 156f6b8ccc1SThomas Gleixner if ((dev->ier & UART_IER_THRI) && (dev->lsr & UART_LSR_TEMT)) 157f6b8ccc1SThomas Gleixner iir |= UART_IIR_THRI; 158f6b8ccc1SThomas Gleixner 159f6b8ccc1SThomas Gleixner /* Now update the irq line, if necessary */ 160f6b8ccc1SThomas Gleixner if (!iir) { 161f6b8ccc1SThomas Gleixner dev->iir = UART_IIR_NO_INT; 162f6b8ccc1SThomas Gleixner if (dev->irq_state) 163f6b8ccc1SThomas Gleixner kvm__irq_line(kvm, dev->irq, 0); 164f6b8ccc1SThomas Gleixner } else { 165f6b8ccc1SThomas Gleixner dev->iir = iir; 166f6b8ccc1SThomas Gleixner if (!dev->irq_state) 167f6b8ccc1SThomas Gleixner kvm__irq_line(kvm, dev->irq, 1); 168f6b8ccc1SThomas Gleixner } 169f6b8ccc1SThomas Gleixner dev->irq_state = iir; 1708dfae8beSThomas Gleixner 1718dfae8beSThomas Gleixner /* 1728dfae8beSThomas Gleixner * If the kernel disabled the tx interrupt, we know that there 1738dfae8beSThomas Gleixner * is nothing more to transmit, so we can reset our tx logic 1748dfae8beSThomas Gleixner * here. 1758dfae8beSThomas Gleixner */ 176d4b02a37SThomas Gleixner if (!(dev->ier & UART_IER_THRI)) 1772651ea58SSasha Levin serial8250_flush_tx(kvm, dev); 178f6b8ccc1SThomas Gleixner } 179f6b8ccc1SThomas Gleixner 180a428f72eSPekka Enberg #define SYSRQ_PENDING_NONE 0 181a428f72eSPekka Enberg 182a428f72eSPekka Enberg static int sysrq_pending; 183a428f72eSPekka Enberg 18443835ac9SSasha Levin static void serial8250__sysrq(struct kvm *kvm, struct serial8250_device *dev) 185a428f72eSPekka Enberg { 186a428f72eSPekka Enberg dev->lsr |= UART_LSR_DR | UART_LSR_BI; 187226e727bSSasha Levin dev->rxbuf[dev->rxcnt++] = sysrq_pending; 188a428f72eSPekka Enberg sysrq_pending = SYSRQ_PENDING_NONE; 189a428f72eSPekka Enberg } 190a428f72eSPekka Enberg 191d4b02a37SThomas Gleixner static void serial8250__receive(struct kvm *kvm, struct serial8250_device *dev, 192d4b02a37SThomas Gleixner bool handle_sysrq) 193251cf9a6SPekka Enberg { 194251cf9a6SPekka Enberg int c; 195251cf9a6SPekka Enberg 196d4b02a37SThomas Gleixner if (dev->mcr & UART_MCR_LOOP) 197db34045cSPekka Enberg return; 198db34045cSPekka Enberg 199d4b02a37SThomas Gleixner if ((dev->lsr & UART_LSR_DR) || dev->rxcnt) 200d4b02a37SThomas Gleixner return; 201d4b02a37SThomas Gleixner 202d4b02a37SThomas Gleixner if (handle_sysrq && sysrq_pending) { 20343835ac9SSasha Levin serial8250__sysrq(kvm, dev); 204a428f72eSPekka Enberg return; 205a428f72eSPekka Enberg } 206a428f72eSPekka Enberg 2072651ea58SSasha Levin if (kvm->cfg.active_console != CONSOLE_8250) 2082651ea58SSasha Levin return; 2092651ea58SSasha Levin 2102651ea58SSasha Levin while (term_readable(dev->id) && 211d4b02a37SThomas Gleixner dev->rxcnt < FIFO_LEN) { 212251cf9a6SPekka Enberg 2134346fd8fSSasha Levin c = term_getc(kvm, dev->id); 21405d1a2a6SAsias He 215251cf9a6SPekka Enberg if (c < 0) 216d4b02a37SThomas Gleixner break; 217d4b02a37SThomas Gleixner dev->rxbuf[dev->rxcnt++] = c; 218251cf9a6SPekka Enberg dev->lsr |= UART_LSR_DR; 219251cf9a6SPekka Enberg } 220d4b02a37SThomas Gleixner } 221251cf9a6SPekka Enberg 222f6b8ccc1SThomas Gleixner void serial8250__update_consoles(struct kvm *kvm) 2238bb34e0dSPekka Enberg { 224479de16fSCyrill Gorcunov unsigned int i; 2251add4b76SSasha Levin 226479de16fSCyrill Gorcunov for (i = 0; i < ARRAY_SIZE(devices); i++) { 2271add4b76SSasha Levin struct serial8250_device *dev = &devices[i]; 228934c193bSPekka Enberg 2294ef0f4d6SPekka Enberg mutex_lock(&dev->mutex); 2302932c9ebSPekka Enberg 231d4b02a37SThomas Gleixner /* Restrict sysrq injection to the first port */ 232d4b02a37SThomas Gleixner serial8250__receive(kvm, dev, i == 0); 233251cf9a6SPekka Enberg 234f6b8ccc1SThomas Gleixner serial8250_update_irq(kvm, dev); 2352932c9ebSPekka Enberg 2364ef0f4d6SPekka Enberg mutex_unlock(&dev->mutex); 2378bb34e0dSPekka Enberg } 2381add4b76SSasha Levin } 2398bb34e0dSPekka Enberg 240226e727bSSasha Levin void serial8250__inject_sysrq(struct kvm *kvm, char sysrq) 241a428f72eSPekka Enberg { 242226e727bSSasha Levin sysrq_pending = sysrq; 243a428f72eSPekka Enberg } 244a428f72eSPekka Enberg 245*47a51060SAndre Przywara static bool serial8250_out(struct serial8250_device *dev, struct kvm_cpu *vcpu, 246*47a51060SAndre Przywara u16 offset, void *data) 24713a7760fSPekka Enberg { 2482932c9ebSPekka Enberg bool ret = true; 249d4b02a37SThomas Gleixner char *addr = data; 25046aa8d69SPekka Enberg 2514ef0f4d6SPekka Enberg mutex_lock(&dev->mutex); 2522932c9ebSPekka Enberg 25346aa8d69SPekka Enberg switch (offset) { 254c59fa0c4SThomas Gleixner case UART_TX: 255d4b02a37SThomas Gleixner if (dev->lcr & UART_LCR_DLAB) { 256c59fa0c4SThomas Gleixner dev->dll = ioport__read8(data); 257d4b02a37SThomas Gleixner break; 258d4b02a37SThomas Gleixner } 259d4b02a37SThomas Gleixner 260d4b02a37SThomas Gleixner /* Loopback mode */ 261d4b02a37SThomas Gleixner if (dev->mcr & UART_MCR_LOOP) { 262d4b02a37SThomas Gleixner if (dev->rxcnt < FIFO_LEN) { 263d4b02a37SThomas Gleixner dev->rxbuf[dev->rxcnt++] = *addr; 264d4b02a37SThomas Gleixner dev->lsr |= UART_LSR_DR; 265d4b02a37SThomas Gleixner } 266d4b02a37SThomas Gleixner break; 267d4b02a37SThomas Gleixner } 268d4b02a37SThomas Gleixner 269d4b02a37SThomas Gleixner if (dev->txcnt < FIFO_LEN) { 270d4b02a37SThomas Gleixner dev->txbuf[dev->txcnt++] = *addr; 271d4b02a37SThomas Gleixner dev->lsr &= ~UART_LSR_TEMT; 272d4b02a37SThomas Gleixner if (dev->txcnt == FIFO_LEN / 2) 273d4b02a37SThomas Gleixner dev->lsr &= ~UART_LSR_THRE; 2744123ca55SMarc Zyngier serial8250_flush_tx(vcpu->kvm, dev); 275d4b02a37SThomas Gleixner } else { 276d4b02a37SThomas Gleixner /* Should never happpen */ 277d4b02a37SThomas Gleixner dev->lsr &= ~(UART_LSR_TEMT | UART_LSR_THRE); 27846aa8d69SPekka Enberg } 279369c01c0SPekka Enberg break; 2804e49b05bSCyrill Gorcunov case UART_IER: 281f6b8ccc1SThomas Gleixner if (!(dev->lcr & UART_LCR_DLAB)) 282d4b02a37SThomas Gleixner dev->ier = ioport__read8(data) & 0x0f; 283f6b8ccc1SThomas Gleixner else 284c59fa0c4SThomas Gleixner dev->dlm = ioport__read8(data); 285c59fa0c4SThomas Gleixner break; 286c59fa0c4SThomas Gleixner case UART_FCR: 287c59fa0c4SThomas Gleixner dev->fcr = ioport__read8(data); 28846aa8d69SPekka Enberg break; 289369c01c0SPekka Enberg case UART_LCR: 290369c01c0SPekka Enberg dev->lcr = ioport__read8(data); 291369c01c0SPekka Enberg break; 292369c01c0SPekka Enberg case UART_MCR: 293369c01c0SPekka Enberg dev->mcr = ioport__read8(data); 294369c01c0SPekka Enberg break; 295369c01c0SPekka Enberg case UART_LSR: 296369c01c0SPekka Enberg /* Factory test */ 297369c01c0SPekka Enberg break; 298369c01c0SPekka Enberg case UART_MSR: 299369c01c0SPekka Enberg /* Not used */ 300369c01c0SPekka Enberg break; 301369c01c0SPekka Enberg case UART_SCR: 302369c01c0SPekka Enberg dev->scr = ioport__read8(data); 303369c01c0SPekka Enberg break; 304369c01c0SPekka Enberg default: 3052932c9ebSPekka Enberg ret = false; 306d2ea115dSThomas Gleixner break; 30746aa8d69SPekka Enberg } 3082932c9ebSPekka Enberg 3094123ca55SMarc Zyngier serial8250_update_irq(vcpu->kvm, dev); 310f6b8ccc1SThomas Gleixner 3114ef0f4d6SPekka Enberg mutex_unlock(&dev->mutex); 3122932c9ebSPekka Enberg 3132932c9ebSPekka Enberg return ret; 31413a7760fSPekka Enberg } 31513a7760fSPekka Enberg 316d4b02a37SThomas Gleixner static void serial8250_rx(struct serial8250_device *dev, void *data) 317d4b02a37SThomas Gleixner { 318d4b02a37SThomas Gleixner if (dev->rxdone == dev->rxcnt) 319d4b02a37SThomas Gleixner return; 320d4b02a37SThomas Gleixner 321d4b02a37SThomas Gleixner /* Break issued ? */ 322d4b02a37SThomas Gleixner if (dev->lsr & UART_LSR_BI) { 323d4b02a37SThomas Gleixner dev->lsr &= ~UART_LSR_BI; 324d4b02a37SThomas Gleixner ioport__write8(data, 0); 325d4b02a37SThomas Gleixner return; 326d4b02a37SThomas Gleixner } 327d4b02a37SThomas Gleixner 328d4b02a37SThomas Gleixner ioport__write8(data, dev->rxbuf[dev->rxdone++]); 329d4b02a37SThomas Gleixner if (dev->rxcnt == dev->rxdone) { 330d4b02a37SThomas Gleixner dev->lsr &= ~UART_LSR_DR; 331d4b02a37SThomas Gleixner dev->rxcnt = dev->rxdone = 0; 332d4b02a37SThomas Gleixner } 333d4b02a37SThomas Gleixner } 334d4b02a37SThomas Gleixner 335*47a51060SAndre Przywara static bool serial8250_in(struct serial8250_device *dev, struct kvm_cpu *vcpu, 336*47a51060SAndre Przywara u16 offset, void *data) 33725af6674SPekka Enberg { 3382932c9ebSPekka Enberg bool ret = true; 33946aa8d69SPekka Enberg 3404ef0f4d6SPekka Enberg mutex_lock(&dev->mutex); 3412932c9ebSPekka Enberg 34246aa8d69SPekka Enberg switch (offset) { 343251cf9a6SPekka Enberg case UART_RX: 344d4b02a37SThomas Gleixner if (dev->lcr & UART_LCR_DLAB) 345c59fa0c4SThomas Gleixner ioport__write8(data, dev->dll); 346d4b02a37SThomas Gleixner else 347d4b02a37SThomas Gleixner serial8250_rx(dev, data); 348369c01c0SPekka Enberg break; 349c59fa0c4SThomas Gleixner case UART_IER: 350c59fa0c4SThomas Gleixner if (dev->lcr & UART_LCR_DLAB) 351c59fa0c4SThomas Gleixner ioport__write8(data, dev->dlm); 352c59fa0c4SThomas Gleixner else 353c59fa0c4SThomas Gleixner ioport__write8(data, dev->ier); 354c59fa0c4SThomas Gleixner break; 355f6b8ccc1SThomas Gleixner case UART_IIR: 356d4b02a37SThomas Gleixner ioport__write8(data, dev->iir | UART_IIR_TYPE_BITS); 35746aa8d69SPekka Enberg break; 3584e49b05bSCyrill Gorcunov case UART_LCR: 359c6a69c61SPekka Enberg ioport__write8(data, dev->lcr); 36046aa8d69SPekka Enberg break; 3614e49b05bSCyrill Gorcunov case UART_MCR: 362c6a69c61SPekka Enberg ioport__write8(data, dev->mcr); 36346aa8d69SPekka Enberg break; 3644e49b05bSCyrill Gorcunov case UART_LSR: 365c6a69c61SPekka Enberg ioport__write8(data, dev->lsr); 36646aa8d69SPekka Enberg break; 3674e49b05bSCyrill Gorcunov case UART_MSR: 368369c01c0SPekka Enberg ioport__write8(data, dev->msr); 36946aa8d69SPekka Enberg break; 3704e49b05bSCyrill Gorcunov case UART_SCR: 371369c01c0SPekka Enberg ioport__write8(data, dev->scr); 37246aa8d69SPekka Enberg break; 373369c01c0SPekka Enberg default: 3742932c9ebSPekka Enberg ret = false; 375c59fa0c4SThomas Gleixner break; 37625af6674SPekka Enberg } 377f6b8ccc1SThomas Gleixner 3784123ca55SMarc Zyngier serial8250_update_irq(vcpu->kvm, dev); 379f6b8ccc1SThomas Gleixner 3804ef0f4d6SPekka Enberg mutex_unlock(&dev->mutex); 3812932c9ebSPekka Enberg 3822932c9ebSPekka Enberg return ret; 38313a7760fSPekka Enberg } 38413a7760fSPekka Enberg 385*47a51060SAndre Przywara static void serial8250_mmio(struct kvm_cpu *vcpu, u64 addr, u8 *data, u32 len, 386*47a51060SAndre Przywara u8 is_write, void *ptr) 387*47a51060SAndre Przywara { 388*47a51060SAndre Przywara struct serial8250_device *dev = ptr; 389*47a51060SAndre Przywara 390*47a51060SAndre Przywara if (is_write) 391*47a51060SAndre Przywara serial8250_out(dev, vcpu, addr - dev->iobase, data); 392*47a51060SAndre Przywara else 393*47a51060SAndre Przywara serial8250_in(dev, vcpu, addr - dev->iobase, data); 394*47a51060SAndre Przywara } 395*47a51060SAndre Przywara 396*47a51060SAndre Przywara static bool serial8250_ioport_out(struct ioport *ioport, struct kvm_cpu *vcpu, 397*47a51060SAndre Przywara u16 port, void *data, int size) 398*47a51060SAndre Przywara { 399*47a51060SAndre Przywara struct serial8250_device *dev = ioport->priv; 400*47a51060SAndre Przywara 401*47a51060SAndre Przywara serial8250_mmio(vcpu, port, data, 1, true, dev); 402*47a51060SAndre Przywara 403*47a51060SAndre Przywara return true; 404*47a51060SAndre Przywara } 405*47a51060SAndre Przywara 406*47a51060SAndre Przywara static bool serial8250_ioport_in(struct ioport *ioport, struct kvm_cpu *vcpu, 407*47a51060SAndre Przywara u16 port, void *data, int size) 408*47a51060SAndre Przywara { 409*47a51060SAndre Przywara struct serial8250_device *dev = ioport->priv; 410*47a51060SAndre Przywara 411*47a51060SAndre Przywara serial8250_mmio(vcpu, port, data, 1, false, dev); 412*47a51060SAndre Przywara 413*47a51060SAndre Przywara return true; 414*47a51060SAndre Przywara } 415*47a51060SAndre Przywara 416d28abb58SWill Deacon #ifdef CONFIG_HAS_LIBFDT 41756e45ea4SAndre Przywara 41856e45ea4SAndre Przywara char *fdt_stdout_path = NULL; 41956e45ea4SAndre Przywara 420e5965f36SMarc Zyngier #define DEVICE_NAME_MAX_LEN 32 4212bfd9ac3SAndre Przywara static 422a81be31eSAndre Przywara void serial8250_generate_fdt_node(void *fdt, struct device_header *dev_hdr, 423a81be31eSAndre Przywara fdt_irq_fn irq_fn) 424d28abb58SWill Deacon { 425e5965f36SMarc Zyngier char dev_name[DEVICE_NAME_MAX_LEN]; 426a81be31eSAndre Przywara struct serial8250_device *dev = container_of(dev_hdr, 427a81be31eSAndre Przywara struct serial8250_device, 428a81be31eSAndre Przywara dev_hdr); 429a81be31eSAndre Przywara 430e5965f36SMarc Zyngier u64 addr = KVM_IOPORT_AREA + dev->iobase; 431d28abb58SWill Deacon u64 reg_prop[] = { 432e5965f36SMarc Zyngier cpu_to_fdt64(addr), 433d28abb58SWill Deacon cpu_to_fdt64(8), 434d28abb58SWill Deacon }; 435d28abb58SWill Deacon 436e5965f36SMarc Zyngier snprintf(dev_name, DEVICE_NAME_MAX_LEN, "U6_16550A@%llx", addr); 437e5965f36SMarc Zyngier 43856e45ea4SAndre Przywara if (!fdt_stdout_path) { 43956e45ea4SAndre Przywara fdt_stdout_path = malloc(strlen(dev_name) + 2); 44056e45ea4SAndre Przywara /* Assumes that this node is a child of the root node. */ 44156e45ea4SAndre Przywara sprintf(fdt_stdout_path, "/%s", dev_name); 44256e45ea4SAndre Przywara } 44356e45ea4SAndre Przywara 444e5965f36SMarc Zyngier _FDT(fdt_begin_node(fdt, dev_name)); 445d28abb58SWill Deacon _FDT(fdt_property_string(fdt, "compatible", "ns16550a")); 446d28abb58SWill Deacon _FDT(fdt_property(fdt, "reg", reg_prop, sizeof(reg_prop))); 447a81be31eSAndre Przywara irq_fn(fdt, dev->irq, IRQ_TYPE_LEVEL_HIGH); 448d28abb58SWill Deacon _FDT(fdt_property_cell(fdt, "clock-frequency", 1843200)); 449d28abb58SWill Deacon _FDT(fdt_end_node(fdt)); 450d28abb58SWill Deacon } 451d28abb58SWill Deacon #endif 452d28abb58SWill Deacon 45346aa8d69SPekka Enberg static struct ioport_operations serial8250_ops = { 454*47a51060SAndre Przywara .io_in = serial8250_ioport_in, 455*47a51060SAndre Przywara .io_out = serial8250_ioport_out, 456a93ec68bSPekka Enberg }; 457a93ec68bSPekka Enberg 458a81be31eSAndre Przywara static int serial8250__device_init(struct kvm *kvm, 459a81be31eSAndre Przywara struct serial8250_device *dev) 460bc4b0ffeSPekka Enberg { 46120715a22SSasha Levin int r; 46220715a22SSasha Levin 463a81be31eSAndre Przywara r = device__register(&dev->dev_hdr); 464a81be31eSAndre Przywara if (r < 0) 465a81be31eSAndre Przywara return r; 466a81be31eSAndre Przywara 467206c41f4SWill Deacon ioport__map_irq(&dev->irq); 468d28abb58SWill Deacon r = ioport__register(kvm, dev->iobase, &serial8250_ops, 8, dev); 46920715a22SSasha Levin 47020715a22SSasha Levin return r; 471bc4b0ffeSPekka Enberg } 472bc4b0ffeSPekka Enberg 47320715a22SSasha Levin int serial8250__init(struct kvm *kvm) 47413a7760fSPekka Enberg { 47520715a22SSasha Levin unsigned int i, j; 47620715a22SSasha Levin int r = 0; 477c6a69c61SPekka Enberg 478c6a69c61SPekka Enberg for (i = 0; i < ARRAY_SIZE(devices); i++) { 479c6a69c61SPekka Enberg struct serial8250_device *dev = &devices[i]; 480c6a69c61SPekka Enberg 48120715a22SSasha Levin r = serial8250__device_init(kvm, dev); 48220715a22SSasha Levin if (r < 0) 48320715a22SSasha Levin goto cleanup; 484c6a69c61SPekka Enberg } 48520715a22SSasha Levin 48620715a22SSasha Levin return r; 48720715a22SSasha Levin cleanup: 48820715a22SSasha Levin for (j = 0; j <= i; j++) { 48920715a22SSasha Levin struct serial8250_device *dev = &devices[j]; 49020715a22SSasha Levin 4914346fd8fSSasha Levin ioport__unregister(kvm, dev->iobase); 492a81be31eSAndre Przywara device__unregister(&dev->dev_hdr); 49320715a22SSasha Levin } 49420715a22SSasha Levin 49520715a22SSasha Levin return r; 49620715a22SSasha Levin } 49749a8afd1SSasha Levin dev_init(serial8250__init); 49820715a22SSasha Levin 49920715a22SSasha Levin int serial8250__exit(struct kvm *kvm) 50020715a22SSasha Levin { 50120715a22SSasha Levin unsigned int i; 50220715a22SSasha Levin int r; 50320715a22SSasha Levin 50420715a22SSasha Levin for (i = 0; i < ARRAY_SIZE(devices); i++) { 50520715a22SSasha Levin struct serial8250_device *dev = &devices[i]; 50620715a22SSasha Levin 5074346fd8fSSasha Levin r = ioport__unregister(kvm, dev->iobase); 50820715a22SSasha Levin if (r < 0) 50920715a22SSasha Levin return r; 510a81be31eSAndre Przywara device__unregister(&dev->dev_hdr); 51120715a22SSasha Levin } 51220715a22SSasha Levin 51320715a22SSasha Levin return 0; 51413a7760fSPekka Enberg } 51549a8afd1SSasha Levin dev_exit(serial8250__exit); 516