All of lore.kernel.org
 help / color / mirror / Atom feed
* [RFC] cpuidle : Add support for pseudo-cpuidle driver
@ 2020-07-23  6:13 Abhishek Goel
  2020-07-23  6:24 ` Randy Dunlap
                   ` (6 more replies)
  0 siblings, 7 replies; 10+ messages in thread
From: Abhishek Goel @ 2020-07-23  6:13 UTC (permalink / raw)
  To: linux-pm, linux-kernel; +Cc: rjw, daniel.lezcano, mpe, ego, Abhishek Goel

This option adds support for a testing cpuidle driver, which allows
user to define custom idle states with their respective latencies and
residencies. This is useful for testing the behaviour of governors on
customized set of idle states.

This can be used as of now by hard-coding the customized set of cpuidle
states in the driver. Will add the capability of this driver to be used
as a module in subsequent patches.

Original idea and discussion for this patch can be found at:
https://lkml.org/lkml/2019/12/17/655

Signed-off-by: Abhishek Goel <huntbag@linux.vnet.ibm.com>
---
 drivers/cpuidle/Kconfig        |   9 ++
 drivers/cpuidle/Makefile       |   1 +
 drivers/cpuidle/cpuidle-test.c | 276 +++++++++++++++++++++++++++++++++
 3 files changed, 286 insertions(+)
 create mode 100644 drivers/cpuidle/cpuidle-test.c

diff --git a/drivers/cpuidle/Kconfig b/drivers/cpuidle/Kconfig
index c0aeedd66f02..1d73153a0e35 100644
--- a/drivers/cpuidle/Kconfig
+++ b/drivers/cpuidle/Kconfig
@@ -71,6 +71,15 @@ config HALTPOLL_CPUIDLE
 	 before halting in the guest (more efficient than polling in the
 	 host via halt_poll_ns for some scenarios).
 
+config TEST_CPUIDLE
+	tristate "cpuidle test driver"
+	default m
+	help
+	 This option enables a testing cpuidle driver, which allows to user
+	 to define custom idle states with their respective latencies and residencies.
+	 This is useful for testing the behaviour of governors on different
+	 set of idle states.
+
 endif
 
 config ARCH_NEEDS_CPU_IDLE_COUPLED
diff --git a/drivers/cpuidle/Makefile b/drivers/cpuidle/Makefile
index f07800cbb43f..68ea7dc257b5 100644
--- a/drivers/cpuidle/Makefile
+++ b/drivers/cpuidle/Makefile
@@ -8,6 +8,7 @@ obj-$(CONFIG_ARCH_NEEDS_CPU_IDLE_COUPLED) += coupled.o
 obj-$(CONFIG_DT_IDLE_STATES)		  += dt_idle_states.o
 obj-$(CONFIG_ARCH_HAS_CPU_RELAX)	  += poll_state.o
 obj-$(CONFIG_HALTPOLL_CPUIDLE)		  += cpuidle-haltpoll.o
+obj-$(CONFIG_TEST_CPUIDLE)		  += cpuidle-test.o
 
 ##################################################################################
 # ARM SoC drivers
diff --git a/drivers/cpuidle/cpuidle-test.c b/drivers/cpuidle/cpuidle-test.c
new file mode 100644
index 000000000000..399729440569
--- /dev/null
+++ b/drivers/cpuidle/cpuidle-test.c
@@ -0,0 +1,276 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ *  cpuidle-test - Test driver for cpuidle.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/moduleparam.h>
+#include <linux/cpuidle.h>
+#include <linux/cpu.h>
+#include <linux/module.h>
+#include <linux/sched/idle.h>
+#include <linux/sched/clock.h>
+#include <linux/sched/idle.h>
+
+#define CPUIDLE_STATE_MAX	10
+#define MAX_PARAM_LENGTH	100
+
+static unsigned int nr_states = 4;
+static unsigned int sim_type = 1;
+static char name[MAX_PARAM_LENGTH];
+static char latency_us[MAX_PARAM_LENGTH];
+static char residency_us[MAX_PARAM_LENGTH];
+
+
+module_param(nr_states, uint, 0644);
+module_param(sim_type, uint, 0644);
+module_param_string(name, name, MAX_PARAM_LENGTH, 0644);
+module_param_string(latency_us, latency_us, MAX_PARAM_LENGTH, 0644);
+module_param_string(residency_us, residency_us, MAX_PARAM_LENGTH, 0644);
+
+static struct cpuidle_driver test_cpuidle_driver = {
+	.name		= "test_cpuidle",
+	.owner		= THIS_MODULE,
+};
+
+static struct cpuidle_state *cpuidle_state_table __read_mostly;
+
+static struct cpuidle_device __percpu *test_cpuidle_devices;
+static enum cpuhp_state test_hp_idlestate;
+
+
+static int __cpuidle idle_loop(struct cpuidle_device *dev,
+				struct cpuidle_driver *drv,
+				int index)
+{
+	u64 time_start;
+
+	local_irq_enable();
+	if (!current_set_polling_and_test()) {
+		while (!need_resched())
+			cpu_relax();
+	}
+
+	time_start = local_clock();
+
+	while (local_clock() - time_start < drv->states[index].exit_latency)
+
+	current_clr_polling();
+
+	return index;
+}
+
+static struct cpuidle_state cpuidle_states[CPUIDLE_STATE_MAX] = {
+	{ /* Snooze */
+		.name = "snooze",
+		.exit_latency = 0,
+		.target_residency = 0,
+		.enter = idle_loop },
+};
+
+static struct cpuidle_state cpuidle_states_ppc[] = {
+	{	.name = "snooze",
+		.exit_latency = 0,
+		.target_residency = 0,
+		.enter = idle_loop },
+	{
+		.name = "stop0",
+		.exit_latency = 2,
+		.target_residency = 20,
+		.enter = idle_loop },
+	{
+		.name = "stop1",
+		.exit_latency = 5,
+		.target_residency = 50,
+		.enter = idle_loop },
+	{
+		.name = "stop2",
+		.exit_latency = 10,
+		.target_residency = 100,
+		.enter = idle_loop },
+};
+
+static struct cpuidle_state cpuidle_states_intel[] = {
+	{	.name = "poll",
+		.exit_latency = 0,
+		.target_residency = 0,
+		.enter = idle_loop },
+	{
+		.name = "c1",
+		.exit_latency = 2,
+		.target_residency = 2,
+		.enter = idle_loop },
+	{
+		.name = "c1e",
+		.exit_latency = 10,
+		.target_residency = 20,
+		.enter = idle_loop },
+	{
+		.name = "c3",
+		.exit_latency = 80,
+		.target_residency = 211,
+		.enter = idle_loop },
+};
+
+int cpuidle_cpu_online(unsigned int cpu)
+{
+	struct cpuidle_device *dev;
+
+	dev = per_cpu_ptr(test_cpuidle_devices, cpu);
+	if (!dev->registered) {
+		dev->cpu = cpu;
+		if (cpuidle_register_device(dev)) {
+			pr_notice("cpuidle_register_device %d failed!\n", cpu);
+			return -EIO;
+		}
+	}
+
+	return 0;
+}
+
+int cpuidle_cpu_dead(unsigned int cpu)
+{
+	struct cpuidle_device *dev;
+
+	dev = per_cpu_ptr(test_cpuidle_devices, cpu);
+	if (dev->registered)
+		cpuidle_unregister_device(dev);
+
+	return 0;
+}
+
+int cpuidle_driver_init(void)
+{
+	int idle_state;
+	struct cpuidle_driver *drv = &test_cpuidle_driver;
+
+	drv->state_count = 0;
+
+	for (idle_state = 0; idle_state < nr_states; ++idle_state) {
+		/* Is the state not enabled? */
+		if (cpuidle_state_table[idle_state].enter == NULL)
+			continue;
+
+		drv->states[drv->state_count] =	/* structure copy */
+			cpuidle_state_table[idle_state];
+
+		drv->state_count += 1;
+	}
+
+	return 0;
+}
+
+int add_cpuidle_states(void)
+{
+	/* Parse the module param and initialize the idle states here
+	 * in cpuidle_state_table.
+	 */
+	char *this_param;
+	char *input_name = name;
+	char *input_res = residency_us;
+	char *input_lat = latency_us;
+	int index = 1;
+	long temp;
+	int rc;
+
+	switch (sim_type) {
+	case 1:
+		cpuidle_state_table = cpuidle_states_ppc;
+		return 0;
+	case 2:
+		cpuidle_state_table = cpuidle_states_intel;
+		return 0;
+	case 3:
+		break;
+	default:
+		pr_warn("Sim value out of bound\n");
+		break;
+	}
+
+	if (strnlen(input_name, MAX_PARAM_LENGTH)) {
+		while ((this_param = strsep(&input_name, ",")) && index <= nr_states) {
+			strcpy(cpuidle_states[index].name, this_param);
+			cpuidle_states[index].enter = idle_loop;
+			index++;
+		}
+	}
+
+	if (strnlen(input_res, MAX_PARAM_LENGTH)) {
+		index = 1;
+		while ((this_param = strsep(&input_res, ",")) && index <= nr_states) {
+			rc = kstrtol(this_param, 10, &temp);
+			cpuidle_states[index].target_residency = temp;
+			index++;
+		}
+	}
+
+	if (strnlen(input_lat, MAX_PARAM_LENGTH)) {
+		index = 1;
+		while ((this_param = strsep(&input_lat, ",")) && index <= nr_states) {
+			rc = kstrtol(this_param, 10, &temp);
+			cpuidle_states[index].exit_latency = temp;
+			index++;
+		}
+	}
+
+	cpuidle_state_table = cpuidle_states;
+	return nr_states;
+}
+
+void test_cpuidle_uninit(void)
+{
+	if (test_hp_idlestate)
+		cpuhp_remove_state(test_hp_idlestate);
+	cpuidle_unregister_driver(&test_cpuidle_driver);
+
+	free_percpu(test_cpuidle_devices);
+	test_cpuidle_devices = NULL;
+}
+
+int __init test_cpuidle_init(void)
+{
+	int retval;
+
+	add_cpuidle_states();
+	cpuidle_driver_init();
+	retval = cpuidle_register(&test_cpuidle_driver, NULL);
+	if (retval) {
+		printk(KERN_DEBUG "Registration of test driver failed.\n");
+		return retval;
+	}
+
+	test_cpuidle_devices = alloc_percpu(struct cpuidle_device);
+	if (test_cpuidle_devices == NULL) {
+		cpuidle_unregister_driver(&test_cpuidle_driver);
+		return -ENOMEM;
+	}
+
+	retval = cpuhp_setup_state_nocalls(CPUHP_AP_ONLINE_DYN,
+					   "cpuidle/powernv:online",
+					   cpuidle_cpu_online,
+					   cpuidle_cpu_dead);
+
+	if (retval < 0) {
+		test_cpuidle_uninit();
+	} else {
+		test_hp_idlestate = retval;
+		retval = 0;
+	}
+
+	return retval;
+}
+
+void __exit test_cpuidle_exit(void)
+{
+	test_cpuidle_uninit();
+}
+
+module_init(test_cpuidle_init);
+module_exit(test_cpuidle_exit);
+MODULE_DESCRIPTION("Test Cpuidle Driver");
+MODULE_AUTHOR("Abhishek Goel");
+MODULE_LICENSE("GPL");
+
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* Re: [RFC] cpuidle : Add support for pseudo-cpuidle driver
  2020-07-23  6:13 [RFC] cpuidle : Add support for pseudo-cpuidle driver Abhishek Goel
@ 2020-07-23  6:24 ` Randy Dunlap
  2020-07-24  3:40 ` kernel test robot
                   ` (5 subsequent siblings)
  6 siblings, 0 replies; 10+ messages in thread
From: Randy Dunlap @ 2020-07-23  6:24 UTC (permalink / raw)
  To: Abhishek Goel, linux-pm, linux-kernel; +Cc: rjw, daniel.lezcano, mpe, ego

On 7/22/20 11:13 PM, Abhishek Goel wrote:
> diff --git a/drivers/cpuidle/Kconfig b/drivers/cpuidle/Kconfig
> index c0aeedd66f02..1d73153a0e35 100644
> --- a/drivers/cpuidle/Kconfig
> +++ b/drivers/cpuidle/Kconfig
> @@ -71,6 +71,15 @@ config HALTPOLL_CPUIDLE
>  	 before halting in the guest (more efficient than polling in the
>  	 host via halt_poll_ns for some scenarios).
>  
> +config TEST_CPUIDLE
> +	tristate "cpuidle test driver"
> +	default m

No default, please.
We don't enable unneeded drivers for the fun of it.

> +	help

Indent the following help text with one tab + 2 spaces.

> +	 This option enables a testing cpuidle driver, which allows to user

	                                                     allows the user  [or a user]

> +	 to define custom idle states with their respective latencies and residencies.
> +	 This is useful for testing the behaviour of governors on different
> +	 set of idle states.

	 sets

> +
>  endif
>  
>  config ARCH_NEEDS_CPU_IDLE_COUPLED

thanks.
-- 
~Randy


^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [RFC] cpuidle : Add support for pseudo-cpuidle driver
  2020-07-23  6:13 [RFC] cpuidle : Add support for pseudo-cpuidle driver Abhishek Goel
  2020-07-23  6:24 ` Randy Dunlap
@ 2020-07-24  3:40 ` kernel test robot
  2020-07-24  3:40 ` [RFC PATCH] cpuidle : cpuidle_cpu_online() can be static kernel test robot
                   ` (4 subsequent siblings)
  6 siblings, 0 replies; 10+ messages in thread
From: kernel test robot @ 2020-07-24  3:40 UTC (permalink / raw)
  To: kbuild-all

[-- Attachment #1: Type: text/plain, Size: 2147 bytes --]

Hi Abhishek,

[FYI, it's a private test report for your RFC patch.]
[auto build test WARNING on pm/linux-next]
[also build test WARNING on linux/master linus/master v5.8-rc6 next-20200723]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch]

url:    https://github.com/0day-ci/linux/commits/Abhishek-Goel/cpuidle-Add-support-for-pseudo-cpuidle-driver/20200723-141912
base:   https://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm.git linux-next
config: i386-randconfig-s001-20200723 (attached as .config)
compiler: gcc-9 (Debian 9.3.0-14) 9.3.0
reproduce:
        # apt-get install sparse
        # sparse version: v0.6.2-93-g4c6cbe55-dirty
        # save the attached .config to linux build tree
        make W=1 C=1 CF='-fdiagnostic-prefix -D__CHECK_ENDIAN__' ARCH=i386 

If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <lkp@intel.com>


sparse warnings: (new ones prefixed by >>)

>> drivers/cpuidle/cpuidle-test.c:118:5: sparse: sparse: symbol 'cpuidle_cpu_online' was not declared. Should it be static?
>> drivers/cpuidle/cpuidle-test.c:134:5: sparse: sparse: symbol 'cpuidle_cpu_dead' was not declared. Should it be static?
>> drivers/cpuidle/cpuidle-test.c:145:5: sparse: sparse: symbol 'cpuidle_driver_init' was not declared. Should it be static?
>> drivers/cpuidle/cpuidle-test.c:166:5: sparse: sparse: symbol 'add_cpuidle_states' was not declared. Should it be static?
>> drivers/cpuidle/cpuidle-test.c:223:6: sparse: sparse: symbol 'test_cpuidle_uninit' was not declared. Should it be static?
>> drivers/cpuidle/cpuidle-test.c:233:12: sparse: sparse: symbol 'test_cpuidle_init' was not declared. Should it be static?
>> drivers/cpuidle/cpuidle-test.c:266:13: sparse: sparse: symbol 'test_cpuidle_exit' was not declared. Should it be static?

Please review and possibly fold the followup patch.

---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all(a)lists.01.org

[-- Attachment #2: config.gz --]
[-- Type: application/gzip, Size: 35331 bytes --]

^ permalink raw reply	[flat|nested] 10+ messages in thread

* [RFC PATCH] cpuidle : cpuidle_cpu_online() can be static
  2020-07-23  6:13 [RFC] cpuidle : Add support for pseudo-cpuidle driver Abhishek Goel
  2020-07-23  6:24 ` Randy Dunlap
  2020-07-24  3:40 ` kernel test robot
@ 2020-07-24  3:40 ` kernel test robot
  2020-07-24  3:41 ` [RFC] cpuidle : Add support for pseudo-cpuidle driver kernel test robot
                   ` (3 subsequent siblings)
  6 siblings, 0 replies; 10+ messages in thread
From: kernel test robot @ 2020-07-24  3:40 UTC (permalink / raw)
  To: kbuild-all

[-- Attachment #1: Type: text/plain, Size: 1878 bytes --]


Signed-off-by: kernel test robot <lkp@intel.com>
---
 cpuidle-test.c |   14 +++++++-------
 1 file changed, 7 insertions(+), 7 deletions(-)

diff --git a/drivers/cpuidle/cpuidle-test.c b/drivers/cpuidle/cpuidle-test.c
index 399729440569d8..d6f037fc00e6ec 100644
--- a/drivers/cpuidle/cpuidle-test.c
+++ b/drivers/cpuidle/cpuidle-test.c
@@ -115,7 +115,7 @@ static struct cpuidle_state cpuidle_states_intel[] = {
 		.enter = idle_loop },
 };
 
-int cpuidle_cpu_online(unsigned int cpu)
+static int cpuidle_cpu_online(unsigned int cpu)
 {
 	struct cpuidle_device *dev;
 
@@ -131,7 +131,7 @@ int cpuidle_cpu_online(unsigned int cpu)
 	return 0;
 }
 
-int cpuidle_cpu_dead(unsigned int cpu)
+static int cpuidle_cpu_dead(unsigned int cpu)
 {
 	struct cpuidle_device *dev;
 
@@ -142,7 +142,7 @@ int cpuidle_cpu_dead(unsigned int cpu)
 	return 0;
 }
 
-int cpuidle_driver_init(void)
+static int cpuidle_driver_init(void)
 {
 	int idle_state;
 	struct cpuidle_driver *drv = &test_cpuidle_driver;
@@ -163,7 +163,7 @@ int cpuidle_driver_init(void)
 	return 0;
 }
 
-int add_cpuidle_states(void)
+static int add_cpuidle_states(void)
 {
 	/* Parse the module param and initialize the idle states here
 	 * in cpuidle_state_table.
@@ -220,7 +220,7 @@ int add_cpuidle_states(void)
 	return nr_states;
 }
 
-void test_cpuidle_uninit(void)
+static void test_cpuidle_uninit(void)
 {
 	if (test_hp_idlestate)
 		cpuhp_remove_state(test_hp_idlestate);
@@ -230,7 +230,7 @@ void test_cpuidle_uninit(void)
 	test_cpuidle_devices = NULL;
 }
 
-int __init test_cpuidle_init(void)
+static int __init test_cpuidle_init(void)
 {
 	int retval;
 
@@ -263,7 +263,7 @@ int __init test_cpuidle_init(void)
 	return retval;
 }
 
-void __exit test_cpuidle_exit(void)
+static void __exit test_cpuidle_exit(void)
 {
 	test_cpuidle_uninit();
 }

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* Re: [RFC] cpuidle : Add support for pseudo-cpuidle driver
  2020-07-23  6:13 [RFC] cpuidle : Add support for pseudo-cpuidle driver Abhishek Goel
                   ` (2 preceding siblings ...)
  2020-07-24  3:40 ` [RFC PATCH] cpuidle : cpuidle_cpu_online() can be static kernel test robot
@ 2020-07-24  3:41 ` kernel test robot
  2020-07-24 10:51 ` kernel test robot
                   ` (2 subsequent siblings)
  6 siblings, 0 replies; 10+ messages in thread
From: kernel test robot @ 2020-07-24  3:41 UTC (permalink / raw)
  To: kbuild-all

[-- Attachment #1: Type: text/plain, Size: 8620 bytes --]

Hi Abhishek,

[FYI, it's a private test report for your RFC patch.]
[auto build test WARNING on pm/linux-next]
[also build test WARNING on linux/master linus/master v5.8-rc6 next-20200723]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch]

url:    https://github.com/0day-ci/linux/commits/Abhishek-Goel/cpuidle-Add-support-for-pseudo-cpuidle-driver/20200723-141912
base:   https://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm.git linux-next
config: x86_64-randconfig-a014-20200723 (attached as .config)
compiler: clang version 12.0.0 (https://github.com/llvm/llvm-project e0ee2288424952e0445f096ae7800472eac11249)
reproduce (this is a W=1 build):
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # install x86_64 cross compiling tool for clang build
        # apt-get install binutils-x86-64-linux-gnu
        # save the attached .config to linux build tree
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=clang make.cross ARCH=x86_64 

If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <lkp@intel.com>

All warnings (new ones prefixed by >>):

>> drivers/cpuidle/cpuidle-test.c:118:5: warning: no previous prototype for function 'cpuidle_cpu_online' [-Wmissing-prototypes]
   int cpuidle_cpu_online(unsigned int cpu)
       ^
   drivers/cpuidle/cpuidle-test.c:118:1: note: declare 'static' if the function is not intended to be used outside of this translation unit
   int cpuidle_cpu_online(unsigned int cpu)
   ^
   static 
>> drivers/cpuidle/cpuidle-test.c:134:5: warning: no previous prototype for function 'cpuidle_cpu_dead' [-Wmissing-prototypes]
   int cpuidle_cpu_dead(unsigned int cpu)
       ^
   drivers/cpuidle/cpuidle-test.c:134:1: note: declare 'static' if the function is not intended to be used outside of this translation unit
   int cpuidle_cpu_dead(unsigned int cpu)
   ^
   static 
>> drivers/cpuidle/cpuidle-test.c:145:5: warning: no previous prototype for function 'cpuidle_driver_init' [-Wmissing-prototypes]
   int cpuidle_driver_init(void)
       ^
   drivers/cpuidle/cpuidle-test.c:145:1: note: declare 'static' if the function is not intended to be used outside of this translation unit
   int cpuidle_driver_init(void)
   ^
   static 
>> drivers/cpuidle/cpuidle-test.c:166:5: warning: no previous prototype for function 'add_cpuidle_states' [-Wmissing-prototypes]
   int add_cpuidle_states(void)
       ^
   drivers/cpuidle/cpuidle-test.c:166:1: note: declare 'static' if the function is not intended to be used outside of this translation unit
   int add_cpuidle_states(void)
   ^
   static 
>> drivers/cpuidle/cpuidle-test.c:223:6: warning: no previous prototype for function 'test_cpuidle_uninit' [-Wmissing-prototypes]
   void test_cpuidle_uninit(void)
        ^
   drivers/cpuidle/cpuidle-test.c:223:1: note: declare 'static' if the function is not intended to be used outside of this translation unit
   void test_cpuidle_uninit(void)
   ^
   static 
>> drivers/cpuidle/cpuidle-test.c:233:12: warning: no previous prototype for function 'test_cpuidle_init' [-Wmissing-prototypes]
   int __init test_cpuidle_init(void)
              ^
   drivers/cpuidle/cpuidle-test.c:233:1: note: declare 'static' if the function is not intended to be used outside of this translation unit
   int __init test_cpuidle_init(void)
   ^
   static 
>> drivers/cpuidle/cpuidle-test.c:266:13: warning: no previous prototype for function 'test_cpuidle_exit' [-Wmissing-prototypes]
   void __exit test_cpuidle_exit(void)
               ^
   drivers/cpuidle/cpuidle-test.c:266:1: note: declare 'static' if the function is not intended to be used outside of this translation unit
   void __exit test_cpuidle_exit(void)
   ^
   static 
   7 warnings generated.

vim +/cpuidle_cpu_online +118 drivers/cpuidle/cpuidle-test.c

   117	
 > 118	int cpuidle_cpu_online(unsigned int cpu)
   119	{
   120		struct cpuidle_device *dev;
   121	
   122		dev = per_cpu_ptr(test_cpuidle_devices, cpu);
   123		if (!dev->registered) {
   124			dev->cpu = cpu;
   125			if (cpuidle_register_device(dev)) {
   126				pr_notice("cpuidle_register_device %d failed!\n", cpu);
   127				return -EIO;
   128			}
   129		}
   130	
   131		return 0;
   132	}
   133	
 > 134	int cpuidle_cpu_dead(unsigned int cpu)
   135	{
   136		struct cpuidle_device *dev;
   137	
   138		dev = per_cpu_ptr(test_cpuidle_devices, cpu);
   139		if (dev->registered)
   140			cpuidle_unregister_device(dev);
   141	
   142		return 0;
   143	}
   144	
 > 145	int cpuidle_driver_init(void)
   146	{
   147		int idle_state;
   148		struct cpuidle_driver *drv = &test_cpuidle_driver;
   149	
   150		drv->state_count = 0;
   151	
   152		for (idle_state = 0; idle_state < nr_states; ++idle_state) {
   153			/* Is the state not enabled? */
   154			if (cpuidle_state_table[idle_state].enter == NULL)
   155				continue;
   156	
   157			drv->states[drv->state_count] =	/* structure copy */
   158				cpuidle_state_table[idle_state];
   159	
   160			drv->state_count += 1;
   161		}
   162	
   163		return 0;
   164	}
   165	
 > 166	int add_cpuidle_states(void)
   167	{
   168		/* Parse the module param and initialize the idle states here
   169		 * in cpuidle_state_table.
   170		 */
   171		char *this_param;
   172		char *input_name = name;
   173		char *input_res = residency_us;
   174		char *input_lat = latency_us;
   175		int index = 1;
   176		long temp;
   177		int rc;
   178	
   179		switch (sim_type) {
   180		case 1:
   181			cpuidle_state_table = cpuidle_states_ppc;
   182			return 0;
   183		case 2:
   184			cpuidle_state_table = cpuidle_states_intel;
   185			return 0;
   186		case 3:
   187			break;
   188		default:
   189			pr_warn("Sim value out of bound\n");
   190			break;
   191		}
   192	
   193		if (strnlen(input_name, MAX_PARAM_LENGTH)) {
   194			while ((this_param = strsep(&input_name, ",")) && index <= nr_states) {
   195				strcpy(cpuidle_states[index].name, this_param);
   196				cpuidle_states[index].enter = idle_loop;
   197				index++;
   198			}
   199		}
   200	
   201		if (strnlen(input_res, MAX_PARAM_LENGTH)) {
   202			index = 1;
   203			while ((this_param = strsep(&input_res, ",")) && index <= nr_states) {
   204				rc = kstrtol(this_param, 10, &temp);
   205				cpuidle_states[index].target_residency = temp;
   206				index++;
   207			}
   208		}
   209	
   210		if (strnlen(input_lat, MAX_PARAM_LENGTH)) {
   211			index = 1;
   212			while ((this_param = strsep(&input_lat, ",")) && index <= nr_states) {
   213				rc = kstrtol(this_param, 10, &temp);
   214				cpuidle_states[index].exit_latency = temp;
   215				index++;
   216			}
   217		}
   218	
   219		cpuidle_state_table = cpuidle_states;
   220		return nr_states;
   221	}
   222	
 > 223	void test_cpuidle_uninit(void)
   224	{
   225		if (test_hp_idlestate)
   226			cpuhp_remove_state(test_hp_idlestate);
   227		cpuidle_unregister_driver(&test_cpuidle_driver);
   228	
   229		free_percpu(test_cpuidle_devices);
   230		test_cpuidle_devices = NULL;
   231	}
   232	
 > 233	int __init test_cpuidle_init(void)
   234	{
   235		int retval;
   236	
   237		add_cpuidle_states();
   238		cpuidle_driver_init();
   239		retval = cpuidle_register(&test_cpuidle_driver, NULL);
   240		if (retval) {
   241			printk(KERN_DEBUG "Registration of test driver failed.\n");
   242			return retval;
   243		}
   244	
   245		test_cpuidle_devices = alloc_percpu(struct cpuidle_device);
   246		if (test_cpuidle_devices == NULL) {
   247			cpuidle_unregister_driver(&test_cpuidle_driver);
   248			return -ENOMEM;
   249		}
   250	
   251		retval = cpuhp_setup_state_nocalls(CPUHP_AP_ONLINE_DYN,
   252						   "cpuidle/powernv:online",
   253						   cpuidle_cpu_online,
   254						   cpuidle_cpu_dead);
   255	
   256		if (retval < 0) {
   257			test_cpuidle_uninit();
   258		} else {
   259			test_hp_idlestate = retval;
   260			retval = 0;
   261		}
   262	
   263		return retval;
   264	}
   265	
 > 266	void __exit test_cpuidle_exit(void)
   267	{
   268		test_cpuidle_uninit();
   269	}
   270	

---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all(a)lists.01.org

[-- Attachment #2: config.gz --]
[-- Type: application/gzip, Size: 35928 bytes --]

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [RFC] cpuidle : Add support for pseudo-cpuidle driver
  2020-07-23  6:13 [RFC] cpuidle : Add support for pseudo-cpuidle driver Abhishek Goel
                   ` (3 preceding siblings ...)
  2020-07-24  3:41 ` [RFC] cpuidle : Add support for pseudo-cpuidle driver kernel test robot
@ 2020-07-24 10:51 ` kernel test robot
  2020-08-05 11:56   ` Dan Carpenter
  2020-08-20 19:33 ` Fontenot, Nathan
  6 siblings, 0 replies; 10+ messages in thread
From: kernel test robot @ 2020-07-24 10:51 UTC (permalink / raw)
  To: kbuild-all

[-- Attachment #1: Type: text/plain, Size: 7254 bytes --]

Hi Abhishek,

[FYI, it's a private test report for your RFC patch.]
[auto build test WARNING on pm/linux-next]
[also build test WARNING on linux/master linus/master v5.8-rc6 next-20200723]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch]

url:    https://github.com/0day-ci/linux/commits/Abhishek-Goel/cpuidle-Add-support-for-pseudo-cpuidle-driver/20200723-141912
base:   https://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm.git linux-next
config: i386-allyesconfig (attached as .config)
compiler: gcc-9 (Debian 9.3.0-14) 9.3.0
reproduce (this is a W=1 build):
        # save the attached .config to linux build tree
        make W=1 ARCH=i386 

If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <lkp@intel.com>

All warnings (new ones prefixed by >>):

>> drivers/cpuidle/cpuidle-test.c:118:5: warning: no previous prototype for 'cpuidle_cpu_online' [-Wmissing-prototypes]
     118 | int cpuidle_cpu_online(unsigned int cpu)
         |     ^~~~~~~~~~~~~~~~~~
>> drivers/cpuidle/cpuidle-test.c:134:5: warning: no previous prototype for 'cpuidle_cpu_dead' [-Wmissing-prototypes]
     134 | int cpuidle_cpu_dead(unsigned int cpu)
         |     ^~~~~~~~~~~~~~~~
>> drivers/cpuidle/cpuidle-test.c:145:5: warning: no previous prototype for 'cpuidle_driver_init' [-Wmissing-prototypes]
     145 | int cpuidle_driver_init(void)
         |     ^~~~~~~~~~~~~~~~~~~
>> drivers/cpuidle/cpuidle-test.c:166:5: warning: no previous prototype for 'add_cpuidle_states' [-Wmissing-prototypes]
     166 | int add_cpuidle_states(void)
         |     ^~~~~~~~~~~~~~~~~~
   drivers/cpuidle/cpuidle-test.c: In function 'add_cpuidle_states':
>> drivers/cpuidle/cpuidle-test.c:177:6: warning: variable 'rc' set but not used [-Wunused-but-set-variable]
     177 |  int rc;
         |      ^~
   drivers/cpuidle/cpuidle-test.c: At top level:
>> drivers/cpuidle/cpuidle-test.c:223:6: warning: no previous prototype for 'test_cpuidle_uninit' [-Wmissing-prototypes]
     223 | void test_cpuidle_uninit(void)
         |      ^~~~~~~~~~~~~~~~~~~
>> drivers/cpuidle/cpuidle-test.c:233:12: warning: no previous prototype for 'test_cpuidle_init' [-Wmissing-prototypes]
     233 | int __init test_cpuidle_init(void)
         |            ^~~~~~~~~~~~~~~~~
>> drivers/cpuidle/cpuidle-test.c:266:13: warning: no previous prototype for 'test_cpuidle_exit' [-Wmissing-prototypes]
     266 | void __exit test_cpuidle_exit(void)
         |             ^~~~~~~~~~~~~~~~~

vim +/cpuidle_cpu_online +118 drivers/cpuidle/cpuidle-test.c

   117	
 > 118	int cpuidle_cpu_online(unsigned int cpu)
   119	{
   120		struct cpuidle_device *dev;
   121	
   122		dev = per_cpu_ptr(test_cpuidle_devices, cpu);
   123		if (!dev->registered) {
   124			dev->cpu = cpu;
   125			if (cpuidle_register_device(dev)) {
   126				pr_notice("cpuidle_register_device %d failed!\n", cpu);
   127				return -EIO;
   128			}
   129		}
   130	
   131		return 0;
   132	}
   133	
 > 134	int cpuidle_cpu_dead(unsigned int cpu)
   135	{
   136		struct cpuidle_device *dev;
   137	
   138		dev = per_cpu_ptr(test_cpuidle_devices, cpu);
   139		if (dev->registered)
   140			cpuidle_unregister_device(dev);
   141	
   142		return 0;
   143	}
   144	
 > 145	int cpuidle_driver_init(void)
   146	{
   147		int idle_state;
   148		struct cpuidle_driver *drv = &test_cpuidle_driver;
   149	
   150		drv->state_count = 0;
   151	
   152		for (idle_state = 0; idle_state < nr_states; ++idle_state) {
   153			/* Is the state not enabled? */
   154			if (cpuidle_state_table[idle_state].enter == NULL)
   155				continue;
   156	
   157			drv->states[drv->state_count] =	/* structure copy */
   158				cpuidle_state_table[idle_state];
   159	
   160			drv->state_count += 1;
   161		}
   162	
   163		return 0;
   164	}
   165	
 > 166	int add_cpuidle_states(void)
   167	{
   168		/* Parse the module param and initialize the idle states here
   169		 * in cpuidle_state_table.
   170		 */
   171		char *this_param;
   172		char *input_name = name;
   173		char *input_res = residency_us;
   174		char *input_lat = latency_us;
   175		int index = 1;
   176		long temp;
 > 177		int rc;
   178	
   179		switch (sim_type) {
   180		case 1:
   181			cpuidle_state_table = cpuidle_states_ppc;
   182			return 0;
   183		case 2:
   184			cpuidle_state_table = cpuidle_states_intel;
   185			return 0;
   186		case 3:
   187			break;
   188		default:
   189			pr_warn("Sim value out of bound\n");
   190			break;
   191		}
   192	
   193		if (strnlen(input_name, MAX_PARAM_LENGTH)) {
   194			while ((this_param = strsep(&input_name, ",")) && index <= nr_states) {
   195				strcpy(cpuidle_states[index].name, this_param);
   196				cpuidle_states[index].enter = idle_loop;
   197				index++;
   198			}
   199		}
   200	
   201		if (strnlen(input_res, MAX_PARAM_LENGTH)) {
   202			index = 1;
   203			while ((this_param = strsep(&input_res, ",")) && index <= nr_states) {
   204				rc = kstrtol(this_param, 10, &temp);
   205				cpuidle_states[index].target_residency = temp;
   206				index++;
   207			}
   208		}
   209	
   210		if (strnlen(input_lat, MAX_PARAM_LENGTH)) {
   211			index = 1;
   212			while ((this_param = strsep(&input_lat, ",")) && index <= nr_states) {
   213				rc = kstrtol(this_param, 10, &temp);
   214				cpuidle_states[index].exit_latency = temp;
   215				index++;
   216			}
   217		}
   218	
   219		cpuidle_state_table = cpuidle_states;
   220		return nr_states;
   221	}
   222	
 > 223	void test_cpuidle_uninit(void)
   224	{
   225		if (test_hp_idlestate)
   226			cpuhp_remove_state(test_hp_idlestate);
   227		cpuidle_unregister_driver(&test_cpuidle_driver);
   228	
   229		free_percpu(test_cpuidle_devices);
   230		test_cpuidle_devices = NULL;
   231	}
   232	
 > 233	int __init test_cpuidle_init(void)
   234	{
   235		int retval;
   236	
   237		add_cpuidle_states();
   238		cpuidle_driver_init();
   239		retval = cpuidle_register(&test_cpuidle_driver, NULL);
   240		if (retval) {
   241			printk(KERN_DEBUG "Registration of test driver failed.\n");
   242			return retval;
   243		}
   244	
   245		test_cpuidle_devices = alloc_percpu(struct cpuidle_device);
   246		if (test_cpuidle_devices == NULL) {
   247			cpuidle_unregister_driver(&test_cpuidle_driver);
   248			return -ENOMEM;
   249		}
   250	
   251		retval = cpuhp_setup_state_nocalls(CPUHP_AP_ONLINE_DYN,
   252						   "cpuidle/powernv:online",
   253						   cpuidle_cpu_online,
   254						   cpuidle_cpu_dead);
   255	
   256		if (retval < 0) {
   257			test_cpuidle_uninit();
   258		} else {
   259			test_hp_idlestate = retval;
   260			retval = 0;
   261		}
   262	
   263		return retval;
   264	}
   265	
 > 266	void __exit test_cpuidle_exit(void)
   267	{
   268		test_cpuidle_uninit();
   269	}
   270	

---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all(a)lists.01.org

[-- Attachment #2: config.gz --]
[-- Type: application/gzip, Size: 74086 bytes --]

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [RFC] cpuidle : Add support for pseudo-cpuidle driver
  2020-07-23  6:13 [RFC] cpuidle : Add support for pseudo-cpuidle driver Abhishek Goel
@ 2020-08-05 11:56   ` Dan Carpenter
  2020-07-24  3:40 ` kernel test robot
                     ` (5 subsequent siblings)
  6 siblings, 0 replies; 10+ messages in thread
From: Dan Carpenter @ 2020-08-05 11:56 UTC (permalink / raw)
  To: kbuild

[-- Attachment #1: Type: text/plain, Size: 2367 bytes --]

Hi Abhishek,

url:    https://github.com/0day-ci/linux/commits/Abhishek-Goel/cpuidle-Add-support-for-pseudo-cpuidle-driver/20200723-141912
base:   https://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm.git linux-next
config: i386-randconfig-m021-20200801 (attached as .config)
compiler: gcc-9 (Debian 9.3.0-14) 9.3.0

If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <lkp@intel.com>
Reported-by: Dan Carpenter <dan.carpenter@oracle.com>

smatch warnings:
drivers/cpuidle/cpuidle-test.c:59 idle_loop() warn: for statement not indented

# https://github.com/0day-ci/linux/commit/27a054c59bf08322f18a47674726524fec8dacf9
git remote add linux-review https://github.com/0day-ci/linux
git remote update linux-review
git checkout 27a054c59bf08322f18a47674726524fec8dacf9
vim +59 drivers/cpuidle/cpuidle-test.c

27a054c59bf0832 Abhishek Goel 2020-07-23  45  static int __cpuidle idle_loop(struct cpuidle_device *dev,
27a054c59bf0832 Abhishek Goel 2020-07-23  46  				struct cpuidle_driver *drv,
27a054c59bf0832 Abhishek Goel 2020-07-23  47  				int index)
27a054c59bf0832 Abhishek Goel 2020-07-23  48  {
27a054c59bf0832 Abhishek Goel 2020-07-23  49  	u64 time_start;
27a054c59bf0832 Abhishek Goel 2020-07-23  50  
27a054c59bf0832 Abhishek Goel 2020-07-23  51  	local_irq_enable();
27a054c59bf0832 Abhishek Goel 2020-07-23  52  	if (!current_set_polling_and_test()) {
27a054c59bf0832 Abhishek Goel 2020-07-23  53  		while (!need_resched())
27a054c59bf0832 Abhishek Goel 2020-07-23  54  			cpu_relax();
27a054c59bf0832 Abhishek Goel 2020-07-23  55  	}
27a054c59bf0832 Abhishek Goel 2020-07-23  56  
27a054c59bf0832 Abhishek Goel 2020-07-23  57  	time_start = local_clock();
27a054c59bf0832 Abhishek Goel 2020-07-23  58  
27a054c59bf0832 Abhishek Goel 2020-07-23 @59  	while (local_clock() - time_start < drv->states[index].exit_latency)

What does this while loop do?

27a054c59bf0832 Abhishek Goel 2020-07-23  60  
27a054c59bf0832 Abhishek Goel 2020-07-23  61  	current_clr_polling();

Not indented.

27a054c59bf0832 Abhishek Goel 2020-07-23  62  
27a054c59bf0832 Abhishek Goel 2020-07-23  63  	return index;
27a054c59bf0832 Abhishek Goel 2020-07-23  64  }

---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all(a)lists.01.org

[-- Attachment #2: config.gz --]
[-- Type: application/gzip, Size: 27218 bytes --]

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [RFC] cpuidle : Add support for pseudo-cpuidle driver
@ 2020-08-05 11:56   ` Dan Carpenter
  0 siblings, 0 replies; 10+ messages in thread
From: Dan Carpenter @ 2020-08-05 11:56 UTC (permalink / raw)
  To: kbuild-all

[-- Attachment #1: Type: text/plain, Size: 2367 bytes --]

Hi Abhishek,

url:    https://github.com/0day-ci/linux/commits/Abhishek-Goel/cpuidle-Add-support-for-pseudo-cpuidle-driver/20200723-141912
base:   https://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm.git linux-next
config: i386-randconfig-m021-20200801 (attached as .config)
compiler: gcc-9 (Debian 9.3.0-14) 9.3.0

If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <lkp@intel.com>
Reported-by: Dan Carpenter <dan.carpenter@oracle.com>

smatch warnings:
drivers/cpuidle/cpuidle-test.c:59 idle_loop() warn: for statement not indented

# https://github.com/0day-ci/linux/commit/27a054c59bf08322f18a47674726524fec8dacf9
git remote add linux-review https://github.com/0day-ci/linux
git remote update linux-review
git checkout 27a054c59bf08322f18a47674726524fec8dacf9
vim +59 drivers/cpuidle/cpuidle-test.c

27a054c59bf0832 Abhishek Goel 2020-07-23  45  static int __cpuidle idle_loop(struct cpuidle_device *dev,
27a054c59bf0832 Abhishek Goel 2020-07-23  46  				struct cpuidle_driver *drv,
27a054c59bf0832 Abhishek Goel 2020-07-23  47  				int index)
27a054c59bf0832 Abhishek Goel 2020-07-23  48  {
27a054c59bf0832 Abhishek Goel 2020-07-23  49  	u64 time_start;
27a054c59bf0832 Abhishek Goel 2020-07-23  50  
27a054c59bf0832 Abhishek Goel 2020-07-23  51  	local_irq_enable();
27a054c59bf0832 Abhishek Goel 2020-07-23  52  	if (!current_set_polling_and_test()) {
27a054c59bf0832 Abhishek Goel 2020-07-23  53  		while (!need_resched())
27a054c59bf0832 Abhishek Goel 2020-07-23  54  			cpu_relax();
27a054c59bf0832 Abhishek Goel 2020-07-23  55  	}
27a054c59bf0832 Abhishek Goel 2020-07-23  56  
27a054c59bf0832 Abhishek Goel 2020-07-23  57  	time_start = local_clock();
27a054c59bf0832 Abhishek Goel 2020-07-23  58  
27a054c59bf0832 Abhishek Goel 2020-07-23 @59  	while (local_clock() - time_start < drv->states[index].exit_latency)

What does this while loop do?

27a054c59bf0832 Abhishek Goel 2020-07-23  60  
27a054c59bf0832 Abhishek Goel 2020-07-23  61  	current_clr_polling();

Not indented.

27a054c59bf0832 Abhishek Goel 2020-07-23  62  
27a054c59bf0832 Abhishek Goel 2020-07-23  63  	return index;
27a054c59bf0832 Abhishek Goel 2020-07-23  64  }

---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all(a)lists.01.org

[-- Attachment #2: config.gz --]
[-- Type: application/gzip, Size: 27218 bytes --]

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [RFC] cpuidle : Add support for pseudo-cpuidle driver
  2020-07-23  6:13 [RFC] cpuidle : Add support for pseudo-cpuidle driver Abhishek Goel
                   ` (5 preceding siblings ...)
  2020-08-05 11:56   ` Dan Carpenter
@ 2020-08-20 19:33 ` Fontenot, Nathan
  6 siblings, 0 replies; 10+ messages in thread
From: Fontenot, Nathan @ 2020-08-20 19:33 UTC (permalink / raw)
  To: Abhishek Goel, linux-pm, linux-kernel; +Cc: rjw, daniel.lezcano, mpe, ego

On 7/23/2020 1:13 AM, Abhishek Goel wrote:
> This option adds support for a testing cpuidle driver, which allows
> user to define custom idle states with their respective latencies and
> residencies. This is useful for testing the behaviour of governors on
> customized set of idle states.
> 
> This can be used as of now by hard-coding the customized set of cpuidle
> states in the driver. Will add the capability of this driver to be used
> as a module in subsequent patches.
> 
> Original idea and discussion for this patch can be found at:
> https://nam11.safelinks.protection.outlook.com/?url=https%3A%2F%2Flkml.org%2Flkml%2F2019%2F12%2F17%2F655&amp;data=02%7C01%7CNathan.Fontenot%40amd.com%7C25e5be70d73e4027242208d82ed0096b%7C3dd8961fe4884e608e11a82d994e183d%7C0%7C0%7C637310818339452963&amp;sdata=mO%2BOhH%2BoDiYJJDHUfF%2BFVtgzBAO8H%2FcaiqWACJOxtmE%3D&amp;reserved=0
> 
> Signed-off-by: Abhishek Goel <huntbag@linux.vnet.ibm.com>
> ---

A couple of thoughts after getting a chance to play around with this on AMD
systems. Once I added C-states for AMD systems andd moved the driver (see below)
everything works as expected. One issue I do see is that boot is really slow
one the system I'm using. I haven't had a chance to look into why but will
let you know if it's related to the driver.

For this to work on x86 I believe you'll need to have the driver
live in drivers/idle instead of drivers/cpuidle. With ACPI you can only register
one idle driver and the first one to register is set as the driver. Moving
this to drivers/idle allows the psuedo-cpuidle driver to register before the
acpi-idle driver. Introducing a boot option to enable the psuedo-idle driver
would also help by allowing you to build the driver into the kernel and allow
you to boot into the default idle driver.

When selecting the C-state tables to use (sim_type=X) I think you could
use the existing acpi routines to read the C-states directly from the
ACPI tables and then just update the .idle routine pointer. This should
allow the driver to work on any x86 system without having to update
the driver code.

-Nathan

>  drivers/cpuidle/Kconfig        |   9 ++
>  drivers/cpuidle/Makefile       |   1 +
>  drivers/cpuidle/cpuidle-test.c | 276 +++++++++++++++++++++++++++++++++
>  3 files changed, 286 insertions(+)
>  create mode 100644 drivers/cpuidle/cpuidle-test.c
> 
> diff --git a/drivers/cpuidle/Kconfig b/drivers/cpuidle/Kconfig
> index c0aeedd66f02..1d73153a0e35 100644
> --- a/drivers/cpuidle/Kconfig
> +++ b/drivers/cpuidle/Kconfig
> @@ -71,6 +71,15 @@ config HALTPOLL_CPUIDLE
>  	 before halting in the guest (more efficient than polling in the
>  	 host via halt_poll_ns for some scenarios).
>  
> +config TEST_CPUIDLE
> +	tristate "cpuidle test driver"
> +	default m
> +	help
> +	 This option enables a testing cpuidle driver, which allows to user
> +	 to define custom idle states with their respective latencies and residencies.
> +	 This is useful for testing the behaviour of governors on different
> +	 set of idle states.
> +
>  endif
>  
>  config ARCH_NEEDS_CPU_IDLE_COUPLED
> diff --git a/drivers/cpuidle/Makefile b/drivers/cpuidle/Makefile
> index f07800cbb43f..68ea7dc257b5 100644
> --- a/drivers/cpuidle/Makefile
> +++ b/drivers/cpuidle/Makefile
> @@ -8,6 +8,7 @@ obj-$(CONFIG_ARCH_NEEDS_CPU_IDLE_COUPLED) += coupled.o
>  obj-$(CONFIG_DT_IDLE_STATES)		  += dt_idle_states.o
>  obj-$(CONFIG_ARCH_HAS_CPU_RELAX)	  += poll_state.o
>  obj-$(CONFIG_HALTPOLL_CPUIDLE)		  += cpuidle-haltpoll.o
> +obj-$(CONFIG_TEST_CPUIDLE)		  += cpuidle-test.o
>  
>  ##################################################################################
>  # ARM SoC drivers
> diff --git a/drivers/cpuidle/cpuidle-test.c b/drivers/cpuidle/cpuidle-test.c
> new file mode 100644
> index 000000000000..399729440569
> --- /dev/null
> +++ b/drivers/cpuidle/cpuidle-test.c
> @@ -0,0 +1,276 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + *  cpuidle-test - Test driver for cpuidle.
> + *
> + */
> +
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +#include <linux/init.h>
> +#include <linux/moduleparam.h>
> +#include <linux/cpuidle.h>
> +#include <linux/cpu.h>
> +#include <linux/module.h>
> +#include <linux/sched/idle.h>
> +#include <linux/sched/clock.h>
> +#include <linux/sched/idle.h>
> +
> +#define CPUIDLE_STATE_MAX	10
> +#define MAX_PARAM_LENGTH	100
> +
> +static unsigned int nr_states = 4;
> +static unsigned int sim_type = 1;
> +static char name[MAX_PARAM_LENGTH];
> +static char latency_us[MAX_PARAM_LENGTH];
> +static char residency_us[MAX_PARAM_LENGTH];
> +
> +
> +module_param(nr_states, uint, 0644);
> +module_param(sim_type, uint, 0644);
> +module_param_string(name, name, MAX_PARAM_LENGTH, 0644);
> +module_param_string(latency_us, latency_us, MAX_PARAM_LENGTH, 0644);
> +module_param_string(residency_us, residency_us, MAX_PARAM_LENGTH, 0644);
> +
> +static struct cpuidle_driver test_cpuidle_driver = {
> +	.name		= "test_cpuidle",
> +	.owner		= THIS_MODULE,
> +};
> +
> +static struct cpuidle_state *cpuidle_state_table __read_mostly;
> +
> +static struct cpuidle_device __percpu *test_cpuidle_devices;
> +static enum cpuhp_state test_hp_idlestate;
> +
> +
> +static int __cpuidle idle_loop(struct cpuidle_device *dev,
> +				struct cpuidle_driver *drv,
> +				int index)
> +{
> +	u64 time_start;
> +
> +	local_irq_enable();
> +	if (!current_set_polling_and_test()) {
> +		while (!need_resched())
> +			cpu_relax();
> +	}
> +
> +	time_start = local_clock();
> +
> +	while (local_clock() - time_start < drv->states[index].exit_latency)
> +
> +	current_clr_polling();
> +
> +	return index;
> +}
> +
> +static struct cpuidle_state cpuidle_states[CPUIDLE_STATE_MAX] = {
> +	{ /* Snooze */
> +		.name = "snooze",
> +		.exit_latency = 0,
> +		.target_residency = 0,
> +		.enter = idle_loop },
> +};
> +
> +static struct cpuidle_state cpuidle_states_ppc[] = {
> +	{	.name = "snooze",
> +		.exit_latency = 0,
> +		.target_residency = 0,
> +		.enter = idle_loop },
> +	{
> +		.name = "stop0",
> +		.exit_latency = 2,
> +		.target_residency = 20,
> +		.enter = idle_loop },
> +	{
> +		.name = "stop1",
> +		.exit_latency = 5,
> +		.target_residency = 50,
> +		.enter = idle_loop },
> +	{
> +		.name = "stop2",
> +		.exit_latency = 10,
> +		.target_residency = 100,
> +		.enter = idle_loop },
> +};
> +
> +static struct cpuidle_state cpuidle_states_intel[] = {
> +	{	.name = "poll",
> +		.exit_latency = 0,
> +		.target_residency = 0,
> +		.enter = idle_loop },
> +	{
> +		.name = "c1",
> +		.exit_latency = 2,
> +		.target_residency = 2,
> +		.enter = idle_loop },
> +	{
> +		.name = "c1e",
> +		.exit_latency = 10,
> +		.target_residency = 20,
> +		.enter = idle_loop },
> +	{
> +		.name = "c3",
> +		.exit_latency = 80,
> +		.target_residency = 211,
> +		.enter = idle_loop },
> +};
> +
> +int cpuidle_cpu_online(unsigned int cpu)
> +{
> +	struct cpuidle_device *dev;
> +
> +	dev = per_cpu_ptr(test_cpuidle_devices, cpu);
> +	if (!dev->registered) {
> +		dev->cpu = cpu;
> +		if (cpuidle_register_device(dev)) {
> +			pr_notice("cpuidle_register_device %d failed!\n", cpu);
> +			return -EIO;
> +		}
> +	}
> +
> +	return 0;
> +}
> +
> +int cpuidle_cpu_dead(unsigned int cpu)
> +{
> +	struct cpuidle_device *dev;
> +
> +	dev = per_cpu_ptr(test_cpuidle_devices, cpu);
> +	if (dev->registered)
> +		cpuidle_unregister_device(dev);
> +
> +	return 0;
> +}
> +
> +int cpuidle_driver_init(void)
> +{
> +	int idle_state;
> +	struct cpuidle_driver *drv = &test_cpuidle_driver;
> +
> +	drv->state_count = 0;
> +
> +	for (idle_state = 0; idle_state < nr_states; ++idle_state) {
> +		/* Is the state not enabled? */
> +		if (cpuidle_state_table[idle_state].enter == NULL)
> +			continue;
> +
> +		drv->states[drv->state_count] =	/* structure copy */
> +			cpuidle_state_table[idle_state];
> +
> +		drv->state_count += 1;
> +	}
> +
> +	return 0;
> +}
> +
> +int add_cpuidle_states(void)
> +{
> +	/* Parse the module param and initialize the idle states here
> +	 * in cpuidle_state_table.
> +	 */
> +	char *this_param;
> +	char *input_name = name;
> +	char *input_res = residency_us;
> +	char *input_lat = latency_us;
> +	int index = 1;
> +	long temp;
> +	int rc;
> +
> +	switch (sim_type) {
> +	case 1:
> +		cpuidle_state_table = cpuidle_states_ppc;
> +		return 0;
> +	case 2:
> +		cpuidle_state_table = cpuidle_states_intel;
> +		return 0;
> +	case 3:
> +		break;
> +	default:
> +		pr_warn("Sim value out of bound\n");
> +		break;
> +	}
> +
> +	if (strnlen(input_name, MAX_PARAM_LENGTH)) {
> +		while ((this_param = strsep(&input_name, ",")) && index <= nr_states) {
> +			strcpy(cpuidle_states[index].name, this_param);
> +			cpuidle_states[index].enter = idle_loop;
> +			index++;
> +		}
> +	}
> +
> +	if (strnlen(input_res, MAX_PARAM_LENGTH)) {
> +		index = 1;
> +		while ((this_param = strsep(&input_res, ",")) && index <= nr_states) {
> +			rc = kstrtol(this_param, 10, &temp);
> +			cpuidle_states[index].target_residency = temp;
> +			index++;
> +		}
> +	}
> +
> +	if (strnlen(input_lat, MAX_PARAM_LENGTH)) {
> +		index = 1;
> +		while ((this_param = strsep(&input_lat, ",")) && index <= nr_states) {
> +			rc = kstrtol(this_param, 10, &temp);
> +			cpuidle_states[index].exit_latency = temp;
> +			index++;
> +		}
> +	}
> +
> +	cpuidle_state_table = cpuidle_states;
> +	return nr_states;
> +}
> +
> +void test_cpuidle_uninit(void)
> +{
> +	if (test_hp_idlestate)
> +		cpuhp_remove_state(test_hp_idlestate);
> +	cpuidle_unregister_driver(&test_cpuidle_driver);
> +
> +	free_percpu(test_cpuidle_devices);
> +	test_cpuidle_devices = NULL;
> +}
> +
> +int __init test_cpuidle_init(void)
> +{
> +	int retval;
> +
> +	add_cpuidle_states();
> +	cpuidle_driver_init();
> +	retval = cpuidle_register(&test_cpuidle_driver, NULL);
> +	if (retval) {
> +		printk(KERN_DEBUG "Registration of test driver failed.\n");
> +		return retval;
> +	}
> +
> +	test_cpuidle_devices = alloc_percpu(struct cpuidle_device);
> +	if (test_cpuidle_devices == NULL) {
> +		cpuidle_unregister_driver(&test_cpuidle_driver);
> +		return -ENOMEM;
> +	}
> +
> +	retval = cpuhp_setup_state_nocalls(CPUHP_AP_ONLINE_DYN,
> +					   "cpuidle/powernv:online",
> +					   cpuidle_cpu_online,
> +					   cpuidle_cpu_dead);
> +
> +	if (retval < 0) {
> +		test_cpuidle_uninit();
> +	} else {
> +		test_hp_idlestate = retval;
> +		retval = 0;
> +	}
> +
> +	return retval;
> +}
> +
> +void __exit test_cpuidle_exit(void)
> +{
> +	test_cpuidle_uninit();
> +}
> +
> +module_init(test_cpuidle_init);
> +module_exit(test_cpuidle_exit);
> +MODULE_DESCRIPTION("Test Cpuidle Driver");
> +MODULE_AUTHOR("Abhishek Goel");
> +MODULE_LICENSE("GPL");
> +
> 

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [RFC] cpuidle : Add support for pseudo-cpuidle driver
@ 2020-08-01  8:30 kernel test robot
  0 siblings, 0 replies; 10+ messages in thread
From: kernel test robot @ 2020-08-01  8:30 UTC (permalink / raw)
  To: kbuild

[-- Attachment #1: Type: text/plain, Size: 3100 bytes --]

CC: kbuild-all(a)lists.01.org
In-Reply-To: <20200723061339.9747-1-huntbag@linux.vnet.ibm.com>
References: <20200723061339.9747-1-huntbag@linux.vnet.ibm.com>
TO: Abhishek Goel <huntbag@linux.vnet.ibm.com>

Hi Abhishek,

[FYI, it's a private test report for your RFC patch.]
[auto build test WARNING on pm/linux-next]
[also build test WARNING on linux/master linus/master v5.8-rc7 next-20200731]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch]

url:    https://github.com/0day-ci/linux/commits/Abhishek-Goel/cpuidle-Add-support-for-pseudo-cpuidle-driver/20200723-141912
base:   https://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm.git linux-next
:::::: branch date: 9 days ago
:::::: commit date: 9 days ago
config: i386-randconfig-m021-20200801 (attached as .config)
compiler: gcc-9 (Debian 9.3.0-14) 9.3.0

If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <lkp@intel.com>
Reported-by: Dan Carpenter <dan.carpenter@oracle.com>

smatch warnings:
drivers/cpuidle/cpuidle-test.c:59 idle_loop() warn: for statement not indented

# https://github.com/0day-ci/linux/commit/27a054c59bf08322f18a47674726524fec8dacf9
git remote add linux-review https://github.com/0day-ci/linux
git remote update linux-review
git checkout 27a054c59bf08322f18a47674726524fec8dacf9
vim +59 drivers/cpuidle/cpuidle-test.c

27a054c59bf0832 Abhishek Goel 2020-07-23  43  
27a054c59bf0832 Abhishek Goel 2020-07-23  44  
27a054c59bf0832 Abhishek Goel 2020-07-23  45  static int __cpuidle idle_loop(struct cpuidle_device *dev,
27a054c59bf0832 Abhishek Goel 2020-07-23  46  				struct cpuidle_driver *drv,
27a054c59bf0832 Abhishek Goel 2020-07-23  47  				int index)
27a054c59bf0832 Abhishek Goel 2020-07-23  48  {
27a054c59bf0832 Abhishek Goel 2020-07-23  49  	u64 time_start;
27a054c59bf0832 Abhishek Goel 2020-07-23  50  
27a054c59bf0832 Abhishek Goel 2020-07-23  51  	local_irq_enable();
27a054c59bf0832 Abhishek Goel 2020-07-23  52  	if (!current_set_polling_and_test()) {
27a054c59bf0832 Abhishek Goel 2020-07-23  53  		while (!need_resched())
27a054c59bf0832 Abhishek Goel 2020-07-23  54  			cpu_relax();
27a054c59bf0832 Abhishek Goel 2020-07-23  55  	}
27a054c59bf0832 Abhishek Goel 2020-07-23  56  
27a054c59bf0832 Abhishek Goel 2020-07-23  57  	time_start = local_clock();
27a054c59bf0832 Abhishek Goel 2020-07-23  58  
27a054c59bf0832 Abhishek Goel 2020-07-23 @59  	while (local_clock() - time_start < drv->states[index].exit_latency)
27a054c59bf0832 Abhishek Goel 2020-07-23  60  
27a054c59bf0832 Abhishek Goel 2020-07-23  61  	current_clr_polling();
27a054c59bf0832 Abhishek Goel 2020-07-23  62  
27a054c59bf0832 Abhishek Goel 2020-07-23  63  	return index;
27a054c59bf0832 Abhishek Goel 2020-07-23  64  }
27a054c59bf0832 Abhishek Goel 2020-07-23  65  

---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all(a)lists.01.org

[-- Attachment #2: config.gz --]
[-- Type: application/gzip, Size: 27218 bytes --]

^ permalink raw reply	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2020-08-20 19:33 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-07-23  6:13 [RFC] cpuidle : Add support for pseudo-cpuidle driver Abhishek Goel
2020-07-23  6:24 ` Randy Dunlap
2020-07-24  3:40 ` kernel test robot
2020-07-24  3:40 ` [RFC PATCH] cpuidle : cpuidle_cpu_online() can be static kernel test robot
2020-07-24  3:41 ` [RFC] cpuidle : Add support for pseudo-cpuidle driver kernel test robot
2020-07-24 10:51 ` kernel test robot
2020-08-05 11:56 ` Dan Carpenter
2020-08-05 11:56   ` Dan Carpenter
2020-08-20 19:33 ` Fontenot, Nathan
2020-08-01  8:30 kernel test robot

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.