Commit d2a2262e authored by Nicholas Piggin's avatar Nicholas Piggin Committed by Michael Ellerman

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 affddff6
("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: default avatarRussell Currey <ruscur@russell.cc>
Signed-off-by: default avatarNicholas Piggin <npiggin@gmail.com>
Signed-off-by: default avatarMichael Ellerman <mpe@ellerman.id.au>
parent e00da0f2
...@@ -305,6 +305,7 @@ extern void opal_configure_cores(void); ...@@ -305,6 +305,7 @@ extern void opal_configure_cores(void);
extern int opal_get_chars(uint32_t vtermno, char *buf, int count); extern int opal_get_chars(uint32_t vtermno, char *buf, int count);
extern int opal_put_chars(uint32_t vtermno, const char *buf, int total_len); extern int opal_put_chars(uint32_t vtermno, const char *buf, int total_len);
extern int opal_flush_console(uint32_t vtermno);
extern void hvc_opal_init_early(void); extern void hvc_opal_init_early(void);
......
...@@ -12,7 +12,6 @@ ...@@ -12,7 +12,6 @@
*/ */
#include <linux/kmsg_dump.h> #include <linux/kmsg_dump.h>
#include <linux/delay.h>
#include <asm/opal.h> #include <asm/opal.h>
#include <asm/opal-api.h> #include <asm/opal-api.h>
...@@ -24,11 +23,9 @@ ...@@ -24,11 +23,9 @@
* may not be completely printed. This function does not actually dump the * may not be completely printed. This function does not actually dump the
* message, it just ensures that OPAL completely flushes the console buffer. * message, it just ensures that OPAL completely flushes the console buffer.
*/ */
static void force_opal_console_flush(struct kmsg_dumper *dumper, static void kmsg_dump_opal_console_flush(struct kmsg_dumper *dumper,
enum kmsg_dump_reason reason) enum kmsg_dump_reason reason)
{ {
s64 rc;
/* /*
* Outside of a panic context the pollers will continue to run, * Outside of a panic context the pollers will continue to run,
* so we don't need to do any special flushing. * so we don't need to do any special flushing.
...@@ -36,37 +33,11 @@ static void force_opal_console_flush(struct kmsg_dumper *dumper, ...@@ -36,37 +33,11 @@ static void force_opal_console_flush(struct kmsg_dumper *dumper,
if (reason != KMSG_DUMP_PANIC) if (reason != KMSG_DUMP_PANIC)
return; return;
if (opal_check_token(OPAL_CONSOLE_FLUSH)) { opal_flush_console(0);
do {
rc = OPAL_BUSY;
while (rc == OPAL_BUSY || rc == OPAL_BUSY_EVENT) {
rc = opal_console_flush(0);
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 */
} else {
__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);
}
} }
static struct kmsg_dumper opal_kmsg_dumper = { static struct kmsg_dumper opal_kmsg_dumper = {
.dump = force_opal_console_flush .dump = kmsg_dump_opal_console_flush
}; };
void __init opal_kmsg_init(void) void __init opal_kmsg_init(void)
......
...@@ -350,7 +350,6 @@ int opal_put_chars(uint32_t vtermno, const char *data, int total_len) ...@@ -350,7 +350,6 @@ int opal_put_chars(uint32_t vtermno, const char *data, int total_len)
__be64 olen; __be64 olen;
s64 len, rc; s64 len, rc;
unsigned long flags; unsigned long flags;
__be64 evt;
if (!opal.entry) if (!opal.entry)
return -ENODEV; return -ENODEV;
...@@ -371,7 +370,7 @@ int opal_put_chars(uint32_t vtermno, const char *data, int total_len) ...@@ -371,7 +370,7 @@ int opal_put_chars(uint32_t vtermno, const char *data, int total_len)
/* Closed -> drop characters */ /* Closed -> drop characters */
if (rc) if (rc)
return total_len; return total_len;
opal_poll_events(NULL); opal_flush_console(vtermno);
return -EAGAIN; return -EAGAIN;
} }
...@@ -410,12 +409,47 @@ int opal_put_chars(uint32_t vtermno, const char *data, int total_len) ...@@ -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 * things a bit later to limit that to synchronous path
* such as the kernel console and xmon/udbg * 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 { do {
opal_poll_events(&evt); opal_poll_events(&evt);
} while (be64_to_cpu(evt) & OPAL_EVENT_CONSOLE_OUTPUT); } 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, static int opal_recover_mce(struct pt_regs *regs,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment