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

Configure Feed

Select the types of activity you want to include in your feed.

powerpc/powernv: Remove OPALv1 support from opal console driver

opal_put_chars deals with partial writes because in OPALv1,
opal_console_write_buffer_space did not work correctly. That firmware
is not supported.

This reworks the opal_put_chars code to no longer deal with partial
writes by turning them into full writes. Partial write handling is still
supported in terms of what gets returned to the caller, but it may not
go to the console atomically. A warning message is printed in this
case.

This allows console flushing to be moved out of the opal_write_lock
spinlock. That could cause the lock to be held for long periods if the
console is busy (especially if it was being spammed by firmware),
which is dangerous because the lock is taken by xmon to debug the
system. Flushing outside the lock improves the situation a bit.

Cc: Benjamin Herrenschmidt <benh@kernel.crashing.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
b74d2807 d2a2262e

+42 -48
+42 -48
arch/powerpc/platforms/powernv/opal.c
··· 346 346 347 347 int opal_put_chars(uint32_t vtermno, const char *data, int total_len) 348 348 { 349 - int written = 0; 350 - __be64 olen; 351 - s64 len, rc; 352 349 unsigned long flags; 350 + int written; 351 + __be64 olen; 352 + s64 rc; 353 353 354 354 if (!opal.entry) 355 355 return -ENODEV; ··· 357 357 /* We want put_chars to be atomic to avoid mangling of hvsi 358 358 * packets. To do that, we first test for room and return 359 359 * -EAGAIN if there isn't enough. 360 - * 361 - * Unfortunately, opal_console_write_buffer_space() doesn't 362 - * appear to work on opal v1, so we just assume there is 363 - * enough room and be done with it 364 360 */ 365 361 spin_lock_irqsave(&opal_write_lock, flags); 366 362 rc = opal_console_write_buffer_space(vtermno, &olen); 367 - len = be64_to_cpu(olen); 368 - if (rc || len < total_len) { 369 - spin_unlock_irqrestore(&opal_write_lock, flags); 363 + if (rc || be64_to_cpu(olen) < total_len) { 370 364 /* Closed -> drop characters */ 371 365 if (rc) 372 - return total_len; 373 - opal_flush_console(vtermno); 374 - return -EAGAIN; 366 + written = total_len; 367 + else 368 + written = -EAGAIN; 369 + goto out; 375 370 } 376 371 377 - /* We still try to handle partial completions, though they 378 - * should no longer happen. 379 - */ 380 - 381 - while (total_len > 0) { 382 - olen = cpu_to_be64(total_len); 383 - 384 - rc = OPAL_BUSY; 385 - while (rc == OPAL_BUSY || rc == OPAL_BUSY_EVENT) { 386 - rc = opal_console_write(vtermno, &olen, data); 387 - if (rc == OPAL_BUSY_EVENT) { 388 - mdelay(OPAL_BUSY_DELAY_MS); 389 - opal_poll_events(NULL); 390 - } else if (rc == OPAL_BUSY) { 391 - mdelay(OPAL_BUSY_DELAY_MS); 392 - } 372 + /* Should not get a partial write here because space is available. */ 373 + olen = cpu_to_be64(total_len); 374 + rc = opal_console_write(vtermno, &olen, data); 375 + if (rc == OPAL_BUSY || rc == OPAL_BUSY_EVENT) { 376 + if (rc == OPAL_BUSY_EVENT) { 377 + mdelay(OPAL_BUSY_DELAY_MS); 378 + opal_poll_events(NULL); 379 + } else if (rc == OPAL_BUSY_EVENT) { 380 + mdelay(OPAL_BUSY_DELAY_MS); 393 381 } 394 - 395 - len = be64_to_cpu(olen); 396 - 397 - /* Closed or other error drop */ 398 - if (rc != OPAL_SUCCESS) { 399 - written += total_len; /* drop remaining chars */ 400 - break; 401 - } 402 - 403 - total_len -= len; 404 - data += len; 405 - written += len; 406 - 407 - /* This is a bit nasty but we need that for the console to 408 - * flush when there aren't any interrupts. We will clean 409 - * things a bit later to limit that to synchronous path 410 - * such as the kernel console and xmon/udbg 411 - */ 412 - opal_flush_console(vtermno); 382 + written = -EAGAIN; 383 + goto out; 413 384 } 385 + 386 + /* Closed or other error drop */ 387 + if (rc != OPAL_SUCCESS) { 388 + written = opal_error_code(rc); 389 + goto out; 390 + } 391 + 392 + written = be64_to_cpu(olen); 393 + if (written < total_len) { 394 + /* Should not happen */ 395 + pr_warn("atomic console write returned partial len=%d written=%d\n", total_len, written); 396 + if (!written) 397 + written = -EAGAIN; 398 + } 399 + 400 + out: 414 401 spin_unlock_irqrestore(&opal_write_lock, flags); 402 + 403 + /* This is a bit nasty but we need that for the console to 404 + * flush when there aren't any interrupts. We will clean 405 + * things a bit later to limit that to synchronous path 406 + * such as the kernel console and xmon/udbg 407 + */ 408 + opal_flush_console(vtermno); 415 409 416 410 return written; 417 411 }