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; 17*1add4b76SSasha 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 46*1add4b76SSasha 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 56*1add4b76SSasha 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 66*1add4b76SSasha 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 76*1add4b76SSasha 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 119*1add4b76SSasha Levin if (!term_readable(CONSOLE_8250, dev->id)) 120251cf9a6SPekka Enberg return; 121251cf9a6SPekka Enberg 122*1add4b76SSasha 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 { 133*1add4b76SSasha Levin int i; 134*1add4b76SSasha Levin 135*1add4b76SSasha Levin for (i = 0; i < 4; i++) { 136*1add4b76SSasha 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 } 156*1add4b76SSasha 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 190c6a69c61SPekka Enberg if (dev->lcr & UART_LCR_DLAB) { 19146aa8d69SPekka Enberg switch (offset) { 1924e49b05bSCyrill Gorcunov case UART_DLL: 193c6a69c61SPekka Enberg dev->dll = ioport__read8(data); 19446aa8d69SPekka Enberg break; 1954e49b05bSCyrill Gorcunov case UART_DLM: 196c6a69c61SPekka Enberg dev->dlm = ioport__read8(data); 19746aa8d69SPekka Enberg break; 198369c01c0SPekka Enberg case UART_FCR: 199369c01c0SPekka Enberg dev->fcr = ioport__read8(data); 200369c01c0SPekka Enberg break; 201369c01c0SPekka Enberg case UART_LCR: 202369c01c0SPekka Enberg dev->lcr = ioport__read8(data); 203369c01c0SPekka Enberg break; 204369c01c0SPekka Enberg case UART_MCR: 205369c01c0SPekka Enberg dev->mcr = ioport__read8(data); 206369c01c0SPekka Enberg break; 207369c01c0SPekka Enberg case UART_LSR: 208369c01c0SPekka Enberg /* Factory test */ 209369c01c0SPekka Enberg break; 210369c01c0SPekka Enberg case UART_MSR: 211369c01c0SPekka Enberg /* Not used */ 212369c01c0SPekka Enberg break; 213369c01c0SPekka Enberg case UART_SCR: 214369c01c0SPekka Enberg dev->scr = ioport__read8(data); 215369c01c0SPekka Enberg break; 216369c01c0SPekka Enberg default: 2172932c9ebSPekka Enberg ret = false; 2182932c9ebSPekka Enberg goto out_unlock; 21946aa8d69SPekka Enberg } 22046aa8d69SPekka Enberg } else { 22146aa8d69SPekka Enberg switch (offset) { 2224e49b05bSCyrill Gorcunov case UART_TX: { 22305d1a2a6SAsias He char *addr = data; 2240ea58e5bSPekka Enberg 2250ea58e5bSPekka Enberg if (!(dev->mcr & UART_MCR_LOOP)) 226*1add4b76SSasha Levin term_putc(CONSOLE_8250, addr, size, dev->id); 2270ea58e5bSPekka Enberg 228133bedc1SPekka Enberg dev->iir = UART_IIR_NO_INT; 22946aa8d69SPekka Enberg break; 23046aa8d69SPekka Enberg } 231369c01c0SPekka Enberg case UART_FCR: 232369c01c0SPekka Enberg dev->fcr = ioport__read8(data); 233369c01c0SPekka Enberg break; 2344e49b05bSCyrill Gorcunov case UART_IER: 235369c01c0SPekka Enberg dev->ier = ioport__read8(data) & 0x3f; 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; 2542932c9ebSPekka Enberg goto out_unlock; 25546aa8d69SPekka Enberg } 25646aa8d69SPekka Enberg } 2572932c9ebSPekka Enberg 2582932c9ebSPekka Enberg out_unlock: 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 27819a2bb7dSPekka Enberg if (dev->lcr & UART_LCR_DLAB) { 27919a2bb7dSPekka Enberg switch (offset) { 28019a2bb7dSPekka Enberg case UART_DLL: 28119a2bb7dSPekka Enberg ioport__write8(data, dev->dll); 2822932c9ebSPekka Enberg goto out_unlock; 2832932c9ebSPekka Enberg 28419a2bb7dSPekka Enberg case UART_DLM: 28519a2bb7dSPekka Enberg ioport__write8(data, dev->dlm); 2862932c9ebSPekka Enberg goto out_unlock; 2872932c9ebSPekka Enberg 288369c01c0SPekka Enberg default: 289369c01c0SPekka Enberg break; 29019a2bb7dSPekka Enberg } 29119a2bb7dSPekka Enberg } else { 29246aa8d69SPekka Enberg switch (offset) { 293251cf9a6SPekka Enberg case UART_RX: 294251cf9a6SPekka Enberg ioport__write8(data, dev->rbr); 295369c01c0SPekka Enberg dev->lsr &= ~UART_LSR_DR; 296369c01c0SPekka Enberg dev->iir = UART_IIR_NO_INT; 2972932c9ebSPekka Enberg goto out_unlock; 2982932c9ebSPekka Enberg 2994e49b05bSCyrill Gorcunov case UART_IER: 300c6a69c61SPekka Enberg ioport__write8(data, dev->ier); 3012932c9ebSPekka Enberg goto out_unlock; 3022932c9ebSPekka Enberg 303369c01c0SPekka Enberg default: 304369c01c0SPekka Enberg break; 30519a2bb7dSPekka Enberg } 30619a2bb7dSPekka Enberg } 30719a2bb7dSPekka Enberg 30819a2bb7dSPekka Enberg switch (offset) { 309369c01c0SPekka Enberg case UART_IIR: { 3103fdf659dSSasha Levin u8 iir = dev->iir; 311369c01c0SPekka Enberg 312369c01c0SPekka Enberg if (dev->fcr & UART_FCR_ENABLE_FIFO) 313369c01c0SPekka Enberg iir |= 0xc0; 314369c01c0SPekka Enberg 315369c01c0SPekka Enberg ioport__write8(data, iir); 31646aa8d69SPekka Enberg break; 317369c01c0SPekka Enberg } 3184e49b05bSCyrill Gorcunov case UART_LCR: 319c6a69c61SPekka Enberg ioport__write8(data, dev->lcr); 32046aa8d69SPekka Enberg break; 3214e49b05bSCyrill Gorcunov case UART_MCR: 322c6a69c61SPekka Enberg ioport__write8(data, dev->mcr); 32346aa8d69SPekka Enberg break; 3244e49b05bSCyrill Gorcunov case UART_LSR: 325c6a69c61SPekka Enberg ioport__write8(data, dev->lsr); 326369c01c0SPekka Enberg dev->lsr &= ~(UART_LSR_OE|UART_LSR_PE|UART_LSR_FE|UART_LSR_BI); 32746aa8d69SPekka Enberg break; 3284e49b05bSCyrill Gorcunov case UART_MSR: 329369c01c0SPekka Enberg ioport__write8(data, dev->msr); 33046aa8d69SPekka Enberg break; 3314e49b05bSCyrill Gorcunov case UART_SCR: 332369c01c0SPekka Enberg ioport__write8(data, dev->scr); 33346aa8d69SPekka Enberg break; 334369c01c0SPekka Enberg default: 3352932c9ebSPekka Enberg ret = false; 3362932c9ebSPekka Enberg goto out_unlock; 33725af6674SPekka Enberg } 3382932c9ebSPekka Enberg out_unlock: 3394ef0f4d6SPekka Enberg mutex_unlock(&dev->mutex); 3402932c9ebSPekka Enberg 3412932c9ebSPekka Enberg return ret; 34213a7760fSPekka Enberg } 34313a7760fSPekka Enberg 34446aa8d69SPekka Enberg static struct ioport_operations serial8250_ops = { 34546aa8d69SPekka Enberg .io_in = serial8250_in, 34646aa8d69SPekka Enberg .io_out = serial8250_out, 347a93ec68bSPekka Enberg }; 348a93ec68bSPekka Enberg 349bc4b0ffeSPekka Enberg static void serial8250__device_init(struct kvm *kvm, struct serial8250_device *dev) 350bc4b0ffeSPekka Enberg { 3513d62dea6SSasha Levin ioport__register(dev->iobase, &serial8250_ops, 8, NULL); 352bc4b0ffeSPekka Enberg kvm__irq_line(kvm, dev->irq, 0); 353bc4b0ffeSPekka Enberg } 354bc4b0ffeSPekka Enberg 355bc4b0ffeSPekka Enberg void serial8250__init(struct kvm *kvm) 35613a7760fSPekka Enberg { 357c6a69c61SPekka Enberg unsigned int i; 358c6a69c61SPekka Enberg 359c6a69c61SPekka Enberg for (i = 0; i < ARRAY_SIZE(devices); i++) { 360c6a69c61SPekka Enberg struct serial8250_device *dev = &devices[i]; 361c6a69c61SPekka Enberg 362bc4b0ffeSPekka Enberg serial8250__device_init(kvm, dev); 363c6a69c61SPekka Enberg } 36413a7760fSPekka Enberg } 365