[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