xref: /kvmtool/hw/serial.c (revision 56e45ea44fbed5136a339f6da582c37bdb7fd607)
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 {
26d3476f7dSSasha Levin 	struct mutex		mutex;
271add4b76SSasha Levin 	u8			id;
282932c9ebSPekka Enberg 
293fdf659dSSasha Levin 	u16			iobase;
303fdf659dSSasha Levin 	u8			irq;
31f6b8ccc1SThomas Gleixner 	u8			irq_state;
328dfae8beSThomas Gleixner 	int			txcnt;
33d4b02a37SThomas Gleixner 	int			rxcnt;
34d4b02a37SThomas Gleixner 	int			rxdone;
35d4b02a37SThomas Gleixner 	char			txbuf[FIFO_LEN];
36d4b02a37SThomas Gleixner 	char			rxbuf[FIFO_LEN];
3776b4a122SPekka Enberg 
383fdf659dSSasha Levin 	u8			dll;
393fdf659dSSasha Levin 	u8			dlm;
403fdf659dSSasha Levin 	u8			iir;
413fdf659dSSasha Levin 	u8			ier;
423fdf659dSSasha Levin 	u8			fcr;
433fdf659dSSasha Levin 	u8			lcr;
443fdf659dSSasha Levin 	u8			mcr;
453fdf659dSSasha Levin 	u8			lsr;
463fdf659dSSasha Levin 	u8			msr;
473fdf659dSSasha Levin 	u8			scr;
4846aa8d69SPekka Enberg };
4946aa8d69SPekka Enberg 
50f3efa592SLiming Wang #define SERIAL_REGS_SETTING \
51f3efa592SLiming Wang 	.iir			= UART_IIR_NO_INT, \
52f3efa592SLiming Wang 	.lsr			= UART_LSR_TEMT | UART_LSR_THRE, \
53f3efa592SLiming Wang 	.msr			= UART_MSR_DCD | UART_MSR_DSR | UART_MSR_CTS, \
54f3efa592SLiming Wang 	.mcr			= UART_MCR_OUT2,
55f3efa592SLiming Wang 
56e62c18deSPekka Enberg static struct serial8250_device devices[] = {
57c6a69c61SPekka Enberg 	/* ttyS0 */
58c6a69c61SPekka Enberg 	[0]	= {
59d3476f7dSSasha Levin 		.mutex			= MUTEX_INITIALIZER,
602932c9ebSPekka Enberg 
611add4b76SSasha Levin 		.id			= 0,
62c6a69c61SPekka Enberg 		.iobase			= 0x3f8,
63e557eef9SPekka Enberg 		.irq			= 4,
64e557eef9SPekka Enberg 
65f3efa592SLiming Wang 		SERIAL_REGS_SETTING
66c6a69c61SPekka Enberg 	},
67e62c18deSPekka Enberg 	/* ttyS1 */
68e62c18deSPekka Enberg 	[1]	= {
69d3476f7dSSasha Levin 		.mutex			= MUTEX_INITIALIZER,
702932c9ebSPekka Enberg 
711add4b76SSasha Levin 		.id			= 1,
72e62c18deSPekka Enberg 		.iobase			= 0x2f8,
73e62c18deSPekka Enberg 		.irq			= 3,
74133bedc1SPekka Enberg 
75f3efa592SLiming Wang 		SERIAL_REGS_SETTING
76e62c18deSPekka Enberg 	},
77e62c18deSPekka Enberg 	/* ttyS2 */
78e62c18deSPekka Enberg 	[2]	= {
79d3476f7dSSasha Levin 		.mutex			= MUTEX_INITIALIZER,
802932c9ebSPekka Enberg 
811add4b76SSasha Levin 		.id			= 2,
82e62c18deSPekka Enberg 		.iobase			= 0x3e8,
83e62c18deSPekka Enberg 		.irq			= 4,
84133bedc1SPekka Enberg 
85f3efa592SLiming Wang 		SERIAL_REGS_SETTING
86e62c18deSPekka Enberg 	},
87bf459c83SPekka Enberg 	/* ttyS3 */
88bf459c83SPekka Enberg 	[3]	= {
89d3476f7dSSasha Levin 		.mutex			= MUTEX_INITIALIZER,
90bf459c83SPekka Enberg 
911add4b76SSasha Levin 		.id			= 3,
92bf459c83SPekka Enberg 		.iobase			= 0x2e8,
93bf459c83SPekka Enberg 		.irq			= 3,
94bf459c83SPekka Enberg 
95f3efa592SLiming Wang 		SERIAL_REGS_SETTING
96bf459c83SPekka Enberg 	},
9746aa8d69SPekka Enberg };
9846aa8d69SPekka Enberg 
992651ea58SSasha Levin static void serial8250_flush_tx(struct kvm *kvm, struct serial8250_device *dev)
100d4b02a37SThomas Gleixner {
101d4b02a37SThomas Gleixner 	dev->lsr |= UART_LSR_TEMT | UART_LSR_THRE;
102d4b02a37SThomas Gleixner 
103d4b02a37SThomas Gleixner 	if (dev->txcnt) {
1042651ea58SSasha Levin 		term_putc(dev->txbuf, dev->txcnt, dev->id);
105d4b02a37SThomas Gleixner 		dev->txcnt = 0;
106d4b02a37SThomas Gleixner 	}
107d4b02a37SThomas Gleixner }
108d4b02a37SThomas Gleixner 
109f6b8ccc1SThomas Gleixner static void serial8250_update_irq(struct kvm *kvm, struct serial8250_device *dev)
110f6b8ccc1SThomas Gleixner {
111f6b8ccc1SThomas Gleixner 	u8 iir = 0;
112f6b8ccc1SThomas Gleixner 
113d4b02a37SThomas Gleixner 	/* Handle clear rx */
114d4b02a37SThomas Gleixner 	if (dev->lcr & UART_FCR_CLEAR_RCVR) {
115d4b02a37SThomas Gleixner 		dev->lcr &= ~UART_FCR_CLEAR_RCVR;
116d4b02a37SThomas Gleixner 		dev->rxcnt = dev->rxdone = 0;
117d4b02a37SThomas Gleixner 		dev->lsr &= ~UART_LSR_DR;
118d4b02a37SThomas Gleixner 	}
119d4b02a37SThomas Gleixner 
120d4b02a37SThomas Gleixner 	/* Handle clear tx */
121d4b02a37SThomas Gleixner 	if (dev->lcr & UART_FCR_CLEAR_XMIT) {
122d4b02a37SThomas Gleixner 		dev->lcr &= ~UART_FCR_CLEAR_XMIT;
123d4b02a37SThomas Gleixner 		dev->txcnt = 0;
124d4b02a37SThomas Gleixner 		dev->lsr |= UART_LSR_TEMT | UART_LSR_THRE;
125d4b02a37SThomas Gleixner 	}
126d4b02a37SThomas Gleixner 
127f6b8ccc1SThomas Gleixner 	/* Data ready and rcv interrupt enabled ? */
128f6b8ccc1SThomas Gleixner 	if ((dev->ier & UART_IER_RDI) && (dev->lsr & UART_LSR_DR))
129f6b8ccc1SThomas Gleixner 		iir |= UART_IIR_RDI;
130f6b8ccc1SThomas Gleixner 
131f6b8ccc1SThomas Gleixner 	/* Transmitter empty and interrupt enabled ? */
132f6b8ccc1SThomas Gleixner 	if ((dev->ier & UART_IER_THRI) && (dev->lsr & UART_LSR_TEMT))
133f6b8ccc1SThomas Gleixner 		iir |= UART_IIR_THRI;
134f6b8ccc1SThomas Gleixner 
135f6b8ccc1SThomas Gleixner 	/* Now update the irq line, if necessary */
136f6b8ccc1SThomas Gleixner 	if (!iir) {
137f6b8ccc1SThomas Gleixner 		dev->iir = UART_IIR_NO_INT;
138f6b8ccc1SThomas Gleixner 		if (dev->irq_state)
139f6b8ccc1SThomas Gleixner 			kvm__irq_line(kvm, dev->irq, 0);
140f6b8ccc1SThomas Gleixner 	} else {
141f6b8ccc1SThomas Gleixner 		dev->iir = iir;
142f6b8ccc1SThomas Gleixner 		if (!dev->irq_state)
143f6b8ccc1SThomas Gleixner 			kvm__irq_line(kvm, dev->irq, 1);
144f6b8ccc1SThomas Gleixner 	}
145f6b8ccc1SThomas Gleixner 	dev->irq_state = iir;
1468dfae8beSThomas Gleixner 
1478dfae8beSThomas Gleixner 	/*
1488dfae8beSThomas Gleixner 	 * If the kernel disabled the tx interrupt, we know that there
1498dfae8beSThomas Gleixner 	 * is nothing more to transmit, so we can reset our tx logic
1508dfae8beSThomas Gleixner 	 * here.
1518dfae8beSThomas Gleixner 	 */
152d4b02a37SThomas Gleixner 	if (!(dev->ier & UART_IER_THRI))
1532651ea58SSasha Levin 		serial8250_flush_tx(kvm, dev);
154f6b8ccc1SThomas Gleixner }
155f6b8ccc1SThomas Gleixner 
156a428f72eSPekka Enberg #define SYSRQ_PENDING_NONE		0
157a428f72eSPekka Enberg 
158a428f72eSPekka Enberg static int sysrq_pending;
159a428f72eSPekka Enberg 
16043835ac9SSasha Levin static void serial8250__sysrq(struct kvm *kvm, struct serial8250_device *dev)
161a428f72eSPekka Enberg {
162a428f72eSPekka Enberg 	dev->lsr |= UART_LSR_DR | UART_LSR_BI;
163226e727bSSasha Levin 	dev->rxbuf[dev->rxcnt++] = sysrq_pending;
164a428f72eSPekka Enberg 	sysrq_pending	= SYSRQ_PENDING_NONE;
165a428f72eSPekka Enberg }
166a428f72eSPekka Enberg 
167d4b02a37SThomas Gleixner static void serial8250__receive(struct kvm *kvm, struct serial8250_device *dev,
168d4b02a37SThomas Gleixner 				bool handle_sysrq)
169251cf9a6SPekka Enberg {
170251cf9a6SPekka Enberg 	int c;
171251cf9a6SPekka Enberg 
172d4b02a37SThomas Gleixner 	if (dev->mcr & UART_MCR_LOOP)
173db34045cSPekka Enberg 		return;
174db34045cSPekka Enberg 
175d4b02a37SThomas Gleixner 	if ((dev->lsr & UART_LSR_DR) || dev->rxcnt)
176d4b02a37SThomas Gleixner 		return;
177d4b02a37SThomas Gleixner 
178d4b02a37SThomas Gleixner 	if (handle_sysrq && sysrq_pending) {
17943835ac9SSasha Levin 		serial8250__sysrq(kvm, dev);
180a428f72eSPekka Enberg 		return;
181a428f72eSPekka Enberg 	}
182a428f72eSPekka Enberg 
1832651ea58SSasha Levin 	if (kvm->cfg.active_console != CONSOLE_8250)
1842651ea58SSasha Levin 		return;
1852651ea58SSasha Levin 
1862651ea58SSasha Levin 	while (term_readable(dev->id) &&
187d4b02a37SThomas Gleixner 	       dev->rxcnt < FIFO_LEN) {
188251cf9a6SPekka Enberg 
1894346fd8fSSasha Levin 		c = term_getc(kvm, dev->id);
19005d1a2a6SAsias He 
191251cf9a6SPekka Enberg 		if (c < 0)
192d4b02a37SThomas Gleixner 			break;
193d4b02a37SThomas Gleixner 		dev->rxbuf[dev->rxcnt++] = c;
194251cf9a6SPekka Enberg 		dev->lsr |= UART_LSR_DR;
195251cf9a6SPekka Enberg 	}
196d4b02a37SThomas Gleixner }
197251cf9a6SPekka Enberg 
198f6b8ccc1SThomas Gleixner void serial8250__update_consoles(struct kvm *kvm)
1998bb34e0dSPekka Enberg {
200479de16fSCyrill Gorcunov 	unsigned int i;
2011add4b76SSasha Levin 
202479de16fSCyrill Gorcunov 	for (i = 0; i < ARRAY_SIZE(devices); i++) {
2031add4b76SSasha Levin 		struct serial8250_device *dev = &devices[i];
204934c193bSPekka Enberg 
2054ef0f4d6SPekka Enberg 		mutex_lock(&dev->mutex);
2062932c9ebSPekka Enberg 
207d4b02a37SThomas Gleixner 		/* Restrict sysrq injection to the first port */
208d4b02a37SThomas Gleixner 		serial8250__receive(kvm, dev, i == 0);
209251cf9a6SPekka Enberg 
210f6b8ccc1SThomas Gleixner 		serial8250_update_irq(kvm, dev);
2112932c9ebSPekka Enberg 
2124ef0f4d6SPekka Enberg 		mutex_unlock(&dev->mutex);
2138bb34e0dSPekka Enberg 	}
2141add4b76SSasha Levin }
2158bb34e0dSPekka Enberg 
216226e727bSSasha Levin void serial8250__inject_sysrq(struct kvm *kvm, char sysrq)
217a428f72eSPekka Enberg {
218226e727bSSasha Levin 	sysrq_pending = sysrq;
219a428f72eSPekka Enberg }
220a428f72eSPekka Enberg 
2214123ca55SMarc Zyngier static bool serial8250_out(struct ioport *ioport, struct kvm_cpu *vcpu, u16 port,
222d4b02a37SThomas Gleixner 			   void *data, int size)
22313a7760fSPekka Enberg {
224d28abb58SWill Deacon 	struct serial8250_device *dev = ioport->priv;
2253fdf659dSSasha Levin 	u16 offset;
2262932c9ebSPekka Enberg 	bool ret = true;
227d4b02a37SThomas Gleixner 	char *addr = data;
22846aa8d69SPekka Enberg 
2294ef0f4d6SPekka Enberg 	mutex_lock(&dev->mutex);
2302932c9ebSPekka Enberg 
231c6a69c61SPekka Enberg 	offset = port - dev->iobase;
232c6a69c61SPekka Enberg 
23346aa8d69SPekka Enberg 	switch (offset) {
234c59fa0c4SThomas Gleixner 	case UART_TX:
235d4b02a37SThomas Gleixner 		if (dev->lcr & UART_LCR_DLAB) {
236c59fa0c4SThomas Gleixner 			dev->dll = ioport__read8(data);
237d4b02a37SThomas Gleixner 			break;
238d4b02a37SThomas Gleixner 		}
239d4b02a37SThomas Gleixner 
240d4b02a37SThomas Gleixner 		/* Loopback mode */
241d4b02a37SThomas Gleixner 		if (dev->mcr & UART_MCR_LOOP) {
242d4b02a37SThomas Gleixner 			if (dev->rxcnt < FIFO_LEN) {
243d4b02a37SThomas Gleixner 				dev->rxbuf[dev->rxcnt++] = *addr;
244d4b02a37SThomas Gleixner 				dev->lsr |= UART_LSR_DR;
245d4b02a37SThomas Gleixner 			}
246d4b02a37SThomas Gleixner 			break;
247d4b02a37SThomas Gleixner 		}
248d4b02a37SThomas Gleixner 
249d4b02a37SThomas Gleixner 		if (dev->txcnt < FIFO_LEN) {
250d4b02a37SThomas Gleixner 			dev->txbuf[dev->txcnt++] = *addr;
251d4b02a37SThomas Gleixner 			dev->lsr &= ~UART_LSR_TEMT;
252d4b02a37SThomas Gleixner 			if (dev->txcnt == FIFO_LEN / 2)
253d4b02a37SThomas Gleixner 				dev->lsr &= ~UART_LSR_THRE;
2544123ca55SMarc Zyngier 			serial8250_flush_tx(vcpu->kvm, dev);
255d4b02a37SThomas Gleixner 		} else {
256d4b02a37SThomas Gleixner 			/* Should never happpen */
257d4b02a37SThomas Gleixner 			dev->lsr &= ~(UART_LSR_TEMT | UART_LSR_THRE);
25846aa8d69SPekka Enberg 		}
259369c01c0SPekka Enberg 		break;
2604e49b05bSCyrill Gorcunov 	case UART_IER:
261f6b8ccc1SThomas Gleixner 		if (!(dev->lcr & UART_LCR_DLAB))
262d4b02a37SThomas Gleixner 			dev->ier = ioport__read8(data) & 0x0f;
263f6b8ccc1SThomas Gleixner 		else
264c59fa0c4SThomas Gleixner 			dev->dlm = ioport__read8(data);
265c59fa0c4SThomas Gleixner 		break;
266c59fa0c4SThomas Gleixner 	case UART_FCR:
267c59fa0c4SThomas Gleixner 		dev->fcr = ioport__read8(data);
26846aa8d69SPekka Enberg 		break;
269369c01c0SPekka Enberg 	case UART_LCR:
270369c01c0SPekka Enberg 		dev->lcr = ioport__read8(data);
271369c01c0SPekka Enberg 		break;
272369c01c0SPekka Enberg 	case UART_MCR:
273369c01c0SPekka Enberg 		dev->mcr = ioport__read8(data);
274369c01c0SPekka Enberg 		break;
275369c01c0SPekka Enberg 	case UART_LSR:
276369c01c0SPekka Enberg 		/* Factory test */
277369c01c0SPekka Enberg 		break;
278369c01c0SPekka Enberg 	case UART_MSR:
279369c01c0SPekka Enberg 		/* Not used */
280369c01c0SPekka Enberg 		break;
281369c01c0SPekka Enberg 	case UART_SCR:
282369c01c0SPekka Enberg 		dev->scr = ioport__read8(data);
283369c01c0SPekka Enberg 		break;
284369c01c0SPekka Enberg 	default:
2852932c9ebSPekka Enberg 		ret = false;
286d2ea115dSThomas Gleixner 		break;
28746aa8d69SPekka Enberg 	}
2882932c9ebSPekka Enberg 
2894123ca55SMarc Zyngier 	serial8250_update_irq(vcpu->kvm, dev);
290f6b8ccc1SThomas Gleixner 
2914ef0f4d6SPekka Enberg 	mutex_unlock(&dev->mutex);
2922932c9ebSPekka Enberg 
2932932c9ebSPekka Enberg 	return ret;
29413a7760fSPekka Enberg }
29513a7760fSPekka Enberg 
296d4b02a37SThomas Gleixner static void serial8250_rx(struct serial8250_device *dev, void *data)
297d4b02a37SThomas Gleixner {
298d4b02a37SThomas Gleixner 	if (dev->rxdone == dev->rxcnt)
299d4b02a37SThomas Gleixner 		return;
300d4b02a37SThomas Gleixner 
301d4b02a37SThomas Gleixner 	/* Break issued ? */
302d4b02a37SThomas Gleixner 	if (dev->lsr & UART_LSR_BI) {
303d4b02a37SThomas Gleixner 		dev->lsr &= ~UART_LSR_BI;
304d4b02a37SThomas Gleixner 		ioport__write8(data, 0);
305d4b02a37SThomas Gleixner 		return;
306d4b02a37SThomas Gleixner 	}
307d4b02a37SThomas Gleixner 
308d4b02a37SThomas Gleixner 	ioport__write8(data, dev->rxbuf[dev->rxdone++]);
309d4b02a37SThomas Gleixner 	if (dev->rxcnt == dev->rxdone) {
310d4b02a37SThomas Gleixner 		dev->lsr &= ~UART_LSR_DR;
311d4b02a37SThomas Gleixner 		dev->rxcnt = dev->rxdone = 0;
312d4b02a37SThomas Gleixner 	}
313d4b02a37SThomas Gleixner }
314d4b02a37SThomas Gleixner 
3154123ca55SMarc Zyngier static bool serial8250_in(struct ioport *ioport, struct kvm_cpu *vcpu, u16 port, void *data, int size)
31625af6674SPekka Enberg {
317d28abb58SWill Deacon 	struct serial8250_device *dev = ioport->priv;
3183fdf659dSSasha Levin 	u16 offset;
3192932c9ebSPekka Enberg 	bool ret = true;
32046aa8d69SPekka Enberg 
3214ef0f4d6SPekka Enberg 	mutex_lock(&dev->mutex);
3222932c9ebSPekka Enberg 
323c6a69c61SPekka Enberg 	offset = port - dev->iobase;
324c6a69c61SPekka Enberg 
32546aa8d69SPekka Enberg 	switch (offset) {
326251cf9a6SPekka Enberg 	case UART_RX:
327d4b02a37SThomas Gleixner 		if (dev->lcr & UART_LCR_DLAB)
328c59fa0c4SThomas Gleixner 			ioport__write8(data, dev->dll);
329d4b02a37SThomas Gleixner 		else
330d4b02a37SThomas Gleixner 			serial8250_rx(dev, data);
331369c01c0SPekka Enberg 		break;
332c59fa0c4SThomas Gleixner 	case UART_IER:
333c59fa0c4SThomas Gleixner 		if (dev->lcr & UART_LCR_DLAB)
334c59fa0c4SThomas Gleixner 			ioport__write8(data, dev->dlm);
335c59fa0c4SThomas Gleixner 		else
336c59fa0c4SThomas Gleixner 			ioport__write8(data, dev->ier);
337c59fa0c4SThomas Gleixner 		break;
338f6b8ccc1SThomas Gleixner 	case UART_IIR:
339d4b02a37SThomas Gleixner 		ioport__write8(data, dev->iir | UART_IIR_TYPE_BITS);
34046aa8d69SPekka Enberg 		break;
3414e49b05bSCyrill Gorcunov 	case UART_LCR:
342c6a69c61SPekka Enberg 		ioport__write8(data, dev->lcr);
34346aa8d69SPekka Enberg 		break;
3444e49b05bSCyrill Gorcunov 	case UART_MCR:
345c6a69c61SPekka Enberg 		ioport__write8(data, dev->mcr);
34646aa8d69SPekka Enberg 		break;
3474e49b05bSCyrill Gorcunov 	case UART_LSR:
348c6a69c61SPekka Enberg 		ioport__write8(data, dev->lsr);
34946aa8d69SPekka Enberg 		break;
3504e49b05bSCyrill Gorcunov 	case UART_MSR:
351369c01c0SPekka Enberg 		ioport__write8(data, dev->msr);
35246aa8d69SPekka Enberg 		break;
3534e49b05bSCyrill Gorcunov 	case UART_SCR:
354369c01c0SPekka Enberg 		ioport__write8(data, dev->scr);
35546aa8d69SPekka Enberg 		break;
356369c01c0SPekka Enberg 	default:
3572932c9ebSPekka Enberg 		ret = false;
358c59fa0c4SThomas Gleixner 		break;
35925af6674SPekka Enberg 	}
360f6b8ccc1SThomas Gleixner 
3614123ca55SMarc Zyngier 	serial8250_update_irq(vcpu->kvm, dev);
362f6b8ccc1SThomas Gleixner 
3634ef0f4d6SPekka Enberg 	mutex_unlock(&dev->mutex);
3642932c9ebSPekka Enberg 
3652932c9ebSPekka Enberg 	return ret;
36613a7760fSPekka Enberg }
36713a7760fSPekka Enberg 
368d28abb58SWill Deacon #ifdef CONFIG_HAS_LIBFDT
369*56e45ea4SAndre Przywara 
370*56e45ea4SAndre Przywara char *fdt_stdout_path = NULL;
371*56e45ea4SAndre Przywara 
372e5965f36SMarc Zyngier #define DEVICE_NAME_MAX_LEN 32
3732bfd9ac3SAndre Przywara static
3742bfd9ac3SAndre Przywara void serial8250_generate_fdt_node(struct ioport *ioport, void *fdt,
375d28abb58SWill Deacon 				  void (*generate_irq_prop)(void *fdt,
3762bfd9ac3SAndre Przywara 							    u8 irq,
3772bfd9ac3SAndre Przywara 							    enum irq_type))
378d28abb58SWill Deacon {
379e5965f36SMarc Zyngier 	char dev_name[DEVICE_NAME_MAX_LEN];
380d28abb58SWill Deacon 	struct serial8250_device *dev = ioport->priv;
381e5965f36SMarc Zyngier 	u64 addr = KVM_IOPORT_AREA + dev->iobase;
382d28abb58SWill Deacon 	u64 reg_prop[] = {
383e5965f36SMarc Zyngier 		cpu_to_fdt64(addr),
384d28abb58SWill Deacon 		cpu_to_fdt64(8),
385d28abb58SWill Deacon 	};
386d28abb58SWill Deacon 
387e5965f36SMarc Zyngier 	snprintf(dev_name, DEVICE_NAME_MAX_LEN, "U6_16550A@%llx", addr);
388e5965f36SMarc Zyngier 
389*56e45ea4SAndre Przywara 	if (!fdt_stdout_path) {
390*56e45ea4SAndre Przywara 		fdt_stdout_path = malloc(strlen(dev_name) + 2);
391*56e45ea4SAndre Przywara 		/* Assumes that this node is a child of the root node. */
392*56e45ea4SAndre Przywara 		sprintf(fdt_stdout_path, "/%s", dev_name);
393*56e45ea4SAndre Przywara 	}
394*56e45ea4SAndre Przywara 
395e5965f36SMarc Zyngier 	_FDT(fdt_begin_node(fdt, dev_name));
396d28abb58SWill Deacon 	_FDT(fdt_property_string(fdt, "compatible", "ns16550a"));
397d28abb58SWill Deacon 	_FDT(fdt_property(fdt, "reg", reg_prop, sizeof(reg_prop)));
398890ad914SAndre Przywara 	generate_irq_prop(fdt, dev->irq, IRQ_TYPE_LEVEL_HIGH);
399d28abb58SWill Deacon 	_FDT(fdt_property_cell(fdt, "clock-frequency", 1843200));
400d28abb58SWill Deacon 	_FDT(fdt_end_node(fdt));
401d28abb58SWill Deacon }
402d28abb58SWill Deacon #else
403d28abb58SWill Deacon #define serial8250_generate_fdt_node	NULL
404d28abb58SWill Deacon #endif
405d28abb58SWill Deacon 
40646aa8d69SPekka Enberg static struct ioport_operations serial8250_ops = {
40746aa8d69SPekka Enberg 	.io_in			= serial8250_in,
40846aa8d69SPekka Enberg 	.io_out			= serial8250_out,
409d28abb58SWill Deacon 	.generate_fdt_node	= serial8250_generate_fdt_node,
410a93ec68bSPekka Enberg };
411a93ec68bSPekka Enberg 
41220715a22SSasha Levin static int serial8250__device_init(struct kvm *kvm, struct serial8250_device *dev)
413bc4b0ffeSPekka Enberg {
41420715a22SSasha Levin 	int r;
41520715a22SSasha Levin 
416206c41f4SWill Deacon 	ioport__map_irq(&dev->irq);
417d28abb58SWill Deacon 	r = ioport__register(kvm, dev->iobase, &serial8250_ops, 8, dev);
41820715a22SSasha Levin 
41920715a22SSasha Levin 	return r;
420bc4b0ffeSPekka Enberg }
421bc4b0ffeSPekka Enberg 
42220715a22SSasha Levin int serial8250__init(struct kvm *kvm)
42313a7760fSPekka Enberg {
42420715a22SSasha Levin 	unsigned int i, j;
42520715a22SSasha Levin 	int r = 0;
426c6a69c61SPekka Enberg 
427c6a69c61SPekka Enberg 	for (i = 0; i < ARRAY_SIZE(devices); i++) {
428c6a69c61SPekka Enberg 		struct serial8250_device *dev = &devices[i];
429c6a69c61SPekka Enberg 
43020715a22SSasha Levin 		r = serial8250__device_init(kvm, dev);
43120715a22SSasha Levin 		if (r < 0)
43220715a22SSasha Levin 			goto cleanup;
433c6a69c61SPekka Enberg 	}
43420715a22SSasha Levin 
43520715a22SSasha Levin 	return r;
43620715a22SSasha Levin cleanup:
43720715a22SSasha Levin 	for (j = 0; j <= i; j++) {
43820715a22SSasha Levin 		struct serial8250_device *dev = &devices[j];
43920715a22SSasha Levin 
4404346fd8fSSasha Levin 		ioport__unregister(kvm, dev->iobase);
44120715a22SSasha Levin 	}
44220715a22SSasha Levin 
44320715a22SSasha Levin 	return r;
44420715a22SSasha Levin }
44549a8afd1SSasha Levin dev_init(serial8250__init);
44620715a22SSasha Levin 
44720715a22SSasha Levin int serial8250__exit(struct kvm *kvm)
44820715a22SSasha Levin {
44920715a22SSasha Levin 	unsigned int i;
45020715a22SSasha Levin 	int r;
45120715a22SSasha Levin 
45220715a22SSasha Levin 	for (i = 0; i < ARRAY_SIZE(devices); i++) {
45320715a22SSasha Levin 		struct serial8250_device *dev = &devices[i];
45420715a22SSasha Levin 
4554346fd8fSSasha Levin 		r = ioport__unregister(kvm, dev->iobase);
45620715a22SSasha Levin 		if (r < 0)
45720715a22SSasha Levin 			return r;
45820715a22SSasha Levin 	}
45920715a22SSasha Levin 
46020715a22SSasha Levin 	return 0;
46113a7760fSPekka Enberg }
46249a8afd1SSasha Levin dev_exit(serial8250__exit);
463