The RAW console does not need writes to be atomic, so implement a
_nonatomic variant which does not take a spinlock. This API is used
in xmon, so the less locking thta's used, the better chance there is
that a crash can be debugged.

Cc: Benjamin Herrenschmidt <b...@kernel.crashing.org>
Signed-off-by: Nicholas Piggin <npig...@gmail.com>
---
 arch/powerpc/include/asm/opal.h       |  1 +
 arch/powerpc/platforms/powernv/opal.c | 35 +++++++++++++++++++--------
 drivers/tty/hvc/hvc_opal.c            |  4 +--
 3 files changed, 28 insertions(+), 12 deletions(-)

diff --git a/arch/powerpc/include/asm/opal.h b/arch/powerpc/include/asm/opal.h
index bbff49fab0e5..66954d671831 100644
--- a/arch/powerpc/include/asm/opal.h
+++ b/arch/powerpc/include/asm/opal.h
@@ -303,6 +303,7 @@ extern void opal_configure_cores(void);
 
 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_nonatomic(uint32_t vtermno, const char *buf, int 
total_len);
 extern int opal_flush_console(uint32_t vtermno);
 
 extern void hvc_opal_init_early(void);
diff --git a/arch/powerpc/platforms/powernv/opal.c 
b/arch/powerpc/platforms/powernv/opal.c
index b05500a70f58..dc77fc57d1e9 100644
--- a/arch/powerpc/platforms/powernv/opal.c
+++ b/arch/powerpc/platforms/powernv/opal.c
@@ -344,9 +344,9 @@ int opal_get_chars(uint32_t vtermno, char *buf, int count)
        return 0;
 }
 
-int opal_put_chars(uint32_t vtermno, const char *data, int total_len)
+static int __opal_put_chars(uint32_t vtermno, const char *data, int total_len, 
bool atomic)
 {
-       unsigned long flags;
+       unsigned long flags = 0 /* shut up gcc */;
        int written;
        __be64 olen;
        s64 rc;
@@ -354,11 +354,8 @@ int opal_put_chars(uint32_t vtermno, const char *data, int 
total_len)
        if (!opal.entry)
                return -ENODEV;
 
-       /* We want put_chars to be atomic to avoid mangling of hvsi
-        * packets. To do that, we first test for room and return
-        * -EAGAIN if there isn't enough.
-        */
-       spin_lock_irqsave(&opal_write_lock, flags);
+       if (atomic)
+               spin_lock_irqsave(&opal_write_lock, flags);
        rc = opal_console_write_buffer_space(vtermno, &olen);
        if (rc || be64_to_cpu(olen) < total_len) {
                /* Closed -> drop characters */
@@ -391,14 +388,18 @@ int opal_put_chars(uint32_t vtermno, const char *data, 
int total_len)
 
        written = be64_to_cpu(olen);
        if (written < total_len) {
-               /* Should not happen */
-               pr_warn("atomic console write returned partial len=%d 
written=%d\n", total_len, written);
+               if (atomic) {
+                       /* Should not happen */
+                       pr_warn("atomic console write returned partial "
+                               "len=%d written=%d\n", total_len, written);
+               }
                if (!written)
                        written = -EAGAIN;
        }
 
 out:
-       spin_unlock_irqrestore(&opal_write_lock, flags);
+       if (atomic)
+               spin_unlock_irqrestore(&opal_write_lock, flags);
 
        /* In the -EAGAIN case, callers loop, so we have to flush the console
         * here in case they have interrupts off (and we don't want to wait
@@ -412,6 +413,20 @@ int opal_put_chars(uint32_t vtermno, const char *data, int 
total_len)
        return written;
 }
 
+int opal_put_chars(uint32_t vtermno, const char *data, int total_len)
+{
+       /* We want put_chars to be atomic to avoid mangling of hvsi
+        * packets. To do that, we first test for room and return
+        * -EAGAIN if there isn't enough.
+        */
+       return __opal_put_chars(vtermno, data, total_len, true);
+}
+
+int opal_put_chars_nonatomic(uint32_t vtermno, const char *data, int total_len)
+{
+       return __opal_put_chars(vtermno, data, total_len, false);
+}
+
 int opal_flush_console(uint32_t vtermno)
 {
        s64 rc;
diff --git a/drivers/tty/hvc/hvc_opal.c b/drivers/tty/hvc/hvc_opal.c
index af122ad7f06d..e151cfacf2a7 100644
--- a/drivers/tty/hvc/hvc_opal.c
+++ b/drivers/tty/hvc/hvc_opal.c
@@ -51,7 +51,7 @@ static u32 hvc_opal_boot_termno;
 
 static const struct hv_ops hvc_opal_raw_ops = {
        .get_chars = opal_get_chars,
-       .put_chars = opal_put_chars,
+       .put_chars = opal_put_chars_nonatomic,
        .notifier_add = notifier_add_irq,
        .notifier_del = notifier_del_irq,
        .notifier_hangup = notifier_hangup_irq,
@@ -269,7 +269,7 @@ static void udbg_opal_putc(char c)
        do {
                switch(hvc_opal_boot_priv.proto) {
                case HV_PROTOCOL_RAW:
-                       count = opal_put_chars(termno, &c, 1);
+                       count = opal_put_chars_nonatomic(termno, &c, 1);
                        break;
                case HV_PROTOCOL_HVSI:
                        count = hvc_opal_hvsi_put_chars(termno, &c, 1);
-- 
2.17.0

Reply via email to