mirror of
https://github.com/torvalds/linux.git
synced 2026-04-18 06:44:00 -04:00
The MPAMSM_EL1 sets the MPAM labels, PMG and PARTID, for loads and stores generated by a shared SMCU. Disable the traps so the kernel can use it and set it to the same configuration as the per-EL cpu MPAM configuration. If an SMCU is not shared with other cpus then it is implementation defined whether the configuration from MPAMSM_EL1 is used or that from the appropriate MPAMy_ELx. As we set the same, PMG_D and PARTID_D, configuration for MPAM0_EL1, MPAM1_EL1 and MPAMSM_EL1 the resulting configuration is the same regardless. The range of valid configurations for the PARTID and PMG in MPAMSM_EL1 is not currently specified in Arm Architectural Reference Manual but the architect has confirmed that it is intended to be the same as that for the cpu configuration in the MPAMy_ELx registers. Tested-by: Gavin Shan <gshan@redhat.com> Tested-by: Shaopeng Tan <tan.shaopeng@jp.fujitsu.com> Tested-by: Peter Newman <peternewman@google.com> Tested-by: Zeng Heng <zengheng4@huawei.com> Tested-by: Punit Agrawal <punit.agrawal@oss.qualcomm.com> Tested-by: Jesse Chick <jessechick@os.amperecomputing.com> Reviewed-by: Zeng Heng <zengheng4@huawei.com> Reviewed-by: Shaopeng Tan <tan.shaopeng@jp.fujitsu.com> Reviewed-by: Jonathan Cameron <jonathan.cameron@huawei.com> Reviewed-by: Gavin Shan <gshan@redhat.com> Reviewed-by: Catalin Marinas <catalin.marinas@arm.com> Reviewed-by: James Morse <james.morse@arm.com> Signed-off-by: Ben Horgan <ben.horgan@arm.com> Signed-off-by: James Morse <james.morse@arm.com>
63 lines
1.5 KiB
C
63 lines
1.5 KiB
C
// SPDX-License-Identifier: GPL-2.0
|
|
/* Copyright (C) 2025 Arm Ltd. */
|
|
|
|
#include <asm/mpam.h>
|
|
|
|
#include <linux/arm_mpam.h>
|
|
#include <linux/cpu_pm.h>
|
|
#include <linux/jump_label.h>
|
|
#include <linux/percpu.h>
|
|
|
|
DEFINE_STATIC_KEY_FALSE(mpam_enabled);
|
|
DEFINE_PER_CPU(u64, arm64_mpam_default);
|
|
DEFINE_PER_CPU(u64, arm64_mpam_current);
|
|
|
|
u64 arm64_mpam_global_default;
|
|
|
|
static int mpam_pm_notifier(struct notifier_block *self,
|
|
unsigned long cmd, void *v)
|
|
{
|
|
u64 regval;
|
|
int cpu = smp_processor_id();
|
|
|
|
switch (cmd) {
|
|
case CPU_PM_EXIT:
|
|
/*
|
|
* Don't use mpam_thread_switch() as the system register
|
|
* value has changed under our feet.
|
|
*/
|
|
regval = READ_ONCE(per_cpu(arm64_mpam_current, cpu));
|
|
write_sysreg_s(regval | MPAM1_EL1_MPAMEN, SYS_MPAM1_EL1);
|
|
if (system_supports_sme()) {
|
|
write_sysreg_s(regval & (MPAMSM_EL1_PARTID_D | MPAMSM_EL1_PMG_D),
|
|
SYS_MPAMSM_EL1);
|
|
}
|
|
isb();
|
|
|
|
write_sysreg_s(regval, SYS_MPAM0_EL1);
|
|
|
|
return NOTIFY_OK;
|
|
default:
|
|
return NOTIFY_DONE;
|
|
}
|
|
}
|
|
|
|
static struct notifier_block mpam_pm_nb = {
|
|
.notifier_call = mpam_pm_notifier,
|
|
};
|
|
|
|
static int __init arm64_mpam_register_cpus(void)
|
|
{
|
|
u64 mpamidr = read_sanitised_ftr_reg(SYS_MPAMIDR_EL1);
|
|
u16 partid_max = FIELD_GET(MPAMIDR_EL1_PARTID_MAX, mpamidr);
|
|
u8 pmg_max = FIELD_GET(MPAMIDR_EL1_PMG_MAX, mpamidr);
|
|
|
|
if (!system_supports_mpam())
|
|
return 0;
|
|
|
|
cpu_pm_register_notifier(&mpam_pm_nb);
|
|
return mpam_register_requestor(partid_max, pmg_max);
|
|
}
|
|
/* Must occur before mpam_msc_driver_init() from subsys_initcall() */
|
|
arch_initcall(arm64_mpam_register_cpus)
|