xref: /kvmtool/hw/serial.c (revision 47a510600e080f21850722d82d0f1faf2f9b4b25)
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 
16d4b02a37SThomas Gleixner /*
17d4b02a37SThomas Gleixner  * This fakes a U6_16550A. The fifo len needs to be 64 as the kernel
18d4b02a37SThomas Gleixner  * expects that for autodetection.
19d4b02a37SThomas Gleixner  */
20d4b02a37SThomas Gleixner #define FIFO_LEN		64
21d4b02a37SThomas Gleixner #define FIFO_MASK		(FIFO_LEN - 1)
22d4b02a37SThomas Gleixner 
23d4b02a37SThomas Gleixner #define UART_IIR_TYPE_BITS	0xc0
24d4b02a37SThomas Gleixner 
2546aa8d69SPekka Enberg struct serial8250_device {
26a81be31eSAndre Przywara 	struct device_header	dev_hdr;
27d3476f7dSSasha Levin 	struct mutex		mutex;
281add4b76SSasha Levin 	u8			id;
292932c9ebSPekka Enberg 
303fdf659dSSasha Levin 	u16			iobase;
313fdf659dSSasha Levin 	u8			irq;
32f6b8ccc1SThomas Gleixner 	u8			irq_state;
338dfae8beSThomas Gleixner 	int			txcnt;
34d4b02a37SThomas Gleixner 	int			rxcnt;
35d4b02a37SThomas Gleixner 	int			rxdone;
36d4b02a37SThomas Gleixner 	char			txbuf[FIFO_LEN];
37d4b02a37SThomas Gleixner 	char			rxbuf[FIFO_LEN];
3876b4a122SPekka Enberg 
393fdf659dSSasha Levin 	u8			dll;
403fdf659dSSasha Levin 	u8			dlm;
413fdf659dSSasha Levin 	u8			iir;
423fdf659dSSasha Levin 	u8			ier;
433fdf659dSSasha Levin 	u8			fcr;
443fdf659dSSasha Levin 	u8			lcr;
453fdf659dSSasha Levin 	u8			mcr;
463fdf659dSSasha Levin 	u8			lsr;
473fdf659dSSasha Levin 	u8			msr;
483fdf659dSSasha Levin 	u8			scr;
4946aa8d69SPekka Enberg };
5046aa8d69SPekka Enberg 
51f3efa592SLiming Wang #define SERIAL_REGS_SETTING \
52f3efa592SLiming Wang 	.iir			= UART_IIR_NO_INT, \
53f3efa592SLiming Wang 	.lsr			= UART_LSR_TEMT | UART_LSR_THRE, \
54f3efa592SLiming Wang 	.msr			= UART_MSR_DCD | UART_MSR_DSR | UART_MSR_CTS, \
55f3efa592SLiming Wang 	.mcr			= UART_MCR_OUT2,
56f3efa592SLiming Wang 
57a81be31eSAndre Przywara #ifdef CONFIG_HAS_LIBFDT
58a81be31eSAndre Przywara static
59a81be31eSAndre Przywara void serial8250_generate_fdt_node(void *fdt, struct device_header *dev_hdr,
60a81be31eSAndre Przywara 				  fdt_irq_fn irq_fn);
61a81be31eSAndre Przywara #else
62a81be31eSAndre Przywara #define serial8250_generate_fdt_node	NULL
63a81be31eSAndre Przywara #endif
64e62c18deSPekka Enberg static struct serial8250_device devices[] = {
65c6a69c61SPekka Enberg 	/* ttyS0 */
66c6a69c61SPekka Enberg 	[0]	= {
67a81be31eSAndre Przywara 		.dev_hdr = {
68a81be31eSAndre Przywara 			.bus_type	= DEVICE_BUS_IOPORT,
69a81be31eSAndre Przywara 			.data		= serial8250_generate_fdt_node,
70a81be31eSAndre Przywara 		},
71d3476f7dSSasha Levin 		.mutex			= MUTEX_INITIALIZER,
722932c9ebSPekka Enberg 
731add4b76SSasha Levin 		.id			= 0,
74c6a69c61SPekka Enberg 		.iobase			= 0x3f8,
75e557eef9SPekka Enberg 		.irq			= 4,
76e557eef9SPekka Enberg 
77f3efa592SLiming Wang 		SERIAL_REGS_SETTING
78c6a69c61SPekka Enberg 	},
79e62c18deSPekka Enberg 	/* ttyS1 */
80e62c18deSPekka Enberg 	[1]	= {
81a81be31eSAndre Przywara 		.dev_hdr = {
82a81be31eSAndre Przywara 			.bus_type	= DEVICE_BUS_IOPORT,
83a81be31eSAndre Przywara 			.data		= serial8250_generate_fdt_node,
84a81be31eSAndre Przywara 		},
85d3476f7dSSasha Levin 		.mutex			= MUTEX_INITIALIZER,
862932c9ebSPekka Enberg 
871add4b76SSasha Levin 		.id			= 1,
88e62c18deSPekka Enberg 		.iobase			= 0x2f8,
89e62c18deSPekka Enberg 		.irq			= 3,
90133bedc1SPekka Enberg 
91f3efa592SLiming Wang 		SERIAL_REGS_SETTING
92e62c18deSPekka Enberg 	},
93e62c18deSPekka Enberg 	/* ttyS2 */
94e62c18deSPekka Enberg 	[2]	= {
95a81be31eSAndre Przywara 		.dev_hdr = {
96a81be31eSAndre Przywara 			.bus_type	= DEVICE_BUS_IOPORT,
97a81be31eSAndre Przywara 			.data		= serial8250_generate_fdt_node,
98a81be31eSAndre Przywara 		},
99d3476f7dSSasha Levin 		.mutex			= MUTEX_INITIALIZER,
1002932c9ebSPekka Enberg 
1011add4b76SSasha Levin 		.id			= 2,
102e62c18deSPekka Enberg 		.iobase			= 0x3e8,
103e62c18deSPekka Enberg 		.irq			= 4,
104133bedc1SPekka Enberg 
105f3efa592SLiming Wang 		SERIAL_REGS_SETTING
106e62c18deSPekka Enberg 	},
107bf459c83SPekka Enberg 	/* ttyS3 */
108bf459c83SPekka Enberg 	[3]	= {
109a81be31eSAndre Przywara 		.dev_hdr = {
110a81be31eSAndre Przywara 			.bus_type	= DEVICE_BUS_IOPORT,
111a81be31eSAndre Przywara 			.data		= serial8250_generate_fdt_node,
112a81be31eSAndre Przywara 		},
113d3476f7dSSasha Levin 		.mutex			= MUTEX_INITIALIZER,
114bf459c83SPekka Enberg 
1151add4b76SSasha Levin 		.id			= 3,
116bf459c83SPekka Enberg 		.iobase			= 0x2e8,
117bf459c83SPekka Enberg 		.irq			= 3,
118bf459c83SPekka Enberg 
119f3efa592SLiming Wang 		SERIAL_REGS_SETTING
120bf459c83SPekka Enberg 	},
12146aa8d69SPekka Enberg };
12246aa8d69SPekka Enberg 
1232651ea58SSasha Levin static void serial8250_flush_tx(struct kvm *kvm, struct serial8250_device *dev)
124d4b02a37SThomas Gleixner {
125d4b02a37SThomas Gleixner 	dev->lsr |= UART_LSR_TEMT | UART_LSR_THRE;
126d4b02a37SThomas Gleixner 
127d4b02a37SThomas Gleixner 	if (dev->txcnt) {
1282651ea58SSasha Levin 		term_putc(dev->txbuf, dev->txcnt, dev->id);
129d4b02a37SThomas Gleixner 		dev->txcnt = 0;
130d4b02a37SThomas Gleixner 	}
131d4b02a37SThomas Gleixner }
132d4b02a37SThomas Gleixner 
133f6b8ccc1SThomas Gleixner static void serial8250_update_irq(struct kvm *kvm, struct serial8250_device *dev)
134f6b8ccc1SThomas Gleixner {
135f6b8ccc1SThomas Gleixner 	u8 iir = 0;
136f6b8ccc1SThomas Gleixner 
137d4b02a37SThomas Gleixner 	/* Handle clear rx */
138d4b02a37SThomas Gleixner 	if (dev->lcr & UART_FCR_CLEAR_RCVR) {
139d4b02a37SThomas Gleixner 		dev->lcr &= ~UART_FCR_CLEAR_RCVR;
140d4b02a37SThomas Gleixner 		dev->rxcnt = dev->rxdone = 0;
141d4b02a37SThomas Gleixner 		dev->lsr &= ~UART_LSR_DR;
142d4b02a37SThomas Gleixner 	}
143d4b02a37SThomas Gleixner 
144d4b02a37SThomas Gleixner 	/* Handle clear tx */
145d4b02a37SThomas Gleixner 	if (dev->lcr & UART_FCR_CLEAR_XMIT) {
146d4b02a37SThomas Gleixner 		dev->lcr &= ~UART_FCR_CLEAR_XMIT;
147d4b02a37SThomas Gleixner 		dev->txcnt = 0;
148d4b02a37SThomas Gleixner 		dev->lsr |= UART_LSR_TEMT | UART_LSR_THRE;
149d4b02a37SThomas Gleixner 	}
150d4b02a37SThomas Gleixner 
151f6b8ccc1SThomas Gleixner 	/* Data ready and rcv interrupt enabled ? */
152f6b8ccc1SThomas Gleixner 	if ((dev->ier & UART_IER_RDI) && (dev->lsr & UART_LSR_DR))
153f6b8ccc1SThomas Gleixner 		iir |= UART_IIR_RDI;
154f6b8ccc1SThomas Gleixner 
155f6b8ccc1SThomas Gleixner 	/* Transmitter empty and interrupt enabled ? */
156f6b8ccc1SThomas Gleixner 	if ((dev->ier & UART_IER_THRI) && (dev->lsr & UART_LSR_TEMT))
157f6b8ccc1SThomas Gleixner 		iir |= UART_IIR_THRI;
158f6b8ccc1SThomas Gleixner 
159f6b8ccc1SThomas Gleixner 	/* Now update the irq line, if necessary */
160f6b8ccc1SThomas Gleixner 	if (!iir) {
161f6b8ccc1SThomas Gleixner 		dev->iir = UART_IIR_NO_INT;
162f6b8ccc1SThomas Gleixner 		if (dev->irq_state)
163f6b8ccc1SThomas Gleixner 			kvm__irq_line(kvm, dev->irq, 0);
164f6b8ccc1SThomas Gleixner 	} else {
165f6b8ccc1SThomas Gleixner 		dev->iir = iir;
166f6b8ccc1SThomas Gleixner 		if (!dev->irq_state)
167f6b8ccc1SThomas Gleixner 			kvm__irq_line(kvm, dev->irq, 1);
168f6b8ccc1SThomas Gleixner 	}
169f6b8ccc1SThomas Gleixner 	dev->irq_state = iir;
1708dfae8beSThomas Gleixner 
1718dfae8beSThomas Gleixner 	/*
1728dfae8beSThomas Gleixner 	 * If the kernel disabled the tx interrupt, we know that there
1738dfae8beSThomas Gleixner 	 * is nothing more to transmit, so we can reset our tx logic
1748dfae8beSThomas Gleixner 	 * here.
1758dfae8beSThomas Gleixner 	 */
176d4b02a37SThomas Gleixner 	if (!(dev->ier & UART_IER_THRI))
1772651ea58SSasha Levin 		serial8250_flush_tx(kvm, dev);
178f6b8ccc1SThomas Gleixner }
179f6b8ccc1SThomas Gleixner 
180a428f72eSPekka Enberg #define SYSRQ_PENDING_NONE		0
181a428f72eSPekka Enberg 
182a428f72eSPekka Enberg static int sysrq_pending;
183a428f72eSPekka Enberg 
18443835ac9SSasha Levin static void serial8250__sysrq(struct kvm *kvm, struct serial8250_device *dev)
185a428f72eSPekka Enberg {
186a428f72eSPekka Enberg 	dev->lsr |= UART_LSR_DR | UART_LSR_BI;
187226e727bSSasha Levin 	dev->rxbuf[dev->rxcnt++] = sysrq_pending;
188a428f72eSPekka Enberg 	sysrq_pending	= SYSRQ_PENDING_NONE;
189a428f72eSPekka Enberg }
190a428f72eSPekka Enberg 
191d4b02a37SThomas Gleixner static void serial8250__receive(struct kvm *kvm, struct serial8250_device *dev,
192d4b02a37SThomas Gleixner 				bool handle_sysrq)
193251cf9a6SPekka Enberg {
194251cf9a6SPekka Enberg 	int c;
195251cf9a6SPekka Enberg 
196d4b02a37SThomas Gleixner 	if (dev->mcr & UART_MCR_LOOP)
197db34045cSPekka Enberg 		return;
198db34045cSPekka Enberg 
199d4b02a37SThomas Gleixner 	if ((dev->lsr & UART_LSR_DR) || dev->rxcnt)
200d4b02a37SThomas Gleixner 		return;
201d4b02a37SThomas Gleixner 
202d4b02a37SThomas Gleixner 	if (handle_sysrq && sysrq_pending) {
20343835ac9SSasha Levin 		serial8250__sysrq(kvm, dev);
204a428f72eSPekka Enberg 		return;
205a428f72eSPekka Enberg 	}
206a428f72eSPekka Enberg 
2072651ea58SSasha Levin 	if (kvm->cfg.active_console != CONSOLE_8250)
2082651ea58SSasha Levin 		return;
2092651ea58SSasha Levin 
2102651ea58SSasha Levin 	while (term_readable(dev->id) &&
211d4b02a37SThomas Gleixner 	       dev->rxcnt < FIFO_LEN) {
212251cf9a6SPekka Enberg 
2134346fd8fSSasha Levin 		c = term_getc(kvm, dev->id);
21405d1a2a6SAsias He 
215251cf9a6SPekka Enberg 		if (c < 0)
216d4b02a37SThomas Gleixner 			break;
217d4b02a37SThomas Gleixner 		dev->rxbuf[dev->rxcnt++] = c;
218251cf9a6SPekka Enberg 		dev->lsr |= UART_LSR_DR;
219251cf9a6SPekka Enberg 	}
220d4b02a37SThomas Gleixner }
221251cf9a6SPekka Enberg 
222f6b8ccc1SThomas Gleixner void serial8250__update_consoles(struct kvm *kvm)
2238bb34e0dSPekka Enberg {
224479de16fSCyrill Gorcunov 	unsigned int i;
2251add4b76SSasha Levin 
226479de16fSCyrill Gorcunov 	for (i = 0; i < ARRAY_SIZE(devices); i++) {
2271add4b76SSasha Levin 		struct serial8250_device *dev = &devices[i];
228934c193bSPekka Enberg 
2294ef0f4d6SPekka Enberg 		mutex_lock(&dev->mutex);
2302932c9ebSPekka Enberg 
231d4b02a37SThomas Gleixner 		/* Restrict sysrq injection to the first port */
232d4b02a37SThomas Gleixner 		serial8250__receive(kvm, dev, i == 0);
233251cf9a6SPekka Enberg 
234f6b8ccc1SThomas Gleixner 		serial8250_update_irq(kvm, dev);
2352932c9ebSPekka Enberg 
2364ef0f4d6SPekka Enberg 		mutex_unlock(&dev->mutex);
2378bb34e0dSPekka Enberg 	}
2381add4b76SSasha Levin }
2398bb34e0dSPekka Enberg 
240226e727bSSasha Levin void serial8250__inject_sysrq(struct kvm *kvm, char sysrq)
241a428f72eSPekka Enberg {
242226e727bSSasha Levin 	sysrq_pending = sysrq;
243a428f72eSPekka Enberg }
244a428f72eSPekka Enberg 
245*47a51060SAndre Przywara static bool serial8250_out(struct serial8250_device *dev, struct kvm_cpu *vcpu,
246*47a51060SAndre Przywara 			   u16 offset, void *data)
24713a7760fSPekka Enberg {
2482932c9ebSPekka Enberg 	bool ret = true;
249d4b02a37SThomas Gleixner 	char *addr = data;
25046aa8d69SPekka Enberg 
2514ef0f4d6SPekka Enberg 	mutex_lock(&dev->mutex);
2522932c9ebSPekka Enberg 
25346aa8d69SPekka Enberg 	switch (offset) {
254c59fa0c4SThomas Gleixner 	case UART_TX:
255d4b02a37SThomas Gleixner 		if (dev->lcr & UART_LCR_DLAB) {
256c59fa0c4SThomas Gleixner 			dev->dll = ioport__read8(data);
257d4b02a37SThomas Gleixner 			break;
258d4b02a37SThomas Gleixner 		}
259d4b02a37SThomas Gleixner 
260d4b02a37SThomas Gleixner 		/* Loopback mode */
261d4b02a37SThomas Gleixner 		if (dev->mcr & UART_MCR_LOOP) {
262d4b02a37SThomas Gleixner 			if (dev->rxcnt < FIFO_LEN) {
263d4b02a37SThomas Gleixner 				dev->rxbuf[dev->rxcnt++] = *addr;
264d4b02a37SThomas Gleixner 				dev->lsr |= UART_LSR_DR;
265d4b02a37SThomas Gleixner 			}
266d4b02a37SThomas Gleixner 			break;
267d4b02a37SThomas Gleixner 		}
268d4b02a37SThomas Gleixner 
269d4b02a37SThomas Gleixner 		if (dev->txcnt < FIFO_LEN) {
270d4b02a37SThomas Gleixner 			dev->txbuf[dev->txcnt++] = *addr;
271d4b02a37SThomas Gleixner 			dev->lsr &= ~UART_LSR_TEMT;
272d4b02a37SThomas Gleixner 			if (dev->txcnt == FIFO_LEN / 2)
273d4b02a37SThomas Gleixner 				dev->lsr &= ~UART_LSR_THRE;
2744123ca55SMarc Zyngier 			serial8250_flush_tx(vcpu->kvm, dev);
275d4b02a37SThomas Gleixner 		} else {
276d4b02a37SThomas Gleixner 			/* Should never happpen */
277d4b02a37SThomas Gleixner 			dev->lsr &= ~(UART_LSR_TEMT | UART_LSR_THRE);
27846aa8d69SPekka Enberg 		}
279369c01c0SPekka Enberg 		break;
2804e49b05bSCyrill Gorcunov 	case UART_IER:
281f6b8ccc1SThomas Gleixner 		if (!(dev->lcr & UART_LCR_DLAB))
282d4b02a37SThomas Gleixner 			dev->ier = ioport__read8(data) & 0x0f;
283f6b8ccc1SThomas Gleixner 		else
284c59fa0c4SThomas Gleixner 			dev->dlm = ioport__read8(data);
285c59fa0c4SThomas Gleixner 		break;
286c59fa0c4SThomas Gleixner 	case UART_FCR:
287c59fa0c4SThomas Gleixner 		dev->fcr = ioport__read8(data);
28846aa8d69SPekka Enberg 		break;
289369c01c0SPekka Enberg 	case UART_LCR:
290369c01c0SPekka Enberg 		dev->lcr = ioport__read8(data);
291369c01c0SPekka Enberg 		break;
292369c01c0SPekka Enberg 	case UART_MCR:
293369c01c0SPekka Enberg 		dev->mcr = ioport__read8(data);
294369c01c0SPekka Enberg 		break;
295369c01c0SPekka Enberg 	case UART_LSR:
296369c01c0SPekka Enberg 		/* Factory test */
297369c01c0SPekka Enberg 		break;
298369c01c0SPekka Enberg 	case UART_MSR:
299369c01c0SPekka Enberg 		/* Not used */
300369c01c0SPekka Enberg 		break;
301369c01c0SPekka Enberg 	case UART_SCR:
302369c01c0SPekka Enberg 		dev->scr = ioport__read8(data);
303369c01c0SPekka Enberg 		break;
304369c01c0SPekka Enberg 	default:
3052932c9ebSPekka Enberg 		ret = false;
306d2ea115dSThomas Gleixner 		break;
30746aa8d69SPekka Enberg 	}
3082932c9ebSPekka Enberg 
3094123ca55SMarc Zyngier 	serial8250_update_irq(vcpu->kvm, dev);
310f6b8ccc1SThomas Gleixner 
3114ef0f4d6SPekka Enberg 	mutex_unlock(&dev->mutex);
3122932c9ebSPekka Enberg 
3132932c9ebSPekka Enberg 	return ret;
31413a7760fSPekka Enberg }
31513a7760fSPekka Enberg 
316d4b02a37SThomas Gleixner static void serial8250_rx(struct serial8250_device *dev, void *data)
317d4b02a37SThomas Gleixner {
318d4b02a37SThomas Gleixner 	if (dev->rxdone == dev->rxcnt)
319d4b02a37SThomas Gleixner 		return;
320d4b02a37SThomas Gleixner 
321d4b02a37SThomas Gleixner 	/* Break issued ? */
322d4b02a37SThomas Gleixner 	if (dev->lsr & UART_LSR_BI) {
323d4b02a37SThomas Gleixner 		dev->lsr &= ~UART_LSR_BI;
324d4b02a37SThomas Gleixner 		ioport__write8(data, 0);
325d4b02a37SThomas Gleixner 		return;
326d4b02a37SThomas Gleixner 	}
327d4b02a37SThomas Gleixner 
328d4b02a37SThomas Gleixner 	ioport__write8(data, dev->rxbuf[dev->rxdone++]);
329d4b02a37SThomas Gleixner 	if (dev->rxcnt == dev->rxdone) {
330d4b02a37SThomas Gleixner 		dev->lsr &= ~UART_LSR_DR;
331d4b02a37SThomas Gleixner 		dev->rxcnt = dev->rxdone = 0;
332d4b02a37SThomas Gleixner 	}
333d4b02a37SThomas Gleixner }
334d4b02a37SThomas Gleixner 
335*47a51060SAndre Przywara static bool serial8250_in(struct serial8250_device *dev, struct kvm_cpu *vcpu,
336*47a51060SAndre Przywara 			  u16 offset, void *data)
33725af6674SPekka Enberg {
3382932c9ebSPekka Enberg 	bool ret = true;
33946aa8d69SPekka Enberg 
3404ef0f4d6SPekka Enberg 	mutex_lock(&dev->mutex);
3412932c9ebSPekka Enberg 
34246aa8d69SPekka Enberg 	switch (offset) {
343251cf9a6SPekka Enberg 	case UART_RX:
344d4b02a37SThomas Gleixner 		if (dev->lcr & UART_LCR_DLAB)
345c59fa0c4SThomas Gleixner 			ioport__write8(data, dev->dll);
346d4b02a37SThomas Gleixner 		else
347d4b02a37SThomas Gleixner 			serial8250_rx(dev, data);
348369c01c0SPekka Enberg 		break;
349c59fa0c4SThomas Gleixner 	case UART_IER:
350c59fa0c4SThomas Gleixner 		if (dev->lcr & UART_LCR_DLAB)
351c59fa0c4SThomas Gleixner 			ioport__write8(data, dev->dlm);
352c59fa0c4SThomas Gleixner 		else
353c59fa0c4SThomas Gleixner 			ioport__write8(data, dev->ier);
354c59fa0c4SThomas Gleixner 		break;
355f6b8ccc1SThomas Gleixner 	case UART_IIR:
356d4b02a37SThomas Gleixner 		ioport__write8(data, dev->iir | UART_IIR_TYPE_BITS);
35746aa8d69SPekka Enberg 		break;
3584e49b05bSCyrill Gorcunov 	case UART_LCR:
359c6a69c61SPekka Enberg 		ioport__write8(data, dev->lcr);
36046aa8d69SPekka Enberg 		break;
3614e49b05bSCyrill Gorcunov 	case UART_MCR:
362c6a69c61SPekka Enberg 		ioport__write8(data, dev->mcr);
36346aa8d69SPekka Enberg 		break;
3644e49b05bSCyrill Gorcunov 	case UART_LSR:
365c6a69c61SPekka Enberg 		ioport__write8(data, dev->lsr);
36646aa8d69SPekka Enberg 		break;
3674e49b05bSCyrill Gorcunov 	case UART_MSR:
368369c01c0SPekka Enberg 		ioport__write8(data, dev->msr);
36946aa8d69SPekka Enberg 		break;
3704e49b05bSCyrill Gorcunov 	case UART_SCR:
371369c01c0SPekka Enberg 		ioport__write8(data, dev->scr);
37246aa8d69SPekka Enberg 		break;
373369c01c0SPekka Enberg 	default:
3742932c9ebSPekka Enberg 		ret = false;
375c59fa0c4SThomas Gleixner 		break;
37625af6674SPekka Enberg 	}
377f6b8ccc1SThomas Gleixner 
3784123ca55SMarc Zyngier 	serial8250_update_irq(vcpu->kvm, dev);
379f6b8ccc1SThomas Gleixner 
3804ef0f4d6SPekka Enberg 	mutex_unlock(&dev->mutex);
3812932c9ebSPekka Enberg 
3822932c9ebSPekka Enberg 	return ret;
38313a7760fSPekka Enberg }
38413a7760fSPekka Enberg 
385*47a51060SAndre Przywara static void serial8250_mmio(struct kvm_cpu *vcpu, u64 addr, u8 *data, u32 len,
386*47a51060SAndre Przywara 			    u8 is_write, void *ptr)
387*47a51060SAndre Przywara {
388*47a51060SAndre Przywara 	struct serial8250_device *dev = ptr;
389*47a51060SAndre Przywara 
390*47a51060SAndre Przywara 	if (is_write)
391*47a51060SAndre Przywara 		serial8250_out(dev, vcpu, addr - dev->iobase, data);
392*47a51060SAndre Przywara 	else
393*47a51060SAndre Przywara 		serial8250_in(dev, vcpu, addr - dev->iobase, data);
394*47a51060SAndre Przywara }
395*47a51060SAndre Przywara 
396*47a51060SAndre Przywara static bool serial8250_ioport_out(struct ioport *ioport, struct kvm_cpu *vcpu,
397*47a51060SAndre Przywara 				  u16 port, void *data, int size)
398*47a51060SAndre Przywara {
399*47a51060SAndre Przywara 	struct serial8250_device *dev = ioport->priv;
400*47a51060SAndre Przywara 
401*47a51060SAndre Przywara 	serial8250_mmio(vcpu, port, data, 1, true, dev);
402*47a51060SAndre Przywara 
403*47a51060SAndre Przywara 	return true;
404*47a51060SAndre Przywara }
405*47a51060SAndre Przywara 
406*47a51060SAndre Przywara static bool serial8250_ioport_in(struct ioport *ioport, struct kvm_cpu *vcpu,
407*47a51060SAndre Przywara 				 u16 port, void *data, int size)
408*47a51060SAndre Przywara {
409*47a51060SAndre Przywara 	struct serial8250_device *dev = ioport->priv;
410*47a51060SAndre Przywara 
411*47a51060SAndre Przywara 	serial8250_mmio(vcpu, port, data, 1, false, dev);
412*47a51060SAndre Przywara 
413*47a51060SAndre Przywara 	return true;
414*47a51060SAndre Przywara }
415*47a51060SAndre Przywara 
416d28abb58SWill Deacon #ifdef CONFIG_HAS_LIBFDT
41756e45ea4SAndre Przywara 
41856e45ea4SAndre Przywara char *fdt_stdout_path = NULL;
41956e45ea4SAndre Przywara 
420e5965f36SMarc Zyngier #define DEVICE_NAME_MAX_LEN 32
4212bfd9ac3SAndre Przywara static
422a81be31eSAndre Przywara void serial8250_generate_fdt_node(void *fdt, struct device_header *dev_hdr,
423a81be31eSAndre Przywara 				  fdt_irq_fn irq_fn)
424d28abb58SWill Deacon {
425e5965f36SMarc Zyngier 	char dev_name[DEVICE_NAME_MAX_LEN];
426a81be31eSAndre Przywara 	struct serial8250_device *dev = container_of(dev_hdr,
427a81be31eSAndre Przywara 						     struct serial8250_device,
428a81be31eSAndre Przywara 						     dev_hdr);
429a81be31eSAndre Przywara 
430e5965f36SMarc Zyngier 	u64 addr = KVM_IOPORT_AREA + dev->iobase;
431d28abb58SWill Deacon 	u64 reg_prop[] = {
432e5965f36SMarc Zyngier 		cpu_to_fdt64(addr),
433d28abb58SWill Deacon 		cpu_to_fdt64(8),
434d28abb58SWill Deacon 	};
435d28abb58SWill Deacon 
436e5965f36SMarc Zyngier 	snprintf(dev_name, DEVICE_NAME_MAX_LEN, "U6_16550A@%llx", addr);
437e5965f36SMarc Zyngier 
43856e45ea4SAndre Przywara 	if (!fdt_stdout_path) {
43956e45ea4SAndre Przywara 		fdt_stdout_path = malloc(strlen(dev_name) + 2);
44056e45ea4SAndre Przywara 		/* Assumes that this node is a child of the root node. */
44156e45ea4SAndre Przywara 		sprintf(fdt_stdout_path, "/%s", dev_name);
44256e45ea4SAndre Przywara 	}
44356e45ea4SAndre Przywara 
444e5965f36SMarc Zyngier 	_FDT(fdt_begin_node(fdt, dev_name));
445d28abb58SWill Deacon 	_FDT(fdt_property_string(fdt, "compatible", "ns16550a"));
446d28abb58SWill Deacon 	_FDT(fdt_property(fdt, "reg", reg_prop, sizeof(reg_prop)));
447a81be31eSAndre Przywara 	irq_fn(fdt, dev->irq, IRQ_TYPE_LEVEL_HIGH);
448d28abb58SWill Deacon 	_FDT(fdt_property_cell(fdt, "clock-frequency", 1843200));
449d28abb58SWill Deacon 	_FDT(fdt_end_node(fdt));
450d28abb58SWill Deacon }
451d28abb58SWill Deacon #endif
452d28abb58SWill Deacon 
45346aa8d69SPekka Enberg static struct ioport_operations serial8250_ops = {
454*47a51060SAndre Przywara 	.io_in			= serial8250_ioport_in,
455*47a51060SAndre Przywara 	.io_out			= serial8250_ioport_out,
456a93ec68bSPekka Enberg };
457a93ec68bSPekka Enberg 
458a81be31eSAndre Przywara static int serial8250__device_init(struct kvm *kvm,
459a81be31eSAndre Przywara 				   struct serial8250_device *dev)
460bc4b0ffeSPekka Enberg {
46120715a22SSasha Levin 	int r;
46220715a22SSasha Levin 
463a81be31eSAndre Przywara 	r = device__register(&dev->dev_hdr);
464a81be31eSAndre Przywara 	if (r < 0)
465a81be31eSAndre Przywara 		return r;
466a81be31eSAndre Przywara 
467206c41f4SWill Deacon 	ioport__map_irq(&dev->irq);
468d28abb58SWill Deacon 	r = ioport__register(kvm, dev->iobase, &serial8250_ops, 8, dev);
46920715a22SSasha Levin 
47020715a22SSasha Levin 	return r;
471bc4b0ffeSPekka Enberg }
472bc4b0ffeSPekka Enberg 
47320715a22SSasha Levin int serial8250__init(struct kvm *kvm)
47413a7760fSPekka Enberg {
47520715a22SSasha Levin 	unsigned int i, j;
47620715a22SSasha Levin 	int r = 0;
477c6a69c61SPekka Enberg 
478c6a69c61SPekka Enberg 	for (i = 0; i < ARRAY_SIZE(devices); i++) {
479c6a69c61SPekka Enberg 		struct serial8250_device *dev = &devices[i];
480c6a69c61SPekka Enberg 
48120715a22SSasha Levin 		r = serial8250__device_init(kvm, dev);
48220715a22SSasha Levin 		if (r < 0)
48320715a22SSasha Levin 			goto cleanup;
484c6a69c61SPekka Enberg 	}
48520715a22SSasha Levin 
48620715a22SSasha Levin 	return r;
48720715a22SSasha Levin cleanup:
48820715a22SSasha Levin 	for (j = 0; j <= i; j++) {
48920715a22SSasha Levin 		struct serial8250_device *dev = &devices[j];
49020715a22SSasha Levin 
4914346fd8fSSasha Levin 		ioport__unregister(kvm, dev->iobase);
492a81be31eSAndre Przywara 		device__unregister(&dev->dev_hdr);
49320715a22SSasha Levin 	}
49420715a22SSasha Levin 
49520715a22SSasha Levin 	return r;
49620715a22SSasha Levin }
49749a8afd1SSasha Levin dev_init(serial8250__init);
49820715a22SSasha Levin 
49920715a22SSasha Levin int serial8250__exit(struct kvm *kvm)
50020715a22SSasha Levin {
50120715a22SSasha Levin 	unsigned int i;
50220715a22SSasha Levin 	int r;
50320715a22SSasha Levin 
50420715a22SSasha Levin 	for (i = 0; i < ARRAY_SIZE(devices); i++) {
50520715a22SSasha Levin 		struct serial8250_device *dev = &devices[i];
50620715a22SSasha Levin 
5074346fd8fSSasha Levin 		r = ioport__unregister(kvm, dev->iobase);
50820715a22SSasha Levin 		if (r < 0)
50920715a22SSasha Levin 			return r;
510a81be31eSAndre Przywara 		device__unregister(&dev->dev_hdr);
51120715a22SSasha Levin 	}
51220715a22SSasha Levin 
51320715a22SSasha Levin 	return 0;
51413a7760fSPekka Enberg }
51549a8afd1SSasha Levin dev_exit(serial8250__exit);
516