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; 172932c9ebSPekka Enberg 183fdf659dSSasha Levin u16 iobase; 193fdf659dSSasha Levin u8 irq; 2076b4a122SPekka Enberg 213fdf659dSSasha Levin u8 rbr; /* receive buffer */ 223fdf659dSSasha Levin u8 dll; 233fdf659dSSasha Levin u8 dlm; 243fdf659dSSasha Levin u8 iir; 253fdf659dSSasha Levin u8 ier; 263fdf659dSSasha Levin u8 fcr; 273fdf659dSSasha Levin u8 lcr; 283fdf659dSSasha Levin u8 mcr; 293fdf659dSSasha Levin u8 lsr; 303fdf659dSSasha Levin u8 msr; 313fdf659dSSasha Levin u8 scr; 3246aa8d69SPekka Enberg }; 3346aa8d69SPekka Enberg 34e62c18deSPekka Enberg static struct serial8250_device devices[] = { 35c6a69c61SPekka Enberg /* ttyS0 */ 36c6a69c61SPekka Enberg [0] = { 372932c9ebSPekka Enberg .mutex = PTHREAD_MUTEX_INITIALIZER, 382932c9ebSPekka Enberg 39c6a69c61SPekka Enberg .iobase = 0x3f8, 40e557eef9SPekka Enberg .irq = 4, 41e557eef9SPekka Enberg 42369c01c0SPekka Enberg .iir = UART_IIR_NO_INT, 43bc4b0ffeSPekka Enberg .lsr = UART_LSR_TEMT | UART_LSR_THRE, 44bc4b0ffeSPekka Enberg .msr = UART_MSR_DCD | UART_MSR_DSR | UART_MSR_CTS, 45bc4b0ffeSPekka Enberg .mcr = UART_MCR_OUT2, 46c6a69c61SPekka Enberg }, 47e62c18deSPekka Enberg /* ttyS1 */ 48e62c18deSPekka Enberg [1] = { 492932c9ebSPekka Enberg .mutex = PTHREAD_MUTEX_INITIALIZER, 502932c9ebSPekka Enberg 51e62c18deSPekka Enberg .iobase = 0x2f8, 52e62c18deSPekka Enberg .irq = 3, 53133bedc1SPekka Enberg 54133bedc1SPekka Enberg .iir = UART_IIR_NO_INT, 55e62c18deSPekka Enberg }, 56e62c18deSPekka Enberg /* ttyS2 */ 57e62c18deSPekka Enberg [2] = { 582932c9ebSPekka Enberg .mutex = PTHREAD_MUTEX_INITIALIZER, 592932c9ebSPekka Enberg 60e62c18deSPekka Enberg .iobase = 0x3e8, 61e62c18deSPekka Enberg .irq = 4, 62133bedc1SPekka Enberg 63133bedc1SPekka Enberg .iir = UART_IIR_NO_INT, 64e62c18deSPekka Enberg }, 65bf459c83SPekka Enberg /* ttyS3 */ 66bf459c83SPekka Enberg [3] = { 67bf459c83SPekka Enberg .mutex = PTHREAD_MUTEX_INITIALIZER, 68bf459c83SPekka Enberg 69bf459c83SPekka Enberg .iobase = 0x2e8, 70bf459c83SPekka Enberg .irq = 3, 71bf459c83SPekka Enberg 72bf459c83SPekka Enberg .iir = UART_IIR_NO_INT, 73bf459c83SPekka Enberg }, 7446aa8d69SPekka Enberg }; 7546aa8d69SPekka Enberg 76a428f72eSPekka Enberg #define SYSRQ_PENDING_NONE 0 77a428f72eSPekka Enberg #define SYSRQ_PENDING_BREAK 1 78a428f72eSPekka Enberg #define SYSRQ_PENDING_CMD 2 79a428f72eSPekka Enberg 80a428f72eSPekka Enberg static int sysrq_pending; 81a428f72eSPekka Enberg 8243835ac9SSasha Levin static void serial8250__sysrq(struct kvm *kvm, struct serial8250_device *dev) 83a428f72eSPekka Enberg { 84a428f72eSPekka Enberg switch (sysrq_pending) { 85a428f72eSPekka Enberg case SYSRQ_PENDING_BREAK: 86a428f72eSPekka Enberg dev->lsr |= UART_LSR_DR | UART_LSR_BI; 87a428f72eSPekka Enberg 88a428f72eSPekka Enberg sysrq_pending = SYSRQ_PENDING_CMD; 89a428f72eSPekka Enberg break; 90a428f72eSPekka Enberg case SYSRQ_PENDING_CMD: 91a428f72eSPekka Enberg dev->rbr = 'p'; 92a428f72eSPekka Enberg dev->lsr |= UART_LSR_DR; 93a428f72eSPekka Enberg 94a428f72eSPekka Enberg sysrq_pending = SYSRQ_PENDING_NONE; 95a428f72eSPekka Enberg break; 96a428f72eSPekka Enberg } 97a428f72eSPekka Enberg } 98a428f72eSPekka Enberg 9943835ac9SSasha Levin static void serial8250__receive(struct kvm *kvm, struct serial8250_device *dev) 100251cf9a6SPekka Enberg { 101251cf9a6SPekka Enberg int c; 102251cf9a6SPekka Enberg 103db34045cSPekka Enberg if (dev->lsr & UART_LSR_DR) 104db34045cSPekka Enberg return; 105db34045cSPekka Enberg 106a428f72eSPekka Enberg if (sysrq_pending) { 10743835ac9SSasha Levin serial8250__sysrq(kvm, dev); 108a428f72eSPekka Enberg return; 109a428f72eSPekka Enberg } 110a428f72eSPekka Enberg 11105d1a2a6SAsias He if (!term_readable(CONSOLE_8250)) 112251cf9a6SPekka Enberg return; 113251cf9a6SPekka Enberg 11405d1a2a6SAsias He c = term_getc(CONSOLE_8250); 11505d1a2a6SAsias He 116251cf9a6SPekka Enberg if (c < 0) 117251cf9a6SPekka Enberg return; 118251cf9a6SPekka Enberg 119251cf9a6SPekka Enberg dev->rbr = c; 120251cf9a6SPekka Enberg dev->lsr |= UART_LSR_DR; 121251cf9a6SPekka Enberg } 122251cf9a6SPekka Enberg 123c6a69c61SPekka Enberg /* 124c6a69c61SPekka Enberg * Interrupts are injected for ttyS0 only. 125c6a69c61SPekka Enberg */ 12643835ac9SSasha Levin void serial8250__inject_interrupt(struct kvm *kvm) 1278bb34e0dSPekka Enberg { 128c6a69c61SPekka Enberg struct serial8250_device *dev = &devices[0]; 129934c193bSPekka Enberg 1304ef0f4d6SPekka Enberg mutex_lock(&dev->mutex); 1312932c9ebSPekka Enberg 13243835ac9SSasha Levin serial8250__receive(kvm, dev); 133251cf9a6SPekka Enberg 134369c01c0SPekka Enberg if (dev->ier & UART_IER_RDI && dev->lsr & UART_LSR_DR) 135369c01c0SPekka Enberg dev->iir = UART_IIR_RDI; 136251cf9a6SPekka Enberg else if (dev->ier & UART_IER_THRI) 137369c01c0SPekka Enberg dev->iir = UART_IIR_THRI; 138369c01c0SPekka Enberg else 139369c01c0SPekka Enberg dev->iir = UART_IIR_NO_INT; 14076b4a122SPekka Enberg 141369c01c0SPekka Enberg if (dev->iir != UART_IIR_NO_INT) { 14243835ac9SSasha Levin kvm__irq_line(kvm, dev->irq, 0); 14343835ac9SSasha Levin kvm__irq_line(kvm, dev->irq, 1); 144e557eef9SPekka Enberg } 1452932c9ebSPekka Enberg 1464ef0f4d6SPekka Enberg mutex_unlock(&dev->mutex); 1478bb34e0dSPekka Enberg } 1488bb34e0dSPekka Enberg 14943835ac9SSasha Levin void serial8250__inject_sysrq(struct kvm *kvm) 150a428f72eSPekka Enberg { 151a428f72eSPekka Enberg sysrq_pending = SYSRQ_PENDING_BREAK; 152a428f72eSPekka Enberg } 153a428f72eSPekka Enberg 1543fdf659dSSasha Levin static struct serial8250_device *find_device(u16 port) 155c6a69c61SPekka Enberg { 156c6a69c61SPekka Enberg unsigned int i; 157c6a69c61SPekka Enberg 158c6a69c61SPekka Enberg for (i = 0; i < ARRAY_SIZE(devices); i++) { 159c6a69c61SPekka Enberg struct serial8250_device *dev = &devices[i]; 160c6a69c61SPekka Enberg 161c6a69c61SPekka Enberg if (dev->iobase == (port & ~0x7)) 162c6a69c61SPekka Enberg return dev; 163c6a69c61SPekka Enberg } 164c6a69c61SPekka Enberg return NULL; 165c6a69c61SPekka Enberg } 166c6a69c61SPekka Enberg 167*3d62dea6SSasha Levin static bool serial8250_out(struct ioport *ioport, struct kvm *kvm, u16 port, void *data, int size, u32 count) 16813a7760fSPekka Enberg { 169c6a69c61SPekka Enberg struct serial8250_device *dev; 1703fdf659dSSasha Levin u16 offset; 1712932c9ebSPekka Enberg bool ret = true; 17246aa8d69SPekka Enberg 173c6a69c61SPekka Enberg dev = find_device(port); 174c6a69c61SPekka Enberg if (!dev) 175c6a69c61SPekka Enberg return false; 176c6a69c61SPekka Enberg 1774ef0f4d6SPekka Enberg mutex_lock(&dev->mutex); 1782932c9ebSPekka Enberg 179c6a69c61SPekka Enberg offset = port - dev->iobase; 180c6a69c61SPekka Enberg 181c6a69c61SPekka Enberg if (dev->lcr & UART_LCR_DLAB) { 18246aa8d69SPekka Enberg switch (offset) { 1834e49b05bSCyrill Gorcunov case UART_DLL: 184c6a69c61SPekka Enberg dev->dll = ioport__read8(data); 18546aa8d69SPekka Enberg break; 1864e49b05bSCyrill Gorcunov case UART_DLM: 187c6a69c61SPekka Enberg dev->dlm = ioport__read8(data); 18846aa8d69SPekka Enberg break; 189369c01c0SPekka Enberg case UART_FCR: 190369c01c0SPekka Enberg dev->fcr = ioport__read8(data); 191369c01c0SPekka Enberg break; 192369c01c0SPekka Enberg case UART_LCR: 193369c01c0SPekka Enberg dev->lcr = ioport__read8(data); 194369c01c0SPekka Enberg break; 195369c01c0SPekka Enberg case UART_MCR: 196369c01c0SPekka Enberg dev->mcr = ioport__read8(data); 197369c01c0SPekka Enberg break; 198369c01c0SPekka Enberg case UART_LSR: 199369c01c0SPekka Enberg /* Factory test */ 200369c01c0SPekka Enberg break; 201369c01c0SPekka Enberg case UART_MSR: 202369c01c0SPekka Enberg /* Not used */ 203369c01c0SPekka Enberg break; 204369c01c0SPekka Enberg case UART_SCR: 205369c01c0SPekka Enberg dev->scr = ioport__read8(data); 206369c01c0SPekka Enberg break; 207369c01c0SPekka Enberg default: 2082932c9ebSPekka Enberg ret = false; 2092932c9ebSPekka Enberg goto out_unlock; 21046aa8d69SPekka Enberg } 21146aa8d69SPekka Enberg } else { 21246aa8d69SPekka Enberg switch (offset) { 2134e49b05bSCyrill Gorcunov case UART_TX: { 21405d1a2a6SAsias He char *addr = data; 2150ea58e5bSPekka Enberg 2160ea58e5bSPekka Enberg if (!(dev->mcr & UART_MCR_LOOP)) 21705d1a2a6SAsias He term_putc(CONSOLE_8250, addr, size * count); 2180ea58e5bSPekka Enberg 219133bedc1SPekka Enberg dev->iir = UART_IIR_NO_INT; 22046aa8d69SPekka Enberg break; 22146aa8d69SPekka Enberg } 222369c01c0SPekka Enberg case UART_FCR: 223369c01c0SPekka Enberg dev->fcr = ioport__read8(data); 224369c01c0SPekka Enberg break; 2254e49b05bSCyrill Gorcunov case UART_IER: 226369c01c0SPekka Enberg dev->ier = ioport__read8(data) & 0x3f; 22746aa8d69SPekka Enberg break; 228369c01c0SPekka Enberg case UART_LCR: 229369c01c0SPekka Enberg dev->lcr = ioport__read8(data); 230369c01c0SPekka Enberg break; 231369c01c0SPekka Enberg case UART_MCR: 232369c01c0SPekka Enberg dev->mcr = ioport__read8(data); 233369c01c0SPekka Enberg break; 234369c01c0SPekka Enberg case UART_LSR: 235369c01c0SPekka Enberg /* Factory test */ 236369c01c0SPekka Enberg break; 237369c01c0SPekka Enberg case UART_MSR: 238369c01c0SPekka Enberg /* Not used */ 239369c01c0SPekka Enberg break; 240369c01c0SPekka Enberg case UART_SCR: 241369c01c0SPekka Enberg dev->scr = ioport__read8(data); 242369c01c0SPekka Enberg break; 243369c01c0SPekka Enberg default: 2442932c9ebSPekka Enberg ret = false; 2452932c9ebSPekka Enberg goto out_unlock; 24646aa8d69SPekka Enberg } 24746aa8d69SPekka Enberg } 2482932c9ebSPekka Enberg 2492932c9ebSPekka Enberg out_unlock: 2504ef0f4d6SPekka Enberg mutex_unlock(&dev->mutex); 2512932c9ebSPekka Enberg 2522932c9ebSPekka Enberg return ret; 25313a7760fSPekka Enberg } 25413a7760fSPekka Enberg 255*3d62dea6SSasha Levin static bool serial8250_in(struct ioport *ioport, struct kvm *kvm, u16 port, void *data, int size, u32 count) 25625af6674SPekka Enberg { 257c6a69c61SPekka Enberg struct serial8250_device *dev; 2583fdf659dSSasha Levin u16 offset; 2592932c9ebSPekka Enberg bool ret = true; 26046aa8d69SPekka Enberg 261c6a69c61SPekka Enberg dev = find_device(port); 262c6a69c61SPekka Enberg if (!dev) 263c6a69c61SPekka Enberg return false; 264c6a69c61SPekka Enberg 2654ef0f4d6SPekka Enberg mutex_lock(&dev->mutex); 2662932c9ebSPekka Enberg 267c6a69c61SPekka Enberg offset = port - dev->iobase; 268c6a69c61SPekka Enberg 26919a2bb7dSPekka Enberg if (dev->lcr & UART_LCR_DLAB) { 27019a2bb7dSPekka Enberg switch (offset) { 27119a2bb7dSPekka Enberg case UART_DLL: 27219a2bb7dSPekka Enberg ioport__write8(data, dev->dll); 2732932c9ebSPekka Enberg goto out_unlock; 2742932c9ebSPekka Enberg 27519a2bb7dSPekka Enberg case UART_DLM: 27619a2bb7dSPekka Enberg ioport__write8(data, dev->dlm); 2772932c9ebSPekka Enberg goto out_unlock; 2782932c9ebSPekka Enberg 279369c01c0SPekka Enberg default: 280369c01c0SPekka Enberg break; 28119a2bb7dSPekka Enberg } 28219a2bb7dSPekka Enberg } else { 28346aa8d69SPekka Enberg switch (offset) { 284251cf9a6SPekka Enberg case UART_RX: 285251cf9a6SPekka Enberg ioport__write8(data, dev->rbr); 286369c01c0SPekka Enberg dev->lsr &= ~UART_LSR_DR; 287369c01c0SPekka Enberg dev->iir = UART_IIR_NO_INT; 2882932c9ebSPekka Enberg goto out_unlock; 2892932c9ebSPekka Enberg 2904e49b05bSCyrill Gorcunov case UART_IER: 291c6a69c61SPekka Enberg ioport__write8(data, dev->ier); 2922932c9ebSPekka Enberg goto out_unlock; 2932932c9ebSPekka Enberg 294369c01c0SPekka Enberg default: 295369c01c0SPekka Enberg break; 29619a2bb7dSPekka Enberg } 29719a2bb7dSPekka Enberg } 29819a2bb7dSPekka Enberg 29919a2bb7dSPekka Enberg switch (offset) { 300369c01c0SPekka Enberg case UART_IIR: { 3013fdf659dSSasha Levin u8 iir = dev->iir; 302369c01c0SPekka Enberg 303369c01c0SPekka Enberg if (dev->fcr & UART_FCR_ENABLE_FIFO) 304369c01c0SPekka Enberg iir |= 0xc0; 305369c01c0SPekka Enberg 306369c01c0SPekka Enberg ioport__write8(data, iir); 30746aa8d69SPekka Enberg break; 308369c01c0SPekka Enberg } 3094e49b05bSCyrill Gorcunov case UART_LCR: 310c6a69c61SPekka Enberg ioport__write8(data, dev->lcr); 31146aa8d69SPekka Enberg break; 3124e49b05bSCyrill Gorcunov case UART_MCR: 313c6a69c61SPekka Enberg ioport__write8(data, dev->mcr); 31446aa8d69SPekka Enberg break; 3154e49b05bSCyrill Gorcunov case UART_LSR: 316c6a69c61SPekka Enberg ioport__write8(data, dev->lsr); 317369c01c0SPekka Enberg dev->lsr &= ~(UART_LSR_OE|UART_LSR_PE|UART_LSR_FE|UART_LSR_BI); 31846aa8d69SPekka Enberg break; 3194e49b05bSCyrill Gorcunov case UART_MSR: 320369c01c0SPekka Enberg ioport__write8(data, dev->msr); 32146aa8d69SPekka Enberg break; 3224e49b05bSCyrill Gorcunov case UART_SCR: 323369c01c0SPekka Enberg ioport__write8(data, dev->scr); 32446aa8d69SPekka Enberg break; 325369c01c0SPekka Enberg default: 3262932c9ebSPekka Enberg ret = false; 3272932c9ebSPekka Enberg goto out_unlock; 32825af6674SPekka Enberg } 3292932c9ebSPekka Enberg out_unlock: 3304ef0f4d6SPekka Enberg mutex_unlock(&dev->mutex); 3312932c9ebSPekka Enberg 3322932c9ebSPekka Enberg return ret; 33313a7760fSPekka Enberg } 33413a7760fSPekka Enberg 33546aa8d69SPekka Enberg static struct ioport_operations serial8250_ops = { 33646aa8d69SPekka Enberg .io_in = serial8250_in, 33746aa8d69SPekka Enberg .io_out = serial8250_out, 338a93ec68bSPekka Enberg }; 339a93ec68bSPekka Enberg 340bc4b0ffeSPekka Enberg static void serial8250__device_init(struct kvm *kvm, struct serial8250_device *dev) 341bc4b0ffeSPekka Enberg { 342*3d62dea6SSasha Levin ioport__register(dev->iobase, &serial8250_ops, 8, NULL); 343bc4b0ffeSPekka Enberg kvm__irq_line(kvm, dev->irq, 0); 344bc4b0ffeSPekka Enberg } 345bc4b0ffeSPekka Enberg 346bc4b0ffeSPekka Enberg void serial8250__init(struct kvm *kvm) 34713a7760fSPekka Enberg { 348c6a69c61SPekka Enberg unsigned int i; 349c6a69c61SPekka Enberg 350c6a69c61SPekka Enberg for (i = 0; i < ARRAY_SIZE(devices); i++) { 351c6a69c61SPekka Enberg struct serial8250_device *dev = &devices[i]; 352c6a69c61SPekka Enberg 353bc4b0ffeSPekka Enberg serial8250__device_init(kvm, dev); 354c6a69c61SPekka Enberg } 35513a7760fSPekka Enberg } 356