From patchwork Fri Dec 18 06:15:36 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Russell Currey X-Patchwork-Id: 558752 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.ozlabs.org (lists.ozlabs.org [103.22.144.68]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 2625B14029E for ; Fri, 18 Dec 2015 17:24:15 +1100 (AEDT) Received: from lists.ozlabs.org (lists.ozlabs.org [IPv6:2401:3900:2:1::3]) by lists.ozlabs.org (Postfix) with ESMTP id 080951A1A41 for ; Fri, 18 Dec 2015 17:24:15 +1100 (AEDT) X-Original-To: skiboot@lists.ozlabs.org Delivered-To: skiboot@lists.ozlabs.org X-Greylist: delayed 399 seconds by postgrey-1.35 at bilbo; Fri, 18 Dec 2015 17:24:11 AEDT Received: from russell.cc (russell.cc [IPv6:2404:9400:2:0:216:3eff:fee0:3370]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by lists.ozlabs.org (Postfix) with ESMTPS id 710E01A1A1E for ; Fri, 18 Dec 2015 17:24:11 +1100 (AEDT) Received: from snap.ozlabs.ibm.com (static-82-10.transact.net.au [122.99.82.10]) by russell.cc (OpenSMTPD) with ESMTPSA id ca0a786c TLS version=TLSv1/SSLv3 cipher=ECDHE-RSA-AES128-SHA256 bits=128 verify=NO; Fri, 18 Dec 2015 06:17:26 +0000 (UTC) From: Russell Currey To: skiboot@lists.ozlabs.org Date: Fri, 18 Dec 2015 17:15:36 +1100 Message-Id: <1450419336-638-1-git-send-email-ruscur@russell.cc> X-Mailer: git-send-email 2.6.4 Subject: [Skiboot] [PATCH V2] Add OPAL_CONSOLE_FLUSH to the OPAL API X-BeenThere: skiboot@lists.ozlabs.org X-Mailman-Version: 2.1.20 Precedence: list List-Id: Mailing list for skiboot development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: skiboot-bounces+incoming=patchwork.ozlabs.org@lists.ozlabs.org Sender: "Skiboot" uart consoles only flush output when polled. The Linux kernel calls these pollers frequently, except when in a panic state. As such, panic messages are not fully printed unless the system is configured to reboot after panic. This patch adds a new call to the OPAL API to flush the buffer. If the system has a uart console (i.e. BMC machines), it will incrementally flush the buffer, returning if there is more to be flushed or not. If the system has a different console, the function will have no effect. This will allow the Linux kernel to ensure that panic message have been fully printed out. The existing synchronous flushing mechanism used in OPAL's shutdown and reboot routines has been refactored into a helper that repeatedly calls the new partial flush function. Signed-off-by: Russell Currey --- Changes since V1: - Refactored into a partial flush instead of a full synchronous flush - Added different return values based on the status - Change the synchronous flushing function to use the new call This patch is dependent on being merged before the PCI hotplug patches, which also add a new OPAL API call, incrementing OPAL_LAST. This should eventually head towards stable, maybe only after the kernel patch that uses it gets merged? --- core/console.c | 25 ++++++++++++++++++++--- core/platform.c | 4 ++-- doc/opal-api/opal-console-read-write-1-2.txt | 16 ++++++++++++++- hw/lpc-uart.c | 30 +++++++++++++++------------- include/console.h | 4 ++-- include/opal-api.h | 3 ++- 6 files changed, 59 insertions(+), 23 deletions(-) diff --git a/core/console.c b/core/console.c index 1cee5da..e851fcf 100644 --- a/core/console.c +++ b/core/console.c @@ -290,10 +290,29 @@ ssize_t read(int fd __unused, void *buf, size_t req_count) return count; } -void flush_console_driver(void) +static int64_t opal_console_flush(int64_t term_number) { - if (con_driver && con_driver->flush != NULL) - con_driver->flush(); + if (term_number != 0) + return OPAL_PARAMETER; + + if (con_driver == NULL || con_driver->flush == NULL) + return OPAL_UNSUPPORTED; + + return con_driver->flush(); +} +opal_call(OPAL_CONSOLE_FLUSH, opal_console_flush, 1); + +/* Helper function to perform a full synchronous flush */ +void console_complete_flush(void) +{ + int64_t ret = opal_console_flush(0); + + if (ret == OPAL_UNSUPPORTED || ret == OPAL_PARAMETER) + return; + + while (ret != OPAL_SUCCESS) { + ret = opal_console_flush(0); + } } void set_console(struct con_ops *driver) diff --git a/core/platform.c b/core/platform.c index 865d5b2..0dfbb88 100644 --- a/core/platform.c +++ b/core/platform.c @@ -37,7 +37,7 @@ static int64_t opal_cec_power_down(uint64_t request) { printf("OPAL: Shutdown request type 0x%llx...\n", request); - flush_console_driver(); + console_complete_flush(); if (platform.cec_power_down) return platform.cec_power_down(request); @@ -50,7 +50,7 @@ static int64_t opal_cec_reboot(void) { printf("OPAL: Reboot request...\n"); - flush_console_driver(); + console_complete_flush(); #ifdef ENABLE_FAST_RESET /* Try a fast reset first */ diff --git a/doc/opal-api/opal-console-read-write-1-2.txt b/doc/opal-api/opal-console-read-write-1-2.txt index b8fbc12..26f9a16 100644 --- a/doc/opal-api/opal-console-read-write-1-2.txt +++ b/doc/opal-api/opal-console-read-write-1-2.txt @@ -1,11 +1,12 @@ OPAL Console calls ------------------ -There are three OPAL calls relating to the OPAL console: +There are four OPAL calls relating to the OPAL console: #define OPAL_CONSOLE_WRITE 1 #define OPAL_CONSOLE_READ 2 #define OPAL_CONSOLE_WRITE_BUFFER_SPACE 25 +#define OPAL_CONSOLE_FLUSH 117 The OPAL console calls can support multiple consoles. Each console MUST be represented in the device tree. @@ -64,3 +65,16 @@ Returns: OPAL_CLOSED Use OPAL_POLL_EVENTS for how to determine + +OPAL_CONSOLE_FLUSH +------------------ + +Parameters: + int64_t term_number + +Returns: + OPAL_SUCCESS + OPAL_UNSUPPORTED - the console does not implement a flush call + OPAL_PARAMETER - invalid term_number + OPAL_PARTIAL - more to flush, call again + OPAL_BUSY - nothing was flushed this call diff --git a/hw/lpc-uart.c b/hw/lpc-uart.c index b6670b3..bba6354 100644 --- a/hw/lpc-uart.c +++ b/hw/lpc-uart.c @@ -156,11 +156,11 @@ static size_t uart_con_write(const char *buf, size_t len) return written; } -static void uart_con_flush_all(void); +static int64_t uart_con_flush(void); static struct con_ops uart_con_driver = { .write = uart_con_write, - .flush = uart_con_flush_all + .flush = uart_con_flush }; /* @@ -193,9 +193,11 @@ static uint8_t *out_buf; static uint32_t out_buf_prod; static uint32_t out_buf_cons; -static void uart_flush_out(void) +/* Asynchronous flush */ +static int64_t uart_con_flush(void) { bool tx_was_full = tx_full; + uint32_t out_buf_cons_initial = out_buf_cons; while(out_buf_prod != out_buf_cons) { if (tx_room == 0) { @@ -220,6 +222,15 @@ static void uart_flush_out(void) } if (tx_full != tx_was_full) uart_update_ier(); + if (out_buf_prod != out_buf_cons) { + /* Return busy if nothing was flushed this call */ + if (out_buf_cons == out_buf_cons_initial) + return OPAL_BUSY; + /* Return partial if there's more to flush */ + return OPAL_PARTIAL; + } + + return OPAL_SUCCESS; } static uint32_t uart_tx_buf_space(void) @@ -246,7 +257,7 @@ static int64_t uart_opal_write(int64_t term_number, int64_t *length, } /* Flush out buffer again */ - uart_flush_out(); + uart_con_flush(); unlock(&uart_lock); @@ -357,7 +368,7 @@ static void __uart_do_poll(u8 trace_ctx) lock(&uart_lock); uart_read_to_buffer(); - uart_flush_out(); + uart_con_flush(); uart_trace(trace_ctx, 0, tx_full, in_count); unlock(&uart_lock); @@ -379,15 +390,6 @@ static void uart_irq(uint32_t chip_id __unused, uint32_t irq_mask __unused) } /* - * Flush the entire buffer all at once - */ -static void uart_con_flush_all(void) -{ - while(out_buf_prod != out_buf_cons) - uart_flush_out(); -} - -/* * Common setup/inits */ diff --git a/include/console.h b/include/console.h index 45f914b..b6fc8bf 100644 --- a/include/console.h +++ b/include/console.h @@ -51,7 +51,7 @@ struct con_ops { size_t (*write)(const char *buf, size_t len); size_t (*read)(char *buf, size_t len); bool (*poll_read)(void); - void (*flush)(void); + int64_t (*flush)(void); }; extern struct lock con_lock; @@ -62,7 +62,7 @@ extern bool flush_console(void); extern bool __flush_console(bool flush_to_drivers); extern void set_console(struct con_ops *driver); -extern void flush_console_driver(void); +extern void console_complete_flush(void); extern int mambo_read(void); extern void mambo_write(const char *buf, size_t count); diff --git a/include/opal-api.h b/include/opal-api.h index 7a11fe8..369aa93 100644 --- a/include/opal-api.h +++ b/include/opal-api.h @@ -162,7 +162,8 @@ #define OPAL_LEDS_GET_INDICATOR 114 #define OPAL_LEDS_SET_INDICATOR 115 #define OPAL_CEC_REBOOT2 116 -#define OPAL_LAST 116 +#define OPAL_CONSOLE_FLUSH 117 +#define OPAL_LAST 117 /* Device tree flags */