From patchwork Mon Jan 25 11:45:22 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Aleksey Makarov X-Patchwork-Id: 8107361 Return-Path: X-Original-To: patchwork-linux-acpi@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork2.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.136]) by patchwork2.web.kernel.org (Postfix) with ESMTP id 6709DBEEE5 for ; Mon, 25 Jan 2016 11:46:33 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 4FB5C202FF for ; Mon, 25 Jan 2016 11:46:32 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 0EE4E202F0 for ; Mon, 25 Jan 2016 11:46:31 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1757137AbcAYLqO (ORCPT ); Mon, 25 Jan 2016 06:46:14 -0500 Received: from mail-lf0-f52.google.com ([209.85.215.52]:36249 "EHLO mail-lf0-f52.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1757042AbcAYLpm (ORCPT ); Mon, 25 Jan 2016 06:45:42 -0500 Received: by mail-lf0-f52.google.com with SMTP id h129so83502669lfh.3 for ; Mon, 25 Jan 2016 03:45:41 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=dVNaT7TmxwB/5ANlW6HZTZa49MphB1bnm1431u4e7xk=; b=J9x95upie1pJiAXlvtfm80d3nfwjvoxNnfh2a45GjudcLjsHP8hWOGlOra3gGfCDO3 hTTM8bVzsyXjBaJ9Tm0XV4btQTm8OURLB+wWDZvUy3g0ZXcyq0hsPyAT0wQlnB9nu+mD S7CumXhgkiFTXHnEscH0RBcjGZ/T5mofOoQ7c= 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=dVNaT7TmxwB/5ANlW6HZTZa49MphB1bnm1431u4e7xk=; b=JCk+qginX3nYHF2gMj2k1m+w5K1zFlhhHjF1ekG7/hSXOBfaKx4zyBaIeKq0C2yli6 Z92PmaZgRqbuKOTE8gD6HS/sjkQWBVk45Bc36PzlFuMy53grZBLEuIWUJhDx2f0DVBny G2iEzN8mLjyZhZmHTA3pefl64GtZUSmZKyoHyyJcumZOpvxPicCqIIqa7wCVb8rMbhdf ytRLFqZoUDATNpHBZaqEeSW/D6V3aRYv5CcxTULK/z3DjIKtT51Pb5618X9g/DrH8xFb g93fty/PPHitPQJZ7PP1DsndmdNKMtqL/pxdLP7/UXCb704OkzwHIh5ry5GFHeR2y1YL QUzQ== X-Gm-Message-State: AG10YOStslxN4POSdrFMvP25gGXhFIq1+bOIeWHBJPdhOlIL/+j5zOD7RxX2DavnFQqkKhYt X-Received: by 10.25.167.74 with SMTP id q71mr5006330lfe.22.1453722340564; Mon, 25 Jan 2016 03:45:40 -0800 (PST) Received: from lemon.localdomain (host-2-60-44-52.pppoe.omsknet.ru. [2.60.44.52]) by smtp.gmail.com with ESMTPSA id jx8sm2662527lbc.29.2016.01.25.03.45.38 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Mon, 25 Jan 2016 03:45:39 -0800 (PST) From: Aleksey Makarov To: linux-acpi@vger.kernel.org Cc: linux-kernel@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-serial@vger.kernel.org, Aleksey Makarov , Graeme Gregory , Russell King , Greg Kroah-Hartman , "Rafael J . Wysocki" , Leif Lindholm , Catalin Marinas , Will Deacon , Len Brown Subject: [PATCH 2/3] ACPI: parse SPCR and enable matching console Date: Mon, 25 Jan 2016 17:45:22 +0600 Message-Id: <1453722324-22407-3-git-send-email-aleksey.makarov@linaro.org> X-Mailer: git-send-email 2.7.0 In-Reply-To: <1453722324-22407-1-git-send-email-aleksey.makarov@linaro.org> References: <1453722324-22407-1-git-send-email-aleksey.makarov@linaro.org> Sender: linux-acpi-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-acpi@vger.kernel.org X-Spam-Status: No, score=-6.8 required=5.0 tests=BAYES_00,DKIM_SIGNED, RCVD_IN_DNSWL_HI,RP_MATCHES_RCVD,T_DKIM_INVALID,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 'ARM Server Base Boot Requiremets' [1] mention SPCR (Serial Port Console Redirection Table) [2] as a mandatory ACPI table that specifies the configuration of serial console. Parse this table and check if any registered console match the description. If it does, enable that console. To implement that, introduce a new member int (*acpi_match)(struct console *, struct acpi_table_spcr *) of struct console. It allows drivers to check if they provide a matching console device. [1] http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.den0044a/index.html [2] http://msdn.microsoft.com/en-us/library/windows/hardware/dn639131(v=vs.85).aspx Signed-off-by: Aleksey Makarov --- arch/arm64/Kconfig | 1 + drivers/acpi/Kconfig | 3 ++ drivers/acpi/Makefile | 1 + drivers/acpi/spcr.c | 85 +++++++++++++++++++++++++++++++++++++++++++++++++ include/linux/console.h | 12 +++++++ kernel/printk/printk.c | 82 +++++++++++++++++++++++++++++++++++++---------- 6 files changed, 167 insertions(+), 17 deletions(-) create mode 100644 drivers/acpi/spcr.c diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig index 573bebc..bf31e3c 100644 --- a/arch/arm64/Kconfig +++ b/arch/arm64/Kconfig @@ -4,6 +4,7 @@ config ARM64 select ACPI_GENERIC_GSI if ACPI select ACPI_PCI_HOST_GENERIC if ACPI select ACPI_REDUCED_HARDWARE_ONLY if ACPI + select ACPI_SPCR_TABLE if ACPI select ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE select ARCH_HAS_ELF_RANDOMIZE select ARCH_HAS_GCOV_PROFILE_ALL diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig index e315061..142a338 100644 --- a/drivers/acpi/Kconfig +++ b/drivers/acpi/Kconfig @@ -60,6 +60,9 @@ config ACPI_CCA_REQUIRED config IORT_TABLE bool +config ACPI_SPCR_TABLE + bool + config ACPI_DEBUGGER bool "AML debugger interface (EXPERIMENTAL)" select ACPI_DEBUG diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile index 265eb90..8316859 100644 --- a/drivers/acpi/Makefile +++ b/drivers/acpi/Makefile @@ -81,6 +81,7 @@ obj-$(CONFIG_ACPI_CUSTOM_METHOD)+= custom_method.o obj-$(CONFIG_ACPI_BGRT) += bgrt.o obj-$(CONFIG_ACPI_CPPC_LIB) += cppc_acpi.o obj-$(CONFIG_IORT_TABLE) += iort.o +obj-$(CONFIG_ACPI_SPCR_TABLE) += spcr.o # processor has its own "processor." module_param namespace processor-y := processor_driver.o diff --git a/drivers/acpi/spcr.c b/drivers/acpi/spcr.c new file mode 100644 index 0000000..ccb19a0 --- /dev/null +++ b/drivers/acpi/spcr.c @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2012, Intel Corporation + * Copyright (c) 2015, Red Hat, Inc. + * Copyright (c) 2015, 2016 Linaro Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ + +#define pr_fmt(fmt) "ACPI: SPCR: " fmt + +#include +#include +#include + +static struct acpi_table_spcr *spcr_table; + +int console_acpi_match(struct console *c, char **options) +{ + int err; + + if (!c->acpi_match) + return -ENODEV; + + if (!spcr_table) + return -EAGAIN; + + err = c->acpi_match(c, spcr_table); + if (err < 0) + return err; + + if (options) { + switch (spcr_table->baud_rate) { + case 3: + *options = "9600"; + break; + case 4: + *options = "19200"; + break; + case 6: + *options = "57600"; + break; + case 7: + *options = "115200"; + break; + default: + *options = ""; + break; + } + } + + return err; +} + +static int __init spcr_table_detect(void) +{ + struct acpi_table_header *table; + acpi_status status; + + if (acpi_disabled) + return -ENODEV; + + status = acpi_get_table(ACPI_SIG_SPCR, 0, &table); + if (ACPI_FAILURE(status)) { + const char *msg = acpi_format_exception(status); + + pr_err("Failed to get table, %s\n", msg); + return -EINVAL; + } + + if (table->revision < 2) + return -EOPNOTSUPP; + + spcr_table = (struct acpi_table_spcr *)table; + + pr_info("Console at 0x%016llx\n", spcr_table->serial_port.address); + + acpi_register_consoles_try_again(); + + return 0; +} + +arch_initcall(spcr_table_detect); diff --git a/include/linux/console.h b/include/linux/console.h index bd19434..94d0bd8 100644 --- a/include/linux/console.h +++ b/include/linux/console.h @@ -117,6 +117,7 @@ static inline int con_debug_leave(void) #define CON_BRL (32) /* Used for a braille device */ #define CON_EXTENDED (64) /* Use the extended output format a la /dev/kmsg */ +struct acpi_table_spcr; struct console { char name[16]; void (*write)(struct console *, const char *, unsigned); @@ -125,6 +126,7 @@ struct console { void (*unblank)(void); int (*setup)(struct console *, char *); int (*match)(struct console *, char *name, int idx, char *options); + int (*acpi_match)(struct console *, struct acpi_table_spcr *); short flags; short index; int cflag; @@ -132,6 +134,16 @@ struct console { struct console *next; }; +#ifdef CONFIG_ACPI +int console_acpi_match(struct console *c, char **options); +#else +static inline int console_acpi_match(struct console *c, char **options) +{ + return -ENODEV; +} +#endif +void acpi_register_consoles_try_again(void); + /* * for_each_console() allows you to iterate on each console */ diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c index 37e531f..3cf8cba 100644 --- a/kernel/printk/printk.c +++ b/kernel/printk/printk.c @@ -2430,6 +2430,25 @@ static int __init keep_bootcon_setup(char *str) early_param("keep_bootcon", keep_bootcon_setup); +static DEFINE_MUTEX(acpi_consoles_delayed_mutex); +static struct console *acpi_consoles_delayed; + +void acpi_register_consoles_try_again(void) +{ + mutex_lock(&acpi_consoles_delayed_mutex); + while (acpi_consoles_delayed) { + + struct console *c = acpi_consoles_delayed; + + acpi_consoles_delayed = acpi_consoles_delayed->next; + + mutex_unlock(&acpi_consoles_delayed_mutex); + register_console(c); + mutex_lock(&acpi_consoles_delayed_mutex); + } + mutex_unlock(&acpi_consoles_delayed_mutex); +} + /* * The console driver calls this routine during kernel initialization * to register the console printing procedure with printk() and to @@ -2538,8 +2557,30 @@ void register_console(struct console *newcon) break; } - if (!(newcon->flags & CON_ENABLED)) - return; + if (!(newcon->flags & CON_ENABLED)) { + char *opts; + int err; + + if (newcon->index < 0) + newcon->index = 0; + + err = console_acpi_match(newcon, &opts); + + if (err == -EAGAIN) { + mutex_lock(&acpi_consoles_delayed_mutex); + newcon->next = acpi_consoles_delayed; + acpi_consoles_delayed = newcon; + mutex_unlock(&acpi_consoles_delayed_mutex); + return; + } else if (err < 0) { + return; + } else { + if (newcon->setup && newcon->setup(newcon, opts) != 0) + return; + newcon->flags |= CON_ENABLED | CON_CONSDEV; + preferred_console = true; + } + } /* * If we have a bootconsole, and are switching to a real console, @@ -2612,34 +2653,41 @@ void register_console(struct console *newcon) } EXPORT_SYMBOL(register_console); +static int delete_from_console_list(struct console **list, struct console *c) +{ + while (*list) { + struct console *cur = *list; + + if (cur == c) { + *list = cur->next; + return 0; + } + list = &cur->next; + } + return 1; +} + int unregister_console(struct console *console) { - struct console *a, *b; int res; pr_info("%sconsole [%s%d] disabled\n", (console->flags & CON_BOOT) ? "boot" : "" , console->name, console->index); + mutex_lock(&acpi_consoles_delayed_mutex); + res = delete_from_console_list(&acpi_consoles_delayed, console); + mutex_unlock(&acpi_consoles_delayed_mutex); + if (res == 0) + return res; + res = _braille_unregister_console(console); if (res) return res; - res = 1; console_lock(); - if (console_drivers == console) { - console_drivers=console->next; - res = 0; - } else if (console_drivers) { - for (a=console_drivers->next, b=console_drivers ; - a; b=a, a=b->next) { - if (a == console) { - b->next = a->next; - res = 0; - break; - } - } - } + + res = delete_from_console_list(&console_drivers, console); if (!res && (console->flags & CON_EXTENDED)) nr_ext_console_drivers--;