All of lore.kernel.org
 help / color / mirror / Atom feed
From: Marc Zyngier <maz@kernel.org>
To: Mark-PK Tsai <mark-pk.tsai@mediatek.com>
Cc: devicetree@vger.kernel.org, alix.wu@mediatek.com,
	jason@lakedaemon.net, yj.chiang@mediatek.com,
	linux-kernel@vger.kernel.org, robh+dt@kernel.org,
	linux-mediatek@lists.infradead.org, matthias.bgg@gmail.com,
	tglx@linutronix.de, linux-arm-kernel@lists.infradead.org
Subject: Re: [PATCH 1/2] irqchip: irq-mt58xx: Add mt58xx interrupt controller support
Date: Mon, 03 Aug 2020 09:04:39 +0100	[thread overview]
Message-ID: <43f5cba1199f89cde68c8a577103f28b@kernel.org> (raw)
In-Reply-To: <20200803062214.24076-2-mark-pk.tsai@mediatek.com>

On 2020-08-03 07:22, Mark-PK Tsai wrote:
> Add mt58xx interrupt controller support using hierarchy irq
> domain.
> 
> Signed-off-by: Mark-PK Tsai <mark-pk.tsai@mediatek.com>
> ---
>  drivers/irqchip/Kconfig      |   7 ++
>  drivers/irqchip/Makefile     |   1 +
>  drivers/irqchip/irq-mt58xx.c | 196 +++++++++++++++++++++++++++++++++++
>  3 files changed, 204 insertions(+)
>  create mode 100644 drivers/irqchip/irq-mt58xx.c
> 
> diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig
> index 216b3b8392b5..00453af78be0 100644
> --- a/drivers/irqchip/Kconfig
> +++ b/drivers/irqchip/Kconfig
> @@ -572,4 +572,11 @@ config LOONGSON_PCH_MSI
>  	help
>  	  Support for the Loongson PCH MSI Controller.
> 
> +config MT58XX_IRQ
> +	bool "MT58XX IRQ"
> +	select IRQ_DOMAIN
> +	select IRQ_DOMAIN_HIERARCHY
> +	help
> +	  Support Mediatek MT58XX Interrupt Controller.
> +
>  endmenu
> diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile
> index 133f9c45744a..5062e9bfa92d 100644
> --- a/drivers/irqchip/Makefile
> +++ b/drivers/irqchip/Makefile
> @@ -111,3 +111,4 @@ obj-$(CONFIG_LOONGSON_HTPIC)		+= 
> irq-loongson-htpic.o
>  obj-$(CONFIG_LOONGSON_HTVEC)		+= irq-loongson-htvec.o
>  obj-$(CONFIG_LOONGSON_PCH_PIC)		+= irq-loongson-pch-pic.o
>  obj-$(CONFIG_LOONGSON_PCH_MSI)		+= irq-loongson-pch-msi.o
> +obj-$(CONFIG_MT58XX_IRQ)		+= irq-mt58xx.o
> diff --git a/drivers/irqchip/irq-mt58xx.c 
> b/drivers/irqchip/irq-mt58xx.c
> new file mode 100644
> index 000000000000..e45ad023afa6
> --- /dev/null
> +++ b/drivers/irqchip/irq-mt58xx.c
> @@ -0,0 +1,196 @@
> +// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
> +/*
> + * Copyright (c) 2020 MediaTek Inc.
> + * Author Mark-PK Tsai <mark-pk.tsai@mediatek.com>
> + */
> +
> +#include <linux/interrupt.h>
> +#include <linux/io.h>
> +#include <linux/irq.h>
> +#include <linux/irqchip.h>
> +#include <linux/irqdomain.h>
> +#include <linux/of.h>
> +#include <linux/of_address.h>
> +#include <linux/of_irq.h>
> +#include <linux/slab.h>
> +
> +#define INTC_MASK	0x0
> +#define INTC_EOI	0x20
> +
> +struct mtk_intc_chip_data {
> +	char *name;
> +	struct irq_chip chip;

There is no need to embed a full struct irqchip per controller, see 
below.

> +	unsigned int irq_start, nr_irqs;
> +	void __iomem *base;
> +};
> +
> +static void mtk_poke_irq(struct irq_data *d, u32 offset)
> +{
> +	struct mtk_intc_chip_data *cd = irq_data_get_irq_chip_data(d);
> +	void __iomem *base = cd->base;
> +	u8 index = (u8)irqd_to_hwirq(d);

Why the restrictive type? Why isn't unsigned int good enough?

> +	u16 val, mask;
> +
> +	mask = 1 << (index % 16);
> +	val = readw_relaxed(base + offset + (index / 16) * 4) | mask;
> +	writew_relaxed(val, base + offset + (index / 16) * 4);

RMW without locking, you will end-up with corruption.
Please store the address calculation in a temporaty variable to make it
more readable

> +}
> +
> +static void mtk_clear_irq(struct irq_data *d, u32 offset)
> +{
> +	struct mtk_intc_chip_data *cd = irq_data_get_irq_chip_data(d);
> +	void __iomem *base = cd->base;
> +	u8 index = (u8)irqd_to_hwirq(d);
> +	u16 val, mask;
> +
> +	mask = 1 << (index % 16);
> +	val = readw_relaxed(base + offset + (index / 16) * 4) & ~mask;
> +	writew_relaxed(val, base + offset + (index / 16) * 4);

Same comments.

> +}
> +
> +static void mtk_intc_mask_irq(struct irq_data *d)
> +{
> +	mtk_poke_irq(d, INTC_MASK);
> +	irq_chip_mask_parent(d);
> +}
> +
> +static void mtk_intc_unmask_irq(struct irq_data *d)
> +{
> +	mtk_clear_irq(d, INTC_MASK);
> +	irq_chip_unmask_parent(d);
> +}
> +
> +static void mtk_intc_eoi_irq(struct irq_data *d)
> +{
> +	mtk_poke_irq(d, INTC_EOI);
> +	irq_chip_eoi_parent(d);
> +}
> +
> +static struct irq_chip mtk_intc_chip = {
> +	.irq_mask		= mtk_intc_mask_irq,
> +	.irq_unmask		= mtk_intc_unmask_irq,
> +	.irq_eoi		= mtk_intc_eoi_irq,
> +	.irq_get_irqchip_state	= irq_chip_get_parent_state,
> +	.irq_set_irqchip_state	= irq_chip_set_parent_state,
> +	.irq_set_affinity	= irq_chip_set_affinity_parent,
> +	.irq_set_vcpu_affinity	= irq_chip_set_vcpu_affinity_parent,

How about retrigger?

> +	.irq_set_type		= irq_chip_set_type_parent,
> +	.flags			= IRQCHIP_SET_TYPE_MASKED |
> +				  IRQCHIP_SKIP_SET_WAKE |
> +				  IRQCHIP_MASK_ON_SUSPEND,
> +};
> +
> +static int mt58xx_intc_domain_translate(struct irq_domain *d,
> +					struct irq_fwspec *fwspec,
> +					unsigned long *hwirq,
> +					unsigned int *type)
> +{
> +	if (is_of_node(fwspec->fwnode)) {
> +		if (fwspec->param_count != 3)
> +			return -EINVAL;
> +
> +		/* No PPI should point to this domain */
> +		if (fwspec->param[0] != 0)
> +			return -EINVAL;
> +
> +		*hwirq = fwspec->param[1];
> +		*type = fwspec->param[2] & IRQ_TYPE_SENSE_MASK;
> +		return 0;
> +	}
> +
> +	return -EINVAL;
> +}
> +
> +static int mt58xx_intc_domain_alloc(struct irq_domain *domain,
> unsigned int virq,
> +				    unsigned int nr_irqs, void *data)
> +{
> +	int i;
> +	irq_hw_number_t hwirq;
> +	struct irq_fwspec parent_fwspec, *fwspec = data;
> +	struct mtk_intc_chip_data *cd = (struct mtk_intc_chip_data
> *)domain->host_data;
> +
> +	/* Not GIC compliant */
> +	if (fwspec->param_count != 3)
> +		return -EINVAL;
> +
> +	/* No PPI should point to this domain */
> +	if (fwspec->param[0])
> +		return -EINVAL;
> +
> +	if (fwspec->param[1] >= cd->nr_irqs)
> +		return -EINVAL;
> +
> +	hwirq = fwspec->param[1];
> +	for (i = 0; i < nr_irqs; i++)
> +		irq_domain_set_hwirq_and_chip(domain, virq + i, hwirq + i,
> +					      &cd->chip,
> +					      domain->host_data);
> +
> +	parent_fwspec = *fwspec;
> +	parent_fwspec.fwnode = domain->parent->fwnode;
> +	parent_fwspec.param[1] = cd->irq_start + hwirq;
> +	return irq_domain_alloc_irqs_parent(domain, virq, nr_irqs, 
> &parent_fwspec);
> +}
> +
> +static const struct irq_domain_ops mt58xx_intc_domain_ops = {
> +	.translate	= mt58xx_intc_domain_translate,
> +	.alloc		= mt58xx_intc_domain_alloc,
> +	.free		= irq_domain_free_irqs_common,
> +};
> +
> +int __init
> +mt58xx_intc_of_init(struct device_node *dn, struct device_node 
> *parent)
> +{
> +	static int nr_intc;
> +	struct irq_domain *domain, *domain_parent;
> +	struct mtk_intc_chip_data *cd;
> +	unsigned int irq_start, irq_end;
> +
> +	domain_parent = irq_find_host(parent);
> +	if (!domain_parent) {
> +		pr_err("mt58xx-intc: interrupt-parent not found\n");
> +		return -EINVAL;
> +	}
> +
> +	cd = kzalloc(sizeof(*cd), GFP_KERNEL);
> +	if (!cd)
> +		return -ENOMEM;
> +
> +	cd->chip = mtk_intc_chip;
> +	if (of_property_read_u32_index(dn, "mediatek,irqs-map-range", 0,
> &irq_start) ||
> +	    of_property_read_u32_index(dn, "mediatek,irqs-map-range", 1, 
> &irq_end)) {
> +		kfree(cd);
> +		return -EINVAL;
> +	}
> +
> +	if (of_property_read_bool(dn, "mediatek,intc-no-eoi"))
> +		cd->chip.irq_eoi = irq_chip_eoi_parent;

No. Just add a flag to your chip data structure, and check for this
flag in your irq_eoi callback. Or provide two distinct irq_chip
structures that will only differ by the irq_eoi method.

> +
> +	cd->irq_start = irq_start;
> +	cd->nr_irqs = irq_end - irq_start + 1;
> +	cd->chip.name = kasprintf(GFP_KERNEL, "mt58xx-intc-%d", nr_intc++);

Neither. That's not useful, and is a waste of memory. Stick to constant
names in the irq_chip structure.

> +	if (!cd->chip.name) {
> +		kfree(cd);
> +		return -ENOMEM;
> +	}
> +
> +	cd->base = of_iomap(dn, 0);
> +	if (!cd->base) {
> +		kfree(cd->chip.name);
> +		kfree(cd);
> +		return -ENOMEM;
> +	}
> +
> +	domain = irq_domain_add_hierarchy(domain_parent, 0, cd->nr_irqs,
> +					  dn, &mt58xx_intc_domain_ops, cd);
> +	if (!domain) {
> +		kfree(cd->chip.name);
> +		iounmap(cd->base);
> +		kfree(cd);
> +		return -ENOMEM;
> +	}
> +
> +	return 0;
> +}
> +
> +IRQCHIP_DECLARE(mt58xx_intc, "mediatek,mt58xx-intc", 
> mt58xx_intc_of_init);

On a side note, the merge window has just opened. Please refrain from
reposting this until -rc1.

Thanks,

         M.
-- 
Jazz is not dead. It just smells funny...

_______________________________________________
Linux-mediatek mailing list
Linux-mediatek@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-mediatek

WARNING: multiple messages have this Message-ID (diff)
From: Mark-PK Tsai <mark-pk.tsai@mediatek.com>
To: <maz@kernel.org>, Mark-PK Tsai <mark-pk.tsai@mediatek.com>
Cc: devicetree@vger.kernel.org, alix.wu@mediatek.com,
	jason@lakedaemon.net, yj.chiang@mediatek.com,
	linux-kernel@vger.kernel.org, robh+dt@kernel.org,
	linux-mediatek@lists.infradead.org, matthias.bgg@gmail.com,
	tglx@linutronix.de, linux-arm-kernel@lists.infradead.org
Subject: Re: [PATCH 1/2] irqchip: irq-mt58xx: Add mt58xx interrupt controller support
Date: Mon, 3 Aug 2020 23:03:37 +0800	[thread overview]
Message-ID: <43f5cba1199f89cde68c8a577103f28b@kernel.org> (raw) (raw)
Message-ID: <20200803150337.pXFiHprm_8hBz7A9Xgj2JkWqEtO1--ra6bbQhIQ0Voc@z> (raw)
In-Reply-To: <20200803062214.24076-2-mark-pk.tsai@mediatek.com>

From: Marc Zyngier <maz@kernel.org>

> On 2020-08-03 07:22, Mark-PK Tsai wrote:
> > Add mt58xx interrupt controller support using hierarchy irq
> > domain.
> > 
> > Signed-off-by: Mark-PK Tsai <mark-pk.tsai@mediatek.com>
> > ---
> >  drivers/irqchip/Kconfig      |   7 ++
> >  drivers/irqchip/Makefile     |   1 +
> >  drivers/irqchip/irq-mt58xx.c | 196 +++++++++++++++++++++++++++++++++++
> >  3 files changed, 204 insertions(+)
> >  create mode 100644 drivers/irqchip/irq-mt58xx.c
> > 
> > diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig
> > index 216b3b8392b5..00453af78be0 100644
> > --- a/drivers/irqchip/Kconfig
> > +++ b/drivers/irqchip/Kconfig
> > @@ -572,4 +572,11 @@ config LOONGSON_PCH_MSI
> >  	help
> >  	  Support for the Loongson PCH MSI Controller.
> > 
> > +config MT58XX_IRQ
> > +	bool "MT58XX IRQ"
> > +	select IRQ_DOMAIN
> > +	select IRQ_DOMAIN_HIERARCHY
> > +	help
> > +	  Support Mediatek MT58XX Interrupt Controller.
> > +
> >  endmenu
> > diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile
> > index 133f9c45744a..5062e9bfa92d 100644
> > --- a/drivers/irqchip/Makefile
> > +++ b/drivers/irqchip/Makefile
> > @@ -111,3 +111,4 @@ obj-$(CONFIG_LOONGSON_HTPIC)		+= 
> > irq-loongson-htpic.o
> >  obj-$(CONFIG_LOONGSON_HTVEC)		+= irq-loongson-htvec.o
> >  obj-$(CONFIG_LOONGSON_PCH_PIC)		+= irq-loongson-pch-pic.o
> >  obj-$(CONFIG_LOONGSON_PCH_MSI)		+= irq-loongson-pch-msi.o
> > +obj-$(CONFIG_MT58XX_IRQ)		+= irq-mt58xx.o
> > diff --git a/drivers/irqchip/irq-mt58xx.c 
> > b/drivers/irqchip/irq-mt58xx.c
> > new file mode 100644
> > index 000000000000..e45ad023afa6
> > --- /dev/null
> > +++ b/drivers/irqchip/irq-mt58xx.c
> > @@ -0,0 +1,196 @@
> > +// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
> > +/*
> > + * Copyright (c) 2020 MediaTek Inc.
> > + * Author Mark-PK Tsai <mark-pk.tsai@mediatek.com>
> > + */
> > +
> > +#include <linux/interrupt.h>
> > +#include <linux/io.h>
> > +#include <linux/irq.h>
> > +#include <linux/irqchip.h>
> > +#include <linux/irqdomain.h>
> > +#include <linux/of.h>
> > +#include <linux/of_address.h>
> > +#include <linux/of_irq.h>
> > +#include <linux/slab.h>
> > +
> > +#define INTC_MASK	0x0
> > +#define INTC_EOI	0x20
> > +
> > +struct mtk_intc_chip_data {
> > +	char *name;
> > +	struct irq_chip chip;
> 
> There is no need to embed a full struct irqchip per controller, see 
> below.

We want to distinguish which controller the device interrupts are belong to
by "cat /proc/interrupts".
And if all the controller share the same struct, the name field will be the
same.
Do you have suggestion for this?

> 
> > +	unsigned int irq_start, nr_irqs;
> > +	void __iomem *base;
> > +
> };
> > +
> > +static void mtk_poke_irq(struct irq_data *d, u32 offset)
> 	> +{
> > +	struct mtk_intc_chip_data *cd = irq_data_get_irq_chip_data(d);
> > +	void __iomem *base = cd->base;
> > +	u8 index = (u8)irqd_to_hwirq(d);
> 
> Why the restrictive type? Why isn't unsigned int good enough?

You're right, unsigned int is ok.
I'll fix it in patch v2.

> 
> > +	u16 val, mask;
> > +
> > +	mask = 1 << (index % 16);
> > +	val = readw_relaxed(base + offset + (index / 16) * 4) | mask;
> > +	writew_relaxed(val, base + offset + (index / 16) * 4);
> 
> RMW without locking, you will end-up with corruption.
> Please store the address calculation in a temporaty variable to make it
> more readable
> 

Thanks for the comment, I will fix it in pacth v2.

> > +
> 	}
> > +
> > +static void mtk_clear_irq(struct irq_data *d, u32 offset)
> 	> +{
> > +	struct mtk_intc_chip_data *cd = irq_data_get_irq_chip_data(d);
> > +	void __iomem *base = cd->base;
> > +	u8 index = (u8)irqd_to_hwirq(d);
> > +	u16 val, mask;
> > +
> > +	mask = 1 << (index % 16);
> > +	val = readw_relaxed(base + offset + (index / 16) * 4) & ~mask;
> > +	writew_relaxed(val, base + offset + (index / 16) * 4);
> 
> Same comments.
> 

You're right, unsigned int is ok.
I'll fix it in patch v2.

> > +
> 	}
> > +
> > +static void mtk_intc_mask_irq(struct irq_data *d)
> 	> +{
> > +	mtk_poke_irq(d, INTC_MASK);
> > +	irq_chip_mask_parent(d);
> > +
> 	}
> > +
> > +static void mtk_intc_unmask_irq(struct irq_data *d)
> 	> +{
> > +	mtk_clear_irq(d, INTC_MASK);
> > +	irq_chip_unmask_parent(d);
> > +
> 	}
> > +
> > +static void mtk_intc_eoi_irq(struct irq_data *d)
> 	> +{
> > +	mtk_poke_irq(d, INTC_EOI);
> > +	irq_chip_eoi_parent(d);
> > +
> 	}
> > +
> > +static struct irq_chip mtk_intc_chip = {
> > +	.irq_mask		= mtk_intc_mask_irq,
> > +	.irq_unmask		= mtk_intc_unmask_irq,
> > +	.irq_eoi		= mtk_intc_eoi_irq,
> > +	.irq_get_irqchip_state	= irq_chip_get_parent_state,
> > +	.irq_set_irqchip_state	= irq_chip_set_parent_state,
> > +	.irq_set_affinity	= irq_chip_set_affinity_parent,
> > +	.irq_set_vcpu_affinity	= irq_chip_set_vcpu_affinity_parent,
> 
> How about retrigger?
> 

What is retrigger means?
To be honest, I just try to direct all the irqchip ops implemented in 
/drivers/irqchip/irq-gic.c to gic driver.
But "irq_set_vcpu_affinity" is not used in our projects now.
Should I remove ".irq_set_vcpu_affinity" here?

> > +	.irq_set_type		= irq_chip_set_type_parent,
> > +	.flags			= IRQCHIP_SET_TYPE_MASKED |
> > +				  IRQCHIP_SKIP_SET_WAKE |
> > +				  IRQCHIP_MASK_ON_SUSPEND,
> > +
> };
> > +
> > +static int mt58xx_intc_domain_translate(struct irq_domain *d,
> > +					struct irq_fwspec *fwspec,
> > +					unsigned long *hwirq,
> > +					unsigned int *type)
> 	> +{
> 		> +	if (is_of_node(fwspec->fwnode)) {
> > +		if (fwspec->param_count != 3)
> > +			return -EINVAL;
> > +
> > +		/* No PPI should point to this domain */
> > +		if (fwspec->param[0] != 0)
> > +			return -EINVAL;
> > +
> > +		*hwirq = fwspec->param[1];
> > +		*type = fwspec->param[2] & IRQ_TYPE_SENSE_MASK;
> > +		return 0;
> > +	
> 		}
> > +
> > +	return -EINVAL;
> > +
> 	}
> > +
> > +static int mt58xx_intc_domain_alloc(struct irq_domain *domain,
> > unsigned int virq,
> > +				    unsigned int nr_irqs, void *data)
> 	> +{
> > +	int i;
> > +	irq_hw_number_t hwirq;
> > +	struct irq_fwspec parent_fwspec, *fwspec = data;
> > +	struct mtk_intc_chip_data *cd = (struct mtk_intc_chip_data
> > *)domain->host_data;
> > +
> > +	/* Not GIC compliant */
> > +	if (fwspec->param_count != 3)
> > +		return -EINVAL;
> > +
> > +	/* No PPI should point to this domain */
> > +	if (fwspec->param[0])
> > +		return -EINVAL;
> > +
> > +	if (fwspec->param[1] >= cd->nr_irqs)
> > +		return -EINVAL;
> > +
> > +	hwirq = fwspec->param[1];
> > +	for (i = 0; i < nr_irqs; i++)
> > +		irq_domain_set_hwirq_and_chip(domain, virq + i, hwirq + i,
> > +					      &cd->chip,
> > +					      domain->host_data);
> > +
> > +	parent_fwspec = *fwspec;
> > +	parent_fwspec.fwnode = domain->parent->fwnode;
> > +	parent_fwspec.param[1] = cd->irq_start + hwirq;
> > +	return irq_domain_alloc_irqs_parent(domain, virq, nr_irqs, 
> > &parent_fwspec);
> > +
> 	}
> > +
> > +static const struct irq_domain_ops mt58xx_intc_domain_ops = {
> > +	.translate	= mt58xx_intc_domain_translate,
> > +	.alloc		= mt58xx_intc_domain_alloc,
> > +	.free		= irq_domain_free_irqs_common,
> > +
> };
> > +
> > +int __init
> > +mt58xx_intc_of_init(struct device_node *dn, struct device_node 
> > *parent)
> > +{
> > +	static int nr_intc;
> > +	struct irq_domain *domain, *domain_parent;
> > +	struct mtk_intc_chip_data *cd;
> > +	unsigned int irq_start, irq_end;
> > +
> > +	domain_parent = irq_find_host(parent);
> > +	if (!domain_parent) {
> > +		pr_err("mt58xx-intc: interrupt-parent not found\n");
> > +		return -EINVAL;
> > +	
> }
> > +
> > +	cd = kzalloc(sizeof(*cd), GFP_KERNEL);
> > +	if (!cd)
> > +		return -ENOMEM;
> > +
> > +	cd->chip = mtk_intc_chip;
> > +	if (of_property_read_u32_index(dn, "mediatek,irqs-map-range", 0,
> > &irq_start) ||
> > +	    of_property_read_u32_index(dn, "mediatek,irqs-map-range", 1, 
> 	> &irq_end)) {
> > +		kfree(cd);
> > +		return -EINVAL;
> > +	
> }
> > +
> > +	if (of_property_read_bool(dn, "mediatek,intc-no-eoi"))
> > +		cd->chip.irq_eoi = irq_chip_eoi_parent;
> 
> No. Just add a flag to your chip data structure, and check for this
> flag in your irq_eoi callback. Or provide two distinct irq_chip
> structures that will only differ by the irq_eoi method.

Thanks for the comment, I will modify it in patch v2.

> 
> > +
> > +	cd->irq_start = irq_start;
> > +	cd->nr_irqs = irq_end - irq_start + 1;
> > +	cd->chip.name = kasprintf(GFP_KERNEL, "mt58xx-intc-%d", nr_intc++);
> 
> Neither. That's not useful, and is a waste of memory. Stick to constant
> names in the irq_chip structure.
> 

Actually we have multiple irq controller in our SoCs.
And if we use the constant names in irq_chip structure, the information in
"/proc/interrupts" will be hard to understand because all the irqchip name
is the same.
Do you have any suggestion for this?

> > +	if (!cd->chip.name) {
> > +		kfree(cd);
> > +		return -ENOMEM;
> > +	
> }
> > +
> > +	cd->base = of_iomap(dn, 0);
> > +	if (!cd->base) {
> > +		kfree(cd->chip.name);
> > +		kfree(cd);
> > +		return -ENOMEM;
> > +	
> }
> > +
> > +	domain = irq_domain_add_hierarchy(domain_parent, 0, cd->nr_irqs,
> > +					  dn, &mt58xx_intc_domain_ops, cd);
> > +	if (!domain) {
> > +		kfree(cd->chip.name);
> > +		iounmap(cd->base);
> > +		kfree(cd);
> > +		return -ENOMEM;
> > +	
> }
> > +
> > +	return 0;
> > +
> }
> > +
> > +IRQCHIP_DECLARE(mt58xx_intc, "mediatek,mt58xx-intc", 
> > mt58xx_intc_of_init);
> 
> On a side note, the merge window has just opened. Please refrain from
> reposting this until -rc1.

Got it, and thanks for your comments.
I'll update the patch and post it after -rc1.
_______________________________________________
Linux-mediatek mailing list
Linux-mediatek@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-mediatek

WARNING: multiple messages have this Message-ID (diff)
From: Marc Zyngier <maz@kernel.org>
To: Mark-PK Tsai <mark-pk.tsai@mediatek.com>
Cc: devicetree@vger.kernel.org, alix.wu@mediatek.com,
	jason@lakedaemon.net, yj.chiang@mediatek.com,
	linux-kernel@vger.kernel.org, robh+dt@kernel.org,
	linux-mediatek@lists.infradead.org, matthias.bgg@gmail.com,
	tglx@linutronix.de, linux-arm-kernel@lists.infradead.org
Subject: Re: [PATCH 1/2] irqchip: irq-mt58xx: Add mt58xx interrupt controller support
Date: Mon, 03 Aug 2020 09:04:39 +0100	[thread overview]
Message-ID: <43f5cba1199f89cde68c8a577103f28b@kernel.org> (raw)
In-Reply-To: <20200803062214.24076-2-mark-pk.tsai@mediatek.com>

On 2020-08-03 07:22, Mark-PK Tsai wrote:
> Add mt58xx interrupt controller support using hierarchy irq
> domain.
> 
> Signed-off-by: Mark-PK Tsai <mark-pk.tsai@mediatek.com>
> ---
>  drivers/irqchip/Kconfig      |   7 ++
>  drivers/irqchip/Makefile     |   1 +
>  drivers/irqchip/irq-mt58xx.c | 196 +++++++++++++++++++++++++++++++++++
>  3 files changed, 204 insertions(+)
>  create mode 100644 drivers/irqchip/irq-mt58xx.c
> 
> diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig
> index 216b3b8392b5..00453af78be0 100644
> --- a/drivers/irqchip/Kconfig
> +++ b/drivers/irqchip/Kconfig
> @@ -572,4 +572,11 @@ config LOONGSON_PCH_MSI
>  	help
>  	  Support for the Loongson PCH MSI Controller.
> 
> +config MT58XX_IRQ
> +	bool "MT58XX IRQ"
> +	select IRQ_DOMAIN
> +	select IRQ_DOMAIN_HIERARCHY
> +	help
> +	  Support Mediatek MT58XX Interrupt Controller.
> +
>  endmenu
> diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile
> index 133f9c45744a..5062e9bfa92d 100644
> --- a/drivers/irqchip/Makefile
> +++ b/drivers/irqchip/Makefile
> @@ -111,3 +111,4 @@ obj-$(CONFIG_LOONGSON_HTPIC)		+= 
> irq-loongson-htpic.o
>  obj-$(CONFIG_LOONGSON_HTVEC)		+= irq-loongson-htvec.o
>  obj-$(CONFIG_LOONGSON_PCH_PIC)		+= irq-loongson-pch-pic.o
>  obj-$(CONFIG_LOONGSON_PCH_MSI)		+= irq-loongson-pch-msi.o
> +obj-$(CONFIG_MT58XX_IRQ)		+= irq-mt58xx.o
> diff --git a/drivers/irqchip/irq-mt58xx.c 
> b/drivers/irqchip/irq-mt58xx.c
> new file mode 100644
> index 000000000000..e45ad023afa6
> --- /dev/null
> +++ b/drivers/irqchip/irq-mt58xx.c
> @@ -0,0 +1,196 @@
> +// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
> +/*
> + * Copyright (c) 2020 MediaTek Inc.
> + * Author Mark-PK Tsai <mark-pk.tsai@mediatek.com>
> + */
> +
> +#include <linux/interrupt.h>
> +#include <linux/io.h>
> +#include <linux/irq.h>
> +#include <linux/irqchip.h>
> +#include <linux/irqdomain.h>
> +#include <linux/of.h>
> +#include <linux/of_address.h>
> +#include <linux/of_irq.h>
> +#include <linux/slab.h>
> +
> +#define INTC_MASK	0x0
> +#define INTC_EOI	0x20
> +
> +struct mtk_intc_chip_data {
> +	char *name;
> +	struct irq_chip chip;

There is no need to embed a full struct irqchip per controller, see 
below.

> +	unsigned int irq_start, nr_irqs;
> +	void __iomem *base;
> +};
> +
> +static void mtk_poke_irq(struct irq_data *d, u32 offset)
> +{
> +	struct mtk_intc_chip_data *cd = irq_data_get_irq_chip_data(d);
> +	void __iomem *base = cd->base;
> +	u8 index = (u8)irqd_to_hwirq(d);

Why the restrictive type? Why isn't unsigned int good enough?

> +	u16 val, mask;
> +
> +	mask = 1 << (index % 16);
> +	val = readw_relaxed(base + offset + (index / 16) * 4) | mask;
> +	writew_relaxed(val, base + offset + (index / 16) * 4);

RMW without locking, you will end-up with corruption.
Please store the address calculation in a temporaty variable to make it
more readable

> +}
> +
> +static void mtk_clear_irq(struct irq_data *d, u32 offset)
> +{
> +	struct mtk_intc_chip_data *cd = irq_data_get_irq_chip_data(d);
> +	void __iomem *base = cd->base;
> +	u8 index = (u8)irqd_to_hwirq(d);
> +	u16 val, mask;
> +
> +	mask = 1 << (index % 16);
> +	val = readw_relaxed(base + offset + (index / 16) * 4) & ~mask;
> +	writew_relaxed(val, base + offset + (index / 16) * 4);

Same comments.

> +}
> +
> +static void mtk_intc_mask_irq(struct irq_data *d)
> +{
> +	mtk_poke_irq(d, INTC_MASK);
> +	irq_chip_mask_parent(d);
> +}
> +
> +static void mtk_intc_unmask_irq(struct irq_data *d)
> +{
> +	mtk_clear_irq(d, INTC_MASK);
> +	irq_chip_unmask_parent(d);
> +}
> +
> +static void mtk_intc_eoi_irq(struct irq_data *d)
> +{
> +	mtk_poke_irq(d, INTC_EOI);
> +	irq_chip_eoi_parent(d);
> +}
> +
> +static struct irq_chip mtk_intc_chip = {
> +	.irq_mask		= mtk_intc_mask_irq,
> +	.irq_unmask		= mtk_intc_unmask_irq,
> +	.irq_eoi		= mtk_intc_eoi_irq,
> +	.irq_get_irqchip_state	= irq_chip_get_parent_state,
> +	.irq_set_irqchip_state	= irq_chip_set_parent_state,
> +	.irq_set_affinity	= irq_chip_set_affinity_parent,
> +	.irq_set_vcpu_affinity	= irq_chip_set_vcpu_affinity_parent,

How about retrigger?

> +	.irq_set_type		= irq_chip_set_type_parent,
> +	.flags			= IRQCHIP_SET_TYPE_MASKED |
> +				  IRQCHIP_SKIP_SET_WAKE |
> +				  IRQCHIP_MASK_ON_SUSPEND,
> +};
> +
> +static int mt58xx_intc_domain_translate(struct irq_domain *d,
> +					struct irq_fwspec *fwspec,
> +					unsigned long *hwirq,
> +					unsigned int *type)
> +{
> +	if (is_of_node(fwspec->fwnode)) {
> +		if (fwspec->param_count != 3)
> +			return -EINVAL;
> +
> +		/* No PPI should point to this domain */
> +		if (fwspec->param[0] != 0)
> +			return -EINVAL;
> +
> +		*hwirq = fwspec->param[1];
> +		*type = fwspec->param[2] & IRQ_TYPE_SENSE_MASK;
> +		return 0;
> +	}
> +
> +	return -EINVAL;
> +}
> +
> +static int mt58xx_intc_domain_alloc(struct irq_domain *domain,
> unsigned int virq,
> +				    unsigned int nr_irqs, void *data)
> +{
> +	int i;
> +	irq_hw_number_t hwirq;
> +	struct irq_fwspec parent_fwspec, *fwspec = data;
> +	struct mtk_intc_chip_data *cd = (struct mtk_intc_chip_data
> *)domain->host_data;
> +
> +	/* Not GIC compliant */
> +	if (fwspec->param_count != 3)
> +		return -EINVAL;
> +
> +	/* No PPI should point to this domain */
> +	if (fwspec->param[0])
> +		return -EINVAL;
> +
> +	if (fwspec->param[1] >= cd->nr_irqs)
> +		return -EINVAL;
> +
> +	hwirq = fwspec->param[1];
> +	for (i = 0; i < nr_irqs; i++)
> +		irq_domain_set_hwirq_and_chip(domain, virq + i, hwirq + i,
> +					      &cd->chip,
> +					      domain->host_data);
> +
> +	parent_fwspec = *fwspec;
> +	parent_fwspec.fwnode = domain->parent->fwnode;
> +	parent_fwspec.param[1] = cd->irq_start + hwirq;
> +	return irq_domain_alloc_irqs_parent(domain, virq, nr_irqs, 
> &parent_fwspec);
> +}
> +
> +static const struct irq_domain_ops mt58xx_intc_domain_ops = {
> +	.translate	= mt58xx_intc_domain_translate,
> +	.alloc		= mt58xx_intc_domain_alloc,
> +	.free		= irq_domain_free_irqs_common,
> +};
> +
> +int __init
> +mt58xx_intc_of_init(struct device_node *dn, struct device_node 
> *parent)
> +{
> +	static int nr_intc;
> +	struct irq_domain *domain, *domain_parent;
> +	struct mtk_intc_chip_data *cd;
> +	unsigned int irq_start, irq_end;
> +
> +	domain_parent = irq_find_host(parent);
> +	if (!domain_parent) {
> +		pr_err("mt58xx-intc: interrupt-parent not found\n");
> +		return -EINVAL;
> +	}
> +
> +	cd = kzalloc(sizeof(*cd), GFP_KERNEL);
> +	if (!cd)
> +		return -ENOMEM;
> +
> +	cd->chip = mtk_intc_chip;
> +	if (of_property_read_u32_index(dn, "mediatek,irqs-map-range", 0,
> &irq_start) ||
> +	    of_property_read_u32_index(dn, "mediatek,irqs-map-range", 1, 
> &irq_end)) {
> +		kfree(cd);
> +		return -EINVAL;
> +	}
> +
> +	if (of_property_read_bool(dn, "mediatek,intc-no-eoi"))
> +		cd->chip.irq_eoi = irq_chip_eoi_parent;

No. Just add a flag to your chip data structure, and check for this
flag in your irq_eoi callback. Or provide two distinct irq_chip
structures that will only differ by the irq_eoi method.

> +
> +	cd->irq_start = irq_start;
> +	cd->nr_irqs = irq_end - irq_start + 1;
> +	cd->chip.name = kasprintf(GFP_KERNEL, "mt58xx-intc-%d", nr_intc++);

Neither. That's not useful, and is a waste of memory. Stick to constant
names in the irq_chip structure.

> +	if (!cd->chip.name) {
> +		kfree(cd);
> +		return -ENOMEM;
> +	}
> +
> +	cd->base = of_iomap(dn, 0);
> +	if (!cd->base) {
> +		kfree(cd->chip.name);
> +		kfree(cd);
> +		return -ENOMEM;
> +	}
> +
> +	domain = irq_domain_add_hierarchy(domain_parent, 0, cd->nr_irqs,
> +					  dn, &mt58xx_intc_domain_ops, cd);
> +	if (!domain) {
> +		kfree(cd->chip.name);
> +		iounmap(cd->base);
> +		kfree(cd);
> +		return -ENOMEM;
> +	}
> +
> +	return 0;
> +}
> +
> +IRQCHIP_DECLARE(mt58xx_intc, "mediatek,mt58xx-intc", 
> mt58xx_intc_of_init);

On a side note, the merge window has just opened. Please refrain from
reposting this until -rc1.

Thanks,

         M.
-- 
Jazz is not dead. It just smells funny...

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

WARNING: multiple messages have this Message-ID (diff)
From: Mark-PK Tsai <mark-pk.tsai@mediatek.com>
To: <maz@kernel.org>, Mark-PK Tsai <mark-pk.tsai@mediatek.com>
Cc: devicetree@vger.kernel.org, alix.wu@mediatek.com,
	jason@lakedaemon.net, yj.chiang@mediatek.com,
	linux-kernel@vger.kernel.org, robh+dt@kernel.org,
	linux-mediatek@lists.infradead.org, matthias.bgg@gmail.com,
	tglx@linutronix.de, linux-arm-kernel@lists.infradead.org
Subject: Re: [PATCH 1/2] irqchip: irq-mt58xx: Add mt58xx interrupt controller support
Date: Mon, 3 Aug 2020 23:03:37 +0800	[thread overview]
Message-ID: <43f5cba1199f89cde68c8a577103f28b@kernel.org> (raw) (raw)
Message-ID: <20200803150337.s5YbNcg-IWH4627iMu3OPMqJj6HNpjv8Zelo-36rykg@z> (raw)
In-Reply-To: <20200803062214.24076-2-mark-pk.tsai@mediatek.com>

From: Marc Zyngier <maz@kernel.org>

> On 2020-08-03 07:22, Mark-PK Tsai wrote:
> > Add mt58xx interrupt controller support using hierarchy irq
> > domain.
> > 
> > Signed-off-by: Mark-PK Tsai <mark-pk.tsai@mediatek.com>
> > ---
> >  drivers/irqchip/Kconfig      |   7 ++
> >  drivers/irqchip/Makefile     |   1 +
> >  drivers/irqchip/irq-mt58xx.c | 196 +++++++++++++++++++++++++++++++++++
> >  3 files changed, 204 insertions(+)
> >  create mode 100644 drivers/irqchip/irq-mt58xx.c
> > 
> > diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig
> > index 216b3b8392b5..00453af78be0 100644
> > --- a/drivers/irqchip/Kconfig
> > +++ b/drivers/irqchip/Kconfig
> > @@ -572,4 +572,11 @@ config LOONGSON_PCH_MSI
> >  	help
> >  	  Support for the Loongson PCH MSI Controller.
> > 
> > +config MT58XX_IRQ
> > +	bool "MT58XX IRQ"
> > +	select IRQ_DOMAIN
> > +	select IRQ_DOMAIN_HIERARCHY
> > +	help
> > +	  Support Mediatek MT58XX Interrupt Controller.
> > +
> >  endmenu
> > diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile
> > index 133f9c45744a..5062e9bfa92d 100644
> > --- a/drivers/irqchip/Makefile
> > +++ b/drivers/irqchip/Makefile
> > @@ -111,3 +111,4 @@ obj-$(CONFIG_LOONGSON_HTPIC)		+= 
> > irq-loongson-htpic.o
> >  obj-$(CONFIG_LOONGSON_HTVEC)		+= irq-loongson-htvec.o
> >  obj-$(CONFIG_LOONGSON_PCH_PIC)		+= irq-loongson-pch-pic.o
> >  obj-$(CONFIG_LOONGSON_PCH_MSI)		+= irq-loongson-pch-msi.o
> > +obj-$(CONFIG_MT58XX_IRQ)		+= irq-mt58xx.o
> > diff --git a/drivers/irqchip/irq-mt58xx.c 
> > b/drivers/irqchip/irq-mt58xx.c
> > new file mode 100644
> > index 000000000000..e45ad023afa6
> > --- /dev/null
> > +++ b/drivers/irqchip/irq-mt58xx.c
> > @@ -0,0 +1,196 @@
> > +// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
> > +/*
> > + * Copyright (c) 2020 MediaTek Inc.
> > + * Author Mark-PK Tsai <mark-pk.tsai@mediatek.com>
> > + */
> > +
> > +#include <linux/interrupt.h>
> > +#include <linux/io.h>
> > +#include <linux/irq.h>
> > +#include <linux/irqchip.h>
> > +#include <linux/irqdomain.h>
> > +#include <linux/of.h>
> > +#include <linux/of_address.h>
> > +#include <linux/of_irq.h>
> > +#include <linux/slab.h>
> > +
> > +#define INTC_MASK	0x0
> > +#define INTC_EOI	0x20
> > +
> > +struct mtk_intc_chip_data {
> > +	char *name;
> > +	struct irq_chip chip;
> 
> There is no need to embed a full struct irqchip per controller, see 
> below.

We want to distinguish which controller the device interrupts are belong to
by "cat /proc/interrupts".
And if all the controller share the same struct, the name field will be the
same.
Do you have suggestion for this?

> 
> > +	unsigned int irq_start, nr_irqs;
> > +	void __iomem *base;
> > +
> };
> > +
> > +static void mtk_poke_irq(struct irq_data *d, u32 offset)
> 	> +{
> > +	struct mtk_intc_chip_data *cd = irq_data_get_irq_chip_data(d);
> > +	void __iomem *base = cd->base;
> > +	u8 index = (u8)irqd_to_hwirq(d);
> 
> Why the restrictive type? Why isn't unsigned int good enough?

You're right, unsigned int is ok.
I'll fix it in patch v2.

> 
> > +	u16 val, mask;
> > +
> > +	mask = 1 << (index % 16);
> > +	val = readw_relaxed(base + offset + (index / 16) * 4) | mask;
> > +	writew_relaxed(val, base + offset + (index / 16) * 4);
> 
> RMW without locking, you will end-up with corruption.
> Please store the address calculation in a temporaty variable to make it
> more readable
> 

Thanks for the comment, I will fix it in pacth v2.

> > +
> 	}
> > +
> > +static void mtk_clear_irq(struct irq_data *d, u32 offset)
> 	> +{
> > +	struct mtk_intc_chip_data *cd = irq_data_get_irq_chip_data(d);
> > +	void __iomem *base = cd->base;
> > +	u8 index = (u8)irqd_to_hwirq(d);
> > +	u16 val, mask;
> > +
> > +	mask = 1 << (index % 16);
> > +	val = readw_relaxed(base + offset + (index / 16) * 4) & ~mask;
> > +	writew_relaxed(val, base + offset + (index / 16) * 4);
> 
> Same comments.
> 

You're right, unsigned int is ok.
I'll fix it in patch v2.

> > +
> 	}
> > +
> > +static void mtk_intc_mask_irq(struct irq_data *d)
> 	> +{
> > +	mtk_poke_irq(d, INTC_MASK);
> > +	irq_chip_mask_parent(d);
> > +
> 	}
> > +
> > +static void mtk_intc_unmask_irq(struct irq_data *d)
> 	> +{
> > +	mtk_clear_irq(d, INTC_MASK);
> > +	irq_chip_unmask_parent(d);
> > +
> 	}
> > +
> > +static void mtk_intc_eoi_irq(struct irq_data *d)
> 	> +{
> > +	mtk_poke_irq(d, INTC_EOI);
> > +	irq_chip_eoi_parent(d);
> > +
> 	}
> > +
> > +static struct irq_chip mtk_intc_chip = {
> > +	.irq_mask		= mtk_intc_mask_irq,
> > +	.irq_unmask		= mtk_intc_unmask_irq,
> > +	.irq_eoi		= mtk_intc_eoi_irq,
> > +	.irq_get_irqchip_state	= irq_chip_get_parent_state,
> > +	.irq_set_irqchip_state	= irq_chip_set_parent_state,
> > +	.irq_set_affinity	= irq_chip_set_affinity_parent,
> > +	.irq_set_vcpu_affinity	= irq_chip_set_vcpu_affinity_parent,
> 
> How about retrigger?
> 

What is retrigger means?
To be honest, I just try to direct all the irqchip ops implemented in 
/drivers/irqchip/irq-gic.c to gic driver.
But "irq_set_vcpu_affinity" is not used in our projects now.
Should I remove ".irq_set_vcpu_affinity" here?

> > +	.irq_set_type		= irq_chip_set_type_parent,
> > +	.flags			= IRQCHIP_SET_TYPE_MASKED |
> > +				  IRQCHIP_SKIP_SET_WAKE |
> > +				  IRQCHIP_MASK_ON_SUSPEND,
> > +
> };
> > +
> > +static int mt58xx_intc_domain_translate(struct irq_domain *d,
> > +					struct irq_fwspec *fwspec,
> > +					unsigned long *hwirq,
> > +					unsigned int *type)
> 	> +{
> 		> +	if (is_of_node(fwspec->fwnode)) {
> > +		if (fwspec->param_count != 3)
> > +			return -EINVAL;
> > +
> > +		/* No PPI should point to this domain */
> > +		if (fwspec->param[0] != 0)
> > +			return -EINVAL;
> > +
> > +		*hwirq = fwspec->param[1];
> > +		*type = fwspec->param[2] & IRQ_TYPE_SENSE_MASK;
> > +		return 0;
> > +	
> 		}
> > +
> > +	return -EINVAL;
> > +
> 	}
> > +
> > +static int mt58xx_intc_domain_alloc(struct irq_domain *domain,
> > unsigned int virq,
> > +				    unsigned int nr_irqs, void *data)
> 	> +{
> > +	int i;
> > +	irq_hw_number_t hwirq;
> > +	struct irq_fwspec parent_fwspec, *fwspec = data;
> > +	struct mtk_intc_chip_data *cd = (struct mtk_intc_chip_data
> > *)domain->host_data;
> > +
> > +	/* Not GIC compliant */
> > +	if (fwspec->param_count != 3)
> > +		return -EINVAL;
> > +
> > +	/* No PPI should point to this domain */
> > +	if (fwspec->param[0])
> > +		return -EINVAL;
> > +
> > +	if (fwspec->param[1] >= cd->nr_irqs)
> > +		return -EINVAL;
> > +
> > +	hwirq = fwspec->param[1];
> > +	for (i = 0; i < nr_irqs; i++)
> > +		irq_domain_set_hwirq_and_chip(domain, virq + i, hwirq + i,
> > +					      &cd->chip,
> > +					      domain->host_data);
> > +
> > +	parent_fwspec = *fwspec;
> > +	parent_fwspec.fwnode = domain->parent->fwnode;
> > +	parent_fwspec.param[1] = cd->irq_start + hwirq;
> > +	return irq_domain_alloc_irqs_parent(domain, virq, nr_irqs, 
> > &parent_fwspec);
> > +
> 	}
> > +
> > +static const struct irq_domain_ops mt58xx_intc_domain_ops = {
> > +	.translate	= mt58xx_intc_domain_translate,
> > +	.alloc		= mt58xx_intc_domain_alloc,
> > +	.free		= irq_domain_free_irqs_common,
> > +
> };
> > +
> > +int __init
> > +mt58xx_intc_of_init(struct device_node *dn, struct device_node 
> > *parent)
> > +{
> > +	static int nr_intc;
> > +	struct irq_domain *domain, *domain_parent;
> > +	struct mtk_intc_chip_data *cd;
> > +	unsigned int irq_start, irq_end;
> > +
> > +	domain_parent = irq_find_host(parent);
> > +	if (!domain_parent) {
> > +		pr_err("mt58xx-intc: interrupt-parent not found\n");
> > +		return -EINVAL;
> > +	
> }
> > +
> > +	cd = kzalloc(sizeof(*cd), GFP_KERNEL);
> > +	if (!cd)
> > +		return -ENOMEM;
> > +
> > +	cd->chip = mtk_intc_chip;
> > +	if (of_property_read_u32_index(dn, "mediatek,irqs-map-range", 0,
> > &irq_start) ||
> > +	    of_property_read_u32_index(dn, "mediatek,irqs-map-range", 1, 
> 	> &irq_end)) {
> > +		kfree(cd);
> > +		return -EINVAL;
> > +	
> }
> > +
> > +	if (of_property_read_bool(dn, "mediatek,intc-no-eoi"))
> > +		cd->chip.irq_eoi = irq_chip_eoi_parent;
> 
> No. Just add a flag to your chip data structure, and check for this
> flag in your irq_eoi callback. Or provide two distinct irq_chip
> structures that will only differ by the irq_eoi method.

Thanks for the comment, I will modify it in patch v2.

> 
> > +
> > +	cd->irq_start = irq_start;
> > +	cd->nr_irqs = irq_end - irq_start + 1;
> > +	cd->chip.name = kasprintf(GFP_KERNEL, "mt58xx-intc-%d", nr_intc++);
> 
> Neither. That's not useful, and is a waste of memory. Stick to constant
> names in the irq_chip structure.
> 

Actually we have multiple irq controller in our SoCs.
And if we use the constant names in irq_chip structure, the information in
"/proc/interrupts" will be hard to understand because all the irqchip name
is the same.
Do you have any suggestion for this?

> > +	if (!cd->chip.name) {
> > +		kfree(cd);
> > +		return -ENOMEM;
> > +	
> }
> > +
> > +	cd->base = of_iomap(dn, 0);
> > +	if (!cd->base) {
> > +		kfree(cd->chip.name);
> > +		kfree(cd);
> > +		return -ENOMEM;
> > +	
> }
> > +
> > +	domain = irq_domain_add_hierarchy(domain_parent, 0, cd->nr_irqs,
> > +					  dn, &mt58xx_intc_domain_ops, cd);
> > +	if (!domain) {
> > +		kfree(cd->chip.name);
> > +		iounmap(cd->base);
> > +		kfree(cd);
> > +		return -ENOMEM;
> > +	
> }
> > +
> > +	return 0;
> > +
> }
> > +
> > +IRQCHIP_DECLARE(mt58xx_intc, "mediatek,mt58xx-intc", 
> > mt58xx_intc_of_init);
> 
> On a side note, the merge window has just opened. Please refrain from
> reposting this until -rc1.

Got it, and thanks for your comments.
I'll update the patch and post it after -rc1.
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

WARNING: multiple messages have this Message-ID (diff)
From: Marc Zyngier <maz@kernel.org>
To: Mark-PK Tsai <mark-pk.tsai@mediatek.com>
Cc: yj.chiang@mediatek.com, alix.wu@mediatek.com, tglx@linutronix.de,
	jason@lakedaemon.net, robh+dt@kernel.org, matthias.bgg@gmail.com,
	linux-kernel@vger.kernel.org, devicetree@vger.kernel.org,
	linux-arm-kernel@lists.infradead.org,
	linux-mediatek@lists.infradead.org
Subject: Re: [PATCH 1/2] irqchip: irq-mt58xx: Add mt58xx interrupt controller support
Date: Mon, 03 Aug 2020 09:04:39 +0100	[thread overview]
Message-ID: <43f5cba1199f89cde68c8a577103f28b@kernel.org> (raw)
In-Reply-To: <20200803062214.24076-2-mark-pk.tsai@mediatek.com>

On 2020-08-03 07:22, Mark-PK Tsai wrote:
> Add mt58xx interrupt controller support using hierarchy irq
> domain.
> 
> Signed-off-by: Mark-PK Tsai <mark-pk.tsai@mediatek.com>
> ---
>  drivers/irqchip/Kconfig      |   7 ++
>  drivers/irqchip/Makefile     |   1 +
>  drivers/irqchip/irq-mt58xx.c | 196 +++++++++++++++++++++++++++++++++++
>  3 files changed, 204 insertions(+)
>  create mode 100644 drivers/irqchip/irq-mt58xx.c
> 
> diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig
> index 216b3b8392b5..00453af78be0 100644
> --- a/drivers/irqchip/Kconfig
> +++ b/drivers/irqchip/Kconfig
> @@ -572,4 +572,11 @@ config LOONGSON_PCH_MSI
>  	help
>  	  Support for the Loongson PCH MSI Controller.
> 
> +config MT58XX_IRQ
> +	bool "MT58XX IRQ"
> +	select IRQ_DOMAIN
> +	select IRQ_DOMAIN_HIERARCHY
> +	help
> +	  Support Mediatek MT58XX Interrupt Controller.
> +
>  endmenu
> diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile
> index 133f9c45744a..5062e9bfa92d 100644
> --- a/drivers/irqchip/Makefile
> +++ b/drivers/irqchip/Makefile
> @@ -111,3 +111,4 @@ obj-$(CONFIG_LOONGSON_HTPIC)		+= 
> irq-loongson-htpic.o
>  obj-$(CONFIG_LOONGSON_HTVEC)		+= irq-loongson-htvec.o
>  obj-$(CONFIG_LOONGSON_PCH_PIC)		+= irq-loongson-pch-pic.o
>  obj-$(CONFIG_LOONGSON_PCH_MSI)		+= irq-loongson-pch-msi.o
> +obj-$(CONFIG_MT58XX_IRQ)		+= irq-mt58xx.o
> diff --git a/drivers/irqchip/irq-mt58xx.c 
> b/drivers/irqchip/irq-mt58xx.c
> new file mode 100644
> index 000000000000..e45ad023afa6
> --- /dev/null
> +++ b/drivers/irqchip/irq-mt58xx.c
> @@ -0,0 +1,196 @@
> +// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
> +/*
> + * Copyright (c) 2020 MediaTek Inc.
> + * Author Mark-PK Tsai <mark-pk.tsai@mediatek.com>
> + */
> +
> +#include <linux/interrupt.h>
> +#include <linux/io.h>
> +#include <linux/irq.h>
> +#include <linux/irqchip.h>
> +#include <linux/irqdomain.h>
> +#include <linux/of.h>
> +#include <linux/of_address.h>
> +#include <linux/of_irq.h>
> +#include <linux/slab.h>
> +
> +#define INTC_MASK	0x0
> +#define INTC_EOI	0x20
> +
> +struct mtk_intc_chip_data {
> +	char *name;
> +	struct irq_chip chip;

There is no need to embed a full struct irqchip per controller, see 
below.

> +	unsigned int irq_start, nr_irqs;
> +	void __iomem *base;
> +};
> +
> +static void mtk_poke_irq(struct irq_data *d, u32 offset)
> +{
> +	struct mtk_intc_chip_data *cd = irq_data_get_irq_chip_data(d);
> +	void __iomem *base = cd->base;
> +	u8 index = (u8)irqd_to_hwirq(d);

Why the restrictive type? Why isn't unsigned int good enough?

> +	u16 val, mask;
> +
> +	mask = 1 << (index % 16);
> +	val = readw_relaxed(base + offset + (index / 16) * 4) | mask;
> +	writew_relaxed(val, base + offset + (index / 16) * 4);

RMW without locking, you will end-up with corruption.
Please store the address calculation in a temporaty variable to make it
more readable

> +}
> +
> +static void mtk_clear_irq(struct irq_data *d, u32 offset)
> +{
> +	struct mtk_intc_chip_data *cd = irq_data_get_irq_chip_data(d);
> +	void __iomem *base = cd->base;
> +	u8 index = (u8)irqd_to_hwirq(d);
> +	u16 val, mask;
> +
> +	mask = 1 << (index % 16);
> +	val = readw_relaxed(base + offset + (index / 16) * 4) & ~mask;
> +	writew_relaxed(val, base + offset + (index / 16) * 4);

Same comments.

> +}
> +
> +static void mtk_intc_mask_irq(struct irq_data *d)
> +{
> +	mtk_poke_irq(d, INTC_MASK);
> +	irq_chip_mask_parent(d);
> +}
> +
> +static void mtk_intc_unmask_irq(struct irq_data *d)
> +{
> +	mtk_clear_irq(d, INTC_MASK);
> +	irq_chip_unmask_parent(d);
> +}
> +
> +static void mtk_intc_eoi_irq(struct irq_data *d)
> +{
> +	mtk_poke_irq(d, INTC_EOI);
> +	irq_chip_eoi_parent(d);
> +}
> +
> +static struct irq_chip mtk_intc_chip = {
> +	.irq_mask		= mtk_intc_mask_irq,
> +	.irq_unmask		= mtk_intc_unmask_irq,
> +	.irq_eoi		= mtk_intc_eoi_irq,
> +	.irq_get_irqchip_state	= irq_chip_get_parent_state,
> +	.irq_set_irqchip_state	= irq_chip_set_parent_state,
> +	.irq_set_affinity	= irq_chip_set_affinity_parent,
> +	.irq_set_vcpu_affinity	= irq_chip_set_vcpu_affinity_parent,

How about retrigger?

> +	.irq_set_type		= irq_chip_set_type_parent,
> +	.flags			= IRQCHIP_SET_TYPE_MASKED |
> +				  IRQCHIP_SKIP_SET_WAKE |
> +				  IRQCHIP_MASK_ON_SUSPEND,
> +};
> +
> +static int mt58xx_intc_domain_translate(struct irq_domain *d,
> +					struct irq_fwspec *fwspec,
> +					unsigned long *hwirq,
> +					unsigned int *type)
> +{
> +	if (is_of_node(fwspec->fwnode)) {
> +		if (fwspec->param_count != 3)
> +			return -EINVAL;
> +
> +		/* No PPI should point to this domain */
> +		if (fwspec->param[0] != 0)
> +			return -EINVAL;
> +
> +		*hwirq = fwspec->param[1];
> +		*type = fwspec->param[2] & IRQ_TYPE_SENSE_MASK;
> +		return 0;
> +	}
> +
> +	return -EINVAL;
> +}
> +
> +static int mt58xx_intc_domain_alloc(struct irq_domain *domain,
> unsigned int virq,
> +				    unsigned int nr_irqs, void *data)
> +{
> +	int i;
> +	irq_hw_number_t hwirq;
> +	struct irq_fwspec parent_fwspec, *fwspec = data;
> +	struct mtk_intc_chip_data *cd = (struct mtk_intc_chip_data
> *)domain->host_data;
> +
> +	/* Not GIC compliant */
> +	if (fwspec->param_count != 3)
> +		return -EINVAL;
> +
> +	/* No PPI should point to this domain */
> +	if (fwspec->param[0])
> +		return -EINVAL;
> +
> +	if (fwspec->param[1] >= cd->nr_irqs)
> +		return -EINVAL;
> +
> +	hwirq = fwspec->param[1];
> +	for (i = 0; i < nr_irqs; i++)
> +		irq_domain_set_hwirq_and_chip(domain, virq + i, hwirq + i,
> +					      &cd->chip,
> +					      domain->host_data);
> +
> +	parent_fwspec = *fwspec;
> +	parent_fwspec.fwnode = domain->parent->fwnode;
> +	parent_fwspec.param[1] = cd->irq_start + hwirq;
> +	return irq_domain_alloc_irqs_parent(domain, virq, nr_irqs, 
> &parent_fwspec);
> +}
> +
> +static const struct irq_domain_ops mt58xx_intc_domain_ops = {
> +	.translate	= mt58xx_intc_domain_translate,
> +	.alloc		= mt58xx_intc_domain_alloc,
> +	.free		= irq_domain_free_irqs_common,
> +};
> +
> +int __init
> +mt58xx_intc_of_init(struct device_node *dn, struct device_node 
> *parent)
> +{
> +	static int nr_intc;
> +	struct irq_domain *domain, *domain_parent;
> +	struct mtk_intc_chip_data *cd;
> +	unsigned int irq_start, irq_end;
> +
> +	domain_parent = irq_find_host(parent);
> +	if (!domain_parent) {
> +		pr_err("mt58xx-intc: interrupt-parent not found\n");
> +		return -EINVAL;
> +	}
> +
> +	cd = kzalloc(sizeof(*cd), GFP_KERNEL);
> +	if (!cd)
> +		return -ENOMEM;
> +
> +	cd->chip = mtk_intc_chip;
> +	if (of_property_read_u32_index(dn, "mediatek,irqs-map-range", 0,
> &irq_start) ||
> +	    of_property_read_u32_index(dn, "mediatek,irqs-map-range", 1, 
> &irq_end)) {
> +		kfree(cd);
> +		return -EINVAL;
> +	}
> +
> +	if (of_property_read_bool(dn, "mediatek,intc-no-eoi"))
> +		cd->chip.irq_eoi = irq_chip_eoi_parent;

No. Just add a flag to your chip data structure, and check for this
flag in your irq_eoi callback. Or provide two distinct irq_chip
structures that will only differ by the irq_eoi method.

> +
> +	cd->irq_start = irq_start;
> +	cd->nr_irqs = irq_end - irq_start + 1;
> +	cd->chip.name = kasprintf(GFP_KERNEL, "mt58xx-intc-%d", nr_intc++);

Neither. That's not useful, and is a waste of memory. Stick to constant
names in the irq_chip structure.

> +	if (!cd->chip.name) {
> +		kfree(cd);
> +		return -ENOMEM;
> +	}
> +
> +	cd->base = of_iomap(dn, 0);
> +	if (!cd->base) {
> +		kfree(cd->chip.name);
> +		kfree(cd);
> +		return -ENOMEM;
> +	}
> +
> +	domain = irq_domain_add_hierarchy(domain_parent, 0, cd->nr_irqs,
> +					  dn, &mt58xx_intc_domain_ops, cd);
> +	if (!domain) {
> +		kfree(cd->chip.name);
> +		iounmap(cd->base);
> +		kfree(cd);
> +		return -ENOMEM;
> +	}
> +
> +	return 0;
> +}
> +
> +IRQCHIP_DECLARE(mt58xx_intc, "mediatek,mt58xx-intc", 
> mt58xx_intc_of_init);

On a side note, the merge window has just opened. Please refrain from
reposting this until -rc1.

Thanks,

         M.
-- 
Jazz is not dead. It just smells funny...

WARNING: multiple messages have this Message-ID (diff)
From: Mark-PK Tsai <mark-pk.tsai@mediatek.com>
To: <maz@kernel.org>, Mark-PK Tsai <mark-pk.tsai@mediatek.com>
Cc: <alix.wu@mediatek.com>, <devicetree@vger.kernel.org>,
	<jason@lakedaemon.net>, <linux-arm-kernel@lists.infradead.org>,
	<linux-kernel@vger.kernel.org>,
	<linux-mediatek@lists.infradead.org>, <matthias.bgg@gmail.com>,
	<robh+dt@kernel.org>, <tglx@linutronix.de>,
	<yj.chiang@mediatek.com>
Subject: Re: [PATCH 1/2] irqchip: irq-mt58xx: Add mt58xx interrupt controller support
Date: Mon, 3 Aug 2020 23:03:37 +0800	[thread overview]
Message-ID: <43f5cba1199f89cde68c8a577103f28b@kernel.org> (raw) (raw)
Message-ID: <20200803150337.LfNGVJsb6p_3Qo8dTAwAYPxi5GUxl9MEQXSYxEfvo8Q@z> (raw)
In-Reply-To: <20200803062214.24076-2-mark-pk.tsai@mediatek.com>

From: Marc Zyngier <maz@kernel.org>

> On 2020-08-03 07:22, Mark-PK Tsai wrote:
> > Add mt58xx interrupt controller support using hierarchy irq
> > domain.
> > 
> > Signed-off-by: Mark-PK Tsai <mark-pk.tsai@mediatek.com>
> > ---
> >  drivers/irqchip/Kconfig      |   7 ++
> >  drivers/irqchip/Makefile     |   1 +
> >  drivers/irqchip/irq-mt58xx.c | 196 +++++++++++++++++++++++++++++++++++
> >  3 files changed, 204 insertions(+)
> >  create mode 100644 drivers/irqchip/irq-mt58xx.c
> > 
> > diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig
> > index 216b3b8392b5..00453af78be0 100644
> > --- a/drivers/irqchip/Kconfig
> > +++ b/drivers/irqchip/Kconfig
> > @@ -572,4 +572,11 @@ config LOONGSON_PCH_MSI
> >  	help
> >  	  Support for the Loongson PCH MSI Controller.
> > 
> > +config MT58XX_IRQ
> > +	bool "MT58XX IRQ"
> > +	select IRQ_DOMAIN
> > +	select IRQ_DOMAIN_HIERARCHY
> > +	help
> > +	  Support Mediatek MT58XX Interrupt Controller.
> > +
> >  endmenu
> > diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile
> > index 133f9c45744a..5062e9bfa92d 100644
> > --- a/drivers/irqchip/Makefile
> > +++ b/drivers/irqchip/Makefile
> > @@ -111,3 +111,4 @@ obj-$(CONFIG_LOONGSON_HTPIC)		+= 
> > irq-loongson-htpic.o
> >  obj-$(CONFIG_LOONGSON_HTVEC)		+= irq-loongson-htvec.o
> >  obj-$(CONFIG_LOONGSON_PCH_PIC)		+= irq-loongson-pch-pic.o
> >  obj-$(CONFIG_LOONGSON_PCH_MSI)		+= irq-loongson-pch-msi.o
> > +obj-$(CONFIG_MT58XX_IRQ)		+= irq-mt58xx.o
> > diff --git a/drivers/irqchip/irq-mt58xx.c 
> > b/drivers/irqchip/irq-mt58xx.c
> > new file mode 100644
> > index 000000000000..e45ad023afa6
> > --- /dev/null
> > +++ b/drivers/irqchip/irq-mt58xx.c
> > @@ -0,0 +1,196 @@
> > +// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
> > +/*
> > + * Copyright (c) 2020 MediaTek Inc.
> > + * Author Mark-PK Tsai <mark-pk.tsai@mediatek.com>
> > + */
> > +
> > +#include <linux/interrupt.h>
> > +#include <linux/io.h>
> > +#include <linux/irq.h>
> > +#include <linux/irqchip.h>
> > +#include <linux/irqdomain.h>
> > +#include <linux/of.h>
> > +#include <linux/of_address.h>
> > +#include <linux/of_irq.h>
> > +#include <linux/slab.h>
> > +
> > +#define INTC_MASK	0x0
> > +#define INTC_EOI	0x20
> > +
> > +struct mtk_intc_chip_data {
> > +	char *name;
> > +	struct irq_chip chip;
> 
> There is no need to embed a full struct irqchip per controller, see 
> below.

We want to distinguish which controller the device interrupts are belong to
by "cat /proc/interrupts".
And if all the controller share the same struct, the name field will be the
same.
Do you have suggestion for this?

> 
> > +	unsigned int irq_start, nr_irqs;
> > +	void __iomem *base;
> > +
> };
> > +
> > +static void mtk_poke_irq(struct irq_data *d, u32 offset)
> 	> +{
> > +	struct mtk_intc_chip_data *cd = irq_data_get_irq_chip_data(d);
> > +	void __iomem *base = cd->base;
> > +	u8 index = (u8)irqd_to_hwirq(d);
> 
> Why the restrictive type? Why isn't unsigned int good enough?

You're right, unsigned int is ok.
I'll fix it in patch v2.

> 
> > +	u16 val, mask;
> > +
> > +	mask = 1 << (index % 16);
> > +	val = readw_relaxed(base + offset + (index / 16) * 4) | mask;
> > +	writew_relaxed(val, base + offset + (index / 16) * 4);
> 
> RMW without locking, you will end-up with corruption.
> Please store the address calculation in a temporaty variable to make it
> more readable
> 

Thanks for the comment, I will fix it in pacth v2.

> > +
> 	}
> > +
> > +static void mtk_clear_irq(struct irq_data *d, u32 offset)
> 	> +{
> > +	struct mtk_intc_chip_data *cd = irq_data_get_irq_chip_data(d);
> > +	void __iomem *base = cd->base;
> > +	u8 index = (u8)irqd_to_hwirq(d);
> > +	u16 val, mask;
> > +
> > +	mask = 1 << (index % 16);
> > +	val = readw_relaxed(base + offset + (index / 16) * 4) & ~mask;
> > +	writew_relaxed(val, base + offset + (index / 16) * 4);
> 
> Same comments.
> 

You're right, unsigned int is ok.
I'll fix it in patch v2.

> > +
> 	}
> > +
> > +static void mtk_intc_mask_irq(struct irq_data *d)
> 	> +{
> > +	mtk_poke_irq(d, INTC_MASK);
> > +	irq_chip_mask_parent(d);
> > +
> 	}
> > +
> > +static void mtk_intc_unmask_irq(struct irq_data *d)
> 	> +{
> > +	mtk_clear_irq(d, INTC_MASK);
> > +	irq_chip_unmask_parent(d);
> > +
> 	}
> > +
> > +static void mtk_intc_eoi_irq(struct irq_data *d)
> 	> +{
> > +	mtk_poke_irq(d, INTC_EOI);
> > +	irq_chip_eoi_parent(d);
> > +
> 	}
> > +
> > +static struct irq_chip mtk_intc_chip = {
> > +	.irq_mask		= mtk_intc_mask_irq,
> > +	.irq_unmask		= mtk_intc_unmask_irq,
> > +	.irq_eoi		= mtk_intc_eoi_irq,
> > +	.irq_get_irqchip_state	= irq_chip_get_parent_state,
> > +	.irq_set_irqchip_state	= irq_chip_set_parent_state,
> > +	.irq_set_affinity	= irq_chip_set_affinity_parent,
> > +	.irq_set_vcpu_affinity	= irq_chip_set_vcpu_affinity_parent,
> 
> How about retrigger?
> 

What is retrigger means?
To be honest, I just try to direct all the irqchip ops implemented in 
/drivers/irqchip/irq-gic.c to gic driver.
But "irq_set_vcpu_affinity" is not used in our projects now.
Should I remove ".irq_set_vcpu_affinity" here?

> > +	.irq_set_type		= irq_chip_set_type_parent,
> > +	.flags			= IRQCHIP_SET_TYPE_MASKED |
> > +				  IRQCHIP_SKIP_SET_WAKE |
> > +				  IRQCHIP_MASK_ON_SUSPEND,
> > +
> };
> > +
> > +static int mt58xx_intc_domain_translate(struct irq_domain *d,
> > +					struct irq_fwspec *fwspec,
> > +					unsigned long *hwirq,
> > +					unsigned int *type)
> 	> +{
> 		> +	if (is_of_node(fwspec->fwnode)) {
> > +		if (fwspec->param_count != 3)
> > +			return -EINVAL;
> > +
> > +		/* No PPI should point to this domain */
> > +		if (fwspec->param[0] != 0)
> > +			return -EINVAL;
> > +
> > +		*hwirq = fwspec->param[1];
> > +		*type = fwspec->param[2] & IRQ_TYPE_SENSE_MASK;
> > +		return 0;
> > +	
> 		}
> > +
> > +	return -EINVAL;
> > +
> 	}
> > +
> > +static int mt58xx_intc_domain_alloc(struct irq_domain *domain,
> > unsigned int virq,
> > +				    unsigned int nr_irqs, void *data)
> 	> +{
> > +	int i;
> > +	irq_hw_number_t hwirq;
> > +	struct irq_fwspec parent_fwspec, *fwspec = data;
> > +	struct mtk_intc_chip_data *cd = (struct mtk_intc_chip_data
> > *)domain->host_data;
> > +
> > +	/* Not GIC compliant */
> > +	if (fwspec->param_count != 3)
> > +		return -EINVAL;
> > +
> > +	/* No PPI should point to this domain */
> > +	if (fwspec->param[0])
> > +		return -EINVAL;
> > +
> > +	if (fwspec->param[1] >= cd->nr_irqs)
> > +		return -EINVAL;
> > +
> > +	hwirq = fwspec->param[1];
> > +	for (i = 0; i < nr_irqs; i++)
> > +		irq_domain_set_hwirq_and_chip(domain, virq + i, hwirq + i,
> > +					      &cd->chip,
> > +					      domain->host_data);
> > +
> > +	parent_fwspec = *fwspec;
> > +	parent_fwspec.fwnode = domain->parent->fwnode;
> > +	parent_fwspec.param[1] = cd->irq_start + hwirq;
> > +	return irq_domain_alloc_irqs_parent(domain, virq, nr_irqs, 
> > &parent_fwspec);
> > +
> 	}
> > +
> > +static const struct irq_domain_ops mt58xx_intc_domain_ops = {
> > +	.translate	= mt58xx_intc_domain_translate,
> > +	.alloc		= mt58xx_intc_domain_alloc,
> > +	.free		= irq_domain_free_irqs_common,
> > +
> };
> > +
> > +int __init
> > +mt58xx_intc_of_init(struct device_node *dn, struct device_node 
> > *parent)
> > +{
> > +	static int nr_intc;
> > +	struct irq_domain *domain, *domain_parent;
> > +	struct mtk_intc_chip_data *cd;
> > +	unsigned int irq_start, irq_end;
> > +
> > +	domain_parent = irq_find_host(parent);
> > +	if (!domain_parent) {
> > +		pr_err("mt58xx-intc: interrupt-parent not found\n");
> > +		return -EINVAL;
> > +	
> }
> > +
> > +	cd = kzalloc(sizeof(*cd), GFP_KERNEL);
> > +	if (!cd)
> > +		return -ENOMEM;
> > +
> > +	cd->chip = mtk_intc_chip;
> > +	if (of_property_read_u32_index(dn, "mediatek,irqs-map-range", 0,
> > &irq_start) ||
> > +	    of_property_read_u32_index(dn, "mediatek,irqs-map-range", 1, 
> 	> &irq_end)) {
> > +		kfree(cd);
> > +		return -EINVAL;
> > +	
> }
> > +
> > +	if (of_property_read_bool(dn, "mediatek,intc-no-eoi"))
> > +		cd->chip.irq_eoi = irq_chip_eoi_parent;
> 
> No. Just add a flag to your chip data structure, and check for this
> flag in your irq_eoi callback. Or provide two distinct irq_chip
> structures that will only differ by the irq_eoi method.

Thanks for the comment, I will modify it in patch v2.

> 
> > +
> > +	cd->irq_start = irq_start;
> > +	cd->nr_irqs = irq_end - irq_start + 1;
> > +	cd->chip.name = kasprintf(GFP_KERNEL, "mt58xx-intc-%d", nr_intc++);
> 
> Neither. That's not useful, and is a waste of memory. Stick to constant
> names in the irq_chip structure.
> 

Actually we have multiple irq controller in our SoCs.
And if we use the constant names in irq_chip structure, the information in
"/proc/interrupts" will be hard to understand because all the irqchip name
is the same.
Do you have any suggestion for this?

> > +	if (!cd->chip.name) {
> > +		kfree(cd);
> > +		return -ENOMEM;
> > +	
> }
> > +
> > +	cd->base = of_iomap(dn, 0);
> > +	if (!cd->base) {
> > +		kfree(cd->chip.name);
> > +		kfree(cd);
> > +		return -ENOMEM;
> > +	
> }
> > +
> > +	domain = irq_domain_add_hierarchy(domain_parent, 0, cd->nr_irqs,
> > +					  dn, &mt58xx_intc_domain_ops, cd);
> > +	if (!domain) {
> > +		kfree(cd->chip.name);
> > +		iounmap(cd->base);
> > +		kfree(cd);
> > +		return -ENOMEM;
> > +	
> }
> > +
> > +	return 0;
> > +
> }
> > +
> > +IRQCHIP_DECLARE(mt58xx_intc, "mediatek,mt58xx-intc", 
> > mt58xx_intc_of_init);
> 
> On a side note, the merge window has just opened. Please refrain from
> reposting this until -rc1.

Got it, and thanks for your comments.
I'll update the patch and post it after -rc1.

  reply	other threads:[~2020-08-03  8:04 UTC|newest]

Thread overview: 36+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-08-03  6:22 [PATCH 0/2] irqchip: irq-mt58xx: Add mt58xx series interrupt Mark-PK Tsai
2020-08-03  6:22 ` Mark-PK Tsai
2020-08-03  6:22 ` Mark-PK Tsai
2020-08-03  6:22 ` [PATCH 1/2] irqchip: irq-mt58xx: Add mt58xx interrupt controller support Mark-PK Tsai
2020-08-03  6:22   ` Mark-PK Tsai
2020-08-03  6:22   ` Mark-PK Tsai
2020-08-03  8:04   ` Marc Zyngier [this message]
2020-08-03 15:03     ` Mark-PK Tsai
2020-08-03 15:03     ` Mark-PK Tsai
2020-08-03 15:03     ` Mark-PK Tsai
2020-08-03  8:04     ` Marc Zyngier
2020-08-03  8:04     ` Marc Zyngier
2020-08-03 15:52     ` Marc Zyngier
2020-08-03 15:52       ` Marc Zyngier
2020-08-03 15:52       ` Marc Zyngier
2020-08-03  6:22 ` [PATCH 2/2] dt-bindings: interrupt-controller: Add MT58XX interrupt controller Mark-PK Tsai
2020-08-03  6:22   ` Mark-PK Tsai
2020-08-03  6:22   ` Mark-PK Tsai
2020-08-03 21:47   ` Rob Herring
2020-08-03 21:47     ` Rob Herring
2020-08-03 21:47     ` Rob Herring
2020-08-06 10:12 ` [PATCH 0/2] irqchip: irq-mt58xx: Add mt58xx series interrupt Daniel Palmer
2020-08-06 10:12   ` Daniel Palmer
2020-08-06 10:12   ` Daniel Palmer
2020-08-06 14:07   ` Mark-PK Tsai
2020-08-06 14:07     ` Mark-PK Tsai
2020-08-06 14:07     ` Mark-PK Tsai
2020-08-06 14:58     ` Daniel Palmer
2020-08-06 14:58       ` Daniel Palmer
2020-08-06 14:58       ` Daniel Palmer
2020-08-06 15:12       ` Marc Zyngier
2020-08-06 15:12         ` Marc Zyngier
2020-08-06 15:12         ` Marc Zyngier
2020-08-07 12:52         ` Mark-PK Tsai
2020-08-07 12:52           ` Mark-PK Tsai
2020-08-07 12:52           ` Mark-PK Tsai

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=43f5cba1199f89cde68c8a577103f28b@kernel.org \
    --to=maz@kernel.org \
    --cc=alix.wu@mediatek.com \
    --cc=devicetree@vger.kernel.org \
    --cc=jason@lakedaemon.net \
    --cc=linux-arm-kernel@lists.infradead.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-mediatek@lists.infradead.org \
    --cc=mark-pk.tsai@mediatek.com \
    --cc=matthias.bgg@gmail.com \
    --cc=robh+dt@kernel.org \
    --cc=tglx@linutronix.de \
    --cc=yj.chiang@mediatek.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.