xref: /freebsd/sys/powerpc/powernv/opal_console.c (revision 18250ec6c089c0c50cbd9fd87d78e03ff89916df)
1  /*-
2   * Copyright (C) 2011,2015 by Nathan Whitehorn. All rights reserved.
3   *
4   * Redistribution and use in source and binary forms, with or without
5   * modification, are permitted provided that the following conditions
6   * are met:
7   * 1. Redistributions of source code must retain the above copyright
8   *    notice, this list of conditions and the following disclaimer.
9   * 2. Redistributions in binary form must reproduce the above copyright
10   *    notice, this list of conditions and the following disclaimer in the
11   *    documentation and/or other materials provided with the distribution.
12   *
13   * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
14   * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
15   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
16   * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
17   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
18   * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
19   * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
20   * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
21   * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
22   * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23   */
24  
25  #include <sys/cdefs.h>
26  #include <sys/endian.h>
27  #include <sys/param.h>
28  #include <sys/conf.h>
29  #include <sys/cons.h>
30  #include <sys/kdb.h>
31  #include <sys/kernel.h>
32  #include <sys/lock.h>
33  #include <sys/module.h>
34  #include <sys/mutex.h>
35  #include <sys/priv.h>
36  #include <sys/proc.h>
37  #include <sys/systm.h>
38  #include <sys/tty.h>
39  
40  #include <vm/vm.h>
41  #include <vm/pmap.h>
42  
43  #include <machine/bus.h>
44  
45  #include <dev/ofw/openfirm.h>
46  #include <dev/ofw/ofw_bus.h>
47  #include <dev/ofw/ofw_bus_subr.h>
48  #include <dev/uart/uart.h>
49  #include <dev/uart/uart_cpu.h>
50  #include <dev/uart/uart_bus.h>
51  
52  #include "opal.h"
53  #include "uart_if.h"
54  
55  struct uart_opal_softc {
56  	device_t dev;
57  	phandle_t node;
58  	int vtermid;
59  
60  	struct tty *tp;
61  	struct resource *irqres;
62  	int irqrid;
63  	struct callout callout;
64  	void *sc_icookie;
65  	int polltime;
66  
67  	struct mtx sc_mtx;
68  	int protocol;
69  
70  	char opal_inbuf[16];
71  	uint64_t inbuflen;
72  	uint8_t outseqno;
73  #if defined(KDB)
74  	int alt_break_state;
75  #endif
76  };
77  
78  static struct uart_opal_softc	*console_sc = NULL;
79  static struct consdev *stdout_cp;
80  
81  enum {
82  	OPAL_RAW, OPAL_HVSI
83  };
84  
85  #define VS_DATA_PACKET_HEADER		0xff
86  #define VS_CONTROL_PACKET_HEADER	0xfe
87  #define  VSV_SET_MODEM_CTL		0x01
88  #define  VSV_MODEM_CTL_UPDATE		0x02
89  #define  VSV_RENEGOTIATE_CONNECTION	0x03
90  #define VS_QUERY_PACKET_HEADER		0xfd
91  #define  VSV_SEND_VERSION_NUMBER	0x01
92  #define  VSV_SEND_MODEM_CTL_STATUS	0x02
93  #define VS_QUERY_RESPONSE_PACKET_HEADER	0xfc
94  
95  static int uart_opal_probe(device_t dev);
96  static int uart_opal_attach(device_t dev);
97  static void uart_opal_intr(void *v);
98  
99  static device_method_t uart_opal_methods[] = {
100  	/* Device interface */
101  	DEVMETHOD(device_probe,		uart_opal_probe),
102  	DEVMETHOD(device_attach,	uart_opal_attach),
103  
104  	DEVMETHOD_END
105  };
106  
107  static driver_t uart_opal_driver = {
108  	"uart",
109  	uart_opal_methods,
110  	sizeof(struct uart_opal_softc),
111  };
112  
113  DRIVER_MODULE(uart_opal, opalcons, uart_opal_driver, 0, 0);
114  
115  static int uart_opal_getc(struct uart_opal_softc *sc);
116  static cn_probe_t uart_opal_cnprobe;
117  static cn_init_t uart_opal_cninit;
118  static cn_term_t uart_opal_cnterm;
119  static cn_getc_t uart_opal_cngetc;
120  static cn_putc_t uart_opal_cnputc;
121  static cn_grab_t uart_opal_cngrab;
122  static cn_ungrab_t uart_opal_cnungrab;
123  
124  CONSOLE_DRIVER(uart_opal);
125  
126  static void uart_opal_ttyoutwakeup(struct tty *tp);
127  
128  static struct ttydevsw uart_opal_tty_class = {
129  	.tsw_flags	= TF_INITLOCK|TF_CALLOUT,
130  	.tsw_outwakeup	= uart_opal_ttyoutwakeup,
131  };
132  
133  static struct {
134  	char tmpbuf[16];
135  	uint64_t size;
136  	struct mtx mtx;
137  } opalcons_buffer;
138  
139  static void
uart_opal_real_map_outbuffer(uint64_t * bufferp,uint64_t * lenp)140  uart_opal_real_map_outbuffer(uint64_t *bufferp, uint64_t *lenp)
141  {
142  
143  	if (!mtx_initialized(&opalcons_buffer.mtx))
144  		mtx_init(&opalcons_buffer.mtx, "uart_opal", NULL,
145  		    MTX_SPIN | MTX_QUIET | MTX_NOWITNESS);
146  
147  	if (!pmap_bootstrapped)
148  		return;
149  
150  	mtx_lock_spin(&opalcons_buffer.mtx);
151  
152  	opalcons_buffer.size = *(uint64_t *)(*lenp) =
153  	    min(sizeof(opalcons_buffer.tmpbuf), *(uint64_t *)(*lenp));
154  	memcpy(opalcons_buffer.tmpbuf, (void *)(*bufferp),
155  	    *(uint64_t *)(*lenp));
156  	*bufferp = (uint64_t)opalcons_buffer.tmpbuf;
157  	*lenp = (uint64_t)&opalcons_buffer.size;
158  }
159  
160  static void
uart_opal_real_unmap_outbuffer(uint64_t * len)161  uart_opal_real_unmap_outbuffer(uint64_t *len)
162  {
163  
164  	if (!pmap_bootstrapped)
165  		return;
166  
167  	mtx_assert(&opalcons_buffer.mtx, MA_OWNED);
168  	*len = opalcons_buffer.size;
169  	mtx_unlock_spin(&opalcons_buffer.mtx);
170  }
171  
172  static int64_t
uart_opal_console_write_buffer_space(int vtermid)173  uart_opal_console_write_buffer_space(int vtermid)
174  {
175  	int64_t buffer_space_val = 0;
176  	vm_paddr_t buffer_space_ptr;
177  
178  	if (pmap_bootstrapped)
179  		buffer_space_ptr = vtophys(&buffer_space_val);
180  	else
181  		buffer_space_ptr = (vm_paddr_t)&buffer_space_val;
182  
183  	if (opal_call(OPAL_CONSOLE_WRITE_BUFFER_SPACE, vtermid,
184  	    buffer_space_ptr) != OPAL_SUCCESS)
185  		return (-1);
186  
187  	return (be64toh(buffer_space_val));
188  }
189  
190  static int
uart_opal_probe_node(struct uart_opal_softc * sc)191  uart_opal_probe_node(struct uart_opal_softc *sc)
192  {
193  	phandle_t node = sc->node;
194  	uint32_t reg;
195  	char buf[64];
196  
197  	sc->inbuflen = 0;
198  	sc->outseqno = 0;
199  
200  	if (OF_getprop(node, "device_type", buf, sizeof(buf)) <= 0)
201  		return (ENXIO);
202  	if (strcmp(buf, "serial") != 0)
203  		return (ENXIO);
204  
205  	reg = -1;
206  	OF_getencprop(node, "reg", &reg, sizeof(reg));
207  	if (reg == -1)
208  		return (ENXIO);
209  	sc->vtermid = reg;
210  	sc->node = node;
211  
212  	if (OF_getprop(node, "compatible", buf, sizeof(buf)) <= 0)
213  		return (ENXIO);
214  	if (strcmp(buf, "ibm,opal-console-raw") == 0) {
215  		sc->protocol = OPAL_RAW;
216  		return (0);
217  	} else if (strcmp(buf, "ibm,opal-console-hvsi") == 0) {
218  		sc->protocol = OPAL_HVSI;
219  		return (0);
220  	}
221  
222  	return (ENXIO);
223  }
224  
225  static int
uart_opal_probe(device_t dev)226  uart_opal_probe(device_t dev)
227  {
228  	struct uart_opal_softc sc;
229  	int err;
230  
231  	sc.node = ofw_bus_get_node(dev);
232  	err = uart_opal_probe_node(&sc);
233  	if (err != 0)
234  		return (err);
235  
236  	device_set_desc(dev, "OPAL Serial Port");
237  
238  	return (err);
239  }
240  
241  static void
uart_opal_cnprobe(struct consdev * cp)242  uart_opal_cnprobe(struct consdev *cp)
243  {
244  	char buf[64];
245  	phandle_t input, chosen;
246  	static struct uart_opal_softc sc;
247  
248  	if (opal_check() != 0)
249  		goto fail;
250  
251  	if ((chosen = OF_finddevice("/chosen")) == -1)
252  		goto fail;
253  
254  	/* Check if OF has an active stdin/stdout */
255  	if (OF_getprop(chosen, "linux,stdout-path", buf, sizeof(buf)) <= 0)
256  		goto fail;
257  
258  	input = OF_finddevice(buf);
259  	if (input == -1)
260  		goto fail;
261  
262  	sc.node = input;
263  	if (uart_opal_probe_node(&sc) != 0)
264  		goto fail;
265  	mtx_init(&sc.sc_mtx, "uart_opal", NULL, MTX_SPIN | MTX_QUIET |
266  	    MTX_NOWITNESS);
267  
268  	cp->cn_pri = CN_NORMAL;
269  	console_sc = &sc;
270  	cp->cn_arg = console_sc;
271  	stdout_cp = cp;
272  	return;
273  
274  fail:
275  	cp->cn_pri = CN_DEAD;
276  	return;
277  }
278  
279  static int
uart_opal_attach(device_t dev)280  uart_opal_attach(device_t dev)
281  {
282  	struct uart_opal_softc *sc;
283  	int unit;
284  
285  	sc = device_get_softc(dev);
286  	sc->node = ofw_bus_get_node(dev);
287  	uart_opal_probe_node(sc);
288  
289  	unit = device_get_unit(dev);
290  	mtx_init(&sc->sc_mtx, device_get_nameunit(dev), NULL,
291  	    MTX_SPIN | MTX_QUIET | MTX_NOWITNESS);
292  
293  	if (console_sc != NULL && console_sc->vtermid == sc->vtermid) {
294  		device_printf(dev, "console\n");
295  		device_set_softc(dev, console_sc);
296  		sc = console_sc;
297  		sprintf(uart_opal_consdev.cn_name, "ttyu%r", unit);
298  	}
299  	sc->tp = tty_alloc(&uart_opal_tty_class, sc);
300  
301  	if (console_sc == sc)
302  		tty_init_console(sc->tp, 0);
303  
304  	sc->dev = dev;
305  	sc->irqrid = 0;
306  	sc->irqres = bus_alloc_resource_any(dev, SYS_RES_IRQ, &sc->irqrid,
307  	    RF_ACTIVE | RF_SHAREABLE);
308  	if (sc->irqres != NULL) {
309  		bus_setup_intr(dev, sc->irqres, INTR_TYPE_TTY | INTR_MPSAFE,
310  		    NULL, uart_opal_intr, sc, &sc->sc_icookie);
311  	} else {
312  		callout_init(&sc->callout, CALLOUT_MPSAFE);
313  		sc->polltime = hz / 20;
314  		if (sc->polltime < 1)
315  			sc->polltime = 1;
316  		callout_reset(&sc->callout, sc->polltime, uart_opal_intr, sc);
317  	}
318  
319  	tty_makedev(sc->tp, NULL, "u%r", unit);
320  
321  	return (0);
322  }
323  
324  static void
uart_opal_cninit(struct consdev * cp)325  uart_opal_cninit(struct consdev *cp)
326  {
327  
328  	strcpy(cp->cn_name, "opalcons");
329  }
330  
331  static void
uart_opal_cnterm(struct consdev * cp)332  uart_opal_cnterm(struct consdev *cp)
333  {
334  }
335  
336  static int
uart_opal_get(struct uart_opal_softc * sc,void * buffer,size_t bufsize)337  uart_opal_get(struct uart_opal_softc *sc, void *buffer, size_t bufsize)
338  {
339  	int err;
340  	int hdr = 0;
341  
342  	if (sc->protocol == OPAL_RAW) {
343  		uint64_t len = htobe64(bufsize);
344  		uint64_t olen = (uint64_t)&len;
345  		uint64_t obuf = (uint64_t)buffer;
346  
347  		if (pmap_bootstrapped) {
348  			olen = vtophys(&len);
349  			obuf = vtophys(buffer);
350  		}
351  
352  		err = opal_call(OPAL_CONSOLE_READ, sc->vtermid, olen, obuf);
353  		if (err != OPAL_SUCCESS)
354  			return (-1);
355  
356  		bufsize = be64toh(len);
357  	} else {
358  		uart_lock(&sc->sc_mtx);
359  		if (sc->inbuflen == 0) {
360  			err = opal_call(OPAL_CONSOLE_READ, sc->vtermid,
361  			    &sc->inbuflen, sc->opal_inbuf);
362  			if (err != OPAL_SUCCESS) {
363  				uart_unlock(&sc->sc_mtx);
364  				return (-1);
365  			}
366  			hdr = 1;
367  			sc->inbuflen = be64toh(sc->inbuflen);
368  		}
369  
370  		if (sc->inbuflen == 0) {
371  			uart_unlock(&sc->sc_mtx);
372  			return (0);
373  		}
374  
375  		if (bufsize > sc->inbuflen)
376  			bufsize = sc->inbuflen;
377  
378  		if (hdr == 1) {
379  			sc->inbuflen = sc->inbuflen - 4;
380  			/* The HVSI protocol has a 4 byte header, skip it */
381  			memmove(&sc->opal_inbuf[0], &sc->opal_inbuf[4],
382  			    sc->inbuflen);
383  		}
384  
385  		memcpy(buffer, sc->opal_inbuf, bufsize);
386  		sc->inbuflen -= bufsize;
387  		if (sc->inbuflen > 0)
388  			memmove(&sc->opal_inbuf[0], &sc->opal_inbuf[bufsize],
389  			    sc->inbuflen);
390  
391  		uart_unlock(&sc->sc_mtx);
392  	}
393  
394  	return (bufsize);
395  }
396  
397  static int
uart_opal_put(struct uart_opal_softc * sc,void * buffer,size_t bufsize)398  uart_opal_put(struct uart_opal_softc *sc, void *buffer, size_t bufsize)
399  {
400  	uint16_t seqno;
401  	uint64_t len;
402  	char	cbuf[16];
403  	int	err;
404  	uint64_t olen = (uint64_t)&len;
405  	uint64_t obuf = (uint64_t)cbuf;
406  
407  	if (sc->protocol == OPAL_RAW) {
408  		obuf = (uint64_t)buffer;
409  		len = bufsize;
410  
411  		uart_opal_real_map_outbuffer(&obuf, &olen);
412  		*(uint64_t*)olen = htobe64(*(uint64_t*)olen);
413  		err = opal_call(OPAL_CONSOLE_WRITE, sc->vtermid, olen, obuf);
414  		*(uint64_t*)olen = be64toh(*(uint64_t*)olen);
415  		uart_opal_real_unmap_outbuffer(&len);
416  	} else {
417  		uart_lock(&sc->sc_mtx);
418  		if (bufsize > 12)
419  			bufsize = 12;
420  		seqno = sc->outseqno++;
421  		cbuf[0] = VS_DATA_PACKET_HEADER;
422  		cbuf[1] = 4 + bufsize; /* total length */
423  		cbuf[2] = (seqno >> 8) & 0xff;
424  		cbuf[3] = seqno & 0xff;
425  		memcpy(&cbuf[4], buffer, bufsize);
426  		len = 4 + bufsize;
427  
428  		uart_opal_real_map_outbuffer(&obuf, &olen);
429  		*(uint64_t*)olen = htobe64(*(uint64_t*)olen);
430  		err = opal_call(OPAL_CONSOLE_WRITE, sc->vtermid, olen, obuf);
431  		*(uint64_t*)olen = be64toh(*(uint64_t*)olen);
432  		uart_opal_real_unmap_outbuffer(&len);
433  
434  		uart_unlock(&sc->sc_mtx);
435  
436  		len -= 4;
437  	}
438  
439  	if (err == OPAL_SUCCESS)
440  		return (len);
441  	else if (err == OPAL_BUSY_EVENT)
442  		return(0);
443  
444  	return (-1);
445  }
446  
447  static int
uart_opal_cngetc(struct consdev * cp)448  uart_opal_cngetc(struct consdev *cp)
449  {
450  	return (uart_opal_getc(cp->cn_arg));
451  }
452  
453  static int
uart_opal_getc(struct uart_opal_softc * sc)454  uart_opal_getc(struct uart_opal_softc *sc)
455  {
456  	unsigned char c;
457  	int retval;
458  
459  	retval = uart_opal_get(sc, &c, 1);
460  	if (retval != 1)
461  		return (-1);
462  #if defined(KDB)
463  	kdb_alt_break(c, &sc->alt_break_state);
464  #endif
465  
466  	return (c);
467  }
468  
469  static void
uart_opal_cnputc(struct consdev * cp,int c)470  uart_opal_cnputc(struct consdev *cp, int c)
471  {
472  	unsigned char ch = c;
473  	int a;
474  
475  	if (1) {
476  		/* Clear FIFO if needed. Must be repeated few times. */
477  		for (a = 0; a < 20; a++) {
478  			opal_call(OPAL_POLL_EVENTS, NULL);
479  		}
480  	}
481  	uart_opal_put(cp->cn_arg, &ch, 1);
482  }
483  
484  static void
uart_opal_cngrab(struct consdev * cp)485  uart_opal_cngrab(struct consdev *cp)
486  {
487  }
488  
489  static void
uart_opal_cnungrab(struct consdev * cp)490  uart_opal_cnungrab(struct consdev *cp)
491  {
492  }
493  
494  static void
uart_opal_ttyoutwakeup(struct tty * tp)495  uart_opal_ttyoutwakeup(struct tty *tp)
496  {
497  	struct uart_opal_softc *sc;
498  	char buffer[8];
499  	int len;
500  	int64_t buffer_space;
501  
502  	sc = tty_softc(tp);
503  
504  	while ((len = ttydisc_getc(tp, buffer, sizeof(buffer))) != 0) {
505  		int bytes_written = 0;
506  		while (bytes_written == 0) {
507  			buffer_space = uart_opal_console_write_buffer_space(sc->vtermid);
508  			if (buffer_space == -1)
509  				/* OPAL failure or invalid terminal */
510  				break;
511  			else if (buffer_space >= len)
512  				bytes_written = uart_opal_put(sc, buffer, len);
513  
514  			if (bytes_written == 0)
515  				/* OPAL must be busy, poll and retry */
516  				opal_call(OPAL_POLL_EVENTS, NULL);
517  			else if (bytes_written == -1)
518  				/* OPAL failure or invalid terminal */
519  				break;
520  		}
521  	}
522  }
523  
524  static void
uart_opal_intr(void * v)525  uart_opal_intr(void *v)
526  {
527  	struct uart_opal_softc *sc = v;
528  	struct tty *tp = sc->tp;
529  	int c;
530  
531  	tty_lock(tp);
532  	while ((c = uart_opal_getc(sc)) > 0)
533  		ttydisc_rint(tp, c, 0);
534  	ttydisc_rint_done(tp);
535  	tty_unlock(tp);
536  
537  	opal_call(OPAL_POLL_EVENTS, NULL);
538  
539  	if (sc->irqres == NULL)
540  		callout_reset(&sc->callout, sc->polltime, uart_opal_intr, sc);
541  }
542  
543  static int
opalcons_probe(device_t dev)544  opalcons_probe(device_t dev)
545  {
546  	const char *name;
547  
548  	name = ofw_bus_get_name(dev);
549  	if (name == NULL || strcmp(name, "consoles") != 0)
550  		return (ENXIO);
551  
552  	device_set_desc(dev, "OPAL Consoles");
553  	return (BUS_PROBE_SPECIFIC);
554  }
555  
556  static int
opalcons_attach(device_t dev)557  opalcons_attach(device_t dev)
558  {
559  	phandle_t child;
560  	device_t cdev;
561  	struct ofw_bus_devinfo *dinfo;
562  
563  	for (child = OF_child(ofw_bus_get_node(dev)); child != 0;
564  	    child = OF_peer(child)) {
565  		dinfo = malloc(sizeof(*dinfo), M_DEVBUF, M_WAITOK | M_ZERO);
566  		if (ofw_bus_gen_setup_devinfo(dinfo, child) != 0) {
567  			free(dinfo, M_DEVBUF);
568  			continue;
569  		}
570  		cdev = device_add_child(dev, NULL, DEVICE_UNIT_ANY);
571  		if (cdev == NULL) {
572  			device_printf(dev, "<%s>: device_add_child failed\n",
573  			    dinfo->obd_name);
574  			ofw_bus_gen_destroy_devinfo(dinfo);
575  			free(dinfo, M_DEVBUF);
576  			continue;
577  		}
578  		device_set_ivars(cdev, dinfo);
579  	}
580  
581  	bus_attach_children(dev);
582  	return (0);
583  }
584  
585  static const struct ofw_bus_devinfo *
opalcons_get_devinfo(device_t dev,device_t child)586  opalcons_get_devinfo(device_t dev, device_t child)
587  {
588          return (device_get_ivars(child));
589  }
590  
591  static device_method_t opalcons_methods[] = {
592  	/* Device interface */
593  	DEVMETHOD(device_probe,		opalcons_probe),
594  	DEVMETHOD(device_attach,	opalcons_attach),
595  
596  	/* ofw_bus interface */
597  	DEVMETHOD(ofw_bus_get_devinfo,	opalcons_get_devinfo),
598  	DEVMETHOD(ofw_bus_get_compat,	ofw_bus_gen_get_compat),
599  	DEVMETHOD(ofw_bus_get_model,	ofw_bus_gen_get_model),
600  	DEVMETHOD(ofw_bus_get_name,	ofw_bus_gen_get_name),
601  	DEVMETHOD(ofw_bus_get_node,	ofw_bus_gen_get_node),
602  	DEVMETHOD(ofw_bus_get_type,	ofw_bus_gen_get_type),
603  
604  	DEVMETHOD_END
605  };
606  
607  static driver_t opalcons_driver = {
608          "opalcons",
609          opalcons_methods,
610          0
611  };
612  
613  DRIVER_MODULE(opalcons, opal, opalcons_driver, 0, 0);
614