From patchwork Tue Nov 18 18:53:04 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Marc Zyngier X-Patchwork-Id: 41075 Return-Path: X-Original-To: linaro@patches.linaro.org Delivered-To: linaro@patches.linaro.org Received: from mail-lb0-f197.google.com (mail-lb0-f197.google.com [209.85.217.197]) by ip-10-151-82-157.ec2.internal (Postfix) with ESMTPS id 829ED241C9 for ; Tue, 18 Nov 2014 18:54:24 +0000 (UTC) Received: by mail-lb0-f197.google.com with SMTP id b6sf7835486lbj.4 for ; Tue, 18 Nov 2014 10:54:23 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:mime-version:delivered-to:from:to:cc:subject :date:message-id:in-reply-to:references:sender:precedence:list-id :x-original-sender:x-original-authentication-results:mailing-list :list-post:list-help:list-archive:list-unsubscribe; bh=CXB6kmNezuXs431lbOQa5sEuoREkMxNSZSqdt61ymno=; b=msfrLqMHY3a4UtcNt3inH2SRLdsP+lv+avR6TZ6GSIXTtovb+/dxk4U5KQkgyYGKpo ZQP+U4KbkGR/Kxoo2z4asn7dbiSsl7vESHr1Ha9eIX7nj7jZ8TJU+pVEOksLrPiw2647 SDM1+27M0hGtBq+spJ/ssahJdpXwekrvJ7A/REyzqDbBJTNRr4yg70svC7+BbZs6jjMr jDhbYGIfCMOgLC/+NK05oOFrfLEYkRjwa/6LJ8/Fs/O/Plp9cSFkGuw84/2SoP/5hDhP uoUG6AUtHPkZnHPSd9d4hySkUaIf2EW+edmLSB7/HIQGPGtHkFH+3tEWAFURdgns4Uno +HFA== X-Gm-Message-State: ALoCoQkK76ahzA/tMLrydz+SQ8utWOTv2mY/+hvA2MfDnKqosozYgyMqIIl6l/USoGea28EyZafB X-Received: by 10.152.88.98 with SMTP id bf2mr15461680lab.1.1416336863472; Tue, 18 Nov 2014 10:54:23 -0800 (PST) MIME-Version: 1.0 X-BeenThere: patchwork-forward@linaro.org Received: by 10.152.28.137 with SMTP id b9ls781788lah.29.gmail; Tue, 18 Nov 2014 10:54:23 -0800 (PST) X-Received: by 10.112.150.136 with SMTP id ui8mr695261lbb.60.1416336863286; Tue, 18 Nov 2014 10:54:23 -0800 (PST) Received: from mail-la0-f47.google.com (mail-la0-f47.google.com. [209.85.215.47]) by mx.google.com with ESMTPS id a3si15272373lbv.43.2014.11.18.10.54.23 for (version=TLSv1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Tue, 18 Nov 2014 10:54:23 -0800 (PST) Received-SPF: pass (google.com: domain of patch+caf_=patchwork-forward=linaro.org@linaro.org designates 209.85.215.47 as permitted sender) client-ip=209.85.215.47; Received: by mail-la0-f47.google.com with SMTP id hz20so653577lab.34 for ; Tue, 18 Nov 2014 10:54:23 -0800 (PST) X-Received: by 10.112.14.69 with SMTP id n5mr743637lbc.34.1416336863172; Tue, 18 Nov 2014 10:54:23 -0800 (PST) X-Forwarded-To: patchwork-forward@linaro.org X-Forwarded-For: patch@linaro.org patchwork-forward@linaro.org Delivered-To: patch@linaro.org Received: by 10.112.184.201 with SMTP id ew9csp1383422lbc; Tue, 18 Nov 2014 10:54:21 -0800 (PST) X-Received: by 10.70.41.46 with SMTP id c14mr38499634pdl.101.1416336860862; Tue, 18 Nov 2014 10:54:20 -0800 (PST) Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id fb8si38846214pac.108.2014.11.18.10.54.20 for ; Tue, 18 Nov 2014 10:54:20 -0800 (PST) Received-SPF: none (google.com: linux-kernel-owner@vger.kernel.org does not designate permitted sender hosts) client-ip=209.132.180.67; Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S932184AbaKRSxq (ORCPT + 26 others); Tue, 18 Nov 2014 13:53:46 -0500 Received: from foss-mx-na.foss.arm.com ([217.140.108.86]:60714 "EHLO foss-mx-na.foss.arm.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S932158AbaKRSxn (ORCPT ); Tue, 18 Nov 2014 13:53:43 -0500 Received: from foss-smtp-na-1.foss.arm.com (unknown [10.80.61.8]) by foss-mx-na.foss.arm.com (Postfix) with ESMTP id 37B9B4EE; Tue, 18 Nov 2014 12:53:35 -0600 (CST) Received: from collaborate-mta1.arm.com (highbank-bc01-b06.austin.arm.com [10.112.81.134]) by foss-smtp-na-1.foss.arm.com (Postfix) with ESMTP id DD7C55FAD7; Tue, 18 Nov 2014 12:53:32 -0600 (CST) Received: from approximate.cambridge.arm.com (approximate.cambridge.arm.com [10.1.209.28]) by collaborate-mta1.arm.com (Postfix) with ESMTP id A6E3B13F6FA; Tue, 18 Nov 2014 12:53:30 -0600 (CST) From: Marc Zyngier To: Thomas Gleixner , Jason Cooper Cc: linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, Jiang Liu , Bjorn Helgaas , Yingjoe Chen , Will Deacon , Catalin marinas , Mark Rutland , Suravee Suthikulpanit , Robert Richter , "Yun Wu (Abel)" Subject: [PATCH v2 09/13] irqchip: GICv3: ITS: MSI support Date: Tue, 18 Nov 2014 18:53:04 +0000 Message-Id: <1416336788-22634-10-git-send-email-marc.zyngier@arm.com> X-Mailer: git-send-email 2.1.3 In-Reply-To: <1416336788-22634-1-git-send-email-marc.zyngier@arm.com> References: <1416336788-22634-1-git-send-email-marc.zyngier@arm.com> Sender: linux-kernel-owner@vger.kernel.org Precedence: list List-ID: X-Mailing-List: linux-kernel@vger.kernel.org X-Removed-Original-Auth: Dkim didn't pass. X-Original-Sender: marc.zyngier@arm.com X-Original-Authentication-Results: mx.google.com; spf=pass (google.com: domain of patch+caf_=patchwork-forward=linaro.org@linaro.org designates 209.85.215.47 as permitted sender) smtp.mail=patch+caf_=patchwork-forward=linaro.org@linaro.org Mailing-list: list patchwork-forward@linaro.org; contact patchwork-forward+owners@linaro.org X-Google-Group-Id: 836684582541 List-Post: , List-Help: , List-Archive: List-Unsubscribe: , Now, the bit of code that allow us to use the ITS as a MSI controller. Both MSI and MSI-X are supported. Signed-off-by: Marc Zyngier --- drivers/irqchip/irq-gic-v3-its.c | 179 +++++++++++++++++++++++++++++++++++++ include/linux/irqchip/arm-gic-v3.h | 6 ++ 2 files changed, 185 insertions(+) diff --git a/drivers/irqchip/irq-gic-v3-its.c b/drivers/irqchip/irq-gic-v3-its.c index d687fd4..ff92aa4 100644 --- a/drivers/irqchip/irq-gic-v3-its.c +++ b/drivers/irqchip/irq-gic-v3-its.c @@ -587,12 +587,47 @@ static int its_set_affinity(struct irq_data *d, const struct cpumask *mask_val, return IRQ_SET_MASK_OK_DONE; } +static void its_irq_compose_msi_msg(struct irq_data *d, struct msi_msg *msg) +{ + struct its_device *its_dev = irq_data_get_irq_chip_data(d); + struct its_node *its; + u64 addr; + + its = its_dev->its; + addr = its->phys_base + GITS_TRANSLATER; + + msg->address_lo = addr & ((1UL << 32) - 1); + msg->address_hi = addr >> 32; + msg->data = its_get_event_id(d); +} + static struct irq_chip its_irq_chip = { .name = "ITS", .irq_mask = its_mask_irq, .irq_unmask = its_unmask_irq, .irq_eoi = its_eoi_irq, .irq_set_affinity = its_set_affinity, + .irq_compose_msi_msg = its_irq_compose_msi_msg, +}; + +static void its_mask_msi_irq(struct irq_data *d) +{ + mask_msi_irq(d); + irq_chip_mask_parent(d); +} + +static void its_unmask_msi_irq(struct irq_data *d) +{ + unmask_msi_irq(d); + irq_chip_unmask_parent(d); +} + +static struct irq_chip its_msi_irq_chip = { + .name = "ITS-MSI", + .irq_unmask = its_unmask_msi_irq, + .irq_mask = its_mask_msi_irq, + .irq_eoi = irq_chip_eoi_parent, + .irq_write_msi_msg = pci_msi_domain_write_msg, }; /* @@ -1055,3 +1090,147 @@ static void its_free_device(struct its_device *its_dev) kfree(its_dev->itt); kfree(its_dev); } + +static int its_alloc_device_irq(struct its_device *dev, irq_hw_number_t *hwirq) +{ + int idx; + + idx = find_first_zero_bit(dev->lpi_map, dev->nr_lpis); + if (idx == dev->nr_lpis) + return -ENOSPC; + + *hwirq = dev->lpi_base + idx; + set_bit(idx, dev->lpi_map); + + /* Map the GIC irq ID to the device */ + its_send_mapvi(dev, *hwirq, idx); + + return 0; +} + +static int its_msi_prepare(struct irq_domain *domain, struct device *dev, + int nvec, msi_alloc_info_t *info) +{ + struct pci_dev *pdev; + struct msi_controller *chip; + struct its_node *its; + u32 dev_id; + struct its_device *its_dev; + + if (!dev_is_pci(dev)) + return -EINVAL; + + pdev = to_pci_dev(dev); + + chip = pdev->bus->msi; + its = container_of(chip, struct its_node, msi_chip); + dev_id = PCI_DEVID(pdev->bus->number, pdev->devfn); + + its_dev = its_find_device(its, dev_id); + if (WARN_ON(its_dev)) + return -EINVAL; + + its_dev = its_create_device(its, dev_id, nvec); + if (!its_dev) + return -ENOMEM; + + dev_dbg(&pdev->dev, "ITT %d entries, %d bits\n", nvec, ilog2(nvec)); + + info->scratchpad[0].ptr = its_dev; + info->scratchpad[1].ptr = dev; + return 0; +} + +static struct msi_domain_ops its_pci_msi_ops = { + .msi_prepare = its_msi_prepare, +}; + +static struct msi_domain_info its_pci_msi_domain_info = { + .flags = (MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS | + MSI_FLAG_MULTI_PCI_MSI | MSI_FLAG_PCI_MSIX), + .ops = &its_pci_msi_ops, + .chip = &its_msi_irq_chip, +}; + +static int its_irq_gic_domain_alloc(struct irq_domain *domain, + unsigned int virq, + irq_hw_number_t hwirq) +{ + struct of_phandle_args args; + + args.np = domain->parent->of_node; + args.args_count = 3; + args.args[0] = GIC_IRQ_TYPE_LPI; + args.args[1] = hwirq; + args.args[2] = IRQ_TYPE_EDGE_RISING; + + return irq_domain_alloc_irqs_parent(domain, virq, 1, &args); +} + +static int its_irq_domain_alloc(struct irq_domain *domain, unsigned int virq, + unsigned int nr_irqs, void *args) +{ + msi_alloc_info_t *info = args; + struct its_device *its_dev = info->scratchpad[0].ptr; + irq_hw_number_t hwirq; + int err; + int i; + + for (i = 0; i < nr_irqs; i++) { + err = its_alloc_device_irq(its_dev, &hwirq); + if (err) + return err; + + err = its_irq_gic_domain_alloc(domain, virq + i, hwirq); + if (err) + return err; + + irq_domain_set_hwirq_and_chip(domain, virq + i, + hwirq, &its_irq_chip, its_dev); + dev_dbg(info->scratchpad[1].ptr, "ID:%d pID:%d vID:%d\n", + (int)(hwirq - its_dev->lpi_base), (int)hwirq, virq + i); + } + + return 0; +} + +static void its_irq_domain_free(struct irq_domain *domain, unsigned int virq, + unsigned int nr_irqs) +{ + struct irq_data *d = irq_domain_get_irq_data(domain, virq); + struct its_device *its_dev = irq_data_get_irq_chip_data(d); + int i; + + for (i = 0; i < nr_irqs; i++) { + struct irq_data *data = irq_domain_get_irq_data(domain, + virq + i); + int event = its_get_event_id(data); + + /* Stop the delivery of interrupts */ + its_send_discard(its_dev, event); + + /* Mark interrupt index as unused */ + clear_bit(event, its_dev->lpi_map); + + /* Nuke the entry in the domain */ + irq_domain_set_hwirq_and_chip(domain, virq + i, 0, NULL, NULL); + } + + /* If all interrupts have been freed, start mopping the floor */ + if (bitmap_empty(its_dev->lpi_map, its_dev->nr_lpis)) { + its_lpi_free(its_dev->lpi_map, + its_dev->lpi_base, + its_dev->nr_lpis); + + /* Unmap device/itt */ + its_send_mapd(its_dev, 0); + its_free_device(its_dev); + } + + irq_domain_free_irqs_parent(domain, virq, nr_irqs); +} + +static const struct irq_domain_ops its_domain_ops = { + .alloc = its_irq_domain_alloc, + .free = its_irq_domain_free, +}; diff --git a/include/linux/irqchip/arm-gic-v3.h b/include/linux/irqchip/arm-gic-v3.h index 21c9d70..0ed30d7 100644 --- a/include/linux/irqchip/arm-gic-v3.h +++ b/include/linux/irqchip/arm-gic-v3.h @@ -295,6 +295,12 @@ #include +/* + * We need a value to serve as a irq-type for LPIs. Choose one that will + * hopefully pique the interest of the reviewer. + */ +#define GIC_IRQ_TYPE_LPI 0xa110c8ed + struct rdists { struct { void __iomem *rd_base;