From patchwork Fri Jul 10 10:45:10 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Hanjun Guo X-Patchwork-Id: 6764971 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 8D1F79F380 for ; Fri, 10 Jul 2015 10:48:36 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 6494B207A8 for ; Fri, 10 Jul 2015 10:48:35 +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 1AAE5207AD for ; Fri, 10 Jul 2015 10:48:34 +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 1ZDVpJ-0005cA-Kq; Fri, 10 Jul 2015 10:46:41 +0000 Received: from mail-pd0-f175.google.com ([209.85.192.175]) by bombadil.infradead.org with esmtps (Exim 4.80.1 #2 (Red Hat Linux)) id 1ZDVoy-0005Aw-Cb for linux-arm-kernel@lists.infradead.org; Fri, 10 Jul 2015 10:46:21 +0000 Received: by pdjr16 with SMTP id r16so21190410pdj.3 for ; Fri, 10 Jul 2015 03:45:59 -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:mime-version:content-type:content-transfer-encoding; bh=0NcufvRv3WV872wWMN15aHB0641A0MF9P1eHlA6jUws=; b=Ae/0LH2TO5QclToyjCF7u/IsTkGDhYXPU3vRYF4CaWQmS1C2HVqNV8XXtjrKZe6QLq VQ2xBLkLk73scb121RyWQJaskjajJP+N8x8DeBKu8ifB9iGUUqD2rVk/BpduJ4jwDEsE 3IChKsGrgLNdHGAmAVDnMwG67ne+bzGEHppzCcrQOfdlvPdxvA0MzcojUTtxmvwTzmCF VYHF/S9F3I82Frj9TjldKXuPGctjTxPr9NeS2CrmX+xa6RdUPwAp96ryLSYHZGTGgu4R PxD50JV4v2RrV7bYpb8N4XkZKnE28XfFU6rsYBCc4aRRe67pHt7O8Dl8zCfRkt5Bpmru 0EMg== X-Gm-Message-State: ALoCoQkO+PIUH+w2vbWHrTy6kjXQw991B925l7Qk0LPXbkwy12grJMSpds6Wqev9D0U3/WPXR+4E X-Received: by 10.66.228.73 with SMTP id sg9mr41275644pac.88.1436525159724; Fri, 10 Jul 2015 03:45:59 -0700 (PDT) Received: from localhost (211-79-127-12.veetime.com. [211.79.127.12]) by smtp.googlemail.com with ESMTPSA id i5sm9131090pat.42.2015.07.10.03.45.57 (version=TLSv1.2 cipher=RC4-SHA bits=128/128); Fri, 10 Jul 2015 03:45:58 -0700 (PDT) From: Hanjun Guo To: Marc Zyngier , Jason Cooper , Will Deacon , Catalin Marinas , "Rafael J. Wysocki" Subject: [PATCH v3 4/8] irqchip / gic: Add stacked irqdomain support for ACPI based GICv2 init Date: Fri, 10 Jul 2015 18:45:10 +0800 Message-Id: <1436525114-14425-5-git-send-email-hanjun.guo@linaro.org> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1436525114-14425-1-git-send-email-hanjun.guo@linaro.org> References: <1436525114-14425-1-git-send-email-hanjun.guo@linaro.org> MIME-Version: 1.0 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20150710_034620_505437_8816D745 X-CRM114-Status: GOOD ( 29.44 ) 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 , Arnd Bergmann , linaro-acpi@lists.linaro.org, linux-kernel@vger.kernel.org, Tomasz Nowicki , linux-acpi@vger.kernel.org, Mark Brown , Hanjun Guo , Grant Likely , Thomas Gleixner , Jiang Liu , linux-arm-kernel@lists.infradead.org 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.8 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 For now, ACPI based GICv2 is using the irq_default_domain as the ACPI core domain which is not scalable, also we don't support stacked irq domains in ACPI, this patch is trying to implement that. Firstly, we need to find the irqdomain with GSI, because we use different model of mapping interrupt with device in ACPI than DT, in DT, we using the interrupt parent property to get the device node of irqchip for devices, that's why we need the matching function that match the device node with the one associated with the irqdomain. But for ACPI, we only can get the GSI which the device is using, no interrupt parent will be specified, then we need a mechanism to find GSI's (also the device's) irqdomain to make the code scalable. Thanks to the usage of GSI, it is a flat hwirq number which is unique in the system, then we can get its associated irq domain by matching the GSI supported by this irqchip (see drawings below), then we can live without the token pointer matching the interrupt controller as DT did. ------------ ---> gsi_base0 | | | | irqdomain <----| irqchip 0 | | | | | |____________| ---> gsi_end0 ------------ ---> gsi_base1 (probably gsi_end0+1) | | | | irqdomain <----| irqchip 1 | | | | | |____________| ---> gsi_end1 ..... if a device is using GSI n, then we can find GSI's irqdomain by matching gsi_base <= n <= gsi_end. For GIC, we only have one GICD, but the above model still valid. GICD structure in ACPI MADT defines System Vector Base in the GICD entry, which means the global system interrupt number where this GIC Distributor’s interrupt inputs start, then we can get the hwirq numbers supported by reading the register, so we can explictly get the GSI's associated irqdomain if the GSI is within the range of hwirq supported by this GICD. Secondly, pass the GSI as the arg for domain's ops alloc() function when register the GSI, then we can take advantage of stacked irqdomains. Signed-off-by: Hanjun Guo --- drivers/acpi/gsi.c | 78 ++++++++++++++++++++++++++++++++++++++--------- drivers/irqchip/irq-gic.c | 37 +++++++++++++--------- include/linux/acpi.h | 5 +++ 3 files changed, 90 insertions(+), 30 deletions(-) diff --git a/drivers/acpi/gsi.c b/drivers/acpi/gsi.c index 38208f2..ba7de7f 100644 --- a/drivers/acpi/gsi.c +++ b/drivers/acpi/gsi.c @@ -3,6 +3,7 @@ * * Copyright (C) 2015 ARM Ltd. * Author: Lorenzo Pieralisi + * Hanjun Guo for stacked irqdomains support * * 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 @@ -14,6 +15,54 @@ enum acpi_irq_model_id acpi_irq_model; +struct gsi_cfg_data { + struct list_head list; + u32 gsi_base; + u32 gsi_end; + struct irq_domain *domain; +}; + +static LIST_HEAD(gsi_cfg_data_list); +static DEFINE_MUTEX(gsi_mutex); + +/* Init the gsi cfg data which is called by irqchip drivers */ +int gsi_cfg_data_add(struct irq_domain *domain, u32 gsi_base, u32 gsi_end) +{ + struct gsi_cfg_data *data; + + data = kzalloc(sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + data->domain = domain; + data->gsi_base = gsi_base; + data->gsi_end = gsi_end; + + mutex_lock(&gsi_mutex); + list_add(&data->list, &gsi_cfg_data_list); + mutex_unlock(&gsi_mutex); + + return 0; +} + +/* Find irqdomain with GSI (hwirq number) */ +static struct irq_domain *acpi_find_irqdomain(u32 gsi) +{ + struct gsi_cfg_data *data; + struct irq_domain *domain = NULL; + + mutex_lock(&gsi_mutex); + list_for_each_entry(data, &gsi_cfg_data_list, list) { + if (gsi >= data->gsi_base && gsi <= data->gsi_end) { + domain = data->domain; + break; + } + } + mutex_unlock(&gsi_mutex); + + return domain; +} + static unsigned int acpi_gsi_get_irq_type(int trigger, int polarity) { switch (polarity) { @@ -45,12 +94,9 @@ static unsigned int acpi_gsi_get_irq_type(int trigger, int polarity) */ int acpi_gsi_to_irq(u32 gsi, unsigned int *irq) { - /* - * Only default domain is supported at present, always find - * the mapping corresponding to default domain by passing NULL - * as irq_domain parameter - */ - *irq = irq_find_mapping(NULL, gsi); + struct irq_domain *domain = acpi_find_irqdomain(gsi); + + *irq = irq_find_mapping(domain, gsi); /* * *irq == 0 means no mapping, that should * be reported as a failure @@ -72,16 +118,17 @@ EXPORT_SYMBOL_GPL(acpi_gsi_to_irq); int acpi_register_gsi(struct device *dev, u32 gsi, int trigger, int polarity) { - unsigned int irq; + int irq; unsigned int irq_type = acpi_gsi_get_irq_type(trigger, polarity); + struct irq_domain *domain = acpi_find_irqdomain(gsi); - /* - * There is no way at present to look-up the IRQ domain on ACPI, - * hence always create mapping referring to the default domain - * by passing NULL as irq_domain parameter - */ - irq = irq_create_mapping(NULL, gsi); - if (!irq) + irq = irq_find_mapping(domain, gsi); + if (irq > 0) + return irq; + + /* pass gsi as the hwirq num and get it in the domain's alloc() ops */ + irq = irq_domain_alloc_irqs(domain, 1, dev_to_node(dev), &gsi); + if (irq <= 0) return -EINVAL; /* Set irq type if specified and different than the current one */ @@ -98,7 +145,8 @@ EXPORT_SYMBOL_GPL(acpi_register_gsi); */ void acpi_unregister_gsi(u32 gsi) { - int irq = irq_find_mapping(NULL, gsi); + struct irq_domain *domain = acpi_find_irqdomain(gsi); + int irq = irq_find_mapping(domain, gsi); irq_dispose_mapping(irq); } diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c index 58a7112..39c1b0d 100644 --- a/drivers/irqchip/irq-gic.c +++ b/drivers/irqchip/irq-gic.c @@ -852,15 +852,22 @@ static struct notifier_block gic_cpu_notifier = { static int gic_irq_domain_alloc(struct irq_domain *domain, unsigned int virq, unsigned int nr_irqs, void *arg) { - int i, ret; + int i; irq_hw_number_t hwirq; - unsigned int type = IRQ_TYPE_NONE; - struct of_phandle_args *irq_data = arg; - ret = gic_irq_domain_xlate(domain, irq_data->np, irq_data->args, - irq_data->args_count, &hwirq, &type); - if (ret) - return ret; + if (acpi_disabled) { /* DT case */ + int ret; + unsigned int type = IRQ_TYPE_NONE; + struct of_phandle_args *irq_data = arg; + + ret = gic_irq_domain_xlate(domain, irq_data->np, + irq_data->args, + irq_data->args_count, &hwirq, &type); + if (ret) + return ret; + } else { /* ACPI case */ + hwirq = (irq_hw_number_t)*(u32 *)arg; + } for (i = 0; i < nr_irqs; i++) gic_irq_domain_map(domain, virq + i, hwirq + i); @@ -946,11 +953,11 @@ void __init gic_init_bases(unsigned int gic_nr, int irq_start, gic_irqs = 1020; gic->gic_irqs = gic_irqs; - if (node) { /* DT case */ + if (node || !acpi_disabled) { /* DT or ACPI case */ gic->domain = irq_domain_add_linear(node, gic_irqs, &gic_irq_domain_hierarchy_ops, gic); - } else { /* Non-DT case */ + } else { /* Non-DT and Non-ACPI case */ /* * For primary GICs, skip over SGIs. * For secondary GICs, skip over PPIs, too. @@ -1044,6 +1051,7 @@ IRQCHIP_DECLARE(msm_qgic2, "qcom,msm-qgic2", gic_of_init); #ifdef CONFIG_ACPI static phys_addr_t dist_phy_base, cpu_phy_base __initdata; +static u32 gsi_base __initdata; static int __init gic_acpi_parse_madt_cpu(struct acpi_subtable_header *header, @@ -1082,6 +1090,7 @@ gic_acpi_parse_madt_distributor(struct acpi_subtable_header *header, if (BAD_MADT_ENTRY(dist, end)) return -EINVAL; + gsi_base = dist->global_irq_base; dist_phy_base = dist->base_address; return 0; } @@ -1131,13 +1140,11 @@ gic_v2_acpi_init(struct acpi_table_header *table) return -ENOMEM; } - /* - * Initialize zero GIC instance (no multi-GIC support). Also, set GIC - * as default IRQ domain to allow for GSI registration and GSI to IRQ - * number translation (see acpi_register_gsi() and acpi_gsi_to_irq()). - */ gic_init_bases(0, -1, dist_base, cpu_base, 0, NULL); - irq_set_default_host(gic_data[0].domain); + + /* since we have only one GICD, we can safely use gic_data[0] here */ + gsi_cfg_data_add(gic_data[0].domain, gsi_base, + gsi_base + gic_data[0].gic_irqs); acpi_irq_model = ACPI_IRQ_MODEL_GIC; return 0; diff --git a/include/linux/acpi.h b/include/linux/acpi.h index 7b058f0..6e84714 100644 --- a/include/linux/acpi.h +++ b/include/linux/acpi.h @@ -204,6 +204,11 @@ extern int acpi_get_override_irq(u32 gsi, int *trigger, int *polarity); */ void acpi_unregister_gsi (u32 gsi); +#ifdef CONFIG_ACPI_GENERIC_GSI +struct irq_domain; +int gsi_cfg_data_add(struct irq_domain *domain, u32 gsi_base, u32 gsi_end); +#endif + struct pci_dev; int acpi_pci_irq_enable (struct pci_dev *dev);