Merge tag 'arm64-upstream' of git://git.kernel.org/pub/scm/linux/kernel/git/arm64/linux
Pull arm64 updates from Catalin Marinas: - Pseudo NMI support for arm64 using GICv3 interrupt priorities - uaccess macros clean-up (unsafe user accessors also merged but reverted, waiting for objtool support on arm64) - ptrace regsets for Pointer Authentication (ARMv8.3) key management - inX() ordering w.r.t. delay() on arm64 and riscv (acks in place by the riscv maintainers) - arm64/perf updates: PMU bindings converted to json-schema, unused variable and misleading comment removed - arm64/debug fixes to ensure checking of the triggering exception level and to avoid the propagation of the UNKNOWN FAR value into the si_code for debug signals - Workaround for Fujitsu A64FX erratum 010001 - lib/raid6 ARM NEON optimisations - NR_CPUS now defaults to 256 on arm64 - Minor clean-ups (documentation/comments, Kconfig warning, unused asm-offsets, clang warnings) - MAINTAINERS update for list information to the ARM64 ACPI entry * tag 'arm64-upstream' of git://git.kernel.org/pub/scm/linux/kernel/git/arm64/linux: (54 commits) arm64: mmu: drop paging_init comments arm64: debug: Ensure debug handlers check triggering exception level arm64: debug: Don't propagate UNKNOWN FAR into si_code for debug signals Revert "arm64: uaccess: Implement unsafe accessors" arm64: avoid clang warning about self-assignment arm64: Kconfig.platforms: fix warning unmet direct dependencies lib/raid6: arm: optimize away a mask operation in NEON recovery routine lib/raid6: use vdupq_n_u8 to avoid endianness warnings arm64: io: Hook up __io_par() for inX() ordering riscv: io: Update __io_[p]ar() macros to take an argument asm-generic/io: Pass result of I/O accessor to __io_[p]ar() arm64: Add workaround for Fujitsu A64FX erratum 010001 arm64: Rename get_thread_info() arm64: Remove documentation about TIF_USEDFPU arm64: irqflags: Fix clang build warnings arm64: Enable the support of pseudo-NMIs arm64: Skip irqflags tracing for NMI in IRQs disabled context arm64: Skip preemption when exiting an NMI arm64: Handle serror in NMI context irqchip/gic-v3: Allow interrupts to be set as pseudo-NMI ...
This commit is contained in:
@@ -27,6 +27,7 @@
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/of_irq.h>
|
||||
#include <linux/percpu.h>
|
||||
#include <linux/refcount.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#include <linux/irqchip.h>
|
||||
@@ -41,6 +42,8 @@
|
||||
|
||||
#include "irq-gic-common.h"
|
||||
|
||||
#define GICD_INT_NMI_PRI (GICD_INT_DEF_PRI & ~0x80)
|
||||
|
||||
#define FLAGS_WORKAROUND_GICR_WAKER_MSM8996 (1ULL << 0)
|
||||
|
||||
struct redist_region {
|
||||
@@ -66,6 +69,34 @@ 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.
|
||||
*
|
||||
* For now, we only support pseudo-NMIs if we have non-secure view of
|
||||
* priorities.
|
||||
*/
|
||||
static DEFINE_STATIC_KEY_FALSE(supports_pseudo_nmis);
|
||||
|
||||
/* ppi_nmi_refs[n] == number of cpus having ppi[n + 16] set as NMI */
|
||||
static refcount_t ppi_nmi_refs[16];
|
||||
|
||||
static struct gic_kvm_info gic_v3_kvm_info;
|
||||
static DEFINE_PER_CPU(bool, has_rss);
|
||||
|
||||
@@ -232,6 +263,12 @@ static void gic_unmask_irq(struct irq_data *d)
|
||||
gic_poke_irq(d, GICD_ISENABLER);
|
||||
}
|
||||
|
||||
static inline bool gic_supports_nmi(void)
|
||||
{
|
||||
return IS_ENABLED(CONFIG_ARM64_PSEUDO_NMI) &&
|
||||
static_branch_likely(&supports_pseudo_nmis);
|
||||
}
|
||||
|
||||
static int gic_irq_set_irqchip_state(struct irq_data *d,
|
||||
enum irqchip_irq_state which, bool val)
|
||||
{
|
||||
@@ -287,6 +324,79 @@ static int gic_irq_get_irqchip_state(struct irq_data *d,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void gic_irq_set_prio(struct irq_data *d, u8 prio)
|
||||
{
|
||||
void __iomem *base = gic_dist_base(d);
|
||||
|
||||
writeb_relaxed(prio, base + GICD_IPRIORITYR + gic_irq(d));
|
||||
}
|
||||
|
||||
static int gic_irq_nmi_setup(struct irq_data *d)
|
||||
{
|
||||
struct irq_desc *desc = irq_to_desc(d->irq);
|
||||
|
||||
if (!gic_supports_nmi())
|
||||
return -EINVAL;
|
||||
|
||||
if (gic_peek_irq(d, GICD_ISENABLER)) {
|
||||
pr_err("Cannot set NMI property of enabled IRQ %u\n", d->irq);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/*
|
||||
* A secondary irq_chip should be in charge of LPI request,
|
||||
* it should not be possible to get there
|
||||
*/
|
||||
if (WARN_ON(gic_irq(d) >= 8192))
|
||||
return -EINVAL;
|
||||
|
||||
/* desc lock should already be held */
|
||||
if (gic_irq(d) < 32) {
|
||||
/* Setting up PPI as NMI, only switch handler for first NMI */
|
||||
if (!refcount_inc_not_zero(&ppi_nmi_refs[gic_irq(d) - 16])) {
|
||||
refcount_set(&ppi_nmi_refs[gic_irq(d) - 16], 1);
|
||||
desc->handle_irq = handle_percpu_devid_fasteoi_nmi;
|
||||
}
|
||||
} else {
|
||||
desc->handle_irq = handle_fasteoi_nmi;
|
||||
}
|
||||
|
||||
gic_irq_set_prio(d, GICD_INT_NMI_PRI);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void gic_irq_nmi_teardown(struct irq_data *d)
|
||||
{
|
||||
struct irq_desc *desc = irq_to_desc(d->irq);
|
||||
|
||||
if (WARN_ON(!gic_supports_nmi()))
|
||||
return;
|
||||
|
||||
if (gic_peek_irq(d, GICD_ISENABLER)) {
|
||||
pr_err("Cannot set NMI property of enabled IRQ %u\n", d->irq);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* A secondary irq_chip should be in charge of LPI request,
|
||||
* it should not be possible to get there
|
||||
*/
|
||||
if (WARN_ON(gic_irq(d) >= 8192))
|
||||
return;
|
||||
|
||||
/* desc lock should already be held */
|
||||
if (gic_irq(d) < 32) {
|
||||
/* Tearing down NMI, only switch handler for last NMI */
|
||||
if (refcount_dec_and_test(&ppi_nmi_refs[gic_irq(d) - 16]))
|
||||
desc->handle_irq = handle_percpu_devid_irq;
|
||||
} else {
|
||||
desc->handle_irq = handle_fasteoi_irq;
|
||||
}
|
||||
|
||||
gic_irq_set_prio(d, GICD_INT_DEF_PRI);
|
||||
}
|
||||
|
||||
static void gic_eoi_irq(struct irq_data *d)
|
||||
{
|
||||
gic_write_eoir(gic_irq(d));
|
||||
@@ -350,12 +460,50 @@ static u64 gic_mpidr_to_affinity(unsigned long mpidr)
|
||||
return aff;
|
||||
}
|
||||
|
||||
static void gic_deactivate_unhandled(u32 irqnr)
|
||||
{
|
||||
if (static_branch_likely(&supports_deactivate_key)) {
|
||||
if (irqnr < 8192)
|
||||
gic_write_dir(irqnr);
|
||||
} else {
|
||||
gic_write_eoir(irqnr);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void gic_handle_nmi(u32 irqnr, struct pt_regs *regs)
|
||||
{
|
||||
int err;
|
||||
|
||||
if (static_branch_likely(&supports_deactivate_key))
|
||||
gic_write_eoir(irqnr);
|
||||
/*
|
||||
* Leave the PSR.I bit set to prevent other NMIs to be
|
||||
* received while handling this one.
|
||||
* PSR.I will be restored when we ERET to the
|
||||
* interrupted context.
|
||||
*/
|
||||
err = handle_domain_nmi(gic_data.domain, irqnr, regs);
|
||||
if (err)
|
||||
gic_deactivate_unhandled(irqnr);
|
||||
}
|
||||
|
||||
static asmlinkage void __exception_irq_entry gic_handle_irq(struct pt_regs *regs)
|
||||
{
|
||||
u32 irqnr;
|
||||
|
||||
irqnr = gic_read_iar();
|
||||
|
||||
if (gic_supports_nmi() &&
|
||||
unlikely(gic_read_rpr() == GICD_INT_NMI_PRI)) {
|
||||
gic_handle_nmi(irqnr, regs);
|
||||
return;
|
||||
}
|
||||
|
||||
if (gic_prio_masking_enabled()) {
|
||||
gic_pmr_mask_irqs();
|
||||
gic_arch_enable_irqs();
|
||||
}
|
||||
|
||||
if (likely(irqnr > 15 && irqnr < 1020) || irqnr >= 8192) {
|
||||
int err;
|
||||
|
||||
@@ -367,12 +515,7 @@ static asmlinkage void __exception_irq_entry gic_handle_irq(struct pt_regs *regs
|
||||
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);
|
||||
}
|
||||
gic_deactivate_unhandled(irqnr);
|
||||
}
|
||||
return;
|
||||
}
|
||||
@@ -395,6 +538,44 @@ 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;
|
||||
u32 old_pmr;
|
||||
|
||||
old_pmr = gic_read_pmr();
|
||||
|
||||
/*
|
||||
* 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();
|
||||
|
||||
gic_write_pmr(old_pmr);
|
||||
|
||||
return val != 0;
|
||||
}
|
||||
|
||||
static void __init gic_dist_init(void)
|
||||
{
|
||||
unsigned int i;
|
||||
@@ -530,13 +711,19 @@ 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();
|
||||
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
|
||||
@@ -548,28 +735,22 @@ 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);
|
||||
if (!gic_prio_masking_enabled()) {
|
||||
write_gicreg(DEFAULT_PMR_VALUE, ICC_PMR_EL1);
|
||||
} else {
|
||||
/*
|
||||
* Mismatch configuration with boot CPU, the system is likely
|
||||
* to die as interrupt masking will not work properly on all
|
||||
* CPUs
|
||||
*/
|
||||
WARN_ON(gic_supports_nmi() && group0 &&
|
||||
!gic_dist_security_disabled());
|
||||
}
|
||||
|
||||
/*
|
||||
* Some firmwares hand over to the kernel with the BPR changed from
|
||||
@@ -824,12 +1005,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)
|
||||
{
|
||||
@@ -866,6 +1041,8 @@ static struct irq_chip gic_chip = {
|
||||
.irq_set_affinity = gic_set_affinity,
|
||||
.irq_get_irqchip_state = gic_irq_get_irqchip_state,
|
||||
.irq_set_irqchip_state = gic_irq_set_irqchip_state,
|
||||
.irq_nmi_setup = gic_irq_nmi_setup,
|
||||
.irq_nmi_teardown = gic_irq_nmi_teardown,
|
||||
.flags = IRQCHIP_SET_TYPE_MASKED |
|
||||
IRQCHIP_SKIP_SET_WAKE |
|
||||
IRQCHIP_MASK_ON_SUSPEND,
|
||||
@@ -881,6 +1058,8 @@ static struct irq_chip gic_eoimode1_chip = {
|
||||
.irq_get_irqchip_state = gic_irq_get_irqchip_state,
|
||||
.irq_set_irqchip_state = gic_irq_set_irqchip_state,
|
||||
.irq_set_vcpu_affinity = gic_irq_set_vcpu_affinity,
|
||||
.irq_nmi_setup = gic_irq_nmi_setup,
|
||||
.irq_nmi_teardown = gic_irq_nmi_teardown,
|
||||
.flags = IRQCHIP_SET_TYPE_MASKED |
|
||||
IRQCHIP_SKIP_SET_WAKE |
|
||||
IRQCHIP_MASK_ON_SUSPEND,
|
||||
@@ -1082,6 +1261,21 @@ static bool gic_enable_quirk_msm8996(void *data)
|
||||
return true;
|
||||
}
|
||||
|
||||
static void gic_enable_nmi_support(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 16; i++)
|
||||
refcount_set(&ppi_nmi_refs[i], 0);
|
||||
|
||||
static_branch_enable(&supports_pseudo_nmis);
|
||||
|
||||
if (static_branch_likely(&supports_deactivate_key))
|
||||
gic_eoimode1_chip.flags |= IRQCHIP_SUPPORTS_NMI;
|
||||
else
|
||||
gic_chip.flags |= IRQCHIP_SUPPORTS_NMI;
|
||||
}
|
||||
|
||||
static int __init gic_init_bases(void __iomem *dist_base,
|
||||
struct redist_region *rdist_regs,
|
||||
u32 nr_redist_regions,
|
||||
@@ -1151,6 +1345,13 @@ static int __init gic_init_bases(void __iomem *dist_base,
|
||||
its_cpu_init();
|
||||
}
|
||||
|
||||
if (gic_prio_masking_enabled()) {
|
||||
if (!gic_has_group0() || gic_dist_security_disabled())
|
||||
gic_enable_nmi_support();
|
||||
else
|
||||
pr_warn("SCR_EL3.FIQ is cleared, cannot enable use of pseudo-NMIs\n");
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
out_free:
|
||||
|
Reference in New Issue
Block a user