[PATCH 1/2] fwts/opal: power management DT Validation tests.
Colin Ian King
colin.king at canonical.com
Fri Apr 21 08:51:56 UTC 2017
Thanks for the patch. Mainly coding style issues more than anything
else. Can you fix those up and then it's good. Thanks!
Colin
On 21/04/17 06:16, 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>
> ---
> src/Makefile.am | 1 +
> src/lib/include/fwts_cpu.h | 18 ++
> src/lib/include/fwts_devicetree.h | 28 +++
> src/lib/src/fwts_devicetree.c | 178 ++++++++++++++++++
> src/opal/power_mgmt_info.c | 379 ++++++++++++++++++++++++++++++++++++++
> 5 files changed, 604 insertions(+)
> create mode 100644 src/opal/power_mgmt_info.c
>
> diff --git a/src/Makefile.am b/src/Makefile.am
> index c1eb285..4cf6201 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 \
Please use tabs rather than spaces in the Makefile.
> 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..42cca25 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 */
> +enum proc_gen {
> + proc_gen_unknown,
> + proc_gen_p7, /* P7 and P7+ */
> + proc_gen_p8,
> + proc_gen_p9,
> +};
I'd prefer it if enums are typedef'd and using the typedef'd type, e.g.
typedef enum {
proc_gen_unknown,
...
proc_gen_p9
} proc_gen_t;
> +extern enum proc_gen 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..e7c4b8c 100644
> --- a/src/lib/include/fwts_devicetree.h
> +++ b/src/lib/include/fwts_devicetree.h
> @@ -42,6 +42,14 @@
> #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 +58,24 @@ static inline int fwts_devicetree_read(fwts_framework *fwts)
>
> return FWTS_OK;
> }
> +
> +static inline int fwts_dt_property_read_u32(void *fdt __attribute__((unused)),
> + int offset __attribute__((unused)),
> + const char *pname __attribute__((unused)),
> + int *value __attribute__((unused)))
> +{
> + return FWTS_OK;
> +}
> +
> +s
> + __attribute__((unused)),
> + int offset __attribute__((unused)),
> + const char *pname __attribute__((unused)),
> + int *value __attribute__((unused)),
> + int *len __attribute__((unused)))
> +{
> + return FWTS_OK;
> +}
For unused args, please use the FWTS_UNUSED macro and also use the fwts
convention for many arguments as:
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);
etc..
}
> #endif
>
> bool check_status_property_okay(fwts_framework *fw,
> @@ -60,4 +86,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..0d7e81d 100644
> --- a/src/lib/src/fwts_devicetree.c
> +++ b/src/lib/src/fwts_devicetree.c
> @@ -26,6 +26,8 @@
>
> #include <libfdt.h>
>
> +enum proc_gen proc_gen;
> +
> int fwts_devicetree_read(fwts_framework *fwts)
> {
> char *command, *data = NULL;
> @@ -171,3 +173,179 @@ 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 u32 */
> +/* FWTS_ERROR on error---*value will contain error code */
Can you use the fwts block comment style in your patches, e.g.
/*
* fwts_dt_property_read_u32 This function reads one u32 DT property
* Returns FWTS_OK on success: *value will contain one u32
* FWTS_ERROR on error: *value will contain error code
*/
> +
> +int fwts_dt_property_read_u32(void *fdt, int offset, const char *pname,
> + int *value)
the comment states it will return one u32 in *value but the return type
is int * and not uint32_t, so there is a discrepancy there.
for long function arg declarations can you use the fwts style of:
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 */
> +/* If property exists, return FWTS_OK----- */
> +/* *value contain full arrray of u32's */
> +/* else, return FWTS_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)
the comment states it will return one an array of u32's in value but the
return type is int * and not uint32_t, so there is a discrepancy there.
> +{
> + 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 */
> +/* If property exists, return FWTS_OK----- */
> +/* *value contain full arrray of u64's */
array not arrray
> +/* else, return FWTS_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;
please replace all space indentation with tab. 1 tab per indentation
layer to keep with the fwts coding style. thanks.
> +
> + 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);
spacing between commas:
"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;
> + int mask = 0xFFFF0000;
I'd use: const int mask = 0xFFFF0000;
> + int pvr;
again, tabs for indentation please
> +
> + 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..901e870
> --- /dev/null
> +++ b/src/opal/power_mgmt_info.c
> @@ -0,0 +1,379 @@
> +/*
> + * 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
> +
> +enum proc_gen 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)
> +{
> + if (a < b)
> + return -1;
> + else if (a > b)
> + return 1;
> +
> + return 0;
> +}
how about:
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], nr_pstates;
> + bool ok = true;
> + int 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;
> +
> + 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);
> + }
Perhaps we should be using "P-states" in the warning text rather than
pstates. Just a thought.
> +
> + 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 Pmin %d,"
> + "Actual Pmin %d",
> + pstate_min, pstates[i]);
> + ok = false;
> + }
> + else if((i == nr_pstates-1) &&
> + (cmp_pstates(pstates[i], pstate_min) != 0)) {
> + fwts_log_warning(fw, "Pstates mismatch: Expected Pmax %d,"
> + "Actual Pmax %d",
> + pstate_max, 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 observed,"
> + "Pstate %d greater then previous Pstate %d",
> + pstates[i], previous_pstate);
> + ok = false;
> + }
> + }
> + }
> +
> + if (ok)
> + fwts_passed(fw, "CPU Frequency pstates are validated");
> + else
> + fwts_failed(fw, LOG_LEVEL_MEDIUM, "CPUPstateLimitsTestFail",
> + "One or few CPU Pstates DT validation tests failed");
> + 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;
> + }
> +
> + if (has_stop_inst) {
> + /* In P9 ibm,enabled-stop-levels present under /ibm,opal/power-mgt/ */
> + const int *buf;
> +
> + buf = fdt_getprop(fw->fdt, offset, "ibm,enabled-stop-levels", &len);
> + if (buf == NULL) {
> + 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 (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 (validate_dt_prop_sizes(fw, "ibm,cpu-idle-state-flags", len,
> + mask_prop, test_len) != FWTS_OK)
> + ok = false;
> +
> + if (ok)
> + fwts_passed(fw, "CPU IDLE States are validated");
> + else
> + fwts_failed(fw, LOG_LEVEL_HIGH, "CPUIDLEStatesFail",
> + "One or few CPU IDLE DT Validation tests failed");
> +
> + 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)
>
More information about the fwts-devel
mailing list