From patchwork Tue Sep 8 12:43:36 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Leif Lindholm X-Patchwork-Id: 7140831 Return-Path: X-Original-To: patchwork-linux-arm@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork1.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.136]) by patchwork1.web.kernel.org (Postfix) with ESMTP id A38229F1D5 for ; Tue, 8 Sep 2015 12:47:13 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 7466720622 for ; Tue, 8 Sep 2015 12:47:12 +0000 (UTC) Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.9]) (using TLSv1.2 with cipher AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id B285E206EA for ; Tue, 8 Sep 2015 12:47:10 +0000 (UTC) Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.80.1 #2 (Red Hat Linux)) id 1ZZIGa-0003gX-9c; Tue, 08 Sep 2015 12:44:52 +0000 Received: from mail-wi0-f179.google.com ([209.85.212.179]) by bombadil.infradead.org with esmtps (Exim 4.80.1 #2 (Red Hat Linux)) id 1ZZIFx-0003Lx-MF for linux-arm-kernel@lists.infradead.org; Tue, 08 Sep 2015 12:44:15 +0000 Received: by wicfx3 with SMTP id fx3so118714512wic.1 for ; Tue, 08 Sep 2015 05:43:51 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=/YZCCeI5dXZVkLjG/CYW3GiLwA/6upoP/C7EUm8w8Q0=; b=mfoQV2zb51mAXXQbNF36APyDhTXlCV5XWD/VPUK4cjr4xWOqWHE+o/F7J2RMu5pWLe Cgx/kupp1yQ/FIMGjL/aWaEhJowhOkRREI76RQr6rvw6gkrPagvsjGzx1rPhqD1KasAE 2lMrAKnBV27Y7ZqFJPUN6pgwtde9qabx056PpsUSaafoazirYdfC2MCqZSXGfoJoS1CV 4uJl9/5qFYrCLNKuaR/r0O00l+zHVESSoc2OYF5Xhn7Zm4o59yKKJiQVmTaENmegIj4A kX22CzU8S8FGQm2mlhM9dUJ76ro/yDZ8mfNSzCNmKVIXUpW+AZZk/aKkxbnAoJJsDxvA o7UA== X-Gm-Message-State: ALoCoQlPvvpVhuI2Nj1qsgWy1jawsnSKIM//m9JUVm3K/S609Iz2ajFo/pe6bl2ScOhKcE6Rw1G1 X-Received: by 10.180.76.231 with SMTP id n7mr44410705wiw.65.1441716231649; Tue, 08 Sep 2015 05:43:51 -0700 (PDT) Received: from mohikan.mushroom.smurfnet.nu (cpc4-cmbg17-2-0-cust71.5-4.cable.virginm.net. [86.14.224.72]) by smtp.gmail.com with ESMTPSA id i7sm4696047wib.15.2015.09.08.05.43.50 (version=TLSv1.2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Tue, 08 Sep 2015 05:43:51 -0700 (PDT) From: Leif Lindholm To: linux-arm-kernel@lists.infradead.org, devicetree@vger.kernel.org, linux-serial@vger.kernel.org, linux-acpi@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [RFC 4/5] tty/console: use SPCR table to define console Date: Tue, 8 Sep 2015 13:43:36 +0100 Message-Id: <1441716217-23786-5-git-send-email-leif.lindholm@linaro.org> X-Mailer: git-send-email 2.1.4 In-Reply-To: <1441716217-23786-1-git-send-email-leif.lindholm@linaro.org> References: <1441716217-23786-1-git-send-email-leif.lindholm@linaro.org> X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20150908_054414_105277_24993937 X-CRM114-Status: GOOD ( 26.15 ) X-Spam-Score: -2.6 (--) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.20 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: mark.rutland@arm.com, al.stone@linaro.org, graeme.gregory@linaro.org, linaro-acpi@lists.linaro.org, jcm@redhat.com, torez@redhat.com, lv.zheng@intel.com MIME-Version: 1.0 Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org X-Spam-Status: No, score=-4.2 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_MED, T_RP_MATCHES_RCVD, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP From: Torez Smith If console= is not added to the kernel command line, the console is not registered until much further into the booting process. This patch adds support to parse the SPCR ACPI table to pull console support out, then use the appropriate drivers to set up console support earlier in the boot process. Signed-off-by: Jon Masters [rebased and cleaned up] Signed-off-by: Torez Smith [reworked to use _CRS, moved to drivers/acpi] Signed-off-by: Leif Lindholm --- drivers/acpi/console.c | 157 +++++++++++++++++++++++++++++++++++++++ drivers/tty/serial/serial_core.c | 14 +++- include/linux/acpi.h | 11 ++- 3 files changed, 179 insertions(+), 3 deletions(-) diff --git a/drivers/acpi/console.c b/drivers/acpi/console.c index a985890..02883a1 100644 --- a/drivers/acpi/console.c +++ b/drivers/acpi/console.c @@ -1,5 +1,6 @@ /* * Copyright (c) 2012, Intel Corporation + * Copyright (c) 2015, Red Hat, Inc. * Copyright (c) 2015, Linaro Ltd. * * This program is free software; you can redistribute it and/or modify @@ -12,11 +13,17 @@ #define pr_fmt(fmt) "ACPI: " KBUILD_MODNAME ": " fmt #include +#include #include #include +#include #define NUM_ELEMS(x) (sizeof(x) / sizeof(*x)) +static u64 acpi_serial_addr; +static struct acpi_device *acpi_serial_device; +static char *acpi_serial_options; + #ifdef CONFIG_SERIAL_EARLYCON static int use_earlycon __initdata; static int __init setup_acpi_earlycon(char *buf) @@ -101,3 +108,153 @@ int __init acpi_early_console_probe(void) return 0; } #endif /* CONFIG_SERIAL_EARLYCON */ + +/* + * Parse the SPCR table. If we are not working with version 2 or + * higher, bail. + * Otherwise, pull out the baud rate and address to the console device. + */ +static int __init acpi_parse_spcr(struct acpi_table_header *table) +{ + struct acpi_table_spcr *spcr = (struct acpi_table_spcr *)table; + + if (table->revision < 2) + return -EOPNOTSUPP; + + /* Handle possible alignment issues */ + memcpy(&acpi_serial_addr, + &spcr->serial_port.address, sizeof(acpi_serial_addr)); + + /* + * The baud rate the BIOS used for redirection. Valid values are.... + * 3 = 9600 + * 4 = 19200 + * 6 = 57600 + * 7 = 115200 + * 0-2, 5, 8 - 255 = reserved + */ + switch (spcr->baud_rate) { + case 3: + acpi_serial_options = "9600"; + break; + case 4: + acpi_serial_options = "19200"; + break; + case 6: + acpi_serial_options = "57600"; + break; + case 7: + acpi_serial_options = "115200"; + break; + default: + acpi_serial_options = ""; + break; + } + + pr_info("SPCR serial device: 0x%llx (options: %s)\n", + acpi_serial_addr, acpi_serial_options); + + return 0; +} + +/* + * Parse an ACPI "Device" to determine if it represents the + * data found in the SPCR table. If the associated Device has + * and Address entry, and, that Address matches the one found + * in our SPCR table, it's the entry we are interested in. + * + */ +static acpi_status acpi_spcr_device_scan(acpi_handle handle, + u32 level, void *context, void **retv) +{ + unsigned long long addr = 0; + struct acpi_buffer name_buffer = { ACPI_ALLOCATE_BUFFER, NULL }; + acpi_status status = AE_OK; + struct acpi_device *adev; + struct list_head resource_list; + struct resource_entry *rentry; + + status = acpi_get_name(handle, ACPI_FULL_PATHNAME, &name_buffer); + if (ACPI_FAILURE(status)) + return status; + + adev = acpi_bus_get_acpi_device(handle); + if (!adev) { + pr_err("Err locating SPCR device from ACPI handle\n"); + return AE_OK; /* skip this one */ + } + + /* + * Read device address from _CRS. + */ + INIT_LIST_HEAD(&resource_list); + if (acpi_dev_get_resources(adev, &resource_list, NULL, NULL) <= 0) + return AE_OK; + + list_for_each_entry(rentry, &resource_list, node) { + if (resource_type(rentry->res) == IORESOURCE_MEM) + addr = rentry->res->start; + } + acpi_dev_free_resource_list(&resource_list); + + if (addr == acpi_serial_addr) { + acpi_serial_device = adev; + + pr_info("SPCR serial console: %s (0x%llx)\n", + (char *)(name_buffer.pointer), addr); + + return AE_OK; /* harmless to continue */ + } + + /* continue */ + return AE_OK; /* continue */ +} + +static int __init acpi_setup_spcr(void) +{ + if (0 != acpi_table_parse(ACPI_SIG_SPCR, acpi_parse_spcr)) { + pr_warn("SPCR table not found - auto console disabled\n"); + return -ENODEV; + } + + acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, + ACPI_UINT32_MAX, acpi_spcr_device_scan, + NULL, NULL, NULL); + + return 0; +} + +static int __init acpi_spcr_setup(void) +{ + /* + * If ACPI is enabled, scan the tables for + * automatic console configuration + */ + if (!acpi_disabled) + acpi_setup_spcr(); + + return 0; +} +subsys_initcall_sync(acpi_spcr_setup); + +/** + * acpi_console_check() - Check for and configure console from ACPI information + * @adev - Pointer to device + * @name - Name to use for preferred console without index. ex. "ttyS" + * @index - Index to use for preferred console. + * + * Check if the given device matches the information provided in the SPCR table + * If it does then register it as the preferred console and return TRUE. + * Otherwise return FALSE. + */ +bool acpi_console_check(struct acpi_device *adev, char *name, int index) +{ + if (acpi_disabled || !adev || adev != acpi_serial_device + || console_set_on_cmdline) + return false; + + pr_info("adding preferred console [%s]\n", name); + + return !add_preferred_console(name, index, + kstrdup(acpi_serial_options, GFP_KERNEL)); +} diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c index 603d2cc..4b20bc6 100644 --- a/drivers/tty/serial/serial_core.c +++ b/drivers/tty/serial/serial_core.c @@ -34,6 +34,7 @@ #include #include #include +#include #include #include @@ -2696,9 +2697,18 @@ int uart_add_one_port(struct uart_driver *drv, struct uart_port *uport) spin_lock_init(&uport->lock); lockdep_set_class(&uport->lock, &port_lock_key); } - if (uport->cons && uport->dev) - of_console_check(uport->dev->of_node, uport->cons->name, uport->line); + /* + * Support both open FW and ACPI access to console definitions. + * Both of_console_check() and acpi_console_check() will call + * add_preferred_console() if a console definition is found. + */ + if (uport->cons && uport->dev) { + if (!acpi_console_check(ACPI_COMPANION(uport->dev), + uport->cons->name, uport->line)) + of_console_check(uport->dev->of_node, + uport->cons->name, uport->line); + } uart_configure_port(drv, state, uport); num_groups = 2; diff --git a/include/linux/acpi.h b/include/linux/acpi.h index 88cb9c1..f1b9a64 100644 --- a/include/linux/acpi.h +++ b/include/linux/acpi.h @@ -811,8 +811,17 @@ static inline struct acpi_device *acpi_get_next_child(struct device *dev, #endif -#if defined(CONFIG_ACPI) && defined(CONFIG_SERIAL_EARLYCON) +#if defined(CONFIG_ACPI) +# if defined(CONFIG_SERIAL_EARLYCON) int __init acpi_early_console_probe(void); +# endif +bool acpi_console_check(struct acpi_device *adev, char *name, int index); +#else +static inline bool acpi_console_check(struct acpi_device *adev, char *name, + int index) +{ + return FALSE; +} #endif #endif /*_LINUX_ACPI_H*/