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" 913a7760fSPekka Enberg 103fdf659dSSasha Levin #include <linux/types.h> 114e49b05bSCyrill Gorcunov #include <linux/serial_reg.h> 124e49b05bSCyrill Gorcunov 132932c9ebSPekka Enberg #include <pthread.h> 1413a7760fSPekka Enberg 15d4b02a37SThomas Gleixner /* 16d4b02a37SThomas Gleixner * This fakes a U6_16550A. The fifo len needs to be 64 as the kernel 17d4b02a37SThomas Gleixner * expects that for autodetection. 18d4b02a37SThomas Gleixner */ 19d4b02a37SThomas Gleixner #define FIFO_LEN 64 20d4b02a37SThomas Gleixner #define FIFO_MASK (FIFO_LEN - 1) 21d4b02a37SThomas Gleixner 22d4b02a37SThomas Gleixner #define UART_IIR_TYPE_BITS 0xc0 23d4b02a37SThomas Gleixner 2446aa8d69SPekka Enberg struct serial8250_device { 25d3476f7dSSasha Levin struct mutex mutex; 261add4b76SSasha Levin u8 id; 272932c9ebSPekka Enberg 283fdf659dSSasha Levin u16 iobase; 293fdf659dSSasha Levin u8 irq; 30f6b8ccc1SThomas Gleixner u8 irq_state; 318dfae8beSThomas Gleixner int txcnt; 32d4b02a37SThomas Gleixner int rxcnt; 33d4b02a37SThomas Gleixner int rxdone; 34d4b02a37SThomas Gleixner char txbuf[FIFO_LEN]; 35d4b02a37SThomas Gleixner char rxbuf[FIFO_LEN]; 3676b4a122SPekka Enberg 373fdf659dSSasha Levin u8 dll; 383fdf659dSSasha Levin u8 dlm; 393fdf659dSSasha Levin u8 iir; 403fdf659dSSasha Levin u8 ier; 413fdf659dSSasha Levin u8 fcr; 423fdf659dSSasha Levin u8 lcr; 433fdf659dSSasha Levin u8 mcr; 443fdf659dSSasha Levin u8 lsr; 453fdf659dSSasha Levin u8 msr; 463fdf659dSSasha Levin u8 scr; 4746aa8d69SPekka Enberg }; 4846aa8d69SPekka Enberg 49f3efa592SLiming Wang #define SERIAL_REGS_SETTING \ 50f3efa592SLiming Wang .iir = UART_IIR_NO_INT, \ 51f3efa592SLiming Wang .lsr = UART_LSR_TEMT | UART_LSR_THRE, \ 52f3efa592SLiming Wang .msr = UART_MSR_DCD | UART_MSR_DSR | UART_MSR_CTS, \ 53f3efa592SLiming Wang .mcr = UART_MCR_OUT2, 54f3efa592SLiming Wang 55e62c18deSPekka Enberg static struct serial8250_device devices[] = { 56c6a69c61SPekka Enberg /* ttyS0 */ 57c6a69c61SPekka Enberg [0] = { 58d3476f7dSSasha Levin .mutex = MUTEX_INITIALIZER, 592932c9ebSPekka Enberg 601add4b76SSasha Levin .id = 0, 61c6a69c61SPekka Enberg .iobase = 0x3f8, 62e557eef9SPekka Enberg .irq = 4, 63e557eef9SPekka Enberg 64f3efa592SLiming Wang SERIAL_REGS_SETTING 65c6a69c61SPekka Enberg }, 66e62c18deSPekka Enberg /* ttyS1 */ 67e62c18deSPekka Enberg [1] = { 68d3476f7dSSasha Levin .mutex = MUTEX_INITIALIZER, 692932c9ebSPekka Enberg 701add4b76SSasha Levin .id = 1, 71e62c18deSPekka Enberg .iobase = 0x2f8, 72e62c18deSPekka Enberg .irq = 3, 73133bedc1SPekka Enberg 74f3efa592SLiming Wang SERIAL_REGS_SETTING 75e62c18deSPekka Enberg }, 76e62c18deSPekka Enberg /* ttyS2 */ 77e62c18deSPekka Enberg [2] = { 78d3476f7dSSasha Levin .mutex = MUTEX_INITIALIZER, 792932c9ebSPekka Enberg 801add4b76SSasha Levin .id = 2, 81e62c18deSPekka Enberg .iobase = 0x3e8, 82e62c18deSPekka Enberg .irq = 4, 83133bedc1SPekka Enberg 84f3efa592SLiming Wang SERIAL_REGS_SETTING 85e62c18deSPekka Enberg }, 86bf459c83SPekka Enberg /* ttyS3 */ 87bf459c83SPekka Enberg [3] = { 88d3476f7dSSasha Levin .mutex = MUTEX_INITIALIZER, 89bf459c83SPekka Enberg 901add4b76SSasha Levin .id = 3, 91bf459c83SPekka Enberg .iobase = 0x2e8, 92bf459c83SPekka Enberg .irq = 3, 93bf459c83SPekka Enberg 94f3efa592SLiming Wang SERIAL_REGS_SETTING 95bf459c83SPekka Enberg }, 9646aa8d69SPekka Enberg }; 9746aa8d69SPekka Enberg 982651ea58SSasha Levin static void serial8250_flush_tx(struct kvm *kvm, struct serial8250_device *dev) 99d4b02a37SThomas Gleixner { 100d4b02a37SThomas Gleixner dev->lsr |= UART_LSR_TEMT | UART_LSR_THRE; 101d4b02a37SThomas Gleixner 102d4b02a37SThomas Gleixner if (dev->txcnt) { 1032651ea58SSasha Levin term_putc(dev->txbuf, dev->txcnt, dev->id); 104d4b02a37SThomas Gleixner dev->txcnt = 0; 105d4b02a37SThomas Gleixner } 106d4b02a37SThomas Gleixner } 107d4b02a37SThomas Gleixner 108f6b8ccc1SThomas Gleixner static void serial8250_update_irq(struct kvm *kvm, struct serial8250_device *dev) 109f6b8ccc1SThomas Gleixner { 110f6b8ccc1SThomas Gleixner u8 iir = 0; 111f6b8ccc1SThomas Gleixner 112d4b02a37SThomas Gleixner /* Handle clear rx */ 113d4b02a37SThomas Gleixner if (dev->lcr & UART_FCR_CLEAR_RCVR) { 114d4b02a37SThomas Gleixner dev->lcr &= ~UART_FCR_CLEAR_RCVR; 115d4b02a37SThomas Gleixner dev->rxcnt = dev->rxdone = 0; 116d4b02a37SThomas Gleixner dev->lsr &= ~UART_LSR_DR; 117d4b02a37SThomas Gleixner } 118d4b02a37SThomas Gleixner 119d4b02a37SThomas Gleixner /* Handle clear tx */ 120d4b02a37SThomas Gleixner if (dev->lcr & UART_FCR_CLEAR_XMIT) { 121d4b02a37SThomas Gleixner dev->lcr &= ~UART_FCR_CLEAR_XMIT; 122d4b02a37SThomas Gleixner dev->txcnt = 0; 123d4b02a37SThomas Gleixner dev->lsr |= UART_LSR_TEMT | UART_LSR_THRE; 124d4b02a37SThomas Gleixner } 125d4b02a37SThomas Gleixner 126f6b8ccc1SThomas Gleixner /* Data ready and rcv interrupt enabled ? */ 127f6b8ccc1SThomas Gleixner if ((dev->ier & UART_IER_RDI) && (dev->lsr & UART_LSR_DR)) 128f6b8ccc1SThomas Gleixner iir |= UART_IIR_RDI; 129f6b8ccc1SThomas Gleixner 130f6b8ccc1SThomas Gleixner /* Transmitter empty and interrupt enabled ? */ 131f6b8ccc1SThomas Gleixner if ((dev->ier & UART_IER_THRI) && (dev->lsr & UART_LSR_TEMT)) 132f6b8ccc1SThomas Gleixner iir |= UART_IIR_THRI; 133f6b8ccc1SThomas Gleixner 134f6b8ccc1SThomas Gleixner /* Now update the irq line, if necessary */ 135f6b8ccc1SThomas Gleixner if (!iir) { 136f6b8ccc1SThomas Gleixner dev->iir = UART_IIR_NO_INT; 137f6b8ccc1SThomas Gleixner if (dev->irq_state) 138f6b8ccc1SThomas Gleixner kvm__irq_line(kvm, dev->irq, 0); 139f6b8ccc1SThomas Gleixner } else { 140f6b8ccc1SThomas Gleixner dev->iir = iir; 141f6b8ccc1SThomas Gleixner if (!dev->irq_state) 142f6b8ccc1SThomas Gleixner kvm__irq_line(kvm, dev->irq, 1); 143f6b8ccc1SThomas Gleixner } 144f6b8ccc1SThomas Gleixner dev->irq_state = iir; 1458dfae8beSThomas Gleixner 1468dfae8beSThomas Gleixner /* 1478dfae8beSThomas Gleixner * If the kernel disabled the tx interrupt, we know that there 1488dfae8beSThomas Gleixner * is nothing more to transmit, so we can reset our tx logic 1498dfae8beSThomas Gleixner * here. 1508dfae8beSThomas Gleixner */ 151d4b02a37SThomas Gleixner if (!(dev->ier & UART_IER_THRI)) 1522651ea58SSasha Levin serial8250_flush_tx(kvm, dev); 153f6b8ccc1SThomas Gleixner } 154f6b8ccc1SThomas Gleixner 155a428f72eSPekka Enberg #define SYSRQ_PENDING_NONE 0 156a428f72eSPekka Enberg 157a428f72eSPekka Enberg static int sysrq_pending; 158a428f72eSPekka Enberg 15943835ac9SSasha Levin static void serial8250__sysrq(struct kvm *kvm, struct serial8250_device *dev) 160a428f72eSPekka Enberg { 161a428f72eSPekka Enberg dev->lsr |= UART_LSR_DR | UART_LSR_BI; 162226e727bSSasha Levin dev->rxbuf[dev->rxcnt++] = sysrq_pending; 163a428f72eSPekka Enberg sysrq_pending = SYSRQ_PENDING_NONE; 164a428f72eSPekka Enberg } 165a428f72eSPekka Enberg 166d4b02a37SThomas Gleixner static void serial8250__receive(struct kvm *kvm, struct serial8250_device *dev, 167d4b02a37SThomas Gleixner bool handle_sysrq) 168251cf9a6SPekka Enberg { 169251cf9a6SPekka Enberg int c; 170251cf9a6SPekka Enberg 1718dfae8beSThomas Gleixner /* 172d4b02a37SThomas Gleixner * If the guest transmitted a full fifo, we clear the 1738dfae8beSThomas Gleixner * TEMT/THRE bits to let the kernel escape from the 8250 1748dfae8beSThomas Gleixner * interrupt handler. We come here only once a ms, so that 175d4b02a37SThomas Gleixner * should give the kernel the desired pause. That also flushes 176d4b02a37SThomas Gleixner * the tx fifo to the terminal. 1778dfae8beSThomas Gleixner */ 1782651ea58SSasha Levin serial8250_flush_tx(kvm, dev); 1798dfae8beSThomas Gleixner 180d4b02a37SThomas Gleixner if (dev->mcr & UART_MCR_LOOP) 181db34045cSPekka Enberg return; 182db34045cSPekka Enberg 183d4b02a37SThomas Gleixner if ((dev->lsr & UART_LSR_DR) || dev->rxcnt) 184d4b02a37SThomas Gleixner return; 185d4b02a37SThomas Gleixner 186d4b02a37SThomas Gleixner if (handle_sysrq && sysrq_pending) { 18743835ac9SSasha Levin serial8250__sysrq(kvm, dev); 188a428f72eSPekka Enberg return; 189a428f72eSPekka Enberg } 190a428f72eSPekka Enberg 1912651ea58SSasha Levin if (kvm->cfg.active_console != CONSOLE_8250) 1922651ea58SSasha Levin return; 1932651ea58SSasha Levin 1942651ea58SSasha Levin while (term_readable(dev->id) && 195d4b02a37SThomas Gleixner dev->rxcnt < FIFO_LEN) { 196251cf9a6SPekka Enberg 1974346fd8fSSasha Levin c = term_getc(kvm, dev->id); 19805d1a2a6SAsias He 199251cf9a6SPekka Enberg if (c < 0) 200d4b02a37SThomas Gleixner break; 201d4b02a37SThomas Gleixner dev->rxbuf[dev->rxcnt++] = c; 202251cf9a6SPekka Enberg dev->lsr |= UART_LSR_DR; 203251cf9a6SPekka Enberg } 204d4b02a37SThomas Gleixner } 205251cf9a6SPekka Enberg 206f6b8ccc1SThomas Gleixner void serial8250__update_consoles(struct kvm *kvm) 2078bb34e0dSPekka Enberg { 208479de16fSCyrill Gorcunov unsigned int i; 2091add4b76SSasha Levin 210479de16fSCyrill Gorcunov for (i = 0; i < ARRAY_SIZE(devices); i++) { 2111add4b76SSasha Levin struct serial8250_device *dev = &devices[i]; 212934c193bSPekka Enberg 2134ef0f4d6SPekka Enberg mutex_lock(&dev->mutex); 2142932c9ebSPekka Enberg 215d4b02a37SThomas Gleixner /* Restrict sysrq injection to the first port */ 216d4b02a37SThomas Gleixner serial8250__receive(kvm, dev, i == 0); 217251cf9a6SPekka Enberg 218f6b8ccc1SThomas Gleixner serial8250_update_irq(kvm, dev); 2192932c9ebSPekka Enberg 2204ef0f4d6SPekka Enberg mutex_unlock(&dev->mutex); 2218bb34e0dSPekka Enberg } 2221add4b76SSasha Levin } 2238bb34e0dSPekka Enberg 224226e727bSSasha Levin void serial8250__inject_sysrq(struct kvm *kvm, char sysrq) 225a428f72eSPekka Enberg { 226226e727bSSasha Levin sysrq_pending = sysrq; 227a428f72eSPekka Enberg } 228a428f72eSPekka Enberg 2293fdf659dSSasha Levin static struct serial8250_device *find_device(u16 port) 230c6a69c61SPekka Enberg { 231c6a69c61SPekka Enberg unsigned int i; 232c6a69c61SPekka Enberg 233c6a69c61SPekka Enberg for (i = 0; i < ARRAY_SIZE(devices); i++) { 234c6a69c61SPekka Enberg struct serial8250_device *dev = &devices[i]; 235c6a69c61SPekka Enberg 236c6a69c61SPekka Enberg if (dev->iobase == (port & ~0x7)) 237c6a69c61SPekka Enberg return dev; 238c6a69c61SPekka Enberg } 239c6a69c61SPekka Enberg return NULL; 240c6a69c61SPekka Enberg } 241c6a69c61SPekka Enberg 242d4b02a37SThomas Gleixner static bool serial8250_out(struct ioport *ioport, struct kvm *kvm, u16 port, 243d4b02a37SThomas Gleixner void *data, int size) 24413a7760fSPekka Enberg { 245c6a69c61SPekka Enberg struct serial8250_device *dev; 2463fdf659dSSasha Levin u16 offset; 2472932c9ebSPekka Enberg bool ret = true; 248d4b02a37SThomas Gleixner char *addr = data; 24946aa8d69SPekka Enberg 250c6a69c61SPekka Enberg dev = find_device(port); 251c6a69c61SPekka Enberg if (!dev) 252c6a69c61SPekka Enberg return false; 253c6a69c61SPekka Enberg 2544ef0f4d6SPekka Enberg mutex_lock(&dev->mutex); 2552932c9ebSPekka Enberg 256c6a69c61SPekka Enberg offset = port - dev->iobase; 257c6a69c61SPekka Enberg 25846aa8d69SPekka Enberg switch (offset) { 259c59fa0c4SThomas Gleixner case UART_TX: 260d4b02a37SThomas Gleixner if (dev->lcr & UART_LCR_DLAB) { 261c59fa0c4SThomas Gleixner dev->dll = ioport__read8(data); 262d4b02a37SThomas Gleixner break; 263d4b02a37SThomas Gleixner } 264d4b02a37SThomas Gleixner 265d4b02a37SThomas Gleixner /* Loopback mode */ 266d4b02a37SThomas Gleixner if (dev->mcr & UART_MCR_LOOP) { 267d4b02a37SThomas Gleixner if (dev->rxcnt < FIFO_LEN) { 268d4b02a37SThomas Gleixner dev->rxbuf[dev->rxcnt++] = *addr; 269d4b02a37SThomas Gleixner dev->lsr |= UART_LSR_DR; 270d4b02a37SThomas Gleixner } 271d4b02a37SThomas Gleixner break; 272d4b02a37SThomas Gleixner } 273d4b02a37SThomas Gleixner 274d4b02a37SThomas Gleixner if (dev->txcnt < FIFO_LEN) { 275d4b02a37SThomas Gleixner dev->txbuf[dev->txcnt++] = *addr; 276d4b02a37SThomas Gleixner dev->lsr &= ~UART_LSR_TEMT; 277d4b02a37SThomas Gleixner if (dev->txcnt == FIFO_LEN / 2) 278d4b02a37SThomas Gleixner dev->lsr &= ~UART_LSR_THRE; 279d4b02a37SThomas Gleixner } else { 280d4b02a37SThomas Gleixner /* Should never happpen */ 281d4b02a37SThomas Gleixner dev->lsr &= ~(UART_LSR_TEMT | UART_LSR_THRE); 28246aa8d69SPekka Enberg } 283369c01c0SPekka Enberg break; 2844e49b05bSCyrill Gorcunov case UART_IER: 285f6b8ccc1SThomas Gleixner if (!(dev->lcr & UART_LCR_DLAB)) 286d4b02a37SThomas Gleixner dev->ier = ioport__read8(data) & 0x0f; 287f6b8ccc1SThomas Gleixner else 288c59fa0c4SThomas Gleixner dev->dlm = ioport__read8(data); 289c59fa0c4SThomas Gleixner break; 290c59fa0c4SThomas Gleixner case UART_FCR: 291c59fa0c4SThomas Gleixner dev->fcr = ioport__read8(data); 29246aa8d69SPekka Enberg break; 293369c01c0SPekka Enberg case UART_LCR: 294369c01c0SPekka Enberg dev->lcr = ioport__read8(data); 295369c01c0SPekka Enberg break; 296369c01c0SPekka Enberg case UART_MCR: 297369c01c0SPekka Enberg dev->mcr = ioport__read8(data); 298369c01c0SPekka Enberg break; 299369c01c0SPekka Enberg case UART_LSR: 300369c01c0SPekka Enberg /* Factory test */ 301369c01c0SPekka Enberg break; 302369c01c0SPekka Enberg case UART_MSR: 303369c01c0SPekka Enberg /* Not used */ 304369c01c0SPekka Enberg break; 305369c01c0SPekka Enberg case UART_SCR: 306369c01c0SPekka Enberg dev->scr = ioport__read8(data); 307369c01c0SPekka Enberg break; 308369c01c0SPekka Enberg default: 3092932c9ebSPekka Enberg ret = false; 310d2ea115dSThomas Gleixner break; 31146aa8d69SPekka Enberg } 3122932c9ebSPekka Enberg 313f6b8ccc1SThomas Gleixner serial8250_update_irq(kvm, dev); 314f6b8ccc1SThomas Gleixner 3154ef0f4d6SPekka Enberg mutex_unlock(&dev->mutex); 3162932c9ebSPekka Enberg 3172932c9ebSPekka Enberg return ret; 31813a7760fSPekka Enberg } 31913a7760fSPekka Enberg 320d4b02a37SThomas Gleixner static void serial8250_rx(struct serial8250_device *dev, void *data) 321d4b02a37SThomas Gleixner { 322d4b02a37SThomas Gleixner if (dev->rxdone == dev->rxcnt) 323d4b02a37SThomas Gleixner return; 324d4b02a37SThomas Gleixner 325d4b02a37SThomas Gleixner /* Break issued ? */ 326d4b02a37SThomas Gleixner if (dev->lsr & UART_LSR_BI) { 327d4b02a37SThomas Gleixner dev->lsr &= ~UART_LSR_BI; 328d4b02a37SThomas Gleixner ioport__write8(data, 0); 329d4b02a37SThomas Gleixner return; 330d4b02a37SThomas Gleixner } 331d4b02a37SThomas Gleixner 332d4b02a37SThomas Gleixner ioport__write8(data, dev->rxbuf[dev->rxdone++]); 333d4b02a37SThomas Gleixner if (dev->rxcnt == dev->rxdone) { 334d4b02a37SThomas Gleixner dev->lsr &= ~UART_LSR_DR; 335d4b02a37SThomas Gleixner dev->rxcnt = dev->rxdone = 0; 336d4b02a37SThomas Gleixner } 337d4b02a37SThomas Gleixner } 338d4b02a37SThomas Gleixner 339c9f6a037SXiao Guangrong static bool serial8250_in(struct ioport *ioport, struct kvm *kvm, u16 port, void *data, int size) 34025af6674SPekka Enberg { 341c6a69c61SPekka Enberg struct serial8250_device *dev; 3423fdf659dSSasha Levin u16 offset; 3432932c9ebSPekka Enberg bool ret = true; 34446aa8d69SPekka Enberg 345c6a69c61SPekka Enberg dev = find_device(port); 346c6a69c61SPekka Enberg if (!dev) 347c6a69c61SPekka Enberg return false; 348c6a69c61SPekka Enberg 3494ef0f4d6SPekka Enberg mutex_lock(&dev->mutex); 3502932c9ebSPekka Enberg 351c6a69c61SPekka Enberg offset = port - dev->iobase; 352c6a69c61SPekka Enberg 35346aa8d69SPekka Enberg switch (offset) { 354251cf9a6SPekka Enberg case UART_RX: 355d4b02a37SThomas Gleixner if (dev->lcr & UART_LCR_DLAB) 356c59fa0c4SThomas Gleixner ioport__write8(data, dev->dll); 357d4b02a37SThomas Gleixner else 358d4b02a37SThomas Gleixner serial8250_rx(dev, data); 359369c01c0SPekka Enberg break; 360c59fa0c4SThomas Gleixner case UART_IER: 361c59fa0c4SThomas Gleixner if (dev->lcr & UART_LCR_DLAB) 362c59fa0c4SThomas Gleixner ioport__write8(data, dev->dlm); 363c59fa0c4SThomas Gleixner else 364c59fa0c4SThomas Gleixner ioport__write8(data, dev->ier); 365c59fa0c4SThomas Gleixner break; 366f6b8ccc1SThomas Gleixner case UART_IIR: 367d4b02a37SThomas Gleixner ioport__write8(data, dev->iir | UART_IIR_TYPE_BITS); 36846aa8d69SPekka Enberg break; 3694e49b05bSCyrill Gorcunov case UART_LCR: 370c6a69c61SPekka Enberg ioport__write8(data, dev->lcr); 37146aa8d69SPekka Enberg break; 3724e49b05bSCyrill Gorcunov case UART_MCR: 373c6a69c61SPekka Enberg ioport__write8(data, dev->mcr); 37446aa8d69SPekka Enberg break; 3754e49b05bSCyrill Gorcunov case UART_LSR: 376c6a69c61SPekka Enberg ioport__write8(data, dev->lsr); 37746aa8d69SPekka Enberg break; 3784e49b05bSCyrill Gorcunov case UART_MSR: 379369c01c0SPekka Enberg ioport__write8(data, dev->msr); 38046aa8d69SPekka Enberg break; 3814e49b05bSCyrill Gorcunov case UART_SCR: 382369c01c0SPekka Enberg ioport__write8(data, dev->scr); 38346aa8d69SPekka Enberg break; 384369c01c0SPekka Enberg default: 3852932c9ebSPekka Enberg ret = false; 386c59fa0c4SThomas Gleixner break; 38725af6674SPekka Enberg } 388f6b8ccc1SThomas Gleixner 389f6b8ccc1SThomas Gleixner serial8250_update_irq(kvm, dev); 390f6b8ccc1SThomas Gleixner 3914ef0f4d6SPekka Enberg mutex_unlock(&dev->mutex); 3922932c9ebSPekka Enberg 3932932c9ebSPekka Enberg return ret; 39413a7760fSPekka Enberg } 39513a7760fSPekka Enberg 39646aa8d69SPekka Enberg static struct ioport_operations serial8250_ops = { 39746aa8d69SPekka Enberg .io_in = serial8250_in, 39846aa8d69SPekka Enberg .io_out = serial8250_out, 399a93ec68bSPekka Enberg }; 400a93ec68bSPekka Enberg 40120715a22SSasha Levin static int serial8250__device_init(struct kvm *kvm, struct serial8250_device *dev) 402bc4b0ffeSPekka Enberg { 40320715a22SSasha Levin int r; 40420715a22SSasha Levin 405*206c41f4SWill Deacon ioport__map_irq(&dev->irq); 4064346fd8fSSasha Levin r = ioport__register(kvm, dev->iobase, &serial8250_ops, 8, NULL); 407bc4b0ffeSPekka Enberg kvm__irq_line(kvm, dev->irq, 0); 40820715a22SSasha Levin 40920715a22SSasha Levin return r; 410bc4b0ffeSPekka Enberg } 411bc4b0ffeSPekka Enberg 41220715a22SSasha Levin int serial8250__init(struct kvm *kvm) 41313a7760fSPekka Enberg { 41420715a22SSasha Levin unsigned int i, j; 41520715a22SSasha Levin int r = 0; 416c6a69c61SPekka Enberg 417c6a69c61SPekka Enberg for (i = 0; i < ARRAY_SIZE(devices); i++) { 418c6a69c61SPekka Enberg struct serial8250_device *dev = &devices[i]; 419c6a69c61SPekka Enberg 42020715a22SSasha Levin r = serial8250__device_init(kvm, dev); 42120715a22SSasha Levin if (r < 0) 42220715a22SSasha Levin goto cleanup; 423c6a69c61SPekka Enberg } 42420715a22SSasha Levin 42520715a22SSasha Levin return r; 42620715a22SSasha Levin cleanup: 42720715a22SSasha Levin for (j = 0; j <= i; j++) { 42820715a22SSasha Levin struct serial8250_device *dev = &devices[j]; 42920715a22SSasha Levin 4304346fd8fSSasha Levin ioport__unregister(kvm, dev->iobase); 43120715a22SSasha Levin } 43220715a22SSasha Levin 43320715a22SSasha Levin return r; 43420715a22SSasha Levin } 43549a8afd1SSasha Levin dev_init(serial8250__init); 43620715a22SSasha Levin 43720715a22SSasha Levin int serial8250__exit(struct kvm *kvm) 43820715a22SSasha Levin { 43920715a22SSasha Levin unsigned int i; 44020715a22SSasha Levin int r; 44120715a22SSasha Levin 44220715a22SSasha Levin for (i = 0; i < ARRAY_SIZE(devices); i++) { 44320715a22SSasha Levin struct serial8250_device *dev = &devices[i]; 44420715a22SSasha Levin 4454346fd8fSSasha Levin r = ioport__unregister(kvm, dev->iobase); 44620715a22SSasha Levin if (r < 0) 44720715a22SSasha Levin return r; 44820715a22SSasha Levin } 44920715a22SSasha Levin 45020715a22SSasha Levin return 0; 45113a7760fSPekka Enberg } 45249a8afd1SSasha Levin dev_exit(serial8250__exit); 453