kernel: update 3.14 to 3.14.18
[openwrt.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  }