Patch Detail
get:
Show a patch.
patch:
Update a patch.
put:
Update a patch.
GET /api/patches/2137314/?format=api
{ "id": 2137314, "url": "http://patchwork.ozlabs.org/api/patches/2137314/?format=api", "web_url": "http://patchwork.ozlabs.org/project/fwts/patch/20250915191415.3710447-1-edhaya.chandran@arm.com/", "project": { "id": 24, "url": "http://patchwork.ozlabs.org/api/projects/24/?format=api", "name": "Firmware Test Suite development", "link_name": "fwts", "list_id": "fwts-devel.lists.ubuntu.com", "list_email": "fwts-devel@lists.ubuntu.com", "web_url": null, "scm_url": null, "webscm_url": null, "list_archive_url": "", "list_archive_url_format": "", "commit_url_format": "" }, "msgid": "<20250915191415.3710447-1-edhaya.chandran@arm.com>", "list_archive_url": null, "date": "2025-09-15T19:14:15", "name": "[1/1] pci/smccc: New tests for Arm PSCI functions", "commit_ref": null, "pull_url": null, "state": "superseded", "archived": false, "hash": "f710ba06716f692b2bd74b65c77dc3e0fc247a44", "submitter": { "id": 83059, "url": "http://patchwork.ozlabs.org/api/people/83059/?format=api", "name": "G Edhaya Chandran", "email": "Edhaya.Chandran@arm.com" }, "delegate": null, "mbox": "http://patchwork.ozlabs.org/project/fwts/patch/20250915191415.3710447-1-edhaya.chandran@arm.com/mbox/", "series": [ { "id": 473746, "url": "http://patchwork.ozlabs.org/api/series/473746/?format=api", "web_url": "http://patchwork.ozlabs.org/project/fwts/list/?series=473746", "date": "2025-09-15T19:14:15", "name": "[1/1] pci/smccc: New tests for Arm PSCI functions", "version": 1, "mbox": "http://patchwork.ozlabs.org/series/473746/mbox/" } ], "comments": "http://patchwork.ozlabs.org/api/patches/2137314/comments/", "check": "pending", "checks": "http://patchwork.ozlabs.org/api/patches/2137314/checks/", "tags": {}, "related": [], "headers": { "Return-Path": "<fwts-devel-bounces@lists.ubuntu.com>", "X-Original-To": "incoming@patchwork.ozlabs.org", "Delivered-To": "patchwork-incoming@legolas.ozlabs.org", "Authentication-Results": "legolas.ozlabs.org;\n spf=pass (sender SPF authorized) smtp.mailfrom=lists.ubuntu.com\n (client-ip=185.125.189.65; helo=lists.ubuntu.com;\n envelope-from=fwts-devel-bounces@lists.ubuntu.com;\n receiver=patchwork.ozlabs.org)", "Received": [ "from lists.ubuntu.com (lists.ubuntu.com [185.125.189.65])\n\t(using TLSv1.2 with cipher ECDHE-ECDSA-AES256-GCM-SHA384 (256/256 bits))\n\t(No client certificate requested)\n\tby legolas.ozlabs.org (Postfix) with ESMTPS id 4cQZTj62sTz1y0D\n\tfor <incoming@patchwork.ozlabs.org>; Tue, 16 Sep 2025 05:14:33 +1000 (AEST)", "from localhost ([127.0.0.1] helo=lists.ubuntu.com)\n\tby lists.ubuntu.com with esmtp (Exim 4.86_2)\n\t(envelope-from <fwts-devel-bounces@lists.ubuntu.com>)\n\tid 1uyEeg-0007EJ-03; Mon, 15 Sep 2025 19:14:26 +0000", "from foss.arm.com ([217.140.110.172])\n by lists.ubuntu.com with esmtp (Exim 4.86_2)\n (envelope-from <edhaya.chandran@arm.com>) id 1uyEed-0007E6-Ej\n for fwts-devel@lists.ubuntu.com; Mon, 15 Sep 2025 19:14:23 +0000", "from usa-sjc-imap-foss1.foss.arm.com (unknown [10.121.207.14])\n by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id 545D91424;\n Mon, 15 Sep 2025 12:14:14 -0700 (PDT)", "from a076513.blr.arm.com (a076513.arm.com [10.164.4.41])\n by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id F3A0F3F694;\n Mon, 15 Sep 2025 12:14:20 -0700 (PDT)" ], "From": "G Edhaya Chandran <edhaya.chandran@arm.com>", "To": "fwts-devel@lists.ubuntu.com", "Subject": "[PATCH 1/1] pci/smccc: New tests for Arm PSCI functions", "Date": "Tue, 16 Sep 2025 00:44:15 +0530", "Message-Id": "<20250915191415.3710447-1-edhaya.chandran@arm.com>", "X-Mailer": "git-send-email 2.34.1", "MIME-Version": "1.0", "Received-SPF": "pass client-ip=217.140.110.172;\n envelope-from=edhaya.chandran@arm.com; helo=foss.arm.com", "X-BeenThere": "fwts-devel@lists.ubuntu.com", "X-Mailman-Version": "2.1.20", "Precedence": "list", "List-Id": "Firmware Test Suite Development <fwts-devel.lists.ubuntu.com>", "List-Unsubscribe": "<https://lists.ubuntu.com/mailman/options/fwts-devel>,\n <mailto:fwts-devel-request@lists.ubuntu.com?subject=unsubscribe>", "List-Archive": "<https://lists.ubuntu.com/archives/fwts-devel>", "List-Post": "<mailto:fwts-devel@lists.ubuntu.com>", "List-Help": "<mailto:fwts-devel-request@lists.ubuntu.com?subject=help>", "List-Subscribe": "<https://lists.ubuntu.com/mailman/listinfo/fwts-devel>,\n <mailto:fwts-devel-request@lists.ubuntu.com?subject=subscribe>", "Cc": "edhay <edhaya.chandran@arm.com>", "Content-Type": "text/plain; charset=\"utf-8\"", "Content-Transfer-Encoding": "base64", "Errors-To": "fwts-devel-bounces@lists.ubuntu.com", "Sender": "\"fwts-devel\" <fwts-devel-bounces@lists.ubuntu.com>" }, "content": "From: edhay <edhaya.chandran@arm.com>\n\nPower State Coordination Interface (PSCI) is a standard to manage power states in systems\nbased on Arm architectures—especially in multi-core or multi-cluster environments. \nPSCI provides a firmware interface that allows operating systems to control\nthe power states of CPUs and other system components in a standardized way.\nActual implementation of these calls reside in secure firmware like Arm Trusted Firmware.\n\nArm defines these interfaces in\nArm Power State Coordination Interface specification\nhttps://developer.arm.com/documentation/den0022/latest/\n\nFollowing new tests are added:\n1. Check if PSCI is supported as per ACPI FADT table\n2. Test for PSCI_VERSION\n3. Test for PSCI_FEATURES: Check for the implementation of all\n the 22 PSCI functions\n4. Test for AFFINITY_INFO\n5. psci_features_bbr_check: Checks if all the mandatory PSCI functions\n according to the Arm BBR specification is implemented.\n enabled only with --sbbr or --ebbr flags\n\nThis suite has dependency on smccc_test kernel module and the same\nshould loaded\n\nusage\nsudo fwts psci\nsudo fwts psci --sbbr\nsudo fwts psci --ebbr\n---\n smccc_test/smccc_test.c | 63 +++++\n smccc_test/smccc_test.h | 6 +\n src/Makefile.am | 1 +\n src/pci/smccc/psci.c | 560 ++++++++++++++++++++++++++++++++++++++++\n src/pci/smccc/smccc.c | 15 +-\n 5 files changed, 640 insertions(+), 5 deletions(-)\n create mode 100644 src/pci/smccc/psci.c", "diff": "diff --git a/smccc_test/smccc_test.c b/smccc_test/smccc_test.c\nindex b37691898852..c70add64fe6b 100644\n--- a/smccc_test/smccc_test.c\n+++ b/smccc_test/smccc_test.c\n@@ -85,6 +85,18 @@ MODULE_LICENSE(\"GPL\");\n #define SMCCC_ARCH_SOC_ID\t0x80000002\n #endif\n \n+#ifndef PSCI_VERSION\n+#define PSCI_VERSION\t0x84000000\n+#endif\n+\n+#ifndef PSCI_FEATURES\n+#define PSCI_FEATURES\t0x8400000A\n+#endif\n+\n+#ifndef AFFINITY_INFO\n+#define AFFINITY_INFO\t0x84000004\n+#endif\n+\n /*\n * smccc_test_copy_to_user()\n *\tcopy arm_res a* registers to user space test_arg w array\n@@ -199,6 +211,51 @@ static long smccc_test_arch_soc_id(unsigned long arg)\n \treturn smccc_test_copy_to_user(arg, &arm_res, conduit);\n }\n \n+static long smccc_test_psci_version(unsigned long arg)\n+{\n+\tstruct arm_smccc_res arm_res = { };\n+\tstruct smccc_test_arg test_arg;\n+\tint ret, conduit;\n+\n+\tret = smccc_test_copy_from_user(&test_arg, arg);\n+\tif (ret)\n+\t\treturn ret;\n+\n+\tconduit = arm_smccc_1_1_invoke(PSCI_VERSION, 0, 0, 0, 0, 0, 0, 0, &arm_res);\n+\n+\treturn smccc_test_copy_to_user(arg, &arm_res, conduit);\n+}\n+\n+static long smccc_test_psci_features(unsigned long arg)\n+{\n+\tstruct arm_smccc_res arm_res = { };\n+\tstruct smccc_test_arg test_arg;\n+\tint ret, conduit;\n+\n+\tret = smccc_test_copy_from_user(&test_arg, arg);\n+\tif (ret)\n+\t\treturn ret;\n+\n+\tconduit = arm_smccc_1_1_invoke(PSCI_FEATURES, test_arg.w[1], 0, 0, 0, 0, 0, 0, &arm_res);\n+\n+\treturn smccc_test_copy_to_user(arg, &arm_res, conduit);\n+}\n+\n+static long smccc_test_affinity_info(unsigned long arg)\n+{\n+\tstruct arm_smccc_res arm_res = { };\n+\tstruct smccc_test_arg test_arg;\n+\tint ret, conduit;\n+\n+\tret = smccc_test_copy_from_user(&test_arg, arg);\n+\tif (ret)\n+\t\treturn ret;\n+\n+\tconduit = arm_smccc_1_1_invoke(AFFINITY_INFO, test_arg.w[1], test_arg.w[2], 0, 0, 0, 0, 0, &arm_res);\n+\n+\treturn smccc_test_copy_to_user(arg, &arm_res, conduit);\n+}\n+\n static long smccc_test_ioctl(struct file *file, unsigned int cmd,\n \t\t\t unsigned long arg)\n {\n@@ -229,6 +286,12 @@ static long smccc_test_ioctl(struct file *file, unsigned int cmd,\n \t\treturn smccc_test_arch_features(arg);\n \tcase SMCCC_TEST_ARCH_SOC_ID:\n \t\treturn smccc_test_arch_soc_id(arg);\n+\tcase SMCCC_TEST_PSCI_VERSION:\n+\t\treturn smccc_test_psci_version(arg);\n+\tcase SMCCC_TEST_PSCI_FEATURES:\n+\t\treturn smccc_test_psci_features(arg);\n+\tcase SMCCC_TEST_AFFINITY_INFO:\n+\t\treturn smccc_test_affinity_info(arg);\n \tdefault:\n \t\tbreak;\n \t}\ndiff --git a/smccc_test/smccc_test.h b/smccc_test/smccc_test.h\nindex 6597d87e7b20..25c83a66e574 100644\n--- a/smccc_test/smccc_test.h\n+++ b/smccc_test/smccc_test.h\n@@ -45,4 +45,10 @@ struct smccc_test_arg {\n _IOWR('p', 0x07, struct smccc_test_arg)\n #define SMCCC_TEST_ARCH_SOC_ID \\\n _IOWR('p', 0x08, struct smccc_test_arg)\n+#define SMCCC_TEST_PSCI_VERSION \\\n+ _IOWR('p', 0x09, struct smccc_test_arg)\n+#define SMCCC_TEST_PSCI_FEATURES \\\n+ _IOWR('p', 0x0A, struct smccc_test_arg)\n+#define SMCCC_TEST_AFFINITY_INFO \\\n+ _IOWR('p', 0x0B, struct smccc_test_arg)\n #endif\ndiff --git a/src/Makefile.am b/src/Makefile.am\nindex 2cdbe60f67e3..448318be3475 100644\n--- a/src/Makefile.am\n+++ b/src/Makefile.am\n@@ -209,6 +209,7 @@ fwts_SOURCES = main.c \t\t\t\t\\\n \tpci/crs/crs.c \t\t\t\t\\\n \tpci/maxreadreq/maxreadreq.c \t\t\\\n \tpci/smccc/smccc.c\t\t\t\\\n+\tpci/smccc/psci.c\t\t\t\\\n \ttpm/tpmevlog/tpmevlog.c\t\t\t\\\n \ttpm/tpmevlogdump/tpmevlogdump.c\t\t\\\n \tuefi/csm/csm.c \t\t\t\t\\\ndiff --git a/src/pci/smccc/psci.c b/src/pci/smccc/psci.c\nnew file mode 100644\nindex 000000000000..feb1b8179694\n--- /dev/null\n+++ b/src/pci/smccc/psci.c\n@@ -0,0 +1,560 @@\n+/*\n+ *\n+ * Copyright (C) 2025 Canonical\n+ * Copyright (C) 2025 Arm\n+ *\n+ * This program is free software; you can redistribute it and/or\n+ * modify it under the terms of the GNU General Public License\n+ * as published by the Free Software Foundation; either version 2\n+ * of the License, or (at your option) any later version.\n+ *\n+ * This program is distributed in the hope that it will be useful,\n+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\n+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n+ * GNU General Public License for more details.\n+ *\n+ * You should have received a copy of the GNU General Public License\n+ * along with this program; if not, write to the Free Software\n+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n+ *\n+ */\n+#include \"fwts.h\"\n+\n+#ifdef FWTS_ARCH_AARCH64\n+\n+#include <errno.h>\n+#include <inttypes.h>\n+#include <stdio.h>\n+#include <stddef.h>\n+#include <stdbool.h>\n+#include <string.h>\n+#include <sys/ioctl.h>\n+#include <fcntl.h>\n+\n+#include \"smccc_test.h\"\n+\n+/*\n+ * ARM PSCI tests,\n+ * https://developer.arm.com/documentation/den0022/latest/\n+ */\n+\n+extern int smccc_init(fwts_framework *fw);\n+extern char *smccc_pci_conduit_name(struct smccc_test_arg *arg);\n+extern int smccc_deinit(fwts_framework *fw);\n+extern int smccc_pci_conduit_check(fwts_framework *fw, struct smccc_test_arg *arg);\n+extern int smccc_fd;\n+\n+#define\tPSCI_VERSION\t\t\t0x84000000\n+#define\tCPU_SUSPEND 0x84000001\n+#define\tCPU_OFF 0x84000002\n+#define\tCPU_ON\t\t\t\t\t0x84000003\n+#define\tAFFINITY_INFO 0x84000004\n+#define\tMIGRATE 0x84000005\n+#define\tMIGRATE_INFO_TYPE 0x84000006\n+#define\tMIGRATE_INFO_UP_CPU 0x84000007\n+#define\tSYSTEM_OFF\t\t\t\t0x84000008\n+#define\tSYSTEM_RESET 0x84000009\n+#define\tPSCI_FEATURES\t\t\t0x8400000A\n+#define\tCPU_FREEZE\t\t\t\t0x8400000B\n+#define\tCPU_DEFAULT_SUSPEND\t\t0x8400000C\n+#define\tNODE_HW_STATE\t\t\t0x8400000D\n+#define\tSYSTEM_SUSPEND\t\t\t0x8400000E\n+#define\tPSCI_SET_SUSPEND_MODE\t0x8400000F\n+#define\tPSCI_STAT_RESIDENCY\t\t0x84000010\n+#define\tPSCI_STAT_COUNT\t\t\t0x84000011\n+#define\tSYSTEM_RESET2\t\t\t0x84000012\n+#define\tMEM_PROTECT \t\t\t0x84000013\n+#define\tMEM_PROTECT_CHECK_RANGE\t0x84000014\n+#define\tSYSTEM_OFF2\t\t\t\t0x84000015\n+\n+#define PSCI_VERSION_0_2 0x00002\n+#define PSCI_VERSION_1_0 0x10000\n+#define PSCI_VERSION_1_1 0x10001\n+#define PSCI_VERSION_1_2 0x10002\n+\n+enum PSCI_ret_code {\n+ PSCI_SUCCESS = 0,\n+ PSCI_NOT_SUPPORTED = -1\n+};\n+\n+typedef struct {\n+\tconst uint32_t\tPSCI_func_id;\n+\tconst char\t*PSCI_func_id_name;\n+\tbool\t\timplemented;\n+} PSCI_func_id_t;\n+\n+static PSCI_func_id_t PSCI_func_id_list[] = {\n+ { PSCI_VERSION,\t\t\t\t\"PSCI_VERSION\",\t\t\t\tfalse },\n+ { CPU_SUSPEND,\t\t\t\t\"CPU_SUSPEND\",\t\t\t\tfalse },\n+ { CPU_OFF,\t\t\t\t\t\"CPU_OFF\",\t\t\t\t\tfalse },\n+ { CPU_ON,\t\t\t\t\t\"CPU_ON\",\t\t\t\t\tfalse },\n+ { AFFINITY_INFO,\t\t\t\"AFFINITY_INFO\",\t\t\tfalse },\n+ { MIGRATE,\t\t\t\t\t\"MIGRATE\",\t\t\t\t\tfalse },\n+ { MIGRATE_INFO_TYPE,\t\t\"MIGRATE_INFO_TYPE\",\t\tfalse },\n+ { MIGRATE_INFO_UP_CPU,\t\t\"MIGRATE_INFO_UP_CPU \",\t false },\n+ { SYSTEM_OFF,\t\t\t\t\"SYSTEM_OFF\",\t\t\t\tfalse },\n+ { SYSTEM_RESET,\t\t\t\t\"SYSTEM_RESET\",\t\t\t\tfalse },\n+ { PSCI_FEATURES,\t\t\t\"PSCI_FEATURES\",\t\t\tfalse },\n+ { CPU_FREEZE,\t\t\t\t\"CPU_FREEZE\",\t\t\t\tfalse },\n+ { CPU_DEFAULT_SUSPEND,\t\t\"CPU_DEFAULT_SUSPEND\",\t\tfalse },\n+ { NODE_HW_STATE,\t\t\t\"NODE_HW_STATE\",\t\t\tfalse },\n+ { SYSTEM_SUSPEND,\t\t\t\"SYSTEM_SUSPEND\",\t\t\tfalse },\n+ { PSCI_SET_SUSPEND_MODE,\t\"PSCI_SET_SUSPEND_MODE\",\tfalse },\n+ { PSCI_STAT_RESIDENCY,\t\t\"PSCI_STAT_RESIDENCY\",\t\tfalse },\n+ { PSCI_STAT_COUNT,\t\t\t\"PSCI_STAT_COUNT\",\t\t\tfalse },\n+ { SYSTEM_RESET2,\t\t\t\"SYSTEM_RESET2\",\t\t\tfalse },\n+ { MEM_PROTECT,\t\t\t\t\"MEM_PROTECT\",\t\t\t\tfalse },\n+ { MEM_PROTECT_CHECK_RANGE,\t\"MEM_PROTECT_CHECK_RANGE\",\tfalse },\n+ { SYSTEM_OFF2,\t\t\t\t\"SYSTEM_OFF2\",\t\t\t\tfalse }\n+};\n+\n+static uint16_t psci_major_version = 0;\n+static uint16_t psci_minor_version = 0;\n+static uint32_t psci_version = 0;\n+\n+/*\n+ * check_for_psci_support()\n+ *\tThis test checks if PSCI is supported in the system by checking the FADT table\n+ */\n+static int check_for_psci_support(fwts_framework *fw)\n+{\n+ static const fwts_acpi_gas null_gas;\n+ fwts_acpi_table_info *table = NULL;\n+ const fwts_acpi_table_fadt *fadt;\n+ int fadt_size;\n+ bool passed = true;\n+\n+\tif (fwts_acpi_find_table(fw, \"FACP\", 0, &table) != FWTS_OK) {\n+\t\tfwts_log_error(fw, \"Cannot read ACPI table FACP.\");\n+\t\treturn FWTS_ERROR;\n+\t}\n+\tif (table == NULL) {\n+\t\tfwts_log_error(fw, \"ACPI table FACP does not exist!\");\n+\t\treturn FWTS_ERROR;\n+\t}\n+\n+\tfadt = (const fwts_acpi_table_fadt *)table->data;\n+\tfadt_size = table->length;\n+\tif (fadt_size == 0) {\n+\t\tfwts_log_error(fw, \"ACPI table FACP has zero length!\");\n+\t\treturn FWTS_ERROR;\n+\t}\n+\n+ bool PSCI_compliant = fadt->arm_boot_flags & FWTS_FACP_ARM_BOOT_ARCH_PSCI_COMPLIANT;\n+ if (PSCI_compliant) {\n+ fwts_log_info_verbatim(fw, \"Arm PSCI: FADT ARM_BOOT_ARCH PSCI compliant flag is set\");\n+ }\n+ else {\n+ fwts_log_error(fw, \"Arm PSCI: FADT ARM_BOOT_ARCH PSCI compliant flag is not set.\"\n+ \" PSCI is not supported\");\n+ return FWTS_ERROR;\n+ }\n+\n+ bool HVC_Conduit = fadt->arm_boot_flags & FWTS_FACP_ARM_BOOT_ARCH_PSCI_USE_HVC;\n+ if (HVC_Conduit) {\n+ fwts_log_info_verbatim(fw, \"Arm PSCI: PSCI uses HVC conduit\");\n+ }\n+ else {\n+ fwts_log_info_verbatim(fw, \"Arm PSCI: PSCI uses SMC conduit\");\n+ }\n+\n+ if (memcmp((const void *)&fadt->sleep_control_reg,\n+\t\t (const void *)&null_gas,\n+\t\t sizeof(fwts_acpi_gas))) {\n+ passed = false;\n+\t\tfwts_log_error(fw, \"Arm PSCI: FADT SLEEP_CONTROL_REG is not zeroed (Recommended)\"\n+ \". Non-zero general register structure detected. Must be coded as all zeros\");\n+\t}\n+\n+ if (memcmp((const void *)&fadt->sleep_status_reg,\n+\t\t (const void *)&null_gas,\n+\t\t sizeof(fwts_acpi_gas))) {\n+ passed = false;\n+\t\tfwts_log_error(fw, \"Arm PSCI: FADT SLEEP_STATUS_REG is not zeroed (Recommended)\"\n+ \". Non-zero general register structure detected. Must be coded as all zeros\");\n+\t}\n+\n+ if (passed == false)\n+ {\n+ fwts_failed(fw, LOG_LEVEL_MEDIUM, \"SleepNonZero\",\n+\t\t \"FADT SLEEP_* registers field are non-zero.\");\n+ return (FWTS_ERROR);\n+ }\n+\n+ fwts_passed(fw, \"Check for Arm PSCI support test passed\");\n+ return FWTS_OK;\n+}\n+\n+\n+/*\n+ * psci_version_test()\n+ *\ttest PSCI function VERSION\n+ */\n+static int psci_version_test(fwts_framework *fw)\n+{\n+\tint ret;\n+\tstruct smccc_test_arg arg = { };\n+\n+\targ.size = sizeof(arg);\n+\targ.w[0] = PSCI_VERSION;\n+\n+\tret = ioctl(smccc_fd, SMCCC_TEST_PSCI_VERSION, &arg);\n+\tif (ret < 0) {\n+\t\tfwts_log_error(fw, \"SMCCC test driver ioctl PSCI_TEST_VERSION \"\n+\t\t\t\"failed, errno=%d (%s)\\n\", errno, strerror(errno));\n+\t\treturn FWTS_ERROR;\n+\t}\n+\tif (smccc_pci_conduit_check(fw, &arg) != FWTS_OK)\n+\t\treturn FWTS_ERROR;\n+\n+\tfwts_log_info_verbatim(fw, \" SMCCC conduit type: 0x%x ('%s')\",\n+\t\targ.conduit, smccc_pci_conduit_name(&arg));\n+\t\n+\tpsci_major_version = arg.w[0] >> 16;\n+\tpsci_minor_version = arg.w[0] & 0x0000ffff;\n+\tfwts_log_info_verbatim(fw, \"Arm PSCI: Major version: %d, Minor version: %d\",\n+\t\tpsci_major_version, psci_minor_version);\n+\n+ psci_version = (psci_major_version << 16) + psci_minor_version;\n+\n+\tfwts_passed(fw, \"Arm PSCI_VERSION test passed\");\n+\treturn FWTS_OK;\n+}\n+\n+\n+/*\n+ * get_implementation_status()\n+ * Query the implementation status by function_id\n+*/\n+static bool get_implementation_status(const uint32_t func_id)\n+{\n+ int k=0;\n+ for (k=0; k<FWTS_ARRAY_SIZE(PSCI_func_id_list); k++) {\n+ if (PSCI_func_id_list[k].PSCI_func_id == func_id)\n+ return (PSCI_func_id_list[k].implemented);\n+ }\n+\n+ return false;\n+}\n+\n+/*\n+ * psci_features_bbr_check()\n+ * Asserts based on the BBR specification rules in\n+ * Section 4.2 which refers to the table 6.9 in the\n+ * PSCI specification https://developer.arm.com/documentation/den0022/latest/\n+ * This function can be run only if SBBR or EBBR flag is set\n+ * while running FWTS\n+ */\n+\n+ static int psci_features_bbr_check(fwts_framework *fw)\n+ {\n+\tbool bbr_check_failed = false;\n+\tuint16_t assert_failed_count = 0;\n+\tint i=0;\n+\n+\tfwts_log_info_verbatim(fw, \"Arm BBR PSCI implementation check - the detected PSCI version is %d.%d\",\n+\t\tpsci_major_version, psci_minor_version);\n+\n+\tfor (i=0; i<FWTS_ARRAY_SIZE(PSCI_func_id_list); i++) {\n+\t\tif(PSCI_func_id_list[i].implemented == false) {\n+\t\t\tswitch (PSCI_func_id_list[i].PSCI_func_id) {\n+\t\t\t\t\n+ case PSCI_VERSION:\n+\t\t\t\tcase CPU_SUSPEND:\n+ case CPU_OFF:\n+ case CPU_ON:\n+ case AFFINITY_INFO:\n+ case SYSTEM_OFF:\n+ case SYSTEM_RESET: {\n+ /* These PSCI functions are mandatory for all versions */\n+\t\t\t\t bbr_check_failed = true;\n+ //fwts_log_info_verbatim(fw, \"failed: The mandatory function: %s is not implemented\",\n+\t\t // PSCI_func_id_list[i].PSCI_func_id_name);\n+\t\t\t\t}\n+\t\t\t\tbreak;\n+\t\t\t\t\n+\t\t\t\tcase PSCI_FEATURES: {\n+\t\t\t\t\t/* PSCI_FEATURES is mandatory for all PSCI versions >= 1.0 */\n+ if(psci_version >= PSCI_VERSION_1_0)\n+\t\t\t\t\t{\n+\t\t\t\t\t\tbbr_check_failed = true;\n+\t\t\t\t\t}\n+\t\t\t\t}\n+\t\t\t\tbreak;\n+ \t\t\t\t\n+\t\t\t\tdefault: {\n+\t\t\t\t\tfwts_log_info_verbatim(fw, \"Info: \\\"Optional\\\" Function: 0x%8.8\" PRIx32 \" (%s) is not Implemented.\",\n+\t\t\t\t\t\tPSCI_func_id_list[i].PSCI_func_id,\n+\t\t\t\t\t\tPSCI_func_id_list[i].PSCI_func_id_name);\n+\t\t\t\t}\n+\t\t\t}\n+\t\t\tif(bbr_check_failed == true) {\n+\t\t\t\tfwts_log_error(fw, \"failed: As per Arm BBR specifciation, \"\n+\t\t\t\t\t\"the implementation of %s is \\\"Mandatory\\\" in PSCI v%d.%d but is not implemented\"\n+\t\t\t\t\t, PSCI_func_id_list[i].PSCI_func_id_name\n+\t\t\t\t\t, psci_major_version, psci_minor_version);\n+\t\t\t\tbbr_check_failed = false;\n+\n+\t\t\t\tassert_failed_count++;\n+\t\t\t}\n+\t\t}\n+\n+ /* Additional checks */\n+ /* Some PSCI functions are mandatory conditionally. Such cases are checked below*/\n+ if(PSCI_func_id_list[i].implemented == true) {\n+ switch (PSCI_func_id_list[i].PSCI_func_id) {\n+ case MIGRATE: {\n+ /* If MIGRATE is implemented then MIGRATE_INFO_UP_CPU is mandatory*/\n+ if (false == get_implementation_status(MIGRATE_INFO_UP_CPU)) {\n+ fwts_log_error(fw, \"failed: MIGRATE is implemented however MIGRATE_INFO_UP_CPU\"\n+ \" is not implemented\");\n+ assert_failed_count++;\n+ }\n+ }\n+ break;\n+\n+ case PSCI_STAT_RESIDENCY: {\n+ /* If PSCI_STAT_RESIDENCY is implemented then PSCI_STAT_COUNT is mandatory*/\n+ if (false == get_implementation_status(PSCI_STAT_COUNT)) {\n+ fwts_log_error(fw, \"failed: PSCI_STAT_RESIDENCY is implemented however PSCI_STAT_COUNT\"\n+ \" is not implemented\");\n+ assert_failed_count++;\n+ }\n+ }\n+ break;\n+\n+ case PSCI_STAT_COUNT: {\n+ /* If PSCI_STAT_COUNT is implemented then PSCI_STAT_RESIDENCY is mandatory*/\n+ if (false == get_implementation_status(PSCI_STAT_RESIDENCY)) {\n+ fwts_log_error(fw, \"failed: PSCI_STAT_COUNT is implemented however PSCI_STAT_RESIDENCY\"\n+ \" is not implemented\");\n+ assert_failed_count++;\n+ }\n+ }\n+ break;\n+\n+ case MEM_PROTECT: {\n+ /* If MEM_PROTECT is implemented then MEM_PROTECT_CHECK_RANGE is mandatory*/\n+ if (false == get_implementation_status(MEM_PROTECT_CHECK_RANGE)) {\n+ fwts_log_error(fw, \"failed: MEM_PROTECT is implemented however MEM_PROTECT_CHECK_RANGE\"\n+ \" is not implemented\");\n+ assert_failed_count++;\n+ }\n+ }\n+ break;\n+\n+ case MEM_PROTECT_CHECK_RANGE: {\n+ /* If MEM_PROTECT_CHECK_RANGE is implemented then MEM_PROTECT is mandatory*/\n+ if (false == get_implementation_status(MEM_PROTECT)) {\n+ fwts_log_error(fw, \"failed: MEM_PROTECT_CHECK_RANGE is implemented however MEM_PROTECT\"\n+ \" is not implemented\");\n+ assert_failed_count++;\n+ }\n+ }\n+ break;\n+ }\n+\n+ }\n+\t}\n+\n+\tif (assert_failed_count > 0) {\n+\t\tfwts_log_error(fw, \"Arm SBBR check for Arm PSCI_FEATURES failed. %d checks failed\",\n+ assert_failed_count);\n+\t\treturn FWTS_ERROR;\n+\t}\n+\n+\tfwts_log_info_verbatim(fw, \"Arm SBBR check for Arm PSCI_FEATURES test passed\");\n+\treturn FWTS_OK;\n+ }\n+\n+\n+/*\n+ * psci_features_test()\n+ *\ttest PSCI function PSCI_FEATURES for each PSCI function\n+ */\n+\n+ static int psci_features_test(fwts_framework *fw)\n+ {\n+\tint ret;\n+\tint i=0;\n+\tstruct smccc_test_arg arg = { };\n+ bool feaatures_test_failed = 0;\n+\n+ if (psci_version == PSCI_VERSION_0_2) {\n+ fwts_skipped(fw, \"PSCI_FEATURES is Not Applicable for PSCI version %d.%d\",\n+ psci_major_version, psci_minor_version);\n+ return FWTS_SKIP;\n+ }\n+\n+ fwts_log_info_verbatim(fw, \"========================= PSCI_FEATURES query ===========================\");\n+ fwts_log_info_verbatim(fw, \" # Function Name Function ID Implementation Status\");\n+\tfor (i=0; i<FWTS_ARRAY_SIZE(PSCI_func_id_list); i++) {\n+\t\tmemset(&arg, 0, sizeof(arg));\n+\t\targ.size = sizeof(arg);\n+\t\targ.w[0] = PSCI_FEATURES;\n+\t\t\n+\t\t//arg.w[1] should contain, the function id of the\n+\t\t//PSCI function to query about,\n+\t\targ.w[1] = PSCI_func_id_list[i].PSCI_func_id;\n+\t\n+\t\tret = ioctl(smccc_fd, SMCCC_TEST_PSCI_FEATURES, &arg);\n+\t\tif (ret < 0) {\n+\t\t\tfwts_log_error(fw, \"SMCCC test driver ioctl PSCI_FEATURES \"\n+\t\t\t\t\"failed, ret=%d, errno=%d (%s)\\n\", ret, errno, strerror(errno));\n+\t\t\treturn FWTS_ERROR;\n+\t\t}\n+\t\tif (smccc_pci_conduit_check(fw, &arg) != FWTS_OK)\n+\t\t\treturn FWTS_ERROR;\n+\t\n+\t\tint32_t return_value = arg.w[0];\n+\n+\t\tif (return_value == PSCI_NOT_SUPPORTED) {\n+\t\t\tfwts_log_info_verbatim(fw, \"%2d %-24s 0x%8.8\" PRIx32\" NOT IMPLEMENTED\",\n+\t\t\t\ti+1,\n+\t\t\t\tPSCI_func_id_list[i].PSCI_func_id_name,\n+ PSCI_func_id_list[i].PSCI_func_id);\n+\t\t\tPSCI_func_id_list[i].implemented = false;\n+\t\t}\n+\t\telse if (((arg.w[0] >> 31) & 0x1) == 0) { /* if bit 31 is 0, then the function is supported */\n+\t\t\tfwts_log_info_verbatim(fw, \"%2d %-24s 0x%8.8\" PRIx32\" IMPLEMENTED\",\n+\t\t\t\ti+1,\n+\t\t\t\tPSCI_func_id_list[i].PSCI_func_id_name,\n+ PSCI_func_id_list[i].PSCI_func_id);\n+\t\t\tPSCI_func_id_list[i].implemented = true;\n+\t\t}\n+\t\telse if (((arg.w[0] >> 31) & 0x1) == 1) { /* if bit 31 is 1, then the implementation is incorrect as per spec*/\n+ fwts_log_info_verbatim(fw, \"%2d %-24s 0x%8.8\" PRIx32\" \"\n+ \" Error Invalid return - Please check the implementation\",\n+\t\t\t\ti+1,\n+\t\t\t\tPSCI_func_id_list[i].PSCI_func_id_name,\n+ PSCI_func_id_list[i].PSCI_func_id);\n+\t\t\tPSCI_func_id_list[i].implemented = false;\n+ feaatures_test_failed = 1;\n+\t\t}\n+\t}\n+ fwts_log_info_verbatim(fw, \"\\n\");\n+\t//if --sbbr flag or --ebbr is set, additionally call the BBR assertions function\n+\tif (fw->flags & FWTS_FLAG_SBBR || fw->flags & FWTS_FLAG_EBBR) {\n+\t if (psci_features_bbr_check(fw) == FWTS_ERROR) {\n+\t\t\tfwts_failed(fw, LOG_LEVEL_HIGH, \"psci_features_bbr_check check \",\n+\t\t \t\t\"for Arm BBR specification rules failed.\\n\");\n+ return (FWTS_ERROR);\n+\t\t}\n+\t}\n+\n+ if(feaatures_test_failed == 1) {\n+ fwts_failed(fw, LOG_LEVEL_HIGH, \"Arm Arm PSCI_FEATURES test\", \"failed\");\n+ return FWTS_ERROR;\n+ }\n+\n+\tfwts_passed(fw, \"Arm PSCI_FEATURES test passed\");\n+\treturn FWTS_OK;\n+ }\n+\n+\n+\n+static inline uint64_t read_mpidr_el1(void)\n+{\n+ uint64_t mpidr;\n+ asm volatile(\"mrs %0, mpidr_el1\" : \"=r\" (mpidr));\n+ return mpidr;\n+}\n+\n+static int affinity_info_test(fwts_framework *fw)\n+{\n+ int ret;\n+\tstruct smccc_test_arg arg = { };\n+\n+ uint64_t mpidr = read_mpidr_el1();\n+ fwts_log_info_verbatim(fw, \"Info: mpidr = 0x%16.16\" PRIx64\"\", mpidr);\n+\n+\n+ uint32_t aff0 = mpidr & 0xFF;\n+ uint32_t aff1 = (mpidr >> 8) & 0xFF;\n+ uint32_t aff2 = (mpidr >> 16) & 0xFF;\n+ /* aff3 is unused */\n+\n+ uint32_t target_affinity = 0;\n+ target_affinity |= aff0;\n+ target_affinity |= (aff1 << 8);\n+ target_affinity |= (aff2 << 16);\n+\n+\tfwts_log_info_verbatim(fw, \"Info: target_affinity = 0x%8.8\" PRIx32\"\", target_affinity);\n+\n+ uint32_t lowest_affinity_level = 0; /* All affinity levels are valid */\n+\n+ arg.size = sizeof(arg);\n+\targ.w[0] = AFFINITY_INFO;\n+ arg.w[1] = target_affinity;\n+ arg.w[2] = lowest_affinity_level;\n+\n+ ret = ioctl(smccc_fd, SMCCC_TEST_AFFINITY_INFO, &arg);\n+\tif (ret < 0) {\n+\t\tfwts_log_error(fw, \"SMCCC test driver ioctl SMCCC_TEST_AFFINITY_INFO \"\n+\t\t\t\"failed, errno=%d (%s)\\n\", errno, strerror(errno));\n+\t\treturn FWTS_ERROR;\n+\t}\n+\tif (smccc_pci_conduit_check(fw, &arg) != FWTS_OK)\n+\t\treturn FWTS_ERROR;\n+\n+\tfwts_log_info_verbatim(fw, \" SMCCC conduit type: 0x%x ('%s')\",\n+\t\targ.conduit, smccc_pci_conduit_name(&arg));\n+\t\n+ int32_t result = arg.w[0];\n+ switch(result) {\n+ case 2: {\n+ fwts_log_info_verbatim(fw,\n+ \"Test AFFINITY_INFO returned value = %d (ON_PENDING)\", result);\n+ }\n+ break;\n+ case 1: {\n+ fwts_log_info_verbatim(fw,\n+ \"Test AFFINITY_INFO returned value = %d (OFF)\", result);\n+ }\n+ break;\n+ case 0: {\n+ fwts_log_info_verbatim(fw,\n+ \"Test AFFINITY_INFO returned value = %d (ON)\", result);\n+ }\n+ break;\n+ case -2: {\n+ fwts_log_info_verbatim(fw,\n+ \"Test AFFINITY_INFO returned value = %d (INVALID_PARAMETERS)\", result);\n+ }\n+ break;\n+ case -8: {\n+ fwts_log_info_verbatim(fw,\n+ \"Test AFFINITY_INFO returned value = %d (DISABLED)\", result);\n+ }\n+ break;\n+ default: {\n+ fwts_log_info_verbatim(fw,\n+ \"Test AFFINITY_INFO returned value = %d , an unexpected value\", result);\n+ fwts_failed(fw, LOG_LEVEL_HIGH, \"Arm PSCI AFFINITY_INFO \",\n+\t\t \t\t\"test failed\");\n+ return FWTS_ERROR;\n+ }\n+ }\n+\n+\tfwts_passed(fw, \"Arm PSCI AFFINITY_INFO test passed\");\n+\treturn FWTS_OK;\n+}\n+\n+static fwts_framework_minor_test psci_tests[] = {\n+ { check_for_psci_support,\t\"Check for Arm PSCI support\" },\n+ { psci_version_test,\t\"Test PSCI_VERSION\" },\n+ { psci_features_test,\t\"Test PSCI_FEATURES\" },\n+ { affinity_info_test,\t\"Test AFFINITY_INFO\" },\n+\t{ NULL, NULL }\n+};\n+\n+static fwts_framework_ops psciops = {\n+\t.description = \"ARM64 PSCI tests.\",\n+\t.init = smccc_init,\n+\t.deinit = smccc_deinit,\n+\t.minor_tests = psci_tests\n+};\n+\n+FWTS_REGISTER(\"psci\", &psciops, FWTS_TEST_ANYTIME, FWTS_FLAG_UNSAFE | FWTS_FLAG_ROOT_PRIV)\n+\n+ #endif\ndiff --git a/src/pci/smccc/smccc.c b/src/pci/smccc/smccc.c\nindex 144a0a24839b..fc477f2417b8 100644\n--- a/src/pci/smccc/smccc.c\n+++ b/src/pci/smccc/smccc.c\n@@ -84,7 +84,7 @@ static pci_func_id_t pci_func_ids[] = {\n static const char *module_name = \"smccc_test\";\n static const char *dev_name = \"/dev/smccc_test\";\n static bool module_loaded;\n-static int smccc_fd = -1;\n+int smccc_fd = -1;\n \n typedef struct {\n \tconst uint32_t\tSMCCC_func_id;\n@@ -103,7 +103,12 @@ static SMCCC_func_id_t SMCCC_func_id_list[] = {\n static uint16_t smccc_major_version = 0;\n static uint16_t smccc_minor_version = 0;\n \n-static int smccc_init(fwts_framework *fw)\n+int smccc_init(fwts_framework *fw);\n+int smccc_deinit(fwts_framework *fw);\n+char *smccc_pci_conduit_name(struct smccc_test_arg *arg);\n+int smccc_pci_conduit_check(fwts_framework *fw, struct smccc_test_arg *arg);\n+\n+int smccc_init(fwts_framework *fw)\n {\n \tif (fwts_module_load(fw, module_name) != FWTS_OK) {\n \t\tmodule_loaded = false;\n@@ -121,7 +126,7 @@ static int smccc_init(fwts_framework *fw)\n \treturn FWTS_OK;\n }\n \n-static int smccc_deinit(fwts_framework *fw)\n+int smccc_deinit(fwts_framework *fw)\n {\n \tif (smccc_fd >= 0) {\n \t\tclose(smccc_fd);\n@@ -140,7 +145,7 @@ static int smccc_deinit(fwts_framework *fw)\n * smccc_pci_conduit_name()\n *\tmap the conduit number to human readable string\n */\n-static char *smccc_pci_conduit_name(struct smccc_test_arg *arg)\n+char *smccc_pci_conduit_name(struct smccc_test_arg *arg)\n {\n \tstatic char unknown[32];\n \n@@ -163,7 +168,7 @@ static char *smccc_pci_conduit_name(struct smccc_test_arg *arg)\n * smccc_pci_conduit_check()\n *\tcheck if conduit number is valid\n */\n-static int smccc_pci_conduit_check(fwts_framework *fw, struct smccc_test_arg *arg)\n+int smccc_pci_conduit_check(fwts_framework *fw, struct smccc_test_arg *arg)\n {\n \tswitch (arg->conduit) {\n \tcase FWTS_SMCCC_CONDUIT_HVC:\n", "prefixes": [ "1/1" ] }