Merge remote-tracking branch 'arm64/for-next/fiq'
The FIQ support series, already merged into arm64, is a dependency of the M1 bring-up series and was split off after the first few versions. Signed-off-by: Hector Martin <marcan@marcan.st>
This commit is contained in:
commit
847bea3d08
|
@ -110,7 +110,6 @@ config ARM64
|
|||
select GENERIC_EARLY_IOREMAP
|
||||
select GENERIC_IDLE_POLL_SETUP
|
||||
select GENERIC_IRQ_IPI
|
||||
select GENERIC_IRQ_MULTI_HANDLER
|
||||
select GENERIC_IRQ_PROBE
|
||||
select GENERIC_IRQ_SHOW
|
||||
select GENERIC_IRQ_SHOW_LEVEL
|
||||
|
|
|
@ -173,7 +173,7 @@ static inline void gic_pmr_mask_irqs(void)
|
|||
|
||||
static inline void gic_arch_enable_irqs(void)
|
||||
{
|
||||
asm volatile ("msr daifclr, #2" : : : "memory");
|
||||
asm volatile ("msr daifclr, #3" : : : "memory");
|
||||
}
|
||||
|
||||
#endif /* __ASSEMBLY__ */
|
||||
|
|
|
@ -40,9 +40,9 @@
|
|||
msr daif, \flags
|
||||
.endm
|
||||
|
||||
/* IRQ is the lowest priority flag, unconditionally unmask the rest. */
|
||||
.macro enable_da_f
|
||||
msr daifclr, #(8 | 4 | 1)
|
||||
/* IRQ/FIQ are the lowest priority flags, unconditionally unmask the rest. */
|
||||
.macro enable_da
|
||||
msr daifclr, #(8 | 4)
|
||||
.endm
|
||||
|
||||
/*
|
||||
|
@ -50,7 +50,7 @@
|
|||
*/
|
||||
.macro save_and_disable_irq, flags
|
||||
mrs \flags, daif
|
||||
msr daifset, #2
|
||||
msr daifset, #3
|
||||
.endm
|
||||
|
||||
.macro restore_irq, flags
|
||||
|
|
|
@ -13,8 +13,8 @@
|
|||
#include <asm/ptrace.h>
|
||||
|
||||
#define DAIF_PROCCTX 0
|
||||
#define DAIF_PROCCTX_NOIRQ PSR_I_BIT
|
||||
#define DAIF_ERRCTX (PSR_I_BIT | PSR_A_BIT)
|
||||
#define DAIF_PROCCTX_NOIRQ (PSR_I_BIT | PSR_F_BIT)
|
||||
#define DAIF_ERRCTX (PSR_A_BIT | PSR_I_BIT | PSR_F_BIT)
|
||||
#define DAIF_MASK (PSR_D_BIT | PSR_A_BIT | PSR_I_BIT | PSR_F_BIT)
|
||||
|
||||
|
||||
|
@ -47,7 +47,7 @@ static inline unsigned long local_daif_save_flags(void)
|
|||
if (system_uses_irq_prio_masking()) {
|
||||
/* If IRQs are masked with PMR, reflect it in the flags */
|
||||
if (read_sysreg_s(SYS_ICC_PMR_EL1) != GIC_PRIO_IRQON)
|
||||
flags |= PSR_I_BIT;
|
||||
flags |= PSR_I_BIT | PSR_F_BIT;
|
||||
}
|
||||
|
||||
return flags;
|
||||
|
@ -69,7 +69,7 @@ static inline void local_daif_restore(unsigned long flags)
|
|||
bool irq_disabled = flags & PSR_I_BIT;
|
||||
|
||||
WARN_ON(system_has_prio_mask_debugging() &&
|
||||
!(read_sysreg(daif) & PSR_I_BIT));
|
||||
(read_sysreg(daif) & (PSR_I_BIT | PSR_F_BIT)) != (PSR_I_BIT | PSR_F_BIT));
|
||||
|
||||
if (!irq_disabled) {
|
||||
trace_hardirqs_on();
|
||||
|
@ -86,7 +86,7 @@ static inline void local_daif_restore(unsigned long flags)
|
|||
* If interrupts are disabled but we can take
|
||||
* asynchronous errors, we can take NMIs
|
||||
*/
|
||||
flags &= ~PSR_I_BIT;
|
||||
flags &= ~(PSR_I_BIT | PSR_F_BIT);
|
||||
pmr = GIC_PRIO_IRQOFF;
|
||||
} else {
|
||||
pmr = GIC_PRIO_IRQON | GIC_PRIO_PSR_I_SET;
|
||||
|
|
|
@ -8,6 +8,10 @@
|
|||
|
||||
struct pt_regs;
|
||||
|
||||
int set_handle_irq(void (*handle_irq)(struct pt_regs *));
|
||||
#define set_handle_irq set_handle_irq
|
||||
int set_handle_fiq(void (*handle_fiq)(struct pt_regs *));
|
||||
|
||||
static inline int nr_legacy_irqs(void)
|
||||
{
|
||||
return 0;
|
||||
|
|
|
@ -12,15 +12,13 @@
|
|||
|
||||
/*
|
||||
* Aarch64 has flags for masking: Debug, Asynchronous (serror), Interrupts and
|
||||
* FIQ exceptions, in the 'daif' register. We mask and unmask them in 'dai'
|
||||
* FIQ exceptions, in the 'daif' register. We mask and unmask them in 'daif'
|
||||
* order:
|
||||
* Masking debug exceptions causes all other exceptions to be masked too/
|
||||
* Masking SError masks irq, but not debug exceptions. Masking irqs has no
|
||||
* side effects for other flags. Keeping to this order makes it easier for
|
||||
* entry.S to know which exceptions should be unmasked.
|
||||
*
|
||||
* FIQ is never expected, but we mask it when we disable debug exceptions, and
|
||||
* unmask it at all other times.
|
||||
* Masking SError masks IRQ/FIQ, but not debug exceptions. IRQ and FIQ are
|
||||
* always masked and unmasked together, and have no side effects for other
|
||||
* flags. Keeping to this order makes it easier for entry.S to know which
|
||||
* exceptions should be unmasked.
|
||||
*/
|
||||
|
||||
/*
|
||||
|
@ -35,7 +33,7 @@ static inline void arch_local_irq_enable(void)
|
|||
}
|
||||
|
||||
asm volatile(ALTERNATIVE(
|
||||
"msr daifclr, #2 // arch_local_irq_enable",
|
||||
"msr daifclr, #3 // arch_local_irq_enable",
|
||||
__msr_s(SYS_ICC_PMR_EL1, "%0"),
|
||||
ARM64_HAS_IRQ_PRIO_MASKING)
|
||||
:
|
||||
|
@ -54,7 +52,7 @@ static inline void arch_local_irq_disable(void)
|
|||
}
|
||||
|
||||
asm volatile(ALTERNATIVE(
|
||||
"msr daifset, #2 // arch_local_irq_disable",
|
||||
"msr daifset, #3 // arch_local_irq_disable",
|
||||
__msr_s(SYS_ICC_PMR_EL1, "%0"),
|
||||
ARM64_HAS_IRQ_PRIO_MASKING)
|
||||
:
|
||||
|
|
|
@ -491,8 +491,8 @@ tsk .req x28 // current thread_info
|
|||
/*
|
||||
* Interrupt handling.
|
||||
*/
|
||||
.macro irq_handler
|
||||
ldr_l x1, handle_arch_irq
|
||||
.macro irq_handler, handler:req
|
||||
ldr_l x1, \handler
|
||||
mov x0, sp
|
||||
irq_stack_entry
|
||||
blr x1
|
||||
|
@ -531,6 +531,47 @@ alternative_endif
|
|||
#endif
|
||||
.endm
|
||||
|
||||
.macro el1_interrupt_handler, handler:req
|
||||
gic_prio_irq_setup pmr=x20, tmp=x1
|
||||
enable_da
|
||||
|
||||
mov x0, sp
|
||||
bl enter_el1_irq_or_nmi
|
||||
|
||||
irq_handler \handler
|
||||
|
||||
#ifdef CONFIG_PREEMPTION
|
||||
ldr x24, [tsk, #TSK_TI_PREEMPT] // get preempt count
|
||||
alternative_if ARM64_HAS_IRQ_PRIO_MASKING
|
||||
/*
|
||||
* DA were cleared at start of handling, and IF are cleared by
|
||||
* the GIC irqchip driver using gic_arch_enable_irqs() for
|
||||
* normal IRQs. If anything is set, it means we come back from
|
||||
* an NMI instead of a normal IRQ, so skip preemption
|
||||
*/
|
||||
mrs x0, daif
|
||||
orr x24, x24, x0
|
||||
alternative_else_nop_endif
|
||||
cbnz x24, 1f // preempt count != 0 || NMI return path
|
||||
bl arm64_preempt_schedule_irq // irq en/disable is done inside
|
||||
1:
|
||||
#endif
|
||||
|
||||
mov x0, sp
|
||||
bl exit_el1_irq_or_nmi
|
||||
.endm
|
||||
|
||||
.macro el0_interrupt_handler, handler:req
|
||||
gic_prio_irq_setup pmr=x20, tmp=x0
|
||||
user_exit_irqoff
|
||||
enable_da
|
||||
|
||||
tbz x22, #55, 1f
|
||||
bl do_el0_irq_bp_hardening
|
||||
1:
|
||||
irq_handler \handler
|
||||
.endm
|
||||
|
||||
.text
|
||||
|
||||
/*
|
||||
|
@ -547,18 +588,18 @@ SYM_CODE_START(vectors)
|
|||
|
||||
kernel_ventry 1, sync // Synchronous EL1h
|
||||
kernel_ventry 1, irq // IRQ EL1h
|
||||
kernel_ventry 1, fiq_invalid // FIQ EL1h
|
||||
kernel_ventry 1, fiq // FIQ EL1h
|
||||
kernel_ventry 1, error // Error EL1h
|
||||
|
||||
kernel_ventry 0, sync // Synchronous 64-bit EL0
|
||||
kernel_ventry 0, irq // IRQ 64-bit EL0
|
||||
kernel_ventry 0, fiq_invalid // FIQ 64-bit EL0
|
||||
kernel_ventry 0, fiq // FIQ 64-bit EL0
|
||||
kernel_ventry 0, error // Error 64-bit EL0
|
||||
|
||||
#ifdef CONFIG_COMPAT
|
||||
kernel_ventry 0, sync_compat, 32 // Synchronous 32-bit EL0
|
||||
kernel_ventry 0, irq_compat, 32 // IRQ 32-bit EL0
|
||||
kernel_ventry 0, fiq_invalid_compat, 32 // FIQ 32-bit EL0
|
||||
kernel_ventry 0, fiq_compat, 32 // FIQ 32-bit EL0
|
||||
kernel_ventry 0, error_compat, 32 // Error 32-bit EL0
|
||||
#else
|
||||
kernel_ventry 0, sync_invalid, 32 // Synchronous 32-bit EL0
|
||||
|
@ -624,12 +665,6 @@ SYM_CODE_START_LOCAL(el0_error_invalid)
|
|||
inv_entry 0, BAD_ERROR
|
||||
SYM_CODE_END(el0_error_invalid)
|
||||
|
||||
#ifdef CONFIG_COMPAT
|
||||
SYM_CODE_START_LOCAL(el0_fiq_invalid_compat)
|
||||
inv_entry 0, BAD_FIQ, 32
|
||||
SYM_CODE_END(el0_fiq_invalid_compat)
|
||||
#endif
|
||||
|
||||
SYM_CODE_START_LOCAL(el1_sync_invalid)
|
||||
inv_entry 1, BAD_SYNC
|
||||
SYM_CODE_END(el1_sync_invalid)
|
||||
|
@ -660,35 +695,16 @@ SYM_CODE_END(el1_sync)
|
|||
.align 6
|
||||
SYM_CODE_START_LOCAL_NOALIGN(el1_irq)
|
||||
kernel_entry 1
|
||||
gic_prio_irq_setup pmr=x20, tmp=x1
|
||||
enable_da_f
|
||||
|
||||
mov x0, sp
|
||||
bl enter_el1_irq_or_nmi
|
||||
|
||||
irq_handler
|
||||
|
||||
#ifdef CONFIG_PREEMPTION
|
||||
ldr x24, [tsk, #TSK_TI_PREEMPT] // get preempt count
|
||||
alternative_if ARM64_HAS_IRQ_PRIO_MASKING
|
||||
/*
|
||||
* DA_F were cleared at start of handling. If anything is set in DAIF,
|
||||
* we come back from an NMI, so skip preemption
|
||||
*/
|
||||
mrs x0, daif
|
||||
orr x24, x24, x0
|
||||
alternative_else_nop_endif
|
||||
cbnz x24, 1f // preempt count != 0 || NMI return path
|
||||
bl arm64_preempt_schedule_irq // irq en/disable is done inside
|
||||
1:
|
||||
#endif
|
||||
|
||||
mov x0, sp
|
||||
bl exit_el1_irq_or_nmi
|
||||
|
||||
el1_interrupt_handler handle_arch_irq
|
||||
kernel_exit 1
|
||||
SYM_CODE_END(el1_irq)
|
||||
|
||||
SYM_CODE_START_LOCAL_NOALIGN(el1_fiq)
|
||||
kernel_entry 1
|
||||
el1_interrupt_handler handle_arch_fiq
|
||||
kernel_exit 1
|
||||
SYM_CODE_END(el1_fiq)
|
||||
|
||||
/*
|
||||
* EL0 mode handlers.
|
||||
*/
|
||||
|
@ -715,6 +731,11 @@ SYM_CODE_START_LOCAL_NOALIGN(el0_irq_compat)
|
|||
b el0_irq_naked
|
||||
SYM_CODE_END(el0_irq_compat)
|
||||
|
||||
SYM_CODE_START_LOCAL_NOALIGN(el0_fiq_compat)
|
||||
kernel_entry 0, 32
|
||||
b el0_fiq_naked
|
||||
SYM_CODE_END(el0_fiq_compat)
|
||||
|
||||
SYM_CODE_START_LOCAL_NOALIGN(el0_error_compat)
|
||||
kernel_entry 0, 32
|
||||
b el0_error_naked
|
||||
|
@ -725,18 +746,17 @@ SYM_CODE_END(el0_error_compat)
|
|||
SYM_CODE_START_LOCAL_NOALIGN(el0_irq)
|
||||
kernel_entry 0
|
||||
el0_irq_naked:
|
||||
gic_prio_irq_setup pmr=x20, tmp=x0
|
||||
user_exit_irqoff
|
||||
enable_da_f
|
||||
|
||||
tbz x22, #55, 1f
|
||||
bl do_el0_irq_bp_hardening
|
||||
1:
|
||||
irq_handler
|
||||
|
||||
el0_interrupt_handler handle_arch_irq
|
||||
b ret_to_user
|
||||
SYM_CODE_END(el0_irq)
|
||||
|
||||
SYM_CODE_START_LOCAL_NOALIGN(el0_fiq)
|
||||
kernel_entry 0
|
||||
el0_fiq_naked:
|
||||
el0_interrupt_handler handle_arch_fiq
|
||||
b ret_to_user
|
||||
SYM_CODE_END(el0_fiq)
|
||||
|
||||
SYM_CODE_START_LOCAL(el1_error)
|
||||
kernel_entry 1
|
||||
mrs x1, esr_el1
|
||||
|
@ -757,7 +777,7 @@ el0_error_naked:
|
|||
mov x0, sp
|
||||
mov x1, x25
|
||||
bl do_serror
|
||||
enable_da_f
|
||||
enable_da
|
||||
b ret_to_user
|
||||
SYM_CODE_END(el0_error)
|
||||
|
||||
|
|
|
@ -71,13 +71,44 @@ static void init_irq_stacks(void)
|
|||
}
|
||||
#endif
|
||||
|
||||
static void default_handle_irq(struct pt_regs *regs)
|
||||
{
|
||||
panic("IRQ taken without a root IRQ handler\n");
|
||||
}
|
||||
|
||||
static void default_handle_fiq(struct pt_regs *regs)
|
||||
{
|
||||
panic("FIQ taken without a root FIQ handler\n");
|
||||
}
|
||||
|
||||
void (*handle_arch_irq)(struct pt_regs *) __ro_after_init = default_handle_irq;
|
||||
void (*handle_arch_fiq)(struct pt_regs *) __ro_after_init = default_handle_fiq;
|
||||
|
||||
int __init set_handle_irq(void (*handle_irq)(struct pt_regs *))
|
||||
{
|
||||
if (handle_arch_irq != default_handle_irq)
|
||||
return -EBUSY;
|
||||
|
||||
handle_arch_irq = handle_irq;
|
||||
pr_info("Root IRQ handler: %ps\n", handle_irq);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int __init set_handle_fiq(void (*handle_fiq)(struct pt_regs *))
|
||||
{
|
||||
if (handle_arch_fiq != default_handle_fiq)
|
||||
return -EBUSY;
|
||||
|
||||
handle_arch_fiq = handle_fiq;
|
||||
pr_info("Root FIQ handler: %ps\n", handle_fiq);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void __init init_IRQ(void)
|
||||
{
|
||||
init_irq_stacks();
|
||||
init_irq_scs();
|
||||
irqchip_init();
|
||||
if (!handle_arch_irq)
|
||||
panic("No interrupt controller found.");
|
||||
|
||||
if (system_uses_irq_prio_masking()) {
|
||||
/*
|
||||
|
|
|
@ -84,7 +84,7 @@ static void noinstr __cpu_do_idle_irqprio(void)
|
|||
unsigned long daif_bits;
|
||||
|
||||
daif_bits = read_sysreg(daif);
|
||||
write_sysreg(daif_bits | PSR_I_BIT, daif);
|
||||
write_sysreg(daif_bits | PSR_I_BIT | PSR_F_BIT, daif);
|
||||
|
||||
/*
|
||||
* Unmask PMR before going idle to make sure interrupts can
|
||||
|
|
|
@ -188,6 +188,7 @@ static void init_gic_priority_masking(void)
|
|||
cpuflags = read_sysreg(daif);
|
||||
|
||||
WARN_ON(!(cpuflags & PSR_I_BIT));
|
||||
WARN_ON(!(cpuflags & PSR_F_BIT));
|
||||
|
||||
gic_write_pmr(GIC_PRIO_IRQON | GIC_PRIO_PSR_I_SET);
|
||||
}
|
||||
|
|
|
@ -1258,11 +1258,13 @@ int __init set_handle_irq(void (*handle_irq)(struct pt_regs *));
|
|||
*/
|
||||
extern void (*handle_arch_irq)(struct pt_regs *) __ro_after_init;
|
||||
#else
|
||||
#ifndef set_handle_irq
|
||||
#define set_handle_irq(handle_irq) \
|
||||
do { \
|
||||
(void)handle_irq; \
|
||||
WARN_ON(1); \
|
||||
} while (0)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#endif /* _LINUX_IRQ_H */
|
||||
|
|
Loading…
Reference in New Issue