Merge pull request #1533 from jeenu-arm/mpam

AArch64: Enable MPAM for lower ELs
diff --git a/Makefile b/Makefile
index 18c4873..cb7eb08 100644
--- a/Makefile
+++ b/Makefile
@@ -550,6 +550,7 @@
 $(eval $(call assert_boolean,EL3_EXCEPTION_HANDLING))
 $(eval $(call assert_boolean,ENABLE_AMU))
 $(eval $(call assert_boolean,ENABLE_ASSERTIONS))
+$(eval $(call assert_boolean,ENABLE_MPAM_FOR_LOWER_ELS))
 $(eval $(call assert_boolean,ENABLE_PLAT_COMPAT))
 $(eval $(call assert_boolean,ENABLE_PMF))
 $(eval $(call assert_boolean,ENABLE_PSCI_STAT))
@@ -601,6 +602,7 @@
 $(eval $(call add_define,EL3_EXCEPTION_HANDLING))
 $(eval $(call add_define,ENABLE_AMU))
 $(eval $(call add_define,ENABLE_ASSERTIONS))
+$(eval $(call add_define,ENABLE_MPAM_FOR_LOWER_ELS))
 $(eval $(call add_define,ENABLE_PLAT_COMPAT))
 $(eval $(call add_define,ENABLE_PMF))
 $(eval $(call add_define,ENABLE_PSCI_STAT))
diff --git a/bl31/bl31.mk b/bl31/bl31.mk
index 066c701..7777954 100644
--- a/bl31/bl31.mk
+++ b/bl31/bl31.mk
@@ -64,6 +64,10 @@
 BL31_SOURCES		+=	lib/extensions/sve/sve.c
 endif
 
+ifeq (${ENABLE_MPAM_FOR_LOWER_ELS},1)
+BL31_SOURCES		+=	lib/extensions/mpam/mpam.c
+endif
+
 ifeq (${WORKAROUND_CVE_2017_5715},1)
 BL31_SOURCES		+=	lib/cpus/aarch64/wa_cve_2017_5715_bpiall.S	\
 				lib/cpus/aarch64/wa_cve_2017_5715_mmu.S
diff --git a/docs/user-guide.rst b/docs/user-guide.rst
index 46370ce..3f8170f 100644
--- a/docs/user-guide.rst
+++ b/docs/user-guide.rst
@@ -351,6 +351,17 @@
    that is only required for the assertion and does not fit in the assertion
    itself.
 
+-  ``ENABLE_MPAM_FOR_LOWER_ELS``: Boolean option to enable lower ELs to use MPAM
+   feature. MPAM is an optional Armv8.4 extension that enables various memory
+   system components and resources to define partitions; software running at
+   various ELs can assign themselves to desired partition to control their
+   performance aspects.
+
+   When this option is set to ``1``, EL3 allows lower ELs to access their own
+   MPAM registers without trapping into EL3. This option doesn't make use of
+   partitioning in EL3, however. Platform initialisation code should configure
+   and use partitions in EL3 as required. This option defaults to ``0``.
+
 -  ``ENABLE_PMF``: Boolean option to enable support for optional Performance
    Measurement Framework(PMF). Default is 0.
 
diff --git a/include/lib/aarch64/arch.h b/include/lib/aarch64/arch.h
index c9619f6..cccb286 100644
--- a/include/lib/aarch64/arch.h
+++ b/include/lib/aarch64/arch.h
@@ -117,6 +117,8 @@
 #define ID_AA64PFR0_SVE_SHIFT	U(32)
 #define ID_AA64PFR0_SVE_MASK	ULL(0xf)
 #define ID_AA64PFR0_SVE_LENGTH	U(4)
+#define ID_AA64PFR0_MPAM_SHIFT	U(40)
+#define ID_AA64PFR0_MPAM_MASK	ULL(0xf)
 #define ID_AA64PFR0_CSV2_SHIFT	U(56)
 #define ID_AA64PFR0_CSV2_MASK	ULL(0xf)
 #define ID_AA64PFR0_CSV2_LENGTH	U(4)
@@ -658,6 +660,14 @@
 #define PMBLIMITR_EL1		S3_0_C9_C10_0
 
 /*******************************************************************************
+ * Definitions for system register interface to MPAM
+ ******************************************************************************/
+#define MPAMIDR_EL1		S3_0_C10_C4_4
+#define MPAM2_EL2		S3_4_C10_C5_0
+#define MPAMHCR_EL2		S3_4_C10_C4_0
+#define MPAM3_EL3		S3_6_C10_C5_0
+
+/*******************************************************************************
  * Definitions for system register interface to AMU for ARMv8.4 onwards
  ******************************************************************************/
 #define AMCR_EL0		S3_3_C13_C2_0
@@ -722,6 +732,11 @@
 #define AMCGCR_EL0_CG1NC_LENGTH	U(8)
 #define AMCGCR_EL0_CG1NC_MASK	U(0xff)
 
+/* MPAM register definitions */
+#define MPAM3_EL3_MPAMEN_BIT		(ULL(1) << 63)
+
+#define MPAMIDR_HAS_HCR_BIT		(ULL(1) << 17)
+
 /*******************************************************************************
  * RAS system registers
  *******************************************************************************/
diff --git a/include/lib/aarch64/arch_helpers.h b/include/lib/aarch64/arch_helpers.h
index 58ec943..8e82dbd 100644
--- a/include/lib/aarch64/arch_helpers.h
+++ b/include/lib/aarch64/arch_helpers.h
@@ -328,6 +328,11 @@
 DEFINE_RENAME_SYSREG_RW_FUNCS(amcntenclr1_el0, AMCNTENCLR1_EL0)
 DEFINE_RENAME_SYSREG_RW_FUNCS(amcntenset1_el0, AMCNTENSET1_EL0)
 
+DEFINE_RENAME_SYSREG_READ_FUNC(mpamidr_el1, MPAMIDR_EL1)
+DEFINE_RENAME_SYSREG_RW_FUNCS(mpam3_el3, MPAM3_EL3)
+DEFINE_RENAME_SYSREG_RW_FUNCS(mpam2_el2, MPAM2_EL2)
+DEFINE_RENAME_SYSREG_RW_FUNCS(mpamhcr_el2, MPAMHCR_EL2)
+
 DEFINE_RENAME_SYSREG_RW_FUNCS(pmblimitr_el1, PMBLIMITR_EL1)
 
 DEFINE_RENAME_SYSREG_WRITE_FUNC(zcr_el3, ZCR_EL3)
diff --git a/include/lib/extensions/mpam.h b/include/lib/extensions/mpam.h
new file mode 100644
index 0000000..571b96b
--- /dev/null
+++ b/include/lib/extensions/mpam.h
@@ -0,0 +1,15 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef MPAM_H
+#define MPAM_H
+
+#include <stdbool.h>
+
+bool mpam_supported(void);
+void mpam_enable(int el2_unused);
+
+#endif /* MPAM_H */
diff --git a/lib/el3_runtime/aarch64/context_mgmt.c b/lib/el3_runtime/aarch64/context_mgmt.c
index f389368..2812bda 100644
--- a/lib/el3_runtime/aarch64/context_mgmt.c
+++ b/lib/el3_runtime/aarch64/context_mgmt.c
@@ -12,6 +12,7 @@
 #include <context.h>
 #include <context_mgmt.h>
 #include <interrupt_mgmt.h>
+#include <mpam.h>
 #include <platform.h>
 #include <platform_def.h>
 #include <pubsub_events.h>
@@ -244,6 +245,10 @@
 #if ENABLE_SVE_FOR_NS
 	sve_enable(el2_unused);
 #endif
+
+#if ENABLE_MPAM_FOR_LOWER_ELS
+	mpam_enable(el2_unused);
+#endif
 #endif
 }
 
diff --git a/lib/extensions/mpam/mpam.c b/lib/extensions/mpam/mpam.c
new file mode 100644
index 0000000..e628827
--- /dev/null
+++ b/lib/extensions/mpam/mpam.c
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <mpam.h>
+#include <stdbool.h>
+
+bool mpam_supported(void)
+{
+	uint64_t features = read_id_aa64dfr0_el1() >> ID_AA64PFR0_MPAM_SHIFT;
+
+	return ((features & ID_AA64PFR0_MPAM_MASK) != 0U);
+}
+
+void mpam_enable(int el2_unused)
+{
+	if (!mpam_supported())
+		return;
+
+	/*
+	 * Enable MPAM, and disable trapping to EL3 when lower ELs access their
+	 * own MPAM registers.
+	 */
+	write_mpam3_el3(MPAM3_EL3_MPAMEN_BIT);
+
+	/*
+	 * If EL2 is implemented but unused, disable trapping to EL2 when lower
+	 * ELs access their own MPAM registers.
+	 */
+	if (el2_unused != 0) {
+		write_mpam2_el2(0);
+
+		if ((read_mpamidr_el1() & MPAMIDR_HAS_HCR_BIT) != 0U)
+			write_mpamhcr_el2(0);
+	}
+}
diff --git a/make_helpers/defaults.mk b/make_helpers/defaults.mk
index e4b5bdc..49f403d 100644
--- a/make_helpers/defaults.mk
+++ b/make_helpers/defaults.mk
@@ -62,6 +62,9 @@
 # development platforms.
 DYN_DISABLE_AUTH		:= 0
 
+# Build option to enable MPAM for lower ELs
+ENABLE_MPAM_FOR_LOWER_ELS	:= 0
+
 # Flag to enable Performance Measurement Framework
 ENABLE_PMF			:= 0