mirror of
https://github.com/torvalds/linux.git
synced 2026-05-26 16:12:59 +02:00
Merge branches 'for-next/cpufeature', 'for-next/misc', 'for-next/kselftest', 'for-next/mte', 'for-next/errata', 'for-next/acpi', 'for-next/gic-v3-pmr' and 'for-next/doc', remote-tracking branch 'arm64/for-next/perf' into for-next/core
* arm64/for-next/perf: perf: add missing MODULE_DESCRIPTION() macros perf: arm_pmuv3: Include asm/arm_pmuv3.h from linux/perf/arm_pmuv3.h perf: arm_v6/7_pmu: Drop non-DT probe support perf/arm: Move 32-bit PMU drivers to drivers/perf/ perf: arm_pmuv3: Drop unnecessary IS_ENABLED(CONFIG_ARM64) check perf: arm_pmuv3: Avoid assigning fixed cycle counter with threshold perf: imx_perf: add support for i.MX95 platform perf: imx_perf: fix counter start and config sequence perf: imx_perf: refactor driver for imx93 perf: imx_perf: let the driver manage the counter usage rather the user perf: imx_perf: add macro definitions for parsing config attr dt-bindings: perf: fsl-imx-ddr: Add i.MX95 compatible perf: pmuv3: Add new Cortex and Neoverse PMUs dt-bindings: arm: pmu: Add new Cortex and Neoverse cores perf/arm-cmn: Enable support for tertiary match group perf/arm-cmn: Decouple wp_config registers from filter group number * for-next/cpufeature: : Various cpufeature infrastructure patches arm64/cpufeature: Replace custom macros with fields from ID_AA64PFR0_EL1 KVM: arm64: Replace custom macros with fields from ID_AA64PFR0_EL1 arm64/cpufeatures/kvm: Add ARMv8.9 FEAT_ECBHB bits in ID_AA64MMFR1 register * for-next/misc: : Miscellaneous patches arm64: smp: Fix missing IPI statistics arm64: Cleanup __cpu_set_tcr_t0sz() arm64/mm: Stop using ESR_ELx_FSC_TYPE during fault arm64: Kconfig: fix typo in __builtin_return_adddress ARM64: reloc_test: add missing MODULE_DESCRIPTION() macro arm64: implement raw_smp_processor_id() using thread_info arm64/arch_timer: include <linux/percpu.h> * for-next/kselftest: : arm64 kselftest updates selftests: arm64: tags: remove the result script selftests: arm64: tags_test: conform test to TAP output kselftest/arm64: Fix a couple of spelling mistakes kselftest/arm64: Fix redundancy of a testcase kselftest/arm64: Include kernel mode NEON in fp-stress * for-next/mte: : MTE updates arm64: mte: Make mte_check_tfsr_*() conditional on KASAN instead of MTE * for-next/errata: : Arm CPU errata workarounds arm64: errata: Expand speculative SSBS workaround arm64: errata: Unify speculative SSBS errata logic arm64: cputype: Add Cortex-X925 definitions arm64: cputype: Add Cortex-A720 definitions arm64: cputype: Add Cortex-X3 definitions * for-next/acpi: : arm64 ACPI patches ACPI: Add acpi=nospcr to disable ACPI SPCR as default console on ARM64 ACPI / amba: Drop unnecessary check for registered amba_dummy_clk arm64: FFH: Move ACPI specific code into drivers/acpi/arm64/ arm64: cpuidle: Move ACPI specific code into drivers/acpi/arm64/ ACPI: arm64: Sort entries alphabetically * for-next/gic-v3-pmr: : arm64: irqchip/gic-v3: Use compiletime constant PMR values arm64: irqchip/gic-v3: Select priorities at boot time irqchip/gic-v3: Detect GICD_CTRL.DS and SCR_EL3.FIQ earlier irqchip/gic-v3: Make distributor priorities variables irqchip/gic-common: Remove sync_access callback wordpart.h: Add REPEAT_BYTE_U32() * for-next/doc: : arm64 documentation updates Documentation: arm64: Update memory.rst for TBI
This commit is contained in:
parent
42bebc7cca
056600ff73
916b93f4e8
6e3bc73be0
26ca442360
75b3c43eab
f5a4af3c75
18fdb6348c
5e30c16b58
commit
3346c56685
|
|
@ -12,7 +12,7 @@
|
|||
acpi= [HW,ACPI,X86,ARM64,RISCV64,EARLY]
|
||||
Advanced Configuration and Power Interface
|
||||
Format: { force | on | off | strict | noirq | rsdt |
|
||||
copy_dsdt }
|
||||
copy_dsdt | nospcr }
|
||||
force -- enable ACPI if default was off
|
||||
on -- enable ACPI but allow fallback to DT [arm64,riscv64]
|
||||
off -- disable ACPI if default was on
|
||||
|
|
@ -21,8 +21,12 @@
|
|||
strictly ACPI specification compliant.
|
||||
rsdt -- prefer RSDT over (default) XSDT
|
||||
copy_dsdt -- copy DSDT to memory
|
||||
For ARM64 and RISCV64, ONLY "acpi=off", "acpi=on" or
|
||||
"acpi=force" are available
|
||||
nospcr -- disable console in ACPI SPCR table as
|
||||
default _serial_ console on ARM64
|
||||
For ARM64, ONLY "acpi=off", "acpi=on", "acpi=force" or
|
||||
"acpi=nospcr" are available
|
||||
For RISCV64, ONLY "acpi=off", "acpi=on" or "acpi=force"
|
||||
are available
|
||||
|
||||
See also Documentation/power/runtime_pm.rst, pci=noacpi
|
||||
|
||||
|
|
|
|||
|
|
@ -18,12 +18,10 @@ ARMv8.2 adds optional support for Large Virtual Address space. This is
|
|||
only available when running with a 64KB page size and expands the
|
||||
number of descriptors in the first level of translation.
|
||||
|
||||
User addresses have bits 63:48 set to 0 while the kernel addresses have
|
||||
the same bits set to 1. TTBRx selection is given by bit 63 of the
|
||||
virtual address. The swapper_pg_dir contains only kernel (global)
|
||||
mappings while the user pgd contains only user (non-global) mappings.
|
||||
The swapper_pg_dir address is written to TTBR1 and never written to
|
||||
TTBR0.
|
||||
TTBRx selection is given by bit 55 of the virtual address. The
|
||||
swapper_pg_dir contains only kernel (global) mappings while the user pgd
|
||||
contains only user (non-global) mappings. The swapper_pg_dir address is
|
||||
written to TTBR1 and never written to TTBR0.
|
||||
|
||||
|
||||
AArch64 Linux memory layout with 4KB pages + 4 levels (48-bit)::
|
||||
|
|
@ -65,14 +63,14 @@ Translation table lookup with 4KB pages::
|
|||
+--------+--------+--------+--------+--------+--------+--------+--------+
|
||||
|63 56|55 48|47 40|39 32|31 24|23 16|15 8|7 0|
|
||||
+--------+--------+--------+--------+--------+--------+--------+--------+
|
||||
| | | | | |
|
||||
| | | | | v
|
||||
| | | | | [11:0] in-page offset
|
||||
| | | | +-> [20:12] L3 index
|
||||
| | | +-----------> [29:21] L2 index
|
||||
| | +---------------------> [38:30] L1 index
|
||||
| +-------------------------------> [47:39] L0 index
|
||||
+-------------------------------------------------> [63] TTBR0/1
|
||||
| | | | | |
|
||||
| | | | | v
|
||||
| | | | | [11:0] in-page offset
|
||||
| | | | +-> [20:12] L3 index
|
||||
| | | +-----------> [29:21] L2 index
|
||||
| | +---------------------> [38:30] L1 index
|
||||
| +-------------------------------> [47:39] L0 index
|
||||
+----------------------------------------> [55] TTBR0/1
|
||||
|
||||
|
||||
Translation table lookup with 64KB pages::
|
||||
|
|
@ -80,14 +78,14 @@ Translation table lookup with 64KB pages::
|
|||
+--------+--------+--------+--------+--------+--------+--------+--------+
|
||||
|63 56|55 48|47 40|39 32|31 24|23 16|15 8|7 0|
|
||||
+--------+--------+--------+--------+--------+--------+--------+--------+
|
||||
| | | | |
|
||||
| | | | v
|
||||
| | | | [15:0] in-page offset
|
||||
| | | +----------> [28:16] L3 index
|
||||
| | +--------------------------> [41:29] L2 index
|
||||
| +-------------------------------> [47:42] L1 index (48-bit)
|
||||
| [51:42] L1 index (52-bit)
|
||||
+-------------------------------------------------> [63] TTBR0/1
|
||||
| | | | |
|
||||
| | | | v
|
||||
| | | | [15:0] in-page offset
|
||||
| | | +----------> [28:16] L3 index
|
||||
| | +--------------------------> [41:29] L2 index
|
||||
| +-------------------------------> [47:42] L1 index (48-bit)
|
||||
| [51:42] L1 index (52-bit)
|
||||
+----------------------------------------> [55] TTBR0/1
|
||||
|
||||
|
||||
When using KVM without the Virtualization Host Extensions, the
|
||||
|
|
|
|||
|
|
@ -132,16 +132,26 @@ stable kernels.
|
|||
+----------------+-----------------+-----------------+-----------------------------+
|
||||
| ARM | Cortex-A710 | #2224489 | ARM64_ERRATUM_2224489 |
|
||||
+----------------+-----------------+-----------------+-----------------------------+
|
||||
| ARM | Cortex-A710 | #3324338 | ARM64_ERRATUM_3194386 |
|
||||
+----------------+-----------------+-----------------+-----------------------------+
|
||||
| ARM | Cortex-A715 | #2645198 | ARM64_ERRATUM_2645198 |
|
||||
+----------------+-----------------+-----------------+-----------------------------+
|
||||
| ARM | Cortex-A720 | #3456091 | ARM64_ERRATUM_3194386 |
|
||||
+----------------+-----------------+-----------------+-----------------------------+
|
||||
| ARM | Cortex-X1 | #1502854 | N/A |
|
||||
+----------------+-----------------+-----------------+-----------------------------+
|
||||
| ARM | Cortex-X2 | #2119858 | ARM64_ERRATUM_2119858 |
|
||||
+----------------+-----------------+-----------------+-----------------------------+
|
||||
| ARM | Cortex-X2 | #2224489 | ARM64_ERRATUM_2224489 |
|
||||
+----------------+-----------------+-----------------+-----------------------------+
|
||||
| ARM | Cortex-X2 | #3324338 | ARM64_ERRATUM_3194386 |
|
||||
+----------------+-----------------+-----------------+-----------------------------+
|
||||
| ARM | Cortex-X3 | #3324335 | ARM64_ERRATUM_3194386 |
|
||||
+----------------+-----------------+-----------------+-----------------------------+
|
||||
| ARM | Cortex-X4 | #3194386 | ARM64_ERRATUM_3194386 |
|
||||
+----------------+-----------------+-----------------+-----------------------------+
|
||||
| ARM | Cortex-X925 | #3324334 | ARM64_ERRATUM_3194386 |
|
||||
+----------------+-----------------+-----------------+-----------------------------+
|
||||
| ARM | Neoverse-N1 | #1188873,1418040| ARM64_ERRATUM_1418040 |
|
||||
+----------------+-----------------+-----------------+-----------------------------+
|
||||
| ARM | Neoverse-N1 | #1349291 | N/A |
|
||||
|
|
@ -156,9 +166,13 @@ stable kernels.
|
|||
+----------------+-----------------+-----------------+-----------------------------+
|
||||
| ARM | Neoverse-N2 | #2253138 | ARM64_ERRATUM_2253138 |
|
||||
+----------------+-----------------+-----------------+-----------------------------+
|
||||
| ARM | Neoverse-N2 | #3324339 | ARM64_ERRATUM_3194386 |
|
||||
+----------------+-----------------+-----------------+-----------------------------+
|
||||
| ARM | Neoverse-V1 | #1619801 | N/A |
|
||||
+----------------+-----------------+-----------------+-----------------------------+
|
||||
| ARM | Neoverse-V3 | #3312417 | ARM64_ERRATUM_3312417 |
|
||||
| ARM | Neoverse-V2 | #3324336 | ARM64_ERRATUM_3194386 |
|
||||
+----------------+-----------------+-----------------+-----------------------------+
|
||||
| ARM | Neoverse-V3 | #3312417 | ARM64_ERRATUM_3194386 |
|
||||
+----------------+-----------------+-----------------+-----------------------------+
|
||||
| ARM | MMU-500 | #841119,826419 | N/A |
|
||||
+----------------+-----------------+-----------------+-----------------------------+
|
||||
|
|
|
|||
|
|
@ -381,7 +381,7 @@ config BROKEN_GAS_INST
|
|||
|
||||
config BUILTIN_RETURN_ADDRESS_STRIPS_PAC
|
||||
bool
|
||||
# Clang's __builtin_return_adddress() strips the PAC since 12.0.0
|
||||
# Clang's __builtin_return_address() strips the PAC since 12.0.0
|
||||
# https://github.com/llvm/llvm-project/commit/2a96f47c5ffca84cd774ad402cacd137f4bf45e2
|
||||
default y if CC_IS_CLANG
|
||||
# GCC's __builtin_return_address() strips the PAC since 11.1.0,
|
||||
|
|
@ -1067,15 +1067,21 @@ config ARM64_ERRATUM_3117295
|
|||
|
||||
If unsure, say Y.
|
||||
|
||||
config ARM64_WORKAROUND_SPECULATIVE_SSBS
|
||||
bool
|
||||
|
||||
config ARM64_ERRATUM_3194386
|
||||
bool "Cortex-X4: 3194386: workaround for MSR SSBS not self-synchronizing"
|
||||
select ARM64_WORKAROUND_SPECULATIVE_SSBS
|
||||
bool "Cortex-{A720,X4,X925}/Neoverse-V3: workaround for MSR SSBS not self-synchronizing"
|
||||
default y
|
||||
help
|
||||
This option adds the workaround for ARM Cortex-X4 erratum 3194386.
|
||||
This option adds the workaround for the following errata:
|
||||
|
||||
* ARM Cortex-A710 erratam 3324338
|
||||
* ARM Cortex-A720 erratum 3456091
|
||||
* ARM Cortex-X2 erratum 3324338
|
||||
* ARM Cortex-X3 erratum 3324335
|
||||
* ARM Cortex-X4 erratum 3194386
|
||||
* ARM Cortex-X925 erratum 3324334
|
||||
* ARM Neoverse N2 erratum 3324339
|
||||
* ARM Neoverse V2 erratum 3324336
|
||||
* ARM Neoverse-V3 erratum 3312417
|
||||
|
||||
On affected cores "MSR SSBS, #0" instructions may not affect
|
||||
subsequent speculative instructions, which may permit unexepected
|
||||
|
|
@ -1089,26 +1095,6 @@ config ARM64_ERRATUM_3194386
|
|||
|
||||
If unsure, say Y.
|
||||
|
||||
config ARM64_ERRATUM_3312417
|
||||
bool "Neoverse-V3: 3312417: workaround for MSR SSBS not self-synchronizing"
|
||||
select ARM64_WORKAROUND_SPECULATIVE_SSBS
|
||||
default y
|
||||
help
|
||||
This option adds the workaround for ARM Neoverse-V3 erratum 3312417.
|
||||
|
||||
On affected cores "MSR SSBS, #0" instructions may not affect
|
||||
subsequent speculative instructions, which may permit unexepected
|
||||
speculative store bypassing.
|
||||
|
||||
Work around this problem by placing a speculation barrier after
|
||||
kernel changes to SSBS. The presence of the SSBS special-purpose
|
||||
register is hidden from hwcaps and EL0 reads of ID_AA64PFR1_EL1, such
|
||||
that userspace will use the PR_SPEC_STORE_BYPASS prctl to change
|
||||
SSBS.
|
||||
|
||||
If unsure, say Y.
|
||||
|
||||
|
||||
config CAVIUM_ERRATUM_22375
|
||||
bool "Cavium erratum 22375, 24313"
|
||||
default y
|
||||
|
|
|
|||
|
|
@ -175,21 +175,6 @@ static inline bool gic_prio_masking_enabled(void)
|
|||
|
||||
static inline void gic_pmr_mask_irqs(void)
|
||||
{
|
||||
BUILD_BUG_ON(GICD_INT_DEF_PRI < (__GIC_PRIO_IRQOFF |
|
||||
GIC_PRIO_PSR_I_SET));
|
||||
BUILD_BUG_ON(GICD_INT_DEF_PRI >= GIC_PRIO_IRQON);
|
||||
/*
|
||||
* Need to make sure IRQON allows IRQs when SCR_EL3.FIQ is cleared
|
||||
* and non-secure PMR accesses are not subject to the shifts that
|
||||
* are applied to IRQ priorities
|
||||
*/
|
||||
BUILD_BUG_ON((0x80 | (GICD_INT_DEF_PRI >> 1)) >= GIC_PRIO_IRQON);
|
||||
/*
|
||||
* Same situation as above, but now we make sure that we can mask
|
||||
* regular interrupts.
|
||||
*/
|
||||
BUILD_BUG_ON((0x80 | (GICD_INT_DEF_PRI >> 1)) < (__GIC_PRIO_IRQOFF_NS |
|
||||
GIC_PRIO_PSR_I_SET));
|
||||
gic_write_pmr(GIC_PRIO_IRQOFF);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@
|
|||
#include <linux/bug.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/jump_label.h>
|
||||
#include <linux/smp.h>
|
||||
#include <linux/percpu.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
#include <clocksource/arm_arch_timer.h>
|
||||
|
|
|
|||
|
|
@ -59,7 +59,7 @@ cpucap_is_possible(const unsigned int cap)
|
|||
case ARM64_WORKAROUND_REPEAT_TLBI:
|
||||
return IS_ENABLED(CONFIG_ARM64_WORKAROUND_REPEAT_TLBI);
|
||||
case ARM64_WORKAROUND_SPECULATIVE_SSBS:
|
||||
return IS_ENABLED(CONFIG_ARM64_WORKAROUND_SPECULATIVE_SSBS);
|
||||
return IS_ENABLED(CONFIG_ARM64_ERRATUM_3194386);
|
||||
}
|
||||
|
||||
return true;
|
||||
|
|
|
|||
|
|
@ -588,14 +588,14 @@ static inline bool id_aa64pfr0_32bit_el1(u64 pfr0)
|
|||
{
|
||||
u32 val = cpuid_feature_extract_unsigned_field(pfr0, ID_AA64PFR0_EL1_EL1_SHIFT);
|
||||
|
||||
return val == ID_AA64PFR0_EL1_ELx_32BIT_64BIT;
|
||||
return val == ID_AA64PFR0_EL1_EL1_AARCH32;
|
||||
}
|
||||
|
||||
static inline bool id_aa64pfr0_32bit_el0(u64 pfr0)
|
||||
{
|
||||
u32 val = cpuid_feature_extract_unsigned_field(pfr0, ID_AA64PFR0_EL1_EL0_SHIFT);
|
||||
|
||||
return val == ID_AA64PFR0_EL1_ELx_32BIT_64BIT;
|
||||
return val == ID_AA64PFR0_EL1_EL0_AARCH32;
|
||||
}
|
||||
|
||||
static inline bool id_aa64pfr0_sve(u64 pfr0)
|
||||
|
|
|
|||
|
|
@ -86,9 +86,12 @@
|
|||
#define ARM_CPU_PART_CORTEX_X2 0xD48
|
||||
#define ARM_CPU_PART_NEOVERSE_N2 0xD49
|
||||
#define ARM_CPU_PART_CORTEX_A78C 0xD4B
|
||||
#define ARM_CPU_PART_CORTEX_X3 0xD4E
|
||||
#define ARM_CPU_PART_NEOVERSE_V2 0xD4F
|
||||
#define ARM_CPU_PART_CORTEX_A720 0xD81
|
||||
#define ARM_CPU_PART_CORTEX_X4 0xD82
|
||||
#define ARM_CPU_PART_NEOVERSE_V3 0xD84
|
||||
#define ARM_CPU_PART_CORTEX_X925 0xD85
|
||||
|
||||
#define APM_CPU_PART_XGENE 0x000
|
||||
#define APM_CPU_VAR_POTENZA 0x00
|
||||
|
|
@ -162,9 +165,12 @@
|
|||
#define MIDR_CORTEX_X2 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_X2)
|
||||
#define MIDR_NEOVERSE_N2 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_NEOVERSE_N2)
|
||||
#define MIDR_CORTEX_A78C MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A78C)
|
||||
#define MIDR_CORTEX_X3 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_X3)
|
||||
#define MIDR_NEOVERSE_V2 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_NEOVERSE_V2)
|
||||
#define MIDR_CORTEX_A720 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A720)
|
||||
#define MIDR_CORTEX_X4 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_X4)
|
||||
#define MIDR_NEOVERSE_V3 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_NEOVERSE_V3)
|
||||
#define MIDR_CORTEX_X925 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_X925)
|
||||
#define MIDR_THUNDERX MIDR_CPU_MODEL(ARM_CPU_IMP_CAVIUM, CAVIUM_CPU_PART_THUNDERX)
|
||||
#define MIDR_THUNDERX_81XX MIDR_CPU_MODEL(ARM_CPU_IMP_CAVIUM, CAVIUM_CPU_PART_THUNDERX_81XX)
|
||||
#define MIDR_THUNDERX_83XX MIDR_CPU_MODEL(ARM_CPU_IMP_CAVIUM, CAVIUM_CPU_PART_THUNDERX_83XX)
|
||||
|
|
|
|||
|
|
@ -121,6 +121,14 @@
|
|||
#define ESR_ELx_FSC_SECC (0x18)
|
||||
#define ESR_ELx_FSC_SECC_TTW(n) (0x1c + (n))
|
||||
|
||||
/* Status codes for individual page table levels */
|
||||
#define ESR_ELx_FSC_ACCESS_L(n) (ESR_ELx_FSC_ACCESS + n)
|
||||
#define ESR_ELx_FSC_PERM_L(n) (ESR_ELx_FSC_PERM + n)
|
||||
|
||||
#define ESR_ELx_FSC_FAULT_nL (0x2C)
|
||||
#define ESR_ELx_FSC_FAULT_L(n) (((n) < 0 ? ESR_ELx_FSC_FAULT_nL : \
|
||||
ESR_ELx_FSC_FAULT) + (n))
|
||||
|
||||
/* ISS field definitions for Data Aborts */
|
||||
#define ESR_ELx_ISV_SHIFT (24)
|
||||
#define ESR_ELx_ISV (UL(1) << ESR_ELx_ISV_SHIFT)
|
||||
|
|
@ -388,20 +396,33 @@ static inline bool esr_is_data_abort(unsigned long esr)
|
|||
|
||||
static inline bool esr_fsc_is_translation_fault(unsigned long esr)
|
||||
{
|
||||
/* Translation fault, level -1 */
|
||||
if ((esr & ESR_ELx_FSC) == 0b101011)
|
||||
return true;
|
||||
return (esr & ESR_ELx_FSC_TYPE) == ESR_ELx_FSC_FAULT;
|
||||
esr = esr & ESR_ELx_FSC;
|
||||
|
||||
return (esr == ESR_ELx_FSC_FAULT_L(3)) ||
|
||||
(esr == ESR_ELx_FSC_FAULT_L(2)) ||
|
||||
(esr == ESR_ELx_FSC_FAULT_L(1)) ||
|
||||
(esr == ESR_ELx_FSC_FAULT_L(0)) ||
|
||||
(esr == ESR_ELx_FSC_FAULT_L(-1));
|
||||
}
|
||||
|
||||
static inline bool esr_fsc_is_permission_fault(unsigned long esr)
|
||||
{
|
||||
return (esr & ESR_ELx_FSC_TYPE) == ESR_ELx_FSC_PERM;
|
||||
esr = esr & ESR_ELx_FSC;
|
||||
|
||||
return (esr == ESR_ELx_FSC_PERM_L(3)) ||
|
||||
(esr == ESR_ELx_FSC_PERM_L(2)) ||
|
||||
(esr == ESR_ELx_FSC_PERM_L(1)) ||
|
||||
(esr == ESR_ELx_FSC_PERM_L(0));
|
||||
}
|
||||
|
||||
static inline bool esr_fsc_is_access_flag_fault(unsigned long esr)
|
||||
{
|
||||
return (esr & ESR_ELx_FSC_TYPE) == ESR_ELx_FSC_ACCESS;
|
||||
esr = esr & ESR_ELx_FSC;
|
||||
|
||||
return (esr == ESR_ELx_FSC_ACCESS_L(3)) ||
|
||||
(esr == ESR_ELx_FSC_ACCESS_L(2)) ||
|
||||
(esr == ESR_ELx_FSC_ACCESS_L(1)) ||
|
||||
(esr == ESR_ELx_FSC_ACCESS_L(0));
|
||||
}
|
||||
|
||||
/* Indicate whether ESR.EC==0x1A is for an ERETAx instruction */
|
||||
|
|
|
|||
|
|
@ -72,11 +72,11 @@ static inline void __cpu_set_tcr_t0sz(unsigned long t0sz)
|
|||
{
|
||||
unsigned long tcr = read_sysreg(tcr_el1);
|
||||
|
||||
if ((tcr & TCR_T0SZ_MASK) >> TCR_T0SZ_OFFSET == t0sz)
|
||||
if ((tcr & TCR_T0SZ_MASK) == t0sz)
|
||||
return;
|
||||
|
||||
tcr &= ~TCR_T0SZ_MASK;
|
||||
tcr |= t0sz << TCR_T0SZ_OFFSET;
|
||||
tcr |= t0sz;
|
||||
write_sysreg(tcr, tcr_el1);
|
||||
isb();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -182,7 +182,7 @@ void mte_check_tfsr_el1(void);
|
|||
|
||||
static inline void mte_check_tfsr_entry(void)
|
||||
{
|
||||
if (!system_supports_mte())
|
||||
if (!kasan_hw_tags_enabled())
|
||||
return;
|
||||
|
||||
mte_check_tfsr_el1();
|
||||
|
|
@ -190,7 +190,7 @@ static inline void mte_check_tfsr_entry(void)
|
|||
|
||||
static inline void mte_check_tfsr_exit(void)
|
||||
{
|
||||
if (!system_supports_mte())
|
||||
if (!kasan_hw_tags_enabled())
|
||||
return;
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -21,35 +21,12 @@
|
|||
#define INIT_PSTATE_EL2 \
|
||||
(PSR_D_BIT | PSR_A_BIT | PSR_I_BIT | PSR_F_BIT | PSR_MODE_EL2h)
|
||||
|
||||
/*
|
||||
* PMR values used to mask/unmask interrupts.
|
||||
*
|
||||
* GIC priority masking works as follows: if an IRQ's priority is a higher value
|
||||
* than the value held in PMR, that IRQ is masked. Lowering the value of PMR
|
||||
* means masking more IRQs (or at least that the same IRQs remain masked).
|
||||
*
|
||||
* To mask interrupts, we clear the most significant bit of PMR.
|
||||
*
|
||||
* Some code sections either automatically switch back to PSR.I or explicitly
|
||||
* require to not use priority masking. If bit GIC_PRIO_PSR_I_SET is included
|
||||
* in the priority mask, it indicates that PSR.I should be set and
|
||||
* interrupt disabling temporarily does not rely on IRQ priorities.
|
||||
*/
|
||||
#define GIC_PRIO_IRQON 0xe0
|
||||
#define __GIC_PRIO_IRQOFF (GIC_PRIO_IRQON & ~0x80)
|
||||
#define __GIC_PRIO_IRQOFF_NS 0xa0
|
||||
#define GIC_PRIO_PSR_I_SET (1 << 4)
|
||||
#include <linux/irqchip/arm-gic-v3-prio.h>
|
||||
|
||||
#define GIC_PRIO_IRQOFF \
|
||||
({ \
|
||||
extern struct static_key_false gic_nonsecure_priorities;\
|
||||
u8 __prio = __GIC_PRIO_IRQOFF; \
|
||||
\
|
||||
if (static_branch_unlikely(&gic_nonsecure_priorities)) \
|
||||
__prio = __GIC_PRIO_IRQOFF_NS; \
|
||||
\
|
||||
__prio; \
|
||||
})
|
||||
#define GIC_PRIO_IRQON GICV3_PRIO_UNMASKED
|
||||
#define GIC_PRIO_IRQOFF GICV3_PRIO_IRQ
|
||||
|
||||
#define GIC_PRIO_PSR_I_SET GICV3_PRIO_PSR_I_SET
|
||||
|
||||
/* Additional SPSR bits not exposed in the UABI */
|
||||
#define PSR_MODE_THREAD_BIT (1 << 0)
|
||||
|
|
|
|||
|
|
@ -25,22 +25,11 @@
|
|||
|
||||
#ifndef __ASSEMBLY__
|
||||
|
||||
#include <asm/percpu.h>
|
||||
|
||||
#include <linux/threads.h>
|
||||
#include <linux/cpumask.h>
|
||||
#include <linux/thread_info.h>
|
||||
|
||||
DECLARE_PER_CPU_READ_MOSTLY(int, cpu_number);
|
||||
|
||||
/*
|
||||
* We don't use this_cpu_read(cpu_number) as that has implicit writes to
|
||||
* preempt_count, and associated (compiler) barriers, that we'd like to avoid
|
||||
* the expense of. If we're preemptible, the value can be stale at use anyway.
|
||||
* And we can't use this_cpu_ptr() either, as that winds up recursing back
|
||||
* here under CONFIG_DEBUG_PREEMPT=y.
|
||||
*/
|
||||
#define raw_smp_processor_id() (*raw_cpu_ptr(&cpu_number))
|
||||
#define raw_smp_processor_id() (current_thread_info()->cpu)
|
||||
|
||||
/*
|
||||
* Logical CPU mapping.
|
||||
|
|
|
|||
|
|
@ -872,10 +872,6 @@
|
|||
/* Position the attr at the correct index */
|
||||
#define MAIR_ATTRIDX(attr, idx) ((attr) << ((idx) * 8))
|
||||
|
||||
/* id_aa64pfr0 */
|
||||
#define ID_AA64PFR0_EL1_ELx_64BIT_ONLY 0x1
|
||||
#define ID_AA64PFR0_EL1_ELx_32BIT_64BIT 0x2
|
||||
|
||||
/* id_aa64mmfr0 */
|
||||
#define ID_AA64MMFR0_EL1_TGRAN4_SUPPORTED_MIN 0x0
|
||||
#define ID_AA64MMFR0_EL1_TGRAN4_LPA2 ID_AA64MMFR0_EL1_TGRAN4_52_BIT
|
||||
|
|
|
|||
|
|
@ -46,7 +46,6 @@ obj-$(CONFIG_PERF_EVENTS) += perf_regs.o perf_callchain.o
|
|||
obj-$(CONFIG_HARDLOCKUP_DETECTOR_PERF) += watchdog_hld.o
|
||||
obj-$(CONFIG_HAVE_HW_BREAKPOINT) += hw_breakpoint.o
|
||||
obj-$(CONFIG_CPU_PM) += sleep.o suspend.o
|
||||
obj-$(CONFIG_CPU_IDLE) += cpuidle.o
|
||||
obj-$(CONFIG_JUMP_LABEL) += jump_label.o
|
||||
obj-$(CONFIG_KGDB) += kgdb.o
|
||||
obj-$(CONFIG_EFI) += efi.o efi-rt-wrapper.o
|
||||
|
|
|
|||
|
|
@ -45,6 +45,7 @@ EXPORT_SYMBOL(acpi_pci_disabled);
|
|||
static bool param_acpi_off __initdata;
|
||||
static bool param_acpi_on __initdata;
|
||||
static bool param_acpi_force __initdata;
|
||||
static bool param_acpi_nospcr __initdata;
|
||||
|
||||
static int __init parse_acpi(char *arg)
|
||||
{
|
||||
|
|
@ -58,6 +59,8 @@ static int __init parse_acpi(char *arg)
|
|||
param_acpi_on = true;
|
||||
else if (strcmp(arg, "force") == 0) /* force ACPI to be enabled */
|
||||
param_acpi_force = true;
|
||||
else if (strcmp(arg, "nospcr") == 0) /* disable SPCR as default console */
|
||||
param_acpi_nospcr = true;
|
||||
else
|
||||
return -EINVAL; /* Core will print when we return error */
|
||||
|
||||
|
|
@ -237,7 +240,20 @@ void __init acpi_boot_table_init(void)
|
|||
acpi_put_table(facs);
|
||||
}
|
||||
#endif
|
||||
acpi_parse_spcr(earlycon_acpi_spcr_enable, true);
|
||||
|
||||
/*
|
||||
* For varying privacy and security reasons, sometimes need
|
||||
* to completely silence the serial console output, and only
|
||||
* enable it when needed.
|
||||
* But there are many existing systems that depend on this
|
||||
* behaviour, use acpi=nospcr to disable console in ACPI SPCR
|
||||
* table as default serial console.
|
||||
*/
|
||||
acpi_parse_spcr(earlycon_acpi_spcr_enable,
|
||||
!param_acpi_nospcr);
|
||||
pr_info("Use ACPI SPCR as default console: %s\n",
|
||||
param_acpi_nospcr ? "No" : "Yes");
|
||||
|
||||
if (IS_ENABLED(CONFIG_ACPI_BGRT))
|
||||
acpi_table_parse(ACPI_SIG_BGRT, acpi_parse_bgrt);
|
||||
}
|
||||
|
|
@ -422,108 +438,3 @@ void arch_reserve_mem_area(acpi_physical_address addr, size_t size)
|
|||
{
|
||||
memblock_mark_nomap(addr, size);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_ACPI_FFH
|
||||
/*
|
||||
* Implements ARM64 specific callbacks to support ACPI FFH Operation Region as
|
||||
* specified in https://developer.arm.com/docs/den0048/latest
|
||||
*/
|
||||
struct acpi_ffh_data {
|
||||
struct acpi_ffh_info info;
|
||||
void (*invoke_ffh_fn)(unsigned long a0, unsigned long a1,
|
||||
unsigned long a2, unsigned long a3,
|
||||
unsigned long a4, unsigned long a5,
|
||||
unsigned long a6, unsigned long a7,
|
||||
struct arm_smccc_res *args,
|
||||
struct arm_smccc_quirk *res);
|
||||
void (*invoke_ffh64_fn)(const struct arm_smccc_1_2_regs *args,
|
||||
struct arm_smccc_1_2_regs *res);
|
||||
};
|
||||
|
||||
int acpi_ffh_address_space_arch_setup(void *handler_ctxt, void **region_ctxt)
|
||||
{
|
||||
enum arm_smccc_conduit conduit;
|
||||
struct acpi_ffh_data *ffh_ctxt;
|
||||
|
||||
if (arm_smccc_get_version() < ARM_SMCCC_VERSION_1_2)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
conduit = arm_smccc_1_1_get_conduit();
|
||||
if (conduit == SMCCC_CONDUIT_NONE) {
|
||||
pr_err("%s: invalid SMCCC conduit\n", __func__);
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
ffh_ctxt = kzalloc(sizeof(*ffh_ctxt), GFP_KERNEL);
|
||||
if (!ffh_ctxt)
|
||||
return -ENOMEM;
|
||||
|
||||
if (conduit == SMCCC_CONDUIT_SMC) {
|
||||
ffh_ctxt->invoke_ffh_fn = __arm_smccc_smc;
|
||||
ffh_ctxt->invoke_ffh64_fn = arm_smccc_1_2_smc;
|
||||
} else {
|
||||
ffh_ctxt->invoke_ffh_fn = __arm_smccc_hvc;
|
||||
ffh_ctxt->invoke_ffh64_fn = arm_smccc_1_2_hvc;
|
||||
}
|
||||
|
||||
memcpy(ffh_ctxt, handler_ctxt, sizeof(ffh_ctxt->info));
|
||||
|
||||
*region_ctxt = ffh_ctxt;
|
||||
return AE_OK;
|
||||
}
|
||||
|
||||
static bool acpi_ffh_smccc_owner_allowed(u32 fid)
|
||||
{
|
||||
int owner = ARM_SMCCC_OWNER_NUM(fid);
|
||||
|
||||
if (owner == ARM_SMCCC_OWNER_STANDARD ||
|
||||
owner == ARM_SMCCC_OWNER_SIP || owner == ARM_SMCCC_OWNER_OEM)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
int acpi_ffh_address_space_arch_handler(acpi_integer *value, void *region_context)
|
||||
{
|
||||
int ret = 0;
|
||||
struct acpi_ffh_data *ffh_ctxt = region_context;
|
||||
|
||||
if (ffh_ctxt->info.offset == 0) {
|
||||
/* SMC/HVC 32bit call */
|
||||
struct arm_smccc_res res;
|
||||
u32 a[8] = { 0 }, *ptr = (u32 *)value;
|
||||
|
||||
if (!ARM_SMCCC_IS_FAST_CALL(*ptr) || ARM_SMCCC_IS_64(*ptr) ||
|
||||
!acpi_ffh_smccc_owner_allowed(*ptr) ||
|
||||
ffh_ctxt->info.length > 32) {
|
||||
ret = AE_ERROR;
|
||||
} else {
|
||||
int idx, len = ffh_ctxt->info.length >> 2;
|
||||
|
||||
for (idx = 0; idx < len; idx++)
|
||||
a[idx] = *(ptr + idx);
|
||||
|
||||
ffh_ctxt->invoke_ffh_fn(a[0], a[1], a[2], a[3], a[4],
|
||||
a[5], a[6], a[7], &res, NULL);
|
||||
memcpy(value, &res, sizeof(res));
|
||||
}
|
||||
|
||||
} else if (ffh_ctxt->info.offset == 1) {
|
||||
/* SMC/HVC 64bit call */
|
||||
struct arm_smccc_1_2_regs *r = (struct arm_smccc_1_2_regs *)value;
|
||||
|
||||
if (!ARM_SMCCC_IS_FAST_CALL(r->a0) || !ARM_SMCCC_IS_64(r->a0) ||
|
||||
!acpi_ffh_smccc_owner_allowed(r->a0) ||
|
||||
ffh_ctxt->info.length > sizeof(*r)) {
|
||||
ret = AE_ERROR;
|
||||
} else {
|
||||
ffh_ctxt->invoke_ffh64_fn(r, r);
|
||||
memcpy(value, r, ffh_ctxt->info.length);
|
||||
}
|
||||
} else {
|
||||
ret = AE_ERROR;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
#endif /* CONFIG_ACPI_FFH */
|
||||
|
|
|
|||
|
|
@ -432,14 +432,17 @@ static const struct midr_range erratum_spec_unpriv_load_list[] = {
|
|||
};
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_ARM64_WORKAROUND_SPECULATIVE_SSBS
|
||||
static const struct midr_range erratum_spec_ssbs_list[] = {
|
||||
#ifdef CONFIG_ARM64_ERRATUM_3194386
|
||||
static const struct midr_range erratum_spec_ssbs_list[] = {
|
||||
MIDR_ALL_VERSIONS(MIDR_CORTEX_A710),
|
||||
MIDR_ALL_VERSIONS(MIDR_CORTEX_A720),
|
||||
MIDR_ALL_VERSIONS(MIDR_CORTEX_X2),
|
||||
MIDR_ALL_VERSIONS(MIDR_CORTEX_X3),
|
||||
MIDR_ALL_VERSIONS(MIDR_CORTEX_X4),
|
||||
#endif
|
||||
#ifdef CONFIG_ARM64_ERRATUM_3312417
|
||||
MIDR_ALL_VERSIONS(MIDR_CORTEX_X925),
|
||||
MIDR_ALL_VERSIONS(MIDR_NEOVERSE_N2),
|
||||
MIDR_ALL_VERSIONS(MIDR_NEOVERSE_V3),
|
||||
#endif
|
||||
MIDR_ALL_VERSIONS(MIDR_NEOVERSE_V2),
|
||||
{}
|
||||
};
|
||||
#endif
|
||||
|
|
@ -741,9 +744,9 @@ const struct arm64_cpu_capabilities arm64_errata[] = {
|
|||
MIDR_FIXED(MIDR_CPU_VAR_REV(1,1), BIT(25)),
|
||||
},
|
||||
#endif
|
||||
#ifdef CONFIG_ARM64_WORKAROUND_SPECULATIVE_SSBS
|
||||
#ifdef CONFIG_ARM64_ERRATUM_3194386
|
||||
{
|
||||
.desc = "ARM errata 3194386, 3312417",
|
||||
.desc = "SSBS not fully self-synchronizing",
|
||||
.capability = ARM64_WORKAROUND_SPECULATIVE_SSBS,
|
||||
ERRATA_MIDR_RANGE_LIST(erratum_spec_ssbs_list),
|
||||
},
|
||||
|
|
|
|||
|
|
@ -285,8 +285,8 @@ static const struct arm64_ftr_bits ftr_id_aa64pfr0[] = {
|
|||
S_ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_LOWER_SAFE, ID_AA64PFR0_EL1_FP_SHIFT, 4, ID_AA64PFR0_EL1_FP_NI),
|
||||
ARM64_FTR_BITS(FTR_HIDDEN, FTR_NONSTRICT, FTR_LOWER_SAFE, ID_AA64PFR0_EL1_EL3_SHIFT, 4, 0),
|
||||
ARM64_FTR_BITS(FTR_HIDDEN, FTR_NONSTRICT, FTR_LOWER_SAFE, ID_AA64PFR0_EL1_EL2_SHIFT, 4, 0),
|
||||
ARM64_FTR_BITS(FTR_HIDDEN, FTR_NONSTRICT, FTR_LOWER_SAFE, ID_AA64PFR0_EL1_EL1_SHIFT, 4, ID_AA64PFR0_EL1_ELx_64BIT_ONLY),
|
||||
ARM64_FTR_BITS(FTR_HIDDEN, FTR_NONSTRICT, FTR_LOWER_SAFE, ID_AA64PFR0_EL1_EL0_SHIFT, 4, ID_AA64PFR0_EL1_ELx_64BIT_ONLY),
|
||||
ARM64_FTR_BITS(FTR_HIDDEN, FTR_NONSTRICT, FTR_LOWER_SAFE, ID_AA64PFR0_EL1_EL1_SHIFT, 4, ID_AA64PFR0_EL1_EL1_IMP),
|
||||
ARM64_FTR_BITS(FTR_HIDDEN, FTR_NONSTRICT, FTR_LOWER_SAFE, ID_AA64PFR0_EL1_EL0_SHIFT, 4, ID_AA64PFR0_EL1_EL0_IMP),
|
||||
ARM64_FTR_END,
|
||||
};
|
||||
|
||||
|
|
@ -429,6 +429,7 @@ static const struct arm64_ftr_bits ftr_id_aa64mmfr0[] = {
|
|||
};
|
||||
|
||||
static const struct arm64_ftr_bits ftr_id_aa64mmfr1[] = {
|
||||
ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_AA64MMFR1_EL1_ECBHB_SHIFT, 4, 0),
|
||||
ARM64_FTR_BITS(FTR_HIDDEN, FTR_NONSTRICT, FTR_LOWER_SAFE, ID_AA64MMFR1_EL1_TIDCP1_SHIFT, 4, 0),
|
||||
ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_LOWER_SAFE, ID_AA64MMFR1_EL1_AFP_SHIFT, 4, 0),
|
||||
ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_AA64MMFR1_EL1_HCX_SHIFT, 4, 0),
|
||||
|
|
|
|||
|
|
@ -105,11 +105,6 @@ KVM_NVHE_ALIAS(__hyp_stub_vectors);
|
|||
KVM_NVHE_ALIAS(vgic_v2_cpuif_trap);
|
||||
KVM_NVHE_ALIAS(vgic_v3_cpuif_trap);
|
||||
|
||||
#ifdef CONFIG_ARM64_PSEUDO_NMI
|
||||
/* Static key checked in GIC_PRIO_IRQOFF. */
|
||||
KVM_NVHE_ALIAS(gic_nonsecure_priorities);
|
||||
#endif
|
||||
|
||||
/* EL2 exception handling */
|
||||
KVM_NVHE_ALIAS(__start___kvm_ex_table);
|
||||
KVM_NVHE_ALIAS(__stop___kvm_ex_table);
|
||||
|
|
|
|||
|
|
@ -567,7 +567,7 @@ static enum mitigation_state spectre_v4_enable_hw_mitigation(void)
|
|||
* Mitigate this with an unconditional speculation barrier, as CPUs
|
||||
* could mis-speculate branches and bypass a conditional barrier.
|
||||
*/
|
||||
if (IS_ENABLED(CONFIG_ARM64_WORKAROUND_SPECULATIVE_SSBS))
|
||||
if (IS_ENABLED(CONFIG_ARM64_ERRATUM_3194386))
|
||||
spec_bar();
|
||||
|
||||
return SPECTRE_MITIGATED;
|
||||
|
|
|
|||
|
|
@ -74,4 +74,5 @@ static void __exit reloc_test_exit(void)
|
|||
module_init(reloc_test_init);
|
||||
module_exit(reloc_test_exit);
|
||||
|
||||
MODULE_DESCRIPTION("Relocation testing module");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
|
|
|
|||
|
|
@ -55,9 +55,6 @@
|
|||
|
||||
#include <trace/events/ipi.h>
|
||||
|
||||
DEFINE_PER_CPU_READ_MOSTLY(int, cpu_number);
|
||||
EXPORT_PER_CPU_SYMBOL(cpu_number);
|
||||
|
||||
/*
|
||||
* as from 2.5, kernels no longer have an init_tasks structure
|
||||
* so we need some other way of telling a new secondary core
|
||||
|
|
@ -749,8 +746,6 @@ void __init smp_prepare_cpus(unsigned int max_cpus)
|
|||
*/
|
||||
for_each_possible_cpu(cpu) {
|
||||
|
||||
per_cpu(cpu_number, cpu) = cpu;
|
||||
|
||||
if (cpu == smp_processor_id())
|
||||
continue;
|
||||
|
||||
|
|
@ -767,13 +762,15 @@ void __init smp_prepare_cpus(unsigned int max_cpus)
|
|||
}
|
||||
}
|
||||
|
||||
static const char *ipi_types[NR_IPI] __tracepoint_string = {
|
||||
static const char *ipi_types[MAX_IPI] __tracepoint_string = {
|
||||
[IPI_RESCHEDULE] = "Rescheduling interrupts",
|
||||
[IPI_CALL_FUNC] = "Function call interrupts",
|
||||
[IPI_CPU_STOP] = "CPU stop interrupts",
|
||||
[IPI_CPU_CRASH_STOP] = "CPU stop (for crash dump) interrupts",
|
||||
[IPI_TIMER] = "Timer broadcast interrupts",
|
||||
[IPI_IRQ_WORK] = "IRQ work interrupts",
|
||||
[IPI_CPU_BACKTRACE] = "CPU backtrace interrupts",
|
||||
[IPI_KGDB_ROUNDUP] = "KGDB roundup interrupts",
|
||||
};
|
||||
|
||||
static void smp_cross_call(const struct cpumask *target, unsigned int ipinr);
|
||||
|
|
@ -784,7 +781,7 @@ int arch_show_interrupts(struct seq_file *p, int prec)
|
|||
{
|
||||
unsigned int cpu, i;
|
||||
|
||||
for (i = 0; i < NR_IPI; i++) {
|
||||
for (i = 0; i < MAX_IPI; i++) {
|
||||
seq_printf(p, "%*s%u:%s", prec - 1, "IPI", i,
|
||||
prec >= 4 ? " " : "");
|
||||
for_each_online_cpu(cpu)
|
||||
|
|
@ -1028,12 +1025,12 @@ void __init set_smp_ipi_range(int ipi_base, int n)
|
|||
|
||||
if (ipi_should_be_nmi(i)) {
|
||||
err = request_percpu_nmi(ipi_base + i, ipi_handler,
|
||||
"IPI", &cpu_number);
|
||||
"IPI", &irq_stat);
|
||||
WARN(err, "Could not request IPI %d as NMI, err=%d\n",
|
||||
i, err);
|
||||
} else {
|
||||
err = request_percpu_irq(ipi_base + i, ipi_handler,
|
||||
"IPI", &cpu_number);
|
||||
"IPI", &irq_stat);
|
||||
WARN(err, "Could not request IPI %d as IRQ, err=%d\n",
|
||||
i, err);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -52,11 +52,11 @@
|
|||
* Supported by KVM
|
||||
*/
|
||||
#define PVM_ID_AA64PFR0_RESTRICT_UNSIGNED (\
|
||||
FIELD_PREP(ARM64_FEATURE_MASK(ID_AA64PFR0_EL1_EL0), ID_AA64PFR0_EL1_ELx_64BIT_ONLY) | \
|
||||
FIELD_PREP(ARM64_FEATURE_MASK(ID_AA64PFR0_EL1_EL1), ID_AA64PFR0_EL1_ELx_64BIT_ONLY) | \
|
||||
FIELD_PREP(ARM64_FEATURE_MASK(ID_AA64PFR0_EL1_EL2), ID_AA64PFR0_EL1_ELx_64BIT_ONLY) | \
|
||||
FIELD_PREP(ARM64_FEATURE_MASK(ID_AA64PFR0_EL1_EL3), ID_AA64PFR0_EL1_ELx_64BIT_ONLY) | \
|
||||
FIELD_PREP(ARM64_FEATURE_MASK(ID_AA64PFR0_EL1_RAS), ID_AA64PFR0_EL1_RAS_IMP) \
|
||||
SYS_FIELD_PREP_ENUM(ID_AA64PFR0_EL1, EL0, IMP) | \
|
||||
SYS_FIELD_PREP_ENUM(ID_AA64PFR0_EL1, EL1, IMP) | \
|
||||
SYS_FIELD_PREP_ENUM(ID_AA64PFR0_EL1, EL2, IMP) | \
|
||||
SYS_FIELD_PREP_ENUM(ID_AA64PFR0_EL1, EL3, IMP) | \
|
||||
SYS_FIELD_PREP_ENUM(ID_AA64PFR0_EL1, RAS, IMP) \
|
||||
)
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -33,9 +33,9 @@ static void pvm_init_traps_aa64pfr0(struct kvm_vcpu *vcpu)
|
|||
|
||||
/* Protected KVM does not support AArch32 guests. */
|
||||
BUILD_BUG_ON(FIELD_GET(ARM64_FEATURE_MASK(ID_AA64PFR0_EL1_EL0),
|
||||
PVM_ID_AA64PFR0_RESTRICT_UNSIGNED) != ID_AA64PFR0_EL1_ELx_64BIT_ONLY);
|
||||
PVM_ID_AA64PFR0_RESTRICT_UNSIGNED) != ID_AA64PFR0_EL1_EL0_IMP);
|
||||
BUILD_BUG_ON(FIELD_GET(ARM64_FEATURE_MASK(ID_AA64PFR0_EL1_EL1),
|
||||
PVM_ID_AA64PFR0_RESTRICT_UNSIGNED) != ID_AA64PFR0_EL1_ELx_64BIT_ONLY);
|
||||
PVM_ID_AA64PFR0_RESTRICT_UNSIGNED) != ID_AA64PFR0_EL1_EL1_IMP);
|
||||
|
||||
/*
|
||||
* Linux guests assume support for floating-point and Advanced SIMD. Do
|
||||
|
|
|
|||
|
|
@ -276,7 +276,7 @@ static bool pvm_access_id_aarch32(struct kvm_vcpu *vcpu,
|
|||
* of AArch32 feature id registers.
|
||||
*/
|
||||
BUILD_BUG_ON(FIELD_GET(ARM64_FEATURE_MASK(ID_AA64PFR0_EL1_EL1),
|
||||
PVM_ID_AA64PFR0_RESTRICT_UNSIGNED) > ID_AA64PFR0_EL1_ELx_64BIT_ONLY);
|
||||
PVM_ID_AA64PFR0_RESTRICT_UNSIGNED) > ID_AA64PFR0_EL1_EL1_IMP);
|
||||
|
||||
return pvm_access_raz_wi(vcpu, p, r);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,10 @@
|
|||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
obj-$(CONFIG_ACPI_AGDI) += agdi.o
|
||||
obj-$(CONFIG_ACPI_IORT) += iort.o
|
||||
obj-$(CONFIG_ACPI_GTDT) += gtdt.o
|
||||
obj-$(CONFIG_ACPI_APMT) += apmt.o
|
||||
obj-$(CONFIG_ACPI_FFH) += ffh.o
|
||||
obj-$(CONFIG_ACPI_GTDT) += gtdt.o
|
||||
obj-$(CONFIG_ACPI_IORT) += iort.o
|
||||
obj-$(CONFIG_ACPI_PROCESSOR_IDLE) += cpuidle.o
|
||||
obj-$(CONFIG_ARM_AMBA) += amba.o
|
||||
obj-y += dma.o init.o
|
||||
obj-y += thermal_cpufreq.o
|
||||
|
|
|
|||
|
|
@ -27,11 +27,7 @@ static const struct acpi_device_id amba_id_list[] = {
|
|||
|
||||
static void amba_register_dummy_clk(void)
|
||||
{
|
||||
static struct clk *amba_dummy_clk;
|
||||
|
||||
/* If clock already registered */
|
||||
if (amba_dummy_clk)
|
||||
return;
|
||||
struct clk *amba_dummy_clk;
|
||||
|
||||
amba_dummy_clk = clk_register_fixed_rate(NULL, "apb_pclk", NULL, 0, 0);
|
||||
clk_register_clkdev(amba_dummy_clk, "apb_pclk", NULL);
|
||||
|
|
|
|||
|
|
@ -10,9 +10,6 @@
|
|||
#include <linux/cpuidle.h>
|
||||
#include <linux/cpu_pm.h>
|
||||
#include <linux/psci.h>
|
||||
|
||||
#ifdef CONFIG_ACPI_PROCESSOR_IDLE
|
||||
|
||||
#include <acpi/processor.h>
|
||||
|
||||
#define ARM64_LPI_IS_RETENTION_STATE(arch_flags) (!(arch_flags))
|
||||
|
|
@ -71,4 +68,3 @@ __cpuidle int acpi_processor_ffh_lpi_enter(struct acpi_lpi_state *lpi)
|
|||
return CPU_PM_CPU_IDLE_ENTER_PARAM_RCU(psci_cpu_suspend_enter,
|
||||
lpi->index, state);
|
||||
}
|
||||
#endif
|
||||
107
drivers/acpi/arm64/ffh.c
Normal file
107
drivers/acpi/arm64/ffh.c
Normal file
|
|
@ -0,0 +1,107 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/arm-smccc.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
/*
|
||||
* Implements ARM64 specific callbacks to support ACPI FFH Operation Region as
|
||||
* specified in https://developer.arm.com/docs/den0048/latest
|
||||
*/
|
||||
struct acpi_ffh_data {
|
||||
struct acpi_ffh_info info;
|
||||
void (*invoke_ffh_fn)(unsigned long a0, unsigned long a1,
|
||||
unsigned long a2, unsigned long a3,
|
||||
unsigned long a4, unsigned long a5,
|
||||
unsigned long a6, unsigned long a7,
|
||||
struct arm_smccc_res *args,
|
||||
struct arm_smccc_quirk *res);
|
||||
void (*invoke_ffh64_fn)(const struct arm_smccc_1_2_regs *args,
|
||||
struct arm_smccc_1_2_regs *res);
|
||||
};
|
||||
|
||||
int acpi_ffh_address_space_arch_setup(void *handler_ctxt, void **region_ctxt)
|
||||
{
|
||||
enum arm_smccc_conduit conduit;
|
||||
struct acpi_ffh_data *ffh_ctxt;
|
||||
|
||||
if (arm_smccc_get_version() < ARM_SMCCC_VERSION_1_2)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
conduit = arm_smccc_1_1_get_conduit();
|
||||
if (conduit == SMCCC_CONDUIT_NONE) {
|
||||
pr_err("%s: invalid SMCCC conduit\n", __func__);
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
ffh_ctxt = kzalloc(sizeof(*ffh_ctxt), GFP_KERNEL);
|
||||
if (!ffh_ctxt)
|
||||
return -ENOMEM;
|
||||
|
||||
if (conduit == SMCCC_CONDUIT_SMC) {
|
||||
ffh_ctxt->invoke_ffh_fn = __arm_smccc_smc;
|
||||
ffh_ctxt->invoke_ffh64_fn = arm_smccc_1_2_smc;
|
||||
} else {
|
||||
ffh_ctxt->invoke_ffh_fn = __arm_smccc_hvc;
|
||||
ffh_ctxt->invoke_ffh64_fn = arm_smccc_1_2_hvc;
|
||||
}
|
||||
|
||||
memcpy(ffh_ctxt, handler_ctxt, sizeof(ffh_ctxt->info));
|
||||
|
||||
*region_ctxt = ffh_ctxt;
|
||||
return AE_OK;
|
||||
}
|
||||
|
||||
static bool acpi_ffh_smccc_owner_allowed(u32 fid)
|
||||
{
|
||||
int owner = ARM_SMCCC_OWNER_NUM(fid);
|
||||
|
||||
if (owner == ARM_SMCCC_OWNER_STANDARD ||
|
||||
owner == ARM_SMCCC_OWNER_SIP || owner == ARM_SMCCC_OWNER_OEM)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
int acpi_ffh_address_space_arch_handler(acpi_integer *value, void *region_context)
|
||||
{
|
||||
int ret = 0;
|
||||
struct acpi_ffh_data *ffh_ctxt = region_context;
|
||||
|
||||
if (ffh_ctxt->info.offset == 0) {
|
||||
/* SMC/HVC 32bit call */
|
||||
struct arm_smccc_res res;
|
||||
u32 a[8] = { 0 }, *ptr = (u32 *)value;
|
||||
|
||||
if (!ARM_SMCCC_IS_FAST_CALL(*ptr) || ARM_SMCCC_IS_64(*ptr) ||
|
||||
!acpi_ffh_smccc_owner_allowed(*ptr) ||
|
||||
ffh_ctxt->info.length > 32) {
|
||||
ret = AE_ERROR;
|
||||
} else {
|
||||
int idx, len = ffh_ctxt->info.length >> 2;
|
||||
|
||||
for (idx = 0; idx < len; idx++)
|
||||
a[idx] = *(ptr + idx);
|
||||
|
||||
ffh_ctxt->invoke_ffh_fn(a[0], a[1], a[2], a[3], a[4],
|
||||
a[5], a[6], a[7], &res, NULL);
|
||||
memcpy(value, &res, sizeof(res));
|
||||
}
|
||||
|
||||
} else if (ffh_ctxt->info.offset == 1) {
|
||||
/* SMC/HVC 64bit call */
|
||||
struct arm_smccc_1_2_regs *r = (struct arm_smccc_1_2_regs *)value;
|
||||
|
||||
if (!ARM_SMCCC_IS_FAST_CALL(r->a0) || !ARM_SMCCC_IS_64(r->a0) ||
|
||||
!acpi_ffh_smccc_owner_allowed(r->a0) ||
|
||||
ffh_ctxt->info.length > sizeof(*r)) {
|
||||
ret = AE_ERROR;
|
||||
} else {
|
||||
ffh_ctxt->invoke_ffh64_fn(r, r);
|
||||
memcpy(value, r, ffh_ctxt->info.length);
|
||||
}
|
||||
} else {
|
||||
ret = AE_ERROR;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
@ -7,6 +7,7 @@
|
|||
#include <linux/io.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/irqchip/arm-gic.h>
|
||||
#include <linux/kernel.h>
|
||||
|
||||
#include "irq-gic-common.h"
|
||||
|
||||
|
|
@ -45,7 +46,7 @@ void gic_enable_quirks(u32 iidr, const struct gic_quirk *quirks,
|
|||
}
|
||||
|
||||
int gic_configure_irq(unsigned int irq, unsigned int type,
|
||||
void __iomem *base, void (*sync_access)(void))
|
||||
void __iomem *base)
|
||||
{
|
||||
u32 confmask = 0x2 << ((irq % 16) * 2);
|
||||
u32 confoff = (irq / 16) * 4;
|
||||
|
|
@ -84,14 +85,10 @@ int gic_configure_irq(unsigned int irq, unsigned int type,
|
|||
|
||||
raw_spin_unlock_irqrestore(&irq_controller_lock, flags);
|
||||
|
||||
if (sync_access)
|
||||
sync_access();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void gic_dist_config(void __iomem *base, int gic_irqs,
|
||||
void (*sync_access)(void))
|
||||
void gic_dist_config(void __iomem *base, int gic_irqs, u8 priority)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
|
|
@ -106,7 +103,8 @@ void gic_dist_config(void __iomem *base, int gic_irqs,
|
|||
* Set priority on all global interrupts.
|
||||
*/
|
||||
for (i = 32; i < gic_irqs; i += 4)
|
||||
writel_relaxed(GICD_INT_DEF_PRI_X4, base + GIC_DIST_PRI + i);
|
||||
writel_relaxed(REPEAT_BYTE_U32(priority),
|
||||
base + GIC_DIST_PRI + i);
|
||||
|
||||
/*
|
||||
* Deactivate and disable all SPIs. Leave the PPI and SGIs
|
||||
|
|
@ -118,12 +116,9 @@ void gic_dist_config(void __iomem *base, int gic_irqs,
|
|||
writel_relaxed(GICD_INT_EN_CLR_X32,
|
||||
base + GIC_DIST_ENABLE_CLEAR + i / 8);
|
||||
}
|
||||
|
||||
if (sync_access)
|
||||
sync_access();
|
||||
}
|
||||
|
||||
void gic_cpu_config(void __iomem *base, int nr, void (*sync_access)(void))
|
||||
void gic_cpu_config(void __iomem *base, int nr, u8 priority)
|
||||
{
|
||||
int i;
|
||||
|
||||
|
|
@ -142,9 +137,6 @@ void gic_cpu_config(void __iomem *base, int nr, void (*sync_access)(void))
|
|||
* Set priority on PPI and SGI interrupts
|
||||
*/
|
||||
for (i = 0; i < nr; i += 4)
|
||||
writel_relaxed(GICD_INT_DEF_PRI_X4,
|
||||
writel_relaxed(REPEAT_BYTE_U32(priority),
|
||||
base + GIC_DIST_PRI + i * 4 / 4);
|
||||
|
||||
if (sync_access)
|
||||
sync_access();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,10 +20,9 @@ struct gic_quirk {
|
|||
};
|
||||
|
||||
int gic_configure_irq(unsigned int irq, unsigned int type,
|
||||
void __iomem *base, void (*sync_access)(void));
|
||||
void gic_dist_config(void __iomem *base, int gic_irqs,
|
||||
void (*sync_access)(void));
|
||||
void gic_cpu_config(void __iomem *base, int nr, void (*sync_access)(void));
|
||||
void __iomem *base);
|
||||
void gic_dist_config(void __iomem *base, int gic_irqs, u8 priority);
|
||||
void gic_cpu_config(void __iomem *base, int nr, u8 priority);
|
||||
void gic_enable_quirks(u32 iidr, const struct gic_quirk *quirks,
|
||||
void *data);
|
||||
void gic_enable_of_quirks(const struct device_node *np,
|
||||
|
|
|
|||
|
|
@ -59,7 +59,7 @@ static u32 lpi_id_bits;
|
|||
#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 GICD_INT_DEF_PRI
|
||||
static u8 __ro_after_init lpi_prop_prio;
|
||||
|
||||
/*
|
||||
* Collection structure - just an ID, and a redistributor address to
|
||||
|
|
@ -1926,7 +1926,7 @@ static int its_vlpi_unmap(struct irq_data *d)
|
|||
/* and restore the physical one */
|
||||
irqd_clr_forwarded_to_vcpu(d);
|
||||
its_send_mapti(its_dev, d->hwirq, event);
|
||||
lpi_update_config(d, 0xff, (LPI_PROP_DEFAULT_PRIO |
|
||||
lpi_update_config(d, 0xff, (lpi_prop_prio |
|
||||
LPI_PROP_ENABLED |
|
||||
LPI_PROP_GROUP1));
|
||||
|
||||
|
|
@ -2181,8 +2181,8 @@ static void its_lpi_free(unsigned long *bitmap, u32 base, u32 nr_ids)
|
|||
|
||||
static void gic_reset_prop_table(void *va)
|
||||
{
|
||||
/* Priority 0xa0, Group-1, disabled */
|
||||
memset(va, LPI_PROP_DEFAULT_PRIO | LPI_PROP_GROUP1, LPI_PROPBASE_SZ);
|
||||
/* Regular IRQ priority, Group-1, disabled */
|
||||
memset(va, lpi_prop_prio | LPI_PROP_GROUP1, LPI_PROPBASE_SZ);
|
||||
|
||||
/* Make sure the GIC will observe the written configuration */
|
||||
gic_flush_dcache_to_poc(va, LPI_PROPBASE_SZ);
|
||||
|
|
@ -5650,7 +5650,7 @@ int __init its_lpi_memreserve_init(void)
|
|||
}
|
||||
|
||||
int __init its_init(struct fwnode_handle *handle, struct rdists *rdists,
|
||||
struct irq_domain *parent_domain)
|
||||
struct irq_domain *parent_domain, u8 irq_prio)
|
||||
{
|
||||
struct device_node *of_node;
|
||||
struct its_node *its;
|
||||
|
|
@ -5660,6 +5660,7 @@ int __init its_init(struct fwnode_handle *handle, struct rdists *rdists,
|
|||
|
||||
gic_rdists = rdists;
|
||||
|
||||
lpi_prop_prio = irq_prio;
|
||||
its_parent = parent_domain;
|
||||
of_node = to_of_node(handle);
|
||||
if (of_node)
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@
|
|||
#include <linux/delay.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/irqdomain.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/kstrtox.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_address.h>
|
||||
|
|
@ -24,6 +25,7 @@
|
|||
#include <linux/irqchip.h>
|
||||
#include <linux/irqchip/arm-gic-common.h>
|
||||
#include <linux/irqchip/arm-gic-v3.h>
|
||||
#include <linux/irqchip/arm-gic-v3-prio.h>
|
||||
#include <linux/irqchip/irq-partition-percpu.h>
|
||||
#include <linux/bitfield.h>
|
||||
#include <linux/bits.h>
|
||||
|
|
@ -36,7 +38,8 @@
|
|||
|
||||
#include "irq-gic-common.h"
|
||||
|
||||
#define GICD_INT_NMI_PRI (GICD_INT_DEF_PRI & ~0x80)
|
||||
static u8 dist_prio_irq __ro_after_init = GICV3_PRIO_IRQ;
|
||||
static u8 dist_prio_nmi __ro_after_init = GICV3_PRIO_NMI;
|
||||
|
||||
#define FLAGS_WORKAROUND_GICR_WAKER_MSM8996 (1ULL << 0)
|
||||
#define FLAGS_WORKAROUND_CAVIUM_ERRATUM_38539 (1ULL << 1)
|
||||
|
|
@ -108,29 +111,96 @@ static DEFINE_STATIC_KEY_TRUE(supports_deactivate_key);
|
|||
*/
|
||||
static DEFINE_STATIC_KEY_FALSE(supports_pseudo_nmis);
|
||||
|
||||
DEFINE_STATIC_KEY_FALSE(gic_nonsecure_priorities);
|
||||
EXPORT_SYMBOL(gic_nonsecure_priorities);
|
||||
static u32 gic_get_pribits(void)
|
||||
{
|
||||
u32 pribits;
|
||||
|
||||
/*
|
||||
* When the Non-secure world has access to group 0 interrupts (as a
|
||||
* consequence of SCR_EL3.FIQ == 0), reading the ICC_RPR_EL1 register will
|
||||
* return the Distributor's view of the interrupt priority.
|
||||
*
|
||||
* When GIC security is enabled (GICD_CTLR.DS == 0), the interrupt priority
|
||||
* written by software is moved to the Non-secure range by the Distributor.
|
||||
*
|
||||
* If both are true (which is when gic_nonsecure_priorities gets enabled),
|
||||
* we need to shift down the priority programmed by software to match it
|
||||
* against the value returned by ICC_RPR_EL1.
|
||||
*/
|
||||
#define GICD_INT_RPR_PRI(priority) \
|
||||
({ \
|
||||
u32 __priority = (priority); \
|
||||
if (static_branch_unlikely(&gic_nonsecure_priorities)) \
|
||||
__priority = 0x80 | (__priority >> 1); \
|
||||
\
|
||||
__priority; \
|
||||
})
|
||||
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 inline bool gic_dist_security_disabled(void)
|
||||
{
|
||||
return readl_relaxed(gic_data.dist_base + GICD_CTLR) & GICD_CTLR_DS;
|
||||
}
|
||||
|
||||
static bool cpus_have_security_disabled __ro_after_init;
|
||||
static bool cpus_have_group0 __ro_after_init;
|
||||
|
||||
static void __init gic_prio_init(void)
|
||||
{
|
||||
cpus_have_security_disabled = gic_dist_security_disabled();
|
||||
cpus_have_group0 = gic_has_group0();
|
||||
|
||||
/*
|
||||
* How priority values are used by the GIC depends on two things:
|
||||
* the security state of the GIC (controlled by the GICD_CTRL.DS bit)
|
||||
* and if Group 0 interrupts can be delivered to Linux in the non-secure
|
||||
* world as FIQs (controlled by the SCR_EL3.FIQ bit). These affect the
|
||||
* way priorities are presented in ICC_PMR_EL1 and in the distributor:
|
||||
*
|
||||
* GICD_CTRL.DS | SCR_EL3.FIQ | ICC_PMR_EL1 | Distributor
|
||||
* -------------------------------------------------------
|
||||
* 1 | - | unchanged | unchanged
|
||||
* -------------------------------------------------------
|
||||
* 0 | 1 | non-secure | non-secure
|
||||
* -------------------------------------------------------
|
||||
* 0 | 0 | unchanged | non-secure
|
||||
*
|
||||
* In the non-secure view reads and writes are modified:
|
||||
*
|
||||
* - A value written is right-shifted by one and the MSB is set,
|
||||
* forcing the priority into the non-secure range.
|
||||
*
|
||||
* - A value read is left-shifted by one.
|
||||
*
|
||||
* In the first two cases, where ICC_PMR_EL1 and the interrupt priority
|
||||
* are both either modified or unchanged, we can use the same set of
|
||||
* priorities.
|
||||
*
|
||||
* In the last case, where only the interrupt priorities are modified to
|
||||
* be in the non-secure range, we program the non-secure values into
|
||||
* the distributor to match the PMR values we want.
|
||||
*/
|
||||
if (cpus_have_group0 & !cpus_have_security_disabled) {
|
||||
dist_prio_irq = __gicv3_prio_to_ns(dist_prio_irq);
|
||||
dist_prio_nmi = __gicv3_prio_to_ns(dist_prio_nmi);
|
||||
}
|
||||
|
||||
pr_info("GICD_CTRL.DS=%d, SCR_EL3.FIQ=%d\n",
|
||||
cpus_have_security_disabled,
|
||||
!cpus_have_group0);
|
||||
}
|
||||
|
||||
/* rdist_nmi_refs[n] == number of cpus having the rdist interrupt n set as NMI */
|
||||
static refcount_t *rdist_nmi_refs;
|
||||
|
|
@ -556,7 +626,7 @@ static int gic_irq_nmi_setup(struct irq_data *d)
|
|||
desc->handle_irq = handle_fasteoi_nmi;
|
||||
}
|
||||
|
||||
gic_irq_set_prio(d, GICD_INT_NMI_PRI);
|
||||
gic_irq_set_prio(d, dist_prio_nmi);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -591,7 +661,7 @@ static void gic_irq_nmi_teardown(struct irq_data *d)
|
|||
desc->handle_irq = handle_fasteoi_irq;
|
||||
}
|
||||
|
||||
gic_irq_set_prio(d, GICD_INT_DEF_PRI);
|
||||
gic_irq_set_prio(d, dist_prio_irq);
|
||||
}
|
||||
|
||||
static bool gic_arm64_erratum_2941627_needed(struct irq_data *d)
|
||||
|
|
@ -670,7 +740,7 @@ static int gic_set_type(struct irq_data *d, unsigned int type)
|
|||
|
||||
offset = convert_offset_index(d, GICD_ICFGR, &index);
|
||||
|
||||
ret = gic_configure_irq(index, type, base + offset, NULL);
|
||||
ret = gic_configure_irq(index, type, base + offset);
|
||||
if (ret && (range == PPI_RANGE || range == EPPI_RANGE)) {
|
||||
/* Misconfigured PPIs are usually not fatal */
|
||||
pr_warn("GIC: PPI INTID%ld is secure or misconfigured\n", irq);
|
||||
|
|
@ -753,7 +823,7 @@ static bool gic_rpr_is_nmi_prio(void)
|
|||
if (!gic_supports_nmi())
|
||||
return false;
|
||||
|
||||
return unlikely(gic_read_rpr() == GICD_INT_RPR_PRI(GICD_INT_NMI_PRI));
|
||||
return unlikely(gic_read_rpr() == GICV3_PRIO_NMI);
|
||||
}
|
||||
|
||||
static bool gic_irqnr_is_special(u32 irqnr)
|
||||
|
|
@ -866,44 +936,6 @@ static asmlinkage void __exception_irq_entry gic_handle_irq(struct pt_regs *regs
|
|||
__gic_handle_irq_from_irqson(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;
|
||||
|
|
@ -937,10 +969,11 @@ static void __init gic_dist_init(void)
|
|||
writel_relaxed(0, base + GICD_ICFGRnE + i / 4);
|
||||
|
||||
for (i = 0; i < GIC_ESPI_NR; i += 4)
|
||||
writel_relaxed(GICD_INT_DEF_PRI_X4, base + GICD_IPRIORITYRnE + i);
|
||||
writel_relaxed(REPEAT_BYTE_U32(dist_prio_irq),
|
||||
base + GICD_IPRIORITYRnE + i);
|
||||
|
||||
/* Now do the common stuff */
|
||||
gic_dist_config(base, GIC_LINE_NR, NULL);
|
||||
gic_dist_config(base, GIC_LINE_NR, dist_prio_irq);
|
||||
|
||||
val = GICD_CTLR_ARE_NS | GICD_CTLR_ENABLE_G1A | GICD_CTLR_ENABLE_G1;
|
||||
if (gic_data.rdists.gicd_typer2 & GICD_TYPER2_nASSGIcap) {
|
||||
|
|
@ -1119,12 +1152,6 @@ static void gic_update_rdist_properties(void)
|
|||
gic_data.rdists.has_vpend_valid_dirty ? "Valid+Dirty " : "");
|
||||
}
|
||||
|
||||
/* 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();
|
||||
|
|
@ -1152,18 +1179,14 @@ static void gic_cpu_sys_reg_init(void)
|
|||
write_gicreg(DEFAULT_PMR_VALUE, ICC_PMR_EL1);
|
||||
} else if (gic_supports_nmi()) {
|
||||
/*
|
||||
* Mismatch configuration with boot CPU, the system is likely
|
||||
* to die as interrupt masking will not work properly on all
|
||||
* CPUs
|
||||
* Check that all CPUs use the same priority space.
|
||||
*
|
||||
* The boot CPU calls this function before enabling NMI support,
|
||||
* and as a result we'll never see this warning in the boot path
|
||||
* for that CPU.
|
||||
* If there's a mismatch with the boot CPU, the system is
|
||||
* likely to die as interrupt masking will not work properly on
|
||||
* all CPUs.
|
||||
*/
|
||||
if (static_branch_unlikely(&gic_nonsecure_priorities))
|
||||
WARN_ON(!group0 || gic_dist_security_disabled());
|
||||
else
|
||||
WARN_ON(group0 && !gic_dist_security_disabled());
|
||||
WARN_ON(group0 != cpus_have_group0);
|
||||
WARN_ON(gic_dist_security_disabled() != cpus_have_security_disabled);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -1282,7 +1305,8 @@ static void gic_cpu_init(void)
|
|||
for (i = 0; i < gic_data.ppi_nr + SGI_NR; i += 32)
|
||||
writel_relaxed(~0, rbase + GICR_IGROUPR0 + i / 8);
|
||||
|
||||
gic_cpu_config(rbase, gic_data.ppi_nr + SGI_NR, gic_redist_wait_for_rwp);
|
||||
gic_cpu_config(rbase, gic_data.ppi_nr + SGI_NR, dist_prio_irq);
|
||||
gic_redist_wait_for_rwp();
|
||||
|
||||
/* initialise system registers */
|
||||
gic_cpu_sys_reg_init();
|
||||
|
|
@ -1948,36 +1972,6 @@ static void gic_enable_nmi_support(void)
|
|||
pr_info("Pseudo-NMIs enabled using %s ICC_PMR_EL1 synchronisation\n",
|
||||
gic_has_relaxed_pmr_sync() ? "relaxed" : "forced");
|
||||
|
||||
/*
|
||||
* How priority values are used by the GIC depends on two things:
|
||||
* the security state of the GIC (controlled by the GICD_CTRL.DS bit)
|
||||
* and if Group 0 interrupts can be delivered to Linux in the non-secure
|
||||
* world as FIQs (controlled by the SCR_EL3.FIQ bit). These affect the
|
||||
* ICC_PMR_EL1 register and the priority that software assigns to
|
||||
* interrupts:
|
||||
*
|
||||
* GICD_CTRL.DS | SCR_EL3.FIQ | ICC_PMR_EL1 | Group 1 priority
|
||||
* -----------------------------------------------------------
|
||||
* 1 | - | unchanged | unchanged
|
||||
* -----------------------------------------------------------
|
||||
* 0 | 1 | non-secure | non-secure
|
||||
* -----------------------------------------------------------
|
||||
* 0 | 0 | unchanged | non-secure
|
||||
*
|
||||
* where non-secure means that the value is right-shifted by one and the
|
||||
* MSB bit set, to make it fit in the non-secure priority range.
|
||||
*
|
||||
* In the first two cases, where ICC_PMR_EL1 and the interrupt priority
|
||||
* are both either modified or unchanged, we can use the same set of
|
||||
* priorities.
|
||||
*
|
||||
* In the last case, where only the interrupt priorities are modified to
|
||||
* be in the non-secure range, we use a different PMR value to mask IRQs
|
||||
* and the rest of the values that we use remain unchanged.
|
||||
*/
|
||||
if (gic_has_group0() && !gic_dist_security_disabled())
|
||||
static_branch_enable(&gic_nonsecure_priorities);
|
||||
|
||||
static_branch_enable(&supports_pseudo_nmis);
|
||||
|
||||
if (static_branch_likely(&supports_deactivate_key))
|
||||
|
|
@ -2058,6 +2052,7 @@ static int __init gic_init_bases(phys_addr_t dist_phys_base,
|
|||
|
||||
gic_update_rdist_properties();
|
||||
|
||||
gic_prio_init();
|
||||
gic_dist_init();
|
||||
gic_cpu_init();
|
||||
gic_enable_nmi_support();
|
||||
|
|
@ -2065,7 +2060,7 @@ static int __init gic_init_bases(phys_addr_t dist_phys_base,
|
|||
gic_cpu_pm_init();
|
||||
|
||||
if (gic_dist_supports_lpis()) {
|
||||
its_init(handle, &gic_data.rdists, gic_data.domain);
|
||||
its_init(handle, &gic_data.rdists, gic_data.domain, dist_prio_irq);
|
||||
its_cpu_init();
|
||||
its_lpi_memreserve_init();
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -303,7 +303,7 @@ static int gic_set_type(struct irq_data *d, unsigned int type)
|
|||
type != IRQ_TYPE_EDGE_RISING)
|
||||
return -EINVAL;
|
||||
|
||||
ret = gic_configure_irq(gicirq, type, base + GIC_DIST_CONFIG, NULL);
|
||||
ret = gic_configure_irq(gicirq, type, base + GIC_DIST_CONFIG);
|
||||
if (ret && gicirq < 32) {
|
||||
/* Misconfigured PPIs are usually not fatal */
|
||||
pr_warn("GIC: PPI%ld is secure or misconfigured\n", gicirq - 16);
|
||||
|
|
@ -479,7 +479,7 @@ static void gic_dist_init(struct gic_chip_data *gic)
|
|||
for (i = 32; i < gic_irqs; i += 4)
|
||||
writel_relaxed(cpumask, base + GIC_DIST_TARGET + i * 4 / 4);
|
||||
|
||||
gic_dist_config(base, gic_irqs, NULL);
|
||||
gic_dist_config(base, gic_irqs, GICD_INT_DEF_PRI);
|
||||
|
||||
writel_relaxed(GICD_ENABLE, base + GIC_DIST_CTRL);
|
||||
}
|
||||
|
|
@ -516,7 +516,7 @@ static int gic_cpu_init(struct gic_chip_data *gic)
|
|||
gic_cpu_map[i] &= ~cpu_mask;
|
||||
}
|
||||
|
||||
gic_cpu_config(dist_base, 32, NULL);
|
||||
gic_cpu_config(dist_base, 32, GICD_INT_DEF_PRI);
|
||||
|
||||
writel_relaxed(GICC_INT_PRI_THRESHOLD, base + GIC_CPU_PRIMASK);
|
||||
gic_cpu_if_up(gic);
|
||||
|
|
@ -608,7 +608,7 @@ void gic_dist_restore(struct gic_chip_data *gic)
|
|||
dist_base + GIC_DIST_CONFIG + i * 4);
|
||||
|
||||
for (i = 0; i < DIV_ROUND_UP(gic_irqs, 4); i++)
|
||||
writel_relaxed(GICD_INT_DEF_PRI_X4,
|
||||
writel_relaxed(REPEAT_BYTE_U32(GICD_INT_DEF_PRI),
|
||||
dist_base + GIC_DIST_PRI + i * 4);
|
||||
|
||||
for (i = 0; i < DIV_ROUND_UP(gic_irqs, 4); i++)
|
||||
|
|
@ -697,7 +697,7 @@ void gic_cpu_restore(struct gic_chip_data *gic)
|
|||
writel_relaxed(ptr[i], dist_base + GIC_DIST_CONFIG + i * 4);
|
||||
|
||||
for (i = 0; i < DIV_ROUND_UP(32, 4); i++)
|
||||
writel_relaxed(GICD_INT_DEF_PRI_X4,
|
||||
writel_relaxed(REPEAT_BYTE_U32(GICD_INT_DEF_PRI),
|
||||
dist_base + GIC_DIST_PRI + i * 4);
|
||||
|
||||
writel_relaxed(GICC_INT_PRI_THRESHOLD, cpu_base + GIC_CPU_PRIMASK);
|
||||
|
|
|
|||
|
|
@ -130,7 +130,7 @@ static int hip04_irq_set_type(struct irq_data *d, unsigned int type)
|
|||
|
||||
raw_spin_lock(&irq_controller_lock);
|
||||
|
||||
ret = gic_configure_irq(irq, type, base + GIC_DIST_CONFIG, NULL);
|
||||
ret = gic_configure_irq(irq, type, base + GIC_DIST_CONFIG);
|
||||
if (ret && irq < 32) {
|
||||
/* Misconfigured PPIs are usually not fatal */
|
||||
pr_warn("GIC: PPI%d is secure or misconfigured\n", irq - 16);
|
||||
|
|
@ -260,7 +260,7 @@ static void __init hip04_irq_dist_init(struct hip04_irq_data *intc)
|
|||
for (i = 32; i < nr_irqs; i += 2)
|
||||
writel_relaxed(cpumask, base + GIC_DIST_TARGET + ((i * 2) & ~3));
|
||||
|
||||
gic_dist_config(base, nr_irqs, NULL);
|
||||
gic_dist_config(base, nr_irqs, GICD_INT_DEF_PRI);
|
||||
|
||||
writel_relaxed(1, base + GIC_DIST_CTRL);
|
||||
}
|
||||
|
|
@ -287,7 +287,7 @@ static void hip04_irq_cpu_init(struct hip04_irq_data *intc)
|
|||
if (i != cpu)
|
||||
hip04_cpu_map[i] &= ~cpu_mask;
|
||||
|
||||
gic_cpu_config(dist_base, 32, NULL);
|
||||
gic_cpu_config(dist_base, 32, GICD_INT_DEF_PRI);
|
||||
|
||||
writel_relaxed(0xf0, base + GIC_CPU_PRIMASK);
|
||||
writel_relaxed(1, base + GIC_CPU_CTRL);
|
||||
|
|
|
|||
|
|
@ -10,10 +10,6 @@
|
|||
#include <linux/irqchip/arm-vgic-info.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)
|
||||
|
||||
struct irq_domain;
|
||||
struct fwnode_handle;
|
||||
|
|
|
|||
52
include/linux/irqchip/arm-gic-v3-prio.h
Normal file
52
include/linux/irqchip/arm-gic-v3-prio.h
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
|
||||
#ifndef __LINUX_IRQCHIP_ARM_GIC_V3_PRIO_H
|
||||
#define __LINUX_IRQCHIP_ARM_GIC_V3_PRIO_H
|
||||
|
||||
/*
|
||||
* GIC priorities from the view of the PMR/RPR.
|
||||
*
|
||||
* These values are chosen to be valid in either the absolute priority space or
|
||||
* the NS view of the priority space. The value programmed into the distributor
|
||||
* and ITS will be chosen at boot time such that these values appear in the
|
||||
* PMR/RPR.
|
||||
*
|
||||
* GICV3_PRIO_UNMASKED is the PMR view of the priority to use to permit both
|
||||
* IRQs and pseudo-NMIs.
|
||||
*
|
||||
* GICV3_PRIO_IRQ is the PMR view of the priority of regular interrupts. This
|
||||
* can be written to the PMR to mask regular IRQs.
|
||||
*
|
||||
* GICV3_PRIO_NMI is the PMR view of the priority of pseudo-NMIs. This can be
|
||||
* written to the PMR to mask pseudo-NMIs.
|
||||
*
|
||||
* On arm64 some code sections either automatically switch back to PSR.I or
|
||||
* explicitly require to not use priority masking. If bit GICV3_PRIO_PSR_I_SET
|
||||
* is included in the priority mask, it indicates that PSR.I should be set and
|
||||
* interrupt disabling temporarily does not rely on IRQ priorities.
|
||||
*/
|
||||
#define GICV3_PRIO_UNMASKED 0xe0
|
||||
#define GICV3_PRIO_IRQ 0xc0
|
||||
#define GICV3_PRIO_NMI 0x80
|
||||
|
||||
#define GICV3_PRIO_PSR_I_SET (1 << 4)
|
||||
|
||||
#ifndef __ASSEMBLER__
|
||||
|
||||
#define __gicv3_prio_to_ns(p) (0xff & ((p) << 1))
|
||||
#define __gicv3_ns_to_prio(ns) (0x80 | ((ns) >> 1))
|
||||
|
||||
#define __gicv3_prio_valid_ns(p) \
|
||||
(__gicv3_ns_to_prio(__gicv3_prio_to_ns(p)) == (p))
|
||||
|
||||
static_assert(__gicv3_prio_valid_ns(GICV3_PRIO_NMI));
|
||||
static_assert(__gicv3_prio_valid_ns(GICV3_PRIO_IRQ));
|
||||
|
||||
static_assert(GICV3_PRIO_NMI < GICV3_PRIO_IRQ);
|
||||
static_assert(GICV3_PRIO_IRQ < GICV3_PRIO_UNMASKED);
|
||||
|
||||
static_assert(GICV3_PRIO_IRQ < (GICV3_PRIO_IRQ | GICV3_PRIO_PSR_I_SET));
|
||||
|
||||
#endif /* __ASSEMBLER */
|
||||
|
||||
#endif /* __LINUX_IRQCHIP_ARM_GIC_V3_PRIO_H */
|
||||
|
|
@ -638,7 +638,7 @@ struct fwnode_handle;
|
|||
int __init its_lpi_memreserve_init(void);
|
||||
int its_cpu_init(void);
|
||||
int its_init(struct fwnode_handle *handle, struct rdists *rdists,
|
||||
struct irq_domain *domain);
|
||||
struct irq_domain *domain, u8 irq_prio);
|
||||
int mbi_init(struct fwnode_handle *fwnode, struct irq_domain *parent);
|
||||
|
||||
static inline bool gic_enable_sre(void)
|
||||
|
|
|
|||
|
|
@ -39,6 +39,14 @@
|
|||
*/
|
||||
#define REPEAT_BYTE(x) ((~0ul / 0xff) * (x))
|
||||
|
||||
/**
|
||||
* REPEAT_BYTE_U32 - repeat the value @x multiple times as a u32 value
|
||||
* @x: value to repeat
|
||||
*
|
||||
* NOTE: @x is not checked for > 0xff; larger values produce odd results.
|
||||
*/
|
||||
#define REPEAT_BYTE_U32(x) lower_32_bits(REPEAT_BYTE(x))
|
||||
|
||||
/* Set bits in the first 'n' bytes when loaded from memory */
|
||||
#ifdef __LITTLE_ENDIAN
|
||||
# define aligned_byte_mask(n) ((1UL << 8*(n))-1)
|
||||
|
|
|
|||
|
|
@ -47,7 +47,7 @@ static void test_tpidr(pid_t child)
|
|||
|
||||
/* ...write a new value.. */
|
||||
write_iov.iov_len = sizeof(uint64_t);
|
||||
write_val[0] = read_val[0]++;
|
||||
write_val[0] = read_val[0] + 1;
|
||||
ret = ptrace(PTRACE_SETREGSET, child, NT_ARM_TLS, &write_iov);
|
||||
ksft_test_result(ret == 0, "write_tpidr_one\n");
|
||||
|
||||
|
|
|
|||
1
tools/testing/selftests/arm64/fp/.gitignore
vendored
1
tools/testing/selftests/arm64/fp/.gitignore
vendored
|
|
@ -2,6 +2,7 @@ fp-pidbench
|
|||
fp-ptrace
|
||||
fp-stress
|
||||
fpsimd-test
|
||||
kernel-test
|
||||
rdvl-sme
|
||||
rdvl-sve
|
||||
sve-probe-vls
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ TEST_GEN_PROGS := \
|
|||
vec-syscfg \
|
||||
za-fork za-ptrace
|
||||
TEST_GEN_PROGS_EXTENDED := fp-pidbench fpsimd-test \
|
||||
kernel-test \
|
||||
rdvl-sme rdvl-sve \
|
||||
sve-test \
|
||||
ssve-test \
|
||||
|
|
|
|||
|
|
@ -319,6 +319,19 @@ static void start_fpsimd(struct child_data *child, int cpu, int copy)
|
|||
ksft_print_msg("Started %s\n", child->name);
|
||||
}
|
||||
|
||||
static void start_kernel(struct child_data *child, int cpu, int copy)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = asprintf(&child->name, "KERNEL-%d-%d", cpu, copy);
|
||||
if (ret == -1)
|
||||
ksft_exit_fail_msg("asprintf() failed\n");
|
||||
|
||||
child_start(child, "./kernel-test");
|
||||
|
||||
ksft_print_msg("Started %s\n", child->name);
|
||||
}
|
||||
|
||||
static void start_sve(struct child_data *child, int vl, int cpu)
|
||||
{
|
||||
int ret;
|
||||
|
|
@ -438,7 +451,7 @@ int main(int argc, char **argv)
|
|||
int ret;
|
||||
int timeout = 10;
|
||||
int cpus, i, j, c;
|
||||
int sve_vl_count, sme_vl_count, fpsimd_per_cpu;
|
||||
int sve_vl_count, sme_vl_count;
|
||||
bool all_children_started = false;
|
||||
int seen_children;
|
||||
int sve_vls[MAX_VLS], sme_vls[MAX_VLS];
|
||||
|
|
@ -482,12 +495,7 @@ int main(int argc, char **argv)
|
|||
have_sme2 = false;
|
||||
}
|
||||
|
||||
/* Force context switching if we only have FPSIMD */
|
||||
if (!sve_vl_count && !sme_vl_count)
|
||||
fpsimd_per_cpu = 2;
|
||||
else
|
||||
fpsimd_per_cpu = 1;
|
||||
tests += cpus * fpsimd_per_cpu;
|
||||
tests += cpus * 2;
|
||||
|
||||
ksft_print_header();
|
||||
ksft_set_plan(tests);
|
||||
|
|
@ -542,8 +550,8 @@ int main(int argc, char **argv)
|
|||
tests);
|
||||
|
||||
for (i = 0; i < cpus; i++) {
|
||||
for (j = 0; j < fpsimd_per_cpu; j++)
|
||||
start_fpsimd(&children[num_children++], i, j);
|
||||
start_fpsimd(&children[num_children++], i, 0);
|
||||
start_kernel(&children[num_children++], i, 0);
|
||||
|
||||
for (j = 0; j < sve_vl_count; j++)
|
||||
start_sve(&children[num_children++], sve_vls[j], i);
|
||||
|
|
|
|||
324
tools/testing/selftests/arm64/fp/kernel-test.c
Normal file
324
tools/testing/selftests/arm64/fp/kernel-test.c
Normal file
|
|
@ -0,0 +1,324 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Copyright (C) 2024 ARM Limited.
|
||||
*/
|
||||
|
||||
#define _GNU_SOURCE
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <signal.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <sys/socket.h>
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/if_alg.h>
|
||||
|
||||
#define DATA_SIZE (16 * 4096)
|
||||
|
||||
static int base, sock;
|
||||
|
||||
static int digest_len;
|
||||
static char *ref;
|
||||
static char *digest;
|
||||
static char *alg_name;
|
||||
|
||||
static struct iovec data_iov;
|
||||
static int zerocopy[2];
|
||||
static int sigs;
|
||||
static int iter;
|
||||
|
||||
static void handle_exit_signal(int sig, siginfo_t *info, void *context)
|
||||
{
|
||||
printf("Terminated by signal %d, iterations=%d, signals=%d\n",
|
||||
sig, iter, sigs);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
static void handle_kick_signal(int sig, siginfo_t *info, void *context)
|
||||
{
|
||||
sigs++;
|
||||
}
|
||||
|
||||
static char *drivers[] = {
|
||||
"crct10dif-arm64-ce",
|
||||
/* "crct10dif-arm64-neon", - Same priority as generic */
|
||||
"sha1-ce",
|
||||
"sha224-arm64",
|
||||
"sha224-arm64-neon",
|
||||
"sha224-ce",
|
||||
"sha256-arm64",
|
||||
"sha256-arm64-neon",
|
||||
"sha256-ce",
|
||||
"sha384-ce",
|
||||
"sha512-ce",
|
||||
"sha3-224-ce",
|
||||
"sha3-256-ce",
|
||||
"sha3-384-ce",
|
||||
"sha3-512-ce",
|
||||
"sm3-ce",
|
||||
"sm3-neon",
|
||||
};
|
||||
|
||||
static bool create_socket(void)
|
||||
{
|
||||
FILE *proc;
|
||||
struct sockaddr_alg addr;
|
||||
char buf[1024];
|
||||
char *c, *driver_name;
|
||||
bool is_shash, match;
|
||||
int ret, i;
|
||||
|
||||
ret = socket(AF_ALG, SOCK_SEQPACKET, 0);
|
||||
if (ret < 0) {
|
||||
if (errno == EAFNOSUPPORT) {
|
||||
printf("AF_ALG not supported\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
printf("Failed to create AF_ALG socket: %s (%d)\n",
|
||||
strerror(errno), errno);
|
||||
return false;
|
||||
}
|
||||
base = ret;
|
||||
|
||||
memset(&addr, 0, sizeof(addr));
|
||||
addr.salg_family = AF_ALG;
|
||||
strncpy((char *)addr.salg_type, "hash", sizeof(addr.salg_type));
|
||||
|
||||
proc = fopen("/proc/crypto", "r");
|
||||
if (!proc) {
|
||||
printf("Unable to open /proc/crypto\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
driver_name = NULL;
|
||||
is_shash = false;
|
||||
match = false;
|
||||
|
||||
/* Look through /proc/crypto for a driver with kernel mode FP usage */
|
||||
while (!match) {
|
||||
c = fgets(buf, sizeof(buf), proc);
|
||||
if (!c) {
|
||||
if (feof(proc)) {
|
||||
printf("Nothing found in /proc/crypto\n");
|
||||
return false;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Algorithm descriptions are separated by a blank line */
|
||||
if (*c == '\n') {
|
||||
if (is_shash && driver_name) {
|
||||
for (i = 0; i < ARRAY_SIZE(drivers); i++) {
|
||||
if (strcmp(drivers[i],
|
||||
driver_name) == 0) {
|
||||
match = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!match) {
|
||||
digest_len = 0;
|
||||
|
||||
free(driver_name);
|
||||
driver_name = NULL;
|
||||
|
||||
free(alg_name);
|
||||
alg_name = NULL;
|
||||
|
||||
is_shash = false;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Remove trailing newline */
|
||||
c = strchr(buf, '\n');
|
||||
if (c)
|
||||
*c = '\0';
|
||||
|
||||
/* Find the field/value separator and start of the value */
|
||||
c = strchr(buf, ':');
|
||||
if (!c)
|
||||
continue;
|
||||
c += 2;
|
||||
|
||||
if (strncmp(buf, "digestsize", strlen("digestsize")) == 0)
|
||||
sscanf(c, "%d", &digest_len);
|
||||
|
||||
if (strncmp(buf, "name", strlen("name")) == 0)
|
||||
alg_name = strdup(c);
|
||||
|
||||
if (strncmp(buf, "driver", strlen("driver")) == 0)
|
||||
driver_name = strdup(c);
|
||||
|
||||
if (strncmp(buf, "type", strlen("type")) == 0)
|
||||
if (strncmp(c, "shash", strlen("shash")) == 0)
|
||||
is_shash = true;
|
||||
}
|
||||
|
||||
strncpy((char *)addr.salg_name, alg_name,
|
||||
sizeof(addr.salg_name) - 1);
|
||||
|
||||
ret = bind(base, (struct sockaddr *)&addr, sizeof(addr));
|
||||
if (ret < 0) {
|
||||
printf("Failed to bind %s: %s (%d)\n",
|
||||
addr.salg_name, strerror(errno), errno);
|
||||
return false;
|
||||
}
|
||||
|
||||
ret = accept(base, NULL, 0);
|
||||
if (ret < 0) {
|
||||
printf("Failed to accept %s: %s (%d)\n",
|
||||
addr.salg_name, strerror(errno), errno);
|
||||
return false;
|
||||
}
|
||||
|
||||
sock = ret;
|
||||
|
||||
ret = pipe(zerocopy);
|
||||
if (ret != 0) {
|
||||
printf("Failed to create zerocopy pipe: %s (%d)\n",
|
||||
strerror(errno), errno);
|
||||
return false;
|
||||
}
|
||||
|
||||
ref = malloc(digest_len);
|
||||
if (!ref) {
|
||||
printf("Failed to allocated %d byte reference\n", digest_len);
|
||||
return false;
|
||||
}
|
||||
|
||||
digest = malloc(digest_len);
|
||||
if (!digest) {
|
||||
printf("Failed to allocated %d byte digest\n", digest_len);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool compute_digest(void *buf)
|
||||
{
|
||||
struct iovec iov;
|
||||
int ret, wrote;
|
||||
|
||||
iov = data_iov;
|
||||
while (iov.iov_len) {
|
||||
ret = vmsplice(zerocopy[1], &iov, 1, SPLICE_F_GIFT);
|
||||
if (ret < 0) {
|
||||
printf("Failed to send buffer: %s (%d)\n",
|
||||
strerror(errno), errno);
|
||||
return false;
|
||||
}
|
||||
|
||||
wrote = ret;
|
||||
ret = splice(zerocopy[0], NULL, sock, NULL, wrote, 0);
|
||||
if (ret < 0) {
|
||||
printf("Failed to splice buffer: %s (%d)\n",
|
||||
strerror(errno), errno);
|
||||
} else if (ret != wrote) {
|
||||
printf("Short splice: %d < %d\n", ret, wrote);
|
||||
}
|
||||
|
||||
iov.iov_len -= wrote;
|
||||
iov.iov_base += wrote;
|
||||
}
|
||||
|
||||
reread:
|
||||
ret = recv(sock, buf, digest_len, 0);
|
||||
if (ret == 0) {
|
||||
printf("No digest returned\n");
|
||||
return false;
|
||||
}
|
||||
if (ret != digest_len) {
|
||||
if (errno == -EAGAIN)
|
||||
goto reread;
|
||||
printf("Failed to get digest: %s (%d)\n",
|
||||
strerror(errno), errno);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
char *data;
|
||||
struct sigaction sa;
|
||||
int ret;
|
||||
|
||||
/* Ensure we have unbuffered output */
|
||||
setvbuf(stdout, NULL, _IOLBF, 0);
|
||||
|
||||
/* The parent will communicate with us via signals */
|
||||
memset(&sa, 0, sizeof(sa));
|
||||
sa.sa_sigaction = handle_exit_signal;
|
||||
sa.sa_flags = SA_RESTART | SA_SIGINFO;
|
||||
sigemptyset(&sa.sa_mask);
|
||||
ret = sigaction(SIGTERM, &sa, NULL);
|
||||
if (ret < 0)
|
||||
printf("Failed to install SIGTERM handler: %s (%d)\n",
|
||||
strerror(errno), errno);
|
||||
|
||||
sa.sa_sigaction = handle_kick_signal;
|
||||
ret = sigaction(SIGUSR2, &sa, NULL);
|
||||
if (ret < 0)
|
||||
printf("Failed to install SIGUSR2 handler: %s (%d)\n",
|
||||
strerror(errno), errno);
|
||||
|
||||
data = malloc(DATA_SIZE);
|
||||
if (!data) {
|
||||
printf("Failed to allocate data buffer\n");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
memset(data, 0, DATA_SIZE);
|
||||
|
||||
data_iov.iov_base = data;
|
||||
data_iov.iov_len = DATA_SIZE;
|
||||
|
||||
/*
|
||||
* If we can't create a socket assume it's a lack of system
|
||||
* support and fall back to a basic FPSIMD test for the
|
||||
* benefit of fp-stress.
|
||||
*/
|
||||
if (!create_socket()) {
|
||||
execl("./fpsimd-test", "./fpsimd-test", NULL);
|
||||
printf("Failed to fall back to fspimd-test: %d (%s)\n",
|
||||
errno, strerror(errno));
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Compute a reference digest we hope is repeatable, we do
|
||||
* this at runtime partly to make it easier to play with
|
||||
* parameters.
|
||||
*/
|
||||
if (!compute_digest(ref)) {
|
||||
printf("Failed to compute reference digest\n");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
printf("AF_ALG using %s\n", alg_name);
|
||||
|
||||
while (true) {
|
||||
if (!compute_digest(digest)) {
|
||||
printf("Failed to compute digest, iter=%d\n", iter);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
if (memcmp(ref, digest, digest_len) != 0) {
|
||||
printf("Digest mismatch, iter=%d\n", iter);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
iter++;
|
||||
}
|
||||
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
|
@ -2,6 +2,5 @@
|
|||
|
||||
CFLAGS += $(KHDR_INCLUDES)
|
||||
TEST_GEN_PROGS := tags_test
|
||||
TEST_PROGS := run_tags_test.sh
|
||||
|
||||
include ../../lib.mk
|
||||
|
|
|
|||
|
|
@ -1,12 +0,0 @@
|
|||
#!/bin/sh
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
echo "--------------------"
|
||||
echo "running tags test"
|
||||
echo "--------------------"
|
||||
./tags_test
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "[FAIL]"
|
||||
else
|
||||
echo "[PASS]"
|
||||
fi
|
||||
|
|
@ -17,19 +17,21 @@ int main(void)
|
|||
static int tbi_enabled = 0;
|
||||
unsigned long tag = 0;
|
||||
struct utsname *ptr;
|
||||
int err;
|
||||
|
||||
ksft_print_header();
|
||||
ksft_set_plan(1);
|
||||
|
||||
if (prctl(PR_SET_TAGGED_ADDR_CTRL, PR_TAGGED_ADDR_ENABLE, 0, 0, 0) == 0)
|
||||
tbi_enabled = 1;
|
||||
ptr = (struct utsname *)malloc(sizeof(*ptr));
|
||||
if (!ptr)
|
||||
ksft_exit_fail_msg("Failed to allocate utsname buffer\n");
|
||||
ksft_exit_fail_perror("Failed to allocate utsname buffer");
|
||||
|
||||
if (tbi_enabled)
|
||||
tag = 0x42;
|
||||
ptr = (struct utsname *)SET_TAG(ptr, tag);
|
||||
err = uname(ptr);
|
||||
ksft_test_result(!uname(ptr), "Syscall successful with tagged address\n");
|
||||
free(ptr);
|
||||
|
||||
return err;
|
||||
ksft_finished();
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user