From patchwork Thu Jul 23 09:26:33 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Marc Zyngier X-Patchwork-Id: 6852001 X-Patchwork-Delegate: bhelgaas@google.com Return-Path: X-Original-To: patchwork-linux-pci@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 901C29F1D4 for ; Thu, 23 Jul 2015 09:27:41 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 8458120778 for ; Thu, 23 Jul 2015 09:27:40 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 4232E2077A for ; Thu, 23 Jul 2015 09:27:39 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752907AbbGWJ1d (ORCPT ); Thu, 23 Jul 2015 05:27:33 -0400 Received: from foss.arm.com ([217.140.101.70]:39505 "EHLO foss.arm.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752849AbbGWJ1Z (ORCPT ); Thu, 23 Jul 2015 05:27:25 -0400 Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.72.51.249]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id 604AC75; Thu, 23 Jul 2015 02:27:38 -0700 (PDT) Received: from approximate.cambridge.arm.com (approximate.cambridge.arm.com [10.1.209.148]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id E83963F510; Thu, 23 Jul 2015 02:27:22 -0700 (PDT) From: Marc Zyngier To: Bjorn Helgaas , Thomas Gleixner , Jiang Liu , Jason Cooper Cc: , , , Yijing Wang , Ma Jun , Lorenzo Pieralisi , Duc Dang Subject: [PATCH v5 14/19] irqchip: gicv3-its: Make the PCI/MSI code standalone Date: Thu, 23 Jul 2015 10:26:33 +0100 Message-Id: <1437643598-19795-15-git-send-email-marc.zyngier@arm.com> X-Mailer: git-send-email 2.1.4 In-Reply-To: <1437643598-19795-1-git-send-email-marc.zyngier@arm.com> References: <1437643598-19795-1-git-send-email-marc.zyngier@arm.com> Sender: linux-pci-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-pci@vger.kernel.org X-Spam-Status: No, score=-8.1 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_HI, 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 We can now lookup the base ITS domain, making it possible to initialize the PCI/MSI code independently from the main ITS subsystem. This allows us to remove all the previously add hooks. Signed-off-by: Marc Zyngier --- drivers/irqchip/irq-gic-v3-its-pci-msi.c | 47 +++++++++++++++++++++++++++---- drivers/irqchip/irq-gic-v3-its.c | 48 +++++++++++++++++++++----------- include/linux/irqchip/arm-gic-v3.h | 5 ---- 3 files changed, 73 insertions(+), 27 deletions(-) diff --git a/drivers/irqchip/irq-gic-v3-its-pci-msi.c b/drivers/irqchip/irq-gic-v3-its-pci-msi.c index 7614721..cf351c6 100644 --- a/drivers/irqchip/irq-gic-v3-its-pci-msi.c +++ b/drivers/irqchip/irq-gic-v3-its-pci-msi.c @@ -20,8 +20,6 @@ #include #include -#include - static void its_mask_msi_irq(struct irq_data *d) { pci_msi_mask_irq(d); @@ -74,17 +72,24 @@ static int its_pci_msi_prepare(struct irq_domain *domain, struct device *dev, { struct pci_dev *pdev; struct its_pci_alias dev_alias; + struct msi_domain_info *msi_info; if (!dev_is_pci(dev)) return -EINVAL; + msi_info = msi_get_domain_info(domain->parent); + pdev = to_pci_dev(dev); dev_alias.pdev = pdev; dev_alias.count = nvec; pci_for_each_dma_alias(pdev, its_get_pci_alias, &dev_alias); - return its_msi_prepare(domain, dev_alias.dev_id, dev_alias.count, info); + /* ITS specific DeviceID, as the core ITS ignores dev. */ + info->scratchpad[0].ul = dev_alias.dev_id; + + return msi_info->ops->msi_prepare(domain->parent, + dev, dev_alias.count, info); } static struct msi_domain_ops its_pci_msi_ops = { @@ -98,8 +103,38 @@ static struct msi_domain_info its_pci_msi_domain_info = { .chip = &its_msi_irq_chip, }; -struct irq_domain *its_pci_msi_alloc_domain(struct device_node *np, - struct irq_domain *parent) +static struct of_device_id its_device_id[] = { + { .compatible = "arm,gic-v3-its", }, + {}, +}; + +static int __init its_pci_msi_init(void) { - return pci_msi_create_irq_domain(np, &its_pci_msi_domain_info, parent); + struct device_node *np; + struct irq_domain *parent; + + for (np = of_find_matching_node(NULL, its_device_id); np; + np = of_find_matching_node(np, its_device_id)) { + if (!of_property_read_bool(np, "msi-controller")) + continue; + + parent = irq_find_matching_host(np, DOMAIN_BUS_NEXUS); + if (!parent || !msi_get_domain_info(parent)) { + pr_err("%s: unable to locate ITS domain\n", + np->full_name); + continue; + } + + if (!pci_msi_create_irq_domain(np, &its_pci_msi_domain_info, + parent)) { + pr_err("%s: unable to create PCI domain\n", + np->full_name); + continue; + } + + pr_info("PCI/MSI: %s domain created\n", np->full_name); + } + + return 0; } +early_initcall(its_pci_msi_init); diff --git a/drivers/irqchip/irq-gic-v3-its.c b/drivers/irqchip/irq-gic-v3-its.c index ca8b1cc..21b002f 100644 --- a/drivers/irqchip/irq-gic-v3-its.c +++ b/drivers/irqchip/irq-gic-v3-its.c @@ -60,7 +60,6 @@ struct its_collection { struct its_node { raw_spinlock_t lock; struct list_head entry; - struct irq_domain *domain; void __iomem *base; unsigned long phys_base; struct its_cmd_block *cmd_base; @@ -1152,13 +1151,25 @@ static int its_alloc_device_irq(struct its_device *dev, irq_hw_number_t *hwirq) return 0; } -int its_msi_prepare(struct irq_domain *domain, u32 dev_id, - int nvec, msi_alloc_info_t *info) +static int its_msi_prepare(struct irq_domain *domain, struct device *dev, + int nvec, msi_alloc_info_t *info) { struct its_node *its; struct its_device *its_dev; + struct msi_domain_info *msi_info; + u32 dev_id; + + /* + * We ignore "dev" entierely, and rely on the dev_id that has + * been passed via the scratchpad. This limits this domain's + * usefulness to upper layers that definitely know that they + * are built on top of the ITS. + */ + dev_id = info->scratchpad[0].ul; + + msi_info = msi_get_domain_info(domain); + its = msi_info->data; - its = domain->parent->host_data; its_dev = its_find_device(its, dev_id); if (its_dev) { /* @@ -1180,6 +1191,10 @@ out: return 0; } +static struct msi_domain_ops its_msi_domain_ops = { + .msi_prepare = its_msi_prepare, +}; + static int its_irq_gic_domain_alloc(struct irq_domain *domain, unsigned int virq, irq_hw_number_t hwirq) @@ -1316,7 +1331,7 @@ static int its_probe(struct device_node *node, struct irq_domain *parent) struct resource res; struct its_node *its; void __iomem *its_base; - struct irq_domain *inner_domain = NULL; + struct irq_domain *inner_domain; u32 val; u64 baser, tmp; int err; @@ -1406,20 +1421,26 @@ static int its_probe(struct device_node *node, struct irq_domain *parent) writel_relaxed(GITS_CTLR_ENABLE, its->base + GITS_CTLR); if (of_property_read_bool(node, "msi-controller")) { + struct msi_domain_info *info; + + info = kzalloc(sizeof(*info), GFP_KERNEL); + if (!info) { + err = -ENOMEM; + goto out_free_tables; + } + inner_domain = irq_domain_add_tree(node, &its_domain_ops, its); if (!inner_domain) { err = -ENOMEM; + kfree(info); goto out_free_tables; } inner_domain->parent = parent; inner_domain->bus_token = DOMAIN_BUS_NEXUS; - - its->domain = its_pci_msi_alloc_domain(node, inner_domain); - if (!its->domain) { - err = -ENOMEM; - goto out_free_domains; - } + info->ops = &its_msi_domain_ops; + info->data = its; + inner_domain->host_data = info; } spin_lock(&its_lock); @@ -1428,11 +1449,6 @@ static int its_probe(struct device_node *node, struct irq_domain *parent) return 0; -out_free_domains: - if (its->domain) - irq_domain_remove(its->domain); - if (inner_domain) - irq_domain_remove(inner_domain); out_free_tables: its_free_tables(its); out_free_cmd: diff --git a/include/linux/irqchip/arm-gic-v3.h b/include/linux/irqchip/arm-gic-v3.h index d6149ba..bf982e0 100644 --- a/include/linux/irqchip/arm-gic-v3.h +++ b/include/linux/irqchip/arm-gic-v3.h @@ -389,11 +389,6 @@ struct irq_domain; int its_cpu_init(void); int its_init(struct device_node *node, struct rdists *rdists, struct irq_domain *domain); -int its_msi_prepare(struct irq_domain *domain, u32 dev_id, - int nvec, msi_alloc_info_t *info); - -struct irq_domain *its_pci_msi_alloc_domain(struct device_node *node, - struct irq_domain *parent); #endif