aboutsummaryrefslogtreecommitdiff
path: root/hw/lpc-uart.c
diff options
context:
space:
mode:
authorBenjamin Herrenschmidt <benh@kernel.crashing.org>2014-10-13 11:14:34 +1100
committerBenjamin Herrenschmidt <benh@kernel.crashing.org>2014-10-15 14:45:28 +1100
commit4d4e25f2ef77bbbeca9050596b7cecf89ec89e78 (patch)
treee3c9eb7cf27bdb8822a0d40e987cce1a3365afba /hw/lpc-uart.c
parentb6be61860788e0eaba95c4e2d87f1047923a49f6 (diff)
downloadskiboot-4d4e25f2ef77bbbeca9050596b7cecf89ec89e78.zip
skiboot-4d4e25f2ef77bbbeca9050596b7cecf89ec89e78.tar.gz
skiboot-4d4e25f2ef77bbbeca9050596b7cecf89ec89e78.tar.bz2
uart: Keep synchronous console flush when IRQ not working
Some boards are missing an EC for interrupts (or might not have the FPGA properly flashed). In that case the serial interrupt isn't working. We attempt to detect this by enabling all interrupts by default and when the first one occurs, we mark interrupts as "functional". Until they are detected as such, we keep all output flushes fully synchronous. Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Diffstat (limited to 'hw/lpc-uart.c')
-rw-r--r--hw/lpc-uart.c28
1 files changed, 25 insertions, 3 deletions
diff --git a/hw/lpc-uart.c b/hw/lpc-uart.c
index 51f744d..7f0909a 100644
--- a/hw/lpc-uart.c
+++ b/hw/lpc-uart.c
@@ -57,11 +57,12 @@ DEFINE_LOG_ENTRY(OPAL_RC_UART_INIT, OPAL_PLATFORM_ERR_EVT, OPAL_UART,
#define IER_RX 0x01
#define IER_THRE 0x02
+#define IER_ALL 0x0f
static struct lock uart_lock = LOCK_UNLOCKED;
static struct dt_node *uart_node;
static uint32_t uart_base;
-static bool has_irq, rx_full, tx_full;
+static bool has_irq, irq_ok, rx_full, tx_full;
static uint8_t tx_room;
static uint8_t cached_ier;
@@ -110,6 +111,13 @@ static void uart_update_ier(void)
if (!has_irq)
return;
+ /* If we have never got an interrupt, enable them all,
+ * the first interrupt received will tell us if interrupts
+ * are functional (some boards are missing an EC or FPGA
+ * programming causing LPC interrupts not to work).
+ */
+ if (!irq_ok)
+ ier = IER_ALL;
if (!rx_full)
ier |= IER_RX;
if (tx_full)
@@ -182,8 +190,18 @@ static void uart_flush_out(void)
bool tx_was_full = tx_full;
while(out_buf_prod != out_buf_cons) {
- if (tx_room == 0)
- uart_check_tx_room();
+ if (tx_room == 0) {
+ /*
+ * If the interrupt is not functional,
+ * we force a full synchronous flush,
+ * otherwise the Linux console isn't
+ * usable (too slow).
+ */
+ if (irq_ok)
+ uart_check_tx_room();
+ else
+ uart_wait_tx_room();
+ }
if (tx_room == 0) {
tx_full = true;
break;
@@ -345,6 +363,10 @@ static void uart_console_poll(void *data __unused)
void uart_irq(void)
{
+ if (!irq_ok) {
+ printf("UART: IRQ functional !\n");
+ irq_ok = true;
+ }
__uart_do_poll(TRACE_UART_CTX_IRQ);
}