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: Tue, 12 Jan 2016 12:39:10 -0700 [thread overview]
Message-ID: <5695565E.4050500@microchip.com> (raw)
In-Reply-To: <alpine.DEB.2.11.1601091148480.3575@nanos>
Thomas,
On 01/10/2016 03:09 AM, Thomas Gleixner wrote:
> Joshua,
>
> On Fri, 8 Jan 2016, Joshua Henderson wrote:
>> On 01/08/2016 12:04 PM, Thomas Gleixner wrote:
>>> On Thu, 7 Jan 2016, Joshua Henderson wrote:
>>>> +/* 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.
>
> The generic chip has functions which handle the seperate register case.
>
> void irq_gc_mask_disable_reg(struct irq_data *d);
> void irq_gc_unmask_enable_reg(struct irq_data *d);
> void irq_gc_mask_disable_reg_and_ack(struct irq_data *d);
> void irq_gc_eoi(struct irq_data *d);
>
This makes sense now. Using these is a natural result of moving to using generic chip as suggested below.
>>>> +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.
>
> I really cannot follow here. The code tells me that I can set
> EDGE_RISING/FALLING/LEVEL_HIGH/LOW for any of those interrupts.
>
> So that makes two questions:
>
> 1) Can the non-external mode handle all type variants automagically? I
> seriously doubt that. If the type cannot be set, then it makes no sense
> to pretend that it can and allow to switch the handler from fasteoi to
> edge mode.
>
> 2) The external irqs do not support level according to your
> evic_set_ext_irq_polarity() function. But you return success if set_type
> is called with a level type and gladly switch the handler. You merily
> pr_warn in evic_set_ext_irq_polarity().
>
> That's just crap.
>
Got it. The plan is for .irq_set_type to only exist for edge interrupts, and properly fail if it is not an external interrupt (meaning, there is no actual hardware change otherwise). External interrupts will configured through a custom DT property in the evic node. So, this means all non external interrupts will be "locked" to the DT specified irq type at mapping. This should cleanly address these two issues. Comments will be added to explain this.
>>>> +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.
>
> You copied it, right? That does not make it any better.
>
Typically, this CPU core interrupt number can be read from the CP0 registers. However, the interrupt controller on PIC32 is the interface/arbiter for all interrupts, peripheral and CPU, and therefore we have to specify it. Because this is not a unique scenario for probably various reasons, the arch/mips/kernel/cevt-r4k.c provides get_c0_compare_int() as a __weak symbol which is currently overwritten by ~11 MIPS platforms in the exact same non-DTS way. This is what I meant by saying PIC32 implemented this like irq-mips-gic.c. So, I see 2 options to address this:
1) Move pic32_get_c0_compare_int() to platform code as get_c0_compare_int(). Load a fixed mapping from DT in the irqchip driver and find that mapping with get_c0_compare_int().
2) Add DT support to arch cevt-r4k.c or cpu_probe.c read an arch common property from DT to get the core timer interrupt number.
I think 1) satisfies your feedback on this. Does this make sense?
>>> 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) ...
>
> And that's exactly the point. They are hardcoded, but you still allow any
> random driver to change the type and therefor the handler. How is that
> supposed to work?
>
To clarify, by hardcoded, I mean the hardware peripheral the interrupt controller is arbitrating for has a defined irq type. We specify this in a DT standard way for each peripheral, seeing that it varies by peripheral and there is no rhyme or reason to it in the linear IRQ mapping for > 200 interrupts at the evic level:
uart1: serial@1f822000 {
compatible = "microchip,pic32mzda-uart";
...
interrupts = <112 IRQ_TYPE_LEVEL_HIGH>,
<113 IRQ_TYPE_LEVEL_HIGH>,
<114 IRQ_TYPE_LEVEL_HIGH>;
...
};
PBTIMER1:pbtimer1 {
compatible = "microchip,pic32mzda-timerA";
...
interrupts = <4 IRQ_TYPE_EDGE_RISING>;
...
};
The shortcoming of allowing a change to the flow handler will be addressed. It does make sense as you are suggesting to use different irq chips for the different flow handlers. irq_alloc_domain_generic_chips() will work as suggested and there will be alternate chips for the different scenarios.
>> ... 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.
>
> And again. Here you can change the type, but only edge rising and falling are
> supported. And you still allow setting a level type.
>
This will be addressed.
> So for both types you allow the driver/DT writer to get it wrong. And of
> course this happens without a single line of comment which explains the
> oddities of your driver, so a causual reader will stumble over it and ask
> exactly the questions I'm asking. We want understandable and maintainable code
> and not some 'work for me' hackery.
Make no mistake, I'm here to do this the right way. A new irqchip driver is in the oven.
Thanks,
Josh
next prev parent reply other threads:[~2016-01-12 19:31 UTC|newest]
Thread overview: 21+ 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 ` [PATCH v3 01/14] dt/bindings: Add bindings for PIC32 interrupt controller Joshua Henderson
2016-01-08 0:00 ` [PATCH v3 02/14] irqchip: irq-pic32-evic: Add support " Joshua Henderson
2016-01-08 19:04 ` Thomas Gleixner
2016-01-08 22:52 ` Joshua Henderson
2016-01-10 10:09 ` Thomas Gleixner
2016-01-12 19:39 ` Joshua Henderson [this message]
2016-01-08 0:00 ` [PATCH v3 03/14] dt/bindings: Add PIC32 clock binding documentation 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 ` [PATCH v3 05/14] dt/bindings: Add bindings for PIC32/MZDA platforms Joshua Henderson
2016-01-08 10:37 ` Antony Pavlov
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 ` [PATCH v3 07/14] dt/bindings: Add bindings for PIC32 pin control and GPIO 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 ` [PATCH v3 09/14] dt/bindings: Add bindings for PIC32 UART driver Joshua Henderson
2016-01-08 0:00 ` [PATCH v3 10/14] serial: pic32_uart: Add " 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 ` [PATCH v3 12/14] mmc: sdhci-pic32: Add PIC32 SDHCI host controller driver 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 ` [PATCH v3 14/14] MIPS: pic32mzda: Add initial PIC32MZDA Starter Kit defconfig 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=5695565E.4050500@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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).