linux/arch/arc/include/asm/irqflags-arcv2.h
Vineet Gupta dec2b2849c ARCv2: intc: Allow interruption by lowest priority interrupt
ARC HS Cores support configurable multiple interrupt priorities of upto
16 levels.

There is processor "interrupt preemption threshhold" in STATUS32.E[4:1]
And several places need to set this up:
1. seed value as kernel is booting
2. seed value for user space programs
3. Arg to SLEEP instruction in idle task (what interrupt prio can wake)
4. Per-IRQ line prioirty (i.e. what is the priority of interrupt
   raised by a peripheral or timer or perf counter...

Currently above sites use the highest priority 0. This can be potential
problem when multiple priorities are supported. e.g. user space could
only be interrupted by P0 interrupt, not others...
So turn this over and instead make default interruption level to be
the lowest priority possible 15. This should be fine even if there are
fewer priority levels configured (say two: P0 HIGH, P1 LOW)

This feature also effectively disables FIRQ feature if present in
hardware config. With old code, a P0 interrupt would be FIRQ, needing
special handling (ISR or Register Banks) which is NOT supported yet.
Now it not be P0 (P15 or whatever is lowest prio) so FIRQ is not
triggered.

Signed-off-by: Vineet Gupta <vgupta@synopsys.com>
2016-02-10 06:38:50 +05:30

131 lines
2.6 KiB
C

/*
* Copyright (C) 2014-15 Synopsys, Inc. (www.synopsys.com)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#ifndef __ASM_IRQFLAGS_ARCV2_H
#define __ASM_IRQFLAGS_ARCV2_H
#include <asm/arcregs.h>
/* status32 Bits */
#define STATUS_AD_BIT 19 /* Disable Align chk: core supports non-aligned */
#define STATUS_IE_BIT 31
#define STATUS_AD_MASK (1<<STATUS_AD_BIT)
#define STATUS_IE_MASK (1<<STATUS_IE_BIT)
#define AUX_USER_SP 0x00D
#define AUX_IRQ_CTRL 0x00E
#define AUX_IRQ_ACT 0x043 /* Active Intr across all levels */
#define AUX_IRQ_LVL_PEND 0x200 /* Pending Intr across all levels */
#define AUX_IRQ_PRIORITY 0x206
#define ICAUSE 0x40a
#define AUX_IRQ_SELECT 0x40b
#define AUX_IRQ_ENABLE 0x40c
/* Was Intr taken in User Mode */
#define AUX_IRQ_ACT_BIT_U 31
/*
* User space should be interruptable even by lowest prio interrupt
* Safe even if actual interrupt priorities is fewer or even one
*/
#define ARCV2_IRQ_DEF_PRIO 15
/* seed value for status register */
#define ISA_INIT_STATUS_BITS (STATUS_IE_MASK | STATUS_AD_MASK | \
(ARCV2_IRQ_DEF_PRIO << 1))
/* SLEEP needs default irq priority (<=) which can interrupt the doze */
#define ISA_SLEEP_ARG (0x10 | ARCV2_IRQ_DEF_PRIO)
#ifndef __ASSEMBLY__
/*
* Save IRQ state and disable IRQs
*/
static inline long arch_local_irq_save(void)
{
unsigned long flags;
__asm__ __volatile__(" clri %0 \n" : "=r" (flags) : : "memory");
return flags;
}
/*
* restore saved IRQ state
*/
static inline void arch_local_irq_restore(unsigned long flags)
{
__asm__ __volatile__(" seti %0 \n" : : "r" (flags) : "memory");
}
/*
* Unconditionally Enable IRQs
*/
static inline void arch_local_irq_enable(void)
{
unsigned int irqact = read_aux_reg(AUX_IRQ_ACT);
if (irqact & 0xffff)
write_aux_reg(AUX_IRQ_ACT, irqact & ~0xffff);
__asm__ __volatile__(" seti \n" : : : "memory");
}
/*
* Unconditionally Disable IRQs
*/
static inline void arch_local_irq_disable(void)
{
__asm__ __volatile__(" clri \n" : : : "memory");
}
/*
* save IRQ state
*/
static inline long arch_local_save_flags(void)
{
unsigned long temp;
__asm__ __volatile__(
" lr %0, [status32] \n"
: "=&r"(temp)
:
: "memory");
return temp;
}
/*
* Query IRQ state
*/
static inline int arch_irqs_disabled_flags(unsigned long flags)
{
return !(flags & (STATUS_IE_MASK));
}
static inline int arch_irqs_disabled(void)
{
return arch_irqs_disabled_flags(arch_local_save_flags());
}
#else
.macro IRQ_DISABLE scratch
clri
.endm
.macro IRQ_ENABLE scratch
seti
.endm
#endif /* __ASSEMBLY__ */
#endif