提交 847bea3d 编写于 作者: H Hector Martin

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: NHector Martin <marcan@marcan.st>
...@@ -110,7 +110,6 @@ config ARM64 ...@@ -110,7 +110,6 @@ config ARM64
select GENERIC_EARLY_IOREMAP select GENERIC_EARLY_IOREMAP
select GENERIC_IDLE_POLL_SETUP select GENERIC_IDLE_POLL_SETUP
select GENERIC_IRQ_IPI select GENERIC_IRQ_IPI
select GENERIC_IRQ_MULTI_HANDLER
select GENERIC_IRQ_PROBE select GENERIC_IRQ_PROBE
select GENERIC_IRQ_SHOW select GENERIC_IRQ_SHOW
select GENERIC_IRQ_SHOW_LEVEL select GENERIC_IRQ_SHOW_LEVEL
......
...@@ -173,7 +173,7 @@ static inline void gic_pmr_mask_irqs(void) ...@@ -173,7 +173,7 @@ static inline void gic_pmr_mask_irqs(void)
static inline void gic_arch_enable_irqs(void) static inline void gic_arch_enable_irqs(void)
{ {
asm volatile ("msr daifclr, #2" : : : "memory"); asm volatile ("msr daifclr, #3" : : : "memory");
} }
#endif /* __ASSEMBLY__ */ #endif /* __ASSEMBLY__ */
......
...@@ -40,9 +40,9 @@ ...@@ -40,9 +40,9 @@
msr daif, \flags msr daif, \flags
.endm .endm
/* IRQ is the lowest priority flag, unconditionally unmask the rest. */ /* IRQ/FIQ are the lowest priority flags, unconditionally unmask the rest. */
.macro enable_da_f .macro enable_da
msr daifclr, #(8 | 4 | 1) msr daifclr, #(8 | 4)
.endm .endm
/* /*
...@@ -50,7 +50,7 @@ ...@@ -50,7 +50,7 @@
*/ */
.macro save_and_disable_irq, flags .macro save_and_disable_irq, flags
mrs \flags, daif mrs \flags, daif
msr daifset, #2 msr daifset, #3
.endm .endm
.macro restore_irq, flags .macro restore_irq, flags
......
...@@ -13,8 +13,8 @@ ...@@ -13,8 +13,8 @@
#include <asm/ptrace.h> #include <asm/ptrace.h>
#define DAIF_PROCCTX 0 #define DAIF_PROCCTX 0
#define DAIF_PROCCTX_NOIRQ PSR_I_BIT #define DAIF_PROCCTX_NOIRQ (PSR_I_BIT | PSR_F_BIT)
#define DAIF_ERRCTX (PSR_I_BIT | PSR_A_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) #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) ...@@ -47,7 +47,7 @@ static inline unsigned long local_daif_save_flags(void)
if (system_uses_irq_prio_masking()) { if (system_uses_irq_prio_masking()) {
/* If IRQs are masked with PMR, reflect it in the flags */ /* If IRQs are masked with PMR, reflect it in the flags */
if (read_sysreg_s(SYS_ICC_PMR_EL1) != GIC_PRIO_IRQON) if (read_sysreg_s(SYS_ICC_PMR_EL1) != GIC_PRIO_IRQON)
flags |= PSR_I_BIT; flags |= PSR_I_BIT | PSR_F_BIT;
} }
return flags; return flags;
...@@ -69,7 +69,7 @@ static inline void local_daif_restore(unsigned long flags) ...@@ -69,7 +69,7 @@ static inline void local_daif_restore(unsigned long flags)
bool irq_disabled = flags & PSR_I_BIT; bool irq_disabled = flags & PSR_I_BIT;
WARN_ON(system_has_prio_mask_debugging() && 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) { if (!irq_disabled) {
trace_hardirqs_on(); trace_hardirqs_on();
...@@ -86,7 +86,7 @@ static inline void local_daif_restore(unsigned long flags) ...@@ -86,7 +86,7 @@ static inline void local_daif_restore(unsigned long flags)
* If interrupts are disabled but we can take * If interrupts are disabled but we can take
* asynchronous errors, we can take NMIs * asynchronous errors, we can take NMIs
*/ */
flags &= ~PSR_I_BIT; flags &= ~(PSR_I_BIT | PSR_F_BIT);
pmr = GIC_PRIO_IRQOFF; pmr = GIC_PRIO_IRQOFF;
} else { } else {
pmr = GIC_PRIO_IRQON | GIC_PRIO_PSR_I_SET; pmr = GIC_PRIO_IRQON | GIC_PRIO_PSR_I_SET;
......
...@@ -8,6 +8,10 @@ ...@@ -8,6 +8,10 @@
struct pt_regs; 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) static inline int nr_legacy_irqs(void)
{ {
return 0; return 0;
......
...@@ -12,15 +12,13 @@ ...@@ -12,15 +12,13 @@
/* /*
* Aarch64 has flags for masking: Debug, Asynchronous (serror), Interrupts and * 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: * order:
* Masking debug exceptions causes all other exceptions to be masked too/ * Masking debug exceptions causes all other exceptions to be masked too/
* Masking SError masks irq, but not debug exceptions. Masking irqs has no * Masking SError masks IRQ/FIQ, but not debug exceptions. IRQ and FIQ are
* side effects for other flags. Keeping to this order makes it easier for * always masked and unmasked together, and have no side effects for other
* entry.S to know which exceptions should be unmasked. * 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.
*/ */
/* /*
...@@ -35,7 +33,7 @@ static inline void arch_local_irq_enable(void) ...@@ -35,7 +33,7 @@ static inline void arch_local_irq_enable(void)
} }
asm volatile(ALTERNATIVE( asm volatile(ALTERNATIVE(
"msr daifclr, #2 // arch_local_irq_enable", "msr daifclr, #3 // arch_local_irq_enable",
__msr_s(SYS_ICC_PMR_EL1, "%0"), __msr_s(SYS_ICC_PMR_EL1, "%0"),
ARM64_HAS_IRQ_PRIO_MASKING) ARM64_HAS_IRQ_PRIO_MASKING)
: :
...@@ -54,7 +52,7 @@ static inline void arch_local_irq_disable(void) ...@@ -54,7 +52,7 @@ static inline void arch_local_irq_disable(void)
} }
asm volatile(ALTERNATIVE( asm volatile(ALTERNATIVE(
"msr daifset, #2 // arch_local_irq_disable", "msr daifset, #3 // arch_local_irq_disable",
__msr_s(SYS_ICC_PMR_EL1, "%0"), __msr_s(SYS_ICC_PMR_EL1, "%0"),
ARM64_HAS_IRQ_PRIO_MASKING) ARM64_HAS_IRQ_PRIO_MASKING)
: :
......
...@@ -491,8 +491,8 @@ tsk .req x28 // current thread_info ...@@ -491,8 +491,8 @@ tsk .req x28 // current thread_info
/* /*
* Interrupt handling. * Interrupt handling.
*/ */
.macro irq_handler .macro irq_handler, handler:req
ldr_l x1, handle_arch_irq ldr_l x1, \handler
mov x0, sp mov x0, sp
irq_stack_entry irq_stack_entry
blr x1 blr x1
...@@ -531,6 +531,47 @@ alternative_endif ...@@ -531,6 +531,47 @@ alternative_endif
#endif #endif
.endm .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 .text
/* /*
...@@ -547,18 +588,18 @@ SYM_CODE_START(vectors) ...@@ -547,18 +588,18 @@ SYM_CODE_START(vectors)
kernel_ventry 1, sync // Synchronous EL1h kernel_ventry 1, sync // Synchronous EL1h
kernel_ventry 1, irq // IRQ 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 1, error // Error EL1h
kernel_ventry 0, sync // Synchronous 64-bit EL0 kernel_ventry 0, sync // Synchronous 64-bit EL0
kernel_ventry 0, irq // IRQ 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 kernel_ventry 0, error // Error 64-bit EL0
#ifdef CONFIG_COMPAT #ifdef CONFIG_COMPAT
kernel_ventry 0, sync_compat, 32 // Synchronous 32-bit EL0 kernel_ventry 0, sync_compat, 32 // Synchronous 32-bit EL0
kernel_ventry 0, irq_compat, 32 // IRQ 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 kernel_ventry 0, error_compat, 32 // Error 32-bit EL0
#else #else
kernel_ventry 0, sync_invalid, 32 // Synchronous 32-bit EL0 kernel_ventry 0, sync_invalid, 32 // Synchronous 32-bit EL0
...@@ -624,12 +665,6 @@ SYM_CODE_START_LOCAL(el0_error_invalid) ...@@ -624,12 +665,6 @@ SYM_CODE_START_LOCAL(el0_error_invalid)
inv_entry 0, BAD_ERROR inv_entry 0, BAD_ERROR
SYM_CODE_END(el0_error_invalid) 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) SYM_CODE_START_LOCAL(el1_sync_invalid)
inv_entry 1, BAD_SYNC inv_entry 1, BAD_SYNC
SYM_CODE_END(el1_sync_invalid) SYM_CODE_END(el1_sync_invalid)
...@@ -660,35 +695,16 @@ SYM_CODE_END(el1_sync) ...@@ -660,35 +695,16 @@ SYM_CODE_END(el1_sync)
.align 6 .align 6
SYM_CODE_START_LOCAL_NOALIGN(el1_irq) SYM_CODE_START_LOCAL_NOALIGN(el1_irq)
kernel_entry 1 kernel_entry 1
gic_prio_irq_setup pmr=x20, tmp=x1 el1_interrupt_handler handle_arch_irq
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
kernel_exit 1 kernel_exit 1
SYM_CODE_END(el1_irq) 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. * EL0 mode handlers.
*/ */
...@@ -715,6 +731,11 @@ SYM_CODE_START_LOCAL_NOALIGN(el0_irq_compat) ...@@ -715,6 +731,11 @@ SYM_CODE_START_LOCAL_NOALIGN(el0_irq_compat)
b el0_irq_naked b el0_irq_naked
SYM_CODE_END(el0_irq_compat) 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) SYM_CODE_START_LOCAL_NOALIGN(el0_error_compat)
kernel_entry 0, 32 kernel_entry 0, 32
b el0_error_naked b el0_error_naked
...@@ -725,18 +746,17 @@ SYM_CODE_END(el0_error_compat) ...@@ -725,18 +746,17 @@ SYM_CODE_END(el0_error_compat)
SYM_CODE_START_LOCAL_NOALIGN(el0_irq) SYM_CODE_START_LOCAL_NOALIGN(el0_irq)
kernel_entry 0 kernel_entry 0
el0_irq_naked: el0_irq_naked:
gic_prio_irq_setup pmr=x20, tmp=x0 el0_interrupt_handler handle_arch_irq
user_exit_irqoff
enable_da_f
tbz x22, #55, 1f
bl do_el0_irq_bp_hardening
1:
irq_handler
b ret_to_user b ret_to_user
SYM_CODE_END(el0_irq) 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) SYM_CODE_START_LOCAL(el1_error)
kernel_entry 1 kernel_entry 1
mrs x1, esr_el1 mrs x1, esr_el1
...@@ -757,7 +777,7 @@ el0_error_naked: ...@@ -757,7 +777,7 @@ el0_error_naked:
mov x0, sp mov x0, sp
mov x1, x25 mov x1, x25
bl do_serror bl do_serror
enable_da_f enable_da
b ret_to_user b ret_to_user
SYM_CODE_END(el0_error) SYM_CODE_END(el0_error)
......
...@@ -71,13 +71,44 @@ static void init_irq_stacks(void) ...@@ -71,13 +71,44 @@ static void init_irq_stacks(void)
} }
#endif #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) void __init init_IRQ(void)
{ {
init_irq_stacks(); init_irq_stacks();
init_irq_scs(); init_irq_scs();
irqchip_init(); irqchip_init();
if (!handle_arch_irq)
panic("No interrupt controller found.");
if (system_uses_irq_prio_masking()) { if (system_uses_irq_prio_masking()) {
/* /*
......
...@@ -84,7 +84,7 @@ static void noinstr __cpu_do_idle_irqprio(void) ...@@ -84,7 +84,7 @@ static void noinstr __cpu_do_idle_irqprio(void)
unsigned long daif_bits; unsigned long daif_bits;
daif_bits = read_sysreg(daif); 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 * Unmask PMR before going idle to make sure interrupts can
......
...@@ -188,6 +188,7 @@ static void init_gic_priority_masking(void) ...@@ -188,6 +188,7 @@ static void init_gic_priority_masking(void)
cpuflags = read_sysreg(daif); cpuflags = read_sysreg(daif);
WARN_ON(!(cpuflags & PSR_I_BIT)); WARN_ON(!(cpuflags & PSR_I_BIT));
WARN_ON(!(cpuflags & PSR_F_BIT));
gic_write_pmr(GIC_PRIO_IRQON | GIC_PRIO_PSR_I_SET); 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 *)); ...@@ -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; extern void (*handle_arch_irq)(struct pt_regs *) __ro_after_init;
#else #else
#ifndef set_handle_irq
#define set_handle_irq(handle_irq) \ #define set_handle_irq(handle_irq) \
do { \ do { \
(void)handle_irq; \ (void)handle_irq; \
WARN_ON(1); \ WARN_ON(1); \
} while (0) } while (0)
#endif #endif
#endif
#endif /* _LINUX_IRQ_H */ #endif /* _LINUX_IRQ_H */
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册