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; 2176b4a122SPekka Enberg 223fdf659dSSasha Levin u8 rbr; /* receive buffer */ 233fdf659dSSasha Levin u8 dll; 243fdf659dSSasha Levin u8 dlm; 253fdf659dSSasha Levin u8 iir; 263fdf659dSSasha Levin u8 ier; 273fdf659dSSasha Levin u8 fcr; 283fdf659dSSasha Levin u8 lcr; 293fdf659dSSasha Levin u8 mcr; 303fdf659dSSasha Levin u8 lsr; 313fdf659dSSasha Levin u8 msr; 323fdf659dSSasha Levin u8 scr; 3346aa8d69SPekka Enberg }; 3446aa8d69SPekka Enberg 35f3efa592SLiming Wang #define SERIAL_REGS_SETTING \ 36f3efa592SLiming Wang .iir = UART_IIR_NO_INT, \ 37f3efa592SLiming Wang .lsr = UART_LSR_TEMT | UART_LSR_THRE, \ 38f3efa592SLiming Wang .msr = UART_MSR_DCD | UART_MSR_DSR | UART_MSR_CTS, \ 39f3efa592SLiming Wang .mcr = UART_MCR_OUT2, 40f3efa592SLiming Wang 41e62c18deSPekka Enberg static struct serial8250_device devices[] = { 42c6a69c61SPekka Enberg /* ttyS0 */ 43c6a69c61SPekka Enberg [0] = { 442932c9ebSPekka Enberg .mutex = PTHREAD_MUTEX_INITIALIZER, 452932c9ebSPekka Enberg 461add4b76SSasha Levin .id = 0, 47c6a69c61SPekka Enberg .iobase = 0x3f8, 48e557eef9SPekka Enberg .irq = 4, 49e557eef9SPekka Enberg 50f3efa592SLiming Wang SERIAL_REGS_SETTING 51c6a69c61SPekka Enberg }, 52e62c18deSPekka Enberg /* ttyS1 */ 53e62c18deSPekka Enberg [1] = { 542932c9ebSPekka Enberg .mutex = PTHREAD_MUTEX_INITIALIZER, 552932c9ebSPekka Enberg 561add4b76SSasha Levin .id = 1, 57e62c18deSPekka Enberg .iobase = 0x2f8, 58e62c18deSPekka Enberg .irq = 3, 59133bedc1SPekka Enberg 60f3efa592SLiming Wang SERIAL_REGS_SETTING 61e62c18deSPekka Enberg }, 62e62c18deSPekka Enberg /* ttyS2 */ 63e62c18deSPekka Enberg [2] = { 642932c9ebSPekka Enberg .mutex = PTHREAD_MUTEX_INITIALIZER, 652932c9ebSPekka Enberg 661add4b76SSasha Levin .id = 2, 67e62c18deSPekka Enberg .iobase = 0x3e8, 68e62c18deSPekka Enberg .irq = 4, 69133bedc1SPekka Enberg 70f3efa592SLiming Wang SERIAL_REGS_SETTING 71e62c18deSPekka Enberg }, 72bf459c83SPekka Enberg /* ttyS3 */ 73bf459c83SPekka Enberg [3] = { 74bf459c83SPekka Enberg .mutex = PTHREAD_MUTEX_INITIALIZER, 75bf459c83SPekka Enberg 761add4b76SSasha Levin .id = 3, 77bf459c83SPekka Enberg .iobase = 0x2e8, 78bf459c83SPekka Enberg .irq = 3, 79bf459c83SPekka Enberg 80f3efa592SLiming Wang SERIAL_REGS_SETTING 81bf459c83SPekka Enberg }, 8246aa8d69SPekka Enberg }; 8346aa8d69SPekka Enberg 84a428f72eSPekka Enberg #define SYSRQ_PENDING_NONE 0 85a428f72eSPekka Enberg #define SYSRQ_PENDING_BREAK 1 86a428f72eSPekka Enberg #define SYSRQ_PENDING_CMD 2 87a428f72eSPekka Enberg 88a428f72eSPekka Enberg static int sysrq_pending; 89a428f72eSPekka Enberg 9043835ac9SSasha Levin static void serial8250__sysrq(struct kvm *kvm, struct serial8250_device *dev) 91a428f72eSPekka Enberg { 92a428f72eSPekka Enberg switch (sysrq_pending) { 93a428f72eSPekka Enberg case SYSRQ_PENDING_BREAK: 94a428f72eSPekka Enberg dev->lsr |= UART_LSR_DR | UART_LSR_BI; 95a428f72eSPekka Enberg 96a428f72eSPekka Enberg sysrq_pending = SYSRQ_PENDING_CMD; 97a428f72eSPekka Enberg break; 98a428f72eSPekka Enberg case SYSRQ_PENDING_CMD: 99a428f72eSPekka Enberg dev->rbr = 'p'; 100a428f72eSPekka Enberg dev->lsr |= UART_LSR_DR; 101a428f72eSPekka Enberg 102a428f72eSPekka Enberg sysrq_pending = SYSRQ_PENDING_NONE; 103a428f72eSPekka Enberg break; 104a428f72eSPekka Enberg } 105a428f72eSPekka Enberg } 106a428f72eSPekka Enberg 10743835ac9SSasha Levin static void serial8250__receive(struct kvm *kvm, struct serial8250_device *dev) 108251cf9a6SPekka Enberg { 109251cf9a6SPekka Enberg int c; 110251cf9a6SPekka Enberg 111db34045cSPekka Enberg if (dev->lsr & UART_LSR_DR) 112db34045cSPekka Enberg return; 113db34045cSPekka Enberg 114a428f72eSPekka Enberg if (sysrq_pending) { 11543835ac9SSasha Levin serial8250__sysrq(kvm, dev); 116a428f72eSPekka Enberg return; 117a428f72eSPekka Enberg } 118a428f72eSPekka Enberg 1191add4b76SSasha Levin if (!term_readable(CONSOLE_8250, dev->id)) 120251cf9a6SPekka Enberg return; 121251cf9a6SPekka Enberg 1221add4b76SSasha Levin c = term_getc(CONSOLE_8250, dev->id); 12305d1a2a6SAsias He 124251cf9a6SPekka Enberg if (c < 0) 125251cf9a6SPekka Enberg return; 126251cf9a6SPekka Enberg 127251cf9a6SPekka Enberg dev->rbr = c; 128251cf9a6SPekka Enberg dev->lsr |= UART_LSR_DR; 129251cf9a6SPekka Enberg } 130251cf9a6SPekka Enberg 13143835ac9SSasha Levin void serial8250__inject_interrupt(struct kvm *kvm) 1328bb34e0dSPekka Enberg { 133479de16fSCyrill Gorcunov unsigned int i; 1341add4b76SSasha Levin 135479de16fSCyrill Gorcunov for (i = 0; i < ARRAY_SIZE(devices); i++) { 1361add4b76SSasha Levin struct serial8250_device *dev = &devices[i]; 137934c193bSPekka Enberg 1384ef0f4d6SPekka Enberg mutex_lock(&dev->mutex); 1392932c9ebSPekka Enberg 14043835ac9SSasha Levin serial8250__receive(kvm, dev); 141251cf9a6SPekka Enberg 142369c01c0SPekka Enberg if (dev->ier & UART_IER_RDI && dev->lsr & UART_LSR_DR) 143369c01c0SPekka Enberg dev->iir = UART_IIR_RDI; 144251cf9a6SPekka Enberg else if (dev->ier & UART_IER_THRI) 145369c01c0SPekka Enberg dev->iir = UART_IIR_THRI; 146369c01c0SPekka Enberg else 147369c01c0SPekka Enberg dev->iir = UART_IIR_NO_INT; 14876b4a122SPekka Enberg 149369c01c0SPekka Enberg if (dev->iir != UART_IIR_NO_INT) { 15043835ac9SSasha Levin kvm__irq_line(kvm, dev->irq, 0); 15143835ac9SSasha Levin kvm__irq_line(kvm, dev->irq, 1); 152e557eef9SPekka Enberg } 1532932c9ebSPekka Enberg 1544ef0f4d6SPekka Enberg mutex_unlock(&dev->mutex); 1558bb34e0dSPekka Enberg } 1561add4b76SSasha Levin } 1578bb34e0dSPekka Enberg 15843835ac9SSasha Levin void serial8250__inject_sysrq(struct kvm *kvm) 159a428f72eSPekka Enberg { 160a428f72eSPekka Enberg sysrq_pending = SYSRQ_PENDING_BREAK; 161a428f72eSPekka Enberg } 162a428f72eSPekka Enberg 1633fdf659dSSasha Levin static struct serial8250_device *find_device(u16 port) 164c6a69c61SPekka Enberg { 165c6a69c61SPekka Enberg unsigned int i; 166c6a69c61SPekka Enberg 167c6a69c61SPekka Enberg for (i = 0; i < ARRAY_SIZE(devices); i++) { 168c6a69c61SPekka Enberg struct serial8250_device *dev = &devices[i]; 169c6a69c61SPekka Enberg 170c6a69c61SPekka Enberg if (dev->iobase == (port & ~0x7)) 171c6a69c61SPekka Enberg return dev; 172c6a69c61SPekka Enberg } 173c6a69c61SPekka Enberg return NULL; 174c6a69c61SPekka Enberg } 175c6a69c61SPekka Enberg 176c9f6a037SXiao Guangrong static bool serial8250_out(struct ioport *ioport, struct kvm *kvm, u16 port, void *data, int size) 17713a7760fSPekka Enberg { 178c6a69c61SPekka Enberg struct serial8250_device *dev; 1793fdf659dSSasha Levin u16 offset; 1802932c9ebSPekka Enberg bool ret = true; 18146aa8d69SPekka Enberg 182c6a69c61SPekka Enberg dev = find_device(port); 183c6a69c61SPekka Enberg if (!dev) 184c6a69c61SPekka Enberg return false; 185c6a69c61SPekka Enberg 1864ef0f4d6SPekka Enberg mutex_lock(&dev->mutex); 1872932c9ebSPekka Enberg 188c6a69c61SPekka Enberg offset = port - dev->iobase; 189c6a69c61SPekka Enberg 19046aa8d69SPekka Enberg switch (offset) { 191*c59fa0c4SThomas Gleixner case UART_TX: 192*c59fa0c4SThomas Gleixner if (!(dev->lcr & UART_LCR_DLAB)) { 19305d1a2a6SAsias He char *addr = data; 1940ea58e5bSPekka Enberg 1950ea58e5bSPekka Enberg if (!(dev->mcr & UART_MCR_LOOP)) 1961add4b76SSasha Levin term_putc(CONSOLE_8250, addr, size, dev->id); 1970ea58e5bSPekka Enberg 198133bedc1SPekka Enberg dev->iir = UART_IIR_NO_INT; 199*c59fa0c4SThomas Gleixner } else { 200*c59fa0c4SThomas Gleixner dev->dll = ioport__read8(data); 20146aa8d69SPekka Enberg } 202369c01c0SPekka Enberg break; 2034e49b05bSCyrill Gorcunov case UART_IER: 204*c59fa0c4SThomas Gleixner if (!(dev->lcr & UART_LCR_DLAB)) { 205369c01c0SPekka Enberg dev->ier = ioport__read8(data) & 0x3f; 206610a82c4SSasha Levin kvm__irq_line(kvm, dev->irq, dev->ier ? 1 : 0); 207*c59fa0c4SThomas Gleixner } else { 208*c59fa0c4SThomas Gleixner dev->dlm = ioport__read8(data); 209*c59fa0c4SThomas Gleixner } 210*c59fa0c4SThomas Gleixner break; 211*c59fa0c4SThomas Gleixner case UART_FCR: 212*c59fa0c4SThomas Gleixner dev->fcr = ioport__read8(data); 21346aa8d69SPekka Enberg break; 214369c01c0SPekka Enberg case UART_LCR: 215369c01c0SPekka Enberg dev->lcr = ioport__read8(data); 216369c01c0SPekka Enberg break; 217369c01c0SPekka Enberg case UART_MCR: 218369c01c0SPekka Enberg dev->mcr = ioport__read8(data); 219369c01c0SPekka Enberg break; 220369c01c0SPekka Enberg case UART_LSR: 221369c01c0SPekka Enberg /* Factory test */ 222369c01c0SPekka Enberg break; 223369c01c0SPekka Enberg case UART_MSR: 224369c01c0SPekka Enberg /* Not used */ 225369c01c0SPekka Enberg break; 226369c01c0SPekka Enberg case UART_SCR: 227369c01c0SPekka Enberg dev->scr = ioport__read8(data); 228369c01c0SPekka Enberg break; 229369c01c0SPekka Enberg default: 2302932c9ebSPekka Enberg ret = false; 231d2ea115dSThomas Gleixner break; 23246aa8d69SPekka Enberg } 2332932c9ebSPekka Enberg 2344ef0f4d6SPekka Enberg mutex_unlock(&dev->mutex); 2352932c9ebSPekka Enberg 2362932c9ebSPekka Enberg return ret; 23713a7760fSPekka Enberg } 23813a7760fSPekka Enberg 239c9f6a037SXiao Guangrong static bool serial8250_in(struct ioport *ioport, struct kvm *kvm, u16 port, void *data, int size) 24025af6674SPekka Enberg { 241c6a69c61SPekka Enberg struct serial8250_device *dev; 2423fdf659dSSasha Levin u16 offset; 2432932c9ebSPekka Enberg bool ret = true; 24446aa8d69SPekka Enberg 245c6a69c61SPekka Enberg dev = find_device(port); 246c6a69c61SPekka Enberg if (!dev) 247c6a69c61SPekka Enberg return false; 248c6a69c61SPekka Enberg 2494ef0f4d6SPekka Enberg mutex_lock(&dev->mutex); 2502932c9ebSPekka Enberg 251c6a69c61SPekka Enberg offset = port - dev->iobase; 252c6a69c61SPekka Enberg 25346aa8d69SPekka Enberg switch (offset) { 254251cf9a6SPekka Enberg case UART_RX: 255*c59fa0c4SThomas Gleixner if (dev->lcr & UART_LCR_DLAB) { 256*c59fa0c4SThomas Gleixner ioport__write8(data, dev->dll); 257*c59fa0c4SThomas Gleixner } else { 258251cf9a6SPekka Enberg ioport__write8(data, dev->rbr); 259369c01c0SPekka Enberg dev->lsr &= ~UART_LSR_DR; 260369c01c0SPekka Enberg dev->iir = UART_IIR_NO_INT; 261*c59fa0c4SThomas Gleixner } 262369c01c0SPekka Enberg break; 263*c59fa0c4SThomas Gleixner case UART_IER: 264*c59fa0c4SThomas Gleixner if (dev->lcr & UART_LCR_DLAB) 265*c59fa0c4SThomas Gleixner ioport__write8(data, dev->dlm); 266*c59fa0c4SThomas Gleixner else 267*c59fa0c4SThomas Gleixner ioport__write8(data, dev->ier); 268*c59fa0c4SThomas Gleixner break; 269369c01c0SPekka Enberg case UART_IIR: { 2703fdf659dSSasha Levin u8 iir = dev->iir; 271369c01c0SPekka Enberg 272369c01c0SPekka Enberg if (dev->fcr & UART_FCR_ENABLE_FIFO) 273369c01c0SPekka Enberg iir |= 0xc0; 274369c01c0SPekka Enberg 275369c01c0SPekka Enberg ioport__write8(data, iir); 27646aa8d69SPekka Enberg break; 277369c01c0SPekka Enberg } 2784e49b05bSCyrill Gorcunov case UART_LCR: 279c6a69c61SPekka Enberg ioport__write8(data, dev->lcr); 28046aa8d69SPekka Enberg break; 2814e49b05bSCyrill Gorcunov case UART_MCR: 282c6a69c61SPekka Enberg ioport__write8(data, dev->mcr); 28346aa8d69SPekka Enberg break; 2844e49b05bSCyrill Gorcunov case UART_LSR: 285c6a69c61SPekka Enberg ioport__write8(data, dev->lsr); 286369c01c0SPekka Enberg dev->lsr &= ~(UART_LSR_OE|UART_LSR_PE|UART_LSR_FE|UART_LSR_BI); 28746aa8d69SPekka Enberg break; 2884e49b05bSCyrill Gorcunov case UART_MSR: 289369c01c0SPekka Enberg ioport__write8(data, dev->msr); 29046aa8d69SPekka Enberg break; 2914e49b05bSCyrill Gorcunov case UART_SCR: 292369c01c0SPekka Enberg ioport__write8(data, dev->scr); 29346aa8d69SPekka Enberg break; 294369c01c0SPekka Enberg default: 2952932c9ebSPekka Enberg ret = false; 296*c59fa0c4SThomas Gleixner break; 29725af6674SPekka Enberg } 2984ef0f4d6SPekka Enberg mutex_unlock(&dev->mutex); 2992932c9ebSPekka Enberg 3002932c9ebSPekka Enberg return ret; 30113a7760fSPekka Enberg } 30213a7760fSPekka Enberg 30346aa8d69SPekka Enberg static struct ioport_operations serial8250_ops = { 30446aa8d69SPekka Enberg .io_in = serial8250_in, 30546aa8d69SPekka Enberg .io_out = serial8250_out, 306a93ec68bSPekka Enberg }; 307a93ec68bSPekka Enberg 308bc4b0ffeSPekka Enberg static void serial8250__device_init(struct kvm *kvm, struct serial8250_device *dev) 309bc4b0ffeSPekka Enberg { 3103d62dea6SSasha Levin ioport__register(dev->iobase, &serial8250_ops, 8, NULL); 311bc4b0ffeSPekka Enberg kvm__irq_line(kvm, dev->irq, 0); 312bc4b0ffeSPekka Enberg } 313bc4b0ffeSPekka Enberg 314bc4b0ffeSPekka Enberg void serial8250__init(struct kvm *kvm) 31513a7760fSPekka Enberg { 316c6a69c61SPekka Enberg unsigned int i; 317c6a69c61SPekka Enberg 318c6a69c61SPekka Enberg for (i = 0; i < ARRAY_SIZE(devices); i++) { 319c6a69c61SPekka Enberg struct serial8250_device *dev = &devices[i]; 320c6a69c61SPekka Enberg 321bc4b0ffeSPekka Enberg serial8250__device_init(kvm, dev); 322c6a69c61SPekka Enberg } 32313a7760fSPekka Enberg } 324