Commit 9dbd3d9b authored by Vineet Gupta's avatar Vineet Gupta

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: default avatarVineet Gupta <vgupta@synopsys.com>
parent c7119d56
...@@ -91,7 +91,19 @@ static inline void arch_local_irq_restore(unsigned long flags) ...@@ -91,7 +91,19 @@ static inline void arch_local_irq_restore(unsigned long flags)
/* /*
* Unconditionally Enable IRQs * Unconditionally Enable IRQs
*/ */
extern void arch_local_irq_enable(void); static inline void arch_local_irq_enable(void)
{
unsigned long temp;
__asm__ __volatile__(
" lr %0, [status32] \n"
" or %0, %0, %1 \n"
" flag %0 \n"
: "=&r"(temp)
: "n"((STATUS_E1_MASK | STATUS_E2_MASK))
: "cc", "memory");
}
/* /*
* Unconditionally Disable IRQs * Unconditionally Disable IRQs
......
...@@ -148,78 +148,15 @@ IRQCHIP_DECLARE(arc_intc, "snps,arc700-intc", init_onchip_IRQ); ...@@ -148,78 +148,15 @@ IRQCHIP_DECLARE(arc_intc, "snps,arc700-intc", init_onchip_IRQ);
void arch_local_irq_enable(void) void arch_local_irq_enable(void)
{ {
unsigned long flags = arch_local_save_flags(); 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) if (flags & STATUS_A2_MASK)
flags &= ~(STATUS_E1_MASK | STATUS_E2_MASK); flags |= STATUS_E2_MASK;
/* Even if in L1 ISR, allowe Higher prio L2 IRQs */
else if (flags & STATUS_A1_MASK) else if (flags & STATUS_A1_MASK)
flags &= ~(STATUS_E1_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);
}
}
arch_local_irq_restore(flags); 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); EXPORT_SYMBOL(arch_local_irq_enable);
#endif
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment