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