summaryrefslogtreecommitdiffstats
path: root/tools/power/cpupower/utils
diff options
context:
space:
mode:
Diffstat (limited to 'tools/power/cpupower/utils')
-rw-r--r--tools/power/cpupower/utils/builtin.h1
-rw-r--r--tools/power/cpupower/utils/cpuidle-info.c24
-rw-r--r--tools/power/cpupower/utils/cpuidle-set.c118
-rw-r--r--tools/power/cpupower/utils/cpupower.c13
-rw-r--r--tools/power/cpupower/utils/helpers/sysfs.c118
-rw-r--r--tools/power/cpupower/utils/helpers/sysfs.h10
-rw-r--r--tools/power/cpupower/utils/idle_monitor/hsw_ext_idle.c196
-rw-r--r--tools/power/cpupower/utils/idle_monitor/idle_monitors.def1
-rw-r--r--tools/power/cpupower/utils/idle_monitor/snb_idle.c4
9 files changed, 461 insertions, 24 deletions
diff --git a/tools/power/cpupower/utils/builtin.h b/tools/power/cpupower/utils/builtin.h
index c10496f..2284c8e 100644
--- a/tools/power/cpupower/utils/builtin.h
+++ b/tools/power/cpupower/utils/builtin.h
@@ -5,6 +5,7 @@ extern int cmd_set(int argc, const char **argv);
extern int cmd_info(int argc, const char **argv);
extern int cmd_freq_set(int argc, const char **argv);
extern int cmd_freq_info(int argc, const char **argv);
+extern int cmd_idle_set(int argc, const char **argv);
extern int cmd_idle_info(int argc, const char **argv);
extern int cmd_monitor(int argc, const char **argv);
diff --git a/tools/power/cpupower/utils/cpuidle-info.c b/tools/power/cpupower/utils/cpuidle-info.c
index 8145af5..75e66de 100644
--- a/tools/power/cpupower/utils/cpuidle-info.c
+++ b/tools/power/cpupower/utils/cpuidle-info.c
@@ -22,7 +22,7 @@
static void cpuidle_cpu_output(unsigned int cpu, int verbose)
{
- int idlestates, idlestate;
+ unsigned int idlestates, idlestate;
char *tmp;
printf(_ ("Analyzing CPU %d:\n"), cpu);
@@ -31,10 +31,8 @@ static void cpuidle_cpu_output(unsigned int cpu, int verbose)
if (idlestates == 0) {
printf(_("CPU %u: No idle states\n"), cpu);
return;
- } else if (idlestates <= 0) {
- printf(_("CPU %u: Can't read idle state info\n"), cpu);
- return;
}
+
printf(_("Number of idle states: %d\n"), idlestates);
printf(_("Available idle states:"));
for (idlestate = 0; idlestate < idlestates; idlestate++) {
@@ -50,10 +48,14 @@ static void cpuidle_cpu_output(unsigned int cpu, int verbose)
return;
for (idlestate = 0; idlestate < idlestates; idlestate++) {
+ int disabled = sysfs_is_idlestate_disabled(cpu, idlestate);
+ /* Disabled interface not supported on older kernels */
+ if (disabled < 0)
+ disabled = 0;
tmp = sysfs_get_idlestate_name(cpu, idlestate);
if (!tmp)
continue;
- printf("%s:\n", tmp);
+ printf("%s%s:\n", tmp, (disabled) ? " (DISABLED) " : "");
free(tmp);
tmp = sysfs_get_idlestate_desc(cpu, idlestate);
@@ -98,21 +100,13 @@ static void cpuidle_general_output(void)
static void proc_cpuidle_cpu_output(unsigned int cpu)
{
long max_allowed_cstate = 2000000000;
- int cstates, cstate;
+ unsigned int cstate, cstates;
cstates = sysfs_get_idlestate_count(cpu);
if (cstates == 0) {
- /*
- * Go on and print same useless info as you'd see with
- * cat /proc/acpi/processor/../power
- * printf(_("CPU %u: No C-states available\n"), cpu);
- * return;
- */
- } else if (cstates <= 0) {
- printf(_("CPU %u: Can't read C-state info\n"), cpu);
+ printf(_("CPU %u: No C-states info\n"), cpu);
return;
}
- /* printf("Cstates: %d\n", cstates); */
printf(_("active state: C0\n"));
printf(_("max_cstate: C%u\n"), cstates-1);
diff --git a/tools/power/cpupower/utils/cpuidle-set.c b/tools/power/cpupower/utils/cpuidle-set.c
new file mode 100644
index 0000000..c78141c
--- /dev/null
+++ b/tools/power/cpupower/utils/cpuidle-set.c
@@ -0,0 +1,118 @@
+#include <unistd.h>
+#include <stdio.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <limits.h>
+#include <string.h>
+#include <ctype.h>
+
+#include <getopt.h>
+
+#include "cpufreq.h"
+#include "helpers/helpers.h"
+#include "helpers/sysfs.h"
+
+static struct option info_opts[] = {
+ { .name = "disable", .has_arg = required_argument, .flag = NULL, .val = 'd'},
+ { .name = "enable", .has_arg = required_argument, .flag = NULL, .val = 'e'},
+ { },
+};
+
+
+int cmd_idle_set(int argc, char **argv)
+{
+ extern char *optarg;
+ extern int optind, opterr, optopt;
+ int ret = 0, cont = 1, param = 0, idlestate = 0;
+ unsigned int cpu = 0;
+
+ do {
+ ret = getopt_long(argc, argv, "d:e:", info_opts, NULL);
+ if (ret == -1)
+ break;
+ switch (ret) {
+ case '?':
+ param = '?';
+ cont = 0;
+ break;
+ case 'd':
+ if (param) {
+ param = -1;
+ cont = 0;
+ break;
+ }
+ param = ret;
+ idlestate = atoi(optarg);
+ break;
+ case 'e':
+ if (param) {
+ param = -1;
+ cont = 0;
+ break;
+ }
+ param = ret;
+ idlestate = atoi(optarg);
+ break;
+ case -1:
+ cont = 0;
+ break;
+ }
+ } while (cont);
+
+ switch (param) {
+ case -1:
+ printf(_("You can't specify more than one "
+ "output-specific argument\n"));
+ exit(EXIT_FAILURE);
+ case '?':
+ printf(_("invalid or unknown argument\n"));
+ exit(EXIT_FAILURE);
+ }
+
+ /* Default is: set all CPUs */
+ if (bitmask_isallclear(cpus_chosen))
+ bitmask_setall(cpus_chosen);
+
+ for (cpu = bitmask_first(cpus_chosen);
+ cpu <= bitmask_last(cpus_chosen); cpu++) {
+
+ if (!bitmask_isbitset(cpus_chosen, cpu))
+ continue;
+
+ switch (param) {
+
+ case 'd':
+ ret = sysfs_idlestate_disable(cpu, idlestate, 1);
+ if (ret == 0)
+ printf(_("Idlestate %u disabled on CPU %u\n"), idlestate, cpu);
+ else if (ret == -1)
+ printf(_("Idlestate %u not available on CPU %u\n"),
+ idlestate, cpu);
+ else if (ret == -2)
+ printf(_("Idlestate disabling not supported by kernel\n"));
+ else
+ printf(_("Idlestate %u not disabled on CPU %u\n"),
+ idlestate, cpu);
+ break;
+ case 'e':
+ ret = sysfs_idlestate_disable(cpu, idlestate, 0);
+ if (ret == 0)
+ printf(_("Idlestate %u enabled on CPU %u\n"), idlestate, cpu);
+ else if (ret == -1)
+ printf(_("Idlestate %u not available on CPU %u\n"),
+ idlestate, cpu);
+ else if (ret == -2)
+ printf(_("Idlestate enabling not supported by kernel\n"));
+ else
+ printf(_("Idlestate %u not enabled on CPU %u\n"),
+ idlestate, cpu);
+ break;
+ default:
+ /* Not reachable with proper args checking */
+ printf(_("Invalid or unknown argument\n"));
+ exit(EXIT_FAILURE);
+ break;
+ }
+ }
+ return EXIT_SUCCESS;
+}
diff --git a/tools/power/cpupower/utils/cpupower.c b/tools/power/cpupower/utils/cpupower.c
index 52bee59..7efc570 100644
--- a/tools/power/cpupower/utils/cpupower.c
+++ b/tools/power/cpupower/utils/cpupower.c
@@ -17,12 +17,6 @@
#include "helpers/helpers.h"
#include "helpers/bitmask.h"
-struct cmd_struct {
- const char *cmd;
- int (*main)(int, const char **);
- int needs_root;
-};
-
#define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0]))
static int cmd_help(int argc, const char **argv);
@@ -43,10 +37,17 @@ int be_verbose;
static void print_help(void);
+struct cmd_struct {
+ const char *cmd;
+ int (*main)(int, const char **);
+ int needs_root;
+};
+
static struct cmd_struct commands[] = {
{ "frequency-info", cmd_freq_info, 0 },
{ "frequency-set", cmd_freq_set, 1 },
{ "idle-info", cmd_idle_info, 0 },
+ { "idle-set", cmd_idle_set, 1 },
{ "set", cmd_set, 1 },
{ "info", cmd_info, 0 },
{ "monitor", cmd_monitor, 0 },
diff --git a/tools/power/cpupower/utils/helpers/sysfs.c b/tools/power/cpupower/utils/helpers/sysfs.c
index 38ab916..5cdc600 100644
--- a/tools/power/cpupower/utils/helpers/sysfs.c
+++ b/tools/power/cpupower/utils/helpers/sysfs.c
@@ -89,6 +89,33 @@ int sysfs_is_cpu_online(unsigned int cpu)
/* CPUidle idlestate specific /sys/devices/system/cpu/cpuX/cpuidle/ access */
+
+/* CPUidle idlestate specific /sys/devices/system/cpu/cpuX/cpuidle/ access */
+
+/*
+ * helper function to check whether a file under "../cpuX/cpuidle/stateX/" dir
+ * exists.
+ * For example the functionality to disable c-states was introduced in later
+ * kernel versions, this function can be used to explicitly check for this
+ * feature.
+ *
+ * returns 1 if the file exists, 0 otherwise.
+ */
+unsigned int sysfs_idlestate_file_exists(unsigned int cpu,
+ unsigned int idlestate,
+ const char *fname)
+{
+ char path[SYSFS_PATH_MAX];
+ struct stat statbuf;
+
+
+ snprintf(path, sizeof(path), PATH_TO_CPU "cpu%u/cpuidle/state%u/%s",
+ cpu, idlestate, fname);
+ if (stat(path, &statbuf) != 0)
+ return 0;
+ return 1;
+}
+
/*
* helper function to read file from /sys into given buffer
* fname is a relative path under "cpuX/cpuidle/stateX/" dir
@@ -121,6 +148,40 @@ unsigned int sysfs_idlestate_read_file(unsigned int cpu, unsigned int idlestate,
return (unsigned int) numread;
}
+/*
+ * helper function to write a new value to a /sys file
+ * fname is a relative path under "../cpuX/cpuidle/cstateY/" dir
+ *
+ * Returns the number of bytes written or 0 on error
+ */
+static
+unsigned int sysfs_idlestate_write_file(unsigned int cpu,
+ unsigned int idlestate,
+ const char *fname,
+ const char *value, size_t len)
+{
+ char path[SYSFS_PATH_MAX];
+ int fd;
+ ssize_t numwrite;
+
+ snprintf(path, sizeof(path), PATH_TO_CPU "cpu%u/cpuidle/state%u/%s",
+ cpu, idlestate, fname);
+
+ fd = open(path, O_WRONLY);
+ if (fd == -1)
+ return 0;
+
+ numwrite = write(fd, value, len);
+ if (numwrite < 1) {
+ close(fd);
+ return 0;
+ }
+
+ close(fd);
+
+ return (unsigned int) numwrite;
+}
+
/* read access to files which contain one numeric value */
enum idlestate_value {
@@ -128,6 +189,7 @@ enum idlestate_value {
IDLESTATE_POWER,
IDLESTATE_LATENCY,
IDLESTATE_TIME,
+ IDLESTATE_DISABLE,
MAX_IDLESTATE_VALUE_FILES
};
@@ -136,6 +198,7 @@ static const char *idlestate_value_files[MAX_IDLESTATE_VALUE_FILES] = {
[IDLESTATE_POWER] = "power",
[IDLESTATE_LATENCY] = "latency",
[IDLESTATE_TIME] = "time",
+ [IDLESTATE_DISABLE] = "disable",
};
static unsigned long long sysfs_idlestate_get_one_value(unsigned int cpu,
@@ -205,8 +268,59 @@ static char *sysfs_idlestate_get_one_string(unsigned int cpu,
return result;
}
+/*
+ * Returns:
+ * 1 if disabled
+ * 0 if enabled
+ * -1 if idlestate is not available
+ * -2 if disabling is not supported by the kernel
+ */
+int sysfs_is_idlestate_disabled(unsigned int cpu,
+ unsigned int idlestate)
+{
+ if (sysfs_get_idlestate_count(cpu) < idlestate)
+ return -1;
+
+ if (!sysfs_idlestate_file_exists(cpu, idlestate,
+ idlestate_value_files[IDLESTATE_DISABLE]))
+ return -2;
+ return sysfs_idlestate_get_one_value(cpu, idlestate, IDLESTATE_DISABLE);
+}
+
+/*
+ * Pass 1 as last argument to disable or 0 to enable the state
+ * Returns:
+ * 0 on success
+ * negative values on error, for example:
+ * -1 if idlestate is not available
+ * -2 if disabling is not supported by the kernel
+ * -3 No write access to disable/enable C-states
+ */
+int sysfs_idlestate_disable(unsigned int cpu,
+ unsigned int idlestate,
+ unsigned int disable)
+{
+ char value[SYSFS_PATH_MAX];
+ int bytes_written;
+
+ if (sysfs_get_idlestate_count(cpu) < idlestate)
+ return -1;
+
+ if (!sysfs_idlestate_file_exists(cpu, idlestate,
+ idlestate_value_files[IDLESTATE_DISABLE]))
+ return -2;
+
+ snprintf(value, SYSFS_PATH_MAX, "%u", disable);
+
+ bytes_written = sysfs_idlestate_write_file(cpu, idlestate, "disable",
+ value, sizeof(disable));
+ if (bytes_written)
+ return 0;
+ return -3;
+}
+
unsigned long sysfs_get_idlestate_latency(unsigned int cpu,
- unsigned int idlestate)
+ unsigned int idlestate)
{
return sysfs_idlestate_get_one_value(cpu, idlestate, IDLESTATE_LATENCY);
}
@@ -238,7 +352,7 @@ char *sysfs_get_idlestate_desc(unsigned int cpu, unsigned int idlestate)
* Negativ in error case
* Zero if cpuidle does not export any C-states
*/
-int sysfs_get_idlestate_count(unsigned int cpu)
+unsigned int sysfs_get_idlestate_count(unsigned int cpu)
{
char file[SYSFS_PATH_MAX];
struct stat statbuf;
diff --git a/tools/power/cpupower/utils/helpers/sysfs.h b/tools/power/cpupower/utils/helpers/sysfs.h
index 8cb797b..d28f11f 100644
--- a/tools/power/cpupower/utils/helpers/sysfs.h
+++ b/tools/power/cpupower/utils/helpers/sysfs.h
@@ -7,8 +7,16 @@
extern unsigned int sysfs_read_file(const char *path, char *buf, size_t buflen);
+extern unsigned int sysfs_idlestate_file_exists(unsigned int cpu,
+ unsigned int idlestate,
+ const char *fname);
+
extern int sysfs_is_cpu_online(unsigned int cpu);
+extern int sysfs_is_idlestate_disabled(unsigned int cpu,
+ unsigned int idlestate);
+extern int sysfs_idlestate_disable(unsigned int cpu, unsigned int idlestate,
+ unsigned int disable);
extern unsigned long sysfs_get_idlestate_latency(unsigned int cpu,
unsigned int idlestate);
extern unsigned long sysfs_get_idlestate_usage(unsigned int cpu,
@@ -19,7 +27,7 @@ extern char *sysfs_get_idlestate_name(unsigned int cpu,
unsigned int idlestate);
extern char *sysfs_get_idlestate_desc(unsigned int cpu,
unsigned int idlestate);
-extern int sysfs_get_idlestate_count(unsigned int cpu);
+extern unsigned int sysfs_get_idlestate_count(unsigned int cpu);
extern char *sysfs_get_cpuidle_governor(void);
extern char *sysfs_get_cpuidle_driver(void);
diff --git a/tools/power/cpupower/utils/idle_monitor/hsw_ext_idle.c b/tools/power/cpupower/utils/idle_monitor/hsw_ext_idle.c
new file mode 100644
index 0000000..ebeaba6
--- /dev/null
+++ b/tools/power/cpupower/utils/idle_monitor/hsw_ext_idle.c
@@ -0,0 +1,196 @@
+/*
+ * (C) 2010,2011 Thomas Renninger <trenn@suse.de>, Novell Inc.
+ *
+ * Licensed under the terms of the GNU GPL License version 2.
+ *
+ * Based on SandyBridge monitor. Implements the new package C-states
+ * (PC8, PC9, PC10) coming with a specific Haswell (family 0x45) CPU.
+ */
+
+#if defined(__i386__) || defined(__x86_64__)
+
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "helpers/helpers.h"
+#include "idle_monitor/cpupower-monitor.h"
+
+#define MSR_PKG_C8_RESIDENCY 0x00000630
+#define MSR_PKG_C9_RESIDENCY 0x00000631
+#define MSR_PKG_C10_RESIDENCY 0x00000632
+
+#define MSR_TSC 0x10
+
+enum intel_hsw_ext_id { PC8 = 0, PC9, PC10, HSW_EXT_CSTATE_COUNT,
+ TSC = 0xFFFF };
+
+static int hsw_ext_get_count_percent(unsigned int self_id, double *percent,
+ unsigned int cpu);
+
+static cstate_t hsw_ext_cstates[HSW_EXT_CSTATE_COUNT] = {
+ {
+ .name = "PC8",
+ .desc = N_("Processor Package C8"),
+ .id = PC8,
+ .range = RANGE_PACKAGE,
+ .get_count_percent = hsw_ext_get_count_percent,
+ },
+ {
+ .name = "PC9",
+ .desc = N_("Processor Package C9"),
+ .desc = N_("Processor Package C2"),
+ .id = PC9,
+ .range = RANGE_PACKAGE,
+ .get_count_percent = hsw_ext_get_count_percent,
+ },
+ {
+ .name = "PC10",
+ .desc = N_("Processor Package C10"),
+ .id = PC10,
+ .range = RANGE_PACKAGE,
+ .get_count_percent = hsw_ext_get_count_percent,
+ },
+};
+
+static unsigned long long tsc_at_measure_start;
+static unsigned long long tsc_at_measure_end;
+static unsigned long long *previous_count[HSW_EXT_CSTATE_COUNT];
+static unsigned long long *current_count[HSW_EXT_CSTATE_COUNT];
+/* valid flag for all CPUs. If a MSR read failed it will be zero */
+static int *is_valid;
+
+static int hsw_ext_get_count(enum intel_hsw_ext_id id, unsigned long long *val,
+ unsigned int cpu)
+{
+ int msr;
+
+ switch (id) {
+ case PC8:
+ msr = MSR_PKG_C8_RESIDENCY;
+ break;
+ case PC9:
+ msr = MSR_PKG_C9_RESIDENCY;
+ break;
+ case PC10:
+ msr = MSR_PKG_C10_RESIDENCY;
+ break;
+ case TSC:
+ msr = MSR_TSC;
+ break;
+ default:
+ return -1;
+ };
+ if (read_msr(cpu, msr, val))
+ return -1;
+ return 0;
+}
+
+static int hsw_ext_get_count_percent(unsigned int id, double *percent,
+ unsigned int cpu)
+{
+ *percent = 0.0;
+
+ if (!is_valid[cpu])
+ return -1;
+
+ *percent = (100.0 *
+ (current_count[id][cpu] - previous_count[id][cpu])) /
+ (tsc_at_measure_end - tsc_at_measure_start);
+
+ dprint("%s: previous: %llu - current: %llu - (%u)\n",
+ hsw_ext_cstates[id].name, previous_count[id][cpu],
+ current_count[id][cpu], cpu);
+
+ dprint("%s: tsc_diff: %llu - count_diff: %llu - percent: %2.f (%u)\n",
+ hsw_ext_cstates[id].name,
+ (unsigned long long) tsc_at_measure_end - tsc_at_measure_start,
+ current_count[id][cpu] - previous_count[id][cpu],
+ *percent, cpu);
+
+ return 0;
+}
+
+static int hsw_ext_start(void)
+{
+ int num, cpu;
+ unsigned long long val;
+
+ for (num = 0; num < HSW_EXT_CSTATE_COUNT; num++) {
+ for (cpu = 0; cpu < cpu_count; cpu++) {
+ hsw_ext_get_count(num, &val, cpu);
+ previous_count[num][cpu] = val;
+ }
+ }
+ hsw_ext_get_count(TSC, &tsc_at_measure_start, 0);
+ return 0;
+}
+
+static int hsw_ext_stop(void)
+{
+ unsigned long long val;
+ int num, cpu;
+
+ hsw_ext_get_count(TSC, &tsc_at_measure_end, 0);
+
+ for (num = 0; num < HSW_EXT_CSTATE_COUNT; num++) {
+ for (cpu = 0; cpu < cpu_count; cpu++) {
+ is_valid[cpu] = !hsw_ext_get_count(num, &val, cpu);
+ current_count[num][cpu] = val;
+ }
+ }
+ return 0;
+}
+
+struct cpuidle_monitor intel_hsw_ext_monitor;
+
+static struct cpuidle_monitor *hsw_ext_register(void)
+{
+ int num;
+
+ if (cpupower_cpu_info.vendor != X86_VENDOR_INTEL
+ || cpupower_cpu_info.family != 6)
+ return NULL;
+
+ switch (cpupower_cpu_info.model) {
+ case 0x45: /* HSW */
+ break;
+ default:
+ return NULL;
+ }
+
+ is_valid = calloc(cpu_count, sizeof(int));
+ for (num = 0; num < HSW_EXT_CSTATE_COUNT; num++) {
+ previous_count[num] = calloc(cpu_count,
+ sizeof(unsigned long long));
+ current_count[num] = calloc(cpu_count,
+ sizeof(unsigned long long));
+ }
+ intel_hsw_ext_monitor.name_len = strlen(intel_hsw_ext_monitor.name);
+ return &intel_hsw_ext_monitor;
+}
+
+void hsw_ext_unregister(void)
+{
+ int num;
+ free(is_valid);
+ for (num = 0; num < HSW_EXT_CSTATE_COUNT; num++) {
+ free(previous_count[num]);
+ free(current_count[num]);
+ }
+}
+
+struct cpuidle_monitor intel_hsw_ext_monitor = {
+ .name = "HaswellExtended",
+ .hw_states = hsw_ext_cstates,
+ .hw_states_num = HSW_EXT_CSTATE_COUNT,
+ .start = hsw_ext_start,
+ .stop = hsw_ext_stop,
+ .do_register = hsw_ext_register,
+ .unregister = hsw_ext_unregister,
+ .needs_root = 1,
+ .overflow_s = 922000000 /* 922337203 seconds TSC overflow
+ at 20GHz */
+};
+#endif /* defined(__i386__) || defined(__x86_64__) */
diff --git a/tools/power/cpupower/utils/idle_monitor/idle_monitors.def b/tools/power/cpupower/utils/idle_monitor/idle_monitors.def
index e3f8d9b..0d6ba4d 100644
--- a/tools/power/cpupower/utils/idle_monitor/idle_monitors.def
+++ b/tools/power/cpupower/utils/idle_monitor/idle_monitors.def
@@ -2,6 +2,7 @@
DEF(amd_fam14h)
DEF(intel_nhm)
DEF(intel_snb)
+DEF(intel_hsw_ext)
DEF(mperf)
#endif
DEF(cpuidle_sysfs)
diff --git a/tools/power/cpupower/utils/idle_monitor/snb_idle.c b/tools/power/cpupower/utils/idle_monitor/snb_idle.c
index a99b43b..efc8a69 100644
--- a/tools/power/cpupower/utils/idle_monitor/snb_idle.c
+++ b/tools/power/cpupower/utils/idle_monitor/snb_idle.c
@@ -155,6 +155,10 @@ static struct cpuidle_monitor *snb_register(void)
case 0x2D: /* SNB Xeon */
case 0x3A: /* IVB */
case 0x3E: /* IVB Xeon */
+ case 0x3C: /* HSW */
+ case 0x3F: /* HSW */
+ case 0x45: /* HSW */
+ case 0x46: /* HSW */
break;
default:
return NULL;
OpenPOWER on IntegriCloud