Re: [Patch V6 2/6] irqchip: xilinx: Clean up irqdomain argument and read/write
From: Michal Simek
Date: Tue Nov 15 2016 - 06:22:52 EST
On 9.11.2016 16:53, Marc Zyngier wrote:
> On 01/11/16 11:05, Zubair Lutfullah Kakakhel wrote:
>> Hi,
>>
>> Thanks for the review.
>>
>> On 10/31/2016 07:51 PM, Thomas Gleixner wrote:
>>> On Mon, 31 Oct 2016, Zubair Lutfullah Kakakhel wrote:
>>>> The drivers read/write function handling is a bit quirky.
>>>
>>> Can you please explain in more detail what's quirky and why it should be
>>> done differently,
>>>
>>>> And the irqmask is passed directly to the handler.
>>>
>>> I can't make any sense out of that sentence. Which handler? If you talk
>>> about the write function, then I don't see a change. So what are you
>>> talking about?
>>
>> Thanks. I'll add more detail in v7 if this patch survives.
>>
>>>
>>>> Add a new irqchip struct to pass to the handler and
>>>> cleanup read/write handling.
>>>
>>> I still don't see what it cleans up. You move the write function pointer
>>> into a data structure, which is exposed by another pointer. So you create
>>> two levels of indirection in the hotpath. The function prototype is still
>>> the same. So all this does is making things slower unless I'm missing
>>> something.
>>
>> I wrote this patch/cleanup based on a review of driver by Marc when I moved the
>> driver from arch/microblaze to drivers/irqchip
>>
>> "Marc Zyngier
>>
>> ...
>>
>> > arch/microblaze/kernel/intc.c | 196 ----------------------------------------
>> > drivers/irqchip/irq-axi-intc.c | 196 ++++++++++++++++++++++++++++++++++++++++
>>
>> ...
>>
>> > + /* Yeah, okay, casting the intr_mask to a void* is butt-ugly, but I'm
>> > + * lazy and Michal can clean it up to something nicer when he tests
>> > + * and commits this patch. ~~gcl */
>> > + root_domain = irq_domain_add_linear(intc, nr_irq, &xintc_irq_domain_ops,
>> > + (void *)intr_mask);
>>
>> Since you're now reworking this driver, how about addressing this
>> ugliness? You could store the intr_mask together with intc_baseaddr,
>> and the read/write functions in a global structure, and pass a
>> pointer to it? That would make the code a bit nicer...
>> "
>>
>> https://patchwork.kernel.org/patch/9287933/
>>
>>>
>>>> -static unsigned int (*read_fn)(void __iomem *);
>>>> -static void (*write_fn)(u32, void __iomem *);
>>>> +struct xintc_irq_chip {
>>>> + void __iomem *base;
>>>> + struct irq_domain *domain;
>>>> + struct irq_chip chip;
>>>
>>> The tabs between struct and the structure name are bogus.
>>>
>>>> + u32 intr_mask;
>>>> + unsigned int (*read)(void __iomem *iomem);
>>>> + void (*write)(u32 data, void __iomem *iomem);
>>>
>>> Please structure that like a table:
>>>
>>> void __iomem *base;
>>> struct irq_domain *domain;
>>> struct irq_chip chip;
>>> u32 intr_mask;
>>> unsigned int (*read)(void __iomem *iomem);
>>> void (*write)(u32 data, void __iomem *iomem);
>>>
>>> Can you see how that makes parsing the struct simpler, because the data
>>> types are clearly to identify?
>>
>> That does make it look much better.
>>
>>>
>>>> +static struct xintc_irq_chip *xintc_irqc;
>>>>
>>>> static void intc_write32(u32 val, void __iomem *addr)
>>>> {
>>>> @@ -54,6 +60,18 @@ static unsigned int intc_read32_be(void __iomem *addr)
>>>> return ioread32be(addr);
>>>> }
>>>>
>>>> +static inline unsigned int xintc_read(struct xintc_irq_chip *xintc_irqc,
>>>> + int reg)
>>>> +{
>>>> + return xintc_irqc->read(xintc_irqc->base + reg);
>>>> +}
>>>> +
>>>> +static inline void xintc_write(struct xintc_irq_chip *xintc_irqc,
>>>> + int reg, u32 data)
>>>> +{
>>>> + xintc_irqc->write(data, xintc_irqc->base + reg);
>>>> +}
>>>> +
>>>> static void intc_enable_or_unmask(struct irq_data *d)
>>>> {
>>>> unsigned long mask = 1 << d->hwirq;
>>>> @@ -65,21 +83,21 @@ static void intc_enable_or_unmask(struct irq_data *d)
>>>> * acks the irq before calling the interrupt handler
>>>> */
>>>> if (irqd_is_level_type(d))
>>>> - write_fn(mask, intc_baseaddr + IAR);
>>>> + xintc_write(xintc_irqc, IAR, mask);
>>>
>>> So this whole thing makes only sense, when you want to support multiple
>>> instances of that chip and then you need to store the xintc_irqc pointer as
>>> irqchip data and retrieve it from there. Unless you do that, this "cleanup"
>>> is just churn for nothing with the effect of making things less efficient.
>>>
>>
>> Indeed the driver doesn't support multiple instances of the Xilinx Interrupt controller.
>> I don't have a use-case or the hardware for that.
>>
>> So what would be the recommended course of action?
>
> If you really don't want/need to support multi-instance, then this is
> indeed overkill. You're then better off having a simple static key that
> deals with the endianess of the peripheral, and have a global structure
> that contains the relevant data:
By design this is PL IP and multi-instance support should be there.
You are using it with MIPS but you can connect more INTC together.
Thanks,
Michal