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 1546aa8d69SPekka Enberg struct serial8250_device { 162932c9ebSPekka Enberg pthread_mutex_t mutex; 171add4b76SSasha Levin u8 id; 182932c9ebSPekka Enberg 193fdf659dSSasha Levin u16 iobase; 203fdf659dSSasha Levin u8 irq; 21*f6b8ccc1SThomas Gleixner u8 irq_state; 2276b4a122SPekka Enberg 233fdf659dSSasha Levin u8 rbr; /* receive buffer */ 243fdf659dSSasha Levin u8 dll; 253fdf659dSSasha Levin u8 dlm; 263fdf659dSSasha Levin u8 iir; 273fdf659dSSasha Levin u8 ier; 283fdf659dSSasha Levin u8 fcr; 293fdf659dSSasha Levin u8 lcr; 303fdf659dSSasha Levin u8 mcr; 313fdf659dSSasha Levin u8 lsr; 323fdf659dSSasha Levin u8 msr; 333fdf659dSSasha Levin u8 scr; 3446aa8d69SPekka Enberg }; 3546aa8d69SPekka Enberg 36f3efa592SLiming Wang #define SERIAL_REGS_SETTING \ 37f3efa592SLiming Wang .iir = UART_IIR_NO_INT, \ 38f3efa592SLiming Wang .lsr = UART_LSR_TEMT | UART_LSR_THRE, \ 39f3efa592SLiming Wang .msr = UART_MSR_DCD | UART_MSR_DSR | UART_MSR_CTS, \ 40f3efa592SLiming Wang .mcr = UART_MCR_OUT2, 41f3efa592SLiming Wang 42e62c18deSPekka Enberg static struct serial8250_device devices[] = { 43c6a69c61SPekka Enberg /* ttyS0 */ 44c6a69c61SPekka Enberg [0] = { 452932c9ebSPekka Enberg .mutex = PTHREAD_MUTEX_INITIALIZER, 462932c9ebSPekka Enberg 471add4b76SSasha Levin .id = 0, 48c6a69c61SPekka Enberg .iobase = 0x3f8, 49e557eef9SPekka Enberg .irq = 4, 50e557eef9SPekka Enberg 51f3efa592SLiming Wang SERIAL_REGS_SETTING 52c6a69c61SPekka Enberg }, 53e62c18deSPekka Enberg /* ttyS1 */ 54e62c18deSPekka Enberg [1] = { 552932c9ebSPekka Enberg .mutex = PTHREAD_MUTEX_INITIALIZER, 562932c9ebSPekka Enberg 571add4b76SSasha Levin .id = 1, 58e62c18deSPekka Enberg .iobase = 0x2f8, 59e62c18deSPekka Enberg .irq = 3, 60133bedc1SPekka Enberg 61f3efa592SLiming Wang SERIAL_REGS_SETTING 62e62c18deSPekka Enberg }, 63e62c18deSPekka Enberg /* ttyS2 */ 64e62c18deSPekka Enberg [2] = { 652932c9ebSPekka Enberg .mutex = PTHREAD_MUTEX_INITIALIZER, 662932c9ebSPekka Enberg 671add4b76SSasha Levin .id = 2, 68e62c18deSPekka Enberg .iobase = 0x3e8, 69e62c18deSPekka Enberg .irq = 4, 70133bedc1SPekka Enberg 71f3efa592SLiming Wang SERIAL_REGS_SETTING 72e62c18deSPekka Enberg }, 73bf459c83SPekka Enberg /* ttyS3 */ 74bf459c83SPekka Enberg [3] = { 75bf459c83SPekka Enberg .mutex = PTHREAD_MUTEX_INITIALIZER, 76bf459c83SPekka Enberg 771add4b76SSasha Levin .id = 3, 78bf459c83SPekka Enberg .iobase = 0x2e8, 79bf459c83SPekka Enberg .irq = 3, 80bf459c83SPekka Enberg 81f3efa592SLiming Wang SERIAL_REGS_SETTING 82bf459c83SPekka Enberg }, 8346aa8d69SPekka Enberg }; 8446aa8d69SPekka Enberg 85*f6b8ccc1SThomas Gleixner static void serial8250_update_irq(struct kvm *kvm, struct serial8250_device *dev) 86*f6b8ccc1SThomas Gleixner { 87*f6b8ccc1SThomas Gleixner u8 iir = 0; 88*f6b8ccc1SThomas Gleixner 89*f6b8ccc1SThomas Gleixner /* Data ready and rcv interrupt enabled ? */ 90*f6b8ccc1SThomas Gleixner if ((dev->ier & UART_IER_RDI) && (dev->lsr & UART_LSR_DR)) 91*f6b8ccc1SThomas Gleixner iir |= UART_IIR_RDI; 92*f6b8ccc1SThomas Gleixner 93*f6b8ccc1SThomas Gleixner /* Transmitter empty and interrupt enabled ? */ 94*f6b8ccc1SThomas Gleixner if ((dev->ier & UART_IER_THRI) && (dev->lsr & UART_LSR_TEMT)) 95*f6b8ccc1SThomas Gleixner iir |= UART_IIR_THRI; 96*f6b8ccc1SThomas Gleixner 97*f6b8ccc1SThomas Gleixner /* Now update the irq line, if necessary */ 98*f6b8ccc1SThomas Gleixner if (!iir) { 99*f6b8ccc1SThomas Gleixner dev->iir = UART_IIR_NO_INT; 100*f6b8ccc1SThomas Gleixner if (dev->irq_state) 101*f6b8ccc1SThomas Gleixner kvm__irq_line(kvm, dev->irq, 0); 102*f6b8ccc1SThomas Gleixner } else { 103*f6b8ccc1SThomas Gleixner dev->iir = iir; 104*f6b8ccc1SThomas Gleixner if (!dev->irq_state) 105*f6b8ccc1SThomas Gleixner kvm__irq_line(kvm, dev->irq, 1); 106*f6b8ccc1SThomas Gleixner } 107*f6b8ccc1SThomas Gleixner dev->irq_state = iir; 108*f6b8ccc1SThomas Gleixner } 109*f6b8ccc1SThomas Gleixner 110a428f72eSPekka Enberg #define SYSRQ_PENDING_NONE 0 111a428f72eSPekka Enberg #define SYSRQ_PENDING_BREAK 1 112a428f72eSPekka Enberg #define SYSRQ_PENDING_CMD 2 113a428f72eSPekka Enberg 114a428f72eSPekka Enberg static int sysrq_pending; 115a428f72eSPekka Enberg 11643835ac9SSasha Levin static void serial8250__sysrq(struct kvm *kvm, struct serial8250_device *dev) 117a428f72eSPekka Enberg { 118a428f72eSPekka Enberg switch (sysrq_pending) { 119a428f72eSPekka Enberg case SYSRQ_PENDING_BREAK: 120a428f72eSPekka Enberg dev->lsr |= UART_LSR_DR | UART_LSR_BI; 121a428f72eSPekka Enberg 122a428f72eSPekka Enberg sysrq_pending = SYSRQ_PENDING_CMD; 123a428f72eSPekka Enberg break; 124a428f72eSPekka Enberg case SYSRQ_PENDING_CMD: 125a428f72eSPekka Enberg dev->rbr = 'p'; 126a428f72eSPekka Enberg dev->lsr |= UART_LSR_DR; 127a428f72eSPekka Enberg 128a428f72eSPekka Enberg sysrq_pending = SYSRQ_PENDING_NONE; 129a428f72eSPekka Enberg break; 130a428f72eSPekka Enberg } 131a428f72eSPekka Enberg } 132a428f72eSPekka Enberg 13343835ac9SSasha Levin static void serial8250__receive(struct kvm *kvm, struct serial8250_device *dev) 134251cf9a6SPekka Enberg { 135251cf9a6SPekka Enberg int c; 136251cf9a6SPekka Enberg 137db34045cSPekka Enberg if (dev->lsr & UART_LSR_DR) 138db34045cSPekka Enberg return; 139db34045cSPekka Enberg 140a428f72eSPekka Enberg if (sysrq_pending) { 14143835ac9SSasha Levin serial8250__sysrq(kvm, dev); 142a428f72eSPekka Enberg return; 143a428f72eSPekka Enberg } 144a428f72eSPekka Enberg 1451add4b76SSasha Levin if (!term_readable(CONSOLE_8250, dev->id)) 146251cf9a6SPekka Enberg return; 147251cf9a6SPekka Enberg 1481add4b76SSasha Levin c = term_getc(CONSOLE_8250, dev->id); 14905d1a2a6SAsias He 150251cf9a6SPekka Enberg if (c < 0) 151251cf9a6SPekka Enberg return; 152251cf9a6SPekka Enberg 153251cf9a6SPekka Enberg dev->rbr = c; 154251cf9a6SPekka Enberg dev->lsr |= UART_LSR_DR; 155251cf9a6SPekka Enberg } 156251cf9a6SPekka Enberg 157*f6b8ccc1SThomas Gleixner void serial8250__update_consoles(struct kvm *kvm) 1588bb34e0dSPekka Enberg { 159479de16fSCyrill Gorcunov unsigned int i; 1601add4b76SSasha Levin 161479de16fSCyrill Gorcunov for (i = 0; i < ARRAY_SIZE(devices); i++) { 1621add4b76SSasha Levin struct serial8250_device *dev = &devices[i]; 163934c193bSPekka Enberg 1644ef0f4d6SPekka Enberg mutex_lock(&dev->mutex); 1652932c9ebSPekka Enberg 16643835ac9SSasha Levin serial8250__receive(kvm, dev); 167251cf9a6SPekka Enberg 168*f6b8ccc1SThomas Gleixner serial8250_update_irq(kvm, dev); 1692932c9ebSPekka Enberg 1704ef0f4d6SPekka Enberg mutex_unlock(&dev->mutex); 1718bb34e0dSPekka Enberg } 1721add4b76SSasha Levin } 1738bb34e0dSPekka Enberg 17443835ac9SSasha Levin void serial8250__inject_sysrq(struct kvm *kvm) 175a428f72eSPekka Enberg { 176a428f72eSPekka Enberg sysrq_pending = SYSRQ_PENDING_BREAK; 177a428f72eSPekka Enberg } 178a428f72eSPekka Enberg 1793fdf659dSSasha Levin static struct serial8250_device *find_device(u16 port) 180c6a69c61SPekka Enberg { 181c6a69c61SPekka Enberg unsigned int i; 182c6a69c61SPekka Enberg 183c6a69c61SPekka Enberg for (i = 0; i < ARRAY_SIZE(devices); i++) { 184c6a69c61SPekka Enberg struct serial8250_device *dev = &devices[i]; 185c6a69c61SPekka Enberg 186c6a69c61SPekka Enberg if (dev->iobase == (port & ~0x7)) 187c6a69c61SPekka Enberg return dev; 188c6a69c61SPekka Enberg } 189c6a69c61SPekka Enberg return NULL; 190c6a69c61SPekka Enberg } 191c6a69c61SPekka Enberg 192c9f6a037SXiao Guangrong static bool serial8250_out(struct ioport *ioport, struct kvm *kvm, u16 port, void *data, int size) 19313a7760fSPekka Enberg { 194c6a69c61SPekka Enberg struct serial8250_device *dev; 1953fdf659dSSasha Levin u16 offset; 1962932c9ebSPekka Enberg bool ret = true; 19746aa8d69SPekka Enberg 198c6a69c61SPekka Enberg dev = find_device(port); 199c6a69c61SPekka Enberg if (!dev) 200c6a69c61SPekka Enberg return false; 201c6a69c61SPekka Enberg 2024ef0f4d6SPekka Enberg mutex_lock(&dev->mutex); 2032932c9ebSPekka Enberg 204c6a69c61SPekka Enberg offset = port - dev->iobase; 205c6a69c61SPekka Enberg 20646aa8d69SPekka Enberg switch (offset) { 207c59fa0c4SThomas Gleixner case UART_TX: 208c59fa0c4SThomas Gleixner if (!(dev->lcr & UART_LCR_DLAB)) { 20905d1a2a6SAsias He char *addr = data; 2100ea58e5bSPekka Enberg 2110ea58e5bSPekka Enberg if (!(dev->mcr & UART_MCR_LOOP)) 2121add4b76SSasha Levin term_putc(CONSOLE_8250, addr, size, dev->id); 213*f6b8ccc1SThomas Gleixner /* else FIXME: Inject data into rcv path for LOOP */ 2140ea58e5bSPekka Enberg 215*f6b8ccc1SThomas Gleixner /* 216*f6b8ccc1SThomas Gleixner * Set transmitter and transmit hold register 217*f6b8ccc1SThomas Gleixner * empty. We have no FIFO at the moment and 218*f6b8ccc1SThomas Gleixner * on the TX side it's only interesting, when 219*f6b8ccc1SThomas Gleixner * we could coalesce port io on the kernel 220*f6b8ccc1SThomas Gleixner * kernel. 221*f6b8ccc1SThomas Gleixner */ 222*f6b8ccc1SThomas Gleixner dev->lsr |= UART_LSR_TEMT | UART_LSR_THRE; 223*f6b8ccc1SThomas Gleixner break; 224c59fa0c4SThomas Gleixner } else { 225c59fa0c4SThomas Gleixner dev->dll = ioport__read8(data); 22646aa8d69SPekka Enberg } 227369c01c0SPekka Enberg break; 2284e49b05bSCyrill Gorcunov case UART_IER: 229*f6b8ccc1SThomas Gleixner if (!(dev->lcr & UART_LCR_DLAB)) 230369c01c0SPekka Enberg dev->ier = ioport__read8(data) & 0x3f; 231*f6b8ccc1SThomas Gleixner else 232c59fa0c4SThomas Gleixner dev->dlm = ioport__read8(data); 233c59fa0c4SThomas Gleixner break; 234c59fa0c4SThomas Gleixner case UART_FCR: 235c59fa0c4SThomas Gleixner dev->fcr = ioport__read8(data); 23646aa8d69SPekka Enberg break; 237369c01c0SPekka Enberg case UART_LCR: 238369c01c0SPekka Enberg dev->lcr = ioport__read8(data); 239369c01c0SPekka Enberg break; 240369c01c0SPekka Enberg case UART_MCR: 241369c01c0SPekka Enberg dev->mcr = ioport__read8(data); 242369c01c0SPekka Enberg break; 243369c01c0SPekka Enberg case UART_LSR: 244369c01c0SPekka Enberg /* Factory test */ 245369c01c0SPekka Enberg break; 246369c01c0SPekka Enberg case UART_MSR: 247369c01c0SPekka Enberg /* Not used */ 248369c01c0SPekka Enberg break; 249369c01c0SPekka Enberg case UART_SCR: 250369c01c0SPekka Enberg dev->scr = ioport__read8(data); 251369c01c0SPekka Enberg break; 252369c01c0SPekka Enberg default: 2532932c9ebSPekka Enberg ret = false; 254d2ea115dSThomas Gleixner break; 25546aa8d69SPekka Enberg } 2562932c9ebSPekka Enberg 257*f6b8ccc1SThomas Gleixner serial8250_update_irq(kvm, dev); 258*f6b8ccc1SThomas Gleixner 2594ef0f4d6SPekka Enberg mutex_unlock(&dev->mutex); 2602932c9ebSPekka Enberg 2612932c9ebSPekka Enberg return ret; 26213a7760fSPekka Enberg } 26313a7760fSPekka Enberg 264c9f6a037SXiao Guangrong static bool serial8250_in(struct ioport *ioport, struct kvm *kvm, u16 port, void *data, int size) 26525af6674SPekka Enberg { 266c6a69c61SPekka Enberg struct serial8250_device *dev; 2673fdf659dSSasha Levin u16 offset; 2682932c9ebSPekka Enberg bool ret = true; 26946aa8d69SPekka Enberg 270c6a69c61SPekka Enberg dev = find_device(port); 271c6a69c61SPekka Enberg if (!dev) 272c6a69c61SPekka Enberg return false; 273c6a69c61SPekka Enberg 2744ef0f4d6SPekka Enberg mutex_lock(&dev->mutex); 2752932c9ebSPekka Enberg 276c6a69c61SPekka Enberg offset = port - dev->iobase; 277c6a69c61SPekka Enberg 27846aa8d69SPekka Enberg switch (offset) { 279251cf9a6SPekka Enberg case UART_RX: 280c59fa0c4SThomas Gleixner if (dev->lcr & UART_LCR_DLAB) { 281c59fa0c4SThomas Gleixner ioport__write8(data, dev->dll); 282c59fa0c4SThomas Gleixner } else { 283251cf9a6SPekka Enberg ioport__write8(data, dev->rbr); 284369c01c0SPekka Enberg dev->lsr &= ~UART_LSR_DR; 285c59fa0c4SThomas Gleixner } 286369c01c0SPekka Enberg break; 287c59fa0c4SThomas Gleixner case UART_IER: 288c59fa0c4SThomas Gleixner if (dev->lcr & UART_LCR_DLAB) 289c59fa0c4SThomas Gleixner ioport__write8(data, dev->dlm); 290c59fa0c4SThomas Gleixner else 291c59fa0c4SThomas Gleixner ioport__write8(data, dev->ier); 292c59fa0c4SThomas Gleixner break; 293*f6b8ccc1SThomas Gleixner case UART_IIR: 294*f6b8ccc1SThomas Gleixner ioport__write8(data, dev->iir); 29546aa8d69SPekka Enberg break; 2964e49b05bSCyrill Gorcunov case UART_LCR: 297c6a69c61SPekka Enberg ioport__write8(data, dev->lcr); 29846aa8d69SPekka Enberg break; 2994e49b05bSCyrill Gorcunov case UART_MCR: 300c6a69c61SPekka Enberg ioport__write8(data, dev->mcr); 30146aa8d69SPekka Enberg break; 3024e49b05bSCyrill Gorcunov case UART_LSR: 303c6a69c61SPekka Enberg ioport__write8(data, dev->lsr); 30446aa8d69SPekka Enberg break; 3054e49b05bSCyrill Gorcunov case UART_MSR: 306369c01c0SPekka Enberg ioport__write8(data, dev->msr); 30746aa8d69SPekka Enberg break; 3084e49b05bSCyrill Gorcunov case UART_SCR: 309369c01c0SPekka Enberg ioport__write8(data, dev->scr); 31046aa8d69SPekka Enberg break; 311369c01c0SPekka Enberg default: 3122932c9ebSPekka Enberg ret = false; 313c59fa0c4SThomas Gleixner break; 31425af6674SPekka Enberg } 315*f6b8ccc1SThomas Gleixner 316*f6b8ccc1SThomas Gleixner serial8250_update_irq(kvm, dev); 317*f6b8ccc1SThomas Gleixner 3184ef0f4d6SPekka Enberg mutex_unlock(&dev->mutex); 3192932c9ebSPekka Enberg 3202932c9ebSPekka Enberg return ret; 32113a7760fSPekka Enberg } 32213a7760fSPekka Enberg 32346aa8d69SPekka Enberg static struct ioport_operations serial8250_ops = { 32446aa8d69SPekka Enberg .io_in = serial8250_in, 32546aa8d69SPekka Enberg .io_out = serial8250_out, 326a93ec68bSPekka Enberg }; 327a93ec68bSPekka Enberg 328bc4b0ffeSPekka Enberg static void serial8250__device_init(struct kvm *kvm, struct serial8250_device *dev) 329bc4b0ffeSPekka Enberg { 3303d62dea6SSasha Levin ioport__register(dev->iobase, &serial8250_ops, 8, NULL); 331bc4b0ffeSPekka Enberg kvm__irq_line(kvm, dev->irq, 0); 332bc4b0ffeSPekka Enberg } 333bc4b0ffeSPekka Enberg 334bc4b0ffeSPekka Enberg void serial8250__init(struct kvm *kvm) 33513a7760fSPekka Enberg { 336c6a69c61SPekka Enberg unsigned int i; 337c6a69c61SPekka Enberg 338c6a69c61SPekka Enberg for (i = 0; i < ARRAY_SIZE(devices); i++) { 339c6a69c61SPekka Enberg struct serial8250_device *dev = &devices[i]; 340c6a69c61SPekka Enberg 341bc4b0ffeSPekka Enberg serial8250__device_init(kvm, dev); 342c6a69c61SPekka Enberg } 34313a7760fSPekka Enberg } 344