]> asedeno.scripts.mit.edu Git - linux.git/commitdiff
powerpc/powernv: Fix OPAL console driver OPAL_BUSY loops
authorNicholas Piggin <npiggin@gmail.com>
Mon, 30 Apr 2018 14:55:45 +0000 (00:55 +1000)
committerMichael Ellerman <mpe@ellerman.id.au>
Tue, 24 Jul 2018 12:09:55 +0000 (22:09 +1000)
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>
arch/powerpc/platforms/powernv/opal.c

index 371e33ecc5477d652862f52064b2b80596021046..a9773a6190818147bf109747b966c5f165993896 100644 (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
         * should no longer happen.
         */
-       rc = OPAL_BUSY;
-       while(total_len > 0 && (rc == OPAL_BUSY ||
-                               rc == OPAL_BUSY_EVENT || rc == OPAL_SUCCESS)) {
+
+       while (total_len > 0) {
                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);
 
                /* Closed or other error drop */
-               if (rc != OPAL_SUCCESS && rc != OPAL_BUSY &&
-                   rc != OPAL_BUSY_EVENT) {
-                       written += total_len;
+               if (rc != OPAL_SUCCESS) {
+                       written += total_len; /* drop remaining chars */
                        break;
                }
-               if (rc == OPAL_SUCCESS) {
-                       total_len -= len;
-                       data += len;
-                       written += len;
-               }
+
+               total_len -= len;
+               data += len;
+               written += len;
+
                /* This is a bit nasty but we need that for the console to
                 * flush when there aren't any interrupts. We will clean
                 * things a bit later to limit that to synchronous path
                 * such as the kernel console and xmon/udbg
                 */
-               do
+               do {
                        opal_poll_events(&evt);
-               while(rc == OPAL_SUCCESS &&
-                       (be64_to_cpu(evt) & OPAL_EVENT_CONSOLE_OUTPUT));
+               } while (be64_to_cpu(evt) & OPAL_EVENT_CONSOLE_OUTPUT);
        }
        spin_unlock_irqrestore(&opal_write_lock, flags);
        return written;