xref: /linux/arch/arm64/kernel/mpam.c (revision 0fc8f6200d2313278fbf4539bbab74677c685531)
18e06d04fSJames Morse // SPDX-License-Identifier: GPL-2.0
28e06d04fSJames Morse /* Copyright (C) 2025 Arm Ltd. */
38e06d04fSJames Morse 
48e06d04fSJames Morse #include <asm/mpam.h>
58e06d04fSJames Morse 
6831a7f16SJames Morse #include <linux/arm_mpam.h>
7735dad99SJames Morse #include <linux/cpu_pm.h>
88e06d04fSJames Morse #include <linux/jump_label.h>
98e06d04fSJames Morse #include <linux/percpu.h>
108e06d04fSJames Morse 
118e06d04fSJames Morse DEFINE_STATIC_KEY_FALSE(mpam_enabled);
128e06d04fSJames Morse DEFINE_PER_CPU(u64, arm64_mpam_default);
138e06d04fSJames Morse DEFINE_PER_CPU(u64, arm64_mpam_current);
148e06d04fSJames Morse 
158e06d04fSJames Morse u64 arm64_mpam_global_default;
16831a7f16SJames Morse 
17735dad99SJames Morse static int mpam_pm_notifier(struct notifier_block *self,
18735dad99SJames Morse 			    unsigned long cmd, void *v)
19735dad99SJames Morse {
20735dad99SJames Morse 	u64 regval;
21735dad99SJames Morse 	int cpu = smp_processor_id();
22735dad99SJames Morse 
23735dad99SJames Morse 	switch (cmd) {
24735dad99SJames Morse 	case CPU_PM_EXIT:
25735dad99SJames Morse 		/*
26735dad99SJames Morse 		 * Don't use mpam_thread_switch() as the system register
27735dad99SJames Morse 		 * value has changed under our feet.
28735dad99SJames Morse 		 */
29735dad99SJames Morse 		regval = READ_ONCE(per_cpu(arm64_mpam_current, cpu));
30735dad99SJames Morse 		write_sysreg_s(regval | MPAM1_EL1_MPAMEN, SYS_MPAM1_EL1);
31*37fe0f98SBen Horgan 		if (system_supports_sme()) {
32*37fe0f98SBen Horgan 			write_sysreg_s(regval & (MPAMSM_EL1_PARTID_D | MPAMSM_EL1_PMG_D),
33*37fe0f98SBen Horgan 				       SYS_MPAMSM_EL1);
34*37fe0f98SBen Horgan 		}
35735dad99SJames Morse 		isb();
36735dad99SJames Morse 
37735dad99SJames Morse 		write_sysreg_s(regval, SYS_MPAM0_EL1);
38735dad99SJames Morse 
39735dad99SJames Morse 		return NOTIFY_OK;
40735dad99SJames Morse 	default:
41735dad99SJames Morse 		return NOTIFY_DONE;
42735dad99SJames Morse 	}
43735dad99SJames Morse }
44735dad99SJames Morse 
45735dad99SJames Morse static struct notifier_block mpam_pm_nb = {
46735dad99SJames Morse 	.notifier_call = mpam_pm_notifier,
47735dad99SJames Morse };
48735dad99SJames Morse 
49831a7f16SJames Morse static int __init arm64_mpam_register_cpus(void)
50831a7f16SJames Morse {
51831a7f16SJames Morse 	u64 mpamidr = read_sanitised_ftr_reg(SYS_MPAMIDR_EL1);
52831a7f16SJames Morse 	u16 partid_max = FIELD_GET(MPAMIDR_EL1_PARTID_MAX, mpamidr);
53831a7f16SJames Morse 	u8 pmg_max = FIELD_GET(MPAMIDR_EL1_PMG_MAX, mpamidr);
54831a7f16SJames Morse 
55735dad99SJames Morse 	if (!system_supports_mpam())
56735dad99SJames Morse 		return 0;
57735dad99SJames Morse 
58735dad99SJames Morse 	cpu_pm_register_notifier(&mpam_pm_nb);
59831a7f16SJames Morse 	return mpam_register_requestor(partid_max, pmg_max);
60831a7f16SJames Morse }
61831a7f16SJames Morse /* Must occur before mpam_msc_driver_init() from subsys_initcall() */
62831a7f16SJames Morse arch_initcall(arm64_mpam_register_cpus)
63