Re: [PATCH v3 02/14] irqchip: irq-pic32-evic: Add support for PIC32 interrupt controller
From: Thomas Gleixner <hidden>
Date: 2016-01-08 19:04:57
Also in:
lkml
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.
+ 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 + 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.
+/* 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 ....
+}
+
+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?
+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?
+}
+
+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.
+};
+
+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.
+ 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.
Thanks,
tglx