1 From 843da234cfc0e7014f9e2da82786a485e0820665 Mon Sep 17 00:00:00 2001
2 From: Thomas Gleixner <tglx@linutronix.de>
3 Date: Thu, 13 Mar 2014 15:32:05 +0100
4 Subject: [PATCH] irq: Add a new IRQCHIP_EOI_THREADED flag
6 This flag must be used in combination with handle_fasteoi_irq, when set
7 handle_fasteoi_irq will delay the calling of chip->irq_eoi until the threaded
10 Reviewed-by: Hans de Goede <hdegoede@redhat.com>
11 Tested-by: Hans de Goede <hdegoede@redhat.com>
12 Signed-off-by: Hans de Goede <hdegoede@redhat.com>
14 include/linux/irq.h | 3 +++
15 kernel/irq/chip.c | 48 ++++++++++++++++++++++++++++++++++++++++--------
16 kernel/irq/internals.h | 1 +
17 kernel/irq/manage.c | 2 +-
18 4 files changed, 45 insertions(+), 9 deletions(-)
20 --- a/include/linux/irq.h
21 +++ b/include/linux/irq.h
22 @@ -349,6 +349,8 @@ struct irq_chip {
23 * IRQCHIP_ONOFFLINE_ENABLED: Only call irq_on/off_line callbacks
25 * IRQCHIP_SKIP_SET_WAKE: Skip chip.irq_set_wake(), for this irq chip
26 + * IRQCHIP_ONESHOT_SAFE: One shot does not require mask/unmask
27 + * IRQCHIP_EOI_THREADED: Chip requires eoi() on unmask in threaded mode
30 IRQCHIP_SET_TYPE_MASKED = (1 << 0),
31 @@ -357,6 +359,7 @@ enum {
32 IRQCHIP_ONOFFLINE_ENABLED = (1 << 3),
33 IRQCHIP_SKIP_SET_WAKE = (1 << 4),
34 IRQCHIP_ONESHOT_SAFE = (1 << 5),
35 + IRQCHIP_EOI_THREADED = (1 << 6),
38 /* This include will go away once we isolated irq_desc usage to core code */
39 --- a/kernel/irq/chip.c
40 +++ b/kernel/irq/chip.c
41 @@ -281,6 +281,19 @@ void unmask_irq(struct irq_desc *desc)
45 +void unmask_threaded_irq(struct irq_desc *desc)
47 + struct irq_chip *chip = desc->irq_data.chip;
49 + if (chip->flags & IRQCHIP_EOI_THREADED)
50 + chip->irq_eoi(&desc->irq_data);
52 + if (chip->irq_unmask) {
53 + chip->irq_unmask(&desc->irq_data);
54 + irq_state_clr_masked(desc);
59 * handle_nested_irq - Handle a nested irq from a irq thread
60 * @irq: the interrupt number
61 @@ -435,6 +448,27 @@ static inline void preflow_handler(struc
62 static inline void preflow_handler(struct irq_desc *desc) { }
65 +static void cond_unmask_eoi_irq(struct irq_desc *desc, struct irq_chip *chip)
67 + if (!(desc->istate & IRQS_ONESHOT)) {
68 + chip->irq_eoi(&desc->irq_data);
72 + * We need to unmask in the following cases:
73 + * - Oneshot irq which did not wake the thread (caused by a
74 + * spurious interrupt or a primary handler handling it
77 + if (!irqd_irq_disabled(&desc->irq_data) &&
78 + irqd_irq_masked(&desc->irq_data) && !desc->threads_oneshot) {
79 + chip->irq_eoi(&desc->irq_data);
81 + } else if (!(chip->flags & IRQCHIP_EOI_THREADED)) {
82 + chip->irq_eoi(&desc->irq_data);
87 * handle_fasteoi_irq - irq handler for transparent controllers
88 * @irq: the interrupt number
89 @@ -448,6 +482,8 @@ static inline void preflow_handler(struc
91 handle_fasteoi_irq(unsigned int irq, struct irq_desc *desc)
93 + struct irq_chip *chip = desc->irq_data.chip;
95 raw_spin_lock(&desc->lock);
97 if (unlikely(irqd_irq_inprogress(&desc->irq_data)))
98 @@ -473,18 +509,14 @@ handle_fasteoi_irq(unsigned int irq, str
99 preflow_handler(desc);
100 handle_irq_event(desc);
102 - if (desc->istate & IRQS_ONESHOT)
103 - cond_unmask_irq(desc);
104 + cond_unmask_eoi_irq(desc, chip);
107 - desc->irq_data.chip->irq_eoi(&desc->irq_data);
109 raw_spin_unlock(&desc->lock);
112 - if (!(desc->irq_data.chip->flags & IRQCHIP_EOI_IF_HANDLED))
115 + if (!(chip->flags & IRQCHIP_EOI_IF_HANDLED))
116 + chip->irq_eoi(&desc->irq_data);
117 + raw_spin_unlock(&desc->lock);
121 --- a/kernel/irq/internals.h
122 +++ b/kernel/irq/internals.h
123 @@ -73,6 +73,7 @@ extern void irq_percpu_enable(struct irq
124 extern void irq_percpu_disable(struct irq_desc *desc, unsigned int cpu);
125 extern void mask_irq(struct irq_desc *desc);
126 extern void unmask_irq(struct irq_desc *desc);
127 +extern void unmask_threaded_irq(struct irq_desc *desc);
129 extern void init_kstat_irqs(struct irq_desc *desc, int node, int nr);
131 --- a/kernel/irq/manage.c
132 +++ b/kernel/irq/manage.c
133 @@ -713,7 +713,7 @@ again:
135 if (!desc->threads_oneshot && !irqd_irq_disabled(&desc->irq_data) &&
136 irqd_irq_masked(&desc->irq_data))
138 + unmask_threaded_irq(desc);
141 raw_spin_unlock_irq(&desc->lock);
142 --- a/drivers/irqchip/irq-sun4i.c
143 +++ b/drivers/irqchip/irq-sun4i.c
144 @@ -41,13 +41,11 @@ static asmlinkage void __exception_irq_e
145 static void sun4i_irq_ack(struct irq_data *irqd)
147 unsigned int irq = irqd_to_hwirq(irqd);
148 - unsigned int irq_off = irq % 32;
149 - int reg = irq / 32;
152 - val = readl(sun4i_irq_base + SUN4I_IRQ_PENDING_REG(reg));
153 - writel(val | (1 << irq_off),
154 - sun4i_irq_base + SUN4I_IRQ_PENDING_REG(reg));
156 + return; /* Only IRQ 0 / the ENMI needs to be acked */
158 + writel(BIT(0), sun4i_irq_base + SUN4I_IRQ_PENDING_REG(0));
161 static void sun4i_irq_mask(struct irq_data *irqd)
162 @@ -76,16 +74,16 @@ static void sun4i_irq_unmask(struct irq_
164 static struct irq_chip sun4i_irq_chip = {
166 - .irq_ack = sun4i_irq_ack,
167 + .irq_eoi = sun4i_irq_ack,
168 .irq_mask = sun4i_irq_mask,
169 .irq_unmask = sun4i_irq_unmask,
170 + .flags = IRQCHIP_EOI_THREADED | IRQCHIP_EOI_IF_HANDLED,
173 static int sun4i_irq_map(struct irq_domain *d, unsigned int virq,
176 - irq_set_chip_and_handler(virq, &sun4i_irq_chip,
178 + irq_set_chip_and_handler(virq, &sun4i_irq_chip, handle_fasteoi_irq);
179 set_irq_flags(virq, IRQF_VALID | IRQF_PROBE);
182 @@ -109,7 +107,7 @@ static int __init sun4i_of_init(struct d
183 writel(0, sun4i_irq_base + SUN4I_IRQ_ENABLE_REG(1));
184 writel(0, sun4i_irq_base + SUN4I_IRQ_ENABLE_REG(2));
186 - /* Mask all the interrupts */
187 + /* Unmask all the interrupts, ENABLE_REG(x) is used for masking */
188 writel(0, sun4i_irq_base + SUN4I_IRQ_MASK_REG(0));
189 writel(0, sun4i_irq_base + SUN4I_IRQ_MASK_REG(1));
190 writel(0, sun4i_irq_base + SUN4I_IRQ_MASK_REG(2));
191 @@ -140,10 +138,24 @@ static asmlinkage void __exception_irq_e
196 + * hwirq == 0 can mean one of 3 things:
197 + * 1) no more irqs pending
200 + * So if we immediately get a reading of 0, check the irq-pending reg
201 + * to differentiate between 2 and 3. We only do this once to avoid
202 + * the extra check in the common case of 1 hapening after having
203 + * read the vector-reg once.
205 hwirq = readl(sun4i_irq_base + SUN4I_IRQ_VECTOR_REG) >> 2;
206 - while (hwirq != 0) {
208 + !(readl(sun4i_irq_base + SUN4I_IRQ_PENDING_REG(0)) & BIT(0)))
212 irq = irq_find_mapping(sun4i_irq_domain, hwirq);
213 handle_IRQ(irq, regs);
214 hwirq = readl(sun4i_irq_base + SUN4I_IRQ_VECTOR_REG) >> 2;
216 + } while (hwirq != 0);