All of lore.kernel.org
 help / color / mirror / Atom feed
From: Joshua Henderson <joshua.henderson@microchip.com>
To: Thomas Gleixner <tglx@linutronix.de>
Cc: <linux-kernel@vger.kernel.org>, <linux-mips@linux-mips.org>,
	<ralf@linux-mips.org>,
	Cristian Birsan <cristian.birsan@microchip.com>,
	Jason Cooper <jason@lakedaemon.net>,
	Marc Zyngier <marc.zyngier@arm.com>
Subject: Re: [PATCH v3 02/14] irqchip: irq-pic32-evic: Add support for PIC32 interrupt controller
Date: Fri, 8 Jan 2016 15:52:15 -0700	[thread overview]
Message-ID: <56903D9F.3010908@microchip.com> (raw)
In-Reply-To: <alpine.DEB.2.11.1601081931080.3575@nanos>

Thomas,

On 01/08/2016 12:04 PM, Thomas Gleixner wrote:
> On Thu, 7 Jan 2016, Joshua Henderson wrote:
>> +struct pic_reg {
>> +	u32 val; /* value register*/
> 
> Just a nit. If you want to document your data structure, then please use
> KernelDoc. These tail comments are horrible.
> 

Consider it done.

>> +	u32 clr; /* clear register */
>> +	u32 set; /* set register */
>> +	u32 inv; /* inv register */
>> +} __packed;
>> +
>> +struct evic {
>> +	struct pic_reg intcon;
>> +	struct pic_reg priss;
>> +	struct pic_reg intstat;
>> +	struct pic_reg iptmr;
>> +	struct pic_reg ifs[6];
>> +	u32 reserved1[8];
>> +	struct pic_reg iec[6];
>> +	u32 reserved2[8];
>> +	struct pic_reg ipc[48];
>> +	u32 reserved3[64];
>> +	u32 off[191];
> 
> It would be way simpler to parse if you structured it like a table
> 

Ack

> +	struct pic_reg	intcon;
> +	struct pic_reg	priss;
> +	struct pic_reg	intstat;
> +	struct pic_reg	iptmr;
> +	struct pic_reg	ifs[6];
> +	u32		reserved1[8];
> +	struct pic_reg	iec[6];
> +	u32		reserved2[8];
> +	struct pic_reg	ipc[48];
> +	u32		reserved3[64];
> +	u32		off[191];
> 
>> +} __packed;
>> +
>> +static int get_ext_irq_index(irq_hw_number_t hw);
>> +static void evic_set_ext_irq_polarity(int ext_irq, u32 type);
> 
> If you move the functions right here, then you don't need the forward
> declarations.
> 

Ack

>> +/* mask off an interrupt */
>> +static inline void mask_pic32_irq(struct irq_data *irqd)
>> +{
>> +	u32 reg, mask;
>> +	unsigned int hwirq = irqd_to_hwirq(irqd);
>> +
>> +	BIT_REG_MASK(hwirq, reg, mask);
>> +	writel(mask, &evic_base->iec[reg].clr);
>> +}
>> +
>> +/* unmask an interrupt */
>> +static inline void unmask_pic32_irq(struct irq_data *irqd)
>> +{
>> +	u32 reg, mask;
>> +	unsigned int hwirq = irqd_to_hwirq(irqd);
>> +
>> +	BIT_REG_MASK(hwirq, reg, mask);
>> +	writel(mask, &evic_base->iec[reg].set);
>> +}
>> +
>> +/* acknowledge an interrupt */
>> +static void ack_pic32_irq(struct irq_data *irqd)
>> +{
>> +	u32 reg, mask;
>> +	unsigned int hwirq = irqd_to_hwirq(irqd);
>> +
>> +	BIT_REG_MASK(hwirq, reg, mask);
>> +	writel(mask, &evic_base->ifs[reg].clr);
> 
> So you invented an open coded variant of the generic irq chip. Just with the
> difference that the generic chip caches the mask and the register offsets ....
> 

On PIC32 we have 4 different register offsets in many cases, including the interrupt
controller registers, to write to one hardware register.  The PIC32 has special
write only registers for set/clear/invert and which one is used is dependent on
the logic at the time of writel(). Point being, there is no obvious value in
caching when using these registers.  We don't have to perform a readl() at any
time beforehand to write a mask to a register to update it atomically.

>> +}
>> +
>> +static int set_type_pic32_irq(struct irq_data *data, unsigned int flow_type)
>> +{
>> +	int index;
>> +
>> +	switch (flow_type) {
>> +
>> +	case IRQ_TYPE_EDGE_RISING:
>> +	case IRQ_TYPE_EDGE_FALLING:
>> +		irq_set_handler_locked(data, handle_edge_irq);
>> +		break;
>> +
>> +	case IRQ_TYPE_LEVEL_HIGH:
>> +	case IRQ_TYPE_LEVEL_LOW:
>> +		irq_set_handler_locked(data, handle_fasteoi_irq);
>> +		break;
>> +
>> +	default:
>> +		pr_err("Invalid interrupt type !\n");
>> +		return -EINVAL;
>> +	}
>> +
>> +	/* set polarity for external interrupts only */
>> +	index = get_ext_irq_index(data->hwirq);
>> +	if (index >= 0)
>> +		evic_set_ext_irq_polarity(index, flow_type);
> 
> So for the non external interrupts you set a different handler and be
> done. How is that supposed to work? They switch magically from one mode to the
> other?
> 

It's all the same handlers (depending on whether it's persistent or
non-persistent) irrelevant of it being an external interrupt or not.  It's all
the same hardware interrupt controller.  Some pins on the chip can be configured
as an interrupt source through pin configuration and those have dedicated
interrupts associated with them.  The only thing "special" about these external
interrupts is they must be explicitly configured as edge rising or edge falling
in hardware- which is what is being handled here.  Non-external interrupts don't
need this configuration.

>> +static void pic32_bind_evic_interrupt(int irq, int set)
>> +{
>> +	writel(set, &evic_base->off[irq]);
>> +}
>> +
>> +int pic32_get_c0_compare_int(void)
>> +{
>> +	int virq;
>> +
>> +	virq = irq_create_mapping(evic_irq_domain, CORE_TIMER_INTERRUPT);
>> +	irq_set_irq_type(virq, IRQ_TYPE_EDGE_RISING);
>> +	return virq;
> 
> Why isn't that information retrieved via device tree?
> 

I suppose it could be.  We took a lesson from irq-mips-gic.c on this one.

>> +}
>> +
>> +static struct irq_chip pic32_irq_chip = {
>> +	.name = "PIC32-EVIC",
>> +	.irq_ack = ack_pic32_irq,
>> +	.irq_mask = mask_pic32_irq,
>> +	.irq_unmask = unmask_pic32_irq,
>> +	.irq_eoi = ack_pic32_irq,
>> +	.irq_set_type = set_type_pic32_irq,
> 
> Again, this want's to be in tabular form, if at all.
> 

Ack

>> +};
>> +
>> +static void evic_set_irq_priority(int irq, int priority)
>> +{
>> +	u32 reg, shift;
>> +
>> +	reg = irq / 4;
>> +	shift = (irq % 4) * 8;
>> +
>> +	/* set priority */
>> +	writel(INT_MASK << shift, &evic_base->ipc[reg].clr);
>> +	writel(priority << shift, &evic_base->ipc[reg].set);
>> +}
>> +
>> +static void evic_set_ext_irq_polarity(int ext_irq, u32 type)
>> +{
>> +	if (WARN_ON(ext_irq >= NR_EXT_IRQS))
>> +		return;
> 
> That WARN_ON is really helpful because you already made sure not to call it
> for non EXT irqs.
> 

It is indeed redundant.

>> +	switch (type) {
>> +	case IRQ_TYPE_EDGE_RISING:
>> +		writel(1 << ext_irq, &evic_base->intcon.set);
>> +		break;
>> +	case IRQ_TYPE_EDGE_FALLING:
>> +		writel(1 << ext_irq, &evic_base->intcon.clr);
>> +		break;
>> +	default:
>> +		pr_err("Invalid external interrupt polarity !\n");
>> +	}
>> +}
>> +
>> +static int get_ext_irq_index(irq_hw_number_t hw)
>> +{
>> +	switch (hw) {
>> +	case EXTERNAL_INTERRUPT_0:
>> +		return 0;
>> +	case EXTERNAL_INTERRUPT_1:
>> +		return 1;
>> +	case EXTERNAL_INTERRUPT_2:
>> +		return 2;
>> +	case EXTERNAL_INTERRUPT_3:
>> +		return 3;
>> +	case EXTERNAL_INTERRUPT_4:
>> +		return 4;
>> +	default:
>> +		return -1;
>> +	}
>> +}
> 
> Why don't you use a seperate irq chip for the ext irqs? You can do that with
> the generic chip as well.
> 
>     irq_alloc_domain_generic_chips(domain, 32, 2, ....)
> 
> And then you assign the alternate chip (2) to your ext irqs and have the set
> type function only for the alternate chip.
> 

We have one interrupt controller.  All interrupts have a hardware hard-coded
flow type (edge, level) with the exception of what we are calling "external
interrupts".  These are essentially gpio interrupts that can be software
configured as edge rising or edge falling.  Otherwise, there is no difference
between any of the interrupts.  Does setting edge parity for these interrupts
really warrant a new irq domain and irq_chip?

> Thanks,
> 
> 	tglx
> 

Josh

WARNING: multiple messages have this Message-ID (diff)
From: Joshua Henderson <joshua.henderson@microchip.com>
To: Thomas Gleixner <tglx@linutronix.de>
Cc: linux-kernel@vger.kernel.org, linux-mips@linux-mips.org,
	ralf@linux-mips.org,
	Cristian Birsan <cristian.birsan@microchip.com>,
	Jason Cooper <jason@lakedaemon.net>,
	Marc Zyngier <marc.zyngier@arm.com>
Subject: Re: [PATCH v3 02/14] irqchip: irq-pic32-evic: Add support for PIC32 interrupt controller
Date: Fri, 8 Jan 2016 15:52:15 -0700	[thread overview]
Message-ID: <56903D9F.3010908@microchip.com> (raw)
Message-ID: <20160108225215.WWdS9nyYpfiiHtAIfLCHw8DaPHNTBjHta9iygcxvfQM@z> (raw)
In-Reply-To: <alpine.DEB.2.11.1601081931080.3575@nanos>

Thomas,

On 01/08/2016 12:04 PM, Thomas Gleixner wrote:
> On Thu, 7 Jan 2016, Joshua Henderson wrote:
>> +struct pic_reg {
>> +	u32 val; /* value register*/
> 
> Just a nit. If you want to document your data structure, then please use
> KernelDoc. These tail comments are horrible.
> 

Consider it done.

>> +	u32 clr; /* clear register */
>> +	u32 set; /* set register */
>> +	u32 inv; /* inv register */
>> +} __packed;
>> +
>> +struct evic {
>> +	struct pic_reg intcon;
>> +	struct pic_reg priss;
>> +	struct pic_reg intstat;
>> +	struct pic_reg iptmr;
>> +	struct pic_reg ifs[6];
>> +	u32 reserved1[8];
>> +	struct pic_reg iec[6];
>> +	u32 reserved2[8];
>> +	struct pic_reg ipc[48];
>> +	u32 reserved3[64];
>> +	u32 off[191];
> 
> It would be way simpler to parse if you structured it like a table
> 

Ack

> +	struct pic_reg	intcon;
> +	struct pic_reg	priss;
> +	struct pic_reg	intstat;
> +	struct pic_reg	iptmr;
> +	struct pic_reg	ifs[6];
> +	u32		reserved1[8];
> +	struct pic_reg	iec[6];
> +	u32		reserved2[8];
> +	struct pic_reg	ipc[48];
> +	u32		reserved3[64];
> +	u32		off[191];
> 
>> +} __packed;
>> +
>> +static int get_ext_irq_index(irq_hw_number_t hw);
>> +static void evic_set_ext_irq_polarity(int ext_irq, u32 type);
> 
> If you move the functions right here, then you don't need the forward
> declarations.
> 

Ack

>> +/* mask off an interrupt */
>> +static inline void mask_pic32_irq(struct irq_data *irqd)
>> +{
>> +	u32 reg, mask;
>> +	unsigned int hwirq = irqd_to_hwirq(irqd);
>> +
>> +	BIT_REG_MASK(hwirq, reg, mask);
>> +	writel(mask, &evic_base->iec[reg].clr);
>> +}
>> +
>> +/* unmask an interrupt */
>> +static inline void unmask_pic32_irq(struct irq_data *irqd)
>> +{
>> +	u32 reg, mask;
>> +	unsigned int hwirq = irqd_to_hwirq(irqd);
>> +
>> +	BIT_REG_MASK(hwirq, reg, mask);
>> +	writel(mask, &evic_base->iec[reg].set);
>> +}
>> +
>> +/* acknowledge an interrupt */
>> +static void ack_pic32_irq(struct irq_data *irqd)
>> +{
>> +	u32 reg, mask;
>> +	unsigned int hwirq = irqd_to_hwirq(irqd);
>> +
>> +	BIT_REG_MASK(hwirq, reg, mask);
>> +	writel(mask, &evic_base->ifs[reg].clr);
> 
> So you invented an open coded variant of the generic irq chip. Just with the
> difference that the generic chip caches the mask and the register offsets ....
> 

On PIC32 we have 4 different register offsets in many cases, including the interrupt
controller registers, to write to one hardware register.  The PIC32 has special
write only registers for set/clear/invert and which one is used is dependent on
the logic at the time of writel(). Point being, there is no obvious value in
caching when using these registers.  We don't have to perform a readl() at any
time beforehand to write a mask to a register to update it atomically.

>> +}
>> +
>> +static int set_type_pic32_irq(struct irq_data *data, unsigned int flow_type)
>> +{
>> +	int index;
>> +
>> +	switch (flow_type) {
>> +
>> +	case IRQ_TYPE_EDGE_RISING:
>> +	case IRQ_TYPE_EDGE_FALLING:
>> +		irq_set_handler_locked(data, handle_edge_irq);
>> +		break;
>> +
>> +	case IRQ_TYPE_LEVEL_HIGH:
>> +	case IRQ_TYPE_LEVEL_LOW:
>> +		irq_set_handler_locked(data, handle_fasteoi_irq);
>> +		break;
>> +
>> +	default:
>> +		pr_err("Invalid interrupt type !\n");
>> +		return -EINVAL;
>> +	}
>> +
>> +	/* set polarity for external interrupts only */
>> +	index = get_ext_irq_index(data->hwirq);
>> +	if (index >= 0)
>> +		evic_set_ext_irq_polarity(index, flow_type);
> 
> So for the non external interrupts you set a different handler and be
> done. How is that supposed to work? They switch magically from one mode to the
> other?
> 

It's all the same handlers (depending on whether it's persistent or
non-persistent) irrelevant of it being an external interrupt or not.  It's all
the same hardware interrupt controller.  Some pins on the chip can be configured
as an interrupt source through pin configuration and those have dedicated
interrupts associated with them.  The only thing "special" about these external
interrupts is they must be explicitly configured as edge rising or edge falling
in hardware- which is what is being handled here.  Non-external interrupts don't
need this configuration.

>> +static void pic32_bind_evic_interrupt(int irq, int set)
>> +{
>> +	writel(set, &evic_base->off[irq]);
>> +}
>> +
>> +int pic32_get_c0_compare_int(void)
>> +{
>> +	int virq;
>> +
>> +	virq = irq_create_mapping(evic_irq_domain, CORE_TIMER_INTERRUPT);
>> +	irq_set_irq_type(virq, IRQ_TYPE_EDGE_RISING);
>> +	return virq;
> 
> Why isn't that information retrieved via device tree?
> 

I suppose it could be.  We took a lesson from irq-mips-gic.c on this one.

>> +}
>> +
>> +static struct irq_chip pic32_irq_chip = {
>> +	.name = "PIC32-EVIC",
>> +	.irq_ack = ack_pic32_irq,
>> +	.irq_mask = mask_pic32_irq,
>> +	.irq_unmask = unmask_pic32_irq,
>> +	.irq_eoi = ack_pic32_irq,
>> +	.irq_set_type = set_type_pic32_irq,
> 
> Again, this want's to be in tabular form, if at all.
> 

Ack

>> +};
>> +
>> +static void evic_set_irq_priority(int irq, int priority)
>> +{
>> +	u32 reg, shift;
>> +
>> +	reg = irq / 4;
>> +	shift = (irq % 4) * 8;
>> +
>> +	/* set priority */
>> +	writel(INT_MASK << shift, &evic_base->ipc[reg].clr);
>> +	writel(priority << shift, &evic_base->ipc[reg].set);
>> +}
>> +
>> +static void evic_set_ext_irq_polarity(int ext_irq, u32 type)
>> +{
>> +	if (WARN_ON(ext_irq >= NR_EXT_IRQS))
>> +		return;
> 
> That WARN_ON is really helpful because you already made sure not to call it
> for non EXT irqs.
> 

It is indeed redundant.

>> +	switch (type) {
>> +	case IRQ_TYPE_EDGE_RISING:
>> +		writel(1 << ext_irq, &evic_base->intcon.set);
>> +		break;
>> +	case IRQ_TYPE_EDGE_FALLING:
>> +		writel(1 << ext_irq, &evic_base->intcon.clr);
>> +		break;
>> +	default:
>> +		pr_err("Invalid external interrupt polarity !\n");
>> +	}
>> +}
>> +
>> +static int get_ext_irq_index(irq_hw_number_t hw)
>> +{
>> +	switch (hw) {
>> +	case EXTERNAL_INTERRUPT_0:
>> +		return 0;
>> +	case EXTERNAL_INTERRUPT_1:
>> +		return 1;
>> +	case EXTERNAL_INTERRUPT_2:
>> +		return 2;
>> +	case EXTERNAL_INTERRUPT_3:
>> +		return 3;
>> +	case EXTERNAL_INTERRUPT_4:
>> +		return 4;
>> +	default:
>> +		return -1;
>> +	}
>> +}
> 
> Why don't you use a seperate irq chip for the ext irqs? You can do that with
> the generic chip as well.
> 
>     irq_alloc_domain_generic_chips(domain, 32, 2, ....)
> 
> And then you assign the alternate chip (2) to your ext irqs and have the set
> type function only for the alternate chip.
> 

We have one interrupt controller.  All interrupts have a hardware hard-coded
flow type (edge, level) with the exception of what we are calling "external
interrupts".  These are essentially gpio interrupts that can be software
configured as edge rising or edge falling.  Otherwise, there is no difference
between any of the interrupts.  Does setting edge parity for these interrupts
really warrant a new irq domain and irq_chip?

> Thanks,
> 
> 	tglx
> 

Josh

  reply	other threads:[~2016-01-08 22:44 UTC|newest]

Thread overview: 44+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2016-01-08  0:00 [PATCH v3 00/14] Initial Microchip PIC32MZDA Support Joshua Henderson
2016-01-08  0:00 ` Joshua Henderson
2016-01-08  0:00 ` Joshua Henderson
2016-01-08  0:00 ` [PATCH v3 01/14] dt/bindings: Add bindings for PIC32 interrupt controller Joshua Henderson
2016-01-08  0:00   ` Joshua Henderson
2016-01-08  0:00 ` [PATCH v3 02/14] irqchip: irq-pic32-evic: Add support " Joshua Henderson
2016-01-08  0:00   ` Joshua Henderson
2016-01-08 19:04   ` Thomas Gleixner
2016-01-08 22:52     ` Joshua Henderson [this message]
2016-01-08 22:52       ` Joshua Henderson
2016-01-10 10:09       ` Thomas Gleixner
2016-01-12 19:39         ` Joshua Henderson
2016-01-12 19:39           ` Joshua Henderson
2016-01-08  0:00 ` [PATCH v3 03/14] dt/bindings: Add PIC32 clock binding documentation Joshua Henderson
2016-01-08  0:00   ` Joshua Henderson
2016-01-08  0:00 ` [PATCH v3 04/14] clk: clk-pic32: Add PIC32 clock driver Joshua Henderson
2016-01-08  0:00   ` Joshua Henderson
2016-01-08  0:00 ` [PATCH v3 05/14] dt/bindings: Add bindings for PIC32/MZDA platforms Joshua Henderson
2016-01-08  0:00   ` Joshua Henderson
2016-01-08 10:37   ` Antony Pavlov
2016-01-08 10:37     ` Antony Pavlov
2016-01-08 10:37     ` Antony Pavlov
2016-01-09  0:35     ` Joshua Henderson
2016-01-09  0:35       ` Joshua Henderson
2016-01-08  0:00 ` [PATCH v3 06/14] MIPS: Add support for PIC32MZDA platform Joshua Henderson
2016-01-08  0:00   ` Joshua Henderson
2016-01-08  0:00 ` [PATCH v3 07/14] dt/bindings: Add bindings for PIC32 pin control and GPIO Joshua Henderson
2016-01-08  0:00   ` Joshua Henderson
2016-01-08  0:00 ` [PATCH v3 08/14] pinctrl: pinctrl-pic32: Add PIC32 pin control driver Joshua Henderson
2016-01-08  0:00   ` Joshua Henderson
2016-01-08  0:00 ` [PATCH v3 09/14] dt/bindings: Add bindings for PIC32 UART driver Joshua Henderson
2016-01-08  0:00   ` Joshua Henderson
     [not found] ` <1452211389-31025-1-git-send-email-joshua.henderson-UWL1GkI3JZL3oGB3hsPCZA@public.gmane.org>
2016-01-08  0:00   ` [PATCH v3 10/14] serial: pic32_uart: Add " Joshua Henderson
2016-01-08  0:00     ` Joshua Henderson
2016-01-08  0:00     ` Joshua Henderson
2016-01-08  0:00 ` [PATCH v3 11/14] dt/bindings: Add bindings for PIC32 SDHCI host controller Joshua Henderson
2016-01-08  0:00   ` Joshua Henderson
2016-01-08  0:00 ` [PATCH v3 12/14] mmc: sdhci-pic32: Add PIC32 SDHCI host controller driver Joshua Henderson
2016-01-08  0:00   ` Joshua Henderson
2016-01-08  0:00   ` Joshua Henderson
2016-01-08  0:00 ` [PATCH v3 13/14] MIPS: dts: Add initial DTS for the PIC32MZDA Starter Kit Joshua Henderson
2016-01-08  0:00   ` Joshua Henderson
2016-01-08  0:00 ` [PATCH v3 14/14] MIPS: pic32mzda: Add initial PIC32MZDA Starter Kit defconfig Joshua Henderson
2016-01-08  0:00   ` Joshua Henderson

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=56903D9F.3010908@microchip.com \
    --to=joshua.henderson@microchip.com \
    --cc=cristian.birsan@microchip.com \
    --cc=jason@lakedaemon.net \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-mips@linux-mips.org \
    --cc=marc.zyngier@arm.com \
    --cc=ralf@linux-mips.org \
    --cc=tglx@linutronix.de \
    /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.