xref: /kvmtool/hw/serial.c (revision 2f030d283c0e7a417f50cf0d70d076870815f3e6)
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"
9d28abb58SWill Deacon #include "kvm/fdt.h"
1013a7760fSPekka Enberg 
113fdf659dSSasha Levin #include <linux/types.h>
124e49b05bSCyrill Gorcunov #include <linux/serial_reg.h>
134e49b05bSCyrill Gorcunov 
142932c9ebSPekka Enberg #include <pthread.h>
1513a7760fSPekka Enberg 
1645b4968eSAndre Przywara #if defined(CONFIG_ARM) || defined(CONFIG_ARM64)
1745b4968eSAndre Przywara #define serial_iobase(nr)	(ARM_UART_MMIO_BASE + (nr) * 0x1000)
1845b4968eSAndre Przywara #define serial_irq(nr)		(32 + (nr))
1945b4968eSAndre Przywara #define SERIAL8250_BUS_TYPE	DEVICE_BUS_MMIO
20*2f030d28SRajnesh Kanwal #elif defined(CONFIG_RISCV)
21*2f030d28SRajnesh Kanwal #define serial_iobase(nr)	(RISCV_UART_MMIO_BASE + (nr) * 0x1000)
22*2f030d28SRajnesh Kanwal #define serial_irq(nr)		(1 + (nr))
23*2f030d28SRajnesh Kanwal #define SERIAL8250_BUS_TYPE	DEVICE_BUS_MMIO
2445b4968eSAndre Przywara #else
2545b4968eSAndre Przywara #define serial_iobase_0		(KVM_IOPORT_AREA + 0x3f8)
2645b4968eSAndre Przywara #define serial_iobase_1		(KVM_IOPORT_AREA + 0x2f8)
2745b4968eSAndre Przywara #define serial_iobase_2		(KVM_IOPORT_AREA + 0x3e8)
2845b4968eSAndre Przywara #define serial_iobase_3		(KVM_IOPORT_AREA + 0x2e8)
2945b4968eSAndre Przywara #define serial_irq_0		4
3045b4968eSAndre Przywara #define serial_irq_1		3
3145b4968eSAndre Przywara #define serial_irq_2		4
3245b4968eSAndre Przywara #define serial_irq_3		3
3345b4968eSAndre Przywara #define serial_iobase(nr)	serial_iobase_##nr
3445b4968eSAndre Przywara #define serial_irq(nr)		serial_irq_##nr
3545b4968eSAndre Przywara #define SERIAL8250_BUS_TYPE	DEVICE_BUS_IOPORT
3645b4968eSAndre Przywara #endif
3745b4968eSAndre Przywara 
38d4b02a37SThomas Gleixner /*
39d4b02a37SThomas Gleixner  * This fakes a U6_16550A. The fifo len needs to be 64 as the kernel
40d4b02a37SThomas Gleixner  * expects that for autodetection.
41d4b02a37SThomas Gleixner  */
42d4b02a37SThomas Gleixner #define FIFO_LEN		64
43d4b02a37SThomas Gleixner #define FIFO_MASK		(FIFO_LEN - 1)
44d4b02a37SThomas Gleixner 
45d4b02a37SThomas Gleixner #define UART_IIR_TYPE_BITS	0xc0
46d4b02a37SThomas Gleixner 
4746aa8d69SPekka Enberg struct serial8250_device {
48a81be31eSAndre Przywara 	struct device_header	dev_hdr;
49d3476f7dSSasha Levin 	struct mutex		mutex;
501add4b76SSasha Levin 	u8			id;
512932c9ebSPekka Enberg 
5245b4968eSAndre Przywara 	u32			iobase;
533fdf659dSSasha Levin 	u8			irq;
54f6b8ccc1SThomas Gleixner 	u8			irq_state;
558dfae8beSThomas Gleixner 	int			txcnt;
56d4b02a37SThomas Gleixner 	int			rxcnt;
57d4b02a37SThomas Gleixner 	int			rxdone;
58d4b02a37SThomas Gleixner 	char			txbuf[FIFO_LEN];
59d4b02a37SThomas Gleixner 	char			rxbuf[FIFO_LEN];
6076b4a122SPekka Enberg 
613fdf659dSSasha Levin 	u8			dll;
623fdf659dSSasha Levin 	u8			dlm;
633fdf659dSSasha Levin 	u8			iir;
643fdf659dSSasha Levin 	u8			ier;
653fdf659dSSasha Levin 	u8			fcr;
663fdf659dSSasha Levin 	u8			lcr;
673fdf659dSSasha Levin 	u8			mcr;
683fdf659dSSasha Levin 	u8			lsr;
693fdf659dSSasha Levin 	u8			msr;
703fdf659dSSasha Levin 	u8			scr;
7146aa8d69SPekka Enberg };
7246aa8d69SPekka Enberg 
73f3efa592SLiming Wang #define SERIAL_REGS_SETTING \
74f3efa592SLiming Wang 	.iir			= UART_IIR_NO_INT, \
75f3efa592SLiming Wang 	.lsr			= UART_LSR_TEMT | UART_LSR_THRE, \
76f3efa592SLiming Wang 	.msr			= UART_MSR_DCD | UART_MSR_DSR | UART_MSR_CTS, \
77f3efa592SLiming Wang 	.mcr			= UART_MCR_OUT2,
78f3efa592SLiming Wang 
79a81be31eSAndre Przywara #ifdef CONFIG_HAS_LIBFDT
80a81be31eSAndre Przywara static
81a81be31eSAndre Przywara void serial8250_generate_fdt_node(void *fdt, struct device_header *dev_hdr,
82a81be31eSAndre Przywara 				  fdt_irq_fn irq_fn);
83a81be31eSAndre Przywara #else
84a81be31eSAndre Przywara #define serial8250_generate_fdt_node	NULL
85a81be31eSAndre Przywara #endif
86e62c18deSPekka Enberg static struct serial8250_device devices[] = {
87c6a69c61SPekka Enberg 	/* ttyS0 */
88c6a69c61SPekka Enberg 	[0]	= {
89a81be31eSAndre Przywara 		.dev_hdr = {
9045b4968eSAndre Przywara 			.bus_type	= SERIAL8250_BUS_TYPE,
91a81be31eSAndre Przywara 			.data		= serial8250_generate_fdt_node,
92a81be31eSAndre Przywara 		},
93d3476f7dSSasha Levin 		.mutex			= MUTEX_INITIALIZER,
942932c9ebSPekka Enberg 
951add4b76SSasha Levin 		.id			= 0,
9645b4968eSAndre Przywara 		.iobase			= serial_iobase(0),
9745b4968eSAndre Przywara 		.irq			= serial_irq(0),
98e557eef9SPekka Enberg 
99f3efa592SLiming Wang 		SERIAL_REGS_SETTING
100c6a69c61SPekka Enberg 	},
101e62c18deSPekka Enberg 	/* ttyS1 */
102e62c18deSPekka Enberg 	[1]	= {
103a81be31eSAndre Przywara 		.dev_hdr = {
10445b4968eSAndre Przywara 			.bus_type	= SERIAL8250_BUS_TYPE,
105a81be31eSAndre Przywara 			.data		= serial8250_generate_fdt_node,
106a81be31eSAndre Przywara 		},
107d3476f7dSSasha Levin 		.mutex			= MUTEX_INITIALIZER,
1082932c9ebSPekka Enberg 
1091add4b76SSasha Levin 		.id			= 1,
11045b4968eSAndre Przywara 		.iobase			= serial_iobase(1),
11145b4968eSAndre Przywara 		.irq			= serial_irq(1),
112133bedc1SPekka Enberg 
113f3efa592SLiming Wang 		SERIAL_REGS_SETTING
114e62c18deSPekka Enberg 	},
115e62c18deSPekka Enberg 	/* ttyS2 */
116e62c18deSPekka Enberg 	[2]	= {
117a81be31eSAndre Przywara 		.dev_hdr = {
11845b4968eSAndre Przywara 			.bus_type	= SERIAL8250_BUS_TYPE,
119a81be31eSAndre Przywara 			.data		= serial8250_generate_fdt_node,
120a81be31eSAndre Przywara 		},
121d3476f7dSSasha Levin 		.mutex			= MUTEX_INITIALIZER,
1222932c9ebSPekka Enberg 
1231add4b76SSasha Levin 		.id			= 2,
12445b4968eSAndre Przywara 		.iobase			= serial_iobase(2),
12545b4968eSAndre Przywara 		.irq			= serial_irq(2),
126133bedc1SPekka Enberg 
127f3efa592SLiming Wang 		SERIAL_REGS_SETTING
128e62c18deSPekka Enberg 	},
129bf459c83SPekka Enberg 	/* ttyS3 */
130bf459c83SPekka Enberg 	[3]	= {
131a81be31eSAndre Przywara 		.dev_hdr = {
13245b4968eSAndre Przywara 			.bus_type	= SERIAL8250_BUS_TYPE,
133a81be31eSAndre Przywara 			.data		= serial8250_generate_fdt_node,
134a81be31eSAndre Przywara 		},
135d3476f7dSSasha Levin 		.mutex			= MUTEX_INITIALIZER,
136bf459c83SPekka Enberg 
1371add4b76SSasha Levin 		.id			= 3,
13845b4968eSAndre Przywara 		.iobase			= serial_iobase(3),
13945b4968eSAndre Przywara 		.irq			= serial_irq(3),
140bf459c83SPekka Enberg 
141f3efa592SLiming Wang 		SERIAL_REGS_SETTING
142bf459c83SPekka Enberg 	},
14346aa8d69SPekka Enberg };
14446aa8d69SPekka Enberg 
serial8250_flush_tx(struct kvm * kvm,struct serial8250_device * dev)1452651ea58SSasha Levin static void serial8250_flush_tx(struct kvm *kvm, struct serial8250_device *dev)
146d4b02a37SThomas Gleixner {
147d4b02a37SThomas Gleixner 	dev->lsr |= UART_LSR_TEMT | UART_LSR_THRE;
148d4b02a37SThomas Gleixner 
149d4b02a37SThomas Gleixner 	if (dev->txcnt) {
1502651ea58SSasha Levin 		term_putc(dev->txbuf, dev->txcnt, dev->id);
151d4b02a37SThomas Gleixner 		dev->txcnt = 0;
152d4b02a37SThomas Gleixner 	}
153d4b02a37SThomas Gleixner }
154d4b02a37SThomas Gleixner 
serial8250_update_irq(struct kvm * kvm,struct serial8250_device * dev)155f6b8ccc1SThomas Gleixner static void serial8250_update_irq(struct kvm *kvm, struct serial8250_device *dev)
156f6b8ccc1SThomas Gleixner {
157f6b8ccc1SThomas Gleixner 	u8 iir = 0;
158f6b8ccc1SThomas Gleixner 
159d4b02a37SThomas Gleixner 	/* Handle clear rx */
160d4b02a37SThomas Gleixner 	if (dev->lcr & UART_FCR_CLEAR_RCVR) {
161d4b02a37SThomas Gleixner 		dev->lcr &= ~UART_FCR_CLEAR_RCVR;
162d4b02a37SThomas Gleixner 		dev->rxcnt = dev->rxdone = 0;
163d4b02a37SThomas Gleixner 		dev->lsr &= ~UART_LSR_DR;
164d4b02a37SThomas Gleixner 	}
165d4b02a37SThomas Gleixner 
166d4b02a37SThomas Gleixner 	/* Handle clear tx */
167d4b02a37SThomas Gleixner 	if (dev->lcr & UART_FCR_CLEAR_XMIT) {
168d4b02a37SThomas Gleixner 		dev->lcr &= ~UART_FCR_CLEAR_XMIT;
169d4b02a37SThomas Gleixner 		dev->txcnt = 0;
170d4b02a37SThomas Gleixner 		dev->lsr |= UART_LSR_TEMT | UART_LSR_THRE;
171d4b02a37SThomas Gleixner 	}
172d4b02a37SThomas Gleixner 
173f6b8ccc1SThomas Gleixner 	/* Data ready and rcv interrupt enabled ? */
174f6b8ccc1SThomas Gleixner 	if ((dev->ier & UART_IER_RDI) && (dev->lsr & UART_LSR_DR))
175f6b8ccc1SThomas Gleixner 		iir |= UART_IIR_RDI;
176f6b8ccc1SThomas Gleixner 
177f6b8ccc1SThomas Gleixner 	/* Transmitter empty and interrupt enabled ? */
178f6b8ccc1SThomas Gleixner 	if ((dev->ier & UART_IER_THRI) && (dev->lsr & UART_LSR_TEMT))
179f6b8ccc1SThomas Gleixner 		iir |= UART_IIR_THRI;
180f6b8ccc1SThomas Gleixner 
181f6b8ccc1SThomas Gleixner 	/* Now update the irq line, if necessary */
182f6b8ccc1SThomas Gleixner 	if (!iir) {
183f6b8ccc1SThomas Gleixner 		dev->iir = UART_IIR_NO_INT;
184f6b8ccc1SThomas Gleixner 		if (dev->irq_state)
185f6b8ccc1SThomas Gleixner 			kvm__irq_line(kvm, dev->irq, 0);
186f6b8ccc1SThomas Gleixner 	} else {
187f6b8ccc1SThomas Gleixner 		dev->iir = iir;
188f6b8ccc1SThomas Gleixner 		if (!dev->irq_state)
189f6b8ccc1SThomas Gleixner 			kvm__irq_line(kvm, dev->irq, 1);
190f6b8ccc1SThomas Gleixner 	}
191f6b8ccc1SThomas Gleixner 	dev->irq_state = iir;
1928dfae8beSThomas Gleixner 
1938dfae8beSThomas Gleixner 	/*
1948dfae8beSThomas Gleixner 	 * If the kernel disabled the tx interrupt, we know that there
1958dfae8beSThomas Gleixner 	 * is nothing more to transmit, so we can reset our tx logic
1968dfae8beSThomas Gleixner 	 * here.
1978dfae8beSThomas Gleixner 	 */
198d4b02a37SThomas Gleixner 	if (!(dev->ier & UART_IER_THRI))
1992651ea58SSasha Levin 		serial8250_flush_tx(kvm, dev);
200f6b8ccc1SThomas Gleixner }
201f6b8ccc1SThomas Gleixner 
202a428f72eSPekka Enberg #define SYSRQ_PENDING_NONE		0
203a428f72eSPekka Enberg 
204a428f72eSPekka Enberg static int sysrq_pending;
205a428f72eSPekka Enberg 
serial8250__sysrq(struct kvm * kvm,struct serial8250_device * dev)20643835ac9SSasha Levin static void serial8250__sysrq(struct kvm *kvm, struct serial8250_device *dev)
207a428f72eSPekka Enberg {
208a428f72eSPekka Enberg 	dev->lsr |= UART_LSR_DR | UART_LSR_BI;
209226e727bSSasha Levin 	dev->rxbuf[dev->rxcnt++] = sysrq_pending;
210a428f72eSPekka Enberg 	sysrq_pending	= SYSRQ_PENDING_NONE;
211a428f72eSPekka Enberg }
212a428f72eSPekka Enberg 
serial8250__receive(struct kvm * kvm,struct serial8250_device * dev,bool handle_sysrq)213d4b02a37SThomas Gleixner static void serial8250__receive(struct kvm *kvm, struct serial8250_device *dev,
214d4b02a37SThomas Gleixner 				bool handle_sysrq)
215251cf9a6SPekka Enberg {
216251cf9a6SPekka Enberg 	int c;
217251cf9a6SPekka Enberg 
218d4b02a37SThomas Gleixner 	if (dev->mcr & UART_MCR_LOOP)
219db34045cSPekka Enberg 		return;
220db34045cSPekka Enberg 
221d4b02a37SThomas Gleixner 	if ((dev->lsr & UART_LSR_DR) || dev->rxcnt)
222d4b02a37SThomas Gleixner 		return;
223d4b02a37SThomas Gleixner 
224d4b02a37SThomas Gleixner 	if (handle_sysrq && sysrq_pending) {
22543835ac9SSasha Levin 		serial8250__sysrq(kvm, dev);
226a428f72eSPekka Enberg 		return;
227a428f72eSPekka Enberg 	}
228a428f72eSPekka Enberg 
2292651ea58SSasha Levin 	if (kvm->cfg.active_console != CONSOLE_8250)
2302651ea58SSasha Levin 		return;
2312651ea58SSasha Levin 
2322651ea58SSasha Levin 	while (term_readable(dev->id) &&
233d4b02a37SThomas Gleixner 	       dev->rxcnt < FIFO_LEN) {
234251cf9a6SPekka Enberg 
2354346fd8fSSasha Levin 		c = term_getc(kvm, dev->id);
23605d1a2a6SAsias He 
237251cf9a6SPekka Enberg 		if (c < 0)
238d4b02a37SThomas Gleixner 			break;
239d4b02a37SThomas Gleixner 		dev->rxbuf[dev->rxcnt++] = c;
240251cf9a6SPekka Enberg 		dev->lsr |= UART_LSR_DR;
241251cf9a6SPekka Enberg 	}
242d4b02a37SThomas Gleixner }
243251cf9a6SPekka Enberg 
serial8250__update_consoles(struct kvm * kvm)244f6b8ccc1SThomas Gleixner void serial8250__update_consoles(struct kvm *kvm)
2458bb34e0dSPekka Enberg {
246479de16fSCyrill Gorcunov 	unsigned int i;
2471add4b76SSasha Levin 
248479de16fSCyrill Gorcunov 	for (i = 0; i < ARRAY_SIZE(devices); i++) {
2491add4b76SSasha Levin 		struct serial8250_device *dev = &devices[i];
250934c193bSPekka Enberg 
2514ef0f4d6SPekka Enberg 		mutex_lock(&dev->mutex);
2522932c9ebSPekka Enberg 
253d4b02a37SThomas Gleixner 		/* Restrict sysrq injection to the first port */
254d4b02a37SThomas Gleixner 		serial8250__receive(kvm, dev, i == 0);
255251cf9a6SPekka Enberg 
256f6b8ccc1SThomas Gleixner 		serial8250_update_irq(kvm, dev);
2572932c9ebSPekka Enberg 
2584ef0f4d6SPekka Enberg 		mutex_unlock(&dev->mutex);
2598bb34e0dSPekka Enberg 	}
2601add4b76SSasha Levin }
2618bb34e0dSPekka Enberg 
serial8250__inject_sysrq(struct kvm * kvm,char sysrq)262226e727bSSasha Levin void serial8250__inject_sysrq(struct kvm *kvm, char sysrq)
263a428f72eSPekka Enberg {
264226e727bSSasha Levin 	sysrq_pending = sysrq;
265a428f72eSPekka Enberg }
266a428f72eSPekka Enberg 
serial8250_out(struct serial8250_device * dev,struct kvm_cpu * vcpu,u16 offset,void * data)26747a51060SAndre Przywara static bool serial8250_out(struct serial8250_device *dev, struct kvm_cpu *vcpu,
26847a51060SAndre Przywara 			   u16 offset, void *data)
26913a7760fSPekka Enberg {
2702932c9ebSPekka Enberg 	bool ret = true;
271d4b02a37SThomas Gleixner 	char *addr = data;
27246aa8d69SPekka Enberg 
2734ef0f4d6SPekka Enberg 	mutex_lock(&dev->mutex);
2742932c9ebSPekka Enberg 
27546aa8d69SPekka Enberg 	switch (offset) {
276c59fa0c4SThomas Gleixner 	case UART_TX:
277d4b02a37SThomas Gleixner 		if (dev->lcr & UART_LCR_DLAB) {
278c59fa0c4SThomas Gleixner 			dev->dll = ioport__read8(data);
279d4b02a37SThomas Gleixner 			break;
280d4b02a37SThomas Gleixner 		}
281d4b02a37SThomas Gleixner 
282d4b02a37SThomas Gleixner 		/* Loopback mode */
283d4b02a37SThomas Gleixner 		if (dev->mcr & UART_MCR_LOOP) {
284d4b02a37SThomas Gleixner 			if (dev->rxcnt < FIFO_LEN) {
285d4b02a37SThomas Gleixner 				dev->rxbuf[dev->rxcnt++] = *addr;
286d4b02a37SThomas Gleixner 				dev->lsr |= UART_LSR_DR;
287d4b02a37SThomas Gleixner 			}
288d4b02a37SThomas Gleixner 			break;
289d4b02a37SThomas Gleixner 		}
290d4b02a37SThomas Gleixner 
291d4b02a37SThomas Gleixner 		if (dev->txcnt < FIFO_LEN) {
292d4b02a37SThomas Gleixner 			dev->txbuf[dev->txcnt++] = *addr;
293d4b02a37SThomas Gleixner 			dev->lsr &= ~UART_LSR_TEMT;
294d4b02a37SThomas Gleixner 			if (dev->txcnt == FIFO_LEN / 2)
295d4b02a37SThomas Gleixner 				dev->lsr &= ~UART_LSR_THRE;
2964123ca55SMarc Zyngier 			serial8250_flush_tx(vcpu->kvm, dev);
297d4b02a37SThomas Gleixner 		} else {
298d4b02a37SThomas Gleixner 			/* Should never happpen */
299d4b02a37SThomas Gleixner 			dev->lsr &= ~(UART_LSR_TEMT | UART_LSR_THRE);
30046aa8d69SPekka Enberg 		}
301369c01c0SPekka Enberg 		break;
3024e49b05bSCyrill Gorcunov 	case UART_IER:
303f6b8ccc1SThomas Gleixner 		if (!(dev->lcr & UART_LCR_DLAB))
304d4b02a37SThomas Gleixner 			dev->ier = ioport__read8(data) & 0x0f;
305f6b8ccc1SThomas Gleixner 		else
306c59fa0c4SThomas Gleixner 			dev->dlm = ioport__read8(data);
307c59fa0c4SThomas Gleixner 		break;
308c59fa0c4SThomas Gleixner 	case UART_FCR:
309c59fa0c4SThomas Gleixner 		dev->fcr = ioport__read8(data);
31046aa8d69SPekka Enberg 		break;
311369c01c0SPekka Enberg 	case UART_LCR:
312369c01c0SPekka Enberg 		dev->lcr = ioport__read8(data);
313369c01c0SPekka Enberg 		break;
314369c01c0SPekka Enberg 	case UART_MCR:
315369c01c0SPekka Enberg 		dev->mcr = ioport__read8(data);
316369c01c0SPekka Enberg 		break;
317369c01c0SPekka Enberg 	case UART_LSR:
318369c01c0SPekka Enberg 		/* Factory test */
319369c01c0SPekka Enberg 		break;
320369c01c0SPekka Enberg 	case UART_MSR:
321369c01c0SPekka Enberg 		/* Not used */
322369c01c0SPekka Enberg 		break;
323369c01c0SPekka Enberg 	case UART_SCR:
324369c01c0SPekka Enberg 		dev->scr = ioport__read8(data);
325369c01c0SPekka Enberg 		break;
326369c01c0SPekka Enberg 	default:
3272932c9ebSPekka Enberg 		ret = false;
328d2ea115dSThomas Gleixner 		break;
32946aa8d69SPekka Enberg 	}
3302932c9ebSPekka Enberg 
3314123ca55SMarc Zyngier 	serial8250_update_irq(vcpu->kvm, dev);
332f6b8ccc1SThomas Gleixner 
3334ef0f4d6SPekka Enberg 	mutex_unlock(&dev->mutex);
3342932c9ebSPekka Enberg 
3352932c9ebSPekka Enberg 	return ret;
33613a7760fSPekka Enberg }
33713a7760fSPekka Enberg 
serial8250_rx(struct serial8250_device * dev,void * data)338d4b02a37SThomas Gleixner static void serial8250_rx(struct serial8250_device *dev, void *data)
339d4b02a37SThomas Gleixner {
340d4b02a37SThomas Gleixner 	if (dev->rxdone == dev->rxcnt)
341d4b02a37SThomas Gleixner 		return;
342d4b02a37SThomas Gleixner 
343d4b02a37SThomas Gleixner 	/* Break issued ? */
344d4b02a37SThomas Gleixner 	if (dev->lsr & UART_LSR_BI) {
345d4b02a37SThomas Gleixner 		dev->lsr &= ~UART_LSR_BI;
346d4b02a37SThomas Gleixner 		ioport__write8(data, 0);
347d4b02a37SThomas Gleixner 		return;
348d4b02a37SThomas Gleixner 	}
349d4b02a37SThomas Gleixner 
350d4b02a37SThomas Gleixner 	ioport__write8(data, dev->rxbuf[dev->rxdone++]);
351d4b02a37SThomas Gleixner 	if (dev->rxcnt == dev->rxdone) {
352d4b02a37SThomas Gleixner 		dev->lsr &= ~UART_LSR_DR;
353d4b02a37SThomas Gleixner 		dev->rxcnt = dev->rxdone = 0;
354d4b02a37SThomas Gleixner 	}
355d4b02a37SThomas Gleixner }
356d4b02a37SThomas Gleixner 
serial8250_in(struct serial8250_device * dev,struct kvm_cpu * vcpu,u16 offset,void * data)35747a51060SAndre Przywara static bool serial8250_in(struct serial8250_device *dev, struct kvm_cpu *vcpu,
35847a51060SAndre Przywara 			  u16 offset, void *data)
35925af6674SPekka Enberg {
3602932c9ebSPekka Enberg 	bool ret = true;
36146aa8d69SPekka Enberg 
3624ef0f4d6SPekka Enberg 	mutex_lock(&dev->mutex);
3632932c9ebSPekka Enberg 
36446aa8d69SPekka Enberg 	switch (offset) {
365251cf9a6SPekka Enberg 	case UART_RX:
366d4b02a37SThomas Gleixner 		if (dev->lcr & UART_LCR_DLAB)
367c59fa0c4SThomas Gleixner 			ioport__write8(data, dev->dll);
368d4b02a37SThomas Gleixner 		else
369d4b02a37SThomas Gleixner 			serial8250_rx(dev, data);
370369c01c0SPekka Enberg 		break;
371c59fa0c4SThomas Gleixner 	case UART_IER:
372c59fa0c4SThomas Gleixner 		if (dev->lcr & UART_LCR_DLAB)
373c59fa0c4SThomas Gleixner 			ioport__write8(data, dev->dlm);
374c59fa0c4SThomas Gleixner 		else
375c59fa0c4SThomas Gleixner 			ioport__write8(data, dev->ier);
376c59fa0c4SThomas Gleixner 		break;
377f6b8ccc1SThomas Gleixner 	case UART_IIR:
378d4b02a37SThomas Gleixner 		ioport__write8(data, dev->iir | UART_IIR_TYPE_BITS);
37946aa8d69SPekka Enberg 		break;
3804e49b05bSCyrill Gorcunov 	case UART_LCR:
381c6a69c61SPekka Enberg 		ioport__write8(data, dev->lcr);
38246aa8d69SPekka Enberg 		break;
3834e49b05bSCyrill Gorcunov 	case UART_MCR:
384c6a69c61SPekka Enberg 		ioport__write8(data, dev->mcr);
38546aa8d69SPekka Enberg 		break;
3864e49b05bSCyrill Gorcunov 	case UART_LSR:
387c6a69c61SPekka Enberg 		ioport__write8(data, dev->lsr);
38846aa8d69SPekka Enberg 		break;
3894e49b05bSCyrill Gorcunov 	case UART_MSR:
390369c01c0SPekka Enberg 		ioport__write8(data, dev->msr);
39146aa8d69SPekka Enberg 		break;
3924e49b05bSCyrill Gorcunov 	case UART_SCR:
393369c01c0SPekka Enberg 		ioport__write8(data, dev->scr);
39446aa8d69SPekka Enberg 		break;
395369c01c0SPekka Enberg 	default:
3962932c9ebSPekka Enberg 		ret = false;
397c59fa0c4SThomas Gleixner 		break;
39825af6674SPekka Enberg 	}
399f6b8ccc1SThomas Gleixner 
4004123ca55SMarc Zyngier 	serial8250_update_irq(vcpu->kvm, dev);
401f6b8ccc1SThomas Gleixner 
4024ef0f4d6SPekka Enberg 	mutex_unlock(&dev->mutex);
4032932c9ebSPekka Enberg 
4042932c9ebSPekka Enberg 	return ret;
40513a7760fSPekka Enberg }
40613a7760fSPekka Enberg 
serial8250_mmio(struct kvm_cpu * vcpu,u64 addr,u8 * data,u32 len,u8 is_write,void * ptr)40747a51060SAndre Przywara static void serial8250_mmio(struct kvm_cpu *vcpu, u64 addr, u8 *data, u32 len,
40847a51060SAndre Przywara 			    u8 is_write, void *ptr)
40947a51060SAndre Przywara {
41047a51060SAndre Przywara 	struct serial8250_device *dev = ptr;
41147a51060SAndre Przywara 
41247a51060SAndre Przywara 	if (is_write)
41347a51060SAndre Przywara 		serial8250_out(dev, vcpu, addr - dev->iobase, data);
41447a51060SAndre Przywara 	else
41547a51060SAndre Przywara 		serial8250_in(dev, vcpu, addr - dev->iobase, data);
41647a51060SAndre Przywara }
41747a51060SAndre Przywara 
418d28abb58SWill Deacon #ifdef CONFIG_HAS_LIBFDT
41956e45ea4SAndre Przywara 
42056e45ea4SAndre Przywara char *fdt_stdout_path = NULL;
42156e45ea4SAndre Przywara 
422e5965f36SMarc Zyngier #define DEVICE_NAME_MAX_LEN 32
4232bfd9ac3SAndre Przywara static
serial8250_generate_fdt_node(void * fdt,struct device_header * dev_hdr,fdt_irq_fn irq_fn)424a81be31eSAndre Przywara void serial8250_generate_fdt_node(void *fdt, struct device_header *dev_hdr,
425a81be31eSAndre Przywara 				  fdt_irq_fn irq_fn)
426d28abb58SWill Deacon {
427e5965f36SMarc Zyngier 	char dev_name[DEVICE_NAME_MAX_LEN];
428a81be31eSAndre Przywara 	struct serial8250_device *dev = container_of(dev_hdr,
429a81be31eSAndre Przywara 						     struct serial8250_device,
430a81be31eSAndre Przywara 						     dev_hdr);
431a81be31eSAndre Przywara 
43245b4968eSAndre Przywara 	u64 addr = dev->iobase;
433d28abb58SWill Deacon 	u64 reg_prop[] = {
434e5965f36SMarc Zyngier 		cpu_to_fdt64(addr),
435d28abb58SWill Deacon 		cpu_to_fdt64(8),
436d28abb58SWill Deacon 	};
437d28abb58SWill Deacon 
438e5965f36SMarc Zyngier 	snprintf(dev_name, DEVICE_NAME_MAX_LEN, "U6_16550A@%llx", addr);
439e5965f36SMarc Zyngier 
44056e45ea4SAndre Przywara 	if (!fdt_stdout_path) {
44156e45ea4SAndre Przywara 		fdt_stdout_path = malloc(strlen(dev_name) + 2);
44256e45ea4SAndre Przywara 		/* Assumes that this node is a child of the root node. */
44356e45ea4SAndre Przywara 		sprintf(fdt_stdout_path, "/%s", dev_name);
44456e45ea4SAndre Przywara 	}
44556e45ea4SAndre Przywara 
446e5965f36SMarc Zyngier 	_FDT(fdt_begin_node(fdt, dev_name));
447d28abb58SWill Deacon 	_FDT(fdt_property_string(fdt, "compatible", "ns16550a"));
448d28abb58SWill Deacon 	_FDT(fdt_property(fdt, "reg", reg_prop, sizeof(reg_prop)));
449a81be31eSAndre Przywara 	irq_fn(fdt, dev->irq, IRQ_TYPE_LEVEL_HIGH);
450d28abb58SWill Deacon 	_FDT(fdt_property_cell(fdt, "clock-frequency", 1843200));
451d28abb58SWill Deacon 	_FDT(fdt_end_node(fdt));
452d28abb58SWill Deacon }
453d28abb58SWill Deacon #endif
454d28abb58SWill Deacon 
serial8250__device_init(struct kvm * kvm,struct serial8250_device * dev)455a81be31eSAndre Przywara static int serial8250__device_init(struct kvm *kvm,
456a81be31eSAndre Przywara 				   struct serial8250_device *dev)
457bc4b0ffeSPekka Enberg {
45820715a22SSasha Levin 	int r;
45920715a22SSasha Levin 
460a81be31eSAndre Przywara 	r = device__register(&dev->dev_hdr);
461a81be31eSAndre Przywara 	if (r < 0)
462a81be31eSAndre Przywara 		return r;
463a81be31eSAndre Przywara 
464206c41f4SWill Deacon 	ioport__map_irq(&dev->irq);
46545b4968eSAndre Przywara 	r = kvm__register_iotrap(kvm, dev->iobase, 8, serial8250_mmio, dev,
46645b4968eSAndre Przywara 				 SERIAL8250_BUS_TYPE);
46720715a22SSasha Levin 
46820715a22SSasha Levin 	return r;
469bc4b0ffeSPekka Enberg }
470bc4b0ffeSPekka Enberg 
serial8250__init(struct kvm * kvm)47120715a22SSasha Levin int serial8250__init(struct kvm *kvm)
47213a7760fSPekka Enberg {
47320715a22SSasha Levin 	unsigned int i, j;
47420715a22SSasha Levin 	int r = 0;
475c6a69c61SPekka Enberg 
476c6a69c61SPekka Enberg 	for (i = 0; i < ARRAY_SIZE(devices); i++) {
477c6a69c61SPekka Enberg 		struct serial8250_device *dev = &devices[i];
478c6a69c61SPekka Enberg 
47920715a22SSasha Levin 		r = serial8250__device_init(kvm, dev);
48020715a22SSasha Levin 		if (r < 0)
48120715a22SSasha Levin 			goto cleanup;
482c6a69c61SPekka Enberg 	}
48320715a22SSasha Levin 
48420715a22SSasha Levin 	return r;
48520715a22SSasha Levin cleanup:
48620715a22SSasha Levin 	for (j = 0; j <= i; j++) {
48720715a22SSasha Levin 		struct serial8250_device *dev = &devices[j];
48820715a22SSasha Levin 
48945b4968eSAndre Przywara 		kvm__deregister_iotrap(kvm, dev->iobase, SERIAL8250_BUS_TYPE);
490a81be31eSAndre Przywara 		device__unregister(&dev->dev_hdr);
49120715a22SSasha Levin 	}
49220715a22SSasha Levin 
49320715a22SSasha Levin 	return r;
49420715a22SSasha Levin }
49549a8afd1SSasha Levin dev_init(serial8250__init);
49620715a22SSasha Levin 
serial8250__exit(struct kvm * kvm)49720715a22SSasha Levin int serial8250__exit(struct kvm *kvm)
49820715a22SSasha Levin {
49920715a22SSasha Levin 	unsigned int i;
50020715a22SSasha Levin 	int r;
50120715a22SSasha Levin 
50220715a22SSasha Levin 	for (i = 0; i < ARRAY_SIZE(devices); i++) {
50320715a22SSasha Levin 		struct serial8250_device *dev = &devices[i];
50420715a22SSasha Levin 
50545b4968eSAndre Przywara 		r = kvm__deregister_iotrap(kvm, dev->iobase,
50645b4968eSAndre Przywara 					   SERIAL8250_BUS_TYPE);
50720715a22SSasha Levin 		if (r < 0)
50820715a22SSasha Levin 			return r;
509a81be31eSAndre Przywara 		device__unregister(&dev->dev_hdr);
51020715a22SSasha Levin 	}
51120715a22SSasha Levin 
51220715a22SSasha Levin 	return 0;
51313a7760fSPekka Enberg }
51449a8afd1SSasha Levin dev_exit(serial8250__exit);
515