|
@@ -148,78 +148,15 @@ IRQCHIP_DECLARE(arc_intc, "snps,arc700-intc", init_onchip_IRQ);
|
|
|
|
|
|
void arch_local_irq_enable(void)
|
|
|
{
|
|
|
-
|
|
|
unsigned long flags = arch_local_save_flags();
|
|
|
|
|
|
- /* Allow both L1 and L2 at the onset */
|
|
|
- flags |= (STATUS_E1_MASK | STATUS_E2_MASK);
|
|
|
-
|
|
|
- /* Called from hard ISR (between irq_enter and irq_exit) */
|
|
|
- if (in_irq()) {
|
|
|
-
|
|
|
- /* If in L2 ISR, don't re-enable any further IRQs as this can
|
|
|
- * cause IRQ priorities to get upside down. e.g. it could allow
|
|
|
- * L1 be taken while in L2 hard ISR which is wrong not only in
|
|
|
- * theory, it can also cause the dreaded L1-L2-L1 scenario
|
|
|
- */
|
|
|
- if (flags & STATUS_A2_MASK)
|
|
|
- flags &= ~(STATUS_E1_MASK | STATUS_E2_MASK);
|
|
|
-
|
|
|
- /* Even if in L1 ISR, allowe Higher prio L2 IRQs */
|
|
|
- else if (flags & STATUS_A1_MASK)
|
|
|
- flags &= ~(STATUS_E1_MASK);
|
|
|
- }
|
|
|
-
|
|
|
- /* called from soft IRQ, ideally we want to re-enable all levels */
|
|
|
-
|
|
|
- else if (in_softirq()) {
|
|
|
-
|
|
|
- /* However if this is case of L1 interrupted by L2,
|
|
|
- * re-enabling both may cause whaco L1-L2-L1 scenario
|
|
|
- * because ARC700 allows level 1 to interrupt an active L2 ISR
|
|
|
- * Thus we disable both
|
|
|
- * However some code, executing in soft ISR wants some IRQs
|
|
|
- * to be enabled so we re-enable L2 only
|
|
|
- *
|
|
|
- * How do we determine L1 intr by L2
|
|
|
- * -A2 is set (means in L2 ISR)
|
|
|
- * -E1 is set in this ISR's pt_regs->status32 which is
|
|
|
- * saved copy of status32_l2 when l2 ISR happened
|
|
|
- */
|
|
|
- struct pt_regs *pt = get_irq_regs();
|
|
|
-
|
|
|
- if ((flags & STATUS_A2_MASK) && pt &&
|
|
|
- (pt->status32 & STATUS_A1_MASK)) {
|
|
|
- /*flags &= ~(STATUS_E1_MASK | STATUS_E2_MASK); */
|
|
|
- flags &= ~(STATUS_E1_MASK);
|
|
|
- }
|
|
|
- }
|
|
|
+ if (flags & STATUS_A2_MASK)
|
|
|
+ flags |= STATUS_E2_MASK;
|
|
|
+ else if (flags & STATUS_A1_MASK)
|
|
|
+ flags |= STATUS_E1_MASK;
|
|
|
|
|
|
arch_local_irq_restore(flags);
|
|
|
}
|
|
|
|
|
|
-#else /* ! CONFIG_ARC_COMPACT_IRQ_LEVELS */
|
|
|
-
|
|
|
-/*
|
|
|
- * Simpler version for only 1 level of interrupt
|
|
|
- * Here we only Worry about Level 1 Bits
|
|
|
- */
|
|
|
-void arch_local_irq_enable(void)
|
|
|
-{
|
|
|
- unsigned long flags;
|
|
|
-
|
|
|
- /*
|
|
|
- * ARC IDE Drivers tries to re-enable interrupts from hard-isr
|
|
|
- * context which is simply wrong
|
|
|
- */
|
|
|
- if (in_irq()) {
|
|
|
- WARN_ONCE(1, "IRQ enabled from hard-isr");
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- flags = arch_local_save_flags();
|
|
|
- flags |= (STATUS_E1_MASK | STATUS_E2_MASK);
|
|
|
- arch_local_irq_restore(flags);
|
|
|
-}
|
|
|
-#endif
|
|
|
EXPORT_SYMBOL(arch_local_irq_enable);
|
|
|
+#endif
|