[Skiboot] [PATCH 10/33] uart: Cleanup initialization and remove simulator hack
Michael Neuling
mikey at neuling.org
Wed Jul 6 16:41:29 AEST 2016
CCing Ryan since he wrote some of this code.
Mikey
On Sat, 2016-06-25 at 08:47 +1000, Benjamin Herrenschmidt wrote:
> Add more generic support for MMIO based UARTs, simplify code,
> use common initialization, and clean up the device-tree
> representation as well.
>
> Signed-off-by: Benjamin Herrenschmidt <benh at kernel.crashing.org>
> ---
> core/init.c | 7 ++-
> core/platform.c | 8 ++-
> hw/lpc-uart.c | 152 ++++++++++++++++++++--------------------------
> include/console.h | 1 -
> include/skiboot.h | 3 +-
> platforms/astbmc/common.c | 4 +-
> platforms/qemu/qemu.c | 8 +--
> platforms/rhesus/rhesus.c | 8 +--
> 8 files changed, 85 insertions(+), 106 deletions(-)
>
> diff --git a/core/init.c b/core/init.c
> index 67b539b..48f5322 100644
> --- a/core/init.c
> +++ b/core/init.c
> @@ -657,10 +657,13 @@ void __noreturn main_cpu_entry(const void *fdt, u32 master_cpu)
> * to access chips via that path early on.
> */
> init_chips();
> +
> + /* If we detect the mambo simulator, we can enable its special console
> + * early on. Do that now.
> + */
> if (chip_quirk(QUIRK_MAMBO_CALLOUTS))
> enable_mambo_console();
> - if (chip_quirk(QUIRK_SIMICS))
> - enable_simics_console();
> +
> xscom_init();
> mfsi_init();
>
> diff --git a/core/platform.c b/core/platform.c
> index 371cf42..de6e406 100644
> --- a/core/platform.c
> +++ b/core/platform.c
> @@ -98,7 +98,13 @@ opal_call(OPAL_CEC_REBOOT2, opal_cec_reboot2, 2);
>
> static void generic_platform_init(void)
> {
> - force_dummy_console();
> + /* Enable a UART if we find one in the device-tree */
> + uart_init();
> +
> + if (uart_enabled())
> + uart_setup_opal_console();
> + else
> + force_dummy_console();
> fake_rtc_init();
> }
>
> diff --git a/hw/lpc-uart.c b/hw/lpc-uart.c
> index 433cdff..6693265 100644
> --- a/hw/lpc-uart.c
> +++ b/hw/lpc-uart.c
> @@ -64,11 +64,10 @@ DEFINE_LOG_ENTRY(OPAL_RC_UART_INIT, OPAL_PLATFORM_ERR_EVT, OPAL_UART,
> static struct lock uart_lock = LOCK_UNLOCKED;
> static struct dt_node *uart_node;
> static uint32_t uart_base;
> -static bool has_irq, irq_ok, rx_full, tx_full;
> +static bool has_irq = false, irq_ok, rx_full, tx_full;
> static uint8_t tx_room;
> static uint8_t cached_ier;
> -static bool simics_uart;
> -static void *simics_uart_base;
> +static void *mmio_uart_base;
>
> static void uart_trace(u8 ctx, u8 cnt, u8 irq_state, u8 in_count)
> {
> @@ -83,16 +82,16 @@ static void uart_trace(u8 ctx, u8 cnt, u8 irq_state, u8 in_count)
>
> static inline uint8_t uart_read(unsigned int reg)
> {
> - if (simics_uart)
> - return in_8(simics_uart_base + reg);
> + if (mmio_uart_base)
> + return in_8(mmio_uart_base + reg);
> else
> return lpc_inb(uart_base + reg);
> }
>
> static inline void uart_write(unsigned int reg, uint8_t val)
> {
> - if (simics_uart)
> - out_8(simics_uart_base + reg, val);
> + if (mmio_uart_base)
> + out_8(mmio_uart_base + reg, val);
> else
> lpc_outb(val, uart_base + reg);
> }
> @@ -121,6 +120,7 @@ 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
> @@ -138,6 +138,11 @@ static void uart_update_ier(void)
> }
> }
>
> +bool uart_enabled(void)
> +{
> + return mmio_uart_base || uart_base;
> +}
> +
> /*
> * Internal console driver (output only)
> */
> @@ -146,7 +151,7 @@ static size_t uart_con_write(const char *buf, size_t len)
> size_t written = 0;
>
> /* If LPC bus is bad, we just swallow data */
> - if (!lpc_ok() && !simics_uart)
> + if (!lpc_ok() && !mmio_uart_base)
> return written;
>
> lock(&uart_lock);
> @@ -362,7 +367,7 @@ static int64_t uart_opal_read(int64_t term_number, int64_t *length,
> uart_trace(TRACE_UART_CTX_READ, read_cnt, tx_full, in_count);
>
> unlock(&uart_lock);
> -
> +
> /* Adjust the OPAL event */
> uart_adjust_opal_event();
>
> @@ -492,15 +497,13 @@ static struct lpc_client uart_lpc_client = {
> .interrupt = uart_irq,
> };
>
> -void uart_init(bool use_interrupt)
> +void uart_init(void)
> {
> const struct dt_property *prop;
> struct dt_node *n;
> char *path __unused;
> - uint32_t chip_id, irq;
> -
> - if (!lpc_present())
> - return;
> + uint32_t chip_id;
> + const uint32_t *irqp;
>
> /* UART lock is in the console path and thus must block
> * printf re-entrancy
> @@ -512,19 +515,55 @@ void uart_init(bool use_interrupt)
> if (!n)
> return;
>
> - /* Get IO base */
> - prop = dt_find_property(n, "reg");
> - if (!prop) {
> - log_simple_error(&e_info(OPAL_RC_UART_INIT),
> - "UART: Can't find reg property\n");
> - return;
> - }
> - if (dt_property_get_cell(prop, 0) != OPAL_LPC_IO) {
> - log_simple_error(&e_info(OPAL_RC_UART_INIT),
> - "UART: Only supports IO addresses\n");
> - return;
> + /* Read the interrupts property if any */
> + irqp = dt_prop_get_def(n, "interrupts", NULL);
> +
> + /* Now check if the UART is on the root bus. This is the case of
> + * directly mapped UARTs in simulation environments
> + */
> + if (n->parent == dt_root) {
> + printf("UART: Found at root !\n");
> + mmio_uart_base = (void *)dt_translate_address(n, 0, NULL);
> + if (!mmio_uart_base) {
> + printf("UART: Failed to translate address !\n");
> + return;
> + }
> +
> + /* If it has an interrupt properly, we consider this to be
> + * a direct XICS/XIVE interrupt
> + */
> + if (irqp)
> + has_irq = true;
> +
> + } else {
> + if (!lpc_present())
> + return;
> +
> + /* Get IO base */
> + prop = dt_find_property(n, "reg");
> + if (!prop) {
> + log_simple_error(&e_info(OPAL_RC_UART_INIT),
> + "UART: Can't find reg property\n");
> + return;
> + }
> + if (dt_property_get_cell(prop, 0) != OPAL_LPC_IO) {
> + log_simple_error(&e_info(OPAL_RC_UART_INIT),
> + "UART: Only supports IO addresses\n");
> + return;
> + }
> + uart_base = dt_property_get_cell(prop, 1);
> +
> + if (irqp) {
> + uint32_t irq = be32_to_cpu(*irqp);
> +
> + chip_id = dt_get_chip_id(uart_node);
> + uart_lpc_client.interrupts = LPC_IRQ(irq);
> + lpc_register_client(chip_id, &uart_lpc_client);
> + prlog(PR_DEBUG, "UART: Using LPC IRQ %d\n", irq);
> + has_irq = true;
> + }
> }
> - uart_base = dt_property_get_cell(prop, 1);
> +
>
> if (!uart_init_hw(dt_prop_get_u32(n, "current-speed"),
> dt_prop_get_u32(n, "clock-frequency"))) {
> @@ -532,7 +571,6 @@ void uart_init(bool use_interrupt)
> dt_add_property_strings(n, "status", "bad");
> return;
> }
> - chip_id = dt_get_chip_id(uart_node);
>
> /*
> * Mark LPC used by the console (will mark the relevant
> @@ -542,65 +580,5 @@ void uart_init(bool use_interrupt)
>
> /* Install console backend for printf() */
> set_console(&uart_con_driver);
> -
> - /* On Naples, use the SerIRQ, which Linux will have to share with
> - * OPAL as we don't really play the cascaded interrupt game at this
> - * point...
> - */
> - if (use_interrupt) {
> - irq = dt_prop_get_u32(n, "interrupts");
> - uart_lpc_client.interrupts = LPC_IRQ(irq);
> - lpc_register_client(chip_id, &uart_lpc_client);
> - has_irq = true;
> - prlog(PR_DEBUG, "UART: Using LPC IRQ %d\n", irq);
> - } else
> - has_irq = false;
> -}
> -
> -static bool simics_con_poll_read(void) {
> - uint8_t lsr = uart_read(REG_LSR);
> - return ((lsr & LSR_DR) != 0);
> }
>
> -static size_t simics_con_read(char *buf, size_t len)
> -{
> - size_t count = 0;
> - while (count < len) {
> - if (!simics_con_poll_read())
> - break;
> - *(buf++) = uart_read(REG_RBR);
> - count++;
> - }
> - return count;
> -}
> -
> -static struct con_ops simics_con_driver = {
> - .poll_read = simics_con_poll_read,
> - .read = simics_con_read,
> - .write = uart_con_write,
> -};
> -
> -void enable_simics_console() {
> - struct dt_node *n;
> -
> - printf("Enabling Simics console\n");
> -
> - n = dt_find_compatible_node(dt_root, NULL, "ns16550");
> - if (!n) {
> - prerror("UART: cannot find ns16550\n");
> - return;
> - }
> -
> - simics_uart_base = (void *)dt_prop_get_u64(n, "console-bar");
> - simics_uart = 1;
> - has_irq = false;
> -
> - if (!uart_init_hw(dt_prop_get_u32(n, "current-speed"),
> - dt_prop_get_u32(n, "clock-frequency"))) {
> - prerror("UART: Initialization failed\n");
> - dt_add_property_strings(n, "status", "bad");
> - return;
> - }
> -
> - set_console(&simics_con_driver);
> -}
> diff --git a/include/console.h b/include/console.h
> index ecb18c4..b6fc8bf 100644
> --- a/include/console.h
> +++ b/include/console.h
> @@ -67,7 +67,6 @@ extern void console_complete_flush(void);
> extern int mambo_read(void);
> extern void mambo_write(const char *buf, size_t count);
> extern void enable_mambo_console(void);
> -extern void enable_simics_console(void);
>
> ssize_t console_write(bool flush_to_drivers, const void *buf, size_t count);
>
> diff --git a/include/skiboot.h b/include/skiboot.h
> index ded6bb8..1d33389 100644
> --- a/include/skiboot.h
> +++ b/include/skiboot.h
> @@ -203,7 +203,7 @@ extern void probe_phb3(void);
> extern int phb3_preload_capp_ucode(void);
> extern void phb3_preload_vpd(void);
> extern void probe_npu(void);
> -extern void uart_init(bool enable_interrupt);
> +extern void uart_init(void);
> extern void homer_init(void);
> extern void occ_pstates_init(void);
> extern void slw_init(void);
> @@ -228,6 +228,7 @@ extern void nvram_read_complete(bool success);
> /* UART stuff */
> extern void uart_setup_linux_passthrough(void);
> extern void uart_setup_opal_console(void);
> +extern bool uart_enabled(void);
>
> /* OCC interrupt */
> extern void occ_interrupt(uint32_t chip_id);
> diff --git a/platforms/astbmc/common.c b/platforms/astbmc/common.c
> index 1ed7d42..0699a44 100644
> --- a/platforms/astbmc/common.c
> +++ b/platforms/astbmc/common.c
> @@ -347,8 +347,8 @@ void astbmc_early_init(void)
> /* Similarly, some BMCs don't configure the BT interrupt properly */
> ast_setup_ibt(BT_IO_BASE, BT_LPC_IRQ);
>
> - /* Setup UART and use it as console with interrupts */
> - uart_init(true);
> + /* Setup UART and use it as console */
> + uart_init();
>
> prd_init();
> }
> diff --git a/platforms/qemu/qemu.c b/platforms/qemu/qemu.c
> index 66a6aa3..a7d2889 100644
> --- a/platforms/qemu/qemu.c
> +++ b/platforms/qemu/qemu.c
> @@ -130,12 +130,8 @@ static bool qemu_probe(void)
>
> psi_set_external_irq_policy(EXTERNAL_IRQ_POLICY_SKIBOOT);
>
> - /*
> - * Setup UART and use it as console. For now, we
> - * don't expose the interrupt as we know it's not
> - * working properly yet
> - */
> - uart_init(true);
> + /* Setup UART and use it as console */
> + uart_init();
>
> return true;
> }
> diff --git a/platforms/rhesus/rhesus.c b/platforms/rhesus/rhesus.c
> index 3e2c41b..a3af777 100644
> --- a/platforms/rhesus/rhesus.c
> +++ b/platforms/rhesus/rhesus.c
> @@ -270,12 +270,8 @@ static bool rhesus_probe(void)
> /* Add missing bits of device-tree such as the UART */
> rhesus_dt_fixup(has_uart_irq);
>
> - /*
> - * Setup UART and use it as console. For now, we
> - * don't expose the interrupt as we know it's not
> - * working properly yet
> - */
> - uart_init(has_uart_irq);
> + /* Setup UART and use it as console */
> + uart_init();
>
> return true;
> }
More information about the Skiboot
mailing list