aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMathieu Briand <mathieu.briand@linaro.org>2012-05-11 11:29:18 +0200
committerAndrey Konovalov <andrey.konovalov@linaro.org>2013-05-25 13:04:35 +0400
commit0a6da5300c989d978190637506a3a064d3a52492 (patch)
treeac60c00fc5a80cce9ae8579d73714d1478de5fac
parentfd54d96fcaed9c77f1d4fe7d3ba14f8ac4dcee3f (diff)
cpufreq/arm-bl-cpufreq: unit tests
Add in-modules tests on arm-bl-cpufreq cpufreq driver. To build the tests, add the following config option: ARM_BL_CPUFREQ_TEST=y The tests will run when the driver is loaded, but they are not run by default. To run the tests, you need to pass the option test_config=1 to the arm-bl-cpufreq driver when loading it. Signed-off-by: Mathieu Briand <mathieu.briand@linaro.org> Signed-off-by: Dave Martin <dave.martin@linaro.org> Signed-off-by: Nicolas Pitre <nicolas.pitre@linaro.org>
-rw-r--r--drivers/cpufreq/Kconfig.arm9
-rw-r--r--drivers/cpufreq/arm-bl-cpufreq.c45
-rw-r--r--drivers/cpufreq/arm-bl-cpufreq.h37
-rw-r--r--drivers/cpufreq/arm-bl-cpufreq_tests.c652
4 files changed, 725 insertions, 18 deletions
diff --git a/drivers/cpufreq/Kconfig.arm b/drivers/cpufreq/Kconfig.arm
index 97dd3fc49a3..204812a5b92 100644
--- a/drivers/cpufreq/Kconfig.arm
+++ b/drivers/cpufreq/Kconfig.arm
@@ -14,6 +14,15 @@ config ARM_BL_CPUFREQ
If unsure, say N.
+config ARM_BL_CPUFREQ_TEST
+ depends on ARM_BL_CPUFREQ
+ bool "Unit testing on cpufreq interface for the ARM big.LITTLE switcher"
+ help
+ Make tests on the cpufreq interface for the ARM big.LITTLE
+ switcher before loading it.
+
+ If unsure, say N.
+
config ARM_OMAP2PLUS_CPUFREQ
bool "TI OMAP2+"
depends on ARCH_OMAP2PLUS
diff --git a/drivers/cpufreq/arm-bl-cpufreq.c b/drivers/cpufreq/arm-bl-cpufreq.c
index 0d7d0fcd4e3..bc633f2d7b0 100644
--- a/drivers/cpufreq/arm-bl-cpufreq.c
+++ b/drivers/cpufreq/arm-bl-cpufreq.c
@@ -18,7 +18,8 @@
*/
#define MODULE_NAME "arm-bl-cpufreq"
-#define pr_fmt(fmt) MODULE_NAME ": " fmt
+#define __module_pr_fmt(prefix, fmt) MODULE_NAME ": " prefix fmt
+#define pr_fmt(fmt) __module_pr_fmt("", fmt)
#include <linux/bug.h>
#include <linux/cache.h>
@@ -32,6 +33,17 @@
#include <asm/bL_switcher.h>
+#include "arm-bl-cpufreq.h"
+
+/*
+ * Include tests prototypes and includes
+ * We need to include this file a second time with ARM_BL_CPUFREQ_DEFINE_TESTS
+ * defined to include functions body.
+ */
+#include "arm-bl-cpufreq_tests.c"
+
+#define ARM_BL_CPUFREQ_DEFINE_TESTS
+#include "arm-bl-cpufreq_tests.c"
/* Dummy frequencies representing the big and little clusters: */
#define FREQ_BIG 1000000
@@ -41,22 +53,6 @@
#define CLUSTER_BIG 0
#define CLUSTER_LITTLE 1
-/*
- * Switch latency advertised to cpufreq. This value is bogus and will
- * need to be properly calibrated when running on real hardware.
- */
-#define BL_CPUFREQ_FAKE_LATENCY 1
-
-static struct cpufreq_frequency_table __read_mostly bl_freqs[] = {
- { CLUSTER_BIG, FREQ_BIG },
- { CLUSTER_LITTLE, FREQ_LITTLE },
- { 0, CPUFREQ_TABLE_END },
-};
-
-/* Cached current cluster for each CPU to save on IPIs */
-static DEFINE_PER_CPU(unsigned int, cpu_cur_cluster);
-
-
/* Miscellaneous helpers */
static unsigned int entry_to_freq(
@@ -237,13 +233,26 @@ static int __init bl_cpufreq_module_init(void)
{
int err;
+ /* test_config :
+ * - 0: Do not run tests
+ * - 1: Run tests and then register cpufreq driver if tests passed
+ */
+ if ((test_config > 0) && (pre_init_tests() != 0))
+ return -EINVAL;
+
err = cpufreq_register_driver(&bl_cpufreq_driver);
if(err)
pr_info("cpufreq backend driver registration failed (%d)\n",
err);
- else
+ else {
pr_info("cpufreq backend driver registered.\n");
+ if ((test_config > 0) && (post_init_tests() != 0)) {
+ cpufreq_unregister_driver(&bl_cpufreq_driver);
+ return -EINVAL;
+ }
+ }
+
return err;
}
module_init(bl_cpufreq_module_init);
diff --git a/drivers/cpufreq/arm-bl-cpufreq.h b/drivers/cpufreq/arm-bl-cpufreq.h
new file mode 100644
index 00000000000..b13bb8c543d
--- /dev/null
+++ b/drivers/cpufreq/arm-bl-cpufreq.h
@@ -0,0 +1,37 @@
+#ifndef ARM_BL_CPUFREQ_H
+#define ARM_BL_CPUFREQ_H
+
+/* Dummy frequencies representing the big and little clusters: */
+#define FREQ_BIG 1000000
+#define FREQ_LITTLE 100000
+
+/* Cluster numbers */
+#define CLUSTER_BIG 0
+#define CLUSTER_LITTLE 1
+
+/*
+ * Switch latency advertised to cpufreq. This value is bogus and will
+ * need to be properly calibrated when running on real hardware.
+ */
+#define BL_CPUFREQ_FAKE_LATENCY 1
+
+static struct cpufreq_frequency_table __read_mostly bl_freqs[] = {
+ { CLUSTER_BIG, FREQ_BIG },
+ { CLUSTER_LITTLE, FREQ_LITTLE },
+ { 0, CPUFREQ_TABLE_END },
+};
+
+/* Cached current cluster for each CPU to save on IPIs */
+static DEFINE_PER_CPU(unsigned int, cpu_cur_cluster);
+
+static unsigned int entry_to_freq(struct cpufreq_frequency_table const *entry);
+static unsigned int entry_to_cluster(
+ struct cpufreq_frequency_table const *entry);
+static struct cpufreq_frequency_table const *find_entry_by_cluster(int cluster);
+static unsigned int cluster_to_freq(int cluster);
+static int get_current_cluster(unsigned int cpu);
+static int get_current_cached_cluster(unsigned int cpu);
+static unsigned int get_current_freq(unsigned int cpu);
+static unsigned int bl_cpufreq_get(unsigned int cpu);
+
+#endif /* ! ARM_BL_CPUFREQ_H */
diff --git a/drivers/cpufreq/arm-bl-cpufreq_tests.c b/drivers/cpufreq/arm-bl-cpufreq_tests.c
new file mode 100644
index 00000000000..da349e165f4
--- /dev/null
+++ b/drivers/cpufreq/arm-bl-cpufreq_tests.c
@@ -0,0 +1,652 @@
+/*
+ * arm-bl-cpufreqtests.c: Unit tests on the simple cpufreq backend for the
+ * ARM big.LITTLE switcher
+ * Copyright (C) 2012 Linaro Limited
+ *
+ * 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.
+ */
+
+#ifndef ARM_BL_CPUFREQ_DEFINE_TESTS
+#include <linux/cpufreq.h>
+#include <linux/module.h>
+#include <linux/printk.h>
+#include <linux/delay.h>
+#include <linux/sched.h>
+
+#include "arm-bl-cpufreq.h"
+
+static short int test_config;
+
+static int pre_init_tests(void);
+static int post_init_tests(void);
+
+#else /* ! ARM_BL_CPUFREQ_DEFINE_TESTS */
+
+#ifdef CONFIG_ARM_BL_CPUFREQ_TEST
+
+#ifdef pr_fmt
+#undef pr_fmt
+#endif
+#define pr_fmt(fmt) __module_pr_fmt("[test] ", fmt)
+
+#define SWITCH_DELAY 10
+#define SWITCH_TRANSITION_DELAY 200
+#define POST_INIT_TESTS_DELAY 100
+
+static DECLARE_WAIT_QUEUE_HEAD(test_wq);
+static int test_transition_count;
+unsigned int test_transition_freq;
+
+module_param(test_config, short, 1);
+MODULE_PARM_DESC(test_config, "Make tests before registering cpufreq driver. (0 : no tests, 1 : tests and registering driver (default))");
+
+static struct cpufreq_frequency_table const *get_other_entry(
+ struct cpufreq_frequency_table const *entry)
+{
+ if (entry_to_cluster(entry) == CLUSTER_BIG)
+ return find_entry_by_cluster(CLUSTER_LITTLE);
+ else
+ return find_entry_by_cluster(CLUSTER_BIG);
+}
+
+static int test_cpufreq_frequency_table(void)
+{
+ int nTest = 0, failCount = 0, testResult = 0;
+ struct cpufreq_frequency_table const *entry;
+
+ /* Get big and little cpufreq_frequency_table entries and check
+ * entry_to_freq() and entry_to_cluster() return corresponding
+ * frequencies and cluster id.
+ */
+ entry = find_entry_by_cluster(CLUSTER_BIG);
+
+ ++nTest;
+ if (entry_to_freq(entry) != FREQ_BIG) {
+ testResult = 0;
+ ++failCount;
+ } else
+ testResult = 1;
+ pr_info("name=pre-init/frequency_table/%d:entry_to_freq(big) result=%s\n",
+ nTest, (testResult ? "PASS" : "FAIL"));
+
+ ++nTest;
+ if (entry_to_cluster(entry) != CLUSTER_BIG) {
+ testResult = 0;
+ ++failCount;
+ } else
+ testResult = 1;
+ pr_info("name=pre-init/frequency_table/%d:entry_to_cluster(big) result=%s\n",
+ nTest, (testResult ? "PASS" : "FAIL"));
+
+ entry = find_entry_by_cluster(CLUSTER_LITTLE);
+
+ ++nTest;
+ if (entry_to_freq(entry) != FREQ_LITTLE) {
+ testResult = 0;
+ ++failCount;
+ } else
+ testResult = 1;
+ pr_info("name=pre-init/frequency_table/%d:entry_to_freq(little) result=%s\n",
+ nTest, (testResult ? "PASS" : "FAIL"));
+
+ ++nTest;
+ if (entry_to_cluster(entry) != CLUSTER_LITTLE) {
+ testResult = 0;
+ ++failCount;
+ } else
+ testResult = 1;
+ pr_info("name=pre-init/frequency_table/%d:entry_to_cluster(little) result=%s\n",
+ nTest, (testResult ? "PASS" : "FAIL"));
+
+ pr_info("name=pre-init/frequency_table run=%d result=%s pass=%d fail=%d\n",
+ nTest, (failCount == 0 ? "PASS" : "FAIL"),
+ (nTest - failCount), failCount);
+ if (failCount != 0)
+ return -1;
+
+ return 0;
+}
+
+static int test_cluster_to_freq(void)
+{
+ int nTest = 0, failCount = 0, testResult = 0;
+
+ /* Check if test_cluster_to_freq() result is consistent, ie :
+ * - CLUSTER_BIG => FREQ_BIG
+ * - CLUSTER_LITTLE => FREQ_LITTLE
+ */
+ ++nTest;
+ if (cluster_to_freq(CLUSTER_BIG) != FREQ_BIG) {
+ testResult = 0;
+ ++failCount;
+ } else
+ testResult = 1;
+ pr_info("name=pre-init/cluster_to_freq/%d:cluster_to_freq(big) result=%s\n",
+ nTest, (testResult ? "PASS" : "FAIL"));
+
+ ++nTest;
+ if (cluster_to_freq(CLUSTER_LITTLE) != FREQ_LITTLE) {
+ testResult = 0;
+ ++failCount;
+ } else
+ testResult = 1;
+ pr_info("name=pre-init/cluster_to_freq/%d:cluster_to_freq(little) result=%s\n",
+ nTest, (testResult ? "PASS" : "FAIL"));
+
+ pr_info("name=pre-init/cluster_to_freq run=%d result=%s pass=%d fail=%d\n",
+ nTest, (failCount == 0 ? "PASS" : "FAIL"),
+ (nTest - failCount), failCount);
+ if (failCount != 0)
+ return -1;
+
+ return 0;
+}
+
+static int test_get_current_cluster(void)
+{
+ int nTest = 0, failCount = 0, testResult = 0;
+ unsigned int cluster, cpu;
+
+ /* Check if get_current_cluster() return a consistent value, ie
+ * CLUSTER_BIG or CLUSTER_LITTLE
+ */
+ for_each_cpu(cpu, cpu_present_mask) {
+ cluster = get_current_cluster(cpu);
+ ++nTest;
+ if ((cluster != CLUSTER_BIG) && (cluster != CLUSTER_LITTLE)) {
+ testResult = 0;
+ ++failCount;
+ } else
+ testResult = 1;
+ pr_info("name=pre-init/get_current_cluster/%d:get_current_cluster(%u) result=%s\n",
+ nTest, cpu, (testResult ? "PASS" : "FAIL"));
+ }
+
+ pr_info("name=pre-init/get_current_cluster run=%d result=%s pass=%d fail=%d\n",
+ nTest, (failCount == 0 ? "PASS" : "FAIL"),
+ (nTest - failCount), failCount);
+ if (failCount != 0)
+ return -1;
+
+ return 0;
+}
+
+static int test_bl_cpufreq_get(void)
+{
+ int nTest = 0, failCount = 0, testResult = 0;
+ unsigned int cpu;
+ struct cpufreq_frequency_table const *other_entry = NULL;
+ struct cpufreq_frequency_table const *origin_entry = NULL;
+ struct cpufreq_policy *policy = NULL;
+
+ /*
+ * Check bl_cpufreq_get() return value : for all cores value has to be
+ * the frequency of origin_entry
+ */
+ for_each_cpu(cpu, cpu_present_mask) {
+ policy = cpufreq_cpu_get(cpu);
+ origin_entry = find_entry_by_cluster(get_current_cluster(cpu));
+ other_entry = get_other_entry(origin_entry);
+
+ ++nTest;
+ if (bl_cpufreq_get(cpu) != entry_to_freq(origin_entry)) {
+ testResult = 0;
+ ++failCount;
+ } else
+ testResult = 1;
+ pr_info("name=post-init/bl_cpufreq_get/%d:origin(%u) result=%s\n",
+ nTest, cpu, (testResult ? "PASS" : "FAIL"));
+
+ /*
+ * Switch to "other" cluster, ie cluster not used at module
+ * loading time
+ */
+ cpufreq_driver_target(policy, entry_to_freq(other_entry),
+ CPUFREQ_RELATION_H);
+
+ ++nTest;
+ if (bl_cpufreq_get(cpu) != entry_to_freq(other_entry)) {
+ testResult = 0;
+ ++failCount;
+ } else
+ testResult = 1;
+ pr_info("name=post-init/bl_cpufreq_get/%d:other(%u) result=%s\n",
+ nTest, cpu, (testResult ? "PASS" : "FAIL"));
+
+ /*
+ * Switch back to "origin" cluster, ie cluster used at module
+ * loading time
+ */
+ cpufreq_driver_target(policy, entry_to_freq(origin_entry),
+ CPUFREQ_RELATION_H);
+ cpufreq_cpu_put(policy);
+ }
+
+ pr_info("name=post-init/bl_cpufreq_get run=%d result=%s pass=%d fail=%d\n",
+ nTest, (failCount == 0 ? "PASS" : "FAIL"),
+ (nTest - failCount), failCount);
+ if (failCount != 0)
+ return -1;
+
+ return 0;
+}
+
+static int test_get_current_freq(void)
+{
+ int nTest = 0, failCount = 0, testResult = 0;
+ unsigned int cpu;
+ struct cpufreq_frequency_table const *other_entry = NULL;
+ struct cpufreq_frequency_table const *origin_entry = NULL;
+ struct cpufreq_policy *policy = NULL;
+
+ /*
+ * Check if get_current_freq() return a consistent value, ie
+ * FREQ_BIG while on big cluster and FREQ_LITTLE on little cluster
+ */
+ for_each_cpu(cpu, cpu_present_mask) {
+ policy = cpufreq_cpu_get(cpu);
+ origin_entry = find_entry_by_cluster(get_current_cluster(cpu));
+ other_entry = get_other_entry(origin_entry);
+
+ ++nTest;
+ if (get_current_freq(cpu) != entry_to_freq(origin_entry)) {
+ testResult = 0;
+ ++failCount;
+ } else
+ testResult = 1;
+ pr_info("name=post-init/get_current_freq/%d:origin(%u) result=%s\n",
+ nTest, cpu, (testResult ? "PASS" : "FAIL"));
+
+ /*
+ * Switch to "other" cluster, ie cluster not used at module
+ * loading time
+ */
+ cpufreq_driver_target(policy, entry_to_freq(other_entry),
+ CPUFREQ_RELATION_H);
+
+ ++nTest;
+ if (get_current_freq(cpu) != entry_to_freq(other_entry)) {
+ testResult = 0;
+ ++failCount;
+ } else
+ testResult = 1;
+ pr_info("name=post-init/get_current_freq/%d:other(%u) result=%s\n",
+ nTest, cpu, (testResult ? "PASS" : "FAIL"));
+
+ /*
+ * Switch back to "origin" cluster, ie cluster used at module
+ * loading time
+ */
+ cpufreq_driver_target(policy, entry_to_freq(origin_entry),
+ CPUFREQ_RELATION_H);
+ cpufreq_cpu_put(policy);
+ }
+
+ pr_info("name=post-init/get_current_freq run=%d result=%s pass=%d fail=%d\n",
+ nTest, (failCount == 0 ? "PASS" : "FAIL"),
+ (nTest - failCount), failCount);
+ if (failCount != 0)
+ return -1;
+
+ return 0;
+}
+
+static int test_get_current_cached_cluster(void)
+{
+ int nTest = 0, failCount = 0, testResult = 0;
+ unsigned int cpu, cluster;
+ struct cpufreq_frequency_table const *other_entry = NULL;
+ struct cpufreq_frequency_table const *origin_entry = NULL;
+ struct cpufreq_policy *policy = NULL;
+
+ /*
+ * Check if get_current_cached_cluster() return a consistent value, ie
+ * CLUSTER_BIG while on big cluster and CLUSTER_LITTLE on little cluster
+ */
+ for_each_cpu(cpu, cpu_present_mask) {
+ policy = cpufreq_cpu_get(cpu);
+ origin_entry = find_entry_by_cluster(get_current_cluster(cpu));
+ other_entry = get_other_entry(origin_entry);
+
+ ++nTest;
+ cluster = get_current_cached_cluster(cpu);
+ if (cluster != entry_to_cluster(origin_entry)) {
+ testResult = 0;
+ ++failCount;
+ } else
+ testResult = 1;
+ pr_info("name=post-init/get_current_cached_cluster/%d:origin(%u) result=%s\n",
+ nTest, cpu, (testResult ? "PASS" : "FAIL"));
+
+ /*
+ * Switch to "other" cluster, ie cluster not used at module
+ * loading time
+ */
+ cpufreq_driver_target(policy, entry_to_freq(other_entry),
+ CPUFREQ_RELATION_H);
+
+ ++nTest;
+ cluster = get_current_cached_cluster(cpu);
+ if (cluster != entry_to_cluster(other_entry)) {
+ testResult = 0;
+ ++failCount;
+ } else
+ testResult = 1;
+ pr_info("name=post-init/get_current_cached_cluster/%d:other(%u) result=%s\n",
+ nTest, cpu, (testResult ? "PASS" : "FAIL"));
+
+ /*
+ * Switch back to "origin" cluster, ie cluster used at module
+ * loading time
+ */
+ cpufreq_driver_target(policy, entry_to_freq(origin_entry),
+ CPUFREQ_RELATION_H);
+ cpufreq_cpu_put(policy);
+ }
+
+ pr_info("name=post-init/get_current_cached_cluster run=%d result=%s pass=%d fail=%d\n",
+ nTest, (failCount == 0 ? "PASS" : "FAIL"),
+ (nTest - failCount), failCount);
+ if (failCount != 0)
+ return -1;
+
+ return 0;
+}
+
+static int test_cpufreq_driver_target(void)
+{
+ int nTest = 0, failCount = 0, testResult = 0;
+ unsigned int cpu;
+ struct cpufreq_frequency_table const *other_entry = NULL;
+ struct cpufreq_frequency_table const *origin_entry = NULL;
+ struct cpufreq_policy *policy = NULL;
+
+ /*
+ * Try to switch between cluster and check if switch was performed with
+ * success
+ */
+ for_each_cpu(cpu, cpu_present_mask) {
+ policy = cpufreq_cpu_get(cpu);
+ origin_entry = find_entry_by_cluster(get_current_cluster(cpu));
+ other_entry = get_other_entry(origin_entry);
+
+ /* Switch to "other" cluster, ie cluster not used at module
+ * loading time
+ */
+ cpufreq_driver_target(policy, entry_to_freq(other_entry),
+ CPUFREQ_RELATION_H);
+
+ /*
+ * Give the hardware some time to switch between clusters
+ */
+ mdelay(SWITCH_DELAY);
+
+ ++nTest;
+ if (get_current_cluster(cpu) != entry_to_cluster(other_entry)) {
+ testResult = 0;
+ ++failCount;
+ } else
+ testResult = 1;
+ pr_info("name=post-init/cpufreq_driver_target/%d:other(%u) result=%s\n",
+ nTest, cpu, (testResult ? "PASS" : "FAIL"));
+
+ /* Switch again to "other" cluster
+ */
+ cpufreq_driver_target(policy, entry_to_freq(other_entry),
+ CPUFREQ_RELATION_H);
+ /*
+ * Give the hardware some time to switch between clusters
+ */
+ mdelay(SWITCH_DELAY);
+
+ ++nTest;
+ if (get_current_cluster(cpu) != entry_to_cluster(other_entry)) {
+ testResult = 0;
+ ++failCount;
+ } else
+ testResult = 1;
+ pr_info("name=post-init/cpufreq_driver_target/%d:otherAgain(%u) result=%s\n",
+ nTest, cpu, (testResult ? "PASS" : "FAIL"));
+
+ /* Switch back to "origin" cluster, ie cluster used at module loading
+ * time
+ */
+ cpufreq_driver_target(policy, entry_to_freq(origin_entry),
+ CPUFREQ_RELATION_H);
+ /*
+ * Give the hardware some time to switch between clusters
+ */
+ mdelay(SWITCH_DELAY);
+
+ ++nTest;
+ if (get_current_cluster(cpu) != entry_to_cluster(origin_entry))
+ {
+ testResult = 0;
+ ++failCount;
+ } else
+ testResult = 1;
+ pr_info("name=post-init/cpufreq_driver_target/%d:origin(%u) result=%s\n",
+ nTest, cpu, (testResult ? "PASS" : "FAIL"));
+
+ /* Switch again to "origin" cluster
+ */
+ cpufreq_driver_target(policy, entry_to_freq(origin_entry),
+ CPUFREQ_RELATION_H);
+ /*
+ * Give the hardware some time to switch between clusters
+ */
+ mdelay(SWITCH_DELAY);
+
+ ++nTest;
+ if (get_current_cluster(cpu) != entry_to_cluster(origin_entry))
+ {
+ testResult = 0;
+ ++failCount;
+ } else
+ testResult = 1;
+ pr_info("name=post-init/cpufreq_driver_target/%d:originAgain(%u) result=%s\n",
+ nTest, cpu, (testResult ? "PASS" : "FAIL"));
+
+ cpufreq_cpu_put(policy);
+ }
+
+ pr_info("name=post-init/cpufreq_driver_target run=%d result=%s pass=%d fail=%d\n",
+ nTest, (failCount == 0 ? "PASS" : "FAIL"),
+ (nTest - failCount), failCount);
+ if (failCount != 0)
+ return -1;
+
+ return 0;
+}
+
+/* Check that new frequency is expected frequency, increment count and wake up
+ * test function.
+ */
+static int test_arm_bl_cpufreq_notifier(struct notifier_block *nb,
+ unsigned long val, void *data)
+{
+ struct cpufreq_freqs *freq = data;
+
+ if (freq->new != test_transition_freq)
+ test_transition_freq = -1;
+
+ ++test_transition_count;
+
+ wake_up(&test_wq);
+
+ return 0;
+}
+static struct notifier_block test_arm_bl_cpufreq_notifier_block = {
+ .notifier_call = test_arm_bl_cpufreq_notifier
+};
+
+static int test_transitions(void)
+{
+ int nTest = 0, failCount = 0, testResult = 0;
+ unsigned int cpu, origin_freq, other_freq;
+ struct cpufreq_frequency_table const *other_entry = NULL;
+ struct cpufreq_frequency_table const *origin_entry = NULL;
+ struct cpufreq_policy *policy = NULL;
+
+ /*
+ * register test_arm_bl_cpufreq_notifier_block as notifier :
+ * test_arm_bl_cpufreq_notifier_block will be called on cluster
+ * change and increment transition_count
+ */
+ cpufreq_register_notifier(&test_arm_bl_cpufreq_notifier_block,
+ CPUFREQ_TRANSITION_NOTIFIER);
+
+ /*
+ * Switch between cluster and check if notifications are received
+ */
+ for_each_cpu(cpu, cpu_present_mask) {
+ policy = cpufreq_cpu_get(cpu);
+ origin_entry = find_entry_by_cluster(get_current_cluster(cpu));
+ other_entry = get_other_entry(origin_entry);
+ origin_freq = entry_to_freq(origin_entry);
+ other_freq = entry_to_freq(other_entry);
+
+ /* Switch on little cluster and check notification
+ */
+ ++nTest;
+ test_transition_count = 0;
+ test_transition_freq = other_freq;
+ cpufreq_driver_target(policy, other_freq, CPUFREQ_RELATION_H);
+ wait_event_timeout(test_wq, (test_transition_count == 2),
+ msecs_to_jiffies(SWITCH_TRANSITION_DELAY));
+
+ if ((test_transition_count != 2)
+ || (test_transition_freq != other_freq)) {
+ testResult = 0;
+ ++failCount;
+ } else
+ testResult = 1;
+ pr_info("name=post-init/transitions/%d:other(%u) result=%s\n",
+ nTest, cpu, (testResult ? "PASS" : "FAIL"));
+
+ /* Switch on big cluster and check notification
+ */
+ ++nTest;
+ test_transition_count = 0;
+ test_transition_freq = origin_freq;
+ cpufreq_driver_target(policy, origin_freq, CPUFREQ_RELATION_H);
+ wait_event_timeout(test_wq, (test_transition_count == 2),
+ msecs_to_jiffies(SWITCH_TRANSITION_DELAY));
+
+ if ((test_transition_count != 2)
+ || (test_transition_freq != origin_freq)) {
+ testResult = 0;
+ ++failCount;
+ } else
+ testResult = 1;
+ pr_info("name=post-init/transitions/%d:origin(%u) result=%s\n",
+ nTest, cpu, (testResult ? "PASS" : "FAIL"));
+
+ cpufreq_cpu_put(policy);
+ }
+
+ cpufreq_unregister_notifier(&test_arm_bl_cpufreq_notifier_block,
+ CPUFREQ_TRANSITION_NOTIFIER);
+
+ pr_info("name=post-init/transitions run=%d result=%s pass=%d fail=%d\n",
+ nTest, (failCount == 0 ? "PASS" : "FAIL"),
+ (nTest - failCount), failCount);
+ if (failCount != 0)
+ return -1;
+
+ return 0;
+}
+
+static int pre_init_tests(void)
+{
+ int nTest = 0, failCount = 0;
+
+ pr_info("Begin pre-init tests");
+
+ ++nTest;
+ if (test_cpufreq_frequency_table() < 0)
+ ++failCount;
+
+ ++nTest;
+ if (test_cluster_to_freq() < 0)
+ ++failCount;
+
+ ++nTest;
+ if (test_get_current_cluster() < 0)
+ ++failCount;
+
+ pr_info("name=pre-init run=%d result=%s pass=%d fail=%d\n",
+ nTest, (failCount == 0 ? "PASS" : "FAIL"),
+ (nTest - failCount), failCount);
+ if (failCount != 0)
+ return -1;
+
+ return 0;
+}
+
+static int post_init_tests(void)
+{
+ /*
+ * Run all post-init tests
+ *
+ * We wait POST_INIT_TESTS_DELAY ms between tests to be sure system is
+ * in a stable state before running a new test.
+ */
+ int nTest = 0, failCount = 0;
+
+
+ mdelay(POST_INIT_TESTS_DELAY);
+ ++nTest;
+ if (test_cpufreq_driver_target() < 0)
+ ++failCount;
+
+ mdelay(POST_INIT_TESTS_DELAY);
+ ++nTest;
+ if (test_transitions() < 0)
+ ++failCount;
+
+ mdelay(POST_INIT_TESTS_DELAY);
+ ++nTest;
+ if (test_get_current_freq() < 0)
+ ++failCount;
+
+ mdelay(POST_INIT_TESTS_DELAY);
+ ++nTest;
+ if (test_bl_cpufreq_get() < 0)
+ ++failCount;
+
+ mdelay(POST_INIT_TESTS_DELAY);
+ ++nTest;
+ if (test_get_current_cached_cluster() < 0)
+ ++failCount;
+
+ pr_info("name=post-init run=%d result=%s pass=%d fail=%d\n",
+ nTest, (failCount == 0 ? "PASS" : "FAIL"),
+ (nTest - failCount), failCount);
+ if (failCount != 0)
+ return -1;
+
+ return 0;
+}
+
+#undef pr_fmt
+#define pr_fmt(fmt) __module_pr_fmt("", fmt)
+#else /* ! CONFIG_ARM_BL_CPUFREQ_TEST */
+
+static int pre_init_tests(void) { return 0; }
+static int post_init_tests(void) { return 0; }
+
+#endif /* CONFIG_ARM_BL_CPUFREQ_TEST */
+#endif /* ARM_BL_CPUFREQ_DEFINE_TESTS */