summaryrefslogtreecommitdiff
path: root/arch/powerpc/platforms/powernv/opal.c
diff options
context:
space:
mode:
authorNicholas Piggin <npiggin@gmail.com>2018-04-30 17:55:48 +0300
committerMichael Ellerman <mpe@ellerman.id.au>2018-07-24 15:09:56 +0300
commitd2a2262e686ce7a27776add27751f925ceda856f (patch)
tree4dff5a937882a3c9d596eacbcf3eae31ab8c94b8 /arch/powerpc/platforms/powernv/opal.c
parente00da0f2db91b90e990cc05088f03adbc58af895 (diff)
downloadlinux-d2a2262e686ce7a27776add27751f925ceda856f.tar.xz
powerpc/powernv: Implement and use opal_flush_console
A new console flushing firmware API was introduced to replace event polling loops, and implemented in opal-kmsg with affddff69c55e ("powerpc/powernv: Add a kmsg_dumper that flushes console output on panic"), to flush the console in the panic path. The OPAL console driver has other situations where interrupts are off and it needs to flush the console synchronously. These still use a polling loop. So move the opal-kmsg flush code to opal_flush_console, and use the new function in opal-kmsg and opal_put_chars. Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org> Reviewed-by: Russell Currey <ruscur@russell.cc> Signed-off-by: Nicholas Piggin <npiggin@gmail.com> Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
Diffstat (limited to 'arch/powerpc/platforms/powernv/opal.c')
-rw-r--r--arch/powerpc/platforms/powernv/opal.c42
1 files changed, 38 insertions, 4 deletions
diff --git a/arch/powerpc/platforms/powernv/opal.c b/arch/powerpc/platforms/powernv/opal.c
index a9773a619081..b007d3ff1445 100644
--- a/arch/powerpc/platforms/powernv/opal.c
+++ b/arch/powerpc/platforms/powernv/opal.c
@@ -350,7 +350,6 @@ int opal_put_chars(uint32_t vtermno, const char *data, int total_len)
__be64 olen;
s64 len, rc;
unsigned long flags;
- __be64 evt;
if (!opal.entry)
return -ENODEV;
@@ -371,7 +370,7 @@ int opal_put_chars(uint32_t vtermno, const char *data, int total_len)
/* Closed -> drop characters */
if (rc)
return total_len;
- opal_poll_events(NULL);
+ opal_flush_console(vtermno);
return -EAGAIN;
}
@@ -410,12 +409,47 @@ int opal_put_chars(uint32_t vtermno, const char *data, int total_len)
* things a bit later to limit that to synchronous path
* such as the kernel console and xmon/udbg
*/
+ opal_flush_console(vtermno);
+ }
+ spin_unlock_irqrestore(&opal_write_lock, flags);
+
+ return written;
+}
+
+int opal_flush_console(uint32_t vtermno)
+{
+ s64 rc;
+
+ if (!opal_check_token(OPAL_CONSOLE_FLUSH)) {
+ __be64 evt;
+
+ WARN_ONCE(1, "opal: OPAL_CONSOLE_FLUSH missing.\n");
+ /*
+ * If OPAL_CONSOLE_FLUSH is not implemented in the firmware,
+ * the console can still be flushed by calling the polling
+ * function while it has OPAL_EVENT_CONSOLE_OUTPUT events.
+ */
do {
opal_poll_events(&evt);
} while (be64_to_cpu(evt) & OPAL_EVENT_CONSOLE_OUTPUT);
+
+ return OPAL_SUCCESS;
}
- spin_unlock_irqrestore(&opal_write_lock, flags);
- return written;
+
+ do {
+ rc = OPAL_BUSY;
+ while (rc == OPAL_BUSY || rc == OPAL_BUSY_EVENT) {
+ rc = opal_console_flush(vtermno);
+ if (rc == OPAL_BUSY_EVENT) {
+ mdelay(OPAL_BUSY_DELAY_MS);
+ opal_poll_events(NULL);
+ } else if (rc == OPAL_BUSY) {
+ mdelay(OPAL_BUSY_DELAY_MS);
+ }
+ }
+ } while (rc == OPAL_PARTIAL); /* More to flush */
+
+ return opal_error_code(rc);
}
static int opal_recover_mce(struct pt_regs *regs,