diff options
author | Nicholas Piggin <npiggin@gmail.com> | 2018-05-01 00:55:57 +1000 |
---|---|---|
committer | Michael Ellerman <mpe@ellerman.id.au> | 2018-07-23 20:13:20 +1000 |
commit | 9f65b81f36e31563c5a5e4df3b3b8bc7550b6030 (patch) | |
tree | a4e3e295eba020c1f68072d40733cdb57f543e84 /drivers/tty/hvc | |
parent | 550ddadcc7580ec2a6c22d4ed04291bc6e2428fb (diff) |
tty: hvc: introduce the hv_ops.flush operation for hvc drivers
Use .flush to wait for drivers to flush their console outside of
the spinlock, to reduce lock/irq latencies.
Flush the hvc console driver after each write, which can help
messages make it out to the console after a crash.
Signed-off-by: Nicholas Piggin <npiggin@gmail.com>
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
Diffstat (limited to 'drivers/tty/hvc')
-rw-r--r-- | drivers/tty/hvc/hvc_console.c | 35 | ||||
-rw-r--r-- | drivers/tty/hvc/hvc_console.h | 1 |
2 files changed, 34 insertions, 2 deletions
diff --git a/drivers/tty/hvc/hvc_console.c b/drivers/tty/hvc/hvc_console.c index 6131d5084c42..5414c4a87bea 100644 --- a/drivers/tty/hvc/hvc_console.c +++ b/drivers/tty/hvc/hvc_console.c @@ -110,6 +110,29 @@ static struct hvc_struct *hvc_get_by_index(int index) return hp; } +static int __hvc_flush(const struct hv_ops *ops, uint32_t vtermno, bool wait) +{ + if (wait) + might_sleep(); + + if (ops->flush) + return ops->flush(vtermno, wait); + return 0; +} + +static int hvc_console_flush(const struct hv_ops *ops, uint32_t vtermno) +{ + return __hvc_flush(ops, vtermno, false); +} + +/* + * Wait for the console to flush before writing more to it. This sleeps. + */ +static int hvc_flush(struct hvc_struct *hp) +{ + return __hvc_flush(hp->ops, hp->vtermno, true); +} + /* * Initial console vtermnos for console API usage prior to full console * initialization. Any vty adapter outside this range will not have usable @@ -155,8 +178,12 @@ static void hvc_console_print(struct console *co, const char *b, if (r <= 0) { /* throw away characters on error * but spin in case of -EAGAIN */ - if (r != -EAGAIN) + if (r != -EAGAIN) { i = 0; + } else { + hvc_console_flush(cons_ops[index], + vtermnos[index]); + } } else if (r > 0) { i -= r; if (i > 0) @@ -164,6 +191,7 @@ static void hvc_console_print(struct console *co, const char *b, } } } + hvc_console_flush(cons_ops[index], vtermnos[index]); } static struct tty_driver *hvc_console_device(struct console *c, int *index) @@ -513,8 +541,11 @@ static int hvc_write(struct tty_struct *tty, const unsigned char *buf, int count spin_unlock_irqrestore(&hp->lock, flags); - if (count) + if (count) { + if (hp->n_outbuf > 0) + hvc_flush(hp); cond_resched(); + } } /* diff --git a/drivers/tty/hvc/hvc_console.h b/drivers/tty/hvc/hvc_console.h index ea63090e013f..e9319954c832 100644 --- a/drivers/tty/hvc/hvc_console.h +++ b/drivers/tty/hvc/hvc_console.h @@ -54,6 +54,7 @@ struct hvc_struct { struct hv_ops { int (*get_chars)(uint32_t vtermno, char *buf, int count); int (*put_chars)(uint32_t vtermno, const char *buf, int count); + int (*flush)(uint32_t vtermno, bool wait); /* Callbacks for notification. Called in open, close and hangup */ int (*notifier_add)(struct hvc_struct *hp, int irq); |