4345d3e0dde4bcda0b2d5d4a5d6ae8089dc22780
[openwrt/staging/yousong.git] / target / linux / sunxi / patches-3.14 / 136-1-irqchip-sun4i-fixes.patch
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
5
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
8 handler has run.
9
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>
13 ---
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(-)
19
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
24 * when irq enabled
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
28 */
29 enum {
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),
36 };
37
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)
42 }
43 }
44
45 +void unmask_threaded_irq(struct irq_desc *desc)
46 +{
47 + struct irq_chip *chip = desc->irq_data.chip;
48 +
49 + if (chip->flags & IRQCHIP_EOI_THREADED)
50 + chip->irq_eoi(&desc->irq_data);
51 +
52 + if (chip->irq_unmask) {
53 + chip->irq_unmask(&desc->irq_data);
54 + irq_state_clr_masked(desc);
55 + }
56 +}
57 +
58 /*
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) { }
63 #endif
64
65 +static void cond_unmask_eoi_irq(struct irq_desc *desc, struct irq_chip *chip)
66 +{
67 + if (!(desc->istate & IRQS_ONESHOT)) {
68 + chip->irq_eoi(&desc->irq_data);
69 + return;
70 + }
71 + /*
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
75 + * completely).
76 + */
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);
80 + unmask_irq(desc);
81 + } else if (!(chip->flags & IRQCHIP_EOI_THREADED)) {
82 + chip->irq_eoi(&desc->irq_data);
83 + }
84 +}
85 +
86 /**
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
90 void
91 handle_fasteoi_irq(unsigned int irq, struct irq_desc *desc)
92 {
93 + struct irq_chip *chip = desc->irq_data.chip;
94 +
95 raw_spin_lock(&desc->lock);
96
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);
101
102 - if (desc->istate & IRQS_ONESHOT)
103 - cond_unmask_irq(desc);
104 + cond_unmask_eoi_irq(desc, chip);
105
106 -out_eoi:
107 - desc->irq_data.chip->irq_eoi(&desc->irq_data);
108 -out_unlock:
109 raw_spin_unlock(&desc->lock);
110 return;
111 out:
112 - if (!(desc->irq_data.chip->flags & IRQCHIP_EOI_IF_HANDLED))
113 - goto out_eoi;
114 - goto out_unlock;
115 + if (!(chip->flags & IRQCHIP_EOI_IF_HANDLED))
116 + chip->irq_eoi(&desc->irq_data);
117 + raw_spin_unlock(&desc->lock);
118 }
119
120 /**
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);
128
129 extern void init_kstat_irqs(struct irq_desc *desc, int node, int nr);
130
131 --- a/kernel/irq/manage.c
132 +++ b/kernel/irq/manage.c
133 @@ -713,7 +713,7 @@ again:
134
135 if (!desc->threads_oneshot && !irqd_irq_disabled(&desc->irq_data) &&
136 irqd_irq_masked(&desc->irq_data))
137 - unmask_irq(desc);
138 + unmask_threaded_irq(desc);
139
140 out_unlock:
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)
146 {
147 unsigned int irq = irqd_to_hwirq(irqd);
148 - unsigned int irq_off = irq % 32;
149 - int reg = irq / 32;
150 - u32 val;
151
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));
155 + if (irq != 0)
156 + return; /* Only IRQ 0 / the ENMI needs to be acked */
157 +
158 + writel(BIT(0), sun4i_irq_base + SUN4I_IRQ_PENDING_REG(0));
159 }
160
161 static void sun4i_irq_mask(struct irq_data *irqd)
162 @@ -76,16 +74,16 @@ static void sun4i_irq_unmask(struct irq_
163
164 static struct irq_chip sun4i_irq_chip = {
165 .name = "sun4i_irq",
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,
171 };
172
173 static int sun4i_irq_map(struct irq_domain *d, unsigned int virq,
174 irq_hw_number_t hw)
175 {
176 - irq_set_chip_and_handler(virq, &sun4i_irq_chip,
177 - handle_level_irq);
178 + irq_set_chip_and_handler(virq, &sun4i_irq_chip, handle_fasteoi_irq);
179 set_irq_flags(virq, IRQF_VALID | IRQF_PROBE);
180
181 return 0;
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));
185
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
192 {
193 u32 irq, hwirq;
194
195 + /*
196 + * hwirq == 0 can mean one of 3 things:
197 + * 1) no more irqs pending
198 + * 2) irq 0 pending
199 + * 3) spurious irq
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.
204 + */
205 hwirq = readl(sun4i_irq_base + SUN4I_IRQ_VECTOR_REG) >> 2;
206 - while (hwirq != 0) {
207 + if (hwirq == 0 &&
208 + !(readl(sun4i_irq_base + SUN4I_IRQ_PENDING_REG(0)) & BIT(0)))
209 + return;
210 +
211 + do {
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;
215 - }
216 + } while (hwirq != 0);
217 }