2018-05-25 09:52:11

by Julien Thierry

[permalink] [raw]
Subject: [PATCH v4 00/26] arm64: provide pseudo NMI with GICv3

This series is a continuation of the work started by Daniel [1]. The goal
is to use GICv3 interrupt priorities to simulate an NMI.

To achieve this, set two priorities, one for standard interrupts and
another, higher priority, for NMIs. Whenever we want to disable interrupts,
we mask the standard priority instead so NMIs can still be raised. Some
corner cases though still require to actually mask all interrupts
effectively disabling the NMI.

Currently, only PPIs and SPIs can be set as NMIs. IPIs being currently
hardcoded IRQ numbers, there isn't a generic interface to set SGIs as NMI
for now. I don't think there is any reason LPIs should be allowed to be set
as NMI as they do not have an active state.
When an NMI is active on a CPU, no other NMI can be triggered on the CPU.

After the big refactoring I get performances similar to the ones I had
in v3[2], reposting old results here:

- "hackbench 200 process 1000" (average over 20 runs)
+-----------+----------+------------+------------------+
| | native | PMR guest | v4.17-rc6 guest |
+-----------+----------+------------+------------------+
| PMR host | 40.0336s | 39.3039s | 39.2044s |
| v4.17-rc6 | 40.4040s | 39.6011s | 39.1147s |
+-----------+----------+------------+------------------+

- Kernel build from defconfig:
PMR host: 13m45.743s
v4.17-rc6: 13m40.400s

I'll try to post more detailed benchmarks later if I find notable
differences with the previous version.


Requirements to use this:
- Have GICv3
- SCR_EL3.FIQ is set to 1 when linux runs or have single security state
- Select Kernel Feature -> Use ICC system registers for IRQ masking


* Patches 1 to 4 aim at applying some alternatives early in the boot
process, including the feature for priority masking.

* Patches 5 to 7 and 17 lightly refactor bits of GIC driver to make things
nicer for the rest of the series.

* Patches 8 to 10 and 16 ensure the logic of daifflags remains valid
after arch_local_irq flags use ICC_PMR_EL1.

* Patches 11 to 14 do some required PMR treatement in order for things to
work when the system uses priority masking.

* Patches 15, 18, 19, 20 and 21 actually make the changes to use
ICC_PMR_EL1 for priority masking/unmasking when disabling/enabling
interrupts.

* Patches 22 to 26 provide support for pseudo-NMI in the GICv3 driver
when priority masking is enabled.


Changes since V3[2]:
* Big refactoring. As suggested by Marc Z., some of the bigger patches
needed to be split into smaller one.

* Try to reduce the amount of #ifdef for the new feature by introducing
an individual cpufeature for priority masking

* Do not track which alternatives have been applied (was a bit dodgy
anyway), and use an alternative for VHE cpu_enable callback

* Fix a build failure with arm by adding the correct RPR accessors

* Added Suggested-by tags for changes from comming or inspired by Daniel's
series. Do let me know if you feel I missed something and am not giving
you due credit.

Changes since V2[3]:
* Series rebase to v4.17-rc6

* Adapt pathces 1 and 2 to the rework of cpufeatures framework

* Use the group0 detection scheme in the GICv3 driver to identify
the priority view, and drop the use of a fake interrupt

* Add the case for a GIC configured in a single security state

* Use local_daif_restore instead of local_irq_enable the first time
we enable interrupts after a bp hardening in the handling of a kernel
entry. Otherwise PRS.I remains set...

Changes since V1[4]:
* Series rebased to v4.15-rc8.

* Check for arm64_early_features in this_cpu_has_cap (spotted by Suzuki).

* Fix issue where debug exception were not masked when enabling debug in
mdscr_el1.

Changes since RFC[5]:
* The series was rebased to v4.15-rc2 which implied some changes mainly
related to the work on exception entries and daif flags by James Morse.

- The first patch in the previous series was dropped because no longer
applicable.

- With the semantics James introduced of "inheriting" daif flags,
handling of PMR on exception entry is simplified as PMR is not altered
by taking an exception and already inherited from previous state.

- James pointed out that taking a PseudoNMI before reading the FAR_EL1
register should not be allowed as per the TRM (D10.2.29):
"FAR_EL1 is made UNKNOWN on an exception return from EL1."
So in this submission PSR.I bit is cleared only after FAR_EL1 is read.

* For KVM, only deal with PMR unmasking/restoring in common code, and VHE
specific code makes sure PSR.I bit is set when necessary.

* When detecting the GIC priority view (patch 5), wait for an actual
interrupt instead of trying only once.


[1] http://www.spinics.net/lists/arm-kernel/msg525077.html
[2] https://lkml.org/lkml/2018/5/21/276
[3] https://lkml.org/lkml/2018/1/17/335
[4] https://www.spinics.net/lists/arm-kernel/msg620763.html
[5] https://www.spinics.net/lists/arm-kernel/msg610736.html

Cheers,

Julien

-->

Daniel Thompson (1):
arm64: alternative: Apply alternatives early in boot process

Julien Thierry (25):
arm64: cpufeature: Set SYSREG_GIC_CPUIF as a boot system feature
arm64: cpufeature: Add cpufeature for IRQ priority masking
arm64: cpufeature: Use alternatives for VHE cpu_enable
irqchip/gic: Unify GIC priority definitions
irqchip/gic: Lower priority of GIC interrupts
irqchip/gic-v3: Remove acknowledge loop
arm64: daifflags: Use irqflags functions for daifflags
arm64: Use daifflag_restore after bp_hardening
arm64: Delay daif masking for user return
arm64: Make PMR part of task context
arm64: Unmask PMR before going idle
arm/arm64: gic-v3: Add helper functions to manage IRQ priorities
arm64: kvm: Unmask PMR before entering guest
arm64: irqflags: Use ICC_PMR_EL1 for interrupt masking
arm64: daifflags: Include PMR in daifflags restore operations
irqchip/gic-v3: Factor group0 detection into functions
irqchip/gic-v3: Do not overwrite PMR value
irqchip/gic-v3: Switch to PMR masking after IRQ acknowledge
arm64: Switch to PMR masking when starting CPUs
arm64: Add build option for IRQ masking via priority
arm64: Detect current view of GIC priorities
irqchip/gic: Add functions to access irq priorities
irqchip/gic-v3: Add base support for pseudo-NMI
irqchip/gic-v3: Provide NMI handlers
irqchip/gic-v3: Allow interrupts to be set as pseudo-NMI

Documentation/arm64/booting.txt | 5 +
arch/arm/include/asm/arch_gicv3.h | 33 ++++
arch/arm64/Kconfig | 15 ++
arch/arm64/include/asm/alternative.h | 3 +-
arch/arm64/include/asm/arch_gicv3.h | 32 ++++
arch/arm64/include/asm/assembler.h | 17 +-
arch/arm64/include/asm/cpucaps.h | 3 +-
arch/arm64/include/asm/cpufeature.h | 2 +
arch/arm64/include/asm/daifflags.h | 32 ++--
arch/arm64/include/asm/efi.h | 3 +-
arch/arm64/include/asm/irqflags.h | 100 ++++++++---
arch/arm64/include/asm/kvm_host.h | 12 ++
arch/arm64/include/asm/processor.h | 1 +
arch/arm64/include/asm/ptrace.h | 13 +-
arch/arm64/kernel/alternative.c | 30 +++-
arch/arm64/kernel/asm-offsets.c | 1 +
arch/arm64/kernel/cpufeature.c | 35 +++-
arch/arm64/kernel/entry.S | 67 ++++++-
arch/arm64/kernel/head.S | 35 ++++
arch/arm64/kernel/process.c | 2 +
arch/arm64/kernel/smp.c | 12 ++
arch/arm64/kvm/hyp/switch.c | 17 ++
arch/arm64/mm/fault.c | 5 +-
arch/arm64/mm/proc.S | 18 ++
drivers/irqchip/irq-gic-common.c | 10 ++
drivers/irqchip/irq-gic-common.h | 2 +
drivers/irqchip/irq-gic-v3-its.c | 2 +-
drivers/irqchip/irq-gic-v3.c | 318 +++++++++++++++++++++++++++------
include/linux/interrupt.h | 1 +
include/linux/irqchip/arm-gic-common.h | 6 +
include/linux/irqchip/arm-gic.h | 5 -
31 files changed, 719 insertions(+), 118 deletions(-)

--
1.9.1


2018-05-25 09:52:23

by Julien Thierry

[permalink] [raw]
Subject: [PATCH v4 22/26] arm64: Detect current view of GIC priorities

The values non secure EL1 needs to use for PMR and RPR registers depends on
the value of SCR_EL3.FIQ.

The values non secure EL1 sees from the distributor and redistributor
depend on whether security is enabled for the GIC or not.

Figure out what values we are dealing with to know if the values we use for
PMR and RPR match the priority values that have been configured in the
distributor and redistributors.

Also, add firmware requirements related to SCR_EL3.

Signed-off-by: Julien Thierry <[email protected]>
Cc: Catalin Marinas <[email protected]>
Cc: Will Deacon <[email protected]>
Cc: Jonathan Corbet <[email protected]>
Cc: Thomas Gleixner <[email protected]>
Cc: Jason Cooper <[email protected]>
Cc: Marc Zyngier <[email protected]>
---
Documentation/arm64/booting.txt | 5 +++++
drivers/irqchip/irq-gic-v3.c | 42 +++++++++++++++++++++++++++++++++++------
2 files changed, 41 insertions(+), 6 deletions(-)

diff --git a/Documentation/arm64/booting.txt b/Documentation/arm64/booting.txt
index 8d0df62..e387938 100644
--- a/Documentation/arm64/booting.txt
+++ b/Documentation/arm64/booting.txt
@@ -188,6 +188,11 @@ Before jumping into the kernel, the following conditions must be met:
the kernel image will be entered must be initialised by software at a
higher exception level to prevent execution in an UNKNOWN state.

+ - SCR_EL3.FIQ must have the same value across all CPUs the kernel is
+ executing on.
+ - The value of SCR_EL3.FIQ must be the same as the one present at boot
+ time whenever the kernel is executing.
+
For systems with a GICv3 interrupt controller to be used in v3 mode:
- If EL3 is present:
ICC_SRE_EL3.Enable (bit 3) must be initialiased to 0b1.
diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c
index 2fd0440..b144f73 100644
--- a/drivers/irqchip/irq-gic-v3.c
+++ b/drivers/irqchip/irq-gic-v3.c
@@ -63,6 +63,28 @@ struct gic_chip_data {
static struct gic_chip_data gic_data __read_mostly;
static DEFINE_STATIC_KEY_TRUE(supports_deactivate_key);

+/*
+ * The behaviours of RPR and PMR registers differ depending on the value of
+ * SCR_EL3.FIQ, and the behaviour of non-secure priority registers of the
+ * distributor and redistributors depends on whether security is enabled in the
+ * GIC.
+ *
+ * When security is enabled, non-secure priority values from the (re)distributor
+ * are presented to the GIC CPUIF as follow:
+ * (GIC_(R)DIST_PRI[irq] >> 1) | 0x80;
+ *
+ * If SCR_EL3.FIQ == 1, the values writen to/read from PMR and RPR at non-secure
+ * EL1 are subject to a similar operation thus matching the priorities presented
+ * from the (re)distributor when security is enabled.
+ *
+ * see GICv3/GICv4 Architecture Specification (IHI0069D):
+ * - section 4.8.1 Non-secure accesses to register fields for Secure interrupt
+ * priorities.
+ * - Figure 4-7 Secure read of the priority field for a Non-secure Group 1
+ * interrupt.
+ */
+DEFINE_STATIC_KEY_FALSE(have_non_secure_prio_view);
+
static struct gic_kvm_info gic_v3_kvm_info;
static DEFINE_PER_CPU(bool, has_rss);

@@ -573,6 +595,12 @@ static void gic_update_vlpi_properties(void)
!gic_data.rdists.has_direct_lpi ? "no " : "");
}

+/* Check whether it's single security state view */
+static inline bool gic_dist_security_disabled(void)
+{
+ return readl_relaxed(gic_data.dist_base + GICD_CTLR) & GICD_CTLR_DS;
+}
+
static void gic_cpu_sys_reg_init(void)
{
int i, cpu = smp_processor_id();
@@ -598,6 +626,9 @@ static void gic_cpu_sys_reg_init(void)
/* Set priority mask register */
if (!arch_uses_gic_prios())
write_gicreg(DEFAULT_PMR_VALUE, ICC_PMR_EL1);
+ else if (static_branch_likely(&have_non_secure_prio_view) && group0)
+ /* Mismatch configuration with boot CPU */
+ WARN_ON(group0 && !gic_dist_security_disabled());

/*
* Some firmwares hand over to the kernel with the BPR changed from
@@ -850,12 +881,6 @@ static int gic_set_affinity(struct irq_data *d, const struct cpumask *mask_val,
#endif

#ifdef CONFIG_CPU_PM
-/* Check whether it's single security state view */
-static bool gic_dist_security_disabled(void)
-{
- return readl_relaxed(gic_data.dist_base + GICD_CTLR) & GICD_CTLR_DS;
-}
-
static int gic_cpu_pm_notifier(struct notifier_block *self,
unsigned long cmd, void *v)
{
@@ -1155,6 +1180,11 @@ static int __init gic_init_bases(void __iomem *dist_base,
gic_cpu_init();
gic_cpu_pm_init();

+ if (arch_uses_gic_prios()) {
+ if (!gic_has_group0() || gic_dist_security_disabled())
+ static_branch_enable(&have_non_secure_prio_view);
+ }
+
return 0;

out_free:
--
1.9.1


2018-05-25 09:53:09

by Julien Thierry

[permalink] [raw]
Subject: [PATCH v4 23/26] irqchip/gic: Add functions to access irq priorities

Add accessors to the GIC distributor/redistributors priority registers.

Signed-off-by: Julien Thierry <[email protected]>
Cc: Thomas Gleixner <[email protected]>
Cc: Jason Cooper <[email protected]>
Cc: Marc Zyngier <[email protected]>
---
drivers/irqchip/irq-gic-common.c | 10 ++++++++++
drivers/irqchip/irq-gic-common.h | 2 ++
2 files changed, 12 insertions(+)

diff --git a/drivers/irqchip/irq-gic-common.c b/drivers/irqchip/irq-gic-common.c
index 01e673c..910746f 100644
--- a/drivers/irqchip/irq-gic-common.c
+++ b/drivers/irqchip/irq-gic-common.c
@@ -98,6 +98,16 @@ int gic_configure_irq(unsigned int irq, unsigned int type,
return ret;
}

+void gic_set_irq_prio(unsigned int irq, void __iomem *base, u8 prio)
+{
+ writeb_relaxed(prio, base + GIC_DIST_PRI + irq);
+}
+
+u8 gic_get_irq_prio(unsigned int irq, void __iomem *base)
+{
+ return readb_relaxed(base + GIC_DIST_PRI + irq);
+}
+
void gic_dist_config(void __iomem *base, int gic_irqs,
void (*sync_access)(void))
{
diff --git a/drivers/irqchip/irq-gic-common.h b/drivers/irqchip/irq-gic-common.h
index 3919cd7..1586dbd 100644
--- a/drivers/irqchip/irq-gic-common.h
+++ b/drivers/irqchip/irq-gic-common.h
@@ -35,6 +35,8 @@ void gic_dist_config(void __iomem *base, int gic_irqs,
void gic_cpu_config(void __iomem *base, void (*sync_access)(void));
void gic_enable_quirks(u32 iidr, const struct gic_quirk *quirks,
void *data);
+void gic_set_irq_prio(unsigned int irq, void __iomem *base, u8 prio);
+u8 gic_get_irq_prio(unsigned int irq, void __iomem *base);

void gic_set_kvm_info(const struct gic_kvm_info *info);

--
1.9.1


2018-05-25 09:53:14

by Julien Thierry

[permalink] [raw]
Subject: [PATCH v4 24/26] irqchip/gic-v3: Add base support for pseudo-NMI

Provide a higher priority to be used for pseudo-NMIs. When such an
interrupt is received, enter the NMI state and prevent other NMIs to
be raised.

When returning from a pseudo-NMI, skip preemption and tracing if the
interrupted context has interrupts disabled.

Signed-off-by: Julien Thierry <[email protected]>
Cc: Russell King <[email protected]>
Cc: Catalin Marinas <[email protected]>
Cc: Will Deacon <[email protected]>
Cc: Thomas Gleixner <[email protected]>
Cc: Jason Cooper <[email protected]>
Cc: Marc Zyngier <[email protected]>
---
arch/arm/include/asm/arch_gicv3.h | 6 ++++++
arch/arm64/include/asm/arch_gicv3.h | 6 ++++++
arch/arm64/kernel/entry.S | 43 +++++++++++++++++++++++++++++++++++++
drivers/irqchip/irq-gic-v3.c | 41 +++++++++++++++++++++++++++++++++++
4 files changed, 96 insertions(+)

diff --git a/arch/arm/include/asm/arch_gicv3.h b/arch/arm/include/asm/arch_gicv3.h
index b39d620..1ed0476 100644
--- a/arch/arm/include/asm/arch_gicv3.h
+++ b/arch/arm/include/asm/arch_gicv3.h
@@ -374,5 +374,11 @@ static inline void gic_start_pmr_masking(void)
WARN_ON(true);
}

+static inline void gic_set_nmi_active(void)
+{
+ /* Should not get called */
+ WARN_ON(true);
+}
+
#endif /* !__ASSEMBLY__ */
#endif /* !__ASM_ARCH_GICV3_H */
diff --git a/arch/arm64/include/asm/arch_gicv3.h b/arch/arm64/include/asm/arch_gicv3.h
index 23c88ac0..3196cf1 100644
--- a/arch/arm64/include/asm/arch_gicv3.h
+++ b/arch/arm64/include/asm/arch_gicv3.h
@@ -166,5 +166,11 @@ static inline void gic_start_pmr_masking(void)
asm volatile ("msr daifclr, #2" : : : "memory");
}

+/* Notify an NMI is active, blocking other NMIs */
+static inline void gic_set_nmi_active(void)
+{
+ asm volatile ("msr daifset, #2" : : : "memory");
+}
+
#endif /* __ASSEMBLY__ */
#endif /* __ASM_ARCH_GICV3_H */
diff --git a/arch/arm64/kernel/entry.S b/arch/arm64/kernel/entry.S
index f56f27e..0d0c829 100644
--- a/arch/arm64/kernel/entry.S
+++ b/arch/arm64/kernel/entry.S
@@ -391,6 +391,16 @@ alternative_insn eret, nop, ARM64_UNMAP_KERNEL_AT_EL0
mov sp, x19
.endm

+ /* Should be checked on return from irq handlers */
+ .macro branch_if_was_nmi, tmp, target
+ alternative_if ARM64_HAS_IRQ_PRIO_MASKING
+ mrs \tmp, daif
+ alternative_else
+ mov \tmp, #0
+ alternative_endif
+ tbnz \tmp, #7, \target // Exiting an NMI
+ .endm
+
/*
* These are the registers used in the syscall handler, and allow us to
* have in theory up to 7 arguments to a function - x0 to x6.
@@ -611,12 +621,30 @@ ENDPROC(el1_sync)
el1_irq:
kernel_entry 1
enable_da_f
+
#ifdef CONFIG_TRACE_IRQFLAGS
+#ifdef CONFIG_USE_ICC_SYSREGS_FOR_IRQFLAGS
+ ldr x20, [sp, #S_PMR_SAVE]
+ /* Irqs were disabled, don't trace */
+ tbz x20, ICC_PMR_EL1_EN_SHIFT, 1f
+#endif
bl trace_hardirqs_off
+1:
#endif

irq_handler

+#ifdef CONFIG_USE_ICC_SYSREGS_FOR_IRQFLAGS
+ /*
+ * Irqs were disabled, we have an nmi.
+ * We might have interrupted a context with interrupt disabled that set
+ * NEED_RESCHED flag.
+ * Skip preemption and irq tracing if needed.
+ */
+ tbz x20, ICC_PMR_EL1_EN_SHIFT, untraced_irq_exit
+ branch_if_was_nmi x0, skip_preempt
+#endif
+
#ifdef CONFIG_PREEMPT
ldr w24, [tsk, #TSK_TI_PREEMPT] // get preempt count
cbnz w24, 1f // preempt count != 0
@@ -625,9 +653,13 @@ el1_irq:
bl el1_preempt
1:
#endif
+
+skip_preempt:
#ifdef CONFIG_TRACE_IRQFLAGS
bl trace_hardirqs_on
#endif
+
+untraced_irq_exit:
kernel_exit 1
ENDPROC(el1_irq)

@@ -858,6 +890,9 @@ el0_irq_naked:
#ifdef CONFIG_TRACE_IRQFLAGS
bl trace_hardirqs_on
#endif
+
+ branch_if_was_nmi x2, nmi_ret_to_user
+
b ret_to_user
ENDPROC(el0_irq)

@@ -1353,3 +1388,11 @@ alternative_else_nop_endif
ENDPROC(__sdei_asm_handler)
NOKPROBE(__sdei_asm_handler)
#endif /* CONFIG_ARM_SDE_INTERFACE */
+
+/*
+ * NMI return path to EL0
+ */
+nmi_ret_to_user:
+ ldr x1, [tsk, #TSK_TI_FLAGS]
+ b finish_ret_to_user
+ENDPROC(nmi_ret_to_user)
diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c
index b144f73..4be5996 100644
--- a/drivers/irqchip/irq-gic-v3.c
+++ b/drivers/irqchip/irq-gic-v3.c
@@ -41,6 +41,8 @@

#include "irq-gic-common.h"

+#define GICD_INT_NMI_PRI 0xa0
+
struct redist_region {
void __iomem *redist_base;
phys_addr_t phys_base;
@@ -253,6 +255,12 @@ static inline bool arch_uses_gic_prios(void)
return IS_ENABLED(CONFIG_USE_ICC_SYSREGS_FOR_IRQFLAGS);
}

+static inline bool gic_supports_nmi(void)
+{
+ return arch_uses_gic_prios()
+ && static_branch_likely(&have_non_secure_prio_view);
+}
+
static int gic_irq_set_irqchip_state(struct irq_data *d,
enum irqchip_irq_state which, bool val)
{
@@ -371,6 +379,20 @@ static u64 gic_mpidr_to_affinity(unsigned long mpidr)
return aff;
}

+static void do_handle_nmi(unsigned int hwirq, struct pt_regs *regs)
+{
+ struct pt_regs *old_regs = set_irq_regs(regs);
+ unsigned int irq;
+
+ nmi_enter();
+
+ irq = irq_find_mapping(gic_data.domain, hwirq);
+ generic_handle_irq(irq);
+
+ nmi_exit();
+ set_irq_regs(old_regs);
+}
+
static asmlinkage void __exception_irq_entry gic_handle_irq(struct pt_regs *regs)
{
u32 irqnr;
@@ -386,6 +408,23 @@ static asmlinkage void __exception_irq_entry gic_handle_irq(struct pt_regs *regs
if (likely(irqnr > 15 && irqnr < 1020) || irqnr >= 8192) {
int err;

+ if (gic_supports_nmi()
+ && unlikely(gic_read_rpr() == GICD_INT_NMI_PRI)) {
+ /*
+ * We need to prevent other NMIs to occur even after a
+ * priority drop.
+ * We keep I flag set until cpsr is restored from
+ * kernel_exit.
+ */
+ gic_set_nmi_active();
+
+ if (static_branch_likely(&supports_deactivate_key))
+ gic_write_eoir(irqnr);
+
+ do_handle_nmi(irqnr, regs);
+ return;
+ }
+
if (static_branch_likely(&supports_deactivate_key))
gic_write_eoir(irqnr);
else if (!arch_uses_gic_prios())
@@ -1183,6 +1222,8 @@ static int __init gic_init_bases(void __iomem *dist_base,
if (arch_uses_gic_prios()) {
if (!gic_has_group0() || gic_dist_security_disabled())
static_branch_enable(&have_non_secure_prio_view);
+ else
+ pr_warn("SCR_EL3.FIQ set, cannot enable use of pseudo-NMIs\n");
}

return 0;
--
1.9.1


2018-05-25 09:53:26

by Julien Thierry

[permalink] [raw]
Subject: [PATCH v4 26/26] irqchip/gic-v3: Allow interrupts to be set as pseudo-NMI

Provide a way to set a GICv3 interrupt as pseudo-NMI. The interrupt
must not be enabled when setting/clearing the NMI status of the interrupt.

Signed-off-by: Julien Thierry <[email protected]>
Cc: Thomas Gleixner <[email protected]>
Cc: Jason Cooper <[email protected]>
Cc: Marc Zyngier <[email protected]>
---
drivers/irqchip/irq-gic-v3.c | 54 ++++++++++++++++++++++++++++++++++++++++++++
include/linux/interrupt.h | 1 +
2 files changed, 55 insertions(+)

diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c
index fa23d12..cea1000 100644
--- a/drivers/irqchip/irq-gic-v3.c
+++ b/drivers/irqchip/irq-gic-v3.c
@@ -305,6 +305,43 @@ static void handle_percpu_devid_nmi(struct irq_desc *desc)
chip->irq_eoi(&desc->irq_data);
}

+static int gic_irq_set_irqchip_prio(struct irq_data *d, bool val)
+{
+ u8 prio;
+ irq_flow_handler_t handler;
+
+ if (gic_peek_irq(d, GICD_ISENABLER)) {
+ pr_err("Cannot set NMI property of enabled IRQ %u\n", d->irq);
+ return -EPERM;
+ }
+
+ if (val) {
+ prio = GICD_INT_NMI_PRI;
+
+ if (gic_irq(d) < 32)
+ handler = handle_percpu_devid_nmi;
+ else
+ handler = handle_fasteoi_nmi;
+ } else {
+ prio = GICD_INT_DEF_PRI;
+
+ if (gic_irq(d) < 32)
+ handler = handle_percpu_devid_irq;
+ else
+ handler = handle_fasteoi_irq;
+ }
+
+ /*
+ * Already in a locked context for the desc from calling
+ * irq_set_irq_chip_state.
+ * It should be safe to simply modify the handler.
+ */
+ irq_to_desc(d->irq)->handle_irq = handler;
+ gic_set_irq_prio(gic_irq(d), gic_dist_base(d), prio);
+
+ return 0;
+}
+
static int gic_irq_set_irqchip_state(struct irq_data *d,
enum irqchip_irq_state which, bool val)
{
@@ -326,6 +363,16 @@ static int gic_irq_set_irqchip_state(struct irq_data *d,
reg = val ? GICD_ICENABLER : GICD_ISENABLER;
break;

+ case IRQCHIP_STATE_NMI:
+ if (gic_supports_nmi()) {
+ return gic_irq_set_irqchip_prio(d, val);
+ } else if (val) {
+ pr_warn("Failed to set IRQ %u as NMI, NMIs are unsupported\n",
+ gic_irq(d));
+ return -EINVAL;
+ }
+ return 0;
+
default:
return -EINVAL;
}
@@ -353,6 +400,13 @@ static int gic_irq_get_irqchip_state(struct irq_data *d,
*val = !gic_peek_irq(d, GICD_ISENABLER);
break;

+ case IRQCHIP_STATE_NMI:
+ if (!gic_supports_nmi())
+ return -EINVAL;
+ *val = (gic_get_irq_prio(gic_irq(d), gic_dist_base(d)) ==
+ GICD_INT_NMI_PRI);
+ break;
+
default:
return -EINVAL;
}
diff --git a/include/linux/interrupt.h b/include/linux/interrupt.h
index 5426627..02c794f 100644
--- a/include/linux/interrupt.h
+++ b/include/linux/interrupt.h
@@ -419,6 +419,7 @@ enum irqchip_irq_state {
IRQCHIP_STATE_ACTIVE, /* Is interrupt in progress? */
IRQCHIP_STATE_MASKED, /* Is interrupt masked? */
IRQCHIP_STATE_LINE_LEVEL, /* Is IRQ line high? */
+ IRQCHIP_STATE_NMI, /* Is IRQ an NMI? */
};

extern int irq_get_irqchip_state(unsigned int irq, enum irqchip_irq_state which,
--
1.9.1


2018-05-25 09:54:31

by Julien Thierry

[permalink] [raw]
Subject: [PATCH v4 25/26] irqchip/gic-v3: Provide NMI handlers

Provide irqchip handlers that are NMI safe for PPIs and SPIs.

Signed-off-by: Julien Thierry <[email protected]>
Cc: Thomas Gleixner <[email protected]>
Cc: Jason Cooper <[email protected]>
Cc: Marc Zyngier <[email protected]>
---
drivers/irqchip/irq-gic-v3.c | 44 ++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 44 insertions(+)

diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c
index 4be5996..fa23d12 100644
--- a/drivers/irqchip/irq-gic-v3.c
+++ b/drivers/irqchip/irq-gic-v3.c
@@ -34,6 +34,8 @@
#include <linux/irqchip/arm-gic-v3.h>
#include <linux/irqchip/irq-partition-percpu.h>

+#include <trace/events/irq.h>
+
#include <asm/cputype.h>
#include <asm/exception.h>
#include <asm/smp_plat.h>
@@ -261,6 +263,48 @@ static inline bool gic_supports_nmi(void)
&& static_branch_likely(&have_non_secure_prio_view);
}

+/*
+ * Chip flow handler for SPIs set as NMI
+ */
+static void handle_fasteoi_nmi(struct irq_desc *desc)
+{
+ struct irq_chip *chip = irq_desc_get_chip(desc);
+ struct irqaction *action = desc->action;
+ unsigned int irq = irq_desc_get_irq(desc);
+ irqreturn_t res;
+
+ if (chip->irq_ack)
+ chip->irq_ack(&desc->irq_data);
+
+ trace_irq_handler_entry(irq, action);
+ res = action->handler(irq, action->dev_id);
+ trace_irq_handler_exit(irq, action, res);
+
+ if (chip->irq_eoi)
+ chip->irq_eoi(&desc->irq_data);
+}
+
+/*
+ * Chip flow handler for PPIs set as NMI
+ */
+static void handle_percpu_devid_nmi(struct irq_desc *desc)
+{
+ struct irq_chip *chip = irq_desc_get_chip(desc);
+ struct irqaction *action = desc->action;
+ unsigned int irq = irq_desc_get_irq(desc);
+ irqreturn_t res;
+
+ if (chip->irq_ack)
+ chip->irq_ack(&desc->irq_data);
+
+ trace_irq_handler_entry(irq, action);
+ res = action->handler(irq, raw_cpu_ptr(action->percpu_dev_id));
+ trace_irq_handler_exit(irq, action, res);
+
+ if (chip->irq_eoi)
+ chip->irq_eoi(&desc->irq_data);
+}
+
static int gic_irq_set_irqchip_state(struct irq_data *d,
enum irqchip_irq_state which, bool val)
{
--
1.9.1


2018-05-25 09:54:54

by Julien Thierry

[permalink] [raw]
Subject: [PATCH v4 18/26] irqchip/gic-v3: Do not overwrite PMR value

If the architecture is using ICC_PMR_EL1 to mask IRQs, do not overwrite
that value.

Signed-off-by: Julien Thierry <[email protected]>
Cc: Thomas Gleixner <[email protected]>
Cc: Jason Cooper <[email protected]>
Cc: Marc Zyngier <[email protected]>
---
drivers/irqchip/irq-gic-v3.c | 13 ++++++++++++-
1 file changed, 12 insertions(+), 1 deletion(-)

diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c
index 13d283d..fc477e2 100644
--- a/drivers/irqchip/irq-gic-v3.c
+++ b/drivers/irqchip/irq-gic-v3.c
@@ -226,6 +226,11 @@ static void gic_unmask_irq(struct irq_data *d)
gic_poke_irq(d, GICD_ISENABLER);
}

+static inline bool arch_uses_gic_prios(void)
+{
+ return IS_ENABLED(CONFIG_USE_ICC_SYSREGS_FOR_IRQFLAGS);
+}
+
static int gic_irq_set_irqchip_state(struct irq_data *d,
enum irqchip_irq_state which, bool val)
{
@@ -404,6 +409,9 @@ static u32 gic_get_pribits(void)
static bool gic_has_group0(void)
{
u32 val;
+ u32 old_pmr;
+
+ old_pmr = gic_read_pmr();

/*
* Let's find out if Group0 is under control of EL3 or not by
@@ -419,6 +427,8 @@ static bool gic_has_group0(void)
gic_write_pmr(BIT(8 - gic_get_pribits()));
val = gic_read_pmr();

+ gic_write_pmr(old_pmr);
+
return val != 0;
}

@@ -580,7 +590,8 @@ static void gic_cpu_sys_reg_init(void)
group0 = gic_has_group0();

/* Set priority mask register */
- write_gicreg(DEFAULT_PMR_VALUE, ICC_PMR_EL1);
+ if (!arch_uses_gic_prios())
+ write_gicreg(DEFAULT_PMR_VALUE, ICC_PMR_EL1);

/*
* Some firmwares hand over to the kernel with the BPR changed from
--
1.9.1


2018-05-25 09:54:56

by Julien Thierry

[permalink] [raw]
Subject: [PATCH v4 19/26] irqchip/gic-v3: Switch to PMR masking after IRQ acknowledge

After an interrupt has been acknowledged, mask the IRQ priority through
PMR and clear PSR.I bit, allowing higher priority interrupts to be
received during interrupt handling.

Signed-off-by: Julien Thierry <[email protected]>
Cc: Russell King <[email protected]>
Cc: Catalin Marinas <[email protected]>
Cc: Will Deacon <[email protected]>
Cc: Thomas Gleixner <[email protected]>
Cc: Jason Cooper <[email protected]>
Cc: Marc Zyngier <[email protected]>
---
arch/arm/include/asm/arch_gicv3.h | 6 ++++++
arch/arm64/include/asm/arch_gicv3.h | 6 ++++++
drivers/irqchip/irq-gic-v3.c | 8 +++++++-
3 files changed, 19 insertions(+), 1 deletion(-)

diff --git a/arch/arm/include/asm/arch_gicv3.h b/arch/arm/include/asm/arch_gicv3.h
index 58d5d3e..b39d620 100644
--- a/arch/arm/include/asm/arch_gicv3.h
+++ b/arch/arm/include/asm/arch_gicv3.h
@@ -368,5 +368,11 @@ static inline bool gic_prio_masking_enabled(void)
return false;
}

+static inline void gic_start_pmr_masking(void)
+{
+ /* Should not get called */
+ WARN_ON(true);
+}
+
#endif /* !__ASSEMBLY__ */
#endif /* !__ASM_ARCH_GICV3_H */
diff --git a/arch/arm64/include/asm/arch_gicv3.h b/arch/arm64/include/asm/arch_gicv3.h
index 98b09db..23c88ac0 100644
--- a/arch/arm64/include/asm/arch_gicv3.h
+++ b/arch/arm64/include/asm/arch_gicv3.h
@@ -160,5 +160,11 @@ static inline bool gic_prio_masking_enabled(void)
return cpus_have_const_cap(ARM64_HAS_IRQ_PRIO_MASKING);
}

+static inline void gic_start_pmr_masking(void)
+{
+ gic_write_pmr(ICC_PMR_EL1_MASKED);
+ asm volatile ("msr daifclr, #2" : : : "memory");
+}
+
#endif /* __ASSEMBLY__ */
#endif /* __ASM_ARCH_GICV3_H */
diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c
index fc477e2..2fd0440 100644
--- a/drivers/irqchip/irq-gic-v3.c
+++ b/drivers/irqchip/irq-gic-v3.c
@@ -355,12 +355,18 @@ static asmlinkage void __exception_irq_entry gic_handle_irq(struct pt_regs *regs

irqnr = gic_read_iar();

+ if (arch_uses_gic_prios()) {
+ isb();
+ /* Masking IRQs earlier would prevent to ack the current interrupt */
+ gic_start_pmr_masking();
+ }
+
if (likely(irqnr > 15 && irqnr < 1020) || irqnr >= 8192) {
int err;

if (static_branch_likely(&supports_deactivate_key))
gic_write_eoir(irqnr);
- else
+ else if (!arch_uses_gic_prios())
isb();

err = handle_domain_irq(gic_data.domain, irqnr, regs);
--
1.9.1


2018-05-25 09:55:07

by Julien Thierry

[permalink] [raw]
Subject: [PATCH v4 15/26] arm64: irqflags: Use ICC_PMR_EL1 for interrupt masking

Instead disabling interrupts by setting the PSR.I bit, use a priority
higher than the one used for interrupts to mask them via PMR.

The value chosen for PMR to enable/disable interrupts encodes the status
of interrupts on a single bit. This information is stored in the irqflags
values used when saving/restoring IRQ status.

Signed-off-by: Julien Thierry <[email protected]>
Suggested-by: Daniel Thompson <[email protected]>
Cc: Catalin Marinas <[email protected]>
Cc: Will Deacon <[email protected]>
Cc: Ard Biesheuvel <[email protected]>
Cc: Oleg Nesterov <[email protected]>
---
arch/arm64/include/asm/assembler.h | 17 ++++++-
arch/arm64/include/asm/efi.h | 3 +-
arch/arm64/include/asm/irqflags.h | 97 ++++++++++++++++++++++++++++++--------
arch/arm64/include/asm/ptrace.h | 10 ++--
arch/arm64/kernel/entry.S | 6 +--
5 files changed, 104 insertions(+), 29 deletions(-)

diff --git a/arch/arm64/include/asm/assembler.h b/arch/arm64/include/asm/assembler.h
index 0bcc98d..0b2dcfd 100644
--- a/arch/arm64/include/asm/assembler.h
+++ b/arch/arm64/include/asm/assembler.h
@@ -23,6 +23,7 @@
#ifndef __ASM_ASSEMBLER_H
#define __ASM_ASSEMBLER_H

+#include <asm/alternative.h>
#include <asm/asm-offsets.h>
#include <asm/cpufeature.h>
#include <asm/debug-monitors.h>
@@ -62,12 +63,24 @@
/*
* Enable and disable interrupts.
*/
- .macro disable_irq
+ .macro disable_irq, tmp
+ mov \tmp, #ICC_PMR_EL1_MASKED
+alternative_if_not ARM64_HAS_IRQ_PRIO_MASKING
msr daifset, #2
+alternative_else
+ msr_s SYS_ICC_PMR_EL1, \tmp
+alternative_endif
.endm

- .macro enable_irq
+ .macro enable_irq, tmp
+ mov \tmp, #ICC_PMR_EL1_UNMASKED
+alternative_if_not ARM64_HAS_IRQ_PRIO_MASKING
msr daifclr, #2
+ nop
+alternative_else
+ msr_s SYS_ICC_PMR_EL1, \tmp
+ dsb sy
+alternative_endif
.endm

.macro save_and_disable_irq, flags
diff --git a/arch/arm64/include/asm/efi.h b/arch/arm64/include/asm/efi.h
index 192d791..a4e0730 100644
--- a/arch/arm64/include/asm/efi.h
+++ b/arch/arm64/include/asm/efi.h
@@ -42,7 +42,8 @@

efi_status_t __efi_rt_asm_wrapper(void *, const char *, ...);

-#define ARCH_EFI_IRQ_FLAGS_MASK (PSR_D_BIT | PSR_A_BIT | PSR_I_BIT | PSR_F_BIT)
+#define ARCH_EFI_IRQ_FLAGS_MASK \
+ (PSR_D_BIT | PSR_A_BIT | PSR_I_BIT | PSR_F_BIT | ARCH_FLAG_PMR_EN)

/* arch specific definitions used by the stub code */

diff --git a/arch/arm64/include/asm/irqflags.h b/arch/arm64/include/asm/irqflags.h
index 24692ed..193cfd0 100644
--- a/arch/arm64/include/asm/irqflags.h
+++ b/arch/arm64/include/asm/irqflags.h
@@ -18,7 +18,27 @@

#ifdef __KERNEL__

+#include <asm/alternative.h>
+#include <asm/cpufeature.h>
#include <asm/ptrace.h>
+#include <asm/sysreg.h>
+
+
+/*
+ * When ICC_PMR_EL1 is used for interrupt masking, only the bit indicating
+ * whether the normal interrupts are masked is kept along with the daif
+ * flags.
+ */
+#define ARCH_FLAG_PMR_EN 0x1
+
+#define MAKE_ARCH_FLAGS(daif, pmr) \
+ ((daif) | (((pmr) >> ICC_PMR_EL1_EN_SHIFT) & ARCH_FLAG_PMR_EN))
+
+#define ARCH_FLAGS_GET_PMR(flags) \
+ ((((flags) & ARCH_FLAG_PMR_EN) << ICC_PMR_EL1_EN_SHIFT) \
+ | ICC_PMR_EL1_MASKED)
+
+#define ARCH_FLAGS_GET_DAIF(flags) ((flags) & ~ARCH_FLAG_PMR_EN)

/*
* Aarch64 has flags for masking: Debug, Asynchronous (serror), Interrupts and
@@ -38,31 +58,50 @@
*/
static inline unsigned long arch_local_irq_save(void)
{
- unsigned long flags;
- asm volatile(
+ unsigned long flags, masked = ICC_PMR_EL1_MASKED;
+ unsigned long pmr = 0;
+
+ asm volatile(ALTERNATIVE(
"mrs %0, daif // arch_local_irq_save\n"
- "msr daifset, #2"
- : "=r" (flags)
- :
+ "msr daifset, #2\n"
+ "mov %1, #" __stringify(ICC_PMR_EL1_UNMASKED),
+ /* --- */
+ "mrs %0, daif\n"
+ "mrs_s %1, " __stringify(SYS_ICC_PMR_EL1) "\n"
+ "msr_s " __stringify(SYS_ICC_PMR_EL1) ", %2",
+ ARM64_HAS_IRQ_PRIO_MASKING)
+ : "=&r" (flags), "=&r" (pmr)
+ : "r" (masked)
: "memory");
- return flags;
+
+ return MAKE_ARCH_FLAGS(flags, pmr);
}

static inline void arch_local_irq_enable(void)
{
- asm volatile(
- "msr daifclr, #2 // arch_local_irq_enable"
- :
+ unsigned long unmasked = ICC_PMR_EL1_UNMASKED;
+
+ asm volatile(ALTERNATIVE(
+ "msr daifclr, #2 // arch_local_irq_enable\n"
+ "nop",
+ "msr_s " __stringify(SYS_ICC_PMR_EL1) ",%0\n"
+ "dsb sy",
+ ARM64_HAS_IRQ_PRIO_MASKING)
:
+ : "r" (unmasked)
: "memory");
}

static inline void arch_local_irq_disable(void)
{
- asm volatile(
- "msr daifset, #2 // arch_local_irq_disable"
- :
+ unsigned long masked = ICC_PMR_EL1_MASKED;
+
+ asm volatile(ALTERNATIVE(
+ "msr daifset, #2 // arch_local_irq_disable",
+ "msr_s " __stringify(SYS_ICC_PMR_EL1) ",%0",
+ ARM64_HAS_IRQ_PRIO_MASKING)
:
+ : "r" (masked)
: "memory");
}

@@ -72,12 +111,19 @@ static inline void arch_local_irq_disable(void)
static inline unsigned long arch_local_save_flags(void)
{
unsigned long flags;
- asm volatile(
- "mrs %0, daif // arch_local_save_flags"
- : "=r" (flags)
+ unsigned long pmr = 0;
+
+ asm volatile(ALTERNATIVE(
+ "mrs %0, daif // arch_local_save_flags\n"
+ "mov %1, #" __stringify(ICC_PMR_EL1_UNMASKED),
+ "mrs %0, daif\n"
+ "mrs_s %1, " __stringify(SYS_ICC_PMR_EL1),
+ ARM64_HAS_IRQ_PRIO_MASKING)
+ : "=r" (flags), "=r" (pmr)
:
: "memory");
- return flags;
+
+ return MAKE_ARCH_FLAGS(flags, pmr);
}

/*
@@ -85,16 +131,27 @@ static inline unsigned long arch_local_save_flags(void)
*/
static inline void arch_local_irq_restore(unsigned long flags)
{
- asm volatile(
- "msr daif, %0 // arch_local_irq_restore"
+ unsigned long pmr = ARCH_FLAGS_GET_PMR(flags);
+
+ flags = ARCH_FLAGS_GET_DAIF(flags);
+
+ asm volatile(ALTERNATIVE(
+ "msr daif, %0 // arch_local_irq_restore\n"
+ "nop\n"
+ "nop",
+ "msr daif, %0\n"
+ "msr_s " __stringify(SYS_ICC_PMR_EL1) ",%1\n"
+ "dsb sy",
+ ARM64_HAS_IRQ_PRIO_MASKING)
:
- : "r" (flags)
+ : "r" (flags), "r" (pmr)
: "memory");
}

static inline int arch_irqs_disabled_flags(unsigned long flags)
{
- return flags & PSR_I_BIT;
+ return (ARCH_FLAGS_GET_DAIF(flags) & (PSR_I_BIT)) |
+ !(ARCH_FLAGS_GET_PMR(flags) & ICC_PMR_EL1_EN_BIT);
}
#endif
#endif
diff --git a/arch/arm64/include/asm/ptrace.h b/arch/arm64/include/asm/ptrace.h
index e87aef7..3ec58a4 100644
--- a/arch/arm64/include/asm/ptrace.h
+++ b/arch/arm64/include/asm/ptrace.h
@@ -25,8 +25,11 @@
#define CurrentEL_EL1 (1 << 2)
#define CurrentEL_EL2 (2 << 2)

-/* PMR value use to unmask interrupts */
+/* PMR values used to mask/unmask interrupts */
#define ICC_PMR_EL1_UNMASKED 0xf0
+#define ICC_PMR_EL1_EN_SHIFT 6
+#define ICC_PMR_EL1_EN_BIT (1 << ICC_PMR_EL1_EN_SHIFT) // PMR IRQ enable
+#define ICC_PMR_EL1_MASKED (ICC_PMR_EL1_UNMASKED ^ ICC_PMR_EL1_EN_BIT)

/* AArch32-specific ptrace requests */
#define COMPAT_PTRACE_GETREGS 12
@@ -174,8 +177,9 @@ static inline void forget_syscall(struct pt_regs *regs)
#define processor_mode(regs) \
((regs)->pstate & PSR_MODE_MASK)

-#define interrupts_enabled(regs) \
- (!((regs)->pstate & PSR_I_BIT))
+#define interrupts_enabled(regs) \
+ ((!((regs)->pstate & PSR_I_BIT)) && \
+ ((regs)->pmr_save & ICC_PMR_EL1_EN_BIT))

#define fast_interrupts_enabled(regs) \
(!((regs)->pstate & PSR_F_BIT))
diff --git a/arch/arm64/kernel/entry.S b/arch/arm64/kernel/entry.S
index 78e4ff4..f56f27e 100644
--- a/arch/arm64/kernel/entry.S
+++ b/arch/arm64/kernel/entry.S
@@ -888,7 +888,7 @@ ENDPROC(el0_error)
* and this includes saving x0 back into the kernel stack.
*/
ret_fast_syscall:
- disable_irq // disable interrupts
+ disable_irq x21 // disable interrupts
str x0, [sp, #S_X0] // returned x0
ldr x1, [tsk, #TSK_TI_FLAGS] // re-check for syscall tracing
and x2, x1, #_TIF_SYSCALL_WORK
@@ -898,7 +898,7 @@ ret_fast_syscall:
enable_step_tsk x1, x2
kernel_exit 0
ret_fast_syscall_trace:
- enable_irq // enable interrupts
+ enable_irq x0 // enable interrupts
b __sys_trace_return_skipped // we already saved x0

/*
@@ -916,7 +916,7 @@ work_pending:
* "slow" syscall return path.
*/
ret_to_user:
- disable_irq // disable interrupts
+ disable_irq x21 // disable interrupts
ldr x1, [tsk, #TSK_TI_FLAGS]
and x2, x1, #_TIF_WORK_MASK
cbnz x2, work_pending
--
1.9.1


2018-05-25 09:55:20

by Julien Thierry

[permalink] [raw]
Subject: [PATCH v4 21/26] arm64: Add build option for IRQ masking via priority

Provide a build option to enable using GICv3 priorities to enable/disable
interrupts.

Signed-off-by: Julien Thierry <[email protected]>
Suggested-by: Daniel Thompson <[email protected]>
Cc: Catalin Marinas <[email protected]>
Cc: Will Deacon <[email protected]>
---
arch/arm64/Kconfig | 15 +++++++++++++++
1 file changed, 15 insertions(+)

diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index eb2cf49..ab214b9 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -938,6 +938,21 @@ config HARDEN_EL2_VECTORS

If unsure, say Y.

+config USE_ICC_SYSREGS_FOR_IRQFLAGS
+ bool "Use ICC system registers for IRQ masking"
+ select CONFIG_ARM_GIC_V3
+ help
+ Using the ICC system registers for IRQ masking makes it possible
+ to simulate NMI on ARM64 systems. This allows several interesting
+ features (especially debug features) to be used on these systems.
+
+ Say Y here to implement IRQ masking using ICC system
+ registers when the GIC System Registers are available. The changes
+ are applied dynamically using the alternatives system so it is safe
+ to enable this option on systems with older interrupt controllers.
+
+ If unsure, say N
+
menuconfig ARMV8_DEPRECATED
bool "Emulate deprecated/obsolete ARMv8 instructions"
depends on COMPAT
--
1.9.1


2018-05-25 09:55:26

by Julien Thierry

[permalink] [raw]
Subject: [PATCH v4 17/26] irqchip/gic-v3: Factor group0 detection into functions

The code to detect whether Linux has access to group0 interrupts can
prove useful in other parts of the driver.

Provide a separate function to do this.

Signed-off-by: Julien Thierry <[email protected]>
Cc: Thomas Gleixner <[email protected]>
Cc: Jason Cooper <[email protected]>
Cc: Marc Zyngier <[email protected]>
---
drivers/irqchip/irq-gic-v3.c | 55 +++++++++++++++++++++++++++++---------------
1 file changed, 36 insertions(+), 19 deletions(-)

diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c
index 0c58db3..13d283d 100644
--- a/drivers/irqchip/irq-gic-v3.c
+++ b/drivers/irqchip/irq-gic-v3.c
@@ -389,6 +389,39 @@ static asmlinkage void __exception_irq_entry gic_handle_irq(struct pt_regs *regs
}
}

+static u32 gic_get_pribits(void)
+{
+ u32 pribits;
+
+ pribits = gic_read_ctlr();
+ pribits &= ICC_CTLR_EL1_PRI_BITS_MASK;
+ pribits >>= ICC_CTLR_EL1_PRI_BITS_SHIFT;
+ pribits++;
+
+ return pribits;
+}
+
+static bool gic_has_group0(void)
+{
+ u32 val;
+
+ /*
+ * Let's find out if Group0 is under control of EL3 or not by
+ * setting the highest possible, non-zero priority in PMR.
+ *
+ * If SCR_EL3.FIQ is set, the priority gets shifted down in
+ * order for the CPU interface to set bit 7, and keep the
+ * actual priority in the non-secure range. In the process, it
+ * looses the least significant bit and the actual priority
+ * becomes 0x80. Reading it back returns 0, indicating that
+ * we're don't have access to Group0.
+ */
+ gic_write_pmr(BIT(8 - gic_get_pribits()));
+ val = gic_read_pmr();
+
+ return val != 0;
+}
+
static void __init gic_dist_init(void)
{
unsigned int i;
@@ -530,7 +563,7 @@ static void gic_cpu_sys_reg_init(void)
u64 mpidr = cpu_logical_map(cpu);
u64 need_rss = MPIDR_RS(mpidr);
bool group0;
- u32 val, pribits;
+ u32 pribits;

/*
* Need to check that the SRE bit has actually been set. If
@@ -542,25 +575,9 @@ static void gic_cpu_sys_reg_init(void)
if (!gic_enable_sre())
pr_err("GIC: unable to set SRE (disabled at EL2), panic ahead\n");

- pribits = gic_read_ctlr();
- pribits &= ICC_CTLR_EL1_PRI_BITS_MASK;
- pribits >>= ICC_CTLR_EL1_PRI_BITS_SHIFT;
- pribits++;
+ pribits = gic_get_pribits();

- /*
- * Let's find out if Group0 is under control of EL3 or not by
- * setting the highest possible, non-zero priority in PMR.
- *
- * If SCR_EL3.FIQ is set, the priority gets shifted down in
- * order for the CPU interface to set bit 7, and keep the
- * actual priority in the non-secure range. In the process, it
- * looses the least significant bit and the actual priority
- * becomes 0x80. Reading it back returns 0, indicating that
- * we're don't have access to Group0.
- */
- write_gicreg(BIT(8 - pribits), ICC_PMR_EL1);
- val = read_gicreg(ICC_PMR_EL1);
- group0 = val != 0;
+ group0 = gic_has_group0();

/* Set priority mask register */
write_gicreg(DEFAULT_PMR_VALUE, ICC_PMR_EL1);
--
1.9.1


2018-05-25 09:55:30

by Julien Thierry

[permalink] [raw]
Subject: [PATCH v4 12/26] arm64: Unmask PMR before going idle

CPU does not received signals for interrupts with a priority masked by
ICC_PMR_EL1. This means the CPU might not come back from a WFI
instruction.

Make sure ICC_PMR_EL1 does not mask interrupts when doing a WFI.

Signed-off-by: Julien Thierry <[email protected]>
Suggested-by: Daniel Thompson <[email protected]>
Cc: Catalin Marinas <[email protected]>
Cc: Will Deacon <[email protected]>
---
arch/arm64/mm/proc.S | 18 ++++++++++++++++++
1 file changed, 18 insertions(+)

diff --git a/arch/arm64/mm/proc.S b/arch/arm64/mm/proc.S
index 5f9a73a..e7cafbf 100644
--- a/arch/arm64/mm/proc.S
+++ b/arch/arm64/mm/proc.S
@@ -20,6 +20,7 @@

#include <linux/init.h>
#include <linux/linkage.h>
+#include <linux/irqchip/arm-gic-v3.h>
#include <asm/assembler.h>
#include <asm/asm-offsets.h>
#include <asm/hwcap.h>
@@ -53,10 +54,27 @@
* cpu_do_idle()
*
* Idle the processor (wait for interrupt).
+ *
+ * If the CPU supports priority masking we must do additional work to
+ * ensure that interrupts are not masked at the PMR (because the core will
+ * not wake up if we block the wake up signal in the interrupt controller).
*/
ENTRY(cpu_do_idle)
+alternative_if_not ARM64_HAS_IRQ_PRIO_MASKING
+ dsb sy // WFI may enter a low-power mode
+ wfi
+ ret
+alternative_else
+ mrs x0, daif // save I bit
+ msr daifset, #2 // set I bit
+ mrs_s x1, SYS_ICC_PMR_EL1 // save PMR
+alternative_endif
+ mov x2, #ICC_PMR_EL1_UNMASKED
+ msr_s SYS_ICC_PMR_EL1, x2 // unmask at PMR
dsb sy // WFI may enter a low-power mode
wfi
+ msr_s SYS_ICC_PMR_EL1, x1 // restore PMR
+ msr daif, x0 // restore I bit
ret
ENDPROC(cpu_do_idle)

--
1.9.1


2018-05-25 09:55:41

by Julien Thierry

[permalink] [raw]
Subject: [PATCH v4 20/26] arm64: Switch to PMR masking when starting CPUs

Once the boot CPU has been prepared or a new secondary CPU has been
brought up, use ICC_PMR_EL1 to mask interrupts on that CPU and clear
PSR.I bit.

Signed-off-by: Julien Thierry <[email protected]>
Suggested-by: Daniel Thompson <[email protected]>
Cc: Catalin Marinas <[email protected]>
Cc: Will Deacon <[email protected]>
Cc: James Morse <[email protected]>
Cc: Marc Zyngier <[email protected]>
---
arch/arm64/include/asm/irqflags.h | 3 +++
arch/arm64/kernel/head.S | 35 +++++++++++++++++++++++++++++++++++
arch/arm64/kernel/smp.c | 5 +++++
3 files changed, 43 insertions(+)

diff --git a/arch/arm64/include/asm/irqflags.h b/arch/arm64/include/asm/irqflags.h
index 193cfd0..d31e9b6 100644
--- a/arch/arm64/include/asm/irqflags.h
+++ b/arch/arm64/include/asm/irqflags.h
@@ -153,5 +153,8 @@ static inline int arch_irqs_disabled_flags(unsigned long flags)
return (ARCH_FLAGS_GET_DAIF(flags) & (PSR_I_BIT)) |
!(ARCH_FLAGS_GET_PMR(flags) & ICC_PMR_EL1_EN_BIT);
}
+
+void maybe_switch_to_sysreg_gic_cpuif(void);
+
#endif
#endif
diff --git a/arch/arm64/kernel/head.S b/arch/arm64/kernel/head.S
index b085306..ba73690 100644
--- a/arch/arm64/kernel/head.S
+++ b/arch/arm64/kernel/head.S
@@ -648,6 +648,41 @@ set_cpu_boot_mode_flag:
ENDPROC(set_cpu_boot_mode_flag)

/*
+ * void maybe_switch_to_sysreg_gic_cpuif(void)
+ *
+ * Enable interrupt controller system register access if this feature
+ * has been detected by the alternatives system.
+ *
+ * Before we jump into generic code we must enable interrupt controller system
+ * register access because this is required by the irqflags macros. We must
+ * also mask interrupts at the PMR and unmask them within the PSR. That leaves
+ * us set up and ready for the kernel to make its first call to
+ * arch_local_irq_enable().
+ *
+ */
+ENTRY(maybe_switch_to_sysreg_gic_cpuif)
+alternative_if_not ARM64_HAS_IRQ_PRIO_MASKING
+ b 1f
+alternative_else
+ mrs_s x0, SYS_ICC_SRE_EL1
+alternative_endif
+ orr x0, x0, #1
+ msr_s SYS_ICC_SRE_EL1, x0 // Set ICC_SRE_EL1.SRE==1
+ isb // Make sure SRE is now set
+ mrs x0, daif
+ tbz x0, #7, no_mask_pmr // Are interrupts on?
+ mov x0, ICC_PMR_EL1_MASKED
+ msr_s SYS_ICC_PMR_EL1, x0 // Prepare for unmask of I bit
+ msr daifclr, #2 // Clear the I bit
+ b 1f
+no_mask_pmr:
+ mov x0, ICC_PMR_EL1_UNMASKED
+ msr_s SYS_ICC_PMR_EL1, x0
+1:
+ ret
+ENDPROC(maybe_switch_to_sysreg_gic_cpuif)
+
+/*
* These values are written with the MMU off, but read with the MMU on.
* Writers will invalidate the corresponding address, discarding up to a
* 'Cache Writeback Granule' (CWG) worth of data. The linker script ensures
diff --git a/arch/arm64/kernel/smp.c b/arch/arm64/kernel/smp.c
index b7fb909..3f39d8c 100644
--- a/arch/arm64/kernel/smp.c
+++ b/arch/arm64/kernel/smp.c
@@ -185,6 +185,8 @@ asmlinkage void secondary_start_kernel(void)
struct mm_struct *mm = &init_mm;
unsigned int cpu;

+ maybe_switch_to_sysreg_gic_cpuif();
+
cpu = task_cpu(current);
set_my_cpu_offset(per_cpu_offset(cpu));

@@ -417,6 +419,9 @@ void __init smp_prepare_boot_cpu(void)
* and/or scheduling is enabled.
*/
apply_boot_alternatives();
+
+ /* Conditionally switch to GIC PMR for interrupt masking */
+ maybe_switch_to_sysreg_gic_cpuif();
}

static u64 __init of_get_cpu_mpidr(struct device_node *dn)
--
1.9.1


2018-05-25 09:56:13

by Julien Thierry

[permalink] [raw]
Subject: [PATCH v4 14/26] arm64: kvm: Unmask PMR before entering guest

Interrupts masked by ICC_PMR_EL1 will not be signaled to the CPU. This
means that hypervisor will not receive masked interrupts while running a
guest.

Avoid this by making sure ICC_PMR_EL1 is unmasked when we enter a guest.

Signed-off-by: Julien Thierry <[email protected]>
Cc: Christoffer Dall <[email protected]>
Cc: Marc Zyngier <[email protected]>
Cc: Catalin Marinas <[email protected]>
Cc: Will Deacon <[email protected]>
Cc: [email protected]
---
arch/arm64/include/asm/kvm_host.h | 12 ++++++++++++
arch/arm64/kvm/hyp/switch.c | 17 +++++++++++++++++
2 files changed, 29 insertions(+)

diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
index 469de8a..bfd9e5b 100644
--- a/arch/arm64/include/asm/kvm_host.h
+++ b/arch/arm64/include/asm/kvm_host.h
@@ -24,6 +24,7 @@

#include <linux/types.h>
#include <linux/kvm_types.h>
+#include <asm/arch_gicv3.h>
#include <asm/cpufeature.h>
#include <asm/daifflags.h>
#include <asm/fpsimd.h>
@@ -433,6 +434,17 @@ static inline void kvm_fpsimd_flush_cpu_state(void)
static inline void kvm_arm_vhe_guest_enter(void)
{
local_daif_mask();
+
+ /*
+ * Having IRQs masked via PMR when entering the guest means the GIC
+ * will not signal the CPU of interrupts of lower priority, and the
+ * only way to get out will be via guest exceptions.
+ * Naturally, we want to avoid this.
+ */
+ if (gic_prio_masking_enabled()) {
+ gic_write_pmr(ICC_PMR_EL1_UNMASKED);
+ dsb(sy);
+ }
}

static inline void kvm_arm_vhe_guest_exit(void)
diff --git a/arch/arm64/kvm/hyp/switch.c b/arch/arm64/kvm/hyp/switch.c
index d964523..f00a04c 100644
--- a/arch/arm64/kvm/hyp/switch.c
+++ b/arch/arm64/kvm/hyp/switch.c
@@ -21,6 +21,7 @@

#include <kvm/arm_psci.h>

+#include <asm/arch_gicv3.h>
#include <asm/kvm_asm.h>
#include <asm/kvm_emulate.h>
#include <asm/kvm_hyp.h>
@@ -442,6 +443,19 @@ int __hyp_text __kvm_vcpu_run_nvhe(struct kvm_vcpu *vcpu)
struct kvm_cpu_context *guest_ctxt;
bool fp_enabled;
u64 exit_code;
+ u32 host_pmr = ICC_PMR_EL1_UNMASKED;
+
+ /*
+ * Having IRQs masked via PMR when entering the guest means the GIC
+ * will not signal the CPU of interrupts of lower priority, and the
+ * only way to get out will be via guest exceptions.
+ * Naturally, we want to avoid this.
+ */
+ if (gic_prio_masking_enabled()) {
+ host_pmr = gic_read_pmr();
+ gic_write_pmr(ICC_PMR_EL1_UNMASKED);
+ dsb(sy);
+ }

vcpu = kern_hyp_va(vcpu);

@@ -496,6 +510,9 @@ int __hyp_text __kvm_vcpu_run_nvhe(struct kvm_vcpu *vcpu)
*/
__debug_switch_to_host(vcpu);

+ if (gic_prio_masking_enabled())
+ gic_write_pmr(host_pmr);
+
return exit_code;
}

--
1.9.1


2018-05-25 09:56:21

by Julien Thierry

[permalink] [raw]
Subject: [PATCH v4 16/26] arm64: daifflags: Include PMR in daifflags restore operations

The addition of PMR should not bypass the semantics of daifflags.

When DA_F are set, I bit is also set as no interrupts (even of higher
priority) is allowed.

When DA_F are cleared, I bit is cleared and interrupt enabling/disabling
goes through ICC_PMR_EL1.

Signed-off-by: Julien Thierry <[email protected]>
Cc: Catalin Marinas <[email protected]>
Cc: Will Deacon <[email protected]>
Cc: James Morse <[email protected]>
---
arch/arm64/include/asm/daifflags.h | 17 +++++++++++++++--
1 file changed, 15 insertions(+), 2 deletions(-)

diff --git a/arch/arm64/include/asm/daifflags.h b/arch/arm64/include/asm/daifflags.h
index 8d91f22..3ae8139 100644
--- a/arch/arm64/include/asm/daifflags.h
+++ b/arch/arm64/include/asm/daifflags.h
@@ -18,8 +18,17 @@

#include <linux/irqflags.h>

-#define DAIF_PROCCTX 0
-#define DAIF_PROCCTX_NOIRQ PSR_I_BIT
+#include <asm/arch_gicv3.h>
+
+#define DAIF_PROCCTX \
+ (gic_prio_masking_enabled() ? \
+ MAKE_ARCH_FLAGS(0, ICC_PMR_EL1_UNMASKED) : \
+ 0)
+
+#define DAIF_PROCCTX_NOIRQ \
+ (gic_prio_masking_enabled() ? \
+ MAKE_ARCH_FLAGS(0, ICC_PMR_EL1_MASKED) : \
+ PSR_I_BIT)

/* mask/save/unmask/restore all exceptions, including interrupts. */
static inline void local_daif_mask(void)
@@ -51,6 +60,10 @@ static inline void local_daif_unmask(void)
:
:
: "memory");
+
+ /* Unmask IRQs in PMR if needed */
+ if (gic_prio_masking_enabled())
+ arch_local_irq_enable();
}

static inline void local_daif_restore(unsigned long flags)
--
1.9.1


2018-05-25 09:56:33

by Julien Thierry

[permalink] [raw]
Subject: [PATCH v4 10/26] arm64: Delay daif masking for user return

Masking daif flags is done very early before returning to EL0.

Only toggle the interrupt masking while in the vector entry and mask daif
once in kernel_exit.

Signed-off-by: Julien Thierry <[email protected]>
Cc: Catalin Marinas <[email protected]>
Cc: Will Deacon <[email protected]>
Cc: Mark Rutland <[email protected]>
Cc: James Morse <[email protected]>
---
arch/arm64/kernel/entry.S | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/arch/arm64/kernel/entry.S b/arch/arm64/kernel/entry.S
index ec2ee72..20252d5 100644
--- a/arch/arm64/kernel/entry.S
+++ b/arch/arm64/kernel/entry.S
@@ -240,9 +240,9 @@ alternative_else_nop_endif
.endm

.macro kernel_exit, el
- .if \el != 0
disable_daif

+ .if \el != 0
/* Restore the task's original addr_limit. */
ldr x20, [sp, #S_ORIG_ADDR_LIMIT]
str x20, [tsk, #TSK_TI_ADDR_LIMIT]
@@ -872,7 +872,7 @@ ENDPROC(el0_error)
* and this includes saving x0 back into the kernel stack.
*/
ret_fast_syscall:
- disable_daif
+ disable_irq // disable interrupts
str x0, [sp, #S_X0] // returned x0
ldr x1, [tsk, #TSK_TI_FLAGS] // re-check for syscall tracing
and x2, x1, #_TIF_SYSCALL_WORK
@@ -882,7 +882,7 @@ ret_fast_syscall:
enable_step_tsk x1, x2
kernel_exit 0
ret_fast_syscall_trace:
- enable_daif
+ enable_irq // enable interrupts
b __sys_trace_return_skipped // we already saved x0

/*
@@ -900,7 +900,7 @@ work_pending:
* "slow" syscall return path.
*/
ret_to_user:
- disable_daif
+ disable_irq // disable interrupts
ldr x1, [tsk, #TSK_TI_FLAGS]
and x2, x1, #_TIF_WORK_MASK
cbnz x2, work_pending
--
1.9.1


2018-05-25 09:56:48

by Julien Thierry

[permalink] [raw]
Subject: [PATCH v4 11/26] arm64: Make PMR part of task context

If ICC_PMR_EL1 is used to mask interrupts, its value should be
saved/restored whenever a task is context switched out/in or
gets an exception.

Add PMR to the registers to save in the pt_regs struct upon kernel entry,
and restore it before ERET. Also, initialize it to a sane value when
creating new tasks.

Signed-off-by: Julien Thierry <[email protected]>
Cc: Catalin Marinas <[email protected]>
Cc: Will Deacon <[email protected]>
Cc: Oleg Nesterov <[email protected]>
Cc: Dave Martin <[email protected]>
---
arch/arm64/include/asm/processor.h | 1 +
arch/arm64/include/asm/ptrace.h | 5 ++++-
arch/arm64/kernel/asm-offsets.c | 1 +
arch/arm64/kernel/entry.S | 16 ++++++++++++++++
arch/arm64/kernel/process.c | 2 ++
5 files changed, 24 insertions(+), 1 deletion(-)

diff --git a/arch/arm64/include/asm/processor.h b/arch/arm64/include/asm/processor.h
index 7675989..40bd0e1 100644
--- a/arch/arm64/include/asm/processor.h
+++ b/arch/arm64/include/asm/processor.h
@@ -163,6 +163,7 @@ static inline void start_thread_common(struct pt_regs *regs, unsigned long pc)
memset(regs, 0, sizeof(*regs));
forget_syscall(regs);
regs->pc = pc;
+ regs->pmr_save = ICC_PMR_EL1_UNMASKED;
}

static inline void start_thread(struct pt_regs *regs, unsigned long pc,
diff --git a/arch/arm64/include/asm/ptrace.h b/arch/arm64/include/asm/ptrace.h
index 6069d66..e87aef7 100644
--- a/arch/arm64/include/asm/ptrace.h
+++ b/arch/arm64/include/asm/ptrace.h
@@ -25,6 +25,9 @@
#define CurrentEL_EL1 (1 << 2)
#define CurrentEL_EL2 (2 << 2)

+/* PMR value use to unmask interrupts */
+#define ICC_PMR_EL1_UNMASKED 0xf0
+
/* AArch32-specific ptrace requests */
#define COMPAT_PTRACE_GETREGS 12
#define COMPAT_PTRACE_SETREGS 13
@@ -136,7 +139,7 @@ struct pt_regs {
#endif

u64 orig_addr_limit;
- u64 unused; // maintain 16 byte alignment
+ u64 pmr_save;
u64 stackframe[2];
};

diff --git a/arch/arm64/kernel/asm-offsets.c b/arch/arm64/kernel/asm-offsets.c
index 5bdda65..1f6a0a9 100644
--- a/arch/arm64/kernel/asm-offsets.c
+++ b/arch/arm64/kernel/asm-offsets.c
@@ -78,6 +78,7 @@ int main(void)
DEFINE(S_ORIG_X0, offsetof(struct pt_regs, orig_x0));
DEFINE(S_SYSCALLNO, offsetof(struct pt_regs, syscallno));
DEFINE(S_ORIG_ADDR_LIMIT, offsetof(struct pt_regs, orig_addr_limit));
+ DEFINE(S_PMR_SAVE, offsetof(struct pt_regs, pmr_save));
DEFINE(S_STACKFRAME, offsetof(struct pt_regs, stackframe));
DEFINE(S_FRAME_SIZE, sizeof(struct pt_regs));
BLANK();
diff --git a/arch/arm64/kernel/entry.S b/arch/arm64/kernel/entry.S
index 20252d5..78e4ff4 100644
--- a/arch/arm64/kernel/entry.S
+++ b/arch/arm64/kernel/entry.S
@@ -230,6 +230,15 @@ alternative_else_nop_endif
msr sp_el0, tsk
.endif

+ /* Save pmr */
+alternative_if ARM64_HAS_IRQ_PRIO_MASKING
+ mrs_s x20, SYS_ICC_PMR_EL1
+alternative_else
+ /* Keep a sane value in the task context */
+ mov x20, ICC_PMR_EL1_UNMASKED
+alternative_endif
+ str x20, [sp, #S_PMR_SAVE]
+
/*
* Registers that may be useful after this macro is invoked:
*
@@ -250,6 +259,13 @@ alternative_else_nop_endif
/* No need to restore UAO, it will be restored from SPSR_EL1 */
.endif

+ /* Restore pmr */
+alternative_if ARM64_HAS_IRQ_PRIO_MASKING
+ ldr x20, [sp, #S_PMR_SAVE]
+ msr_s SYS_ICC_PMR_EL1, x20
+ dsb sy
+alternative_else_nop_endif
+
ldp x21, x22, [sp, #S_PC] // load ELR, SPSR
.if \el == 0
ct_user_enter
diff --git a/arch/arm64/kernel/process.c b/arch/arm64/kernel/process.c
index f08a2ed..fbc9886 100644
--- a/arch/arm64/kernel/process.c
+++ b/arch/arm64/kernel/process.c
@@ -230,6 +230,7 @@ void __show_regs(struct pt_regs *regs)
}

printk("sp : %016llx\n", sp);
+ printk("pmr_save: %08llx\n", regs->pmr_save);

i = top_reg;

@@ -355,6 +356,7 @@ int copy_thread(unsigned long clone_flags, unsigned long stack_start,
} else {
memset(childregs, 0, sizeof(struct pt_regs));
childregs->pstate = PSR_MODE_EL1h;
+ childregs->pmr_save = ICC_PMR_EL1_UNMASKED;
if (IS_ENABLED(CONFIG_ARM64_UAO) &&
cpus_have_const_cap(ARM64_HAS_UAO))
childregs->pstate |= PSR_UAO_BIT;
--
1.9.1


2018-05-25 09:56:52

by Julien Thierry

[permalink] [raw]
Subject: [PATCH v4 08/26] arm64: daifflags: Use irqflags functions for daifflags

Some of the work done in daifflags save/restore is already provided
by irqflags functions. Daifflags should always be a superset of irqflags
(it handles irq status + status of other flags). Modifying behaviour of
irqflags should alter the behaviour of daifflags.

Use irqflags_save/restore functions for the corresponding daifflags
operation.

Signed-off-by: Julien Thierry <[email protected]>
Cc: Catalin Marinas <[email protected]>
Cc: Will Deacon <[email protected]>
Cc: James Morse <[email protected]>
---
arch/arm64/include/asm/daifflags.h | 15 +++++----------
1 file changed, 5 insertions(+), 10 deletions(-)

Note:
A latter patch changes the behaviour of arch_local_flags but the daif
flag still need to follow the semantics of arch_local_flags.

diff --git a/arch/arm64/include/asm/daifflags.h b/arch/arm64/include/asm/daifflags.h
index 22e4c83..8d91f22 100644
--- a/arch/arm64/include/asm/daifflags.h
+++ b/arch/arm64/include/asm/daifflags.h
@@ -36,11 +36,8 @@ static inline unsigned long local_daif_save(void)
{
unsigned long flags;

- asm volatile(
- "mrs %0, daif // local_daif_save\n"
- : "=r" (flags)
- :
- : "memory");
+ flags = arch_local_save_flags();
+
local_daif_mask();

return flags;
@@ -60,11 +57,9 @@ static inline void local_daif_restore(unsigned long flags)
{
if (!arch_irqs_disabled_flags(flags))
trace_hardirqs_on();
- asm volatile(
- "msr daif, %0 // local_daif_restore"
- :
- : "r" (flags)
- : "memory");
+
+ arch_local_irq_restore(flags);
+
if (arch_irqs_disabled_flags(flags))
trace_hardirqs_off();
}
--
1.9.1

2018-05-25 09:56:54

by Julien Thierry

[permalink] [raw]
Subject: [PATCH v4 13/26] arm/arm64: gic-v3: Add helper functions to manage IRQ priorities

Add a function to check if priority masking is supported and accessors
for PMR/RPR.

Signed-off-by: Julien Thierry <[email protected]>
Cc: Russell King <[email protected]>
Cc: Catalin Marinas <[email protected]>
Cc: Will Deacon <[email protected]>
Cc: Marc Zyngier <[email protected]>
---
arch/arm/include/asm/arch_gicv3.h | 21 +++++++++++++++++++++
arch/arm64/include/asm/arch_gicv3.h | 20 ++++++++++++++++++++
2 files changed, 41 insertions(+)

diff --git a/arch/arm/include/asm/arch_gicv3.h b/arch/arm/include/asm/arch_gicv3.h
index 0bd5307..58d5d3e 100644
--- a/arch/arm/include/asm/arch_gicv3.h
+++ b/arch/arm/include/asm/arch_gicv3.h
@@ -34,6 +34,7 @@
#define ICC_SRE __ACCESS_CP15(c12, 0, c12, 5)
#define ICC_IGRPEN1 __ACCESS_CP15(c12, 0, c12, 7)
#define ICC_BPR1 __ACCESS_CP15(c12, 0, c12, 3)
+#define ICC_RPR __ACCESS_CP15(c12, 0, c11, 3)

#define __ICC_AP0Rx(x) __ACCESS_CP15(c12, 0, c8, 4 | x)
#define ICC_AP0R0 __ICC_AP0Rx(0)
@@ -245,6 +246,21 @@ static inline void gic_write_bpr1(u32 val)
write_sysreg(val, ICC_BPR1);
}

+static inline u32 gic_read_pmr(void)
+{
+ return read_sysreg(ICC_PMR);
+}
+
+static inline void gic_write_pmr(u32 val)
+{
+ write_sysreg(val, ICC_PMR);
+}
+
+static inline u32 gic_read_rpr(void)
+{
+ return read_sysreg(ICC_RPR);
+}
+
/*
* Even in 32bit systems that use LPAE, there is no guarantee that the I/O
* interface provides true 64bit atomic accesses, so using strd/ldrd doesn't
@@ -347,5 +363,10 @@ static inline void gits_write_vpendbaser(u64 val, void * __iomem addr)

#define gits_read_vpendbaser(c) __gic_readq_nonatomic(c)

+static inline bool gic_prio_masking_enabled(void)
+{
+ return false;
+}
+
#endif /* !__ASSEMBLY__ */
#endif /* !__ASM_ARCH_GICV3_H */
diff --git a/arch/arm64/include/asm/arch_gicv3.h b/arch/arm64/include/asm/arch_gicv3.h
index e278f94..98b09db 100644
--- a/arch/arm64/include/asm/arch_gicv3.h
+++ b/arch/arm64/include/asm/arch_gicv3.h
@@ -114,6 +114,21 @@ static inline void gic_write_bpr1(u32 val)
write_sysreg_s(val, SYS_ICC_BPR1_EL1);
}

+static inline u32 gic_read_pmr(void)
+{
+ return read_sysreg_s(SYS_ICC_PMR_EL1);
+}
+
+static inline void gic_write_pmr(u32 val)
+{
+ write_sysreg_s(val, SYS_ICC_PMR_EL1);
+}
+
+static inline u32 gic_read_rpr(void)
+{
+ return read_sysreg_s(SYS_ICC_RPR_EL1);
+}
+
#define gic_read_typer(c) readq_relaxed(c)
#define gic_write_irouter(v, c) writeq_relaxed(v, c)
#define gic_read_lpir(c) readq_relaxed(c)
@@ -140,5 +155,10 @@ static inline void gic_write_bpr1(u32 val)
#define gits_write_vpendbaser(v, c) writeq_relaxed(v, c)
#define gits_read_vpendbaser(c) readq_relaxed(c)

+static inline bool gic_prio_masking_enabled(void)
+{
+ return cpus_have_const_cap(ARM64_HAS_IRQ_PRIO_MASKING);
+}
+
#endif /* __ASSEMBLY__ */
#endif /* __ASM_ARCH_GICV3_H */
--
1.9.1


2018-05-25 09:56:56

by Julien Thierry

[permalink] [raw]
Subject: [PATCH v4 09/26] arm64: Use daifflag_restore after bp_hardening

For EL0 entries requiring bp_hardening, daif status is kept at
DAIF_PROCCTX_NOIRQ until after hardening has been done. Then interrupts
are enabled through local_irq_enable().

Before using local_irq_* functions, daifflags should be properly restored
to a state where IRQs are enabled.

Enable IRQs by restoring DAIF_PROCCTX state after bp hardening.

Signed-off-by: Julien Thierry <[email protected]>
Cc: Catalin Marinas <[email protected]>
Cc: Will Deacon <[email protected]>
Cc: Mark Rutland <[email protected]>
Cc: James Morse <[email protected]>
---
arch/arm64/mm/fault.c | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)

Note:
This doesn't introduce a real change in behaviour, but once PMR
is used for interrupt masking, PSR.I bit needs to be cleared and
local_irq_enable won't do that anymore.

diff --git a/arch/arm64/mm/fault.c b/arch/arm64/mm/fault.c
index 4165485..7a18634 100644
--- a/arch/arm64/mm/fault.c
+++ b/arch/arm64/mm/fault.c
@@ -37,6 +37,7 @@
#include <asm/cmpxchg.h>
#include <asm/cpufeature.h>
#include <asm/exception.h>
+#include <asm/daifflags.h>
#include <asm/debug-monitors.h>
#include <asm/esr.h>
#include <asm/sysreg.h>
@@ -712,7 +713,7 @@ asmlinkage void __exception do_el0_ia_bp_hardening(unsigned long addr,
if (addr > TASK_SIZE)
arm64_apply_bp_hardening();

- local_irq_enable();
+ local_daif_restore(DAIF_PROCCTX);
do_mem_abort(addr, esr, regs);
}

@@ -726,7 +727,7 @@ asmlinkage void __exception do_sp_pc_abort(unsigned long addr,
if (user_mode(regs)) {
if (instruction_pointer(regs) > TASK_SIZE)
arm64_apply_bp_hardening();
- local_irq_enable();
+ local_daif_restore(DAIF_PROCCTX);
}

info.si_signo = SIGBUS;
--
1.9.1

2018-05-25 09:57:14

by Julien Thierry

[permalink] [raw]
Subject: [PATCH v4 05/26] irqchip/gic: Unify GIC priority definitions

LPIs use the same priority value as other GIC interrupts.

Make the GIC default priority definition visible to ITS implementation
and use this same definition for LPI priorities.

Signed-off-by: Julien Thierry <[email protected]>
Cc: Thomas Gleixner <[email protected]>
Cc: Jason Cooper <[email protected]>
Cc: Marc Zyngier <[email protected]>
---
drivers/irqchip/irq-gic-v3-its.c | 2 +-
include/linux/irqchip/arm-gic-common.h | 6 ++++++
include/linux/irqchip/arm-gic.h | 5 -----
3 files changed, 7 insertions(+), 6 deletions(-)

diff --git a/drivers/irqchip/irq-gic-v3-its.c b/drivers/irqchip/irq-gic-v3-its.c
index 5416f2b..9ac146c 100644
--- a/drivers/irqchip/irq-gic-v3-its.c
+++ b/drivers/irqchip/irq-gic-v3-its.c
@@ -62,7 +62,7 @@
#define LPI_PROPBASE_SZ ALIGN(BIT(LPI_NRBITS), SZ_64K)
#define LPI_PENDBASE_SZ ALIGN(BIT(LPI_NRBITS) / 8, SZ_64K)

-#define LPI_PROP_DEFAULT_PRIO 0xa0
+#define LPI_PROP_DEFAULT_PRIO GICD_INT_DEF_PRI

/*
* Collection structure - just an ID, and a redistributor address to
diff --git a/include/linux/irqchip/arm-gic-common.h b/include/linux/irqchip/arm-gic-common.h
index 0a83b43..9a1a479 100644
--- a/include/linux/irqchip/arm-gic-common.h
+++ b/include/linux/irqchip/arm-gic-common.h
@@ -13,6 +13,12 @@
#include <linux/types.h>
#include <linux/ioport.h>

+#define GICD_INT_DEF_PRI 0xa0
+#define GICD_INT_DEF_PRI_X4 ((GICD_INT_DEF_PRI << 24) |\
+ (GICD_INT_DEF_PRI << 16) |\
+ (GICD_INT_DEF_PRI << 8) |\
+ GICD_INT_DEF_PRI)
+
enum gic_type {
GIC_V2,
GIC_V3,
diff --git a/include/linux/irqchip/arm-gic.h b/include/linux/irqchip/arm-gic.h
index 68d8b1f..5f2129b 100644
--- a/include/linux/irqchip/arm-gic.h
+++ b/include/linux/irqchip/arm-gic.h
@@ -65,11 +65,6 @@
#define GICD_INT_EN_CLR_X32 0xffffffff
#define GICD_INT_EN_SET_SGI 0x0000ffff
#define GICD_INT_EN_CLR_PPI 0xffff0000
-#define GICD_INT_DEF_PRI 0xa0
-#define GICD_INT_DEF_PRI_X4 ((GICD_INT_DEF_PRI << 24) |\
- (GICD_INT_DEF_PRI << 16) |\
- (GICD_INT_DEF_PRI << 8) |\
- GICD_INT_DEF_PRI)

#define GICH_HCR 0x0
#define GICH_VTR 0x4
--
1.9.1


2018-05-25 09:57:39

by Julien Thierry

[permalink] [raw]
Subject: [PATCH v4 06/26] irqchip/gic: Lower priority of GIC interrupts

The current value used for IRQ priorities is high among the
non-secure interrupt priority values.

Lower the default priority of interrupts so there is more flexibility
to define higher priority interrupts.

Signed-off-by: Julien Thierry <[email protected]>
Suggested-by: Daniel Thompson <[email protected]>
Cc: Marc Zyngier <[email protected]>
---
include/linux/irqchip/arm-gic-common.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/include/linux/irqchip/arm-gic-common.h b/include/linux/irqchip/arm-gic-common.h
index 9a1a479..2c9a4b3 100644
--- a/include/linux/irqchip/arm-gic-common.h
+++ b/include/linux/irqchip/arm-gic-common.h
@@ -13,7 +13,7 @@
#include <linux/types.h>
#include <linux/ioport.h>

-#define GICD_INT_DEF_PRI 0xa0
+#define GICD_INT_DEF_PRI 0xc0
#define GICD_INT_DEF_PRI_X4 ((GICD_INT_DEF_PRI << 24) |\
(GICD_INT_DEF_PRI << 16) |\
(GICD_INT_DEF_PRI << 8) |\
--
1.9.1


2018-05-25 09:57:44

by Julien Thierry

[permalink] [raw]
Subject: [PATCH v4 04/26] arm64: alternative: Apply alternatives early in boot process

From: Daniel Thompson <[email protected]>

Currently alternatives are applied very late in the boot process (and
a long time after we enable scheduling). Some alternative sequences,
such as those that alter the way CPU context is stored, must be applied
much earlier in the boot sequence.

Introduce apply_boot_alternatives() to allow some alternatives to be
applied immediately after we detect the CPU features of the boot CPU.

Signed-off-by: Daniel Thompson <[email protected]>
[[email protected]: rename to fit new cpufeature framework better,
apply BOOT_SCOPE feature early in boot]
Signed-off-by: Julien Thierry <[email protected]>
Cc: Catalin Marinas <[email protected]>
Cc: Will Deacon <[email protected]>
Cc: Christoffer Dall <[email protected]>
Cc: Suzuki K Poulose <[email protected]>
---
arch/arm64/include/asm/alternative.h | 3 +--
arch/arm64/include/asm/cpufeature.h | 2 ++
arch/arm64/kernel/alternative.c | 30 +++++++++++++++++++++++++++---
arch/arm64/kernel/cpufeature.c | 5 +++++
arch/arm64/kernel/smp.c | 7 +++++++
5 files changed, 42 insertions(+), 5 deletions(-)

diff --git a/arch/arm64/include/asm/alternative.h b/arch/arm64/include/asm/alternative.h
index a91933b..9fc938f 100644
--- a/arch/arm64/include/asm/alternative.h
+++ b/arch/arm64/include/asm/alternative.h
@@ -14,8 +14,6 @@
#include <linux/stddef.h>
#include <linux/stringify.h>

-extern int alternatives_applied;
-
struct alt_instr {
s32 orig_offset; /* offset to original instruction */
s32 alt_offset; /* offset to replacement instruction */
@@ -27,6 +25,7 @@ struct alt_instr {
typedef void (*alternative_cb_t)(struct alt_instr *alt,
__le32 *origptr, __le32 *updptr, int nr_inst);

+void __init apply_boot_alternatives(void);
void __init apply_alternatives_all(void);
void apply_alternatives(void *start, size_t length);

diff --git a/arch/arm64/include/asm/cpufeature.h b/arch/arm64/include/asm/cpufeature.h
index 09b0f2a..19efe4e 100644
--- a/arch/arm64/include/asm/cpufeature.h
+++ b/arch/arm64/include/asm/cpufeature.h
@@ -359,6 +359,8 @@ static inline int cpucap_default_scope(const struct arm64_cpu_capabilities *cap)
extern struct static_key_false cpu_hwcap_keys[ARM64_NCAPS];
extern struct static_key_false arm64_const_caps_ready;

+extern unsigned long boot_capabilities;
+
bool this_cpu_has_cap(unsigned int cap);

static inline bool cpu_have_feature(unsigned int num)
diff --git a/arch/arm64/kernel/alternative.c b/arch/arm64/kernel/alternative.c
index 5c4bce4..3f540ff 100644
--- a/arch/arm64/kernel/alternative.c
+++ b/arch/arm64/kernel/alternative.c
@@ -122,7 +122,8 @@ static void patch_alternative(struct alt_instr *alt,
}
}

-static void __apply_alternatives(void *alt_region, bool use_linear_alias)
+static void __apply_alternatives(void *alt_region, bool use_linear_alias,
+ unsigned long feature_mask)
{
struct alt_instr *alt;
struct alt_region *region = alt_region;
@@ -132,6 +133,9 @@ static void __apply_alternatives(void *alt_region, bool use_linear_alias)
for (alt = region->begin; alt < region->end; alt++) {
int nr_inst;

+ if ((BIT(alt->cpufeature) & feature_mask) == 0)
+ continue;
+
/* Use ARM64_CB_PATCH as an unconditional patch */
if (alt->cpufeature < ARM64_CB_PATCH &&
!cpus_have_cap(alt->cpufeature))
@@ -178,7 +182,9 @@ static int __apply_alternatives_multi_stop(void *unused)
isb();
} else {
BUG_ON(alternatives_applied);
- __apply_alternatives(&region, true);
+
+ __apply_alternatives(&region, true, ~boot_capabilities);
+
/* Barriers provided by the cache flushing */
WRITE_ONCE(alternatives_applied, 1);
}
@@ -192,6 +198,24 @@ void __init apply_alternatives_all(void)
stop_machine(__apply_alternatives_multi_stop, NULL, cpu_online_mask);
}

+/*
+ * This is called very early in the boot process (directly after we run
+ * a feature detect on the boot CPU). No need to worry about other CPUs
+ * here.
+ */
+void __init apply_boot_alternatives(void)
+{
+ struct alt_region region = {
+ .begin = (struct alt_instr *)__alt_instructions,
+ .end = (struct alt_instr *)__alt_instructions_end,
+ };
+
+ /* If called on non-boot cpu things could go wrong */
+ WARN_ON(smp_processor_id() != 0);
+
+ __apply_alternatives(&region, true, boot_capabilities);
+}
+
void apply_alternatives(void *start, size_t length)
{
struct alt_region region = {
@@ -199,5 +223,5 @@ void apply_alternatives(void *start, size_t length)
.end = start + length,
};

- __apply_alternatives(&region, false);
+ __apply_alternatives(&region, false, -1);
}
diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c
index a3a5585d..7a4f602 100644
--- a/arch/arm64/kernel/cpufeature.c
+++ b/arch/arm64/kernel/cpufeature.c
@@ -52,6 +52,8 @@
DECLARE_BITMAP(cpu_hwcaps, ARM64_NCAPS);
EXPORT_SYMBOL(cpu_hwcaps);

+unsigned long boot_capabilities;
+
/*
* Flag to indicate if we have computed the system wide
* capabilities based on the boot time active CPUs. This
@@ -1370,6 +1372,9 @@ static void __update_cpu_capabilities(const struct arm64_cpu_capabilities *caps,
if (!cpus_have_cap(caps->capability) && caps->desc)
pr_info("%s %s\n", info, caps->desc);
cpus_set_cap(caps->capability);
+
+ if (scope_mask & SCOPE_BOOT_CPU)
+ __set_bit(caps->capability, &boot_capabilities);
}
}

diff --git a/arch/arm64/kernel/smp.c b/arch/arm64/kernel/smp.c
index f3e2e3a..b7fb909 100644
--- a/arch/arm64/kernel/smp.c
+++ b/arch/arm64/kernel/smp.c
@@ -410,6 +410,13 @@ void __init smp_prepare_boot_cpu(void)
*/
jump_label_init();
cpuinfo_store_boot_cpu();
+
+ /*
+ * We now know enough about the boot CPU to apply the
+ * alternatives that cannot wait until interrupt handling
+ * and/or scheduling is enabled.
+ */
+ apply_boot_alternatives();
}

static u64 __init of_get_cpu_mpidr(struct device_node *dn)
--
1.9.1


2018-05-25 09:57:52

by Julien Thierry

[permalink] [raw]
Subject: [PATCH v4 02/26] arm64: cpufeature: Add cpufeature for IRQ priority masking

Add a cpufeature indicating whether a cpu supports masking interrupts
by priority.

Signed-off-by: Julien Thierry <[email protected]>
Cc: Catalin Marinas <[email protected]>
Cc: Will Deacon <[email protected]>
Cc: Marc Zyngier <[email protected]>
Cc: Suzuki K Poulose <[email protected]>
---
arch/arm64/include/asm/cpucaps.h | 3 ++-
arch/arm64/kernel/cpufeature.c | 15 +++++++++++++++
2 files changed, 17 insertions(+), 1 deletion(-)

diff --git a/arch/arm64/include/asm/cpucaps.h b/arch/arm64/include/asm/cpucaps.h
index bc51b72..cd8f9ed 100644
--- a/arch/arm64/include/asm/cpucaps.h
+++ b/arch/arm64/include/asm/cpucaps.h
@@ -48,7 +48,8 @@
#define ARM64_HAS_CACHE_IDC 27
#define ARM64_HAS_CACHE_DIC 28
#define ARM64_HW_DBM 29
+#define ARM64_HAS_IRQ_PRIO_MASKING 30

-#define ARM64_NCAPS 30
+#define ARM64_NCAPS 31

#endif /* __ASM_CPUCAPS_H */
diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c
index e03e897..a177104 100644
--- a/arch/arm64/kernel/cpufeature.c
+++ b/arch/arm64/kernel/cpufeature.c
@@ -1202,6 +1202,21 @@ static void cpu_copy_el2regs(const struct arm64_cpu_capabilities *__unused)
.cpu_enable = cpu_enable_hw_dbm,
},
#endif
+#ifdef CONFIG_USE_ICC_SYSREGS_FOR_IRQFLAGS
+ {
+ /*
+ * Depends on having GICv3
+ */
+ .desc = "IRQ priority masking",
+ .capability = ARM64_HAS_IRQ_PRIO_MASKING,
+ .type = ARM64_CPUCAP_STRICT_BOOT_CPU_FEATURE,
+ .matches = has_useable_gicv3_cpuif,
+ .sys_reg = SYS_ID_AA64PFR0_EL1,
+ .field_pos = ID_AA64PFR0_GIC_SHIFT,
+ .sign = FTR_UNSIGNED,
+ .min_field_value = 1,
+ },
+#endif
{},
};

--
1.9.1


2018-05-25 09:58:33

by Julien Thierry

[permalink] [raw]
Subject: [PATCH v4 07/26] irqchip/gic-v3: Remove acknowledge loop

Multiple interrupts pending for a CPU is actually rare. Doing an
acknowledge loop does not give much better performance or even can
deteriorate them.

Do not loop when an interrupt has been acknowledged, just return
from interrupt and wait for another one to be raised.

Signed-off-by: Julien Thierry <[email protected]>
Cc: Thomas Gleixner <[email protected]>
Cc: Jason Cooper <[email protected]>
Cc: Marc Zyngier <[email protected]>
---
drivers/irqchip/irq-gic-v3.c | 65 +++++++++++++++++++++-----------------------
1 file changed, 31 insertions(+), 34 deletions(-)

Note:
The loop pattern also discourages from using PMR for IRQ masking because
PMR needs to be unmasked to acknowledge interrupts.

diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c
index e5d1014..0c58db3 100644
--- a/drivers/irqchip/irq-gic-v3.c
+++ b/drivers/irqchip/irq-gic-v3.c
@@ -348,48 +348,45 @@ static asmlinkage void __exception_irq_entry gic_handle_irq(struct pt_regs *regs
{
u32 irqnr;

- do {
- irqnr = gic_read_iar();
+ irqnr = gic_read_iar();

- if (likely(irqnr > 15 && irqnr < 1020) || irqnr >= 8192) {
- int err;
+ if (likely(irqnr > 15 && irqnr < 1020) || irqnr >= 8192) {
+ int err;

- if (static_branch_likely(&supports_deactivate_key))
+ if (static_branch_likely(&supports_deactivate_key))
+ gic_write_eoir(irqnr);
+ else
+ isb();
+
+ err = handle_domain_irq(gic_data.domain, irqnr, regs);
+ if (err) {
+ WARN_ONCE(true, "Unexpected interrupt received!\n");
+ if (static_branch_likely(&supports_deactivate_key)) {
+ if (irqnr < 8192)
+ gic_write_dir(irqnr);
+ } else {
gic_write_eoir(irqnr);
- else
- isb();
-
- err = handle_domain_irq(gic_data.domain, irqnr, regs);
- if (err) {
- WARN_ONCE(true, "Unexpected interrupt received!\n");
- if (static_branch_likely(&supports_deactivate_key)) {
- if (irqnr < 8192)
- gic_write_dir(irqnr);
- } else {
- gic_write_eoir(irqnr);
- }
}
- continue;
}
- if (irqnr < 16) {
- gic_write_eoir(irqnr);
- if (static_branch_likely(&supports_deactivate_key))
- gic_write_dir(irqnr);
+ return;
+ }
+ if (irqnr < 16) {
+ gic_write_eoir(irqnr);
+ if (static_branch_likely(&supports_deactivate_key))
+ gic_write_dir(irqnr);
#ifdef CONFIG_SMP
- /*
- * Unlike GICv2, we don't need an smp_rmb() here.
- * The control dependency from gic_read_iar to
- * the ISB in gic_write_eoir is enough to ensure
- * that any shared data read by handle_IPI will
- * be read after the ACK.
- */
- handle_IPI(irqnr, regs);
+ /*
+ * Unlike GICv2, we don't need an smp_rmb() here.
+ * The control dependency from gic_read_iar to
+ * the ISB in gic_write_eoir is enough to ensure
+ * that any shared data read by handle_IPI will
+ * be read after the ACK.
+ */
+ handle_IPI(irqnr, regs);
#else
- WARN_ONCE(true, "Unexpected SGI received!\n");
+ WARN_ONCE(true, "Unexpected SGI received!\n");
#endif
- continue;
- }
- } while (irqnr != ICC_IAR1_EL1_SPURIOUS);
+ }
}

static void __init gic_dist_init(void)
--
1.9.1

2018-05-25 09:58:57

by Julien Thierry

[permalink] [raw]
Subject: [PATCH v4 03/26] arm64: cpufeature: Use alternatives for VHE cpu_enable

The cpu_enable callback for VHE feature requires all alternatives to have
been applied. This prevents applying VHE alternative separately from the
rest.

Use an alternative depending on VHE feature to know whether VHE
alternatives have already been applied.

Signed-off-by: Julien Thierry <[email protected]>
Cc: Catalin Marinas <[email protected]>
Cc: Will Deacon <[email protected]>
Cc: Suzuki K Poulose <[email protected]>
Cc: Marc Zyngier <[email protected]>
Cc: Christoffer Dall <[email protected]>
---
arch/arm64/kernel/cpufeature.c | 13 +++++++++++--
1 file changed, 11 insertions(+), 2 deletions(-)

diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c
index a177104..a3a5585d 100644
--- a/arch/arm64/kernel/cpufeature.c
+++ b/arch/arm64/kernel/cpufeature.c
@@ -1013,6 +1013,8 @@ static bool runs_at_el2(const struct arm64_cpu_capabilities *entry, int __unused

static void cpu_copy_el2regs(const struct arm64_cpu_capabilities *__unused)
{
+ u64 tmp = 0;
+
/*
* Copy register values that aren't redirected by hardware.
*
@@ -1021,8 +1023,15 @@ static void cpu_copy_el2regs(const struct arm64_cpu_capabilities *__unused)
* that, freshly-onlined CPUs will set tpidr_el2, so we don't need to
* do anything here.
*/
- if (!alternatives_applied)
- write_sysreg(read_sysreg(tpidr_el1), tpidr_el2);
+ asm volatile(ALTERNATIVE(
+ "mrs %0, tpidr_el1\n"
+ "msr tpidr_el2, %0",
+ "nop\n"
+ "nop",
+ ARM64_HAS_VIRT_HOST_EXTN)
+ : "+r" (tmp)
+ :
+ : "memory");
}
#endif

--
1.9.1


2018-05-25 09:59:36

by Julien Thierry

[permalink] [raw]
Subject: [PATCH v4 01/26] arm64: cpufeature: Set SYSREG_GIC_CPUIF as a boot system feature

Signed-off-by: Julien Thierry <[email protected]>
Suggested-by: Daniel Thompson <[email protected]>
Cc: Catalin Marinas <[email protected]>
Cc: Will Deacon <[email protected]>
Cc: Suzuki K Poulose <[email protected]>
Cc: Marc Zyngier <[email protected]>
---
arch/arm64/kernel/cpufeature.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c
index 9d1b06d..e03e897 100644
--- a/arch/arm64/kernel/cpufeature.c
+++ b/arch/arm64/kernel/cpufeature.c
@@ -1030,7 +1030,7 @@ static void cpu_copy_el2regs(const struct arm64_cpu_capabilities *__unused)
{
.desc = "GIC system register CPU interface",
.capability = ARM64_HAS_SYSREG_GIC_CPUIF,
- .type = ARM64_CPUCAP_SYSTEM_FEATURE,
+ .type = ARM64_CPUCAP_STRICT_BOOT_CPU_FEATURE,
.matches = has_useable_gicv3_cpuif,
.sys_reg = SYS_ID_AA64PFR0_EL1,
.field_pos = ID_AA64PFR0_GIC_SHIFT,
--
1.9.1


2018-05-25 10:01:29

by Suzuki K Poulose

[permalink] [raw]
Subject: Re: [PATCH v4 04/26] arm64: alternative: Apply alternatives early in boot process

On 25/05/18 10:49, Julien Thierry wrote:
> From: Daniel Thompson <[email protected]>
>
> Currently alternatives are applied very late in the boot process (and
> a long time after we enable scheduling). Some alternative sequences,
> such as those that alter the way CPU context is stored, must be applied
> much earlier in the boot sequence.
>
> Introduce apply_boot_alternatives() to allow some alternatives to be
> applied immediately after we detect the CPU features of the boot CPU.
>
> Signed-off-by: Daniel Thompson <[email protected]>
> [[email protected]: rename to fit new cpufeature framework better,
> apply BOOT_SCOPE feature early in boot]
> Signed-off-by: Julien Thierry <[email protected]>
> Cc: Catalin Marinas <[email protected]>
> Cc: Will Deacon <[email protected]>
> Cc: Christoffer Dall <[email protected]>
> Cc: Suzuki K Poulose <[email protected]>
> ---
> arch/arm64/include/asm/alternative.h | 3 +--
> arch/arm64/include/asm/cpufeature.h | 2 ++
> arch/arm64/kernel/alternative.c | 30 +++++++++++++++++++++++++++---
> arch/arm64/kernel/cpufeature.c | 5 +++++
> arch/arm64/kernel/smp.c | 7 +++++++
> 5 files changed, 42 insertions(+), 5 deletions(-)
>

...

>
> +unsigned long boot_capabilities;
> +
> /*
> * Flag to indicate if we have computed the system wide
> * capabilities based on the boot time active CPUs. This
> @@ -1370,6 +1372,9 @@ static void __update_cpu_capabilities(const struct arm64_cpu_capabilities *caps,
> if (!cpus_have_cap(caps->capability) && caps->desc)
> pr_info("%s %s\n", info, caps->desc);
> cpus_set_cap(caps->capability);
> +
> + if (scope_mask & SCOPE_BOOT_CPU)
> + __set_bit(caps->capability, &boot_capabilities);

Julien

I think this check is problematic. The scope_mask passed on by the boot CPU
is (SCOPE_BOOT_CPU | SCOPE_LOCAL_CPU) to cover both BOOT CPU capabilities *and*
CPU local capabilites on the boot CPU. So, you might apply the alternatives for
a "local" CPU erratum, which is not intended. You may change the above check to :

if (caps->type & SCOPE_BOOT_CPU)

to make sure you check the "capability" has the SCOPE_BOOT_CPU set.

Suzuki

2018-05-25 10:06:25

by Suzuki K Poulose

[permalink] [raw]
Subject: Re: [PATCH v4 02/26] arm64: cpufeature: Add cpufeature for IRQ priority masking

On 25/05/18 10:49, Julien Thierry wrote:
> Add a cpufeature indicating whether a cpu supports masking interrupts
> by priority.

How is this different from the SYSREG_GIC_CPUIF cap ? Is it just
the description ?

Suzuki

2018-05-25 10:18:12

by Julien Thierry

[permalink] [raw]
Subject: Re: [PATCH v4 02/26] arm64: cpufeature: Add cpufeature for IRQ priority masking



On 25/05/18 11:04, Suzuki K Poulose wrote:
> On 25/05/18 10:49, Julien Thierry wrote:
>> Add a cpufeature indicating whether a cpu supports masking interrupts
>> by priority.
>
> How is this different from the SYSREG_GIC_CPUIF cap ? Is it just
> the description ?

More or less.

It is just to have an easier condition in the rest of the series.
Basically the PRIO masking feature is enabled if we have a GICv3 CPUIF
working *and* the option was selected at build time. Before this meant
that I was checking for the GIC_CPUIF cap inside #ifdefs (and putting
alternatives depending on that inside #ifdefs as well).

Having this as a separate feature feels easier to manage in the code. It
also makes it clearer at boot time that the kernel will be using irq
priorities (although I admit it was not the initial intention):

[ 0.000000] CPU features: detected: IRQ priority masking


But yes that new feature will be detected only if SYSREG_GIC_CPUIF gets
detected as well.

Cheers,

--
Julien Thierry

2018-05-25 10:18:19

by Daniel Thompson

[permalink] [raw]
Subject: Re: [PATCH v4 00/26] arm64: provide pseudo NMI with GICv3

On Fri, May 25, 2018 at 10:49:06AM +0100, Julien Thierry wrote:
> This series is a continuation of the work started by Daniel [1]. The goal
> is to use GICv3 interrupt priorities to simulate an NMI.
>
> To achieve this, set two priorities, one for standard interrupts and
> another, higher priority, for NMIs. Whenever we want to disable interrupts,
> we mask the standard priority instead so NMIs can still be raised. Some
> corner cases though still require to actually mask all interrupts
> effectively disabling the NMI.
>
> Currently, only PPIs and SPIs can be set as NMIs. IPIs being currently
> hardcoded IRQ numbers, there isn't a generic interface to set SGIs as NMI
> for now. I don't think there is any reason LPIs should be allowed to be set
> as NMI as they do not have an active state.
> When an NMI is active on a CPU, no other NMI can be triggered on the CPU.
>
> After the big refactoring I get performances similar to the ones I had
> in v3[2], reposting old results here:
>
> - "hackbench 200 process 1000" (average over 20 runs)
> +-----------+----------+------------+------------------+
> | | native | PMR guest | v4.17-rc6 guest |
> +-----------+----------+------------+------------------+
> | PMR host | 40.0336s | 39.3039s | 39.2044s |
> | v4.17-rc6 | 40.4040s | 39.6011s | 39.1147s |
> +-----------+----------+------------+------------------+
>
> - Kernel build from defconfig:
> PMR host: 13m45.743s
> v4.17-rc6: 13m40.400s
>
> I'll try to post more detailed benchmarks later if I find notable
> differences with the previous version.

Do you have a public git tree anywhere... I *can* apply 26 patches from
e-mail but I'd rather pull them!


Daniel.

>
>
> Requirements to use this:
> - Have GICv3
> - SCR_EL3.FIQ is set to 1 when linux runs or have single security state
> - Select Kernel Feature -> Use ICC system registers for IRQ masking
>
>
> * Patches 1 to 4 aim at applying some alternatives early in the boot
> process, including the feature for priority masking.
>
> * Patches 5 to 7 and 17 lightly refactor bits of GIC driver to make things
> nicer for the rest of the series.
>
> * Patches 8 to 10 and 16 ensure the logic of daifflags remains valid
> after arch_local_irq flags use ICC_PMR_EL1.
>
> * Patches 11 to 14 do some required PMR treatement in order for things to
> work when the system uses priority masking.
>
> * Patches 15, 18, 19, 20 and 21 actually make the changes to use
> ICC_PMR_EL1 for priority masking/unmasking when disabling/enabling
> interrupts.
>
> * Patches 22 to 26 provide support for pseudo-NMI in the GICv3 driver
> when priority masking is enabled.
>
>
> Changes since V3[2]:
> * Big refactoring. As suggested by Marc Z., some of the bigger patches
> needed to be split into smaller one.
>
> * Try to reduce the amount of #ifdef for the new feature by introducing
> an individual cpufeature for priority masking
>
> * Do not track which alternatives have been applied (was a bit dodgy
> anyway), and use an alternative for VHE cpu_enable callback
>
> * Fix a build failure with arm by adding the correct RPR accessors
>
> * Added Suggested-by tags for changes from comming or inspired by Daniel's
> series. Do let me know if you feel I missed something and am not giving
> you due credit.
>
> Changes since V2[3]:
> * Series rebase to v4.17-rc6
>
> * Adapt pathces 1 and 2 to the rework of cpufeatures framework
>
> * Use the group0 detection scheme in the GICv3 driver to identify
> the priority view, and drop the use of a fake interrupt
>
> * Add the case for a GIC configured in a single security state
>
> * Use local_daif_restore instead of local_irq_enable the first time
> we enable interrupts after a bp hardening in the handling of a kernel
> entry. Otherwise PRS.I remains set...
>
> Changes since V1[4]:
> * Series rebased to v4.15-rc8.
>
> * Check for arm64_early_features in this_cpu_has_cap (spotted by Suzuki).
>
> * Fix issue where debug exception were not masked when enabling debug in
> mdscr_el1.
>
> Changes since RFC[5]:
> * The series was rebased to v4.15-rc2 which implied some changes mainly
> related to the work on exception entries and daif flags by James Morse.
>
> - The first patch in the previous series was dropped because no longer
> applicable.
>
> - With the semantics James introduced of "inheriting" daif flags,
> handling of PMR on exception entry is simplified as PMR is not altered
> by taking an exception and already inherited from previous state.
>
> - James pointed out that taking a PseudoNMI before reading the FAR_EL1
> register should not be allowed as per the TRM (D10.2.29):
> "FAR_EL1 is made UNKNOWN on an exception return from EL1."
> So in this submission PSR.I bit is cleared only after FAR_EL1 is read.
>
> * For KVM, only deal with PMR unmasking/restoring in common code, and VHE
> specific code makes sure PSR.I bit is set when necessary.
>
> * When detecting the GIC priority view (patch 5), wait for an actual
> interrupt instead of trying only once.
>
>
> [1] http://www.spinics.net/lists/arm-kernel/msg525077.html
> [2] https://lkml.org/lkml/2018/5/21/276
> [3] https://lkml.org/lkml/2018/1/17/335
> [4] https://www.spinics.net/lists/arm-kernel/msg620763.html
> [5] https://www.spinics.net/lists/arm-kernel/msg610736.html
>
> Cheers,
>
> Julien
>
> -->
>
> Daniel Thompson (1):
> arm64: alternative: Apply alternatives early in boot process
>
> Julien Thierry (25):
> arm64: cpufeature: Set SYSREG_GIC_CPUIF as a boot system feature
> arm64: cpufeature: Add cpufeature for IRQ priority masking
> arm64: cpufeature: Use alternatives for VHE cpu_enable
> irqchip/gic: Unify GIC priority definitions
> irqchip/gic: Lower priority of GIC interrupts
> irqchip/gic-v3: Remove acknowledge loop
> arm64: daifflags: Use irqflags functions for daifflags
> arm64: Use daifflag_restore after bp_hardening
> arm64: Delay daif masking for user return
> arm64: Make PMR part of task context
> arm64: Unmask PMR before going idle
> arm/arm64: gic-v3: Add helper functions to manage IRQ priorities
> arm64: kvm: Unmask PMR before entering guest
> arm64: irqflags: Use ICC_PMR_EL1 for interrupt masking
> arm64: daifflags: Include PMR in daifflags restore operations
> irqchip/gic-v3: Factor group0 detection into functions
> irqchip/gic-v3: Do not overwrite PMR value
> irqchip/gic-v3: Switch to PMR masking after IRQ acknowledge
> arm64: Switch to PMR masking when starting CPUs
> arm64: Add build option for IRQ masking via priority
> arm64: Detect current view of GIC priorities
> irqchip/gic: Add functions to access irq priorities
> irqchip/gic-v3: Add base support for pseudo-NMI
> irqchip/gic-v3: Provide NMI handlers
> irqchip/gic-v3: Allow interrupts to be set as pseudo-NMI
>
> Documentation/arm64/booting.txt | 5 +
> arch/arm/include/asm/arch_gicv3.h | 33 ++++
> arch/arm64/Kconfig | 15 ++
> arch/arm64/include/asm/alternative.h | 3 +-
> arch/arm64/include/asm/arch_gicv3.h | 32 ++++
> arch/arm64/include/asm/assembler.h | 17 +-
> arch/arm64/include/asm/cpucaps.h | 3 +-
> arch/arm64/include/asm/cpufeature.h | 2 +
> arch/arm64/include/asm/daifflags.h | 32 ++--
> arch/arm64/include/asm/efi.h | 3 +-
> arch/arm64/include/asm/irqflags.h | 100 ++++++++---
> arch/arm64/include/asm/kvm_host.h | 12 ++
> arch/arm64/include/asm/processor.h | 1 +
> arch/arm64/include/asm/ptrace.h | 13 +-
> arch/arm64/kernel/alternative.c | 30 +++-
> arch/arm64/kernel/asm-offsets.c | 1 +
> arch/arm64/kernel/cpufeature.c | 35 +++-
> arch/arm64/kernel/entry.S | 67 ++++++-
> arch/arm64/kernel/head.S | 35 ++++
> arch/arm64/kernel/process.c | 2 +
> arch/arm64/kernel/smp.c | 12 ++
> arch/arm64/kvm/hyp/switch.c | 17 ++
> arch/arm64/mm/fault.c | 5 +-
> arch/arm64/mm/proc.S | 18 ++
> drivers/irqchip/irq-gic-common.c | 10 ++
> drivers/irqchip/irq-gic-common.h | 2 +
> drivers/irqchip/irq-gic-v3-its.c | 2 +-
> drivers/irqchip/irq-gic-v3.c | 318 +++++++++++++++++++++++++++------
> include/linux/interrupt.h | 1 +
> include/linux/irqchip/arm-gic-common.h | 6 +
> include/linux/irqchip/arm-gic.h | 5 -
> 31 files changed, 719 insertions(+), 118 deletions(-)
>
> --
> 1.9.1

2018-05-25 10:26:04

by Julien Thierry

[permalink] [raw]
Subject: Re: [PATCH v4 04/26] arm64: alternative: Apply alternatives early in boot process



On 25/05/18 11:00, Suzuki K Poulose wrote:
> On 25/05/18 10:49, Julien Thierry wrote:
>> From: Daniel Thompson <[email protected]>
>>
>> Currently alternatives are applied very late in the boot process (and
>> a long time after we enable scheduling). Some alternative sequences,
>> such as those that alter the way CPU context is stored, must be applied
>> much earlier in the boot sequence.
>>
>> Introduce apply_boot_alternatives() to allow some alternatives to be
>> applied immediately after we detect the CPU features of the boot CPU.
>>
>> Signed-off-by: Daniel Thompson <[email protected]>
>> [[email protected]: rename to fit new cpufeature framework better,
>>              apply BOOT_SCOPE feature early in boot]
>> Signed-off-by: Julien Thierry <[email protected]>
>> Cc: Catalin Marinas <[email protected]>
>> Cc: Will Deacon <[email protected]>
>> Cc: Christoffer Dall <[email protected]>
>> Cc: Suzuki K Poulose <[email protected]>
>> ---
>>   arch/arm64/include/asm/alternative.h |  3 +--
>>   arch/arm64/include/asm/cpufeature.h  |  2 ++
>>   arch/arm64/kernel/alternative.c      | 30
>> +++++++++++++++++++++++++++---
>>   arch/arm64/kernel/cpufeature.c       |  5 +++++
>>   arch/arm64/kernel/smp.c              |  7 +++++++
>>   5 files changed, 42 insertions(+), 5 deletions(-)
>>
>
> ...
>
>> +unsigned long boot_capabilities;
>> +
>>   /*
>>    * Flag to indicate if we have computed the system wide
>>    * capabilities based on the boot time active CPUs. This
>> @@ -1370,6 +1372,9 @@ static void __update_cpu_capabilities(const
>> struct arm64_cpu_capabilities *caps,
>>           if (!cpus_have_cap(caps->capability) && caps->desc)
>>               pr_info("%s %s\n", info, caps->desc);
>>           cpus_set_cap(caps->capability);
>> +
>> +        if (scope_mask & SCOPE_BOOT_CPU)
>> +            __set_bit(caps->capability, &boot_capabilities);
>
> Julien
>
> I think this check is problematic. The scope_mask passed on by the boot CPU
> is (SCOPE_BOOT_CPU | SCOPE_LOCAL_CPU) to cover both BOOT CPU
> capabilities *and*
> CPU local capabilites on the boot CPU. So, you might apply the
> alternatives for
> a "local" CPU erratum, which is not intended. You may change the above
> check to :
>
>     if (caps->type & SCOPE_BOOT_CPU)
>
> to make sure you check the "capability" has the SCOPE_BOOT_CPU set.
>

Makes sense, I'll do that.

Thanks,

--
Julien Thierry

2018-05-25 10:37:30

by Suzuki K Poulose

[permalink] [raw]
Subject: Re: [PATCH v4 02/26] arm64: cpufeature: Add cpufeature for IRQ priority masking

On 25/05/18 11:17, Julien Thierry wrote:
>
>
> On 25/05/18 11:04, Suzuki K Poulose wrote:
>> On 25/05/18 10:49, Julien Thierry wrote:
>>> Add a cpufeature indicating whether a cpu supports masking interrupts
>>> by priority.
>>
>> How is this different from the SYSREG_GIC_CPUIF cap ? Is it just
>> the description ?
>
> More or less.
>
> It is just to have an easier condition in the rest of the series. Basically the PRIO masking feature is enabled if we have a GICv3 CPUIF working *and* the option was selected at build time. Before this meant that I was checking for the GIC_CPUIF cap inside #ifdefs (and putting alternatives depending on that inside #ifdefs as well).
>
> Having this as a separate feature feels easier to manage in the code. It also makes it clearer at boot time that the kernel will be using irq priorities (although I admit it was not the initial intention):
>
> [    0.000000] CPU features: detected: IRQ priority masking
>
>
> But yes that new feature will be detected only if SYSREG_GIC_CPUIF gets detected as well.

Well, you could always wrap the check like :

static inline bool system_has_irq_priority_masking(void)
{
return (IS_ENABLED(CONFIG_YOUR_CONFIG) && cpus_have_const_cap(HWCAP_SYSREG_GIC_CPUIF));
}

and use it everywhere.

The description could be statically changed to reflect based on the #ifdef.


static const struct arm64_cpu_capabilities arm64_features[] = {
{
#ifdef CONFIG_YOUR_CONFIG
.desc = "GIC System register CPU interface with IRQ priority masking"
#else
.desc = "GIC system register CPU interface",
#endif
.capability = ARM64_HAS_SYSREG_GIC_CPUIF,
.type = ARM64_CPUCAP_SYSTEM_FEATURE,
.matches = has_useable_gicv3_cpuif,
.sys_reg = SYS_ID_AA64PFR0_EL1,
.field_pos = ID_AA64PFR0_GIC_SHIFT,
.sign = FTR_UNSIGNED,
.min_field_value = 1,

Cheers
Suzuki

2018-05-25 10:39:44

by Julien Thierry

[permalink] [raw]
Subject: Re: [PATCH v4 02/26] arm64: cpufeature: Add cpufeature for IRQ priority masking



On 25/05/18 11:36, Suzuki K Poulose wrote:
> On 25/05/18 11:17, Julien Thierry wrote:
>>
>>
>> On 25/05/18 11:04, Suzuki K Poulose wrote:
>>> On 25/05/18 10:49, Julien Thierry wrote:
>>>> Add a cpufeature indicating whether a cpu supports masking interrupts
>>>> by priority.
>>>
>>> How is this different from the SYSREG_GIC_CPUIF cap ? Is it just
>>> the description ?
>>
>> More or less.
>>
>> It is just to have an easier condition in the rest of the series.
>> Basically the PRIO masking feature is enabled if we have a GICv3 CPUIF
>> working *and* the option was selected at build time. Before this meant
>> that I was checking for the GIC_CPUIF cap inside #ifdefs (and putting
>> alternatives depending on that inside #ifdefs as well).
>>
>> Having this as a separate feature feels easier to manage in the code.
>> It also makes it clearer at boot time that the kernel will be using
>> irq priorities (although I admit it was not the initial intention):
>>
>> [    0.000000] CPU features: detected: IRQ priority masking
>>
>>
>> But yes that new feature will be detected only if SYSREG_GIC_CPUIF
>> gets detected as well.
>
> Well, you could always wrap the check like :
>
> static inline bool system_has_irq_priority_masking(void)
> {
>     return (IS_ENABLED(CONFIG_YOUR_CONFIG) &&
> cpus_have_const_cap(HWCAP_SYSREG_GIC_CPUIF));
> }
>
> and use it everywhere.
>

Yes, but I can't use that in the asm parts that use alternatives and
would need to surround them in #ifdef... :\

> The description could be statically changed to reflect based on the #ifdef.
>
>
> static const struct arm64_cpu_capabilities arm64_features[] = {
>         {
> #ifdef CONFIG_YOUR_CONFIG
>         .desc = "GIC System register CPU interface with IRQ priority
> masking"
> #else
>                 .desc = "GIC system register CPU interface",
> #endif
>                 .capability = ARM64_HAS_SYSREG_GIC_CPUIF,
>                 .type = ARM64_CPUCAP_SYSTEM_FEATURE,
>                 .matches = has_useable_gicv3_cpuif,
>                 .sys_reg = SYS_ID_AA64PFR0_EL1,
>                 .field_pos = ID_AA64PFR0_GIC_SHIFT,
>                 .sign = FTR_UNSIGNED,
>                 .min_field_value = 1,
>
> Cheers
> Suzuki

--
Julien Thierry

2018-05-25 10:41:44

by Julien Thierry

[permalink] [raw]
Subject: Re: [PATCH v4 00/26] arm64: provide pseudo NMI with GICv3



On 25/05/18 11:16, Daniel Thompson wrote:
> On Fri, May 25, 2018 at 10:49:06AM +0100, Julien Thierry wrote:
>> This series is a continuation of the work started by Daniel [1]. The goal
>> is to use GICv3 interrupt priorities to simulate an NMI.
>>
>> To achieve this, set two priorities, one for standard interrupts and
>> another, higher priority, for NMIs. Whenever we want to disable interrupts,
>> we mask the standard priority instead so NMIs can still be raised. Some
>> corner cases though still require to actually mask all interrupts
>> effectively disabling the NMI.
>>
>> Currently, only PPIs and SPIs can be set as NMIs. IPIs being currently
>> hardcoded IRQ numbers, there isn't a generic interface to set SGIs as NMI
>> for now. I don't think there is any reason LPIs should be allowed to be set
>> as NMI as they do not have an active state.
>> When an NMI is active on a CPU, no other NMI can be triggered on the CPU.
>>
>> After the big refactoring I get performances similar to the ones I had
>> in v3[2], reposting old results here:
>>
>> - "hackbench 200 process 1000" (average over 20 runs)
>> +-----------+----------+------------+------------------+
>> | | native | PMR guest | v4.17-rc6 guest |
>> +-----------+----------+------------+------------------+
>> | PMR host | 40.0336s | 39.3039s | 39.2044s |
>> | v4.17-rc6 | 40.4040s | 39.6011s | 39.1147s |
>> +-----------+----------+------------+------------------+
>>
>> - Kernel build from defconfig:
>> PMR host: 13m45.743s
>> v4.17-rc6: 13m40.400s
>>
>> I'll try to post more detailed benchmarks later if I find notable
>> differences with the previous version.
>
> Do you have a public git tree anywhere... I *can* apply 26 patches from
> e-mail but I'd rather pull them!
>

Yes that makes sense, I'll try to get one set up.

I'll let you know once I have done so.

Cheers,

>
> Daniel.
>
>>
>>
>> Requirements to use this:
>> - Have GICv3
>> - SCR_EL3.FIQ is set to 1 when linux runs or have single security state
>> - Select Kernel Feature -> Use ICC system registers for IRQ masking
>>
>>
>> * Patches 1 to 4 aim at applying some alternatives early in the boot
>> process, including the feature for priority masking.
>>
>> * Patches 5 to 7 and 17 lightly refactor bits of GIC driver to make things
>> nicer for the rest of the series.
>>
>> * Patches 8 to 10 and 16 ensure the logic of daifflags remains valid
>> after arch_local_irq flags use ICC_PMR_EL1.
>>
>> * Patches 11 to 14 do some required PMR treatement in order for things to
>> work when the system uses priority masking.
>>
>> * Patches 15, 18, 19, 20 and 21 actually make the changes to use
>> ICC_PMR_EL1 for priority masking/unmasking when disabling/enabling
>> interrupts.
>>
>> * Patches 22 to 26 provide support for pseudo-NMI in the GICv3 driver
>> when priority masking is enabled.
>>
>>
>> Changes since V3[2]:
>> * Big refactoring. As suggested by Marc Z., some of the bigger patches
>> needed to be split into smaller one.
>>
>> * Try to reduce the amount of #ifdef for the new feature by introducing
>> an individual cpufeature for priority masking
>>
>> * Do not track which alternatives have been applied (was a bit dodgy
>> anyway), and use an alternative for VHE cpu_enable callback
>>
>> * Fix a build failure with arm by adding the correct RPR accessors
>>
>> * Added Suggested-by tags for changes from comming or inspired by Daniel's
>> series. Do let me know if you feel I missed something and am not giving
>> you due credit.
>>
>> Changes since V2[3]:
>> * Series rebase to v4.17-rc6
>>
>> * Adapt pathces 1 and 2 to the rework of cpufeatures framework
>>
>> * Use the group0 detection scheme in the GICv3 driver to identify
>> the priority view, and drop the use of a fake interrupt
>>
>> * Add the case for a GIC configured in a single security state
>>
>> * Use local_daif_restore instead of local_irq_enable the first time
>> we enable interrupts after a bp hardening in the handling of a kernel
>> entry. Otherwise PRS.I remains set...
>>
>> Changes since V1[4]:
>> * Series rebased to v4.15-rc8.
>>
>> * Check for arm64_early_features in this_cpu_has_cap (spotted by Suzuki).
>>
>> * Fix issue where debug exception were not masked when enabling debug in
>> mdscr_el1.
>>
>> Changes since RFC[5]:
>> * The series was rebased to v4.15-rc2 which implied some changes mainly
>> related to the work on exception entries and daif flags by James Morse.
>>
>> - The first patch in the previous series was dropped because no longer
>> applicable.
>>
>> - With the semantics James introduced of "inheriting" daif flags,
>> handling of PMR on exception entry is simplified as PMR is not altered
>> by taking an exception and already inherited from previous state.
>>
>> - James pointed out that taking a PseudoNMI before reading the FAR_EL1
>> register should not be allowed as per the TRM (D10.2.29):
>> "FAR_EL1 is made UNKNOWN on an exception return from EL1."
>> So in this submission PSR.I bit is cleared only after FAR_EL1 is read.
>>
>> * For KVM, only deal with PMR unmasking/restoring in common code, and VHE
>> specific code makes sure PSR.I bit is set when necessary.
>>
>> * When detecting the GIC priority view (patch 5), wait for an actual
>> interrupt instead of trying only once.
>>
>>
>> [1] http://www.spinics.net/lists/arm-kernel/msg525077.html
>> [2] https://lkml.org/lkml/2018/5/21/276
>> [3] https://lkml.org/lkml/2018/1/17/335
>> [4] https://www.spinics.net/lists/arm-kernel/msg620763.html
>> [5] https://www.spinics.net/lists/arm-kernel/msg610736.html
>>
>> Cheers,
>>
>> Julien
>>
>> -->
>>
>> Daniel Thompson (1):
>> arm64: alternative: Apply alternatives early in boot process
>>
>> Julien Thierry (25):
>> arm64: cpufeature: Set SYSREG_GIC_CPUIF as a boot system feature
>> arm64: cpufeature: Add cpufeature for IRQ priority masking
>> arm64: cpufeature: Use alternatives for VHE cpu_enable
>> irqchip/gic: Unify GIC priority definitions
>> irqchip/gic: Lower priority of GIC interrupts
>> irqchip/gic-v3: Remove acknowledge loop
>> arm64: daifflags: Use irqflags functions for daifflags
>> arm64: Use daifflag_restore after bp_hardening
>> arm64: Delay daif masking for user return
>> arm64: Make PMR part of task context
>> arm64: Unmask PMR before going idle
>> arm/arm64: gic-v3: Add helper functions to manage IRQ priorities
>> arm64: kvm: Unmask PMR before entering guest
>> arm64: irqflags: Use ICC_PMR_EL1 for interrupt masking
>> arm64: daifflags: Include PMR in daifflags restore operations
>> irqchip/gic-v3: Factor group0 detection into functions
>> irqchip/gic-v3: Do not overwrite PMR value
>> irqchip/gic-v3: Switch to PMR masking after IRQ acknowledge
>> arm64: Switch to PMR masking when starting CPUs
>> arm64: Add build option for IRQ masking via priority
>> arm64: Detect current view of GIC priorities
>> irqchip/gic: Add functions to access irq priorities
>> irqchip/gic-v3: Add base support for pseudo-NMI
>> irqchip/gic-v3: Provide NMI handlers
>> irqchip/gic-v3: Allow interrupts to be set as pseudo-NMI
>>
>> Documentation/arm64/booting.txt | 5 +
>> arch/arm/include/asm/arch_gicv3.h | 33 ++++
>> arch/arm64/Kconfig | 15 ++
>> arch/arm64/include/asm/alternative.h | 3 +-
>> arch/arm64/include/asm/arch_gicv3.h | 32 ++++
>> arch/arm64/include/asm/assembler.h | 17 +-
>> arch/arm64/include/asm/cpucaps.h | 3 +-
>> arch/arm64/include/asm/cpufeature.h | 2 +
>> arch/arm64/include/asm/daifflags.h | 32 ++--
>> arch/arm64/include/asm/efi.h | 3 +-
>> arch/arm64/include/asm/irqflags.h | 100 ++++++++---
>> arch/arm64/include/asm/kvm_host.h | 12 ++
>> arch/arm64/include/asm/processor.h | 1 +
>> arch/arm64/include/asm/ptrace.h | 13 +-
>> arch/arm64/kernel/alternative.c | 30 +++-
>> arch/arm64/kernel/asm-offsets.c | 1 +
>> arch/arm64/kernel/cpufeature.c | 35 +++-
>> arch/arm64/kernel/entry.S | 67 ++++++-
>> arch/arm64/kernel/head.S | 35 ++++
>> arch/arm64/kernel/process.c | 2 +
>> arch/arm64/kernel/smp.c | 12 ++
>> arch/arm64/kvm/hyp/switch.c | 17 ++
>> arch/arm64/mm/fault.c | 5 +-
>> arch/arm64/mm/proc.S | 18 ++
>> drivers/irqchip/irq-gic-common.c | 10 ++
>> drivers/irqchip/irq-gic-common.h | 2 +
>> drivers/irqchip/irq-gic-v3-its.c | 2 +-
>> drivers/irqchip/irq-gic-v3.c | 318 +++++++++++++++++++++++++++------
>> include/linux/interrupt.h | 1 +
>> include/linux/irqchip/arm-gic-common.h | 6 +
>> include/linux/irqchip/arm-gic.h | 5 -
>> 31 files changed, 719 insertions(+), 118 deletions(-)
>>
>> --
>> 1.9.1

--
Julien Thierry

2018-05-25 10:42:39

by Suzuki K Poulose

[permalink] [raw]
Subject: Re: [PATCH v4 02/26] arm64: cpufeature: Add cpufeature for IRQ priority masking

On 25/05/18 11:39, Julien Thierry wrote:
>
>
> On 25/05/18 11:36, Suzuki K Poulose wrote:
>> On 25/05/18 11:17, Julien Thierry wrote:
>>>
>>>
>>> On 25/05/18 11:04, Suzuki K Poulose wrote:
>>>> On 25/05/18 10:49, Julien Thierry wrote:
>>>>> Add a cpufeature indicating whether a cpu supports masking interrupts
>>>>> by priority.
>>>>
>>>> How is this different from the SYSREG_GIC_CPUIF cap ? Is it just
>>>> the description ?
>>>
>>> More or less.
>>>
>>> It is just to have an easier condition in the rest of the series. Basically the PRIO masking feature is enabled if we have a GICv3 CPUIF working *and* the option was selected at build time. Before this meant that I was checking for the GIC_CPUIF cap inside #ifdefs (and putting alternatives depending on that inside #ifdefs as well).
>>>
>>> Having this as a separate feature feels easier to manage in the code. It also makes it clearer at boot time that the kernel will be using irq priorities (although I admit it was not the initial intention):
>>>
>>> [    0.000000] CPU features: detected: IRQ priority masking
>>>
>>>
>>> But yes that new feature will be detected only if SYSREG_GIC_CPUIF gets detected as well.
>>
>> Well, you could always wrap the check like :
>>
>> static inline bool system_has_irq_priority_masking(void)
>> {
>>      return (IS_ENABLED(CONFIG_YOUR_CONFIG) && cpus_have_const_cap(HWCAP_SYSREG_GIC_CPUIF));
>> }
>>
>> and use it everywhere.
>>
>
> Yes, but I can't use that in the asm parts that use alternatives and would need to surround them in #ifdef... :\

I thought there is _ALTERNATIVE_CFG() to base the alternative depend on a CONFIG_xxx ?
Doesn't that solve the problem ?

Suzuki

2018-05-25 10:48:57

by Julien Thierry

[permalink] [raw]
Subject: Re: [PATCH v4 02/26] arm64: cpufeature: Add cpufeature for IRQ priority masking



On 25/05/18 11:41, Suzuki K Poulose wrote:
> On 25/05/18 11:39, Julien Thierry wrote:
>>
>>
>> On 25/05/18 11:36, Suzuki K Poulose wrote:
>>> On 25/05/18 11:17, Julien Thierry wrote:
>>>>
>>>>
>>>> On 25/05/18 11:04, Suzuki K Poulose wrote:
>>>>> On 25/05/18 10:49, Julien Thierry wrote:
>>>>>> Add a cpufeature indicating whether a cpu supports masking interrupts
>>>>>> by priority.
>>>>>
>>>>> How is this different from the SYSREG_GIC_CPUIF cap ? Is it just
>>>>> the description ?
>>>>
>>>> More or less.
>>>>
>>>> It is just to have an easier condition in the rest of the series.
>>>> Basically the PRIO masking feature is enabled if we have a GICv3
>>>> CPUIF working *and* the option was selected at build time. Before
>>>> this meant that I was checking for the GIC_CPUIF cap inside #ifdefs
>>>> (and putting alternatives depending on that inside #ifdefs as well).
>>>>
>>>> Having this as a separate feature feels easier to manage in the
>>>> code. It also makes it clearer at boot time that the kernel will be
>>>> using irq priorities (although I admit it was not the initial
>>>> intention):
>>>>
>>>> [    0.000000] CPU features: detected: IRQ priority masking
>>>>
>>>>
>>>> But yes that new feature will be detected only if SYSREG_GIC_CPUIF
>>>> gets detected as well.
>>>
>>> Well, you could always wrap the check like :
>>>
>>> static inline bool system_has_irq_priority_masking(void)
>>> {
>>>      return (IS_ENABLED(CONFIG_YOUR_CONFIG) &&
>>> cpus_have_const_cap(HWCAP_SYSREG_GIC_CPUIF));
>>> }
>>>
>>> and use it everywhere.
>>>
>>
>> Yes, but I can't use that in the asm parts that use alternatives and
>> would need to surround them in #ifdef... :\
>
> I thought there is _ALTERNATIVE_CFG() to base the alternative depend on
> a CONFIG_xxx ?
> Doesn't that solve the problem ?

Right, I didn't see that one. It should work yes.

I'll try that when working on the next version.

Thanks,

--
Julien Thierry

2018-05-25 13:44:48

by Julien Thierry

[permalink] [raw]
Subject: Re: [PATCH v4 00/26] arm64: provide pseudo NMI with GICv3



On 25/05/18 11:40, Julien Thierry wrote:
>
>
> On 25/05/18 11:16, Daniel Thompson wrote:
>> On Fri, May 25, 2018 at 10:49:06AM +0100, Julien Thierry wrote:
>>> This series is a continuation of the work started by Daniel [1]. The
>>> goal
>>> is to use GICv3 interrupt priorities to simulate an NMI.
>>>
>>> To achieve this, set two priorities, one for standard interrupts and
>>> another, higher priority, for NMIs. Whenever we want to disable
>>> interrupts,
>>> we mask the standard priority instead so NMIs can still be raised. Some
>>> corner cases though still require to actually mask all interrupts
>>> effectively disabling the NMI.
>>>
>>> Currently, only PPIs and SPIs can be set as NMIs. IPIs being currently
>>> hardcoded IRQ numbers, there isn't a generic interface to set SGIs as
>>> NMI
>>> for now. I don't think there is any reason LPIs should be allowed to
>>> be set
>>> as NMI as they do not have an active state.
>>> When an NMI is active on a CPU, no other NMI can be triggered on the
>>> CPU.
>>>
>>> After the big refactoring I get performances similar to the ones I had
>>> in v3[2], reposting old results here:
>>>
>>> - "hackbench 200 process 1000" (average over 20 runs)
>>> +-----------+----------+------------+------------------+
>>> |           | native   | PMR guest  | v4.17-rc6 guest  |
>>> +-----------+----------+------------+------------------+
>>> | PMR host  | 40.0336s |   39.3039s |         39.2044s |
>>> | v4.17-rc6 | 40.4040s |   39.6011s |         39.1147s |
>>> +-----------+----------+------------+------------------+
>>>
>>> - Kernel build from defconfig:
>>> PMR host:  13m45.743s
>>> v4.17-rc6: 13m40.400s
>>>
>>> I'll try to post more detailed benchmarks later if I find notable
>>> differences with the previous version.
>>
>> Do you have a public git tree anywhere... I *can* apply 26 patches from
>> e-mail but I'd rather pull them!
>>
>
> Yes that makes sense, I'll try to get one set up.
>
> I'll let you know once I have done so.

My public git is up. You can pull the patches from:

git://linux-arm.org/linux-jt.git v4.17-pseudo-nmi

Cheers,

--
Julien Thierry

2018-06-12 13:47:25

by Julien Thierry

[permalink] [raw]
Subject: Re: [PATCH v4 02/26] arm64: cpufeature: Add cpufeature for IRQ priority masking



On 25/05/18 11:48, Julien Thierry wrote:
>
>
> On 25/05/18 11:41, Suzuki K Poulose wrote:
>> On 25/05/18 11:39, Julien Thierry wrote:
>>>
>>>
>>> On 25/05/18 11:36, Suzuki K Poulose wrote:
>>>> On 25/05/18 11:17, Julien Thierry wrote:
>>>>>
>>>>>
>>>>> On 25/05/18 11:04, Suzuki K Poulose wrote:
>>>>>> On 25/05/18 10:49, Julien Thierry wrote:
>>>>>>> Add a cpufeature indicating whether a cpu supports masking
>>>>>>> interrupts
>>>>>>> by priority.
>>>>>>
>>>>>> How is this different from the SYSREG_GIC_CPUIF cap ? Is it just
>>>>>> the description ?
>>>>>
>>>>> More or less.
>>>>>
>>>>> It is just to have an easier condition in the rest of the series.
>>>>> Basically the PRIO masking feature is enabled if we have a GICv3
>>>>> CPUIF working *and* the option was selected at build time. Before
>>>>> this meant that I was checking for the GIC_CPUIF cap inside #ifdefs
>>>>> (and putting alternatives depending on that inside #ifdefs as well).
>>>>>
>>>>> Having this as a separate feature feels easier to manage in the
>>>>> code. It also makes it clearer at boot time that the kernel will be
>>>>> using irq priorities (although I admit it was not the initial
>>>>> intention):
>>>>>
>>>>> [    0.000000] CPU features: detected: IRQ priority masking
>>>>>
>>>>>
>>>>> But yes that new feature will be detected only if SYSREG_GIC_CPUIF
>>>>> gets detected as well.
>>>>
>>>> Well, you could always wrap the check like :
>>>>
>>>> static inline bool system_has_irq_priority_masking(void)
>>>> {
>>>>      return (IS_ENABLED(CONFIG_YOUR_CONFIG) &&
>>>> cpus_have_const_cap(HWCAP_SYSREG_GIC_CPUIF));
>>>> }
>>>>
>>>> and use it everywhere.
>>>>
>>>
>>> Yes, but I can't use that in the asm parts that use alternatives and
>>> would need to surround them in #ifdef... :\
>>
>> I thought there is _ALTERNATIVE_CFG() to base the alternative depend
>> on a CONFIG_xxx ?
>> Doesn't that solve the problem ?
>
> Right, I didn't see that one. It should work yes.
>
> I'll try that when working on the next version.

I've been trying to use this now, but I can't figure out how.

The _ALTERNATIVE_CFG does not seem to work in assembly code (despite
having its own definition for __ASSEMBLY__), and the alternative_insn
does not seem to be suited for instructions that take operands (or more
than one operand)

If I am mistaken, can you provide an example of how to use this in
assembly with instructions having more than 1 operand?

Cheers,

--
Julien Thierry

2018-06-13 11:08:12

by Julien Thierry

[permalink] [raw]
Subject: Re: [PATCH v4 26/26] irqchip/gic-v3: Allow interrupts to be set as pseudo-NMI



On 25/05/18 10:49, Julien Thierry wrote:
> Provide a way to set a GICv3 interrupt as pseudo-NMI. The interrupt
> must not be enabled when setting/clearing the NMI status of the interrupt.
>
> Signed-off-by: Julien Thierry <[email protected]>
> Cc: Thomas Gleixner <[email protected]>
> Cc: Jason Cooper <[email protected]>
> Cc: Marc Zyngier <[email protected]>
> ---
> drivers/irqchip/irq-gic-v3.c | 54 ++++++++++++++++++++++++++++++++++++++++++++
> include/linux/interrupt.h | 1 +
> 2 files changed, 55 insertions(+)
>

[...]

> diff --git a/include/linux/interrupt.h b/include/linux/interrupt.h
> index 5426627..02c794f 100644
> --- a/include/linux/interrupt.h
> +++ b/include/linux/interrupt.h
> @@ -419,6 +419,7 @@ enum irqchip_irq_state {
> IRQCHIP_STATE_ACTIVE, /* Is interrupt in progress? */
> IRQCHIP_STATE_MASKED, /* Is interrupt masked? */
> IRQCHIP_STATE_LINE_LEVEL, /* Is IRQ line high? */
> + IRQCHIP_STATE_NMI, /* Is IRQ an NMI? */
> };

After discussing with Thomas, NMI setting should not be exposed/managed
through the generic irq interface.

--
Julien Thierry

2018-06-13 11:15:30

by Julien Thierry

[permalink] [raw]
Subject: Re: [PATCH v4 24/26] irqchip/gic-v3: Add base support for pseudo-NMI



On 25/05/18 10:49, Julien Thierry wrote:
> Provide a higher priority to be used for pseudo-NMIs. When such an
> interrupt is received, enter the NMI state and prevent other NMIs to
> be raised.
>
> When returning from a pseudo-NMI, skip preemption and tracing if the
> interrupted context has interrupts disabled.
>
> Signed-off-by: Julien Thierry <[email protected]>
> Cc: Russell King <[email protected]>
> Cc: Catalin Marinas <[email protected]>
> Cc: Will Deacon <[email protected]>
> Cc: Thomas Gleixner <[email protected]>
> Cc: Jason Cooper <[email protected]>
> Cc: Marc Zyngier <[email protected]>
> ---
> arch/arm/include/asm/arch_gicv3.h | 6 ++++++
> arch/arm64/include/asm/arch_gicv3.h | 6 ++++++
> arch/arm64/kernel/entry.S | 43 +++++++++++++++++++++++++++++++++++++
> drivers/irqchip/irq-gic-v3.c | 41 +++++++++++++++++++++++++++++++++++
> 4 files changed, 96 insertions(+)
>

[...]

> diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c
> index b144f73..4be5996 100644
> --- a/drivers/irqchip/irq-gic-v3.c
> +++ b/drivers/irqchip/irq-gic-v3.c
> @@ -371,6 +379,20 @@ static u64 gic_mpidr_to_affinity(unsigned long mpidr)
> return aff;
> }
>
> +static void do_handle_nmi(unsigned int hwirq, struct pt_regs *regs)
> +{
> + struct pt_regs *old_regs = set_irq_regs(regs);
> + unsigned int irq;
> +
> + nmi_enter();

RAS/SEA also enters NMI state and things will break if asynchronous
error occurs during a pseudo-NMI.

I'll have this fixed in the next version.

--
Julien Thierry

2018-06-15 10:19:01

by Suzuki K Poulose

[permalink] [raw]
Subject: Re: [PATCH v4 02/26] arm64: cpufeature: Add cpufeature for IRQ priority masking

On 12/06/18 14:46, Julien Thierry wrote:
>
>
> On 25/05/18 11:48, Julien Thierry wrote:
>>
>>
>> On 25/05/18 11:41, Suzuki K Poulose wrote:
>>> On 25/05/18 11:39, Julien Thierry wrote:
>>>>
>>>>
>>>> On 25/05/18 11:36, Suzuki K Poulose wrote:
>>>>> On 25/05/18 11:17, Julien Thierry wrote:
>>>>>>
>>>>>>
>>>>>> On 25/05/18 11:04, Suzuki K Poulose wrote:
>>>>>>> On 25/05/18 10:49, Julien Thierry wrote:
>>>>>>>> Add a cpufeature indicating whether a cpu supports masking interrupts
>>>>>>>> by priority.
>>>>>>>
>>>>>>> How is this different from the SYSREG_GIC_CPUIF cap ? Is it just
>>>>>>> the description ?
>>>>>>
>>>>>> More or less.
>>>>>>
>>>>>> It is just to have an easier condition in the rest of the series. Basically the PRIO masking feature is enabled if we have a GICv3 CPUIF working *and* the option was selected at build time. Before this meant that I was checking for the GIC_CPUIF cap inside #ifdefs (and putting alternatives depending on that inside #ifdefs as well).
>>>>>>
>>>>>> Having this as a separate feature feels easier to manage in the code. It also makes it clearer at boot time that the kernel will be using irq priorities (although I admit it was not the initial intention):
>>>>>>
>>>>>> [    0.000000] CPU features: detected: IRQ priority masking
>>>>>>
>>>>>>
>>>>>> But yes that new feature will be detected only if SYSREG_GIC_CPUIF gets detected as well.
>>>>>
>>>>> Well, you could always wrap the check like :
>>>>>
>>>>> static inline bool system_has_irq_priority_masking(void)
>>>>> {
>>>>>      return (IS_ENABLED(CONFIG_YOUR_CONFIG) && cpus_have_const_cap(HWCAP_SYSREG_GIC_CPUIF));
>>>>> }
>>>>>
>>>>> and use it everywhere.
>>>>>
>>>>
>>>> Yes, but I can't use that in the asm parts that use alternatives and would need to surround them in #ifdef... :\
>>>
>>> I thought there is _ALTERNATIVE_CFG() to base the alternative depend on a CONFIG_xxx ?
>>> Doesn't that solve the problem ?
>>
>> Right, I didn't see that one. It should work yes.
>>
>> I'll try that when working on the next version.
>
> I've been trying to use this now, but I can't figure out how.
>
> The _ALTERNATIVE_CFG does not seem to work in assembly code (despite having its own definition for __ASSEMBLY__), and the alternative_insn does not seem to be suited for instructions that take operands (or more than one operand)
>
> If I am mistaken, can you provide an example of how to use this in assembly with instructions having more than 1 operand?

I am sorry, but I think the ALTERNATIVE_CFG is not the right one, as it
omits the entire block, if the CONFIG is not enabled. So you are left with
only three choices :

1) Use alternative call back
2) Stick to two separate caps.
3) Use #ifdef

Cheers
Suzuki


2018-07-20 15:10:40

by Daniel Thompson

[permalink] [raw]
Subject: Re: [PATCH v4 00/26] arm64: provide pseudo NMI with GICv3

On Fri, May 25, 2018 at 10:49:06AM +0100, Julien Thierry wrote:
> This series is a continuation of the work started by Daniel [1]. The goal
> is to use GICv3 interrupt priorities to simulate an NMI.
>
> To achieve this, set two priorities, one for standard interrupts and
> another, higher priority, for NMIs. Whenever we want to disable interrupts,
> we mask the standard priority instead so NMIs can still be raised. Some
> corner cases though still require to actually mask all interrupts
> effectively disabling the NMI.
>
> Currently, only PPIs and SPIs can be set as NMIs. IPIs being currently
> hardcoded IRQ numbers, there isn't a generic interface to set SGIs as NMI
> for now. I don't think there is any reason LPIs should be allowed to be set
> as NMI as they do not have an active state.
> When an NMI is active on a CPU, no other NMI can be triggered on the CPU.
>
> After the big refactoring I get performances similar to the ones I had
> in v3[2], reposting old results here:
>
> - "hackbench 200 process 1000" (average over 20 runs)
> +-----------+----------+------------+------------------+
> | | native | PMR guest | v4.17-rc6 guest |
> +-----------+----------+------------+------------------+
> | PMR host | 40.0336s | 39.3039s | 39.2044s |
> | v4.17-rc6 | 40.4040s | 39.6011s | 39.1147s |
> +-----------+----------+------------+------------------+
>
> - Kernel build from defconfig:
> PMR host: 13m45.743s
> v4.17-rc6: 13m40.400s
>
> I'll try to post more detailed benchmarks later if I find notable
> differences with the previous version.

So... I'm rather late sharing these benchmarks but...

I ran some kernel build benchmarks on the Developerbox from 96Boards
(aka Synquacer E-series by Socionext): 24 C-A53 cores running at 1GHz.
This is obviously a real workload and one that anything called
Developerbox needs to care about!

The difference in performance is slight but PMR based locking is
marginally slower than using the I-bit. It varies with the
parrallel-ness of the build slightly but the slowdown on this platform
is between 0.2% and 0.6% [1].

This delta was sufficiently small that I was willing to leave the PMR
masking in place for a fair amount of my day to day work. On that basis
these patches could also be described as:

Tested-by: Daniel Thompson <[email protected]>


Daniel.


[1] For anyone interested in the raw numbers then the spreadsheet where
I checked the results is here:
https://docs.google.com/spreadsheets/d/1gGxAJd_gL-HjeTF-x0Ut5lWT4JULNRDeTbPvPInZ4H4/edit?usp=sharing

2018-07-23 12:40:22

by Julien Thierry

[permalink] [raw]
Subject: Re: [PATCH v4 00/26] arm64: provide pseudo NMI with GICv3

Hi Daniel,

On 20/07/18 16:09, Daniel Thompson wrote:
> On Fri, May 25, 2018 at 10:49:06AM +0100, Julien Thierry wrote:
>> This series is a continuation of the work started by Daniel [1]. The goal
>> is to use GICv3 interrupt priorities to simulate an NMI.
>>
>> To achieve this, set two priorities, one for standard interrupts and
>> another, higher priority, for NMIs. Whenever we want to disable interrupts,
>> we mask the standard priority instead so NMIs can still be raised. Some
>> corner cases though still require to actually mask all interrupts
>> effectively disabling the NMI.
>>
>> Currently, only PPIs and SPIs can be set as NMIs. IPIs being currently
>> hardcoded IRQ numbers, there isn't a generic interface to set SGIs as NMI
>> for now. I don't think there is any reason LPIs should be allowed to be set
>> as NMI as they do not have an active state.
>> When an NMI is active on a CPU, no other NMI can be triggered on the CPU.
>>
>> After the big refactoring I get performances similar to the ones I had
>> in v3[2], reposting old results here:
>>
>> - "hackbench 200 process 1000" (average over 20 runs)
>> +-----------+----------+------------+------------------+
>> | | native | PMR guest | v4.17-rc6 guest |
>> +-----------+----------+------------+------------------+
>> | PMR host | 40.0336s | 39.3039s | 39.2044s |
>> | v4.17-rc6 | 40.4040s | 39.6011s | 39.1147s |
>> +-----------+----------+------------+------------------+
>>
>> - Kernel build from defconfig:
>> PMR host: 13m45.743s
>> v4.17-rc6: 13m40.400s
>>
>> I'll try to post more detailed benchmarks later if I find notable
>> differences with the previous version.
>
> So... I'm rather late sharing these benchmarks but...
>
> I ran some kernel build benchmarks on the Developerbox from 96Boards
> (aka Synquacer E-series by Socionext): 24 C-A53 cores running at 1GHz.
> This is obviously a real workload and one that anything called
> Developerbox needs to care about!
>
> The difference in performance is slight but PMR based locking is
> marginally slower than using the I-bit. It varies with the
> parrallel-ness of the build slightly but the slowdown on this platform
> is between 0.2% and 0.6% [1].
>
> This delta was sufficiently small that I was willing to leave the PMR
> masking in place for a fair amount of my day to day work. On that basis
> these patches could also be described as:
>
> Tested-by: Daniel Thompson <[email protected]>
>

Thanks very much for doing this testing. Things have changed a bit in
the NMI side of the series and I am trying to get a saner API to get
upstreamed before posting a new version of these patches. But the PMR
masking/unmasking remains the same so the benchmarks should still be
valid in the future version.

Thanks,

>
> Daniel.
>
>
> [1] For anyone interested in the raw numbers then the spreadsheet where
> I checked the results is here:
> https://docs.google.com/spreadsheets/d/1gGxAJd_gL-HjeTF-x0Ut5lWT4JULNRDeTbPvPInZ4H4/edit?usp=sharing
>

--
Julien Thierry