Received: by 2002:ac0:a594:0:0:0:0:0 with SMTP id m20-v6csp910130imm; Wed, 23 May 2018 07:24:34 -0700 (PDT) X-Google-Smtp-Source: AB8JxZo1udIaZwn/VQ5YCNG3C1wPjo5NBhkfoMbTUS6ovFKyGmLSpwc9g/REpyP4yC8byfN7E13P X-Received: by 2002:a17:902:8bc4:: with SMTP id r4-v6mr3150876plo.381.1527085474513; Wed, 23 May 2018 07:24:34 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1527085474; cv=none; d=google.com; s=arc-20160816; b=VryHMF0HYHSxq6TuDShaU2i8kmlOF3JPY40Isqyyf/Lj8M/oX3Pfp8ocbHRUnNGTup 8SJsXxoCi51REFkfhxMozSns0hIZ6RKFkgiMKnfGXWCiHvJLg4mAO5MIPt/QdtrI7/ar eXRnw1i+X20JD0/JOeLIH0xNao2nVSNbIutTVygIwMqca61iy5tcoSF7OkunZXBhh+A1 Ij9ZqhYnQqk5IqCPMCn1VoUXB6TcGKHxFIfHsUWV37DGxCaQnkhC5a97pPy4FjeJ6vYX 4XCBNRZbZhPxRJxs+cAm219IlBMRGa7zqQ9pM3yHNUqeIOLldf0rB00lJiqRBwDeGDND Ru0Q== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:content-transfer-encoding :content-language:in-reply-to:mime-version:user-agent:date :message-id:organization:from:references:cc:to:subject :arc-authentication-results; bh=YKpVJtEZiKPB/SlbnvYfK+N1JUd9Jsa3i8bINlY9o74=; b=eOG8Ayiv+2mh/xhq5PiRBeoeprG2lTFlaLFMj+CPJpQw2wkQj/j5AOcFXRFmJ/mVeG tW7P1/Aqlr4OWznFs5hBiDaoZW0JDTKf4uzM0a2sPmu0+UNUoTn3R7L0Ug+JWjYhZwBb pwQUEpfXNUQK/jknjn+GXfhXgL+JdRHVZOkCFdgP5Awvzh7kRfjpLsU4AaJePtGH4Tol g8LwzjGBQvd/4Ve6hnH3f8v7MojDernI+qLIUzCb7nmxx8hR9+XdYWogtfyVno4g82nV zVCZEPz3p7UOdteWKsKzb+903mWxADhwo0bZdRGTzxG3RVwUmSe3Rnq2SPDeX3/t+dEs qAJg== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id k84-v6si18830111pfh.62.2018.05.23.07.24.16; Wed, 23 May 2018 07:24:34 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-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-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S933176AbeEWOX6 (ORCPT + 99 others); Wed, 23 May 2018 10:23:58 -0400 Received: from usa-sjc-mx-foss1.foss.arm.com ([217.140.101.70]:56164 "EHLO foss.arm.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S932564AbeEWOX4 (ORCPT ); Wed, 23 May 2018 10:23:56 -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 A804080D; Wed, 23 May 2018 07:23:55 -0700 (PDT) Received: from [10.1.206.75] (usa-sjc-imap-foss1.foss.arm.com [10.72.51.249]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id B56D93F589; Wed, 23 May 2018 07:23:50 -0700 (PDT) Subject: Re: [PATCH v2 11/16] irqchip/irq-mvebu-icu: add support for System Error Interrupts (SEI) To: Miquel Raynal , Thomas Gleixner , Jason Cooper , Catalin Marinas , Will Deacon , Andrew Lunn , Gregory Clement , Sebastian Hesselbarth Cc: Rob Herring , Mark Rutland , devicetree@vger.kernel.org, linux-arm-kernel@lists.infradead.org, Thomas Petazzoni , Antoine Tenart , Maxime Chevallier , Nadav Haklai , Haim Boot , Hanna Hawa , linux-kernel@vger.kernel.org References: <20180522094042.24770-1-miquel.raynal@bootlin.com> <20180522094042.24770-12-miquel.raynal@bootlin.com> From: Marc Zyngier Organization: ARM Ltd Message-ID: Date: Wed, 23 May 2018 15:23:48 +0100 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:52.0) Gecko/20100101 Thunderbird/52.7.0 MIME-Version: 1.0 In-Reply-To: <20180522094042.24770-12-miquel.raynal@bootlin.com> Content-Type: text/plain; charset=utf-8 Content-Language: en-GB Content-Transfer-Encoding: 7bit Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org On 22/05/18 10:40, Miquel Raynal wrote: > An SEI driver provides an MSI domain through which it is possible to > raise SEIs. > > Handle the NSR probe function in a more generic way to support other > type of interrupts (ie. the SEIs). > > For clarity we do not use tree IRQ domains for now but linear ones > instead, allocating the 207 ICU lines for each interrupt group. What's the rational for not using trees? Because that's effectively a 100% overhead... > Reallocating an ICU slot is prevented by the use of an ICU-wide bitmap. > > Signed-off-by: Miquel Raynal > --- > drivers/irqchip/irq-mvebu-icu.c | 126 ++++++++++++++++++++++++++++++++++------ > 1 file changed, 108 insertions(+), 18 deletions(-) > > diff --git a/drivers/irqchip/irq-mvebu-icu.c b/drivers/irqchip/irq-mvebu-icu.c > index 977e47b2716f..6ad6236d6ff1 100644 > --- a/drivers/irqchip/irq-mvebu-icu.c > +++ b/drivers/irqchip/irq-mvebu-icu.c > @@ -28,6 +28,10 @@ > #define ICU_SETSPI_NSR_AH 0x14 > #define ICU_CLRSPI_NSR_AL 0x18 > #define ICU_CLRSPI_NSR_AH 0x1c > +#define ICU_SET_SEI_AL 0x50 > +#define ICU_SET_SEI_AH 0x54 > +#define ICU_CLR_SEI_AL 0x58 > +#define ICU_CLR_SEI_AH 0x5C > #define ICU_INT_CFG(x) (0x100 + 4 * (x)) > #define ICU_INT_ENABLE BIT(24) > #define ICU_IS_EDGE BIT(28) > @@ -38,12 +42,28 @@ > #define ICU_SATA0_ICU_ID 109 > #define ICU_SATA1_ICU_ID 107 > > +struct mvebu_icu_subset_data { > + unsigned int icu_group; > + unsigned int offset_set_ah; > + unsigned int offset_set_al; > + unsigned int offset_clr_ah; > + unsigned int offset_clr_al; > +}; > + > struct mvebu_icu { > struct irq_chip irq_chip; > struct regmap *regmap; > struct device *dev; > - atomic_t initialized; > bool legacy_bindings; > + /* Lock on interrupt allocations/releases */ > + spinlock_t msi_lock; > + DECLARE_BITMAP(msi_bitmap, ICU_MAX_IRQS); > +}; > + > +struct mvebu_icu_msi_data { > + struct mvebu_icu *icu; > + atomic_t initialized; > + const struct mvebu_icu_subset_data *subset_data; > }; > > struct mvebu_icu_irq_data { > @@ -76,16 +96,25 @@ static struct mvebu_icu *mvebu_icu_dev_get_drvdata(struct platform_device *pdev) > return icu; > } > > -static void mvebu_icu_init(struct mvebu_icu *icu, struct msi_msg *msg) > +static void mvebu_icu_init(struct mvebu_icu *icu, struct irq_domain *d, > + struct msi_msg *msg) > { > - if (atomic_cmpxchg(&icu->initialized, false, true)) > + struct mvebu_icu_msi_data *msi_data = platform_msi_get_host_data(d); > + const struct mvebu_icu_subset_data *subset = msi_data->subset_data; > + > + if (atomic_cmpxchg(&msi_data->initialized, false, true)) > + return; > + > + /* Set 'SET' ICU SPI message address in AP */ > + regmap_write(icu->regmap, subset->offset_set_ah, msg[0].address_hi); > + regmap_write(icu->regmap, subset->offset_set_al, msg[0].address_lo); > + > + if (subset->icu_group != ICU_GRP_NSR) > return; > > - /* Set Clear/Set ICU SPI message address in AP */ > - regmap_write(icu->regmap, ICU_SETSPI_NSR_AH, msg[0].address_hi); > - regmap_write(icu->regmap, ICU_SETSPI_NSR_AL, msg[0].address_lo); > - regmap_write(icu->regmap, ICU_CLRSPI_NSR_AH, msg[1].address_hi); > - regmap_write(icu->regmap, ICU_CLRSPI_NSR_AL, msg[1].address_lo); > + /* Set 'CLEAR' ICU SPI message address in AP (level-MSI only) */ > + regmap_write(icu->regmap, subset->offset_clr_ah, msg[1].address_hi); > + regmap_write(icu->regmap, subset->offset_clr_al, msg[1].address_lo); > } > > static void mvebu_icu_write_msg(struct msi_desc *desc, struct msi_msg *msg) > @@ -96,8 +125,8 @@ static void mvebu_icu_write_msg(struct msi_desc *desc, struct msi_msg *msg) > unsigned int icu_int; > > if (msg->address_lo || msg->address_hi) { > - /* One off initialization */ > - mvebu_icu_init(icu, msg); > + /* One off initialization per domain */ > + mvebu_icu_init(icu, d->domain, msg); > /* Configure the ICU with irq number & type */ > icu_int = msg->data | ICU_INT_ENABLE; > if (icu_irqd->type & IRQ_TYPE_EDGE_RISING) > @@ -131,7 +160,8 @@ static int > mvebu_icu_irq_domain_translate(struct irq_domain *d, struct irq_fwspec *fwspec, > unsigned long *hwirq, unsigned int *type) > { > - struct mvebu_icu *icu = platform_msi_get_host_data(d); > + struct mvebu_icu_msi_data *msi_data = platform_msi_get_host_data(d); > + struct mvebu_icu *icu = msi_data->icu; > unsigned int param_count = icu->legacy_bindings ? 3 : 2; > > /* Check the count of the parameters in dt */ > @@ -172,7 +202,9 @@ mvebu_icu_irq_domain_alloc(struct irq_domain *domain, unsigned int virq, > int err; > unsigned long hwirq; > struct irq_fwspec *fwspec = args; > - struct mvebu_icu *icu = platform_msi_get_host_data(domain); > + struct mvebu_icu_msi_data *msi_data = > + platform_msi_get_host_data(domain); > + struct mvebu_icu *icu = msi_data->icu; > struct mvebu_icu_irq_data *icu_irqd; > > icu_irqd = kmalloc(sizeof(*icu_irqd), GFP_KERNEL); > @@ -186,16 +218,22 @@ mvebu_icu_irq_domain_alloc(struct irq_domain *domain, unsigned int virq, > goto free_irqd; > } > > + spin_lock(&icu->msi_lock); > + err = bitmap_allocate_region(icu->msi_bitmap, hwirq, 0); > + spin_unlock(&icu->msi_lock); This (and the freeing counterpart) could deserve a couple of helpers. > + if (err < 0) > + goto free_irqd; > + > if (icu->legacy_bindings) > icu_irqd->icu_group = fwspec->param[0]; > else > - icu_irqd->icu_group = ICU_GRP_NSR; > + icu_irqd->icu_group = msi_data->subset_data->icu_group; > icu_irqd->icu = icu; > > err = platform_msi_domain_alloc(domain, virq, nr_irqs); > if (err) { > dev_err(icu->dev, "failed to allocate ICU interrupt in parent domain\n"); > - goto free_irqd; > + goto free_bitmap; > } > > /* Make sure there is no interrupt left pending by the firmware */ > @@ -214,6 +252,10 @@ mvebu_icu_irq_domain_alloc(struct irq_domain *domain, unsigned int virq, > > free_msi: > platform_msi_domain_free(domain, virq, nr_irqs); > +free_bitmap: > + spin_lock(&icu->msi_lock); > + bitmap_release_region(icu->msi_bitmap, hwirq, 0); > + spin_unlock(&icu->msi_lock); > free_irqd: > kfree(icu_irqd); > return err; > @@ -223,12 +265,19 @@ static void > mvebu_icu_irq_domain_free(struct irq_domain *domain, unsigned int virq, > unsigned int nr_irqs) > { > + struct mvebu_icu_msi_data *msi_data = > + platform_msi_get_host_data(domain); > + struct mvebu_icu *icu = msi_data->icu; > struct irq_data *d = irq_get_irq_data(virq); > struct mvebu_icu_irq_data *icu_irqd = d->chip_data; > > kfree(icu_irqd); > > platform_msi_domain_free(domain, virq, nr_irqs); > + > + spin_lock(&icu->msi_lock); > + bitmap_release_region(icu->msi_bitmap, d->hwirq, 0); > + spin_unlock(&icu->msi_lock); > } > > static const struct irq_domain_ops mvebu_icu_domain_ops = { > @@ -239,14 +288,29 @@ static const struct irq_domain_ops mvebu_icu_domain_ops = { > > static int mvebu_icu_subset_probe(struct platform_device *pdev) > { > + const struct mvebu_icu_subset_data *subset; > + struct mvebu_icu_msi_data *msi_data; > struct device_node *msi_parent_dn; > struct irq_domain *irq_domain; > struct mvebu_icu *icu; > > + msi_data = devm_kzalloc(&pdev->dev, sizeof(*msi_data), GFP_KERNEL); > + if (!msi_data) > + return -ENOMEM; > + > icu = mvebu_icu_dev_get_drvdata(pdev); > if (IS_ERR(icu)) > return PTR_ERR(icu); > > + subset = of_device_get_match_data(&pdev->dev); > + if (!subset) { > + dev_err(&pdev->dev, "Could not retrieve subset data\n"); > + return -EINVAL; > + } > + > + msi_data->icu = icu; > + msi_data->subset_data = subset; > + > pdev->dev.msi_domain = of_msi_get_domain(&pdev->dev, pdev->dev.of_node, > DOMAIN_BUS_PLATFORM_MSI); > if (!pdev->dev.msi_domain) > @@ -259,7 +323,7 @@ static int mvebu_icu_subset_probe(struct platform_device *pdev) > irq_domain = platform_msi_create_device_domain(&pdev->dev, ICU_MAX_IRQS, > mvebu_icu_write_msg, > &mvebu_icu_domain_ops, > - icu); > + msi_data); > if (!irq_domain) { > dev_err(&pdev->dev, "Failed to create ICU MSI domain\n"); > return -ENOMEM; > @@ -268,9 +332,30 @@ static int mvebu_icu_subset_probe(struct platform_device *pdev) > return 0; > } > > +static const struct mvebu_icu_subset_data mvebu_icu_nsr_subset_data = { > + .icu_group = ICU_GRP_NSR, > + .offset_set_ah = ICU_SETSPI_NSR_AH, > + .offset_set_al = ICU_SETSPI_NSR_AL, > + .offset_clr_ah = ICU_CLRSPI_NSR_AH, > + .offset_clr_al = ICU_CLRSPI_NSR_AL, > +}; > + > +static const struct mvebu_icu_subset_data mvebu_icu_sei_subset_data = { > + .icu_group = ICU_GRP_SEI, > + .offset_set_ah = ICU_SET_SEI_AH, > + .offset_set_al = ICU_SET_SEI_AL, > + .offset_clr_ah = ICU_CLR_SEI_AH, > + .offset_clr_al = ICU_CLR_SEI_AL, I thought SEI was edge only, given what you do in mvebu_icu_init. Confused... > +}; > + > static const struct of_device_id mvebu_icu_subset_of_match[] = { > { > .compatible = "marvell,cp110-icu-nsr", > + .data = &mvebu_icu_nsr_subset_data, > + }, > + { > + .compatible = "marvell,cp110-icu-sei", > + .data = &mvebu_icu_sei_subset_data, > }, > {}, > }; > @@ -317,6 +402,8 @@ static int mvebu_icu_probe(struct platform_device *pdev) > if (IS_ERR(icu->regmap)) > return PTR_ERR(icu->regmap); > > + spin_lock_init(&icu->msi_lock); > + > icu->irq_chip.name = devm_kasprintf(&pdev->dev, GFP_KERNEL, > "ICU.%x", > (unsigned int)res->start); > @@ -341,7 +428,7 @@ static int mvebu_icu_probe(struct platform_device *pdev) > #endif > > /* > - * Clean all ICU interrupts with type SPI_NSR, required to > + * Clean all ICU interrupts of type NSR and SEI, required to > * avoid unpredictable SPI assignments done by firmware. > */ > for (i = 0 ; i < ICU_MAX_IRQS ; i++) { > @@ -350,7 +437,8 @@ static int mvebu_icu_probe(struct platform_device *pdev) > regmap_read(icu->regmap, ICU_INT_CFG(i), &icu_int); > icu_grp = icu_int >> ICU_GROUP_SHIFT; > > - if (icu_grp == ICU_GRP_NSR) > + if (icu_grp == ICU_GRP_NSR || > + (icu_grp == ICU_GRP_SEI && !icu->legacy_bindings)) > regmap_write(icu->regmap, ICU_INT_CFG(i), 0); > } > > @@ -363,7 +451,9 @@ static int mvebu_icu_probe(struct platform_device *pdev) > } > > static const struct of_device_id mvebu_icu_of_match[] = { > - { .compatible = "marvell,cp110-icu", }, > + { > + .compatible = "marvell,cp110-icu", > + }, > {}, > }; > > Thanks, M. -- Jazz is not dead. It just smells funny...