aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniel Thompson <daniel.thompson@linaro.org>2017-01-27 16:07:13 +0000
committerDaniel Thompson <daniel.thompson@linaro.org>2017-03-30 19:29:03 +0100
commit9d9c6c34f93859d01b6201bf69301a69a0663c44 (patch)
tree4dab97f3eb63db3a93d1753e51568bcabc9adb0f
parent0ab44db1752bb96ae49726a386ead41b3298c5e9 (diff)
WIP: Migrating PMR interrupt locking away from kernel_entrydev/arm64_nmi-v4.11
Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
-rw-r--r--arch/arm64/kernel/entry.S14
-rw-r--r--drivers/irqchip/irq-gic-v3.c27
-rw-r--r--kernel/rcu/tree.c1
3 files changed, 39 insertions, 3 deletions
diff --git a/arch/arm64/kernel/entry.S b/arch/arm64/kernel/entry.S
index c71405d3c814..e22b7a04dc1a 100644
--- a/arch/arm64/kernel/entry.S
+++ b/arch/arm64/kernel/entry.S
@@ -125,8 +125,6 @@ alternative_endif
lsl x20, x20, #PSR_G_PMR_G_SHIFT // Shift to a PSTATE RES0 bit
eor x20, x20, #PSR_G_BIT // Invert bit
orr x23, x20, x23 // Store PMR within PSTATE
- mov x20, #ICC_PMR_EL1_MASKED
- msr_s ICC_PMR_EL1, x20 // Mask normal interrupts at PMR
1:
#endif
@@ -371,6 +369,8 @@ tsk .req x28 // current thread_info
* Interrupt handling.
*/
.macro irq_handler
+ mov x20, #ICC_PMR_EL1_MASKED
+ msr_s ICC_PMR_EL1, x20 // Mask normal interrupts at PMR
ldr_l x1, handle_arch_irq
mov x0, sp
irq_stack_entry
@@ -420,6 +420,8 @@ END(vectors)
*/
.macro inv_entry, el, reason, regsize = 64
kernel_entry \el, \regsize
+ mov x20, #ICC_PMR_EL1_MASKED
+ msr_s ICC_PMR_EL1, x20 // Mask normal interrupts at PMR
mov x0, sp
mov x1, #\reason
mrs x2, esr_el1
@@ -474,6 +476,8 @@ ENDPROC(el1_error_invalid)
.align 6
el1_sync:
kernel_entry 1
+ mov x20, #ICC_PMR_EL1_MASKED
+ msr_s ICC_PMR_EL1, x20 // Mask normal interrupts at PMR
mrs x1, esr_el1 // read the syndrome register
lsr x24, x1, #ESR_ELx_EC_SHIFT // exception class
cmp x24, #ESR_ELx_EC_DABT_CUR // data abort in EL1
@@ -509,11 +513,13 @@ alternative_if_not ARM64_HAS_SYSREG_GIC_CPUIF
tbnz x23, #7, 1f // PSR_I_BIT
msr daifclr, #2
nop
+ nop
1:
alternative_else
tbnz x23, #PSR_G_SHIFT, 1f // PSR_G_BIT
mov x2, #ICC_PMR_EL1_UNMASKED
msr_s ICC_PMR_EL1, x2
+ dsb sy
1:
alternative_endif
#else
@@ -606,6 +612,8 @@ el1_preempt:
.align 6
el0_sync:
kernel_entry 0
+ mov x20, #ICC_PMR_EL1_MASKED
+ msr_s ICC_PMR_EL1, x20 // Mask normal interrupts at PMR
mrs x25, esr_el1 // read the syndrome register
lsr x24, x25, #ESR_ELx_EC_SHIFT // exception class
cmp x24, #ESR_ELx_EC_SVC64 // SVC in 64-bit state
@@ -634,6 +642,8 @@ el0_sync:
.align 6
el0_sync_compat:
kernel_entry 0, 32
+ mov x20, #ICC_PMR_EL1_MASKED
+ msr_s ICC_PMR_EL1, x20 // Mask normal interrupts at PMR
mrs x25, esr_el1 // read the syndrome register
lsr x24, x25, #ESR_ELx_EC_SHIFT // exception class
cmp x24, #ESR_ELx_EC_SVC32 // SVC in 32-bit state
diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c
index 39232014d200..9ca08aa9e3ba 100644
--- a/drivers/irqchip/irq-gic-v3.c
+++ b/drivers/irqchip/irq-gic-v3.c
@@ -343,7 +343,7 @@ static u64 gic_mpidr_to_affinity(unsigned long mpidr)
}
#ifdef CONFIG_USE_ICC_SYSREGS_FOR_IRQFLAGS
-static bool gic_handle_nmi(struct pt_regs *regs)
+static bool __maybe_unused gic_handle_nmi(struct pt_regs *regs)
{
u64 irqnr;
struct pt_regs *old_regs;
@@ -393,12 +393,37 @@ static asmlinkage void __exception_irq_entry gic_handle_irq(struct pt_regs *regs
{
u32 irqnr;
+#if 1
+ local_irq_disable();
+
if (gic_handle_nmi(regs))
return;
+#endif
do {
irqnr = gic_read_iar();
+#if 0
+ printk_ratelimited(KERN_INFO "irqnr %d\n", irqnr);
+
+ if (unlikely(SMP_IPI_NMI_MASK & (1 << irqnr))) {
+ struct pt_regs *old_regs;
+
+ old_regs = set_irq_regs(regs);
+ nmi_enter();
+
+ gic_write_eoir(irqnr);
+ if (static_key_true(&supports_deactivate))
+ gic_write_dir(irqnr);
+
+ nmi_cpu_backtrace(regs);
+
+ nmi_exit();
+ set_irq_regs(old_regs);
+ continue;
+ }
+#endif
+
if (likely(irqnr > 15 && irqnr < 1020) || irqnr >= 8192) {
int err;
diff --git a/kernel/rcu/tree.c b/kernel/rcu/tree.c
index 50fee7689e71..6f1ce868969f 100644
--- a/kernel/rcu/tree.c
+++ b/kernel/rcu/tree.c
@@ -1474,6 +1474,7 @@ static void print_other_cpu_stall(struct rcu_state *rsp, unsigned long gpnum)
}
print_cpu_stall_info_end();
+ trigger_all_cpu_backtrace();
for_each_possible_cpu(cpu)
totqlen += per_cpu_ptr(rsp->rda, cpu)->qlen;
pr_cont("(detected by %d, t=%ld jiffies, g=%ld, c=%ld, q=%lu)\n",