mirror of https://gitee.com/openkylin/linux.git
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:
parent
bd90284cc6
commit
36d2dabc87
|
@ -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_console_write(vtermno, &olen, data);
|
|
||||||
|
rc = OPAL_BUSY;
|
||||||
|
while (rc == OPAL_BUSY || rc == OPAL_BUSY_EVENT) {
|
||||||
|
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;
|
||||||
|
|
Loading…
Reference in New Issue