diff mbox series

acpi: fadt: get _CST c2 c3 for p_lvl2 and p_lvl3 tests

Message ID 20220812062834.1467-1-ivan.hu@canonical.com
State Accepted
Headers show
Series acpi: fadt: get _CST c2 c3 for p_lvl2 and p_lvl3 tests | expand

Commit Message

ivanhu Aug. 12, 2022, 6:28 a.m. UTC
buglink: https://bugs.launchpad.net/fwts/+bug/1983853

From the ACPI specification, the _CST may override the P_BLK, and declarations
via the ASL Processor statement are deprecated. The _CST C2 and C3 also need
to be checked for the P_LVL2_LAT and P_LVL3_LAT tests.

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

Patch

diff --git a/src/acpi/fadt/fadt.c b/src/acpi/fadt/fadt.c
index ab4d9f1f..bae0c805 100644
--- a/src/acpi/fadt/fadt.c
+++ b/src/acpi/fadt/fadt.c
@@ -1443,9 +1443,60 @@  static uint64_t fadt_find_p_blk(fwts_framework *fw)
 	return pblk;
 }
 
-static void acpi_table_check_fadt_p_lvl2_lat(fwts_framework *fw, uint64_t pblk)
+static void get_cst_c2c3(fwts_framework *fw, uint16_t *c2, uint16_t *c3)
 {
-	if (pblk) {
+	const size_t name_len = 4;
+	fwts_list_link	*item;
+	fwts_list *objects;
+
+	if ((objects = fwts_acpi_object_get_names()) == NULL) {
+		fwts_log_info(fw, "Cannot find any ACPI objects");
+		return;
+	}
+
+	fwts_list_foreach(item, objects) {
+		char *name = fwts_list_data(char*, item);
+		const size_t len = strlen(name);
+		if (strncmp("_CST", name + len - name_len, name_len) == 0) {
+			ACPI_OBJECT_LIST arg_list;
+			ACPI_BUFFER buf;
+			ACPI_OBJECT *obj;
+			int ret;
+
+			arg_list.Count   = 0;
+			arg_list.Pointer = NULL;
+
+			ret = fwts_acpi_object_evaluate(fw, name, &arg_list, &buf);
+			if ((ACPI_FAILURE(ret) != AE_OK) || (buf.Pointer == NULL))
+				continue;
+
+			obj = buf.Pointer;
+			if ((obj->Type == ACPI_TYPE_PACKAGE) &&
+			    (obj->Package.Count) &&
+			    (obj->Package.Elements[0].Type == ACPI_TYPE_INTEGER) &&
+			    (obj->Package.Elements[0].Integer.Value == (obj->Package.Count - 1))) {
+				ACPI_OBJECT *pkg = NULL;
+				uint32_t i;
+
+				for (i = 1; i < obj->Package.Count; i++){
+					if (*c2 == 0 || *c3 == 0) {
+						pkg = &obj->Package.Elements[i];
+						if ((uint8_t)pkg->Package.Elements[1].Integer.Value == 2)
+							*c2 = (uint16_t)pkg->Package.Elements[2].Integer.Value;
+						else if ((uint8_t)pkg->Package.Elements[1].Integer.Value == 3)
+							*c3 = (uint16_t)pkg->Package.Elements[2].Integer.Value;
+					}
+				}
+			}
+			free(buf.Pointer);
+		}
+	}
+	return;
+}
+
+static void acpi_table_check_fadt_p_lvl2_lat(fwts_framework *fw, uint64_t pblk, uint16_t c2)
+{
+	if (pblk || c2) {
 		if (fadt->p_lvl2_lat <= 100)
 			fwts_passed(fw,
 				    "FADT P_LVL2_LAT is within proper range "
@@ -1453,12 +1504,13 @@  static void acpi_table_check_fadt_p_lvl2_lat(fwts_framework *fw, uint64_t pblk)
 		else
 			fwts_warning(fw,
 				     "FADT P_LVL2_LAT is > 100 (%" PRIu16 ") "
-				     "but a P_BLK is defined.  This implies "
-				     "a C2 state is not supported, but there "
-				     "is a P_BLK register block defined which "
-				     "implies there might be a C2 state that "
-				     "works.  There is not enough information "
-				     "to determine if this is expected or not.",
+				     "but a P_BLK or _CST C2 is defined. This "
+				     "implies a C2 state is not supported, but "
+				     "there is a P_BLK register block or _CST "
+				     "C2 defined which implies there might be "
+				     "a C2 state that works. There is not "
+				     "enough information to determine if this "
+				     "is expected or not.",
 				     fadt->p_lvl2_lat);
 	} else {
 		if (fadt->p_lvl2_lat <= 100)
@@ -1467,21 +1519,22 @@  static void acpi_table_check_fadt_p_lvl2_lat(fwts_framework *fw, uint64_t pblk)
 				    "FADT P_LVL2_LAT is <= 100 (%" PRIu16 ") "
 				    "which implies a C2 state is supported "
 				    "but there is no P_BLK register block "
-				    "defined to enable the C2 transition.",
+				    "or _CST C2 defined to enable the C2 "
+				    "transition.",
 				    fadt->p_lvl2_lat);
 		else
 			fwts_passed(fw,
 				    "FADT P_LVL2_LAT is > 100 (%" PRIu16 ") "
-				    "and no P_BLK is defined.",
+				    "and no P_BLK or _CST C2 is defined.",
 				    fadt->p_lvl2_lat);
 	}
 
 	return;
 }
 
-static void acpi_table_check_fadt_p_lvl3_lat(fwts_framework *fw, uint64_t pblk)
+static void acpi_table_check_fadt_p_lvl3_lat(fwts_framework *fw, uint64_t pblk, uint16_t c3)
 {
-	if (pblk) {
+	if (pblk || c3) {
 		if (fadt->p_lvl3_lat <= 1000)
 			fwts_passed(fw,
 				    "FADT P_LVL3_LAT is within proper range "
@@ -1489,12 +1542,13 @@  static void acpi_table_check_fadt_p_lvl3_lat(fwts_framework *fw, uint64_t pblk)
 		else
 			fwts_warning(fw,
 				     "FADT P_LVL3_LAT is > 1000 (%" PRIu16 ") "
-				     "but a P_BLK is defined.  This implies "
-				     "a C3 state is not supported, but there "
-				     "is a P_BLK register block defined which "
-				     "implies there might be a C3 state that "
-				     "works.  There is not enough information "
-				     "to determine if this is expected or not.",
+				     "but a P_BLK or _CST C3 is defined. This "
+				     "implies a C3 state is not supported, but "
+				     "there is a P_BLK register block or _CST "
+				     "C3 defined which implies there might be "
+				     "a C3 state that works. There is not "
+				     "enough information to determine if this "
+				     "is expected or not.",
 				     fadt->p_lvl3_lat);
 	} else {
 		if (fadt->p_lvl3_lat <= 1000)
@@ -1503,12 +1557,13 @@  static void acpi_table_check_fadt_p_lvl3_lat(fwts_framework *fw, uint64_t pblk)
 				    "FADT P_LVL3_LAT is <= 1000 (%" PRIu16 ") "
 				    "which implies a C3 state is supported "
 				    "but there is no P_BLK register block "
-				    "defined to enable the C3 transition.",
+				    "or _CST C3 defined to enable the C3 "
+				    "transition.",
 				    fadt->p_lvl3_lat);
 		else
 			fwts_passed(fw,
-				    "FADT P_LVL3_LAT is > 100 (%" PRIu16 ") "
-				    "and no P_BLK is defined.",
+				    "FADT P_LVL3_LAT is > 1000 (%" PRIu16 ") "
+				    "and no P_BLK or _CST C3 is defined.",
 				    fadt->p_lvl3_lat);
 	}
 
@@ -1642,9 +1697,12 @@  static int fadt_test1(fwts_framework *fw)
 
 		if (fwts_acpi_init(fw) == FWTS_OK) {
 			uint64_t pblk = fadt_find_p_blk(fw);
+			uint16_t c2 = 0;
+			uint16_t c3 = 0;
 
-			acpi_table_check_fadt_p_lvl2_lat(fw, pblk);
-			acpi_table_check_fadt_p_lvl3_lat(fw, pblk);
+			get_cst_c2c3(fw, &c2, &c3);
+			acpi_table_check_fadt_p_lvl2_lat(fw, pblk, c2);
+			acpi_table_check_fadt_p_lvl3_lat(fw, pblk, c3);
 			fwts_acpi_deinit(fw);
 		} else {
 			fwts_log_error(fw, "Cannot initialize ACPI namespace.");