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