arm64 fixes for -rc5

- Fix the recently merged user ABI for the Arm CMN PMU driver filtering
   logic so that the ordering matches the hardware spec
 
 - Fix spurious warning when attempting to read PROT_NONE mappings of
   /dev/mem
 
 - Allow WFxT to be disabled on the command line, which is necessary for
   some configurations of recent Apple SoCs
 
 - Fix EL2 fine-grained trap configuration for the CPU PMU
 
 - Fix MIDR matching when applying CPU errata workarounds in a VM
 -----BEGIN PGP SIGNATURE-----
 
 iQFEBAABCgAuFiEEPxTL6PPUbjXGY88ct6xw3ITBYzQFAmq06TIQHHdpbGxAa2Vy
 bmVsLm9yZwAKCRC3rHDchMFjNPGQCACK7VeQk7ER46znaeMNyHaQARWkuF7D3wdU
 wCvt/hppo6DzHpsiWw5rDrBIHyeVpWkilDVROuaM1q8Qf6HaFe2h+sbuK96OVo1Y
 OLP1aZUBj3ZGLUNBIxDANP4A200Avd6gFLLY2jPvZ2YyJfEB9Ok3D0KahaRdtMh9
 PGX4qo3j7dZaTLChMrVhXApAidkZ079w5+Di5wXilU5QNyCWsfA+SKBY7jZWP7jw
 yPQ5PPDeYDYUziCUT4ooAegY9vODgmtbikXPFQQzF0zPeTtqKuFwSekdXnkJQS3E
 R3+bBmV5JrDuitjMqUvrxreTGZqWj6R1mHL4tsActCnhTFEc2mar
 =dNHO
 -----END PGP SIGNATURE-----

Merge tag 'arm64-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/arm64/linux

Pull arm64 fixes from Will Deacon:

 - Fix the recently merged user ABI for the Arm CMN PMU driver filtering
   logic so that the ordering matches the hardware spec

 - Fix spurious warning when attempting to read PROT_NONE mappings of
  /dev/mem

 - Allow WFxT to be disabled on the command line, which is necessary for
   some configurations of recent Apple SoCs

 - Fix EL2 fine-grained trap configuration for the CPU PMU

 - Fix MIDR matching when applying CPU errata workarounds in a VM

* tag 'arm64-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/arm64/linux:
  arm64/boot: Disable trapping of PMZR_EL0 writes to EL2
  arm64: errata: match the target implementation CPU's own MIDR
  arm64: Add override for WFxT
  arm64: io: Reject non-user protection in ioremap_prot()
  perf/arm-cmn: Fix multi-filter encoding
This commit is contained in:
Linus Torvalds 2026-09-24 06:08:15 -07:00
commit ef33dd4e0a
7 changed files with 59 additions and 32 deletions

View File

@ -589,6 +589,9 @@ Kernel parameters
arm64.nosve [ARM64] Unconditionally disable Scalable Vector
Extension support
arm64.nowfxt [ARM64] Unconditionally disable Wait For Event with
Timeout and Wait For Interrupt with Timeout support
ataflop= [HW,M68k]
atarimouse= [HW,MOUSE] Atari Mouse

View File

@ -465,6 +465,7 @@ Before jumping into the kernel, the following conditions must be met:
- HDFGWTR2_EL2.nPMICNTR_EL0 (bit 2) must be initialised to 0b1.
- HDFGWTR2_EL2.nPMICFILTR_EL0 (bit 3) must be initialised to 0b1.
- HDFGWTR2_EL2.nPMUACR_EL1 (bit 4) must be initialised to 0b1.
- HDFGWTR2_EL2.nPMZR_EL0 (bit 21) must be initialised to 0b1.
For CPUs with SPE data source filtering (FEAT_SPE_FDS):

View File

@ -418,6 +418,7 @@
b.lt .Lskip_fgt2_\@
mov x0, xzr
mov x2, xzr
mrs x1, id_aa64dfr0_el1
ubfx x1, x1, #ID_AA64DFR0_EL1_PMUVer_SHIFT, #4
cmp x1, #ID_AA64DFR0_EL1_PMUVer_V3P9
@ -426,6 +427,11 @@
orr x0, x0, #HDFGRTR2_EL2_nPMICNTR_EL0
orr x0, x0, #HDFGRTR2_EL2_nPMICFILTR_EL0
orr x0, x0, #HDFGRTR2_EL2_nPMUACR_EL1
orr x2, x2, #HDFGWTR2_EL2_nPMICNTR_EL0
orr x2, x2, #HDFGWTR2_EL2_nPMICFILTR_EL0
orr x2, x2, #HDFGWTR2_EL2_nPMUACR_EL1
/* PMZR_EL0 is write-only, so it has no read trap to disable */
orr x2, x2, #HDFGWTR2_EL2_nPMZR_EL0
.Lskip_pmuv3p9_\@:
/* If SPE is implemented, */
__spe_vers_imp .Lskip_spefds_\@, ID_AA64DFR0_EL1_PMSVer_IMP, x1
@ -436,10 +442,11 @@
cbz x1, .Lskip_spefds_\@
/* disable traps of PMSDSFR to EL2. */
orr x0, x0, #HDFGRTR2_EL2_nPMSDSFR_EL1
orr x2, x2, #HDFGWTR2_EL2_nPMSDSFR_EL1
.Lskip_spefds_\@:
msr_s SYS_HDFGRTR2_EL2, x0
msr_s SYS_HDFGWTR2_EL2, x0
msr_s SYS_HDFGWTR2_EL2, x2
msr_s SYS_HFGRTR2_EL2, xzr
msr_s SYS_HFGWTR2_EL2, xzr
msr_s SYS_HFGITR2_EL2, xzr

View File

@ -280,7 +280,8 @@ static inline void __iomem *ioremap_prot(phys_addr_t phys, size_t size,
pgprot_t prot;
ptval_t user_prot_val = pgprot_val(user_prot);
if (WARN_ON_ONCE(!(user_prot_val & PTE_USER)))
/* Reject PROT_NONE and exec-only */
if (!(user_prot_val & PTE_USER))
return NULL;
prot = __pgprot_modify(PAGE_KERNEL, PTE_ATTRINDX_MASK,

View File

@ -28,18 +28,21 @@ bool cpu_errata_set_target_impl(u64 num, void *impl_cpus)
return true;
}
static inline bool __is_midr_in_range(u32 midr, struct midr_range const *range)
{
return midr_is_cpu_model_range(midr, range->model,
range->rv_min, range->rv_max);
}
static inline bool is_midr_in_range(struct midr_range const *range)
{
int i;
if (!target_impl_cpu_num)
return midr_is_cpu_model_range(read_cpuid_id(), range->model,
range->rv_min, range->rv_max);
return __is_midr_in_range(read_cpuid_id(), range);
for (i = 0; i < target_impl_cpu_num; i++) {
if (midr_is_cpu_model_range(target_impl_cpus[i].midr,
range->model,
range->rv_min, range->rv_max))
if (__is_midr_in_range(target_impl_cpus[i].midr, range))
return true;
}
return false;
@ -59,7 +62,7 @@ __is_affected_midr_range(const struct arm64_cpu_capabilities *entry,
u32 midr, u32 revidr)
{
const struct arm64_midr_revidr *fix;
if (!is_midr_in_range(&entry->midr_range))
if (!__is_midr_in_range(midr, &entry->midr_range))
return false;
midr &= MIDR_REVISION_MASK | MIDR_VARIANT_MASK;

View File

@ -186,6 +186,7 @@ static const struct ftr_set_desc isar2 __prel64_initconst = {
.name = "id_aa64isar2",
.override = &id_aa64isar2_override,
.fields = {
FIELD("wfxt", ID_AA64ISAR2_EL1_WFxT_SHIFT, NULL),
FIELD("gpa3", ID_AA64ISAR2_EL1_GPA3_SHIFT, NULL),
FIELD("apa3", ID_AA64ISAR2_EL1_APA3_SHIFT, NULL),
FIELD("mops", ID_AA64ISAR2_EL1_MOPS_SHIFT, NULL),
@ -254,6 +255,7 @@ static const struct {
"id_aa64isar1.api=0 id_aa64isar1.apa=0 "
"id_aa64isar2.gpa3=0 id_aa64isar2.apa3=0" },
{ "arm64.nomops", "id_aa64isar2.mops=0" },
{ "arm64.nowfxt", "id_aa64isar2.wfxt=0" },
{ "arm64.nomte", "id_aa64pfr1.mte=0" },
{ "nokaslr", "arm64_sw.nokaslr=1" },
{ "rodata=off", "arm64_sw.rodataoff=1" },

View File

@ -305,9 +305,9 @@ enum cmn_filter_select {
SEL_NONE,
SEL_OCCUP1_ID,
SEL_CLASS_OCCUP_ID,
SEL_CBUSY_SNTHROTTLE_SEL,
SEL_HBT_LBT_SEL,
SEL_SN_HOME_SEL,
SEL_CBUSY_SNTHROTTLE_SEL,
SEL_SNP_VC_SEL,
SEL_ENHANCED_HBT_LBT_SEL,
SEL_EVICT_STATE_SEL,
@ -978,10 +978,14 @@ static umode_t arm_cmn_event_attr_is_visible(struct kobject *kobj,
_CMN_EVENT_HNS(_model, _name##_all, _event, _sel, 0), \
_CMN_EVENT_HNS(_model, _name##_hbt, _event, _sel, 1), \
_CMN_EVENT_HNS(_model, _name##_lbt, _event, _sel, 2)
#define _CMN_EVENT_HNS_HBT2(_model, _name, _event, _fsel1, f1) \
_CMN_EVENT_HNS(_model, _name##_all, _event, _fsel1, f1, SEL_HBT_LBT_SEL, 0), \
_CMN_EVENT_HNS(_model, _name##_hbt, _event, _fsel1, f1, SEL_HBT_LBT_SEL, 1), \
_CMN_EVENT_HNS(_model, _name##_lbt, _event, _fsel1, f1, SEL_HBT_LBT_SEL, 2)
#define _CMN_EVENT_HNS_EVICT(_model, _name, _event, _fsel1, f1) \
_CMN_EVENT_HNS(_model, _name##_all, _event, _fsel1, f1, SEL_EVICT_STATE_SEL, 0), \
_CMN_EVENT_HNS(_model, _name##_eu, _event, _fsel1, f1, SEL_EVICT_STATE_SEL, 1), \
_CMN_EVENT_HNS(_model, _name##_en, _event, _fsel1, f1, SEL_EVICT_STATE_SEL, 2), \
_CMN_EVENT_HNS(_model, _name##_su, _event, _fsel1, f1, SEL_EVICT_STATE_SEL, 3), \
_CMN_EVENT_HNS(_model, _name##_sn, _event, _fsel1, f1, SEL_EVICT_STATE_SEL, 4), \
_CMN_EVENT_HNS(_model, _name##_mu, _event, _fsel1, f1, SEL_EVICT_STATE_SEL, 5), \
_CMN_EVENT_HNS(_model, _name##_mn, _event, _fsel1, f1, SEL_EVICT_STATE_SEL, 6)
#define CMN_EVENT_HNS_OCC(_model, _name, _event) \
CMN_EVENT_HN_OCC(_model, hns_##_name, CMN_TYPE_HNS, _event), \
@ -1014,13 +1018,9 @@ static umode_t arm_cmn_event_attr_is_visible(struct kobject *kobj,
_CMN_EVENT_HNS(CMNS3R2, _name##_ccglcn, _event, SEL_ENHANCED_HBT_LBT_SEL, 5), \
_CMN_EVENT_HNS(CMNS3R2, _name##_ccgrn, _event, SEL_ENHANCED_HBT_LBT_SEL, 6)
#define CMN_EVENT_HNS_EVICT(_model, _name, _event) \
_CMN_EVENT_HNS_HBT2(_model, _name##_all, _event, SEL_EVICT_STATE_SEL, 0), \
_CMN_EVENT_HNS_HBT2(_model, _name##_eu, _event, SEL_EVICT_STATE_SEL, 1), \
_CMN_EVENT_HNS_HBT2(_model, _name##_en, _event, SEL_EVICT_STATE_SEL, 2), \
_CMN_EVENT_HNS_HBT2(_model, _name##_su, _event, SEL_EVICT_STATE_SEL, 3), \
_CMN_EVENT_HNS_HBT2(_model, _name##_sn, _event, SEL_EVICT_STATE_SEL, 4), \
_CMN_EVENT_HNS_HBT2(_model, _name##_mu, _event, SEL_EVICT_STATE_SEL, 5), \
_CMN_EVENT_HNS_HBT2(_model, _name##_mn, _event, SEL_EVICT_STATE_SEL, 6)
_CMN_EVENT_HNS_EVICT(_model, _name##_all, _event, SEL_HBT_LBT_SEL, 0), \
_CMN_EVENT_HNS_EVICT(_model, _name##_hbt, _event, SEL_HBT_LBT_SEL, 1), \
_CMN_EVENT_HNS_EVICT(_model, _name##_lbt, _event, SEL_HBT_LBT_SEL, 2)
#define CMN_EVENT_HNSR0_HBT(_name, _event) \
_CMN_EVENT_HNS_HBT(CMN700 | CMNS3R01, _name, _event, SEL_HBT_LBT_SEL)
@ -1860,10 +1860,12 @@ static void arm_cmn_val_add_event(struct arm_cmn *cmn, struct arm_cmn_val *val,
val->dtm_count[dtm]++;
if (sel == SEL_EVICT_STATE_SEL) {
val->filter[dtm][sel] = CMN_EVENT_FILTER2(event) + 1;
sel = SEL_HBT_LBT_SEL;
}
if (sel)
val->filter[dtm][sel] = CMN_EVENT_FILTER(event) + 1;
if (sel == SEL_EVICT_STATE_SEL)
val->filter[dtm][SEL_HBT_LBT_SEL] = CMN_EVENT_FILTER2(event) + 1;
if (type != CMN_TYPE_WP)
continue;
@ -1914,14 +1916,17 @@ static int arm_cmn_validate_group(struct arm_cmn *cmn, struct perf_event *event)
if (val->dtm_count[dtm] == CMN_DTM_NUM_COUNTERS)
goto done;
if (sel == SEL_EVICT_STATE_SEL) {
if (val->filter[dtm][sel] &&
val->filter[dtm][sel] != CMN_EVENT_FILTER2(event) + 1)
goto done;
sel = SEL_HBT_LBT_SEL;
}
if (sel && val->filter[dtm][sel] &&
val->filter[dtm][sel] != CMN_EVENT_FILTER(event) + 1)
goto done;
if (sel == SEL_EVICT_STATE_SEL && val->filter[dtm][SEL_HBT_LBT_SEL] &&
val->filter[dtm][SEL_HBT_LBT_SEL] != CMN_EVENT_FILTER2(event) + 1)
goto done;
if (type != CMN_TYPE_WP)
continue;
@ -1950,7 +1955,7 @@ static enum cmn_filter_select arm_cmn_event_filter(const struct arm_cmn *cmn,
for (int i = 0; i < ARRAY_SIZE(arm_cmn_event_attrs) - 1; i++) {
e = container_of(arm_cmn_event_attrs[i], typeof(*e), attr.attr);
if (e->model & model && e->type == type && e->eventid == eventid)
return e->filter[0].sel;
return e->filter[1].sel ?: e->filter[0].sel;
}
return SEL_NONE;
}
@ -2081,16 +2086,21 @@ static void arm_cmn_event_clear(struct arm_cmn *cmn, struct perf_event *event,
static int arm_cmn_set_event_filter(struct arm_cmn_node *dn, struct perf_event *event)
{
enum cmn_filter_select fsel = to_cmn_hw(event)->filter_sel;
bool evict_state = fsel == SEL_EVICT_STATE_SEL;
int ret = 0;
if (evict_state) {
ret = arm_cmn_set_event_sel_hi(dn, fsel, CMN_EVENT_FILTER2(event));
if (ret)
return ret;
fsel = SEL_HBT_LBT_SEL;
}
if (fsel)
ret = arm_cmn_set_event_sel_hi(dn, fsel, CMN_EVENT_FILTER(event));
if (fsel == SEL_EVICT_STATE_SEL && !ret) {
ret = arm_cmn_set_event_sel_hi(dn, SEL_HBT_LBT_SEL, CMN_EVENT_FILTER2(event));
if (ret)
dn->filter[fsel].count--;
}
if (ret && evict_state)
dn->filter[SEL_EVICT_STATE_SEL].count--;
return ret;
}