fix(errata-abi): add support for handling split workarounds

Certain erratum workarounds like Neoverse N1 1542419, need a part
of their mitigation done in EL3 and the rest in lower EL. But currently
such workarounds return HIGHER_EL_MITIGATION which indicates that the
erratum has already been mitigated by a higher EL(EL3 in this case)
which causes the lower EL to not apply it's part of the mitigation.

This patch fixes this issue by adding support for split workarounds
so that on certain errata we return AFFECTED even though EL3 has
applied it's workaround. This is done by reusing the chosen field of
erratum_entry structure into a bitfield that has two bitfields -
Bit 0 indicates that the erratum has been enabled in build,
Bit 1 indicates that the erratum is a split workaround and should
return AFFECTED instead of HIGHER_EL_MITIGATION.

SDEN documentation:
https://developer.arm.com/documentation/SDEN885747/latest

Signed-off-by: Arvind Ram Prakash <arvind.ramprakash@arm.com>
Change-Id: Iec94d665b5f55609507a219a7d1771eb75e7f4a7
diff --git a/include/lib/cpus/aarch64/cpu_macros.S b/include/lib/cpus/aarch64/cpu_macros.S
index a43746f..c35503a 100644
--- a/include/lib/cpus/aarch64/cpu_macros.S
+++ b/include/lib/cpus/aarch64/cpu_macros.S
@@ -235,10 +235,11 @@
  * _chosen:
  *	Compile time flag on whether the erratum is included
  *
- * _apply_at_reset:
- *	Whether the erratum should be automatically applied at reset
+ * _split_wa:
+ *	Flag that indicates whether an erratum has split workaround or not.
+ *	Default value is 0.
  */
-.macro add_erratum_entry _cpu:req, _cve:req, _id:req, _chosen:req
+.macro add_erratum_entry _cpu:req, _cve:req, _id:req, _chosen:req, _split_wa=0
 #if REPORT_ERRATA || ERRATA_ABI_SUPPORT
 	.pushsection .rodata.errata_entries
 		.align	3
@@ -250,7 +251,8 @@
 		/* Will fit CVEs with up to 10 character in the ID field */
 		.word	\_id
 		.hword	\_cve
-		.byte	\_chosen
+		/* bit magic that appends chosen field based on _split_wa */
+		.byte	((\_chosen * 0b11) & ((\_split_wa << 1) | \_chosen))
 		.byte	0x0 /* alignment */
 	.popsection
 #endif
@@ -276,14 +278,20 @@
  * _chosen:
  *	Compile time flag on whether the erratum is included
  *
+ * _split_wa:
+ *	Flag that indicates whether an erratum has split workaround or not.
+ *	Default value is 0.
+ *
  * in body:
  *	clobber x0 to x7 (please only use those)
  *	argument x7 - cpu_rev_var
  *
  * _wa clobbers: x0-x8 (PCS compliant)
  */
-.macro workaround_reset_start _cpu:req, _cve:req, _id:req, _chosen:req
-	add_erratum_entry \_cpu, \_cve, \_id, \_chosen
+.macro workaround_reset_start _cpu:req, _cve:req, _id:req, \
+	_chosen:req, _split_wa=0
+
+	add_erratum_entry \_cpu, \_cve, \_id, \_chosen, \_split_wa
 
 	.if \_chosen
 		/* put errata directly into the reset function */
diff --git a/include/lib/cpus/errata.h b/include/lib/cpus/errata.h
index 10b949f..9eae276 100644
--- a/include/lib/cpus/errata.h
+++ b/include/lib/cpus/errata.h
@@ -42,6 +42,12 @@
 	uint32_t id;
 	/* Denote CVEs with their year or errata with 0 */
 	uint16_t cve;
+	/*
+	 * a bitfield:
+	 * bit 0 - denotes if the erratum is enabled in build.
+	 * bit 1 - denotes if the erratum workaround is split and
+	 * 	   also needs to be implemented at a lower EL.
+	 */
 	uint8_t chosen;
 	uint8_t _alignment;
 } __packed;
@@ -96,4 +102,11 @@
 /* Macro to get CPU revision code for checking errata version compatibility. */
 #define CPU_REV(r, p)		((r << 4) | p)
 
+/* Used for errata that have split workaround */
+#define SPLIT_WA			1
+
+/* chosen bitfield entries */
+#define WA_ENABLED_MASK			BIT(0)
+#define SPLIT_WA_MASK			BIT(1)
+
 #endif /* ERRATA_H */
diff --git a/lib/cpus/aarch64/neoverse_n1.S b/lib/cpus/aarch64/neoverse_n1.S
index 1ad9557..5868bf2 100644
--- a/lib/cpus/aarch64/neoverse_n1.S
+++ b/lib/cpus/aarch64/neoverse_n1.S
@@ -116,7 +116,7 @@
 
 check_erratum_ls neoverse_n1, ERRATUM(1315703), CPU_REV(3, 0)
 
-workaround_reset_start neoverse_n1, ERRATUM(1542419), ERRATA_N1_1542419
+workaround_reset_start neoverse_n1, ERRATUM(1542419), ERRATA_N1_1542419, SPLIT_WA
 	/* Apply instruction patching sequence */
 	ldr	x0, =0x0
 	msr	CPUPSELR_EL3, x0
diff --git a/services/std_svc/errata_abi/errata_abi_main.c b/services/std_svc/errata_abi/errata_abi_main.c
index 0d0ecc3..a945637 100644
--- a/services/std_svc/errata_abi/errata_abi_main.c
+++ b/services/std_svc/errata_abi/errata_abi_main.c
@@ -197,8 +197,11 @@
 	while ((entry <= end) && (ret_val == EM_UNKNOWN_ERRATUM)) {
 		if (entry->id == errata_id) {
 			if (entry->check_func(rev_var)) {
-				if (entry->chosen)
-					return EM_HIGHER_EL_MITIGATION;
+				if (entry->chosen & WA_ENABLED_MASK)
+					if (entry->chosen & SPLIT_WA_MASK)
+						return EM_AFFECTED;
+					else
+						return EM_HIGHER_EL_MITIGATION;
 				else
 					return EM_AFFECTED;
 			}