diff mbox series

acpi: method: clarify TAD device methods requirements (mantis 2253)

Message ID 20231227040851.23354-1-ivan.hu@canonical.com
State Accepted
Headers show
Series acpi: method: clarify TAD device methods requirements (mantis 2253) | expand

Commit Message

ivanhu Dec. 27, 2023, 4:08 a.m. UTC
BugLink:https://bugs.launchpad.net/fwts/+bug/2047212
Clarify Time and Alarm Device methods requirements added in ACPI6.5

Signed-off-by: Ivan Hu <ivan.hu@canonical.com>
---
 src/acpi/method/method.c | 163 ++++++++++++++++++++++++++++++++++-----
 1 file changed, 144 insertions(+), 19 deletions(-)
diff mbox series

Patch

diff --git a/src/acpi/method/method.c b/src/acpi/method/method.c
index 2885f3f1..93251d89 100644
--- a/src/acpi/method/method.c
+++ b/src/acpi/method/method.c
@@ -271,6 +271,7 @@ 
 #define DEVICE_D3COLD	4
 
 static bool fadt_mobile_platform;	/* True if a mobile platform */
+static uint32_t gcp_return_value;
 
 #define method_test_integer(name, type)				\
 static int method_test ## name(fwts_framework *fw)		\
@@ -296,6 +297,7 @@  static int method_init(fwts_framework *fw)
 	bool got_fadt = false;
 
 	fadt_mobile_platform = false;
+	gcp_return_value = 0;
 
 	/* Some systems have multiple FADTs, sigh */
 	for (i = 0; i < 256; i++) {
@@ -2907,11 +2909,94 @@  static int method_test_UPP(fwts_framework *fw)
 /*
  * Section 9.18 Wake Alarm Device
  */
+static void method_test_GCP_return(
+	fwts_framework *fw,
+	char *name,
+	ACPI_BUFFER *buf,
+	ACPI_OBJECT *obj,
+	void *private)
+{
+	uint32_t *mask = (uint32_t *) private;
+	bool failed = false;
+
+	if (fwts_method_check_type(fw, name, buf, ACPI_TYPE_INTEGER) != FWTS_OK)
+		return;
+
+	gcp_return_value = obj->Integer.Value;
+
+	if (gcp_return_value & *mask) {
+		failed = true;
+		fwts_failed(fw, LOG_LEVEL_MEDIUM, "MethodIllegalReserved",
+			"%s returned value 0x%4.4" PRIx32 " and some of the "
+			"reserved bits are set when they should be zero.",
+			name, (uint32_t)obj->Integer.Value);
+	}
+	/* If wake on DC is supported (bit 1), then wake from AC (bit 0) must be supported */
+	if (gcp_return_value & (1 << 1) && !(gcp_return_value & 1)) {
+		failed = true;
+		fwts_failed(fw, LOG_LEVEL_MEDIUM, "MethodBadSupport",
+			"%s returned value 0x%4.4" PRIx32 ", if DC is supported(bit 1), "
+			"then wake from AC(bit 0) must be supported.", name, gcp_return_value);
+	}
+        /* If wake on AC from S5 is supported (bit 6), then wake on AC from S4 must be supported (bit 5) */
+	if (gcp_return_value & (1 << 6) && !(gcp_return_value & (1 << 5))) {
+		failed = true;
+		fwts_failed(fw, LOG_LEVEL_MEDIUM, "MethodBadSupport",
+			"%s returned value 0x%4.4" PRIx32 ", if wake on AC from S5 is supported(bit 6), "
+			"then wake on AC from S4 must be supported(bit 5).", name, gcp_return_value);
+	}
+        /* If wake on AC from S4 is supported (bit 5), then wake on AC must be supported (bit 0) */
+	if (gcp_return_value & (1 << 5) && !(gcp_return_value & 1)) {
+		failed = true;
+		fwts_failed(fw, LOG_LEVEL_MEDIUM, "MethodBadSupport",
+			"%s returned value 0x%4.4" PRIx32 ", if wake on AC from S4 is supported(bit 5), "
+			"then wake on AC must be supported(bit 0).", name, gcp_return_value);
+	}
+        /* If wake on DC from S5 is supported (bit 8), then wake on DC from S4 must be supported (bit 7) */
+	if (gcp_return_value & (1 << 8) && !(gcp_return_value & (1 << 7))) {
+		failed = true;
+		fwts_failed(fw, LOG_LEVEL_MEDIUM, "MethodBadSupport",
+			"%s returned value 0x%4.4" PRIx32 ", if wake on DC from S5 is supported(bit 8), "
+			"then wake on DC from S4 must be supported(bit 7).", name, gcp_return_value);
+	}
+        /* If wake on DC from S4 is supported (bit 7), then wake on DC must be supported (bit 1) */
+	if (gcp_return_value & (1 << 7) && !(gcp_return_value & (1 << 1))) {
+		failed = true;
+		fwts_failed(fw, LOG_LEVEL_MEDIUM, "MethodBadSupport",
+			"%s returned value 0x%4.4" PRIx32 ", if wake on DC from S4 is supported(bit 7), "
+			"then wake on DC must be supported(bit 1).", name, gcp_return_value);
+	}
+        /* If wake on DC from S4 is supported (bit 7), then wake on AC from S4 must be supported (bit 5) */
+	if (gcp_return_value & (1 << 7) && !(gcp_return_value & (1 << 5))) {
+		failed = true;
+		fwts_failed(fw, LOG_LEVEL_MEDIUM, "MethodBadSupport",
+			"%s returned value 0x%4.4" PRIx32 ", if wake on DC from S4 is supported(bit 7), "
+			"then wake on AC from S4 must be supported(bit 5).", name, gcp_return_value);
+	}
+        /* If wake on DC from S5 is supported (bit 8), then wake on AC from S5 must be supported (bit 6) */
+	if (gcp_return_value & (1 << 8) && !(gcp_return_value & (1 << 6))) {
+		failed = true;
+		fwts_failed(fw, LOG_LEVEL_MEDIUM, "MethodBadSupport",
+			"%s returned value 0x%4.4" PRIx32 ", if wake on DC from S5 is supported(bit 8), "
+			"then wake on AC from S5 must be supported(bit 6).", name, gcp_return_value);
+	}
+        /* If wake from S4/S5 is supported (bits 5-8), then _GWS must be supported (bit 4) */
+	if (gcp_return_value & 0x1e0 && !(gcp_return_value & (1 << 4))) {
+		failed = true;
+		fwts_failed(fw, LOG_LEVEL_MEDIUM, "MethodBadSupport",
+			"%s returned value 0x%4.4" PRIx32 ", if wake from S4/S5 is supported(bits 5-8), "
+			"then _GWS must be supported(bit 4).", name, gcp_return_value);
+	}
+
+	if (!failed)
+		fwts_passed(fw, "%s correctly returned an integer.", name);
+}
+
 static int method_test_GCP(fwts_framework *fw)
 {
-	uint64_t mask = ~0x1ff;
+	uint32_t mask = ~0x1ff;
 	return method_evaluate_method(fw, METHOD_OPTIONAL,
-		"_GCP", NULL, 0, fwts_method_test_integer_reserved_bits_return, &mask);
+		"_GCP", NULL, 0, method_test_GCP_return, &mask);
 }
 
 static void method_test_GRT_return(
@@ -2938,8 +3023,13 @@  static void method_test_GRT_return(
 
 static int method_test_GRT(fwts_framework *fw)
 {
-	return method_evaluate_method(fw, METHOD_OPTIONAL,
-		"_GRT", NULL, 0, method_test_GRT_return, NULL);
+	/* This object is required if the capabilities bit 2 is set to 1 */
+	if (gcp_return_value & (1 << 2))
+		return method_evaluate_method(fw, METHOD_MANDATORY,
+			"_GRT", NULL, 0, method_test_GRT_return, NULL);
+	else
+		return method_evaluate_method(fw, METHOD_OPTIONAL,
+			"_GRT", NULL, 0, method_test_GRT_return, NULL);
 }
 
 static int method_test_SRT(fwts_framework *fw)
@@ -2959,9 +3049,13 @@  static int method_test_SRT(fwts_framework *fw)
 	arg0.Type = ACPI_TYPE_BUFFER;
 	arg0.Buffer.Length = time_size;
 	arg0.Buffer.Pointer = (void *)&real_time;
-
-	return method_evaluate_method(fw, METHOD_OPTIONAL,
-		"_SRT", &arg0, 1, fwts_method_test_integer_return, NULL);
+	/* This object is required if the capabilities bit 2 is set to 1 */
+	if (gcp_return_value & (1 << 2))
+		return method_evaluate_method(fw, METHOD_MANDATORY,
+			"_SRT", &arg0, 1, fwts_method_test_integer_return, NULL);
+	else
+		return method_evaluate_method(fw, METHOD_OPTIONAL,
+			"_SRT", &arg0, 1, fwts_method_test_integer_return, NULL);
 }
 
 static int method_test_GWS(fwts_framework *fw)
@@ -2972,8 +3066,13 @@  static int method_test_GWS(fwts_framework *fw)
 	arg[0].Type = ACPI_TYPE_INTEGER;
 	arg[0].Integer.Value = 1;	/* DC timer */
 
-	return method_evaluate_method(fw, METHOD_OPTIONAL,
-		"_GWS", arg, 1, fwts_method_test_integer_reserved_bits_return, &mask);
+	/* This object is required if the capabilities bit 0 is set to 1 */
+	if (gcp_return_value & 1) 
+		return method_evaluate_method(fw, METHOD_MANDATORY, "_GWS",
+			arg, 1, fwts_method_test_integer_reserved_bits_return, &mask);
+	else
+		return method_evaluate_method(fw, METHOD_OPTIONAL, "_GWS",
+			arg, 1, fwts_method_test_integer_reserved_bits_return, &mask);
 }
 
 static void method_test_CWS_return(
@@ -3005,8 +3104,13 @@  static int method_test_CWS(fwts_framework *fw)
 
 	for (i = 0; i < 2; i++) {
 		arg[0].Integer.Value = i;
-		ret = method_evaluate_method(fw, METHOD_OPTIONAL,
-			"_CWS", arg, 1, method_test_CWS_return, NULL);
+		/* This object is required if the capabilities bit 0 is set to 1 */
+		if (gcp_return_value & 1)
+			ret = method_evaluate_method(fw, METHOD_MANDATORY,
+				"_CWS", arg, 1, method_test_CWS_return, NULL);
+		else
+			ret = method_evaluate_method(fw, METHOD_OPTIONAL,
+				"_CWS", arg, 1, method_test_CWS_return, NULL);
 
 		if (ret != FWTS_OK)
 			break;
@@ -3024,8 +3128,13 @@  static int method_test_STP(fwts_framework *fw)
 	arg[1].Type = ACPI_TYPE_INTEGER;
 	arg[1].Integer.Value = 0;	/* wake up instantly */
 
-	return method_evaluate_method(fw, METHOD_OPTIONAL,
-		"_STP", arg, 2, fwts_method_test_passed_failed_return, "_STP");
+	/* This object is required if the capabilities bit 0 is set to 1 */
+	if (gcp_return_value & 1)
+		return method_evaluate_method(fw, METHOD_MANDATORY, "_STP",
+			arg, 2, fwts_method_test_passed_failed_return, "_STP");
+	else
+		return method_evaluate_method(fw, METHOD_OPTIONAL, "_STP",
+			arg, 2, fwts_method_test_passed_failed_return, "_STP");
 }
 
 static int method_test_STV(fwts_framework *fw)
@@ -3037,8 +3146,13 @@  static int method_test_STV(fwts_framework *fw)
 	arg[1].Type = ACPI_TYPE_INTEGER;
 	arg[1].Integer.Value = 100;	/* timer value */
 
-	return method_evaluate_method(fw, METHOD_OPTIONAL,
-		"_STV", arg, 2, fwts_method_test_passed_failed_return, "_STV");
+	/* This object is required if the capabilities bit 0 is set to 1 */
+	if (gcp_return_value & 1)
+		return method_evaluate_method(fw, METHOD_MANDATORY, "_STV",
+			arg, 2, fwts_method_test_passed_failed_return, "_STV");
+	else
+		return method_evaluate_method(fw, METHOD_OPTIONAL, "_STV",
+			arg, 2, fwts_method_test_passed_failed_return, "_STV");
 }
 
 static int method_test_TIP(fwts_framework *fw)
@@ -3048,8 +3162,13 @@  static int method_test_TIP(fwts_framework *fw)
 	arg[0].Type = ACPI_TYPE_INTEGER;
 	arg[0].Integer.Value = 1;	/* DC timer */
 
-	return method_evaluate_method(fw, METHOD_OPTIONAL,
-		"_TIP", arg, 1, fwts_method_test_integer_return, NULL);
+	/* This object is required if the capabilities bit 0 is set to 1 */
+	if (gcp_return_value & 1)
+		return method_evaluate_method(fw, METHOD_MANDATORY,
+			"_TIP", arg, 1, fwts_method_test_integer_return, NULL);
+	else
+		return method_evaluate_method(fw, METHOD_OPTIONAL,
+			"_TIP", arg, 1, fwts_method_test_integer_return, NULL);
 }
 
 static int method_test_TIV(fwts_framework *fw)
@@ -3059,8 +3178,14 @@  static int method_test_TIV(fwts_framework *fw)
 	arg[0].Type = ACPI_TYPE_INTEGER;
 	arg[0].Integer.Value = 1;	/* DC timer */
 
-	return method_evaluate_method(fw, METHOD_OPTIONAL,
-		"_TIV", arg, 1, fwts_method_test_integer_return, NULL);
+	/* This object is required if the capabilities bit 0 is set to 1 */
+	if (gcp_return_value & 1)
+		return method_evaluate_method(fw, METHOD_MANDATORY,
+			"_TIV", arg, 1, fwts_method_test_integer_return, NULL);
+	else
+		return method_evaluate_method(fw, METHOD_OPTIONAL,
+			"_TIV", arg, 1, fwts_method_test_integer_return, NULL);
+			
 }
 
 /*