From patchwork Wed Jul 29 10:08:51 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Hanjun Guo X-Patchwork-Id: 6891841 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 58EFB9F358 for ; Wed, 29 Jul 2015 10:12:48 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 508382079C for ; Wed, 29 Jul 2015 10:12:47 +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 51BAF20788 for ; Wed, 29 Jul 2015 10:12:46 +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 1ZKOJs-00019m-De; Wed, 29 Jul 2015 10:10:40 +0000 Received: from mail-pa0-f51.google.com ([209.85.220.51]) by bombadil.infradead.org with esmtps (Exim 4.80.1 #2 (Red Hat Linux)) id 1ZKOJW-0007qQ-1Y for linux-arm-kernel@lists.infradead.org; Wed, 29 Jul 2015 10:10:20 +0000 Received: by pabkd10 with SMTP id kd10so3379590pab.2 for ; Wed, 29 Jul 2015 03:09:57 -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=M+rVc97rEpyU0OH9xnkCNbhhLlkQ9l9tpggpqePBNqU=; b=YOTAmUA3OhicRnPtbrdLaP/w/Ta2vX8yGuVseKu05NAJqf4V8YqZKbtP7OOB6cGRCv PpX8SYdp/So/GsCekVKUvdmZVQGDNUFm7lQQ9+bjkUW0cn/XZ7QMuQQmwmUKrK2qS32a 3vX+pvoigKvDI634OX2htQpr86hhh3EzTwrPatCOEpx3Grcb/47MeSi8h/erEZTdONwV rCdeDGxn4j01/f5NxVEPwS+rnepb7usu1L+Peky+/P8IWKhMU+SvqyRTAJz2EWCWdhwo PZ+IkcwHJqi50UPydjgR1FBOgTQC3t47XvZ/TAj/FtWgUzDU45gTy3JVBBqG+eEN1y7c LuzQ== X-Gm-Message-State: ALoCoQlzA04XWoIzTriX7tWAlgCYKjyVNn2F8/rf0UE2+9qqCgkn+XN6bzVCzh8c4YZSWe/KqgIG X-Received: by 10.66.119.239 with SMTP id kx15mr93173341pab.156.1438164596875; Wed, 29 Jul 2015 03:09:56 -0700 (PDT) Received: from localhost ([180.150.157.4]) by smtp.googlemail.com with ESMTPSA id a5sm468333pdk.90.2015.07.29.03.09.55 (version=TLSv1.2 cipher=RC4-SHA bits=128/128); Wed, 29 Jul 2015 03:09:55 -0700 (PDT) From: Hanjun Guo To: Marc Zyngier , Jason Cooper , Will Deacon , Catalin Marinas , "Rafael J. Wysocki" Subject: [PATCH v4 02/10] ACPI / irqchip: Add self-probe infrastructure to initialize IRQ controller Date: Wed, 29 Jul 2015 18:08:51 +0800 Message-Id: <1438164539-29256-3-git-send-email-hanjun.guo@linaro.org> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1438164539-29256-1-git-send-email-hanjun.guo@linaro.org> References: <1438164539-29256-1-git-send-email-hanjun.guo@linaro.org> X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20150729_031018_309663_1B8A779B X-CRM114-Status: GOOD ( 19.70 ) 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: Wei Huang , Lorenzo Pieralisi , linux-acpi@vger.kernel.org, Timur Tabi , linaro-acpi@lists.linaro.org, linux-kernel@vger.kernel.org, Tomasz Nowicki , Grant Likely , Mark Brown , Hanjun Guo , Suravee Suthikulpanit , Bjorn Helgaas , Thomas Gleixner , Jiang Liu , linux-arm-kernel@lists.infradead.org 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=-5.6 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_MED, 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 This self-probe infrastructure works in the similar way as OF, but there is some different in the mechanism: For DT, the init fn will be called once it finds compatible strings in DT, but for ACPI, we init irqchips by static tables, and in static ACPI tables, there are no compatible strings to indicate irqchips, but thanks to the GIC version presented in ACPI table, we can call the corresponding GIC drivers matching the GIC version with this framework. This mechanism can also be used for clock declare and may also works on x86 for some table parsing too. This patch is based on Tomasz Nowicki 's work. Signed-off-by: Hanjun Guo --- drivers/irqchip/irq-gic-acpi.c | 33 +++++++++++++++++++++++++++++++++ include/asm-generic/vmlinux.lds.h | 13 +++++++++++++ include/linux/acpi.h | 16 ++++++++++++++++ include/linux/irqchip.h | 13 +++++++++++++ include/linux/mod_devicetable.h | 8 ++++++++ 5 files changed, 83 insertions(+) diff --git a/drivers/irqchip/irq-gic-acpi.c b/drivers/irqchip/irq-gic-acpi.c index 6537b43..011468d 100644 --- a/drivers/irqchip/irq-gic-acpi.c +++ b/drivers/irqchip/irq-gic-acpi.c @@ -107,3 +107,36 @@ static int __init acpi_gic_version_init(void) return 0; } + +/* + * This special acpi_table_id is the sentinel at the end of the + * acpi_table_id[] array of all irqchips. It is automatically placed at + * the end of the array by the linker, thanks to being part of a + * special section. + */ +static const struct acpi_table_id +irqchip_acpi_match_end __used __section(__irqchip_acpi_table_end); + +extern struct acpi_table_id __irqchip_acpi_table[]; + +void __init acpi_irqchip_init(void) +{ + struct acpi_table_id *id; + + if (acpi_disabled) + return; + + if (acpi_gic_version_init()) + return; + + /* scan the irqchip table to match the GIC version and its driver */ + for (id = __irqchip_acpi_table; id->id[0]; id++) { + if (gic_version == (u8)id->driver_data) { + acpi_table_parse(id->id, + (acpi_tbl_table_handler)id->handler); + return; + } + } + + pr_err("No matched driver GIC version %d\n", gic_version); +} diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h index 8bd374d..625776c 100644 --- a/include/asm-generic/vmlinux.lds.h +++ b/include/asm-generic/vmlinux.lds.h @@ -181,6 +181,18 @@ #define CPUIDLE_METHOD_OF_TABLES() OF_TABLE(CONFIG_CPU_IDLE, cpuidle_method) #define EARLYCON_OF_TABLES() OF_TABLE(CONFIG_SERIAL_EARLYCON, earlycon) +#ifdef CONFIG_ACPI +#define ACPI_TABLE(name) \ + . = ALIGN(8); \ + VMLINUX_SYMBOL(__##name##_acpi_table) = .; \ + *(__##name##_acpi_table) \ + *(__##name##_acpi_table_end) + +#define IRQCHIP_ACPI_MATCH_TABLE() ACPI_TABLE(irqchip) +#else +#define IRQCHIP_ACPI_MATCH_TABLE() +#endif + #define KERNEL_DTB() \ STRUCT_ALIGN(); \ VMLINUX_SYMBOL(__dtb_start) = .; \ @@ -516,6 +528,7 @@ CPUIDLE_METHOD_OF_TABLES() \ KERNEL_DTB() \ IRQCHIP_OF_MATCH_TABLE() \ + IRQCHIP_ACPI_MATCH_TABLE() \ EARLYCON_TABLE() \ EARLYCON_OF_TABLES() diff --git a/include/linux/acpi.h b/include/linux/acpi.h index 0820cb1..04dd0bb 100644 --- a/include/linux/acpi.h +++ b/include/linux/acpi.h @@ -829,4 +829,20 @@ static inline struct acpi_device *acpi_get_next_child(struct device *dev, #endif +#ifdef CONFIG_ACPI +#define ACPI_DECLARE(table, name, table_id, data, fn) \ + static const struct acpi_table_id __acpi_table_##name \ + __used __section(__##table##_acpi_table) \ + = { .id = table_id, \ + .handler = (void *)fn, \ + .driver_data = data } +#else +#define ACPI_DECLARE(table, name, table_id, data, fn) \ + static const struct acpi_table_id __acpi_table_##name \ + __attribute__((unused)) \ + = { .id = table_id, \ + .handler = (void *)fn, \ + .driver_data = data } +#endif + #endif /*_LINUX_ACPI_H*/ diff --git a/include/linux/irqchip.h b/include/linux/irqchip.h index 6388873..6b66d3e 100644 --- a/include/linux/irqchip.h +++ b/include/linux/irqchip.h @@ -11,6 +11,7 @@ #ifndef _LINUX_IRQCHIP_H #define _LINUX_IRQCHIP_H +#include #include /* @@ -25,6 +26,18 @@ */ #define IRQCHIP_DECLARE(name, compat, fn) OF_DECLARE_2(irqchip, name, compat, fn) +/* + * This macro must be used by the different ARM GIC drivers to declare + * the association between their version and their initialization function. + * + * @name: name that must be unique accross all IRQCHIP_ACPI_DECLARE of the + * same file. + * @gic_version: version of GIC + * @fn: initialization function + */ +#define IRQCHIP_ACPI_DECLARE(name, gic_version, fn) \ + ACPI_DECLARE(irqchip, name, ACPI_SIG_MADT, gic_version, fn) + #ifdef CONFIG_IRQCHIP void irqchip_init(void); #else diff --git a/include/linux/mod_devicetable.h b/include/linux/mod_devicetable.h index 34f25b7..105be1f 100644 --- a/include/linux/mod_devicetable.h +++ b/include/linux/mod_devicetable.h @@ -193,6 +193,14 @@ struct acpi_device_id { __u32 cls_msk; }; +#define ACPI_TABLE_ID_LEN 5 + +struct acpi_table_id { + __u8 id[ACPI_TABLE_ID_LEN]; + const void *handler; + kernel_ulong_t driver_data; +}; + #define PNP_ID_LEN 8 #define PNP_MAX_DEVICES 8