From patchwork Wed Sep 14 14:21:15 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Hanjun Guo X-Patchwork-Id: 76207 Delivered-To: patch@linaro.org Received: by 10.140.106.72 with SMTP id d66csp1902699qgf; Wed, 14 Sep 2016 07:24:09 -0700 (PDT) X-Received: by 10.66.146.201 with SMTP id te9mr4976273pab.104.1473863048635; Wed, 14 Sep 2016 07:24:08 -0700 (PDT) Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id d129si33736052pfa.184.2016.09.14.07.24.08; Wed, 14 Sep 2016 07:24:08 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-acpi-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of linux-acpi-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-acpi-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S932948AbcINOX6 (ORCPT + 6 others); Wed, 14 Sep 2016 10:23:58 -0400 Received: from szxga02-in.huawei.com ([119.145.14.65]:32432 "EHLO szxga02-in.huawei.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S933144AbcINOXz (ORCPT ); Wed, 14 Sep 2016 10:23:55 -0400 Received: from 172.24.1.60 (EHLO szxeml426-hub.china.huawei.com) ([172.24.1.60]) by szxrg02-dlp.huawei.com (MOS 4.3.7-GA FastPath queued) with ESMTP id DNB48943; Wed, 14 Sep 2016 22:23:26 +0800 (CST) Received: from linux-ibm.site (10.175.102.37) by szxeml426-hub.china.huawei.com (10.82.67.181) with Microsoft SMTP Server id 14.3.235.1; Wed, 14 Sep 2016 22:23:17 +0800 From: Hanjun Guo To: "Rafael J. Wysocki" , Marc Zyngier , Lorenzo Pieralisi CC: , , , Thomas Gleixner , "Bjorn Helgaas" , Greg KH , "Tomasz Nowicki" , Ma Jun , Kefeng Wang , Charles Garcia-Tobin , , Hanjun Guo , Agustin Vega-Frias Subject: [RFC PATCH v2 07/11] ACPI: irq: introduce interrupt producer Date: Wed, 14 Sep 2016 22:21:15 +0800 Message-ID: <1473862879-7769-8-git-send-email-guohanjun@huawei.com> X-Mailer: git-send-email 1.7.12.4 In-Reply-To: <1473862879-7769-1-git-send-email-guohanjun@huawei.com> References: <1473862879-7769-1-git-send-email-guohanjun@huawei.com> MIME-Version: 1.0 X-Originating-IP: [10.175.102.37] X-CFilter-Loop: Reflected X-Mirapoint-Virus-RAPID-Raw: score=unknown(0), refid=str=0001.0A090203.57D95D5E.01C6, ss=1, re=0.000, recu=0.000, reip=0.000, cl=1, cld=1, fgs=0, ip=0.0.0.0, so=2013-06-18 04:22:30, dmn=2013-03-21 17:37:32 X-Mirapoint-Loop-Id: bc63a7a72c824ecc13923f7f92dc5bc3 Sender: linux-acpi-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-acpi@vger.kernel.org From: Hanjun Guo In ACPI 6.1 spec, section 19.6.62, Interrupt Resource Descriptor Macro, Interrupt (ResourceUsage, EdgeLevel, ActiveLevel, Shared, ResourceSourceIndex, ResourceSource, DescriptorName) { InterruptList } => Buffer For the arguement ResourceUsage and DescriptorName, which means: ResourceUsage describes whether the device consumes the specified interrupt ( ResourceConsumer ) or produces it for use by a child device ( ResourceProducer ). If nothing is specified, then ResourceConsumer is assumed. DescriptorName evaluates to a name string which refers to the entire resource descriptor. So it can be used for devices connecting to a specific interrupt prodcucer instead of the main interrupt controller in MADT. In the real world, we have irqchip such as mbi-gen which connecting to a group of wired interrupts and then issue msi to the ITS, devices connecting to such interrupt controller fit this scope. For now the irq for ACPI only pointer to the main interrupt controller's irqdomain, for devices not connecting to those irqdomains, which need to present its irq parent, we can use following ASL code to represent it: Interrupt(ResourceConsumer,..., "\_SB.IRQP") {12,14,....} then we can parse the interrupt producer with the full path name "\_SB.IRQP". In order to do that, we introduce a pointer interrupt_producer in struct acpi_device, and fill it when scanning irq resources for acpi device if it specifies the interrupt producer. But for now when parsing the resources for acpi devices, we don't pass the acpi device for acpi_walk_resoures() in drivers/acpi/resource.c, so introduce a adev in struct res_proc_context to pass it as a context to scan the interrupt resources, then finally pass to acpi_register_gsi() to find its interrupt producer to get the virq from diffrent domains. With steps above ready, rework acpi_register_gsi() to get other interrupt producer if devices not connecting to main interrupt controller. Since we often pass NULL to acpi_register_gsi() and there is no interrupt producer for devices connect to gicd on ARM or io-apic on X86, so it will use the default irqdomain for those deivces and no functional changes to those devices. Cc: Rafael J. Wysocki Cc: Agustin Vega-Frias Signed-off-by: Hanjun Guo --- drivers/acpi/gsi.c | 10 ++++-- drivers/acpi/resource.c | 85 ++++++++++++++++++++++++++++++++++--------------- include/acpi/acpi_bus.h | 1 + 3 files changed, 68 insertions(+), 28 deletions(-) -- 1.7.12.4 -- To unsubscribe from this list: send the line "unsubscribe linux-acpi" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html diff --git a/drivers/acpi/gsi.c b/drivers/acpi/gsi.c index ee9e0f2..29ee547 100644 --- a/drivers/acpi/gsi.c +++ b/drivers/acpi/gsi.c @@ -55,13 +55,19 @@ int acpi_register_gsi(struct device *dev, u32 gsi, int trigger, int polarity) { struct irq_fwspec fwspec; + struct acpi_device *adev = dev ? to_acpi_device(dev) : NULL; - if (WARN_ON(!acpi_gsi_domain_id)) { + if (adev && &adev->fwnode && adev->interrupt_producer) + /* devices in DSDT connecting to spefic interrupt producer */ + fwspec.fwnode = adev->interrupt_producer; + else if (acpi_gsi_domain_id) + /* devices connecting to gicd in default */ + fwspec.fwnode = acpi_gsi_domain_id; + else { pr_warn("GSI: No registered irqchip, giving up\n"); return -EINVAL; } - fwspec.fwnode = acpi_gsi_domain_id; fwspec.param[0] = gsi; fwspec.param[1] = acpi_dev_get_irq_type(trigger, polarity); fwspec.param_count = 2; diff --git a/drivers/acpi/resource.c b/drivers/acpi/resource.c index 56241eb..f1371cf 100644 --- a/drivers/acpi/resource.c +++ b/drivers/acpi/resource.c @@ -381,7 +381,7 @@ static void acpi_dev_irqresource_disabled(struct resource *res, u32 gsi) res->flags = IORESOURCE_IRQ | IORESOURCE_DISABLED | IORESOURCE_UNSET; } -static void acpi_dev_get_irqresource(struct resource *res, u32 gsi, +static void acpi_dev_get_irqresource(struct acpi_device *adev, struct resource *res, u32 gsi, u8 triggering, u8 polarity, u8 shareable, bool legacy) { @@ -415,7 +415,7 @@ static void acpi_dev_get_irqresource(struct resource *res, u32 gsi, } res->flags = acpi_dev_irq_flags(triggering, polarity, shareable); - irq = acpi_register_gsi(NULL, gsi, triggering, polarity); + irq = acpi_register_gsi(&adev->dev, gsi, triggering, polarity); if (irq >= 0) { res->start = irq; res->end = irq; @@ -424,27 +424,9 @@ static void acpi_dev_get_irqresource(struct resource *res, u32 gsi, } } -/** - * acpi_dev_resource_interrupt - Extract ACPI interrupt resource information. - * @ares: Input ACPI resource object. - * @index: Index into the array of GSIs represented by the resource. - * @res: Output generic resource object. - * - * Check if the given ACPI resource object represents an interrupt resource - * and @index does not exceed the resource's interrupt count (true is returned - * in that case regardless of the results of the other checks)). If that's the - * case, register the GSI corresponding to @index from the array of interrupts - * represented by the resource and populate the generic resource object pointed - * to by @res accordingly. If the registration of the GSI is not successful, - * IORESOURCE_DISABLED will be set it that object's flags. - * - * Return: - * 1) false with res->flags setting to zero: not the expected resource type - * 2) false with IORESOURCE_DISABLED in res->flags: valid unassigned resource - * 3) true: valid assigned resource - */ -bool acpi_dev_resource_interrupt(struct acpi_resource *ares, int index, - struct resource *res) +static bool __acpi_dev_resource_interrupt(struct acpi_device *adev, + struct acpi_resource *ares, int index, + struct resource *res) { struct acpi_resource_irq *irq; struct acpi_resource_extended_irq *ext_irq; @@ -460,7 +442,7 @@ bool acpi_dev_resource_interrupt(struct acpi_resource *ares, int index, acpi_dev_irqresource_disabled(res, 0); return false; } - acpi_dev_get_irqresource(res, irq->interrupts[index], + acpi_dev_get_irqresource(adev, res, irq->interrupts[index], irq->triggering, irq->polarity, irq->sharable, true); break; @@ -470,7 +452,31 @@ bool acpi_dev_resource_interrupt(struct acpi_resource *ares, int index, acpi_dev_irqresource_disabled(res, 0); return false; } - acpi_dev_get_irqresource(res, ext_irq->interrupts[index], + + /* + * It's a interrupt consumer device and connecting to specfic + * interrupt controller. For now, we only support connecting + * interrupts to one irq controller for a single device + */ + if (ext_irq->producer_consumer == ACPI_CONSUMER + && ext_irq->resource_source.string_length != 0 + && !adev->interrupt_producer) { + acpi_status status; + acpi_handle handle; + struct acpi_device *device; + + status = acpi_get_handle(NULL, ext_irq->resource_source.string_ptr, &handle); + if (ACPI_FAILURE(status)) + return false; + + device = acpi_bus_get_acpi_device(handle); + if (!device) + return false; + + adev->interrupt_producer = &device->fwnode; + } + + acpi_dev_get_irqresource(adev, res, ext_irq->interrupts[index], ext_irq->triggering, ext_irq->polarity, ext_irq->sharable, false); break; @@ -481,6 +487,31 @@ bool acpi_dev_resource_interrupt(struct acpi_resource *ares, int index, return true; } + +/** + * acpi_dev_resource_interrupt - Extract ACPI interrupt resource information. + * @ares: Input ACPI resource object. + * @index: Index into the array of GSIs represented by the resource. + * @res: Output generic resource object. + * + * Check if the given ACPI resource object represents an interrupt resource + * and @index does not exceed the resource's interrupt count (true is returned + * in that case regardless of the results of the other checks)). If that's the + * case, register the GSI corresponding to @index from the array of interrupts + * represented by the resource and populate the generic resource object pointed + * to by @res accordingly. If the registration of the GSI is not successful, + * IORESOURCE_DISABLED will be set it that object's flags. + * + * Return: + * 1) false with res->flags setting to zero: not the expected resource type + * 2) false with IORESOURCE_DISABLED in res->flags: valid unassigned resource + * 3) true: valid assigned resource + */ +bool acpi_dev_resource_interrupt(struct acpi_resource *ares, int index, + struct resource *res) +{ + return __acpi_dev_resource_interrupt(NULL, ares, index, res); +} EXPORT_SYMBOL_GPL(acpi_dev_resource_interrupt); /** @@ -499,6 +530,7 @@ struct res_proc_context { void *preproc_data; int count; int error; + struct acpi_device *adev; }; static acpi_status acpi_dev_new_resource_entry(struct resource_win *win, @@ -546,7 +578,7 @@ static acpi_status acpi_dev_process_resource(struct acpi_resource *ares, || acpi_dev_resource_ext_address_space(ares, &win)) return acpi_dev_new_resource_entry(&win, c); - for (i = 0; acpi_dev_resource_interrupt(ares, i, res); i++) { + for (i = 0; __acpi_dev_resource_interrupt(c->adev, ares, i, res); i++) { acpi_status status; status = acpi_dev_new_resource_entry(&win, c); @@ -599,6 +631,7 @@ int acpi_dev_get_resources(struct acpi_device *adev, struct list_head *list, c.preproc_data = preproc_data; c.count = 0; c.error = 0; + c.adev = adev; status = acpi_walk_resources(adev->handle, METHOD_NAME__CRS, acpi_dev_process_resource, &c); if (ACPI_FAILURE(status)) { diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h index 4242c31..5410d3b 100644 --- a/include/acpi/acpi_bus.h +++ b/include/acpi/acpi_bus.h @@ -355,6 +355,7 @@ struct acpi_device { int device_type; acpi_handle handle; /* no handle for fixed hardware */ struct fwnode_handle fwnode; + struct fwnode_handle *interrupt_producer; struct acpi_device *parent; struct list_head children; struct list_head node;