ACK: [PATCH V3 1/2] fwts/opal: Power management DT Validation tests.
Colin Ian King
colin.king at canonical.com
Thu Apr 27 16:18:14 UTC 2017
On 27/04/17 03:59, Pridhiviraj Paidipeddi wrote:
> This patch contains testcases for below Power Processor
> energey management subsystems.
> a. cpuidle
> b. cpufreq
>
> These testcases validate the device tree properties for these two
> subsystems which are got exposed to linux from the system
> firmware(OPAL).
>
> This patch is enhanced based on the initial patch developed by shilpa
> for pstates.
> https://lists.ubuntu.com/archives/fwts-devel/2016-May/007874.html
>
> Added cpuidle states DT Validation tests.
>
> Signed-off-by: Pridhiviraj Paidipeddi <ppaidipe at linux.vnet.ibm.com>
> ---
> Changes since V2:
> - Changed fwts_dt_* functions to static inline if there is no DT
> Changes since V1:
> - Changed to tabs instead of spaces wherever it is required
> - Changed to new typedef proc_gen_t
> - For unused args, used the FWTS_UNUSED macro
> - Changed multi line comment style to fwts block comment style
> - Changed mask type from int to const inst
> ---
> src/Makefile.am | 1 +
> src/lib/include/fwts_cpu.h | 18 ++
> src/lib/include/fwts_devicetree.h | 85 ++++++++
> src/lib/src/fwts_devicetree.c | 196 ++++++++++++++++++
> src/opal/power_mgmt_info.c | 409 ++++++++++++++++++++++++++++++++++++++
> 5 files changed, 709 insertions(+)
> create mode 100644 src/opal/power_mgmt_info.c
>
> diff --git a/src/Makefile.am b/src/Makefile.am
> index c1eb285..e833554 100644
> --- a/src/Makefile.am
> +++ b/src/Makefile.am
> @@ -147,6 +147,7 @@ fwts_SOURCES = main.c \
> kernel/version/version.c \
> opal/mtd_info.c \
> opal/prd_info.c \
> + opal/power_mgmt_info.c \
> pci/aspm/aspm.c \
> pci/crs/crs.c \
> pci/maxreadreq/maxreadreq.c \
> diff --git a/src/lib/include/fwts_cpu.h b/src/lib/include/fwts_cpu.h
> index 9ab2ccf..be1c6cb 100644
> --- a/src/lib/include/fwts_cpu.h
> +++ b/src/lib/include/fwts_cpu.h
> @@ -33,6 +33,24 @@ typedef struct cpuinfo_x86 {
> char *flags; /* String containing flags */
> } fwts_cpuinfo_x86;
>
> +/* PowerPC Processor specific bits */
> +/* PVR definitions */
> +#define PVR_TYPE_P7 0x003f
> +#define PVR_TYPE_P7P 0x004a
> +#define PVR_TYPE_P8E 0x004b /* Murano */
> +#define PVR_TYPE_P8 0x004d /* Venice */
> +#define PVR_TYPE_P8NVL 0x004c /* Naples */
> +#define PVR_TYPE_P9 0x004e
> +
> +/* Processor generation */
> +typedef enum proc_gen {
> + proc_gen_unknown,
> + proc_gen_p7, /* P7 and P7+ */
> + proc_gen_p8,
> + proc_gen_p9,
> +} proc_gen_t;
> +extern proc_gen_t proc_gen;
> +
> typedef struct cpu_benchmark_result {
> bool cycles_valid;
> uint64_t loops;
> diff --git a/src/lib/include/fwts_devicetree.h b/src/lib/include/fwts_devicetree.h
> index 662f6ec..938e03d 100644
> --- a/src/lib/include/fwts_devicetree.h
> +++ b/src/lib/include/fwts_devicetree.h
> @@ -42,6 +42,28 @@
> #if FWTS_HAS_DEVICETREE
>
> int fwts_devicetree_read(fwts_framework *fwts);
> +int fwts_dt_property_read_u32(
> + void *fdt,
> + int offset,
> + const char *pname,
> + int *value);
> +int fwts_dt_property_read_u32_arr(
> + void *fdt,
> + int offset,
> + const char *pname,
> + int *value,
> + int *len);
> +int fwts_dt_property_read_u64_arr(
> + void *fdt,
> + int offset,
> + const char *pname,
> + uint64_t *value,
> + int *len);
> +int fwts_dt_stringlist_count(
> + fwts_framework *fw,
> + const void *fdt,
> + int nodeoffset,
> + const char *property);
>
> #else /* !FWTS_HAS_DEVICETREE */
> static inline int fwts_devicetree_read(fwts_framework *fwts)
> @@ -50,6 +72,67 @@ static inline int fwts_devicetree_read(fwts_framework *fwts)
>
> return FWTS_OK;
> }
> +
> +static inline int fwts_dt_property_read_u32(
> + void *fdt,
> + int offset,
> + const char *pname,
> + int *value)
> +{
> + FWTS_UNUSED(fdt);
> + FWTS_UNUSED(offset);
> + FWTS_UNUSED(pname);
> + FWTS_UNUSED(value);
> +
> + return FWTS_OK;
> +}
> +
> +static inline int fwts_dt_property_read_u32_arr(
> + void *fdt,
> + int offset,
> + const char *pname,
> + int *value,
> + int *len)
> +{
> + FWTS_UNUSED(fdt);
> + FWTS_UNUSED(offset);
> + FWTS_UNUSED(pname);
> + FWTS_UNUSED(value);
> + FWTS_UNUSED(len);
> +
> + return FWTS_OK;
> +}
> +
> +static inline int fwts_dt_property_read_u64_arr(
> + void *fdt,
> + int offset,
> + const char *pname,
> + uint64_t *value,
> + int *len)
> +{
> + FWTS_UNUSED(fdt);
> + FWTS_UNUSED(offset);
> + FWTS_UNUSED(pname);
> + FWTS_UNUSED(value);
> + FWTS_UNUSED(len);
> +
> + return FWTS_OK;
> +}
> +
> +static inline int fwts_dt_stringlist_count(
> + fwts_framework *fw,
> + const void *fdt,
> + int nodeoffset,
> + const char *property)
> +{
> + FWTS_UNUSED(fw);
> + FWTS_UNUSED(fdt);
> + FWTS_UNUSED(nodeoffset);
> + FWTS_UNUSED(property);
> +
> + return FWTS_OK;
> +}
> +
> #endif
>
> bool check_status_property_okay(fwts_framework *fw,
> @@ -60,4 +143,6 @@ int check_property_printable(fwts_framework *fw,
>
> char *hidewhitespace(char *name);
>
> +int get_proc_gen(fwts_framework *fw);
> +
> #endif
> diff --git a/src/lib/src/fwts_devicetree.c b/src/lib/src/fwts_devicetree.c
> index bf5686a..2fea3c8 100644
> --- a/src/lib/src/fwts_devicetree.c
> +++ b/src/lib/src/fwts_devicetree.c
> @@ -26,6 +26,8 @@
>
> #include <libfdt.h>
>
> +proc_gen_t proc_gen;
> +
> int fwts_devicetree_read(fwts_framework *fwts)
> {
> char *command, *data = NULL;
> @@ -171,3 +173,197 @@ char *hidewhitespace(char *name)
> return name;
>
> }
> +
> +/*
> + * fwts_dt_property_read_u32 This function reads one u32 DT property
> + * Returns FWTS_OK on success: *value will contain one int
> + * FWTS_ERROR on error: *value will contain error code
> + */
> +
> +int fwts_dt_property_read_u32(
> + void *fdt,
> + int offset,
> + const char *pname,
> + int *value)
> +{
> + int len;
> + const int *buf;
> +
> + buf = fdt_getprop(fdt, offset, pname, &len);
> + if (buf == NULL) {
> + *value = len;
> + return FWTS_ERROR;
> + }
> + *value = be32toh(*buf);
> + return FWTS_OK;
> +}
> +
> +/*
> + * This function reads DT property array of u32's
> + * Return FWTS_OK on success: *value contain full array of int's
> + * FWTS_ERROR on error: *value will contain error code which
> + * comes from *len
> + */
> +
> +int fwts_dt_property_read_u32_arr(
> + void *fdt,
> + int offset,
> + const char *pname,
> + int *value,
> + int *len)
> +{
> + int i;
> + const int *buf;
> +
> + buf = fdt_getprop(fdt, offset, pname, len);
> + if (buf == NULL) {
> + *value = *len;
> + return FWTS_ERROR;
> + }
> +
> + *len = *len / sizeof(int);
> + for (i = 0; i < *len; i++)
> + value[i] = be32toh(buf[i]);
> + return FWTS_OK;
> +}
> +
> +/*
> + * This function reads DT property array of u64's
> + * Return FWTS_OK on success: *value contain full array of u64's
> + * FWTS_ERROR on error: *value will contain error code which
> + * comes from *len
> + */
> +
> +int fwts_dt_property_read_u64_arr(
> + void *fdt,
> + int offset,
> + const char *pname,
> + uint64_t *value,
> + int *len)
> +{
> + int i;
> + const int *buf;
> +
> + buf = fdt_getprop(fdt, offset, pname, len);
> + if (buf == NULL) {
> + *value = *len;
> + return FWTS_ERROR;
> + }
> +
> + *len = *len / sizeof(uint64_t);
> + for (i = 0; i < *len; i++)
> + value[i] = be64toh(buf[i]);
> + return FWTS_OK;
> +}
> +
> +/* Get's the length of DT property string list */
> +
> +int fwts_dt_stringlist_count(
> + fwts_framework *fw,
> + const void *fdt,
> + int nodeoffset,
> + const char *property)
> +{
> + const char *list, *end;
> + int length, count = 0;
> +
> + list = fdt_getprop(fdt, nodeoffset, property, &length);
> + if (!list) {
> + fwts_failed(fw, LOG_LEVEL_HIGH, "PropertyNotFound",
> + "Failed to get property %s rc %d", property, length);
> + return FWTS_ERROR;
> + }
> +
> + end = list + length;
> +
> + while (list < end) {
> + length = strnlen(list, end - list) + 1;
> +
> + /* Check if the last string isn't properly NUL-terminated. */
> + if (list + length > end) {
> + fwts_failed(fw, LOG_LEVEL_HIGH, "NotNULLTerminated",
> + "Last string is not properly NULL terminated");
> + return FWTS_ERROR;
> + }
> +
> + list += length;
> + count++;
> + }
> +
> + return count;
> +}
> +
> +static int get_cpu_version(fwts_framework *fw, int *value)
> +{
> + const char *cpus_path = "/cpus/";
> + int offset;
> + int cpu_version; int ret;
> +
> + if (!fw->fdt) {
> + fwts_skipped(fw, "Device tree not found");
> + return FWTS_SKIP;
> + }
> +
> + offset = fdt_path_offset(fw->fdt, cpus_path);
> + if (offset < 0) {
> + fwts_failed(fw, LOG_LEVEL_MEDIUM, "DTNodeMissing",
> + "/cpus node is missing");
> + return FWTS_ERROR;
> + }
> +
> + offset = fdt_node_offset_by_prop_value(fw->fdt, -1, "device_type",
> + "cpu", sizeof("cpu"));
> + if (offset < 0) {
> + fwts_failed(fw, LOG_LEVEL_MEDIUM, "DTNodeMissing",
> + "cpu node is missing");
> + return FWTS_ERROR;
> + }
> +
> + ret = fwts_dt_property_read_u32(fw->fdt, offset,
> + "cpu-version", &cpu_version);
> + if (ret != FWTS_OK) {
> + fwts_failed(fw, LOG_LEVEL_MEDIUM, "DTPropertyReadError",
> + "Failed to read property cpu-version %s",
> + fdt_strerror(cpu_version));
> + return FWTS_ERROR;
> + }
> + *value = cpu_version;
> + return FWTS_OK;
> +}
> +
> +int get_proc_gen(fwts_framework *fw)
> +{
> + int version; int ret;
> + const int mask = 0xFFFF0000;
> + int pvr;
> +
> + ret = get_cpu_version(fw, &version);
> + if (ret != FWTS_OK) {
> + fwts_failed(fw, LOG_LEVEL_HIGH, "DTNoCPUVersion",
> + "Not able to get the CPU version");
> + return FWTS_ERROR;
> + }
> +
> + pvr = (mask & version) >> 16;
> + switch (pvr) {
> + /* Get CPU family and other flags based on PVR */
> + case PVR_TYPE_P7:
> + case PVR_TYPE_P7P:
> + proc_gen = proc_gen_p7;
> + break;
> + case PVR_TYPE_P8E:
> + case PVR_TYPE_P8:
> + proc_gen = proc_gen_p8;
> + break;
> + case PVR_TYPE_P8NVL:
> + proc_gen = proc_gen_p8;
> + break;
> + case PVR_TYPE_P9:
> + proc_gen = proc_gen_p9;
> + break;
> + default:
> + proc_gen = proc_gen_unknown;
> + }
> +
> + return FWTS_OK;
> +}
> diff --git a/src/opal/power_mgmt_info.c b/src/opal/power_mgmt_info.c
> new file mode 100644
> index 0000000..5456c43
> --- /dev/null
> +++ b/src/opal/power_mgmt_info.c
> @@ -0,0 +1,409 @@
> +/*
> + * Copyright (C) 2010-2017 Canonical
> + * Some of this work - Copyright (C) 2016-2017 IBM
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License
> + * as published by the Free Software Foundation; either version 2
> + * of the License, or (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, write to the Free Software
> + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
> + *
> + */
> +
> +#include <fcntl.h>
> +#include <stdlib.h>
> +#include <sys/ioctl.h>
> +
> +#include "fwts.h"
> +
> +#ifdef HAVE_LIBFDT
> +#include <libfdt.h>
> +#endif
> +
> +#define MAX_PSTATES 256
> +
> +#define CPUIDLE_STATE_MAX 10
> +
> +proc_gen_t proc_gen;
> +
> +static const char *power_mgt_path = "/ibm,opal/power-mgt/";
> +
> +/**
> + * cmp_pstates: Compares the given two pstates and determines which
> + * among them is associated with a higher pstate.
> + *
> + * @a, at b: The pstate ids of the pstates being compared.
> + *
> + * Returns: -1 : If pstate associated with @a is smaller than
> + * the pstate associated with @b.
> + * 0 : If pstates associated with @a and @b are equal.
> + * 1 : If pstate associated with @a is greater than
> + * the pstate associated with @b.
> + */
> +static int (*cmp_pstates)(int a, int b);
> +
> +static int cmp_positive_pstates(int a, int b)
> +{
> + if (a > b)
> + return -1;
> + else if (a < b)
> + return 1;
> +
> + return 0;
> +}
> +
> +static int cmp_negative_pstates(int a, int b)
> +{
> + return cmp_positive_pstates(b, a);
> +}
> +
> +static int validate_dt_prop_sizes(
> + fwts_framework *fw,
> + const char *prop1,
> + int prop1_len,
> + const char *prop2,
> + int prop2_len)
> +{
> + if (prop1_len == prop2_len)
> + return FWTS_OK;
> +
> + fwts_failed(fw, LOG_LEVEL_HIGH, "SizeMismatch",
> + "array sizes don't match for %s len %d and %s len %d\n",
> + prop1, prop1_len, prop2, prop2_len);
> +
> + return FWTS_ERROR;
> +}
> +
> +static int power_mgmt_init(fwts_framework *fw)
> +{
> + int ret;
> +
> + if (fwts_firmware_detect() != FWTS_FIRMWARE_OPAL) {
> + fwts_skipped(fw,
> + "The firmware type detected was non OPAL "
> + "so skipping the OPAL Power Management DT checks.");
> + return FWTS_SKIP;
> + }
> +
> + if (!fw->fdt) {
> + fwts_failed(fw, LOG_LEVEL_HIGH, "NoDeviceTree",
> + "Device tree not found");
> + return FWTS_ERROR;
> + }
> +
> + ret = get_proc_gen(fw);
> + if (ret != FWTS_OK) {
> + fwts_failed(fw, LOG_LEVEL_HIGH, "ProcGenFail",
> + "Failed to get the Processor generation");
> + return FWTS_ERROR;
> + }
> +
> + return FWTS_OK;
> +}
> +
> +
> +static int pstate_limits_test(fwts_framework *fw)
> +{
> + int pstate_min, pstate_max, pstates[MAX_PSTATES];
> + bool ok = true;
> + int nr_pstates, offset, len, ret, i;
> +
> + switch (proc_gen) {
> + case proc_gen_p8:
> + cmp_pstates = cmp_negative_pstates;
> + break;
> + case proc_gen_p9:
> + cmp_pstates = cmp_positive_pstates;
> + break;
> + default:
> + fwts_failed(fw, LOG_LEVEL_HIGH, "UnknownProcessorChip",
> + "Unknown processor generation %d", proc_gen);
> + return FWTS_ERROR;
> + }
> +
> + offset = fdt_path_offset(fw->fdt, power_mgt_path);
> + if (offset < 0) {
> + fwts_failed(fw, LOG_LEVEL_MEDIUM, "DTNodeMissing",
> + "power management node %s is missing", power_mgt_path);
> + return FWTS_ERROR;
> + }
> +
> + ret = fwts_dt_property_read_u32(fw->fdt, offset, "ibm,pstate-min",
> + &pstate_min);
> + if (ret != FWTS_OK) {
> + fwts_failed(fw, LOG_LEVEL_MEDIUM, "DTPropertyReadError",
> + "Failed to read property ibm,pstate-min %s",
> + fdt_strerror(pstate_min));
> + return FWTS_ERROR;
> + }
> +
> + ret = fwts_dt_property_read_u32(fw->fdt, offset, "ibm,pstate-max",
> + &pstate_max);
> + if (ret != FWTS_OK) {
> + fwts_failed(fw, LOG_LEVEL_MEDIUM, "DTPropertyReadError",
> + "Failed to read property ibm,pstate-max %s",
> + fdt_strerror(pstate_max));
> + return FWTS_ERROR;
> + }
> +
> + ret = fwts_dt_property_read_u32_arr(fw->fdt, offset, "ibm,pstate-ids",
> + pstates, &len);
> + if (ret != FWTS_OK) {
> + fwts_failed(fw, LOG_LEVEL_MEDIUM, "DTPropertyReadError",
> + "Failed to read property ibm,pstate-ids %s",
> + fdt_strerror(len));
> + return FWTS_ERROR;
> + }
> +
> + nr_pstates = abs(pstate_max - pstate_min) + 1;
> +
> + fwts_log_info(fw, "Pstates info: "
> + "Pstate min: %d "
> + "Pstate max: %d "
> + "nr_pstates: %d "
> + "Pstate ID's: ",
> + pstate_min, pstate_max, nr_pstates);
> +
> + for (i = 0; i < nr_pstates; i++)
> + fwts_log_info(fw, " %d ", pstates[i]);
> +
> + if (nr_pstates <= 1 || nr_pstates > 128) {
> + if (proc_gen == proc_gen_p8)
> + fwts_log_warning(fw, "Pstates range %d is not valid",
> + nr_pstates);
> + else if (proc_gen == proc_gen_p9)
> + fwts_log_warning(fw,
> + "More than 128 pstates in pstate table %d",
> + nr_pstates);
> + }
> +
> + if (len != nr_pstates)
> + fwts_log_warning(fw, "Wrong number of pstates."
> + "Expected %d pstates, found %d pstates",
> + nr_pstates, len);
> +
> + for (i = 0; i < nr_pstates; i++) {
> + if (cmp_pstates(pstate_max, pstates[i]) < 0) {
> + fwts_log_warning(fw, "Invalid Pstate id %d "
> + "greater than max pstate %d",
> + pstates[i], pstate_max);
> + ok = false;
> + }
> + if (cmp_pstates(pstates[i], pstate_min) < 0) {
> + fwts_log_warning(fw, "Invalid Pstate id %d "
> + "lesser than min pstate %d",
> + pstates[i], pstate_min);
> + ok = false;
> + }
> + }
> +
> + /* Pstates should be in monotonic descending order */
> + for (i = 0; i < nr_pstates; i++) {
> + if ((i == 0) && (cmp_pstates(pstates[i], pstate_max) != 0)) {
> + fwts_log_warning(fw, "Pstates mismatch: "
> + "Expected Pmax %d,"
> + "Actual Pmax %d",
> + pstate_max, pstates[i]);
> + ok = false;
> + } else if ((i == nr_pstates - 1) &&
> + (cmp_pstates(pstates[i], pstate_min) != 0)) {
> + fwts_log_warning(fw, "Pstates mismatch: "
> + "Expected Pmin %d,"
> + "Actual Pmin %d",
> + pstate_min, pstates[i]);
> + ok = false;
> + } else {
> + int previous_pstate;
> + previous_pstate = pstates[i-1];
> + if (cmp_pstates(pstates[i], previous_pstate) > 0) {
> + fwts_log_warning(fw, "Non monotonicity ...,"
> + "Pstate %d greater then"
> + " previous Pstate %d",
> + pstates[i], previous_pstate);
> + ok = false;
> + }
> + }
> + }
> +
> + if (!ok) {
> + fwts_failed(fw, LOG_LEVEL_MEDIUM, "CPUPstateLimitsTestFail",
> + "One or few CPU Pstates DT validation tests failed");
> + return FWTS_ERROR;
> + }
> + fwts_passed(fw, "CPU Frequency pstates are validated");
> + return FWTS_OK;
> +
> +}
> +
> +static int cpuidle_states_test(fwts_framework *fw)
> +{
> + int offset, len, test_len, ret;
> + int latency_ns[CPUIDLE_STATE_MAX];
> + int residency_ns[CPUIDLE_STATE_MAX];
> + int flags[CPUIDLE_STATE_MAX];
> + uint64_t pm_cr[CPUIDLE_STATE_MAX];
> + uint64_t pm_cr_mask[CPUIDLE_STATE_MAX];
> + bool has_stop_inst = false;
> + bool ok = true;
> + char *control_prop, *mask_prop;
> +
> + switch (proc_gen) {
> + case proc_gen_p8:
> + has_stop_inst = false;
> + control_prop = "ibm,cpu-idle-state-pmicr";
> + mask_prop = "ibm,cpu-idle-state-pmicr-mask";
> + break;
> + case proc_gen_p9:
> + has_stop_inst = true;
> + control_prop = "ibm,cpu-idle-state-psscr";
> + mask_prop = "ibm,cpu-idle-state-psscr-mask";
> + break;
> + default:
> + fwts_failed(fw, LOG_LEVEL_HIGH, "UnknownProcessorChip",
> + "Unknown processor generation %d", proc_gen);
> + return FWTS_ERROR;
> + }
> +
> + offset = fdt_path_offset(fw->fdt, power_mgt_path);
> + if (offset < 0) {
> + fwts_failed(fw, LOG_LEVEL_MEDIUM, "DTNodeMissing",
> + "power management node %s is missing", power_mgt_path);
> + return FWTS_ERROR;
> + }
> +
> + /* In P9 ibm,enabled-stop-levels present in /ibm,opal/power-mgt/ */
> + if (has_stop_inst) {
> + const int *buf;
> +
> + buf = fdt_getprop(fw->fdt, offset, "ibm,enabled-stop-levels",
> + &len);
> + if (!buf) {
> + fwts_failed(fw, LOG_LEVEL_MEDIUM, "DTPropertyMissing",
> + "ibm,enabled-stop-levels missing under %s",
> + power_mgt_path);
> + return FWTS_ERROR;
> + }
> + }
> +
> + /* Validate ibm,cpu-idle-state-flags property */
> + ret = fwts_dt_property_read_u32_arr(fw->fdt, offset,
> + "ibm,cpu-idle-state-flags", flags, &len);
> + if (ret != FWTS_OK) {
> + fwts_failed(fw, LOG_LEVEL_MEDIUM, "DTPropertyReadError",
> + "Failed to read property ibm,cpu-idle-state-flags %s",
> + fdt_strerror(len));
> + return FWTS_ERROR;
> + }
> +
> + if (len < 0) {
> + fwts_failed(fw, LOG_LEVEL_MEDIUM, "DTNoIdleStates",
> + "No idle states found in DT");
> + return FWTS_ERROR;
> + }
> +
> + if (len > CPUIDLE_STATE_MAX-1) {
> + fwts_failed(fw, LOG_LEVEL_MEDIUM, "DTMoreIdleStates",
> + "More idle states found in DT than the expected");
> + return FWTS_ERROR;
> + }
> +
> + /* Validate ibm,cpu-idle-state-latencies-ns property */
> + ret = fwts_dt_property_read_u32_arr(fw->fdt, offset,
> + "ibm,cpu-idle-state-latencies-ns",
> + latency_ns, &test_len);
> + if (ret != FWTS_OK) {
> + fwts_failed(fw, LOG_LEVEL_MEDIUM, "DTPropertyReadError",
> + "Failed to read property"
> + " ibm,cpu-idle-state-latencies-ns %s",
> + fdt_strerror(test_len));
> + return FWTS_ERROR;
> + }
> +
> + if (validate_dt_prop_sizes(fw, "ibm,cpu-idle-state-flags", len,
> + "ibm,cpu-idle-state-latencies-ns", test_len) != FWTS_OK)
> + ok = false;
> +
> + /* Validate ibm,cpu-idle-state-names property */
> + test_len = fwts_dt_stringlist_count(fw, fw->fdt, offset,
> + "ibm,cpu-idle-state-names");
> + if (test_len > 0) {
> + if (validate_dt_prop_sizes(fw, "ibm,cpu-idle-state-flags", len,
> + "ibm,cpu-idle-state-names", test_len) != FWTS_OK)
> + ok = false;
> + }
> +
> + /* Validate ibm,cpu-idle-state-residency-ns property */
> + ret = fwts_dt_property_read_u32_arr(fw->fdt, offset,
> + "ibm,cpu-idle-state-residency-ns",
> + residency_ns, &test_len);
> + if (ret != FWTS_OK) {
> + fwts_failed(fw, LOG_LEVEL_MEDIUM, "DTPropertyReadError",
> + "Failed to read property "
> + "ibm,cpu-idle-state-residency-ns %s",
> + fdt_strerror(test_len));
> + return FWTS_ERROR;
> + }
> +
> + if (validate_dt_prop_sizes(fw, "ibm,cpu-idle-state-flags", len,
> + "ibm,cpu-idle-state-residency-ns", test_len) != FWTS_OK)
> + ok = false;
> +
> + /* Validate pmicr and psscr value and mask bits */
> + ret = fwts_dt_property_read_u64_arr(fw->fdt, offset,
> + control_prop, pm_cr, &test_len);
> + if (ret != FWTS_OK) {
> + fwts_failed(fw, LOG_LEVEL_MEDIUM, "DTPropertyReadError",
> + "Failed to read property %s rc: %s", control_prop,
> + fdt_strerror(test_len));
> + return FWTS_ERROR;
> + }
> +
> + if (validate_dt_prop_sizes(fw, "ibm,cpu-idle-state-flags", len,
> + control_prop, test_len) != FWTS_OK)
> + ok = false;
> +
> + ret = fwts_dt_property_read_u64_arr(fw->fdt, offset,
> + mask_prop, pm_cr_mask, &test_len);
> + if (ret != FWTS_OK) {
> + fwts_failed(fw, LOG_LEVEL_MEDIUM, "DTPropertyReadError",
> + "Failed to read property %s rc: %s", mask_prop,
> + fdt_strerror(test_len));
> + return FWTS_ERROR;
> + }
> +
> + if (validate_dt_prop_sizes(fw, "ibm,cpu-idle-state-flags", len,
> + mask_prop, test_len) != FWTS_OK)
> + ok = false;
> +
> + if (!ok) {
> + fwts_failed(fw, LOG_LEVEL_HIGH, "CPUIDLEStatesFail",
> + "One or few CPU IDLE DT Validation tests failed");
> + return FWTS_ERROR;
> + }
> + fwts_passed(fw, "CPU IDLE States are validated");
> + return FWTS_OK;
> +}
> +
> +static fwts_framework_minor_test power_mgmt_tests[] = {
> + { pstate_limits_test, "OPAL Processor Frequency States Info" },
> + { cpuidle_states_test, "OPAL Processor Idle States Info" },
> + { NULL, NULL }
> +};
> +
> +static fwts_framework_ops power_mgmt_tests_ops = {
> + .description = "OPAL Processor Power Management DT Validation Tests",
> + .init = power_mgmt_init,
> + .minor_tests = power_mgmt_tests
> +};
> +
> +FWTS_REGISTER_FEATURES("power_mgmt", &power_mgmt_tests_ops, FWTS_TEST_EARLY,
> + FWTS_FLAG_BATCH | FWTS_FLAG_ROOT_PRIV,
> + FWTS_FW_FEATURE_DEVICETREE)
>
Thanks again.
V3 of both patches apply cleanly to the fwts repo tip and build fine for
me. They also pass static analysis tests, so ACK'd again from me.
Acked-by: Colin Ian King <colin.king at canonical.com>
More information about the fwts-devel
mailing list