powerpc/powernv: Fix OPAL console driver OPAL_BUSY loops

The OPAL console driver does not delay in case it gets OPAL_BUSY or
OPAL_BUSY_EVENT from firmware.

It can't yet be made to sleep because it is called under spinlock,
but it can be changed to the standard OPAL_BUSY loop form, and a
delay added to keep it from hitting the firmware too frequently.

Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: Nicholas Piggin <npiggin@gmail.com>
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
This commit is contained in:
Nicholas Piggin 2018-05-01 00:55:45 +10:00 committed by Michael Ellerman
parent bd90284cc6
commit 36d2dabc87
1 changed files with 23 additions and 15 deletions

View File

@ -378,33 +378,41 @@ int opal_put_chars(uint32_t vtermno, const char *data, int total_len)
/* We still try to handle partial completions, though they /* We still try to handle partial completions, though they
* should no longer happen. * should no longer happen.
*/ */
rc = OPAL_BUSY;
while(total_len > 0 && (rc == OPAL_BUSY || while (total_len > 0) {
rc == OPAL_BUSY_EVENT || rc == OPAL_SUCCESS)) {
olen = cpu_to_be64(total_len); olen = cpu_to_be64(total_len);
rc = OPAL_BUSY;
while (rc == OPAL_BUSY || rc == OPAL_BUSY_EVENT) {
rc = opal_console_write(vtermno, &olen, data); rc = opal_console_write(vtermno, &olen, data);
if (rc == OPAL_BUSY_EVENT) {
mdelay(OPAL_BUSY_DELAY_MS);
opal_poll_events(NULL);
} else if (rc == OPAL_BUSY) {
mdelay(OPAL_BUSY_DELAY_MS);
}
}
len = be64_to_cpu(olen); len = be64_to_cpu(olen);
/* Closed or other error drop */ /* Closed or other error drop */
if (rc != OPAL_SUCCESS && rc != OPAL_BUSY && if (rc != OPAL_SUCCESS) {
rc != OPAL_BUSY_EVENT) { written += total_len; /* drop remaining chars */
written += total_len;
break; break;
} }
if (rc == OPAL_SUCCESS) {
total_len -= len; total_len -= len;
data += len; data += len;
written += len; written += len;
}
/* This is a bit nasty but we need that for the console to /* This is a bit nasty but we need that for the console to
* flush when there aren't any interrupts. We will clean * flush when there aren't any interrupts. We will clean
* 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
*/ */
do do {
opal_poll_events(&evt); opal_poll_events(&evt);
while(rc == OPAL_SUCCESS && } while (be64_to_cpu(evt) & OPAL_EVENT_CONSOLE_OUTPUT);
(be64_to_cpu(evt) & OPAL_EVENT_CONSOLE_OUTPUT));
} }
spin_unlock_irqrestore(&opal_write_lock, flags); spin_unlock_irqrestore(&opal_write_lock, flags);
return written; return written;