xref: /kvmtool/hw/serial.c (revision 45b4968e0de1559d6ab32475bf6011dbb07e020c)
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 
16*45b4968eSAndre Przywara #if defined(CONFIG_ARM) || defined(CONFIG_ARM64)
17*45b4968eSAndre Przywara #define serial_iobase(nr)	(ARM_UART_MMIO_BASE + (nr) * 0x1000)
18*45b4968eSAndre Przywara #define serial_irq(nr)		(32 + (nr))
19*45b4968eSAndre Przywara #define SERIAL8250_BUS_TYPE	DEVICE_BUS_MMIO
20*45b4968eSAndre Przywara #else
21*45b4968eSAndre Przywara #define serial_iobase_0		(KVM_IOPORT_AREA + 0x3f8)
22*45b4968eSAndre Przywara #define serial_iobase_1		(KVM_IOPORT_AREA + 0x2f8)
23*45b4968eSAndre Przywara #define serial_iobase_2		(KVM_IOPORT_AREA + 0x3e8)
24*45b4968eSAndre Przywara #define serial_iobase_3		(KVM_IOPORT_AREA + 0x2e8)
25*45b4968eSAndre Przywara #define serial_irq_0		4
26*45b4968eSAndre Przywara #define serial_irq_1		3
27*45b4968eSAndre Przywara #define serial_irq_2		4
28*45b4968eSAndre Przywara #define serial_irq_3		3
29*45b4968eSAndre Przywara #define serial_iobase(nr)	serial_iobase_##nr
30*45b4968eSAndre Przywara #define serial_irq(nr)		serial_irq_##nr
31*45b4968eSAndre Przywara #define SERIAL8250_BUS_TYPE	DEVICE_BUS_IOPORT
32*45b4968eSAndre Przywara #endif
33*45b4968eSAndre Przywara 
34d4b02a37SThomas Gleixner /*
35d4b02a37SThomas Gleixner  * This fakes a U6_16550A. The fifo len needs to be 64 as the kernel
36d4b02a37SThomas Gleixner  * expects that for autodetection.
37d4b02a37SThomas Gleixner  */
38d4b02a37SThomas Gleixner #define FIFO_LEN		64
39d4b02a37SThomas Gleixner #define FIFO_MASK		(FIFO_LEN - 1)
40d4b02a37SThomas Gleixner 
41d4b02a37SThomas Gleixner #define UART_IIR_TYPE_BITS	0xc0
42d4b02a37SThomas Gleixner 
4346aa8d69SPekka Enberg struct serial8250_device {
44a81be31eSAndre Przywara 	struct device_header	dev_hdr;
45d3476f7dSSasha Levin 	struct mutex		mutex;
461add4b76SSasha Levin 	u8			id;
472932c9ebSPekka Enberg 
48*45b4968eSAndre Przywara 	u32			iobase;
493fdf659dSSasha Levin 	u8			irq;
50f6b8ccc1SThomas Gleixner 	u8			irq_state;
518dfae8beSThomas Gleixner 	int			txcnt;
52d4b02a37SThomas Gleixner 	int			rxcnt;
53d4b02a37SThomas Gleixner 	int			rxdone;
54d4b02a37SThomas Gleixner 	char			txbuf[FIFO_LEN];
55d4b02a37SThomas Gleixner 	char			rxbuf[FIFO_LEN];
5676b4a122SPekka Enberg 
573fdf659dSSasha Levin 	u8			dll;
583fdf659dSSasha Levin 	u8			dlm;
593fdf659dSSasha Levin 	u8			iir;
603fdf659dSSasha Levin 	u8			ier;
613fdf659dSSasha Levin 	u8			fcr;
623fdf659dSSasha Levin 	u8			lcr;
633fdf659dSSasha Levin 	u8			mcr;
643fdf659dSSasha Levin 	u8			lsr;
653fdf659dSSasha Levin 	u8			msr;
663fdf659dSSasha Levin 	u8			scr;
6746aa8d69SPekka Enberg };
6846aa8d69SPekka Enberg 
69f3efa592SLiming Wang #define SERIAL_REGS_SETTING \
70f3efa592SLiming Wang 	.iir			= UART_IIR_NO_INT, \
71f3efa592SLiming Wang 	.lsr			= UART_LSR_TEMT | UART_LSR_THRE, \
72f3efa592SLiming Wang 	.msr			= UART_MSR_DCD | UART_MSR_DSR | UART_MSR_CTS, \
73f3efa592SLiming Wang 	.mcr			= UART_MCR_OUT2,
74f3efa592SLiming Wang 
75a81be31eSAndre Przywara #ifdef CONFIG_HAS_LIBFDT
76a81be31eSAndre Przywara static
77a81be31eSAndre Przywara void serial8250_generate_fdt_node(void *fdt, struct device_header *dev_hdr,
78a81be31eSAndre Przywara 				  fdt_irq_fn irq_fn);
79a81be31eSAndre Przywara #else
80a81be31eSAndre Przywara #define serial8250_generate_fdt_node	NULL
81a81be31eSAndre Przywara #endif
82e62c18deSPekka Enberg static struct serial8250_device devices[] = {
83c6a69c61SPekka Enberg 	/* ttyS0 */
84c6a69c61SPekka Enberg 	[0]	= {
85a81be31eSAndre Przywara 		.dev_hdr = {
86*45b4968eSAndre Przywara 			.bus_type	= SERIAL8250_BUS_TYPE,
87a81be31eSAndre Przywara 			.data		= serial8250_generate_fdt_node,
88a81be31eSAndre Przywara 		},
89d3476f7dSSasha Levin 		.mutex			= MUTEX_INITIALIZER,
902932c9ebSPekka Enberg 
911add4b76SSasha Levin 		.id			= 0,
92*45b4968eSAndre Przywara 		.iobase			= serial_iobase(0),
93*45b4968eSAndre Przywara 		.irq			= serial_irq(0),
94e557eef9SPekka Enberg 
95f3efa592SLiming Wang 		SERIAL_REGS_SETTING
96c6a69c61SPekka Enberg 	},
97e62c18deSPekka Enberg 	/* ttyS1 */
98e62c18deSPekka Enberg 	[1]	= {
99a81be31eSAndre Przywara 		.dev_hdr = {
100*45b4968eSAndre Przywara 			.bus_type	= SERIAL8250_BUS_TYPE,
101a81be31eSAndre Przywara 			.data		= serial8250_generate_fdt_node,
102a81be31eSAndre Przywara 		},
103d3476f7dSSasha Levin 		.mutex			= MUTEX_INITIALIZER,
1042932c9ebSPekka Enberg 
1051add4b76SSasha Levin 		.id			= 1,
106*45b4968eSAndre Przywara 		.iobase			= serial_iobase(1),
107*45b4968eSAndre Przywara 		.irq			= serial_irq(1),
108133bedc1SPekka Enberg 
109f3efa592SLiming Wang 		SERIAL_REGS_SETTING
110e62c18deSPekka Enberg 	},
111e62c18deSPekka Enberg 	/* ttyS2 */
112e62c18deSPekka Enberg 	[2]	= {
113a81be31eSAndre Przywara 		.dev_hdr = {
114*45b4968eSAndre Przywara 			.bus_type	= SERIAL8250_BUS_TYPE,
115a81be31eSAndre Przywara 			.data		= serial8250_generate_fdt_node,
116a81be31eSAndre Przywara 		},
117d3476f7dSSasha Levin 		.mutex			= MUTEX_INITIALIZER,
1182932c9ebSPekka Enberg 
1191add4b76SSasha Levin 		.id			= 2,
120*45b4968eSAndre Przywara 		.iobase			= serial_iobase(2),
121*45b4968eSAndre Przywara 		.irq			= serial_irq(2),
122133bedc1SPekka Enberg 
123f3efa592SLiming Wang 		SERIAL_REGS_SETTING
124e62c18deSPekka Enberg 	},
125bf459c83SPekka Enberg 	/* ttyS3 */
126bf459c83SPekka Enberg 	[3]	= {
127a81be31eSAndre Przywara 		.dev_hdr = {
128*45b4968eSAndre Przywara 			.bus_type	= SERIAL8250_BUS_TYPE,
129a81be31eSAndre Przywara 			.data		= serial8250_generate_fdt_node,
130a81be31eSAndre Przywara 		},
131d3476f7dSSasha Levin 		.mutex			= MUTEX_INITIALIZER,
132bf459c83SPekka Enberg 
1331add4b76SSasha Levin 		.id			= 3,
134*45b4968eSAndre Przywara 		.iobase			= serial_iobase(3),
135*45b4968eSAndre Przywara 		.irq			= serial_irq(3),
136bf459c83SPekka Enberg 
137f3efa592SLiming Wang 		SERIAL_REGS_SETTING
138bf459c83SPekka Enberg 	},
13946aa8d69SPekka Enberg };
14046aa8d69SPekka Enberg 
1412651ea58SSasha Levin static void serial8250_flush_tx(struct kvm *kvm, struct serial8250_device *dev)
142d4b02a37SThomas Gleixner {
143d4b02a37SThomas Gleixner 	dev->lsr |= UART_LSR_TEMT | UART_LSR_THRE;
144d4b02a37SThomas Gleixner 
145d4b02a37SThomas Gleixner 	if (dev->txcnt) {
1462651ea58SSasha Levin 		term_putc(dev->txbuf, dev->txcnt, dev->id);
147d4b02a37SThomas Gleixner 		dev->txcnt = 0;
148d4b02a37SThomas Gleixner 	}
149d4b02a37SThomas Gleixner }
150d4b02a37SThomas Gleixner 
151f6b8ccc1SThomas Gleixner static void serial8250_update_irq(struct kvm *kvm, struct serial8250_device *dev)
152f6b8ccc1SThomas Gleixner {
153f6b8ccc1SThomas Gleixner 	u8 iir = 0;
154f6b8ccc1SThomas Gleixner 
155d4b02a37SThomas Gleixner 	/* Handle clear rx */
156d4b02a37SThomas Gleixner 	if (dev->lcr & UART_FCR_CLEAR_RCVR) {
157d4b02a37SThomas Gleixner 		dev->lcr &= ~UART_FCR_CLEAR_RCVR;
158d4b02a37SThomas Gleixner 		dev->rxcnt = dev->rxdone = 0;
159d4b02a37SThomas Gleixner 		dev->lsr &= ~UART_LSR_DR;
160d4b02a37SThomas Gleixner 	}
161d4b02a37SThomas Gleixner 
162d4b02a37SThomas Gleixner 	/* Handle clear tx */
163d4b02a37SThomas Gleixner 	if (dev->lcr & UART_FCR_CLEAR_XMIT) {
164d4b02a37SThomas Gleixner 		dev->lcr &= ~UART_FCR_CLEAR_XMIT;
165d4b02a37SThomas Gleixner 		dev->txcnt = 0;
166d4b02a37SThomas Gleixner 		dev->lsr |= UART_LSR_TEMT | UART_LSR_THRE;
167d4b02a37SThomas Gleixner 	}
168d4b02a37SThomas Gleixner 
169f6b8ccc1SThomas Gleixner 	/* Data ready and rcv interrupt enabled ? */
170f6b8ccc1SThomas Gleixner 	if ((dev->ier & UART_IER_RDI) && (dev->lsr & UART_LSR_DR))
171f6b8ccc1SThomas Gleixner 		iir |= UART_IIR_RDI;
172f6b8ccc1SThomas Gleixner 
173f6b8ccc1SThomas Gleixner 	/* Transmitter empty and interrupt enabled ? */
174f6b8ccc1SThomas Gleixner 	if ((dev->ier & UART_IER_THRI) && (dev->lsr & UART_LSR_TEMT))
175f6b8ccc1SThomas Gleixner 		iir |= UART_IIR_THRI;
176f6b8ccc1SThomas Gleixner 
177f6b8ccc1SThomas Gleixner 	/* Now update the irq line, if necessary */
178f6b8ccc1SThomas Gleixner 	if (!iir) {
179f6b8ccc1SThomas Gleixner 		dev->iir = UART_IIR_NO_INT;
180f6b8ccc1SThomas Gleixner 		if (dev->irq_state)
181f6b8ccc1SThomas Gleixner 			kvm__irq_line(kvm, dev->irq, 0);
182f6b8ccc1SThomas Gleixner 	} else {
183f6b8ccc1SThomas Gleixner 		dev->iir = iir;
184f6b8ccc1SThomas Gleixner 		if (!dev->irq_state)
185f6b8ccc1SThomas Gleixner 			kvm__irq_line(kvm, dev->irq, 1);
186f6b8ccc1SThomas Gleixner 	}
187f6b8ccc1SThomas Gleixner 	dev->irq_state = iir;
1888dfae8beSThomas Gleixner 
1898dfae8beSThomas Gleixner 	/*
1908dfae8beSThomas Gleixner 	 * If the kernel disabled the tx interrupt, we know that there
1918dfae8beSThomas Gleixner 	 * is nothing more to transmit, so we can reset our tx logic
1928dfae8beSThomas Gleixner 	 * here.
1938dfae8beSThomas Gleixner 	 */
194d4b02a37SThomas Gleixner 	if (!(dev->ier & UART_IER_THRI))
1952651ea58SSasha Levin 		serial8250_flush_tx(kvm, dev);
196f6b8ccc1SThomas Gleixner }
197f6b8ccc1SThomas Gleixner 
198a428f72eSPekka Enberg #define SYSRQ_PENDING_NONE		0
199a428f72eSPekka Enberg 
200a428f72eSPekka Enberg static int sysrq_pending;
201a428f72eSPekka Enberg 
20243835ac9SSasha Levin static void serial8250__sysrq(struct kvm *kvm, struct serial8250_device *dev)
203a428f72eSPekka Enberg {
204a428f72eSPekka Enberg 	dev->lsr |= UART_LSR_DR | UART_LSR_BI;
205226e727bSSasha Levin 	dev->rxbuf[dev->rxcnt++] = sysrq_pending;
206a428f72eSPekka Enberg 	sysrq_pending	= SYSRQ_PENDING_NONE;
207a428f72eSPekka Enberg }
208a428f72eSPekka Enberg 
209d4b02a37SThomas Gleixner static void serial8250__receive(struct kvm *kvm, struct serial8250_device *dev,
210d4b02a37SThomas Gleixner 				bool handle_sysrq)
211251cf9a6SPekka Enberg {
212251cf9a6SPekka Enberg 	int c;
213251cf9a6SPekka Enberg 
214d4b02a37SThomas Gleixner 	if (dev->mcr & UART_MCR_LOOP)
215db34045cSPekka Enberg 		return;
216db34045cSPekka Enberg 
217d4b02a37SThomas Gleixner 	if ((dev->lsr & UART_LSR_DR) || dev->rxcnt)
218d4b02a37SThomas Gleixner 		return;
219d4b02a37SThomas Gleixner 
220d4b02a37SThomas Gleixner 	if (handle_sysrq && sysrq_pending) {
22143835ac9SSasha Levin 		serial8250__sysrq(kvm, dev);
222a428f72eSPekka Enberg 		return;
223a428f72eSPekka Enberg 	}
224a428f72eSPekka Enberg 
2252651ea58SSasha Levin 	if (kvm->cfg.active_console != CONSOLE_8250)
2262651ea58SSasha Levin 		return;
2272651ea58SSasha Levin 
2282651ea58SSasha Levin 	while (term_readable(dev->id) &&
229d4b02a37SThomas Gleixner 	       dev->rxcnt < FIFO_LEN) {
230251cf9a6SPekka Enberg 
2314346fd8fSSasha Levin 		c = term_getc(kvm, dev->id);
23205d1a2a6SAsias He 
233251cf9a6SPekka Enberg 		if (c < 0)
234d4b02a37SThomas Gleixner 			break;
235d4b02a37SThomas Gleixner 		dev->rxbuf[dev->rxcnt++] = c;
236251cf9a6SPekka Enberg 		dev->lsr |= UART_LSR_DR;
237251cf9a6SPekka Enberg 	}
238d4b02a37SThomas Gleixner }
239251cf9a6SPekka Enberg 
240f6b8ccc1SThomas Gleixner void serial8250__update_consoles(struct kvm *kvm)
2418bb34e0dSPekka Enberg {
242479de16fSCyrill Gorcunov 	unsigned int i;
2431add4b76SSasha Levin 
244479de16fSCyrill Gorcunov 	for (i = 0; i < ARRAY_SIZE(devices); i++) {
2451add4b76SSasha Levin 		struct serial8250_device *dev = &devices[i];
246934c193bSPekka Enberg 
2474ef0f4d6SPekka Enberg 		mutex_lock(&dev->mutex);
2482932c9ebSPekka Enberg 
249d4b02a37SThomas Gleixner 		/* Restrict sysrq injection to the first port */
250d4b02a37SThomas Gleixner 		serial8250__receive(kvm, dev, i == 0);
251251cf9a6SPekka Enberg 
252f6b8ccc1SThomas Gleixner 		serial8250_update_irq(kvm, dev);
2532932c9ebSPekka Enberg 
2544ef0f4d6SPekka Enberg 		mutex_unlock(&dev->mutex);
2558bb34e0dSPekka Enberg 	}
2561add4b76SSasha Levin }
2578bb34e0dSPekka Enberg 
258226e727bSSasha Levin void serial8250__inject_sysrq(struct kvm *kvm, char sysrq)
259a428f72eSPekka Enberg {
260226e727bSSasha Levin 	sysrq_pending = sysrq;
261a428f72eSPekka Enberg }
262a428f72eSPekka Enberg 
26347a51060SAndre Przywara static bool serial8250_out(struct serial8250_device *dev, struct kvm_cpu *vcpu,
26447a51060SAndre Przywara 			   u16 offset, void *data)
26513a7760fSPekka Enberg {
2662932c9ebSPekka Enberg 	bool ret = true;
267d4b02a37SThomas Gleixner 	char *addr = data;
26846aa8d69SPekka Enberg 
2694ef0f4d6SPekka Enberg 	mutex_lock(&dev->mutex);
2702932c9ebSPekka Enberg 
27146aa8d69SPekka Enberg 	switch (offset) {
272c59fa0c4SThomas Gleixner 	case UART_TX:
273d4b02a37SThomas Gleixner 		if (dev->lcr & UART_LCR_DLAB) {
274c59fa0c4SThomas Gleixner 			dev->dll = ioport__read8(data);
275d4b02a37SThomas Gleixner 			break;
276d4b02a37SThomas Gleixner 		}
277d4b02a37SThomas Gleixner 
278d4b02a37SThomas Gleixner 		/* Loopback mode */
279d4b02a37SThomas Gleixner 		if (dev->mcr & UART_MCR_LOOP) {
280d4b02a37SThomas Gleixner 			if (dev->rxcnt < FIFO_LEN) {
281d4b02a37SThomas Gleixner 				dev->rxbuf[dev->rxcnt++] = *addr;
282d4b02a37SThomas Gleixner 				dev->lsr |= UART_LSR_DR;
283d4b02a37SThomas Gleixner 			}
284d4b02a37SThomas Gleixner 			break;
285d4b02a37SThomas Gleixner 		}
286d4b02a37SThomas Gleixner 
287d4b02a37SThomas Gleixner 		if (dev->txcnt < FIFO_LEN) {
288d4b02a37SThomas Gleixner 			dev->txbuf[dev->txcnt++] = *addr;
289d4b02a37SThomas Gleixner 			dev->lsr &= ~UART_LSR_TEMT;
290d4b02a37SThomas Gleixner 			if (dev->txcnt == FIFO_LEN / 2)
291d4b02a37SThomas Gleixner 				dev->lsr &= ~UART_LSR_THRE;
2924123ca55SMarc Zyngier 			serial8250_flush_tx(vcpu->kvm, dev);
293d4b02a37SThomas Gleixner 		} else {
294d4b02a37SThomas Gleixner 			/* Should never happpen */
295d4b02a37SThomas Gleixner 			dev->lsr &= ~(UART_LSR_TEMT | UART_LSR_THRE);
29646aa8d69SPekka Enberg 		}
297369c01c0SPekka Enberg 		break;
2984e49b05bSCyrill Gorcunov 	case UART_IER:
299f6b8ccc1SThomas Gleixner 		if (!(dev->lcr & UART_LCR_DLAB))
300d4b02a37SThomas Gleixner 			dev->ier = ioport__read8(data) & 0x0f;
301f6b8ccc1SThomas Gleixner 		else
302c59fa0c4SThomas Gleixner 			dev->dlm = ioport__read8(data);
303c59fa0c4SThomas Gleixner 		break;
304c59fa0c4SThomas Gleixner 	case UART_FCR:
305c59fa0c4SThomas Gleixner 		dev->fcr = ioport__read8(data);
30646aa8d69SPekka Enberg 		break;
307369c01c0SPekka Enberg 	case UART_LCR:
308369c01c0SPekka Enberg 		dev->lcr = ioport__read8(data);
309369c01c0SPekka Enberg 		break;
310369c01c0SPekka Enberg 	case UART_MCR:
311369c01c0SPekka Enberg 		dev->mcr = ioport__read8(data);
312369c01c0SPekka Enberg 		break;
313369c01c0SPekka Enberg 	case UART_LSR:
314369c01c0SPekka Enberg 		/* Factory test */
315369c01c0SPekka Enberg 		break;
316369c01c0SPekka Enberg 	case UART_MSR:
317369c01c0SPekka Enberg 		/* Not used */
318369c01c0SPekka Enberg 		break;
319369c01c0SPekka Enberg 	case UART_SCR:
320369c01c0SPekka Enberg 		dev->scr = ioport__read8(data);
321369c01c0SPekka Enberg 		break;
322369c01c0SPekka Enberg 	default:
3232932c9ebSPekka Enberg 		ret = false;
324d2ea115dSThomas Gleixner 		break;
32546aa8d69SPekka Enberg 	}
3262932c9ebSPekka Enberg 
3274123ca55SMarc Zyngier 	serial8250_update_irq(vcpu->kvm, dev);
328f6b8ccc1SThomas Gleixner 
3294ef0f4d6SPekka Enberg 	mutex_unlock(&dev->mutex);
3302932c9ebSPekka Enberg 
3312932c9ebSPekka Enberg 	return ret;
33213a7760fSPekka Enberg }
33313a7760fSPekka Enberg 
334d4b02a37SThomas Gleixner static void serial8250_rx(struct serial8250_device *dev, void *data)
335d4b02a37SThomas Gleixner {
336d4b02a37SThomas Gleixner 	if (dev->rxdone == dev->rxcnt)
337d4b02a37SThomas Gleixner 		return;
338d4b02a37SThomas Gleixner 
339d4b02a37SThomas Gleixner 	/* Break issued ? */
340d4b02a37SThomas Gleixner 	if (dev->lsr & UART_LSR_BI) {
341d4b02a37SThomas Gleixner 		dev->lsr &= ~UART_LSR_BI;
342d4b02a37SThomas Gleixner 		ioport__write8(data, 0);
343d4b02a37SThomas Gleixner 		return;
344d4b02a37SThomas Gleixner 	}
345d4b02a37SThomas Gleixner 
346d4b02a37SThomas Gleixner 	ioport__write8(data, dev->rxbuf[dev->rxdone++]);
347d4b02a37SThomas Gleixner 	if (dev->rxcnt == dev->rxdone) {
348d4b02a37SThomas Gleixner 		dev->lsr &= ~UART_LSR_DR;
349d4b02a37SThomas Gleixner 		dev->rxcnt = dev->rxdone = 0;
350d4b02a37SThomas Gleixner 	}
351d4b02a37SThomas Gleixner }
352d4b02a37SThomas Gleixner 
35347a51060SAndre Przywara static bool serial8250_in(struct serial8250_device *dev, struct kvm_cpu *vcpu,
35447a51060SAndre Przywara 			  u16 offset, void *data)
35525af6674SPekka Enberg {
3562932c9ebSPekka Enberg 	bool ret = true;
35746aa8d69SPekka Enberg 
3584ef0f4d6SPekka Enberg 	mutex_lock(&dev->mutex);
3592932c9ebSPekka Enberg 
36046aa8d69SPekka Enberg 	switch (offset) {
361251cf9a6SPekka Enberg 	case UART_RX:
362d4b02a37SThomas Gleixner 		if (dev->lcr & UART_LCR_DLAB)
363c59fa0c4SThomas Gleixner 			ioport__write8(data, dev->dll);
364d4b02a37SThomas Gleixner 		else
365d4b02a37SThomas Gleixner 			serial8250_rx(dev, data);
366369c01c0SPekka Enberg 		break;
367c59fa0c4SThomas Gleixner 	case UART_IER:
368c59fa0c4SThomas Gleixner 		if (dev->lcr & UART_LCR_DLAB)
369c59fa0c4SThomas Gleixner 			ioport__write8(data, dev->dlm);
370c59fa0c4SThomas Gleixner 		else
371c59fa0c4SThomas Gleixner 			ioport__write8(data, dev->ier);
372c59fa0c4SThomas Gleixner 		break;
373f6b8ccc1SThomas Gleixner 	case UART_IIR:
374d4b02a37SThomas Gleixner 		ioport__write8(data, dev->iir | UART_IIR_TYPE_BITS);
37546aa8d69SPekka Enberg 		break;
3764e49b05bSCyrill Gorcunov 	case UART_LCR:
377c6a69c61SPekka Enberg 		ioport__write8(data, dev->lcr);
37846aa8d69SPekka Enberg 		break;
3794e49b05bSCyrill Gorcunov 	case UART_MCR:
380c6a69c61SPekka Enberg 		ioport__write8(data, dev->mcr);
38146aa8d69SPekka Enberg 		break;
3824e49b05bSCyrill Gorcunov 	case UART_LSR:
383c6a69c61SPekka Enberg 		ioport__write8(data, dev->lsr);
38446aa8d69SPekka Enberg 		break;
3854e49b05bSCyrill Gorcunov 	case UART_MSR:
386369c01c0SPekka Enberg 		ioport__write8(data, dev->msr);
38746aa8d69SPekka Enberg 		break;
3884e49b05bSCyrill Gorcunov 	case UART_SCR:
389369c01c0SPekka Enberg 		ioport__write8(data, dev->scr);
39046aa8d69SPekka Enberg 		break;
391369c01c0SPekka Enberg 	default:
3922932c9ebSPekka Enberg 		ret = false;
393c59fa0c4SThomas Gleixner 		break;
39425af6674SPekka Enberg 	}
395f6b8ccc1SThomas Gleixner 
3964123ca55SMarc Zyngier 	serial8250_update_irq(vcpu->kvm, dev);
397f6b8ccc1SThomas Gleixner 
3984ef0f4d6SPekka Enberg 	mutex_unlock(&dev->mutex);
3992932c9ebSPekka Enberg 
4002932c9ebSPekka Enberg 	return ret;
40113a7760fSPekka Enberg }
40213a7760fSPekka Enberg 
40347a51060SAndre Przywara static void serial8250_mmio(struct kvm_cpu *vcpu, u64 addr, u8 *data, u32 len,
40447a51060SAndre Przywara 			    u8 is_write, void *ptr)
40547a51060SAndre Przywara {
40647a51060SAndre Przywara 	struct serial8250_device *dev = ptr;
40747a51060SAndre Przywara 
40847a51060SAndre Przywara 	if (is_write)
40947a51060SAndre Przywara 		serial8250_out(dev, vcpu, addr - dev->iobase, data);
41047a51060SAndre Przywara 	else
41147a51060SAndre Przywara 		serial8250_in(dev, vcpu, addr - dev->iobase, data);
41247a51060SAndre Przywara }
41347a51060SAndre Przywara 
414d28abb58SWill Deacon #ifdef CONFIG_HAS_LIBFDT
41556e45ea4SAndre Przywara 
41656e45ea4SAndre Przywara char *fdt_stdout_path = NULL;
41756e45ea4SAndre Przywara 
418e5965f36SMarc Zyngier #define DEVICE_NAME_MAX_LEN 32
4192bfd9ac3SAndre Przywara static
420a81be31eSAndre Przywara void serial8250_generate_fdt_node(void *fdt, struct device_header *dev_hdr,
421a81be31eSAndre Przywara 				  fdt_irq_fn irq_fn)
422d28abb58SWill Deacon {
423e5965f36SMarc Zyngier 	char dev_name[DEVICE_NAME_MAX_LEN];
424a81be31eSAndre Przywara 	struct serial8250_device *dev = container_of(dev_hdr,
425a81be31eSAndre Przywara 						     struct serial8250_device,
426a81be31eSAndre Przywara 						     dev_hdr);
427a81be31eSAndre Przywara 
428*45b4968eSAndre Przywara 	u64 addr = dev->iobase;
429d28abb58SWill Deacon 	u64 reg_prop[] = {
430e5965f36SMarc Zyngier 		cpu_to_fdt64(addr),
431d28abb58SWill Deacon 		cpu_to_fdt64(8),
432d28abb58SWill Deacon 	};
433d28abb58SWill Deacon 
434e5965f36SMarc Zyngier 	snprintf(dev_name, DEVICE_NAME_MAX_LEN, "U6_16550A@%llx", addr);
435e5965f36SMarc Zyngier 
43656e45ea4SAndre Przywara 	if (!fdt_stdout_path) {
43756e45ea4SAndre Przywara 		fdt_stdout_path = malloc(strlen(dev_name) + 2);
43856e45ea4SAndre Przywara 		/* Assumes that this node is a child of the root node. */
43956e45ea4SAndre Przywara 		sprintf(fdt_stdout_path, "/%s", dev_name);
44056e45ea4SAndre Przywara 	}
44156e45ea4SAndre Przywara 
442e5965f36SMarc Zyngier 	_FDT(fdt_begin_node(fdt, dev_name));
443d28abb58SWill Deacon 	_FDT(fdt_property_string(fdt, "compatible", "ns16550a"));
444d28abb58SWill Deacon 	_FDT(fdt_property(fdt, "reg", reg_prop, sizeof(reg_prop)));
445a81be31eSAndre Przywara 	irq_fn(fdt, dev->irq, IRQ_TYPE_LEVEL_HIGH);
446d28abb58SWill Deacon 	_FDT(fdt_property_cell(fdt, "clock-frequency", 1843200));
447d28abb58SWill Deacon 	_FDT(fdt_end_node(fdt));
448d28abb58SWill Deacon }
449d28abb58SWill Deacon #endif
450d28abb58SWill Deacon 
451a81be31eSAndre Przywara static int serial8250__device_init(struct kvm *kvm,
452a81be31eSAndre Przywara 				   struct serial8250_device *dev)
453bc4b0ffeSPekka Enberg {
45420715a22SSasha Levin 	int r;
45520715a22SSasha Levin 
456a81be31eSAndre Przywara 	r = device__register(&dev->dev_hdr);
457a81be31eSAndre Przywara 	if (r < 0)
458a81be31eSAndre Przywara 		return r;
459a81be31eSAndre Przywara 
460206c41f4SWill Deacon 	ioport__map_irq(&dev->irq);
461*45b4968eSAndre Przywara 	r = kvm__register_iotrap(kvm, dev->iobase, 8, serial8250_mmio, dev,
462*45b4968eSAndre Przywara 				 SERIAL8250_BUS_TYPE);
46320715a22SSasha Levin 
46420715a22SSasha Levin 	return r;
465bc4b0ffeSPekka Enberg }
466bc4b0ffeSPekka Enberg 
46720715a22SSasha Levin int serial8250__init(struct kvm *kvm)
46813a7760fSPekka Enberg {
46920715a22SSasha Levin 	unsigned int i, j;
47020715a22SSasha Levin 	int r = 0;
471c6a69c61SPekka Enberg 
472c6a69c61SPekka Enberg 	for (i = 0; i < ARRAY_SIZE(devices); i++) {
473c6a69c61SPekka Enberg 		struct serial8250_device *dev = &devices[i];
474c6a69c61SPekka Enberg 
47520715a22SSasha Levin 		r = serial8250__device_init(kvm, dev);
47620715a22SSasha Levin 		if (r < 0)
47720715a22SSasha Levin 			goto cleanup;
478c6a69c61SPekka Enberg 	}
47920715a22SSasha Levin 
48020715a22SSasha Levin 	return r;
48120715a22SSasha Levin cleanup:
48220715a22SSasha Levin 	for (j = 0; j <= i; j++) {
48320715a22SSasha Levin 		struct serial8250_device *dev = &devices[j];
48420715a22SSasha Levin 
485*45b4968eSAndre Przywara 		kvm__deregister_iotrap(kvm, dev->iobase, SERIAL8250_BUS_TYPE);
486a81be31eSAndre Przywara 		device__unregister(&dev->dev_hdr);
48720715a22SSasha Levin 	}
48820715a22SSasha Levin 
48920715a22SSasha Levin 	return r;
49020715a22SSasha Levin }
49149a8afd1SSasha Levin dev_init(serial8250__init);
49220715a22SSasha Levin 
49320715a22SSasha Levin int serial8250__exit(struct kvm *kvm)
49420715a22SSasha Levin {
49520715a22SSasha Levin 	unsigned int i;
49620715a22SSasha Levin 	int r;
49720715a22SSasha Levin 
49820715a22SSasha Levin 	for (i = 0; i < ARRAY_SIZE(devices); i++) {
49920715a22SSasha Levin 		struct serial8250_device *dev = &devices[i];
50020715a22SSasha Levin 
501*45b4968eSAndre Przywara 		r = kvm__deregister_iotrap(kvm, dev->iobase,
502*45b4968eSAndre Przywara 					   SERIAL8250_BUS_TYPE);
50320715a22SSasha Levin 		if (r < 0)
50420715a22SSasha Levin 			return r;
505a81be31eSAndre Przywara 		device__unregister(&dev->dev_hdr);
50620715a22SSasha Levin 	}
50720715a22SSasha Levin 
50820715a22SSasha Levin 	return 0;
50913a7760fSPekka Enberg }
51049a8afd1SSasha Levin dev_exit(serial8250__exit);
511