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