Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Nicholas Piggin and committed by
Michael Ellerman
95b861a7 997dd26c

+57 -33
+1
arch/powerpc/include/asm/opal.h
··· 308 308 extern int opal_get_chars(uint32_t vtermno, char *buf, int count); 309 309 extern int opal_put_chars(uint32_t vtermno, const char *buf, int total_len); 310 310 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); 311 312 extern int opal_flush_console(uint32_t vtermno); 312 313 313 314 extern void hvc_opal_init_early(void);
+54 -33
arch/powerpc/platforms/powernv/opal.c
··· 370 370 olen = cpu_to_be64(total_len); 371 371 rc = opal_console_write(vtermno, &olen, data); 372 372 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) 375 374 opal_poll_events(NULL); 376 - } else if (rc == OPAL_BUSY_EVENT) { 377 - mdelay(OPAL_BUSY_DELAY_MS); 378 - } 379 375 written = -EAGAIN; 380 376 goto out; 381 377 } ··· 397 401 if (atomic) 398 402 spin_unlock_irqrestore(&opal_write_lock, flags); 399 403 400 - /* In the -EAGAIN case, callers loop, so we have to flush the console 401 - * here in case they have interrupts off (and we don't want to wait 402 - * for async flushing if we can make immediate progress here). If 403 - * necessary the API could be made entirely non-flushing if the 404 - * callers had a ->flush API to use. 405 - */ 406 - if (written == -EAGAIN) 407 - opal_flush_console(vtermno); 408 - 409 404 return written; 410 405 } 411 406 ··· 416 429 return __opal_put_chars(vtermno, data, total_len, true); 417 430 } 418 431 419 - int opal_flush_console(uint32_t vtermno) 432 + static s64 __opal_flush_console(uint32_t vtermno) 420 433 { 421 434 s64 rc; 422 435 423 436 if (!opal_check_token(OPAL_CONSOLE_FLUSH)) { 424 437 __be64 evt; 425 438 426 - WARN_ONCE(1, "opal: OPAL_CONSOLE_FLUSH missing.\n"); 427 439 /* 428 440 * If OPAL_CONSOLE_FLUSH is not implemented in the firmware, 429 441 * the console can still be flushed by calling the polling 430 442 * function while it has OPAL_EVENT_CONSOLE_OUTPUT events. 431 443 */ 432 - do { 433 - opal_poll_events(&evt); 434 - } while (be64_to_cpu(evt) & OPAL_EVENT_CONSOLE_OUTPUT); 444 + WARN_ONCE(1, "opal: OPAL_CONSOLE_FLUSH missing.\n"); 435 445 436 - return OPAL_SUCCESS; 446 + opal_poll_events(&evt); 447 + if (!(be64_to_cpu(evt) & OPAL_EVENT_CONSOLE_OUTPUT)) 448 + return OPAL_SUCCESS; 449 + return OPAL_BUSY; 450 + 451 + } else { 452 + rc = opal_console_flush(vtermno); 453 + if (rc == OPAL_BUSY_EVENT) { 454 + opal_poll_events(NULL); 455 + rc = OPAL_BUSY; 456 + } 457 + return rc; 437 458 } 438 459 439 - do { 440 - rc = OPAL_BUSY; 441 - while (rc == OPAL_BUSY || rc == OPAL_BUSY_EVENT) { 442 - rc = opal_console_flush(vtermno); 443 - if (rc == OPAL_BUSY_EVENT) { 444 - mdelay(OPAL_BUSY_DELAY_MS); 445 - opal_poll_events(NULL); 446 - } else if (rc == OPAL_BUSY) { 447 - mdelay(OPAL_BUSY_DELAY_MS); 448 - } 449 - } 450 - } while (rc == OPAL_PARTIAL); /* More to flush */ 460 + } 451 461 452 - return opal_error_code(rc); 462 + /* 463 + * opal_flush_console spins until the console is flushed 464 + */ 465 + int opal_flush_console(uint32_t vtermno) 466 + { 467 + for (;;) { 468 + s64 rc = __opal_flush_console(vtermno); 469 + 470 + if (rc == OPAL_BUSY || rc == OPAL_PARTIAL) { 471 + mdelay(1); 472 + continue; 473 + } 474 + 475 + return opal_error_code(rc); 476 + } 477 + } 478 + 479 + /* 480 + * opal_flush_chars is an hvc interface that sleeps until the console is 481 + * flushed if wait, otherwise it will return -EBUSY if the console has data, 482 + * -EAGAIN if it has data and some of it was flushed. 483 + */ 484 + int opal_flush_chars(uint32_t vtermno, bool wait) 485 + { 486 + for (;;) { 487 + s64 rc = __opal_flush_console(vtermno); 488 + 489 + if (rc == OPAL_BUSY || rc == OPAL_PARTIAL) { 490 + if (wait) { 491 + msleep(OPAL_BUSY_DELAY_MS); 492 + continue; 493 + } 494 + if (rc == OPAL_PARTIAL) 495 + return -EAGAIN; 496 + } 497 + 498 + return opal_error_code(rc); 499 + } 453 500 } 454 501 455 502 static int opal_recover_mce(struct pt_regs *regs,
+2
drivers/tty/hvc/hvc_opal.c
··· 52 52 static const struct hv_ops hvc_opal_raw_ops = { 53 53 .get_chars = opal_get_chars, 54 54 .put_chars = opal_put_chars, 55 + .flush = opal_flush_chars, 55 56 .notifier_add = notifier_add_irq, 56 57 .notifier_del = notifier_del_irq, 57 58 .notifier_hangup = notifier_hangup_irq, ··· 142 141 static const struct hv_ops hvc_opal_hvsi_ops = { 143 142 .get_chars = hvc_opal_hvsi_get_chars, 144 143 .put_chars = hvc_opal_hvsi_put_chars, 144 + .flush = opal_flush_chars, 145 145 .notifier_add = hvc_opal_hvsi_open, 146 146 .notifier_del = hvc_opal_hvsi_close, 147 147 .notifier_hangup = hvc_opal_hvsi_hangup,