Commit 36d2dabc authored by Nicholas Piggin's avatar Nicholas Piggin Committed by Michael Ellerman
Browse files

powerpc/powernv: Fix OPAL console driver OPAL_BUSY loops



The OPAL console driver does not delay in case it gets OPAL_BUSY or
OPAL_BUSY_EVENT from firmware.

It can't yet be made to sleep because it is called under spinlock,
but it can be changed to the standard OPAL_BUSY loop form, and a
delay added to keep it from hitting the firmware too frequently.

Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: default avatarNicholas Piggin <npiggin@gmail.com>
Signed-off-by: default avatarMichael Ellerman <mpe@ellerman.id.au>
parent bd90284c
Loading
Loading
Loading
Loading
+23 −15
Original line number Diff line number Diff line
@@ -378,33 +378,41 @@ int opal_put_chars(uint32_t vtermno, const char *data, int total_len)
	/* We still try to handle partial completions, though they
	 * should no longer happen.
	 */
	rc = OPAL_BUSY;
	while(total_len > 0 && (rc == OPAL_BUSY ||
				rc == OPAL_BUSY_EVENT || rc == OPAL_SUCCESS)) {

	while (total_len > 0) {
		olen = cpu_to_be64(total_len);

		rc = OPAL_BUSY;
		while (rc == OPAL_BUSY || rc == OPAL_BUSY_EVENT) {
			rc = opal_console_write(vtermno, &olen, data);
			if (rc == OPAL_BUSY_EVENT) {
				mdelay(OPAL_BUSY_DELAY_MS);
				opal_poll_events(NULL);
			} else if (rc == OPAL_BUSY) {
				mdelay(OPAL_BUSY_DELAY_MS);
			}
		}

		len = be64_to_cpu(olen);

		/* Closed or other error drop */
		if (rc != OPAL_SUCCESS && rc != OPAL_BUSY &&
		    rc != OPAL_BUSY_EVENT) {
			written += total_len;
		if (rc != OPAL_SUCCESS) {
			written += total_len; /* drop remaining chars */
			break;
		}
		if (rc == OPAL_SUCCESS) {

		total_len -= len;
		data += len;
		written += len;
		}

		/* This is a bit nasty but we need that for the console to
		 * flush when there aren't any interrupts. We will clean
		 * things a bit later to limit that to synchronous path
		 * such as the kernel console and xmon/udbg
		 */
		do
		do {
			opal_poll_events(&evt);
		while(rc == OPAL_SUCCESS &&
			(be64_to_cpu(evt) & OPAL_EVENT_CONSOLE_OUTPUT));
		} while (be64_to_cpu(evt) & OPAL_EVENT_CONSOLE_OUTPUT);
	}
	spin_unlock_irqrestore(&opal_write_lock, flags);
	return written;