svn commit: r277766 - projects/powernv/powerpc/powernv

Nathan Whitehorn nwhitehorn at FreeBSD.org
Mon Jan 26 19:01:07 UTC 2015


Author: nwhitehorn
Date: Mon Jan 26 19:01:06 2015
New Revision: 277766
URL: https://svnweb.freebsd.org/changeset/base/277766

Log:
  Avoid the lock in vtophys() by providing a static direct-mapped spinlock-
  protected output buffer to use when the console driver cannot acquire locks
  for some reason. This allows the idle thread to use printf() (e.g.  the SMP
  startup messages) without crashing the kernel.

Modified:
  projects/powernv/powerpc/powernv/opal_console.c

Modified: projects/powernv/powerpc/powernv/opal_console.c
==============================================================================
--- projects/powernv/powerpc/powernv/opal_console.c	Mon Jan 26 18:48:27 2015	(r277765)
+++ projects/powernv/powerpc/powernv/opal_console.c	Mon Jan 26 19:01:06 2015	(r277766)
@@ -34,6 +34,7 @@ __FBSDID("$FreeBSD$");
 #include <sys/types.h>
 #include <sys/conf.h>
 #include <sys/cons.h>
+#include <sys/proc.h>
 #include <sys/tty.h>
 
 #include <vm/vm.h>
@@ -70,6 +71,7 @@ struct uart_opal_softc {
 };
 
 static struct uart_opal_softc	*console_sc = NULL;
+
 #if defined(KDB)
 static int			alt_break_state;
 #endif
@@ -125,6 +127,48 @@ static struct ttydevsw uart_opal_tty_cla
 	.tsw_outwakeup	= uart_opal_ttyoutwakeup,
 };
 
+static struct {
+	char tmpbuf[16];
+	uint64_t size;
+	struct mtx mtx;
+} escapehatch;
+
+static void
+uart_opal_real_map_outbuffer(uint64_t *bufferp, uint64_t *lenp)
+{
+
+	if (!mtx_initialized(&escapehatch.mtx))
+		mtx_init(&escapehatch.mtx, "uart_opal", NULL, MTX_SPIN | MTX_QUIET |
+		    MTX_NOWITNESS);
+
+	if (!pmap_bootstrapped)
+		return;
+
+	if (TD_IS_IDLETHREAD(curthread)) {
+		escapehatch.size = *(uint64_t *)(*lenp) =
+		    min(sizeof(escapehatch.tmpbuf), *(uint64_t *)(*lenp));
+		mtx_lock_spin(&escapehatch.mtx);
+		memcpy(escapehatch.tmpbuf, (void *)(*bufferp), *(uint64_t *)(*lenp));
+		*bufferp = (uint64_t)escapehatch.tmpbuf;
+		*lenp = (uint64_t)&escapehatch.size;
+	}
+
+	*bufferp = vtophys(*bufferp);
+	*lenp = vtophys(*lenp);
+}
+	
+static void
+uart_opal_real_unmap_outbuffer(uint64_t lenp, uint64_t *origlen)
+{
+
+	if (!pmap_bootstrapped || !TD_IS_IDLETHREAD(curthread))
+		return;
+
+	mtx_assert(&escapehatch.mtx, MA_OWNED);
+	*origlen = escapehatch.size;
+	mtx_unlock_spin(&escapehatch.mtx);
+}
+
 static int
 uart_opal_probe_node(struct uart_opal_softc *sc)
 {
@@ -229,6 +273,7 @@ uart_opal_attach(device_t dev)
 	    MTX_SPIN | MTX_QUIET | MTX_NOWITNESS);
 
 	if (console_sc != NULL && console_sc->vtermid == sc->vtermid) {
+		device_printf(dev, "console\n");
 		sc->outseqno = console_sc->outseqno;
 		console_sc = sc;
 		sprintf(uart_opal_consdev.cn_name, "ttyu%r", unit);
@@ -330,25 +375,20 @@ static int
 uart_opal_put(struct uart_opal_softc *sc, void *buffer, size_t bufsize)
 {
 	uint16_t seqno;
-	uint64_t len = bufsize;
+	uint64_t len;
 	char	cbuf[16];
 	int	err;
 	uint64_t olen = (uint64_t)&len;
 	uint64_t obuf = (uint64_t)cbuf;
 
-	if (pmap_bootstrapped)
-		olen = vtophys(&len);
-
 	if (sc->protocol == OPAL_RAW) {
-		if (pmap_bootstrapped)
-			obuf = vtophys(buffer);
-		else
-			obuf = (uint64_t)(buffer);
+		obuf = (uint64_t)buffer;
+		len = bufsize;
 
+		uart_opal_real_map_outbuffer(&obuf, &olen);
 		err = opal_call(OPAL_CONSOLE_WRITE, sc->vtermid, olen, obuf);
+		uart_opal_real_unmap_outbuffer(olen, &len);
 	} else {
-		if (pmap_bootstrapped)
-			obuf = vtophys(cbuf);
 		uart_lock(&sc->sc_mtx);
 		if (bufsize > 12)
 			bufsize = 12;
@@ -359,7 +399,11 @@ uart_opal_put(struct uart_opal_softc *sc
 		cbuf[3] = seqno & 0xff;
 		memcpy(&cbuf[4], buffer, bufsize);
 		len = 4 + bufsize;
+
+		uart_opal_real_map_outbuffer(&obuf, &olen);
 		err = opal_call(OPAL_CONSOLE_WRITE, sc->vtermid, olen, obuf);
+		uart_opal_real_unmap_outbuffer(olen, &len);
+
 		uart_unlock(&sc->sc_mtx);
 
 		len -= 4;


More information about the svn-src-projects mailing list