aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVineet Gupta <vgupta@synopsys.com>2015-09-05 13:17:30 -0400
committerVineet Gupta <vgupta@synopsys.com>2015-10-17 08:18:22 -0400
commit9dbd3d9bfd56707f9b1ccc301506e2fac0e95795 (patch)
tree6da3363df38759b7e2130ed7e4a2ef8c194d3835
parentc7119d56d2755fc2770b0e2c1c4385e10f4c9161 (diff)
ARC: [arcompact] don't check for hard isr calling local_irq_enable()
Historically this was done by ARC IDE driver, which is long gone. IRQ core is pretty robust now and already checks if IRQs are enabled in hard ISRs. Thus no point in checking this in arch code, for every call of irq enabled. Further if some driver does do that - let it bring down the system so we notice/fix this sooner than covering up for sucker This makes local_irq_enable() - for L1 only case atleast simple enough so we can inline it. Signed-off-by: Vineet Gupta <vgupta@synopsys.com>
-rw-r--r--arch/arc/include/asm/irqflags-compact.h14
-rw-r--r--arch/arc/kernel/intc-compact.c73
2 files changed, 18 insertions, 69 deletions
diff --git a/arch/arc/include/asm/irqflags-compact.h b/arch/arc/include/asm/irqflags-compact.h
index aa805575c320..a9490841c801 100644
--- a/arch/arc/include/asm/irqflags-compact.h
+++ b/arch/arc/include/asm/irqflags-compact.h
@@ -91,7 +91,19 @@ static inline void arch_local_irq_restore(unsigned long flags)
91/* 91/*
92 * Unconditionally Enable IRQs 92 * Unconditionally Enable IRQs
93 */ 93 */
94extern void arch_local_irq_enable(void); 94static inline void arch_local_irq_enable(void)
95{
96 unsigned long temp;
97
98 __asm__ __volatile__(
99 " lr %0, [status32] \n"
100 " or %0, %0, %1 \n"
101 " flag %0 \n"
102 : "=&r"(temp)
103 : "n"((STATUS_E1_MASK | STATUS_E2_MASK))
104 : "cc", "memory");
105}
106
95 107
96/* 108/*
97 * Unconditionally Disable IRQs 109 * Unconditionally Disable IRQs
diff --git a/arch/arc/kernel/intc-compact.c b/arch/arc/kernel/intc-compact.c
index 039fac30b5c1..a1669cf2a277 100644
--- a/arch/arc/kernel/intc-compact.c
+++ b/arch/arc/kernel/intc-compact.c
@@ -148,78 +148,15 @@ IRQCHIP_DECLARE(arc_intc, "snps,arc700-intc", init_onchip_IRQ);
148 148
149void arch_local_irq_enable(void) 149void arch_local_irq_enable(void)
150{ 150{
151
152 unsigned long flags = arch_local_save_flags(); 151 unsigned long flags = arch_local_save_flags();
153 152
154 /* Allow both L1 and L2 at the onset */ 153 if (flags & STATUS_A2_MASK)
155 flags |= (STATUS_E1_MASK | STATUS_E2_MASK); 154 flags |= STATUS_E2_MASK;
156 155 else if (flags & STATUS_A1_MASK)
157 /* Called from hard ISR (between irq_enter and irq_exit) */ 156 flags |= STATUS_E1_MASK;
158 if (in_irq()) {
159
160 /* If in L2 ISR, don't re-enable any further IRQs as this can
161 * cause IRQ priorities to get upside down. e.g. it could allow
162 * L1 be taken while in L2 hard ISR which is wrong not only in
163 * theory, it can also cause the dreaded L1-L2-L1 scenario
164 */
165 if (flags & STATUS_A2_MASK)
166 flags &= ~(STATUS_E1_MASK | STATUS_E2_MASK);
167
168 /* Even if in L1 ISR, allowe Higher prio L2 IRQs */
169 else if (flags & STATUS_A1_MASK)
170 flags &= ~(STATUS_E1_MASK);
171 }
172
173 /* called from soft IRQ, ideally we want to re-enable all levels */
174
175 else if (in_softirq()) {
176
177 /* However if this is case of L1 interrupted by L2,
178 * re-enabling both may cause whaco L1-L2-L1 scenario
179 * because ARC700 allows level 1 to interrupt an active L2 ISR
180 * Thus we disable both
181 * However some code, executing in soft ISR wants some IRQs
182 * to be enabled so we re-enable L2 only
183 *
184 * How do we determine L1 intr by L2
185 * -A2 is set (means in L2 ISR)
186 * -E1 is set in this ISR's pt_regs->status32 which is
187 * saved copy of status32_l2 when l2 ISR happened
188 */
189 struct pt_regs *pt = get_irq_regs();
190
191 if ((flags & STATUS_A2_MASK) && pt &&
192 (pt->status32 & STATUS_A1_MASK)) {
193 /*flags &= ~(STATUS_E1_MASK | STATUS_E2_MASK); */
194 flags &= ~(STATUS_E1_MASK);
195 }
196 }
197 157
198 arch_local_irq_restore(flags); 158 arch_local_irq_restore(flags);
199} 159}
200 160
201#else /* ! CONFIG_ARC_COMPACT_IRQ_LEVELS */
202
203/*
204 * Simpler version for only 1 level of interrupt
205 * Here we only Worry about Level 1 Bits
206 */
207void arch_local_irq_enable(void)
208{
209 unsigned long flags;
210
211 /*
212 * ARC IDE Drivers tries to re-enable interrupts from hard-isr
213 * context which is simply wrong
214 */
215 if (in_irq()) {
216 WARN_ONCE(1, "IRQ enabled from hard-isr");
217 return;
218 }
219
220 flags = arch_local_save_flags();
221 flags |= (STATUS_E1_MASK | STATUS_E2_MASK);
222 arch_local_irq_restore(flags);
223}
224#endif
225EXPORT_SYMBOL(arch_local_irq_enable); 161EXPORT_SYMBOL(arch_local_irq_enable);
162#endif