Skip to content

Commit 95b861a

Browse files
npigginmpe
authored andcommitted
powerpc/powernv: provide a console flush operation for opal hvc driver
Provide the flush hv_op for the opal hvc driver. This will flush the firmware console buffers without spinning with interrupts disabled. Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org> Cc: linuxppc-dev@lists.ozlabs.org Signed-off-by: Nicholas Piggin <npiggin@gmail.com> Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
1 parent 997dd26 commit 95b861a

File tree

3 files changed

+55
-31
lines changed

3 files changed

+55
-31
lines changed

arch/powerpc/include/asm/opal.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -308,6 +308,7 @@ extern void opal_configure_cores(void);
308308
extern int opal_get_chars(uint32_t vtermno, char *buf, int count);
309309
extern int opal_put_chars(uint32_t vtermno, const char *buf, int total_len);
310310
extern int opal_put_chars_atomic(uint32_t vtermno, const char *buf, int total_len);
311+
extern int opal_flush_chars(uint32_t vtermno, bool wait);
311312
extern int opal_flush_console(uint32_t vtermno);
312313

313314
extern void hvc_opal_init_early(void);

arch/powerpc/platforms/powernv/opal.c

Lines changed: 52 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -370,12 +370,8 @@ static int __opal_put_chars(uint32_t vtermno, const char *data, int total_len, b
370370
olen = cpu_to_be64(total_len);
371371
rc = opal_console_write(vtermno, &olen, data);
372372
if (rc == OPAL_BUSY || rc == OPAL_BUSY_EVENT) {
373-
if (rc == OPAL_BUSY_EVENT) {
374-
mdelay(OPAL_BUSY_DELAY_MS);
373+
if (rc == OPAL_BUSY_EVENT)
375374
opal_poll_events(NULL);
376-
} else if (rc == OPAL_BUSY_EVENT) {
377-
mdelay(OPAL_BUSY_DELAY_MS);
378-
}
379375
written = -EAGAIN;
380376
goto out;
381377
}
@@ -401,15 +397,6 @@ static int __opal_put_chars(uint32_t vtermno, const char *data, int total_len, b
401397
if (atomic)
402398
spin_unlock_irqrestore(&opal_write_lock, flags);
403399

404-
/* In the -EAGAIN case, callers loop, so we have to flush the console
405-
* here in case they have interrupts off (and we don't want to wait
406-
* for async flushing if we can make immediate progress here). If
407-
* necessary the API could be made entirely non-flushing if the
408-
* callers had a ->flush API to use.
409-
*/
410-
if (written == -EAGAIN)
411-
opal_flush_console(vtermno);
412-
413400
return written;
414401
}
415402

@@ -429,40 +416,74 @@ int opal_put_chars_atomic(uint32_t vtermno, const char *data, int total_len)
429416
return __opal_put_chars(vtermno, data, total_len, true);
430417
}
431418

432-
int opal_flush_console(uint32_t vtermno)
419+
static s64 __opal_flush_console(uint32_t vtermno)
433420
{
434421
s64 rc;
435422

436423
if (!opal_check_token(OPAL_CONSOLE_FLUSH)) {
437424
__be64 evt;
438425

439-
WARN_ONCE(1, "opal: OPAL_CONSOLE_FLUSH missing.\n");
440426
/*
441427
* If OPAL_CONSOLE_FLUSH is not implemented in the firmware,
442428
* the console can still be flushed by calling the polling
443429
* function while it has OPAL_EVENT_CONSOLE_OUTPUT events.
444430
*/
445-
do {
446-
opal_poll_events(&evt);
447-
} while (be64_to_cpu(evt) & OPAL_EVENT_CONSOLE_OUTPUT);
431+
WARN_ONCE(1, "opal: OPAL_CONSOLE_FLUSH missing.\n");
432+
433+
opal_poll_events(&evt);
434+
if (!(be64_to_cpu(evt) & OPAL_EVENT_CONSOLE_OUTPUT))
435+
return OPAL_SUCCESS;
436+
return OPAL_BUSY;
448437

449-
return OPAL_SUCCESS;
438+
} else {
439+
rc = opal_console_flush(vtermno);
440+
if (rc == OPAL_BUSY_EVENT) {
441+
opal_poll_events(NULL);
442+
rc = OPAL_BUSY;
443+
}
444+
return rc;
450445
}
451446

452-
do {
453-
rc = OPAL_BUSY;
454-
while (rc == OPAL_BUSY || rc == OPAL_BUSY_EVENT) {
455-
rc = opal_console_flush(vtermno);
456-
if (rc == OPAL_BUSY_EVENT) {
457-
mdelay(OPAL_BUSY_DELAY_MS);
458-
opal_poll_events(NULL);
459-
} else if (rc == OPAL_BUSY) {
460-
mdelay(OPAL_BUSY_DELAY_MS);
447+
}
448+
449+
/*
450+
* opal_flush_console spins until the console is flushed
451+
*/
452+
int opal_flush_console(uint32_t vtermno)
453+
{
454+
for (;;) {
455+
s64 rc = __opal_flush_console(vtermno);
456+
457+
if (rc == OPAL_BUSY || rc == OPAL_PARTIAL) {
458+
mdelay(1);
459+
continue;
460+
}
461+
462+
return opal_error_code(rc);
463+
}
464+
}
465+
466+
/*
467+
* opal_flush_chars is an hvc interface that sleeps until the console is
468+
* flushed if wait, otherwise it will return -EBUSY if the console has data,
469+
* -EAGAIN if it has data and some of it was flushed.
470+
*/
471+
int opal_flush_chars(uint32_t vtermno, bool wait)
472+
{
473+
for (;;) {
474+
s64 rc = __opal_flush_console(vtermno);
475+
476+
if (rc == OPAL_BUSY || rc == OPAL_PARTIAL) {
477+
if (wait) {
478+
msleep(OPAL_BUSY_DELAY_MS);
479+
continue;
461480
}
481+
if (rc == OPAL_PARTIAL)
482+
return -EAGAIN;
462483
}
463-
} while (rc == OPAL_PARTIAL); /* More to flush */
464484

465-
return opal_error_code(rc);
485+
return opal_error_code(rc);
486+
}
466487
}
467488

468489
static int opal_recover_mce(struct pt_regs *regs,

drivers/tty/hvc/hvc_opal.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ static u32 hvc_opal_boot_termno;
5252
static const struct hv_ops hvc_opal_raw_ops = {
5353
.get_chars = opal_get_chars,
5454
.put_chars = opal_put_chars,
55+
.flush = opal_flush_chars,
5556
.notifier_add = notifier_add_irq,
5657
.notifier_del = notifier_del_irq,
5758
.notifier_hangup = notifier_hangup_irq,
@@ -141,6 +142,7 @@ static int hvc_opal_hvsi_tiocmset(struct hvc_struct *hp, unsigned int set,
141142
static const struct hv_ops hvc_opal_hvsi_ops = {
142143
.get_chars = hvc_opal_hvsi_get_chars,
143144
.put_chars = hvc_opal_hvsi_put_chars,
145+
.flush = opal_flush_chars,
144146
.notifier_add = hvc_opal_hvsi_open,
145147
.notifier_del = hvc_opal_hvsi_close,
146148
.notifier_hangup = hvc_opal_hvsi_hangup,

0 commit comments

Comments
 (0)