diff mbox

cpuidle: add freescale e500 family porcessors idle support

Message ID 1375167603-16722-1-git-send-email-dongsheng.wang@freescale.com (mailing list archive)
State Changes Requested, archived
Headers show

Commit Message

Dongsheng Wang July 30, 2013, 7 a.m. UTC
From: Wang Dongsheng <dongsheng.wang@freescale.com>

Add cpuidle support for e500 family, using cpuidle framework to
manage various low power modes. The new implementation will remain
compatible with original idle method.

Initially, this supports PW10, and subsequent patches will support
PW20/DOZE/NAP.

Signed-off-by: Wang Dongsheng <dongsheng.wang@freescale.com>
---
This patch keep using cpuidle_register_device(), because we need to support cpu
hotplug. I will fix "device" issue in this driver, after
Deepthi Dharwar <deepthi@linux.vnet.ibm.com> add a hotplug handler into cpuidle
freamwork.

Comments

Daniel Lezcano July 30, 2013, 9:51 a.m. UTC | #1
On 07/30/2013 09:00 AM, Dongsheng Wang wrote:
> From: Wang Dongsheng <dongsheng.wang@freescale.com>
> 
> Add cpuidle support for e500 family, using cpuidle framework to
> manage various low power modes. The new implementation will remain
> compatible with original idle method.
> 
> Initially, this supports PW10, and subsequent patches will support
> PW20/DOZE/NAP.
> 
> Signed-off-by: Wang Dongsheng <dongsheng.wang@freescale.com>
> ---
> This patch keep using cpuidle_register_device(), because we need to support cpu
> hotplug. I will fix "device" issue in this driver, after
> Deepthi Dharwar <deepthi@linux.vnet.ibm.com> add a hotplug handler into cpuidle
> freamwork.
> 
> diff --git a/arch/powerpc/include/asm/machdep.h b/arch/powerpc/include/asm/machdep.h
> index 8b48090..cbdbe25 100644
> --- a/arch/powerpc/include/asm/machdep.h
> +++ b/arch/powerpc/include/asm/machdep.h
> @@ -271,6 +271,16 @@ extern void power7_idle(void);
>  extern void ppc6xx_idle(void);
>  extern void book3e_idle(void);
>  
> +/* Wait for Interrupt */
> +static inline void fsl_cpuidle_wait(void)
> +{
> +#ifdef CONFIG_PPC64
> +	book3e_idle();
> +#else
> +	e500_idle();
> +#endif
> +}
> +
>  /*
>   * ppc_md contains a copy of the machine description structure for the
>   * current platform. machine_id contains the initial address where the
> diff --git a/drivers/cpuidle/Kconfig b/drivers/cpuidle/Kconfig
> index b3fb81d..7ed114b 100644
> --- a/drivers/cpuidle/Kconfig
> +++ b/drivers/cpuidle/Kconfig
> @@ -35,6 +35,11 @@ depends on ARM
>  source "drivers/cpuidle/Kconfig.arm"
>  endmenu
>  
> +menu "PowerPC CPU Idle Drivers"
> +depends on PPC32 || PPC64
> +source "drivers/cpuidle/Kconfig.powerpc"
> +endmenu
> +
>  endif
>  
>  config ARCH_NEEDS_CPU_IDLE_COUPLED
> diff --git a/drivers/cpuidle/Kconfig.powerpc b/drivers/cpuidle/Kconfig.powerpc
> new file mode 100644
> index 0000000..9f3f5ef
> --- /dev/null
> +++ b/drivers/cpuidle/Kconfig.powerpc
> @@ -0,0 +1,9 @@
> +#
> +# PowerPC CPU Idle drivers
> +#
> +
> +config PPC_E500_CPUIDLE
> +	bool "CPU Idle Driver for E500 family processors"
> +	depends on FSL_SOC_BOOKE
> +	help
> +	  Select this to enable cpuidle on e500 family processors.
> diff --git a/drivers/cpuidle/Makefile b/drivers/cpuidle/Makefile
> index 0b9d200..0dde3db 100644
> --- a/drivers/cpuidle/Makefile
> +++ b/drivers/cpuidle/Makefile
> @@ -11,3 +11,7 @@ obj-$(CONFIG_ARM_HIGHBANK_CPUIDLE)	+= cpuidle-calxeda.o
>  obj-$(CONFIG_ARM_KIRKWOOD_CPUIDLE)	+= cpuidle-kirkwood.o
>  obj-$(CONFIG_ARM_ZYNQ_CPUIDLE)		+= cpuidle-zynq.o
>  obj-$(CONFIG_ARM_U8500_CPUIDLE)         += cpuidle-ux500.o
> +
> +##################################################################################
> +# PowerPC platform drivers
> +obj-$(CONFIG_PPC_E500_CPUIDLE)		+= cpuidle-e500.o
> diff --git a/drivers/cpuidle/cpuidle-e500.c b/drivers/cpuidle/cpuidle-e500.c
> new file mode 100644
> index 0000000..1919cea
> --- /dev/null
> +++ b/drivers/cpuidle/cpuidle-e500.c
> @@ -0,0 +1,222 @@
> +/*
> + * Copyright 2013 Freescale Semiconductor, Inc.
> + *
> + * CPU Idle driver for Freescale PowerPC e500 family processors.
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + *
> + * Author: Wang Dongsheng <dongsheng.wang@freescale.com>
> + */
> +
> +#include <linux/cpu.h>
> +#include <linux/cpuidle.h>
> +#include <linux/init.h>
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +#include <linux/notifier.h>
> +
> +#include <asm/machdep.h>
> +
> +static struct cpuidle_driver e500_idle_driver = {
> +	.name = "e500_idle",
> +	.owner = THIS_MODULE,
> +};
> +
> +static struct cpuidle_device __percpu *e500_cpuidle_devices;
> +
> +static void e500_cpuidle(void)
> +{
> +	/*
> +	 * This would call on the cpuidle framework, and the back-end
> +	 * driver to go to idle states.
> +	 */
> +	if (cpuidle_idle_call()) {
> +		/*
> +		 * On error, execute default handler
> +		 * to go into low thread priority and possibly
> +		 * low power mode.
> +		 */
> +		HMT_low();
> +		HMT_very_low();
> +	}
> +}

Nope, this is not the place to add such function.

> +static int pw10_enter(struct cpuidle_device *dev,
> +			struct cpuidle_driver *drv, int index)
> +{
> +	fsl_cpuidle_wait();
> +	return index;
> +}
> +
> +static struct cpuidle_state fsl_pw_idle_states[] = {
> +	{
> +		.name = "pw10",
> +		.desc = "pw10",
> +		.flags = CPUIDLE_FLAG_TIME_VALID,
> +		.exit_latency = 0,
> +		.target_residency = 0,
> +		.enter = &pw10_enter
> +	},
> +};
> +
> +static int cpu_hotplug_notify(struct notifier_block *n,
> +			unsigned long action, void *hcpu)
> +{
> +	unsigned long hotcpu = (unsigned long)hcpu;
> +	struct cpuidle_device *dev =
> +			per_cpu_ptr(e500_cpuidle_devices, hotcpu);
> +
> +	if (dev && cpuidle_get_driver()) {
> +		switch (action) {
> +		case CPU_ONLINE:
> +		case CPU_ONLINE_FROZEN:
> +			cpuidle_pause_and_lock();
> +			cpuidle_enable_device(dev);
> +			cpuidle_resume_and_unlock();
> +			break;
> +
> +		case CPU_DEAD:
> +		case CPU_DEAD_FROZEN:
> +			cpuidle_pause_and_lock();
> +			cpuidle_disable_device(dev);
> +			cpuidle_resume_and_unlock();
> +			break;
> +
> +		default:
> +			return NOTIFY_DONE;
> +		}
> +	}
> +
> +	return NOTIFY_OK;
> +}
> +
> +static struct notifier_block cpu_hotplug_notifier = {
> +	.notifier_call = cpu_hotplug_notify,
> +};

This should go to the cpuidle framework.

> +
> +/*
> + * e500_idle_devices_init(void)
> + * allocate, initialize and register cpuidle device
> + */
> +static int e500_idle_devices_init(void)
> +{
> +	int i;
> +	struct cpuidle_driver *drv = &e500_idle_driver;
> +	struct cpuidle_device *dev;
> +
> +	e500_cpuidle_devices = alloc_percpu(struct cpuidle_device);
> +	if (!e500_cpuidle_devices)
> +		return -ENOMEM;
> +
> +	for_each_possible_cpu(i) {
> +		dev = per_cpu_ptr(e500_cpuidle_devices, i);
> +		dev->state_count = drv->state_count;
> +		dev->cpu = i;
> +
> +		if (cpuidle_register_device(dev)) {
> +			pr_err("cpuidle_register_device %d failed!\n", i);
> +			return -EIO;
> +		}
> +	}
> +
> +	return 0;
> +}
> +
> +/*
> + * e500_idle_devices_uninit(void)
> + * unregister cpuidle devices and de-allocate memory
> + */
> +static void e500_idle_devices_uninit(void)
> +{
> +	int i;
> +	struct cpuidle_device *dev;
> +
> +	if (!e500_cpuidle_devices)
> +		return;
> +
> +	for_each_possible_cpu(i) {
> +		dev = per_cpu_ptr(e500_cpuidle_devices, i);
> +		cpuidle_unregister_device(dev);
> +	}
> +
> +	free_percpu(e500_cpuidle_devices);
> +}
> +
> +static void e500_cpuidle_driver_init(unsigned int max_idle_state,
> +		struct cpuidle_state *cpuidle_state_table)
> +{
> +	int idle_state;
> +	struct cpuidle_driver *drv = &e500_idle_driver;
> +
> +	drv->state_count = 0;
> +
> +	for (idle_state = 0; idle_state < max_idle_state; ++idle_state) {
> +		if (!cpuidle_state_table[idle_state].enter)
> +			break;
> +
> +		drv->states[drv->state_count] = cpuidle_state_table[idle_state];
> +		drv->state_count++;
> +	}
> +}
> +
> +static int cpu_is_feature(unsigned long feature)
> +{
> +	return (cur_cpu_spec->cpu_features == feature);
> +}
> +
> +static int __init e500_idle_init(void)
> +{
> +	struct cpuidle_state *cpuidle_state_table = NULL;
> +	struct cpuidle_driver *drv = &e500_idle_driver;
> +	int err;
> +	unsigned int max_idle_state = 0;
> +
> +	if (cpuidle_disable != IDLE_NO_OVERRIDE)
> +		return -ENODEV;
> +
> +	if (cpu_is_feature(CPU_FTRS_E500MC) || cpu_is_feature(CPU_FTRS_E5500) ||
> +			cpu_is_feature(CPU_FTRS_E6500)) {
> +		cpuidle_state_table = fsl_pw_idle_states;
> +		max_idle_state = ARRAY_SIZE(fsl_pw_idle_states);
> +	}
> +
> +	if (!cpuidle_state_table || !max_idle_state)
> +		return -EPERM;

Please use different drivers for each and then register the right one
instead of state count convolutions.

Then use cpuidle_register(&mydriver, NULL) and get rid of the duplicate
initialization routine.


> +	e500_cpuidle_driver_init(max_idle_state, cpuidle_state_table);
> +
> +	if (!drv->state_count)
> +		return -EPERM;
> +
> +	err = cpuidle_register_driver(drv);
> +	if (err) {
> +		pr_err("Register e500 family cpuidle driver failed.\n");
> +
> +		return err;
> +	}
> +
> +	err = e500_idle_devices_init();
> +	if (err)
> +		goto out;
> +
> +	err = register_cpu_notifier(&cpu_hotplug_notifier);
> +	if (err)
> +		goto out;
> +
> +	ppc_md.power_save = e500_cpuidle;

This is not the place.

> +
> +	pr_info("e500_idle_driver registered.\n");
> +
> +	return 0;
> +
> +out:
> +	e500_idle_devices_uninit();
> +	cpuidle_unregister_driver(drv);
> +
> +	pr_err("Register e500 family cpuidle driver failed.\n");
> +
> +	return err;
> +}
> +device_initcall(e500_idle_init);
>
Wang Dongsheng-B40534 July 30, 2013, 11:02 a.m. UTC | #2
DQoNCj4gLS0tLS1PcmlnaW5hbCBNZXNzYWdlLS0tLS0NCj4gRnJvbTogRGFuaWVsIExlemNhbm8g
W21haWx0bzpkYW5pZWwubGV6Y2Fub0BsaW5hcm8ub3JnXQ0KPiBTZW50OiBUdWVzZGF5LCBKdWx5
IDMwLCAyMDEzIDU6NTEgUE0NCj4gVG86IFdhbmcgRG9uZ3NoZW5nLUI0MDUzNA0KPiBDYzogV29v
ZCBTY290dC1CMDc0MjE7IHJqd0BzaXNrLnBsOyBiZW5oQGtlcm5lbC5jcmFzaGluZy5vcmc7IExp
IFlhbmctDQo+IFI1ODQ3MjsgWmhhbyBDaGVuaHVpLUIzNTMzNjsgbGludXgtcG1Admdlci5rZXJu
ZWwub3JnOyBsaW51eHBwYy0NCj4gZGV2QGxpc3RzLm96bGFicy5vcmcNCj4gU3ViamVjdDogUmU6
IFtQQVRDSF0gY3B1aWRsZTogYWRkIGZyZWVzY2FsZSBlNTAwIGZhbWlseSBwb3JjZXNzb3JzIGlk
bGUNCj4gc3VwcG9ydA0KPiANCj4gT24gMDcvMzAvMjAxMyAwOTowMCBBTSwgRG9uZ3NoZW5nIFdh
bmcgd3JvdGU6DQo+ID4gRnJvbTogV2FuZyBEb25nc2hlbmcgPGRvbmdzaGVuZy53YW5nQGZyZWVz
Y2FsZS5jb20+DQo+ID4NCj4gPiBBZGQgY3B1aWRsZSBzdXBwb3J0IGZvciBlNTAwIGZhbWlseSwg
dXNpbmcgY3B1aWRsZSBmcmFtZXdvcmsgdG8gbWFuYWdlDQo+ID4gdmFyaW91cyBsb3cgcG93ZXIg
bW9kZXMuIFRoZSBuZXcgaW1wbGVtZW50YXRpb24gd2lsbCByZW1haW4gY29tcGF0aWJsZQ0KPiA+
IHdpdGggb3JpZ2luYWwgaWRsZSBtZXRob2QuDQo+ID4NCj4gPiBJbml0aWFsbHksIHRoaXMgc3Vw
cG9ydHMgUFcxMCwgYW5kIHN1YnNlcXVlbnQgcGF0Y2hlcyB3aWxsIHN1cHBvcnQNCj4gPiBQVzIw
L0RPWkUvTkFQLg0KPiA+DQo+ID4gU2lnbmVkLW9mZi1ieTogV2FuZyBEb25nc2hlbmcgPGRvbmdz
aGVuZy53YW5nQGZyZWVzY2FsZS5jb20+DQo+ID4gLS0tDQo+ID4gVGhpcyBwYXRjaCBrZWVwIHVz
aW5nIGNwdWlkbGVfcmVnaXN0ZXJfZGV2aWNlKCksIGJlY2F1c2Ugd2UgbmVlZCB0bw0KPiA+IHN1
cHBvcnQgY3B1IGhvdHBsdWcuIEkgd2lsbCBmaXggImRldmljZSIgaXNzdWUgaW4gdGhpcyBkcml2
ZXIsIGFmdGVyDQo+ID4gRGVlcHRoaSBEaGFyd2FyIDxkZWVwdGhpQGxpbnV4LnZuZXQuaWJtLmNv
bT4gYWRkIGEgaG90cGx1ZyBoYW5kbGVyDQo+ID4gaW50byBjcHVpZGxlIGZyZWFtd29yay4NCj4g
Pg0KPiA+IGRpZmYgLS1naXQgYS9hcmNoL3Bvd2VycGMvaW5jbHVkZS9hc20vbWFjaGRlcC5oDQo+
ID4gYi9hcmNoL3Bvd2VycGMvaW5jbHVkZS9hc20vbWFjaGRlcC5oDQo+ID4gaW5kZXggOGI0ODA5
MC4uY2JkYmUyNSAxMDA2NDQNCj4gPiAtLS0gYS9hcmNoL3Bvd2VycGMvaW5jbHVkZS9hc20vbWFj
aGRlcC5oDQo+ID4gKysrIGIvYXJjaC9wb3dlcnBjL2luY2x1ZGUvYXNtL21hY2hkZXAuaA0KPiA+
IEBAIC0yNzEsNiArMjcxLDE2IEBAIGV4dGVybiB2b2lkIHBvd2VyN19pZGxlKHZvaWQpOyAgZXh0
ZXJuIHZvaWQNCj4gPiBwcGM2eHhfaWRsZSh2b2lkKTsgIGV4dGVybiB2b2lkIGJvb2szZV9pZGxl
KHZvaWQpOw0KPiA+DQo+ID4gKy8qIFdhaXQgZm9yIEludGVycnVwdCAqLw0KPiA+ICtzdGF0aWMg
aW5saW5lIHZvaWQgZnNsX2NwdWlkbGVfd2FpdCh2b2lkKSB7ICNpZmRlZiBDT05GSUdfUFBDNjQN
Cj4gPiArCWJvb2szZV9pZGxlKCk7DQo+ID4gKyNlbHNlDQo+ID4gKwllNTAwX2lkbGUoKTsNCj4g
PiArI2VuZGlmDQo+ID4gK30NCj4gPiArDQo+ID4gIC8qDQo+ID4gICAqIHBwY19tZCBjb250YWlu
cyBhIGNvcHkgb2YgdGhlIG1hY2hpbmUgZGVzY3JpcHRpb24gc3RydWN0dXJlIGZvciB0aGUNCj4g
PiAgICogY3VycmVudCBwbGF0Zm9ybS4gbWFjaGluZV9pZCBjb250YWlucyB0aGUgaW5pdGlhbCBh
ZGRyZXNzIHdoZXJlIHRoZQ0KPiA+IGRpZmYgLS1naXQgYS9kcml2ZXJzL2NwdWlkbGUvS2NvbmZp
ZyBiL2RyaXZlcnMvY3B1aWRsZS9LY29uZmlnDQo+ID4gaW5kZXggYjNmYjgxZC4uN2VkMTE0YiAx
MDA2NDQNCj4gPiAtLS0gYS9kcml2ZXJzL2NwdWlkbGUvS2NvbmZpZw0KPiA+ICsrKyBiL2RyaXZl
cnMvY3B1aWRsZS9LY29uZmlnDQo+ID4gQEAgLTM1LDYgKzM1LDExIEBAIGRlcGVuZHMgb24gQVJN
DQo+ID4gIHNvdXJjZSAiZHJpdmVycy9jcHVpZGxlL0tjb25maWcuYXJtIg0KPiA+ICBlbmRtZW51
DQo+ID4NCj4gPiArbWVudSAiUG93ZXJQQyBDUFUgSWRsZSBEcml2ZXJzIg0KPiA+ICtkZXBlbmRz
IG9uIFBQQzMyIHx8IFBQQzY0DQo+ID4gK3NvdXJjZSAiZHJpdmVycy9jcHVpZGxlL0tjb25maWcu
cG93ZXJwYyINCj4gPiArZW5kbWVudQ0KPiA+ICsNCj4gPiAgZW5kaWYNCj4gPg0KPiA+ICBjb25m
aWcgQVJDSF9ORUVEU19DUFVfSURMRV9DT1VQTEVEDQo+ID4gZGlmZiAtLWdpdCBhL2RyaXZlcnMv
Y3B1aWRsZS9LY29uZmlnLnBvd2VycGMNCj4gYi9kcml2ZXJzL2NwdWlkbGUvS2NvbmZpZy5wb3dl
cnBjDQo+ID4gbmV3IGZpbGUgbW9kZSAxMDA2NDQNCj4gPiBpbmRleCAwMDAwMDAwLi45ZjNmNWVm
DQo+ID4gLS0tIC9kZXYvbnVsbA0KPiA+ICsrKyBiL2RyaXZlcnMvY3B1aWRsZS9LY29uZmlnLnBv
d2VycGMNCj4gPiBAQCAtMCwwICsxLDkgQEANCj4gPiArIw0KPiA+ICsjIFBvd2VyUEMgQ1BVIElk
bGUgZHJpdmVycw0KPiA+ICsjDQo+ID4gKw0KPiA+ICtjb25maWcgUFBDX0U1MDBfQ1BVSURMRQ0K
PiA+ICsJYm9vbCAiQ1BVIElkbGUgRHJpdmVyIGZvciBFNTAwIGZhbWlseSBwcm9jZXNzb3JzIg0K
PiA+ICsJZGVwZW5kcyBvbiBGU0xfU09DX0JPT0tFDQo+ID4gKwloZWxwDQo+ID4gKwkgIFNlbGVj
dCB0aGlzIHRvIGVuYWJsZSBjcHVpZGxlIG9uIGU1MDAgZmFtaWx5IHByb2Nlc3NvcnMuDQo+ID4g
ZGlmZiAtLWdpdCBhL2RyaXZlcnMvY3B1aWRsZS9NYWtlZmlsZSBiL2RyaXZlcnMvY3B1aWRsZS9N
YWtlZmlsZQ0KPiA+IGluZGV4IDBiOWQyMDAuLjBkZGUzZGIgMTAwNjQ0DQo+ID4gLS0tIGEvZHJp
dmVycy9jcHVpZGxlL01ha2VmaWxlDQo+ID4gKysrIGIvZHJpdmVycy9jcHVpZGxlL01ha2VmaWxl
DQo+ID4gQEAgLTExLDMgKzExLDcgQEAgb2JqLSQoQ09ORklHX0FSTV9ISUdIQkFOS19DUFVJRExF
KQkrPSBjcHVpZGxlLQ0KPiBjYWx4ZWRhLm8NCj4gPiAgb2JqLSQoQ09ORklHX0FSTV9LSVJLV09P
RF9DUFVJRExFKQkrPSBjcHVpZGxlLWtpcmt3b29kLm8NCj4gPiAgb2JqLSQoQ09ORklHX0FSTV9a
WU5RX0NQVUlETEUpCQkrPSBjcHVpZGxlLXp5bnEubw0KPiA+ICBvYmotJChDT05GSUdfQVJNX1U4
NTAwX0NQVUlETEUpICAgICAgICAgKz0gY3B1aWRsZS11eDUwMC5vDQo+ID4gKw0KPiA+DQo+ICsj
IyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMj
IyMjIyMjIyMjIyMjIyMNCj4gIyMjIyMjIyMjIw0KPiA+ICsjIFBvd2VyUEMgcGxhdGZvcm0gZHJp
dmVycw0KPiA+ICtvYmotJChDT05GSUdfUFBDX0U1MDBfQ1BVSURMRSkJCSs9IGNwdWlkbGUtZTUw
MC5vDQo+ID4gZGlmZiAtLWdpdCBhL2RyaXZlcnMvY3B1aWRsZS9jcHVpZGxlLWU1MDAuYyBiL2Ry
aXZlcnMvY3B1aWRsZS9jcHVpZGxlLQ0KPiBlNTAwLmMNCj4gPiBuZXcgZmlsZSBtb2RlIDEwMDY0
NA0KPiA+IGluZGV4IDAwMDAwMDAuLjE5MTljZWENCj4gPiAtLS0gL2Rldi9udWxsDQo+ID4gKysr
IGIvZHJpdmVycy9jcHVpZGxlL2NwdWlkbGUtZTUwMC5jDQo+ID4gQEAgLTAsMCArMSwyMjIgQEAN
Cj4gPiArLyoNCj4gPiArICogQ29weXJpZ2h0IDIwMTMgRnJlZXNjYWxlIFNlbWljb25kdWN0b3Is
IEluYy4NCj4gPiArICoNCj4gPiArICogQ1BVIElkbGUgZHJpdmVyIGZvciBGcmVlc2NhbGUgUG93
ZXJQQyBlNTAwIGZhbWlseSBwcm9jZXNzb3JzLg0KPiA+ICsgKg0KPiA+ICsgKiBUaGlzIHByb2dy
YW0gaXMgZnJlZSBzb2Z0d2FyZTsgeW91IGNhbiByZWRpc3RyaWJ1dGUgaXQgYW5kL29yDQo+IG1v
ZGlmeQ0KPiA+ICsgKiBpdCB1bmRlciB0aGUgdGVybXMgb2YgdGhlIEdOVSBHZW5lcmFsIFB1Ymxp
YyBMaWNlbnNlIHZlcnNpb24gMiBhcw0KPiA+ICsgKiBwdWJsaXNoZWQgYnkgdGhlIEZyZWUgU29m
dHdhcmUgRm91bmRhdGlvbi4NCj4gPiArICoNCj4gPiArICogQXV0aG9yOiBXYW5nIERvbmdzaGVu
ZyA8ZG9uZ3NoZW5nLndhbmdAZnJlZXNjYWxlLmNvbT4NCj4gPiArICovDQo+ID4gKw0KPiA+ICsj
aW5jbHVkZSA8bGludXgvY3B1Lmg+DQo+ID4gKyNpbmNsdWRlIDxsaW51eC9jcHVpZGxlLmg+DQo+
ID4gKyNpbmNsdWRlIDxsaW51eC9pbml0Lmg+DQo+ID4gKyNpbmNsdWRlIDxsaW51eC9rZXJuZWwu
aD4NCj4gPiArI2luY2x1ZGUgPGxpbnV4L21vZHVsZS5oPg0KPiA+ICsjaW5jbHVkZSA8bGludXgv
bm90aWZpZXIuaD4NCj4gPiArDQo+ID4gKyNpbmNsdWRlIDxhc20vbWFjaGRlcC5oPg0KPiA+ICsN
Cj4gPiArc3RhdGljIHN0cnVjdCBjcHVpZGxlX2RyaXZlciBlNTAwX2lkbGVfZHJpdmVyID0gew0K
PiA+ICsJLm5hbWUgPSAiZTUwMF9pZGxlIiwNCj4gPiArCS5vd25lciA9IFRISVNfTU9EVUxFLA0K
PiA+ICt9Ow0KPiA+ICsNCj4gPiArc3RhdGljIHN0cnVjdCBjcHVpZGxlX2RldmljZSBfX3BlcmNw
dSAqZTUwMF9jcHVpZGxlX2RldmljZXM7DQo+ID4gKw0KPiA+ICtzdGF0aWMgdm9pZCBlNTAwX2Nw
dWlkbGUodm9pZCkNCj4gPiArew0KPiA+ICsJLyoNCj4gPiArCSAqIFRoaXMgd291bGQgY2FsbCBv
biB0aGUgY3B1aWRsZSBmcmFtZXdvcmssIGFuZCB0aGUgYmFjay1lbmQNCj4gPiArCSAqIGRyaXZl
ciB0byBnbyB0byBpZGxlIHN0YXRlcy4NCj4gPiArCSAqLw0KPiA+ICsJaWYgKGNwdWlkbGVfaWRs
ZV9jYWxsKCkpIHsNCj4gPiArCQkvKg0KPiA+ICsJCSAqIE9uIGVycm9yLCBleGVjdXRlIGRlZmF1
bHQgaGFuZGxlcg0KPiA+ICsJCSAqIHRvIGdvIGludG8gbG93IHRocmVhZCBwcmlvcml0eSBhbmQg
cG9zc2libHkNCj4gPiArCQkgKiBsb3cgcG93ZXIgbW9kZS4NCj4gPiArCQkgKi8NCj4gPiArCQlI
TVRfbG93KCk7DQo+ID4gKwkJSE1UX3ZlcnlfbG93KCk7DQo+ID4gKwl9DQo+ID4gK30NCj4gDQo+
IE5vcGUsIHRoaXMgaXMgbm90IHRoZSBwbGFjZSB0byBhZGQgc3VjaCBmdW5jdGlvbi4NCj4gDQpU
aGFua3MuDQoNCkJ1dCBXaHkgbm90PyBPbiBwb3dlcnBjIHRoZXJlIGlzIGFscmVhZHkgaGF2ZSBh
IGNwdWlkbGUgbWV0aG9kLiBXZSBuZWVkIHRvIGNvbXBhdGlibGUgdGhlbS4NCg0KVW0uLiBhcmNo
L3Bvd2VycGMvcGxhdGZvcm1zL3h4eCA/DQoNCj4gPiArc3RhdGljIGludCBwdzEwX2VudGVyKHN0
cnVjdCBjcHVpZGxlX2RldmljZSAqZGV2LA0KPiA+ICsJCQlzdHJ1Y3QgY3B1aWRsZV9kcml2ZXIg
KmRydiwgaW50IGluZGV4KQ0KPiA+ICt7DQo+ID4gKwlmc2xfY3B1aWRsZV93YWl0KCk7DQo+ID4g
KwlyZXR1cm4gaW5kZXg7DQo+ID4gK30NCj4gPiArDQo+ID4gK3N0YXRpYyBzdHJ1Y3QgY3B1aWRs
ZV9zdGF0ZSBmc2xfcHdfaWRsZV9zdGF0ZXNbXSA9IHsNCj4gPiArCXsNCj4gPiArCQkubmFtZSA9
ICJwdzEwIiwNCj4gPiArCQkuZGVzYyA9ICJwdzEwIiwNCj4gPiArCQkuZmxhZ3MgPSBDUFVJRExF
X0ZMQUdfVElNRV9WQUxJRCwNCj4gPiArCQkuZXhpdF9sYXRlbmN5ID0gMCwNCj4gPiArCQkudGFy
Z2V0X3Jlc2lkZW5jeSA9IDAsDQo+ID4gKwkJLmVudGVyID0gJnB3MTBfZW50ZXINCj4gPiArCX0s
DQo+ID4gK307DQo+ID4gKw0KPiA+ICtzdGF0aWMgaW50IGNwdV9ob3RwbHVnX25vdGlmeShzdHJ1
Y3Qgbm90aWZpZXJfYmxvY2sgKm4sDQo+ID4gKwkJCXVuc2lnbmVkIGxvbmcgYWN0aW9uLCB2b2lk
ICpoY3B1KQ0KPiA+ICt7DQo+ID4gKwl1bnNpZ25lZCBsb25nIGhvdGNwdSA9ICh1bnNpZ25lZCBs
b25nKWhjcHU7DQo+ID4gKwlzdHJ1Y3QgY3B1aWRsZV9kZXZpY2UgKmRldiA9DQo+ID4gKwkJCXBl
cl9jcHVfcHRyKGU1MDBfY3B1aWRsZV9kZXZpY2VzLCBob3RjcHUpOw0KPiA+ICsNCj4gPiArCWlm
IChkZXYgJiYgY3B1aWRsZV9nZXRfZHJpdmVyKCkpIHsNCj4gPiArCQlzd2l0Y2ggKGFjdGlvbikg
ew0KPiA+ICsJCWNhc2UgQ1BVX09OTElORToNCj4gPiArCQljYXNlIENQVV9PTkxJTkVfRlJPWkVO
Og0KPiA+ICsJCQljcHVpZGxlX3BhdXNlX2FuZF9sb2NrKCk7DQo+ID4gKwkJCWNwdWlkbGVfZW5h
YmxlX2RldmljZShkZXYpOw0KPiA+ICsJCQljcHVpZGxlX3Jlc3VtZV9hbmRfdW5sb2NrKCk7DQo+
ID4gKwkJCWJyZWFrOw0KPiA+ICsNCj4gPiArCQljYXNlIENQVV9ERUFEOg0KPiA+ICsJCWNhc2Ug
Q1BVX0RFQURfRlJPWkVOOg0KPiA+ICsJCQljcHVpZGxlX3BhdXNlX2FuZF9sb2NrKCk7DQo+ID4g
KwkJCWNwdWlkbGVfZGlzYWJsZV9kZXZpY2UoZGV2KTsNCj4gPiArCQkJY3B1aWRsZV9yZXN1bWVf
YW5kX3VubG9jaygpOw0KPiA+ICsJCQlicmVhazsNCj4gPiArDQo+ID4gKwkJZGVmYXVsdDoNCj4g
PiArCQkJcmV0dXJuIE5PVElGWV9ET05FOw0KPiA+ICsJCX0NCj4gPiArCX0NCj4gPiArDQo+ID4g
KwlyZXR1cm4gTk9USUZZX09LOw0KPiA+ICt9DQo+ID4gKw0KPiA+ICtzdGF0aWMgc3RydWN0IG5v
dGlmaWVyX2Jsb2NrIGNwdV9ob3RwbHVnX25vdGlmaWVyID0gew0KPiA+ICsJLm5vdGlmaWVyX2Nh
bGwgPSBjcHVfaG90cGx1Z19ub3RpZnksDQo+ID4gK307DQo+IA0KPiBUaGlzIHNob3VsZCBnbyB0
byB0aGUgY3B1aWRsZSBmcmFtZXdvcmsuDQo+IA0KWWVzLCBJIHNlZSwgRGVlcHRoaSB3aWxsIHBv
c3QgaXQuLi4NCjooLCBUaGlzIHBhdGNoIGlzIHJlbHlpbmcgb24gZm9yIERlZXB0aGkncyBwYXRj
aCBhYm91dCAiaG90cGx1ZyBub3RpZmllciIuDQoNCj4gPiArDQo+ID4gKy8qDQo+ID4gKyAqIGU1
MDBfaWRsZV9kZXZpY2VzX2luaXQodm9pZCkNCj4gPiArICogYWxsb2NhdGUsIGluaXRpYWxpemUg
YW5kIHJlZ2lzdGVyIGNwdWlkbGUgZGV2aWNlDQo+ID4gKyAqLw0KPiA+ICtzdGF0aWMgaW50IGU1
MDBfaWRsZV9kZXZpY2VzX2luaXQodm9pZCkNCj4gPiArew0KPiA+ICsJaW50IGk7DQo+ID4gKwlz
dHJ1Y3QgY3B1aWRsZV9kcml2ZXIgKmRydiA9ICZlNTAwX2lkbGVfZHJpdmVyOw0KPiA+ICsJc3Ry
dWN0IGNwdWlkbGVfZGV2aWNlICpkZXY7DQo+ID4gKw0KPiA+ICsJZTUwMF9jcHVpZGxlX2Rldmlj
ZXMgPSBhbGxvY19wZXJjcHUoc3RydWN0IGNwdWlkbGVfZGV2aWNlKTsNCj4gPiArCWlmICghZTUw
MF9jcHVpZGxlX2RldmljZXMpDQo+ID4gKwkJcmV0dXJuIC1FTk9NRU07DQo+ID4gKw0KPiA+ICsJ
Zm9yX2VhY2hfcG9zc2libGVfY3B1KGkpIHsNCj4gPiArCQlkZXYgPSBwZXJfY3B1X3B0cihlNTAw
X2NwdWlkbGVfZGV2aWNlcywgaSk7DQo+ID4gKwkJZGV2LT5zdGF0ZV9jb3VudCA9IGRydi0+c3Rh
dGVfY291bnQ7DQo+ID4gKwkJZGV2LT5jcHUgPSBpOw0KPiA+ICsNCj4gPiArCQlpZiAoY3B1aWRs
ZV9yZWdpc3Rlcl9kZXZpY2UoZGV2KSkgew0KPiA+ICsJCQlwcl9lcnIoImNwdWlkbGVfcmVnaXN0
ZXJfZGV2aWNlICVkIGZhaWxlZCFcbiIsIGkpOw0KPiA+ICsJCQlyZXR1cm4gLUVJTzsNCj4gPiAr
CQl9DQo+ID4gKwl9DQo+ID4gKw0KPiA+ICsJcmV0dXJuIDA7DQo+ID4gK30NCj4gPiArDQo+ID4g
Ky8qDQo+ID4gKyAqIGU1MDBfaWRsZV9kZXZpY2VzX3VuaW5pdCh2b2lkKQ0KPiA+ICsgKiB1bnJl
Z2lzdGVyIGNwdWlkbGUgZGV2aWNlcyBhbmQgZGUtYWxsb2NhdGUgbWVtb3J5DQo+ID4gKyAqLw0K
PiA+ICtzdGF0aWMgdm9pZCBlNTAwX2lkbGVfZGV2aWNlc191bmluaXQodm9pZCkNCj4gPiArew0K
PiA+ICsJaW50IGk7DQo+ID4gKwlzdHJ1Y3QgY3B1aWRsZV9kZXZpY2UgKmRldjsNCj4gPiArDQo+
ID4gKwlpZiAoIWU1MDBfY3B1aWRsZV9kZXZpY2VzKQ0KPiA+ICsJCXJldHVybjsNCj4gPiArDQo+
ID4gKwlmb3JfZWFjaF9wb3NzaWJsZV9jcHUoaSkgew0KPiA+ICsJCWRldiA9IHBlcl9jcHVfcHRy
KGU1MDBfY3B1aWRsZV9kZXZpY2VzLCBpKTsNCj4gPiArCQljcHVpZGxlX3VucmVnaXN0ZXJfZGV2
aWNlKGRldik7DQo+ID4gKwl9DQo+ID4gKw0KPiA+ICsJZnJlZV9wZXJjcHUoZTUwMF9jcHVpZGxl
X2RldmljZXMpOw0KPiA+ICt9DQo+ID4gKw0KPiA+ICtzdGF0aWMgdm9pZCBlNTAwX2NwdWlkbGVf
ZHJpdmVyX2luaXQodW5zaWduZWQgaW50IG1heF9pZGxlX3N0YXRlLA0KPiA+ICsJCXN0cnVjdCBj
cHVpZGxlX3N0YXRlICpjcHVpZGxlX3N0YXRlX3RhYmxlKQ0KPiA+ICt7DQo+ID4gKwlpbnQgaWRs
ZV9zdGF0ZTsNCj4gPiArCXN0cnVjdCBjcHVpZGxlX2RyaXZlciAqZHJ2ID0gJmU1MDBfaWRsZV9k
cml2ZXI7DQo+ID4gKw0KPiA+ICsJZHJ2LT5zdGF0ZV9jb3VudCA9IDA7DQo+ID4gKw0KPiA+ICsJ
Zm9yIChpZGxlX3N0YXRlID0gMDsgaWRsZV9zdGF0ZSA8IG1heF9pZGxlX3N0YXRlOyArK2lkbGVf
c3RhdGUpIHsNCj4gPiArCQlpZiAoIWNwdWlkbGVfc3RhdGVfdGFibGVbaWRsZV9zdGF0ZV0uZW50
ZXIpDQo+ID4gKwkJCWJyZWFrOw0KPiA+ICsNCj4gPiArCQlkcnYtPnN0YXRlc1tkcnYtPnN0YXRl
X2NvdW50XSA9DQo+IGNwdWlkbGVfc3RhdGVfdGFibGVbaWRsZV9zdGF0ZV07DQo+ID4gKwkJZHJ2
LT5zdGF0ZV9jb3VudCsrOw0KPiA+ICsJfQ0KPiA+ICt9DQo+ID4gKw0KPiA+ICtzdGF0aWMgaW50
IGNwdV9pc19mZWF0dXJlKHVuc2lnbmVkIGxvbmcgZmVhdHVyZSkNCj4gPiArew0KPiA+ICsJcmV0
dXJuIChjdXJfY3B1X3NwZWMtPmNwdV9mZWF0dXJlcyA9PSBmZWF0dXJlKTsNCj4gPiArfQ0KPiA+
ICsNCj4gPiArc3RhdGljIGludCBfX2luaXQgZTUwMF9pZGxlX2luaXQodm9pZCkNCj4gPiArew0K
PiA+ICsJc3RydWN0IGNwdWlkbGVfc3RhdGUgKmNwdWlkbGVfc3RhdGVfdGFibGUgPSBOVUxMOw0K
PiA+ICsJc3RydWN0IGNwdWlkbGVfZHJpdmVyICpkcnYgPSAmZTUwMF9pZGxlX2RyaXZlcjsNCj4g
PiArCWludCBlcnI7DQo+ID4gKwl1bnNpZ25lZCBpbnQgbWF4X2lkbGVfc3RhdGUgPSAwOw0KPiA+
ICsNCj4gPiArCWlmIChjcHVpZGxlX2Rpc2FibGUgIT0gSURMRV9OT19PVkVSUklERSkNCj4gPiAr
CQlyZXR1cm4gLUVOT0RFVjsNCj4gPiArDQo+ID4gKwlpZiAoY3B1X2lzX2ZlYXR1cmUoQ1BVX0ZU
UlNfRTUwME1DKSB8fA0KPiBjcHVfaXNfZmVhdHVyZShDUFVfRlRSU19FNTUwMCkgfHwNCj4gPiAr
CQkJY3B1X2lzX2ZlYXR1cmUoQ1BVX0ZUUlNfRTY1MDApKSB7DQo+ID4gKwkJY3B1aWRsZV9zdGF0
ZV90YWJsZSA9IGZzbF9wd19pZGxlX3N0YXRlczsNCj4gPiArCQltYXhfaWRsZV9zdGF0ZSA9IEFS
UkFZX1NJWkUoZnNsX3B3X2lkbGVfc3RhdGVzKTsNCj4gPiArCX0NCj4gPiArDQo+ID4gKwlpZiAo
IWNwdWlkbGVfc3RhdGVfdGFibGUgfHwgIW1heF9pZGxlX3N0YXRlKQ0KPiA+ICsJCXJldHVybiAt
RVBFUk07DQo+IA0KPiBQbGVhc2UgdXNlIGRpZmZlcmVudCBkcml2ZXJzIGZvciBlYWNoIGFuZCB0
aGVuIHJlZ2lzdGVyIHRoZSByaWdodCBvbmUNCj4gaW5zdGVhZCBvZiBzdGF0ZSBjb3VudCBjb252
b2x1dGlvbnMuDQo+IA0KPiBUaGVuIHVzZSBjcHVpZGxlX3JlZ2lzdGVyKCZteWRyaXZlciwgTlVM
TCkgYW5kIGdldCByaWQgb2YgdGhlIGR1cGxpY2F0ZQ0KPiBpbml0aWFsaXphdGlvbiByb3V0aW5l
Lg0KPiANClllcywgVGhhbmtzLCBUaGlzIHBhdGNoIGtlZXAgdXNpbmcgY3B1aWRsZV9yZWdpc3Rl
cl9kZXZpY2UoKSwgYmVjYXVzZSB3ZSBuZWVkIHRvDQpzdXBwb3J0IGNwdSBob3RwbHVnLiBJIHdp
bGwgZml4ICJkZXZpY2UiIGlzc3VlIGluIHRoaXMgZHJpdmVyLCBhZnRlcg0KRGVlcHRoaSBEaGFy
d2FyIDxkZWVwdGhpQGxpbnV4LnZuZXQuaWJtLmNvbT4gYWRkIGEgaG90cGx1ZyBoYW5kbGVyDQpp
bnRvIGNwdWlkbGUgZnJlYW13b3JrLg0KDQo+IA0KPiA+ICsJZTUwMF9jcHVpZGxlX2RyaXZlcl9p
bml0KG1heF9pZGxlX3N0YXRlLCBjcHVpZGxlX3N0YXRlX3RhYmxlKTsNCj4gPiArDQo+ID4gKwlp
ZiAoIWRydi0+c3RhdGVfY291bnQpDQo+ID4gKwkJcmV0dXJuIC1FUEVSTTsNCj4gPiArDQo+ID4g
KwllcnIgPSBjcHVpZGxlX3JlZ2lzdGVyX2RyaXZlcihkcnYpOw0KPiA+ICsJaWYgKGVycikgew0K
PiA+ICsJCXByX2VycigiUmVnaXN0ZXIgZTUwMCBmYW1pbHkgY3B1aWRsZSBkcml2ZXIgZmFpbGVk
LlxuIik7DQo+ID4gKw0KPiA+ICsJCXJldHVybiBlcnI7DQo+ID4gKwl9DQo+ID4gKw0KPiA+ICsJ
ZXJyID0gZTUwMF9pZGxlX2RldmljZXNfaW5pdCgpOw0KPiA+ICsJaWYgKGVycikNCj4gPiArCQln
b3RvIG91dDsNCj4gPiArDQo+ID4gKwllcnIgPSByZWdpc3Rlcl9jcHVfbm90aWZpZXIoJmNwdV9o
b3RwbHVnX25vdGlmaWVyKTsNCj4gPiArCWlmIChlcnIpDQo+ID4gKwkJZ290byBvdXQ7DQo+ID4g
Kw0KPiA+ICsJcHBjX21kLnBvd2VyX3NhdmUgPSBlNTAwX2NwdWlkbGU7DQo+IA0KPiBUaGlzIGlz
IG5vdCB0aGUgcGxhY2UuDQo+IA0KPiA+ICsNCj4gPiArCXByX2luZm8oImU1MDBfaWRsZV9kcml2
ZXIgcmVnaXN0ZXJlZC5cbiIpOw0KPiA+ICsNCj4gPiArCXJldHVybiAwOw0KPiA+ICsNCj4gPiAr
b3V0Og0KPiA+ICsJZTUwMF9pZGxlX2RldmljZXNfdW5pbml0KCk7DQo+ID4gKwljcHVpZGxlX3Vu
cmVnaXN0ZXJfZHJpdmVyKGRydik7DQo+ID4gKw0KPiA+ICsJcHJfZXJyKCJSZWdpc3RlciBlNTAw
IGZhbWlseSBjcHVpZGxlIGRyaXZlciBmYWlsZWQuXG4iKTsNCj4gPiArDQo+ID4gKwlyZXR1cm4g
ZXJyOw0KPiA+ICt9DQo+ID4gK2RldmljZV9pbml0Y2FsbChlNTAwX2lkbGVfaW5pdCk7DQo+ID4N
Cj4gDQo+IA0KPiAtLQ0KPiAgPGh0dHA6Ly93d3cubGluYXJvLm9yZy8+IExpbmFyby5vcmcg4pSC
IE9wZW4gc291cmNlIHNvZnR3YXJlIGZvciBBUk0gU29Dcw0KPiANCj4gRm9sbG93IExpbmFybzog
IDxodHRwOi8vd3d3LmZhY2Vib29rLmNvbS9wYWdlcy9MaW5hcm8+IEZhY2Vib29rIHwNCj4gPGh0
dHA6Ly90d2l0dGVyLmNvbS8jIS9saW5hcm9vcmc+IFR3aXR0ZXIgfA0KPiA8aHR0cDovL3d3dy5s
aW5hcm8ub3JnL2xpbmFyby1ibG9nLz4gQmxvZw0KPiANCg0K

--
To unsubscribe from this list: send the line "unsubscribe linux-pm" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Deepthi Dharwar July 31, 2013, 3:03 a.m. UTC | #3
On 07/30/2013 04:32 PM, Wang Dongsheng-B40534 wrote:

Hi Dongsheng,

I have posted out a generic powerpc idle backend driver ccing you.
Please take a look at it and integrate your platform idle states into it.

Right now, cpu hotplug notifier is common for all powerpc. This
shouldn't hinder you.
This will reduce code duplication and would make it easier to
plug into the framework. All you need is platform specific
idle states table and config changes.

Regards,
Deepthi


> 
>> -----Original Message-----
>> From: Daniel Lezcano [mailto:daniel.lezcano@linaro.org]
>> Sent: Tuesday, July 30, 2013 5:51 PM
>> To: Wang Dongsheng-B40534
>> Cc: Wood Scott-B07421; rjw@sisk.pl; benh@kernel.crashing.org; Li Yang-
>> R58472; Zhao Chenhui-B35336; linux-pm@vger.kernel.org; linuxppc-
>> dev@lists.ozlabs.org
>> Subject: Re: [PATCH] cpuidle: add freescale e500 family porcessors idle
>> support
>>
>> On 07/30/2013 09:00 AM, Dongsheng Wang wrote:
>>> From: Wang Dongsheng <dongsheng.wang@freescale.com>
>>>
>>> Add cpuidle support for e500 family, using cpuidle framework to manage
>>> various low power modes. The new implementation will remain compatible
>>> with original idle method.
>>>
>>> Initially, this supports PW10, and subsequent patches will support
>>> PW20/DOZE/NAP.
>>>
>>> Signed-off-by: Wang Dongsheng <dongsheng.wang@freescale.com>
>>> ---
>>> This patch keep using cpuidle_register_device(), because we need to
>>> support cpu hotplug. I will fix "device" issue in this driver, after
>>> Deepthi Dharwar <deepthi@linux.vnet.ibm.com> add a hotplug handler
>>> into cpuidle freamwork.
>>>
>>> diff --git a/arch/powerpc/include/asm/machdep.h
>>> b/arch/powerpc/include/asm/machdep.h
>>> index 8b48090..cbdbe25 100644
>>> --- a/arch/powerpc/include/asm/machdep.h
>>> +++ b/arch/powerpc/include/asm/machdep.h
>>> @@ -271,6 +271,16 @@ extern void power7_idle(void);  extern void
>>> ppc6xx_idle(void);  extern void book3e_idle(void);
>>>
>>> +/* Wait for Interrupt */
>>> +static inline void fsl_cpuidle_wait(void) { #ifdef CONFIG_PPC64
>>> +	book3e_idle();
>>> +#else
>>> +	e500_idle();
>>> +#endif
>>> +}
>>> +
>>>  /*
>>>   * ppc_md contains a copy of the machine description structure for the
>>>   * current platform. machine_id contains the initial address where the
>>> diff --git a/drivers/cpuidle/Kconfig b/drivers/cpuidle/Kconfig
>>> index b3fb81d..7ed114b 100644
>>> --- a/drivers/cpuidle/Kconfig
>>> +++ b/drivers/cpuidle/Kconfig
>>> @@ -35,6 +35,11 @@ depends on ARM
>>>  source "drivers/cpuidle/Kconfig.arm"
>>>  endmenu
>>>
>>> +menu "PowerPC CPU Idle Drivers"
>>> +depends on PPC32 || PPC64
>>> +source "drivers/cpuidle/Kconfig.powerpc"
>>> +endmenu
>>> +
>>>  endif
>>>
>>>  config ARCH_NEEDS_CPU_IDLE_COUPLED
>>> diff --git a/drivers/cpuidle/Kconfig.powerpc
>> b/drivers/cpuidle/Kconfig.powerpc
>>> new file mode 100644
>>> index 0000000..9f3f5ef
>>> --- /dev/null
>>> +++ b/drivers/cpuidle/Kconfig.powerpc
>>> @@ -0,0 +1,9 @@
>>> +#
>>> +# PowerPC CPU Idle drivers
>>> +#
>>> +
>>> +config PPC_E500_CPUIDLE
>>> +	bool "CPU Idle Driver for E500 family processors"
>>> +	depends on FSL_SOC_BOOKE
>>> +	help
>>> +	  Select this to enable cpuidle on e500 family processors.
>>> diff --git a/drivers/cpuidle/Makefile b/drivers/cpuidle/Makefile
>>> index 0b9d200..0dde3db 100644
>>> --- a/drivers/cpuidle/Makefile
>>> +++ b/drivers/cpuidle/Makefile
>>> @@ -11,3 +11,7 @@ obj-$(CONFIG_ARM_HIGHBANK_CPUIDLE)	+= cpuidle-
>> calxeda.o
>>>  obj-$(CONFIG_ARM_KIRKWOOD_CPUIDLE)	+= cpuidle-kirkwood.o
>>>  obj-$(CONFIG_ARM_ZYNQ_CPUIDLE)		+= cpuidle-zynq.o
>>>  obj-$(CONFIG_ARM_U8500_CPUIDLE)         += cpuidle-ux500.o
>>> +
>>>
>> +########################################################################
>> ##########
>>> +# PowerPC platform drivers
>>> +obj-$(CONFIG_PPC_E500_CPUIDLE)		+= cpuidle-e500.o
>>> diff --git a/drivers/cpuidle/cpuidle-e500.c b/drivers/cpuidle/cpuidle-
>> e500.c
>>> new file mode 100644
>>> index 0000000..1919cea
>>> --- /dev/null
>>> +++ b/drivers/cpuidle/cpuidle-e500.c
>>> @@ -0,0 +1,222 @@
>>> +/*
>>> + * Copyright 2013 Freescale Semiconductor, Inc.
>>> + *
>>> + * CPU Idle driver for Freescale PowerPC e500 family processors.
>>> + *
>>> + * This program is free software; you can redistribute it and/or
>> modify
>>> + * it under the terms of the GNU General Public License version 2 as
>>> + * published by the Free Software Foundation.
>>> + *
>>> + * Author: Wang Dongsheng <dongsheng.wang@freescale.com>
>>> + */
>>> +
>>> +#include <linux/cpu.h>
>>> +#include <linux/cpuidle.h>
>>> +#include <linux/init.h>
>>> +#include <linux/kernel.h>
>>> +#include <linux/module.h>
>>> +#include <linux/notifier.h>
>>> +
>>> +#include <asm/machdep.h>
>>> +
>>> +static struct cpuidle_driver e500_idle_driver = {
>>> +	.name = "e500_idle",
>>> +	.owner = THIS_MODULE,
>>> +};
>>> +
>>> +static struct cpuidle_device __percpu *e500_cpuidle_devices;
>>> +
>>> +static void e500_cpuidle(void)
>>> +{
>>> +	/*
>>> +	 * This would call on the cpuidle framework, and the back-end
>>> +	 * driver to go to idle states.
>>> +	 */
>>> +	if (cpuidle_idle_call()) {
>>> +		/*
>>> +		 * On error, execute default handler
>>> +		 * to go into low thread priority and possibly
>>> +		 * low power mode.
>>> +		 */
>>> +		HMT_low();
>>> +		HMT_very_low();
>>> +	}
>>> +}
>>
>> Nope, this is not the place to add such function.
>>
> Thanks.
> 
> But Why not? On powerpc there is already have a cpuidle method. We need to compatible them.
> 
> Um.. arch/powerpc/platforms/xxx ?
> 
>>> +static int pw10_enter(struct cpuidle_device *dev,
>>> +			struct cpuidle_driver *drv, int index)
>>> +{
>>> +	fsl_cpuidle_wait();
>>> +	return index;
>>> +}
>>> +
>>> +static struct cpuidle_state fsl_pw_idle_states[] = {
>>> +	{
>>> +		.name = "pw10",
>>> +		.desc = "pw10",
>>> +		.flags = CPUIDLE_FLAG_TIME_VALID,
>>> +		.exit_latency = 0,
>>> +		.target_residency = 0,
>>> +		.enter = &pw10_enter
>>> +	},
>>> +};
>>> +
>>> +static int cpu_hotplug_notify(struct notifier_block *n,
>>> +			unsigned long action, void *hcpu)
>>> +{
>>> +	unsigned long hotcpu = (unsigned long)hcpu;
>>> +	struct cpuidle_device *dev =
>>> +			per_cpu_ptr(e500_cpuidle_devices, hotcpu);
>>> +
>>> +	if (dev && cpuidle_get_driver()) {
>>> +		switch (action) {
>>> +		case CPU_ONLINE:
>>> +		case CPU_ONLINE_FROZEN:
>>> +			cpuidle_pause_and_lock();
>>> +			cpuidle_enable_device(dev);
>>> +			cpuidle_resume_and_unlock();
>>> +			break;
>>> +
>>> +		case CPU_DEAD:
>>> +		case CPU_DEAD_FROZEN:
>>> +			cpuidle_pause_and_lock();
>>> +			cpuidle_disable_device(dev);
>>> +			cpuidle_resume_and_unlock();
>>> +			break;
>>> +
>>> +		default:
>>> +			return NOTIFY_DONE;
>>> +		}
>>> +	}
>>> +
>>> +	return NOTIFY_OK;
>>> +}
>>> +
>>> +static struct notifier_block cpu_hotplug_notifier = {
>>> +	.notifier_call = cpu_hotplug_notify,
>>> +};
>>
>> This should go to the cpuidle framework.
>>
> Yes, I see, Deepthi will post it...
> :(, This patch is relying on for Deepthi's patch about "hotplug notifier".
> 
>>> +
>>> +/*
>>> + * e500_idle_devices_init(void)
>>> + * allocate, initialize and register cpuidle device
>>> + */
>>> +static int e500_idle_devices_init(void)
>>> +{
>>> +	int i;
>>> +	struct cpuidle_driver *drv = &e500_idle_driver;
>>> +	struct cpuidle_device *dev;
>>> +
>>> +	e500_cpuidle_devices = alloc_percpu(struct cpuidle_device);
>>> +	if (!e500_cpuidle_devices)
>>> +		return -ENOMEM;
>>> +
>>> +	for_each_possible_cpu(i) {
>>> +		dev = per_cpu_ptr(e500_cpuidle_devices, i);
>>> +		dev->state_count = drv->state_count;
>>> +		dev->cpu = i;
>>> +
>>> +		if (cpuidle_register_device(dev)) {
>>> +			pr_err("cpuidle_register_device %d failed!\n", i);
>>> +			return -EIO;
>>> +		}
>>> +	}
>>> +
>>> +	return 0;
>>> +}
>>> +
>>> +/*
>>> + * e500_idle_devices_uninit(void)
>>> + * unregister cpuidle devices and de-allocate memory
>>> + */
>>> +static void e500_idle_devices_uninit(void)
>>> +{
>>> +	int i;
>>> +	struct cpuidle_device *dev;
>>> +
>>> +	if (!e500_cpuidle_devices)
>>> +		return;
>>> +
>>> +	for_each_possible_cpu(i) {
>>> +		dev = per_cpu_ptr(e500_cpuidle_devices, i);
>>> +		cpuidle_unregister_device(dev);
>>> +	}
>>> +
>>> +	free_percpu(e500_cpuidle_devices);
>>> +}
>>> +
>>> +static void e500_cpuidle_driver_init(unsigned int max_idle_state,
>>> +		struct cpuidle_state *cpuidle_state_table)
>>> +{
>>> +	int idle_state;
>>> +	struct cpuidle_driver *drv = &e500_idle_driver;
>>> +
>>> +	drv->state_count = 0;
>>> +
>>> +	for (idle_state = 0; idle_state < max_idle_state; ++idle_state) {
>>> +		if (!cpuidle_state_table[idle_state].enter)
>>> +			break;
>>> +
>>> +		drv->states[drv->state_count] =
>> cpuidle_state_table[idle_state];
>>> +		drv->state_count++;
>>> +	}
>>> +}
>>> +
>>> +static int cpu_is_feature(unsigned long feature)
>>> +{
>>> +	return (cur_cpu_spec->cpu_features == feature);
>>> +}
>>> +
>>> +static int __init e500_idle_init(void)
>>> +{
>>> +	struct cpuidle_state *cpuidle_state_table = NULL;
>>> +	struct cpuidle_driver *drv = &e500_idle_driver;
>>> +	int err;
>>> +	unsigned int max_idle_state = 0;
>>> +
>>> +	if (cpuidle_disable != IDLE_NO_OVERRIDE)
>>> +		return -ENODEV;
>>> +
>>> +	if (cpu_is_feature(CPU_FTRS_E500MC) ||
>> cpu_is_feature(CPU_FTRS_E5500) ||
>>> +			cpu_is_feature(CPU_FTRS_E6500)) {
>>> +		cpuidle_state_table = fsl_pw_idle_states;
>>> +		max_idle_state = ARRAY_SIZE(fsl_pw_idle_states);
>>> +	}
>>> +
>>> +	if (!cpuidle_state_table || !max_idle_state)
>>> +		return -EPERM;
>>
>> Please use different drivers for each and then register the right one
>> instead of state count convolutions.
>>
>> Then use cpuidle_register(&mydriver, NULL) and get rid of the duplicate
>> initialization routine.
>>
> Yes, Thanks, This patch keep using cpuidle_register_device(), because we need to
> support cpu hotplug. I will fix "device" issue in this driver, after
> Deepthi Dharwar <deepthi@linux.vnet.ibm.com> add a hotplug handler
> into cpuidle freamwork.
> 
>>
>>> +	e500_cpuidle_driver_init(max_idle_state, cpuidle_state_table);
>>> +
>>> +	if (!drv->state_count)
>>> +		return -EPERM;
>>> +
>>> +	err = cpuidle_register_driver(drv);
>>> +	if (err) {
>>> +		pr_err("Register e500 family cpuidle driver failed.\n");
>>> +
>>> +		return err;
>>> +	}
>>> +
>>> +	err = e500_idle_devices_init();
>>> +	if (err)
>>> +		goto out;
>>> +
>>> +	err = register_cpu_notifier(&cpu_hotplug_notifier);
>>> +	if (err)
>>> +		goto out;
>>> +
>>> +	ppc_md.power_save = e500_cpuidle;
>>
>> This is not the place.
>>
>>> +
>>> +	pr_info("e500_idle_driver registered.\n");
>>> +
>>> +	return 0;
>>> +
>>> +out:
>>> +	e500_idle_devices_uninit();
>>> +	cpuidle_unregister_driver(drv);
>>> +
>>> +	pr_err("Register e500 family cpuidle driver failed.\n");
>>> +
>>> +	return err;
>>> +}
>>> +device_initcall(e500_idle_init);
>>>
>>
>>
>> --
>>  <http://www.linaro.org/> Linaro.org ? Open source software for ARM SoCs
>>
>> Follow Linaro:  <http://www.facebook.com/pages/Linaro> Facebook |
>> <http://twitter.com/#!/linaroorg> Twitter |
>> <http://www.linaro.org/linaro-blog/> Blog
>>
> 
> _______________________________________________
> Linuxppc-dev mailing list
> Linuxppc-dev@lists.ozlabs.org
> https://lists.ozlabs.org/listinfo/linuxppc-dev
> 

--
To unsubscribe from this list: send the line "unsubscribe linux-pm" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Wang Dongsheng-B40534 July 31, 2013, 6:30 a.m. UTC | #4
> -----Original Message-----
> From: Wood Scott-B07421
> Sent: Wednesday, July 31, 2013 3:38 AM
> To: Wang Dongsheng-B40534
> Cc: rjw@sisk.pl; daniel.lezcano@linaro.org; benh@kernel.crashing.org; Li
> Yang-R58472; Zhao Chenhui-B35336; linux-pm@vger.kernel.org; linuxppc-
> dev@lists.ozlabs.org
> Subject: Re: [PATCH] cpuidle: add freescale e500 family porcessors idle
> support
> 
> On 07/30/2013 02:00:03 AM, Dongsheng Wang wrote:
> > From: Wang Dongsheng <dongsheng.wang@freescale.com>
> >
> > Add cpuidle support for e500 family, using cpuidle framework to
> > manage various low power modes. The new implementation will remain
> > compatible with original idle method.
> >
> > Initially, this supports PW10, and subsequent patches will support
> > PW20/DOZE/NAP.
> 
> Could you explain what the cpuidle framework does for us that the
> current idle code doesn't?
> 

The current idle code, Only a state of low power can make the core idle.
The core can't get into more low power state.

> In particular, what scenario do you see where we would require a
> software
> governor to choose between idle states, and how much power is saved
> compared to a simpler approach?  There is timer that can be used to
> automatically enter PW20 after a certain amount of time in PW10.

Yes, the hardware can automatically enter PW20 state. But this is hardware
feature, we need to software to manage it. Only for PW20 state, we can drop
this cpuidle and using the hardware to control it. But if we need to support
PH10/PH15/PH20/PH30, the current idle code cannot support them. 

> How much better results do you get from a software governor?  Do we even
> have the right data to characterize each state so that a software governor
> could make good decisions?  Is cpuidle capable of governing the interval
> of such a timer, rather than directly governing states?
> 
From now on we did not benchmark these data, because we only have PW10 state.

I can do support doze/nap for e6500. To get some data to show you.

> As for doze/nap, why would we want to use those on newer cores?  Do you
> have numbers for how much power each mode saves?
> 
The PH state is plan to support, if the core can make into more low power state,
why not to do this.

PH10(doze)/PH15(nap)/PH20/PH30, These states can save more CPU power.

> Active governors may be useful on older cores that only have doze/nap,
> to
> select between them, but if that's the use case then why start with
> pw10?
Pw10 is supported on E500MC/E5500/E6500. And we plan to support PW20 for E65OO core.
I will take doze/nap up a bit later.

> And I'd want to see numbers for how much power nap saves versus doze.
> 
> > Signed-off-by: Wang Dongsheng <dongsheng.wang@freescale.com>
> > ---
> > This patch keep using cpuidle_register_device(), because we need to
> > support cpu
> > hotplug. I will fix "device" issue in this driver, after
> > Deepthi Dharwar <deepthi@linux.vnet.ibm.com> add a hotplug handler
> > into cpuidle
> > freamwork.
> 
> Where's the diffstat?
> 
See, http://patchwork.ozlabs.org/patch/260997/

> > @@ -0,0 +1,222 @@
> > +/*
> > + * Copyright 2013 Freescale Semiconductor, Inc.
> > + *
> > + * CPU Idle driver for Freescale PowerPC e500 family processors.
> > + *
> > + * This program is free software; you can redistribute it and/or
> > modify
> > + * it under the terms of the GNU General Public License version 2 as
> > + * published by the Free Software Foundation.
> > + *
> > + * Author: Wang Dongsheng <dongsheng.wang@freescale.com>
> > + */
> 
> Is this derived from some other file?  It looks like it...  Where's the
> attribution?
> 
The copyright is from drivers/cpufreq/ppc-corenet-cpufreq.c

> > +#include <linux/cpu.h>
> > +#include <linux/cpuidle.h>
> > +#include <linux/init.h>
> > +#include <linux/kernel.h>
> > +#include <linux/module.h>
> > +#include <linux/notifier.h>
> > +
> > +#include <asm/machdep.h>
> > +
> > +static struct cpuidle_driver e500_idle_driver = {
> > +	.name = "e500_idle",
> > +	.owner = THIS_MODULE,
> > +};
> > +
> > +static struct cpuidle_device __percpu *e500_cpuidle_devices;
> > +
> > +static void e500_cpuidle(void)
> > +{
> > +	/*
> > +	 * This would call on the cpuidle framework, and the back-end
> > +	 * driver to go to idle states.
> > +	 */
> > +	if (cpuidle_idle_call()) {
> > +		/*
> > +		 * On error, execute default handler
> > +		 * to go into low thread priority and possibly
> > +		 * low power mode.
> > +		 */
> > +		HMT_low();
> > +		HMT_very_low();
> 
> This HMT stuff doesn't do anything on e500 derivatives AFAIK.
> 
Yes, there should do nothing, let arch_cpu_idle to do the failed.

> > +static struct cpuidle_state fsl_pw_idle_states[] = {
> > +	{
> > +		.name = "pw10",
> > +		.desc = "pw10",
> > +		.flags = CPUIDLE_FLAG_TIME_VALID,
> > +		.exit_latency = 0,
> > +		.target_residency = 0,
> > +		.enter = &pw10_enter
> 
> Where is pw10_enter defined?
> 
In this patch..

> > +static int cpu_is_feature(unsigned long feature)
> > +{
> > +	return (cur_cpu_spec->cpu_features == feature);
> > +}
> > +
> > +static int __init e500_idle_init(void)
> > +{
> > +	struct cpuidle_state *cpuidle_state_table = NULL;
> > +	struct cpuidle_driver *drv = &e500_idle_driver;
> > +	int err;
> > +	unsigned int max_idle_state = 0;
> > +
> > +	if (cpuidle_disable != IDLE_NO_OVERRIDE)
> > +		return -ENODEV;
> > +
> > +	if (cpu_is_feature(CPU_FTRS_E500MC) ||
> > cpu_is_feature(CPU_FTRS_E5500) ||
> > +			cpu_is_feature(CPU_FTRS_E6500)) {
> 
> There's no guarantee that a CPU with the same set of features is the
> exact same CPU.
> 
> What specific feature are you looking for here?
> 
Here is the type of the core. E500MC,E5500,E6500 do wait.

> > +		cpuidle_state_table = fsl_pw_idle_states;
> > +		max_idle_state = ARRAY_SIZE(fsl_pw_idle_states);
> > +	}
> > +
> > +	if (!cpuidle_state_table || !max_idle_state)
> > +		return -EPERM;
> 
> ENODEV?
> 
Looks better than EPERM.

-dongsheng

--
To unsubscribe from this list: send the line "unsubscribe linux-pm" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

diff --git a/arch/powerpc/include/asm/machdep.h b/arch/powerpc/include/asm/machdep.h
index 8b48090..cbdbe25 100644
--- a/arch/powerpc/include/asm/machdep.h
+++ b/arch/powerpc/include/asm/machdep.h
@@ -271,6 +271,16 @@  extern void power7_idle(void);
 extern void ppc6xx_idle(void);
 extern void book3e_idle(void);
 
+/* Wait for Interrupt */
+static inline void fsl_cpuidle_wait(void)
+{
+#ifdef CONFIG_PPC64
+	book3e_idle();
+#else
+	e500_idle();
+#endif
+}
+
 /*
  * ppc_md contains a copy of the machine description structure for the
  * current platform. machine_id contains the initial address where the
diff --git a/drivers/cpuidle/Kconfig b/drivers/cpuidle/Kconfig
index b3fb81d..7ed114b 100644
--- a/drivers/cpuidle/Kconfig
+++ b/drivers/cpuidle/Kconfig
@@ -35,6 +35,11 @@  depends on ARM
 source "drivers/cpuidle/Kconfig.arm"
 endmenu
 
+menu "PowerPC CPU Idle Drivers"
+depends on PPC32 || PPC64
+source "drivers/cpuidle/Kconfig.powerpc"
+endmenu
+
 endif
 
 config ARCH_NEEDS_CPU_IDLE_COUPLED
diff --git a/drivers/cpuidle/Kconfig.powerpc b/drivers/cpuidle/Kconfig.powerpc
new file mode 100644
index 0000000..9f3f5ef
--- /dev/null
+++ b/drivers/cpuidle/Kconfig.powerpc
@@ -0,0 +1,9 @@ 
+#
+# PowerPC CPU Idle drivers
+#
+
+config PPC_E500_CPUIDLE
+	bool "CPU Idle Driver for E500 family processors"
+	depends on FSL_SOC_BOOKE
+	help
+	  Select this to enable cpuidle on e500 family processors.
diff --git a/drivers/cpuidle/Makefile b/drivers/cpuidle/Makefile
index 0b9d200..0dde3db 100644
--- a/drivers/cpuidle/Makefile
+++ b/drivers/cpuidle/Makefile
@@ -11,3 +11,7 @@  obj-$(CONFIG_ARM_HIGHBANK_CPUIDLE)	+= cpuidle-calxeda.o
 obj-$(CONFIG_ARM_KIRKWOOD_CPUIDLE)	+= cpuidle-kirkwood.o
 obj-$(CONFIG_ARM_ZYNQ_CPUIDLE)		+= cpuidle-zynq.o
 obj-$(CONFIG_ARM_U8500_CPUIDLE)         += cpuidle-ux500.o
+
+##################################################################################
+# PowerPC platform drivers
+obj-$(CONFIG_PPC_E500_CPUIDLE)		+= cpuidle-e500.o
diff --git a/drivers/cpuidle/cpuidle-e500.c b/drivers/cpuidle/cpuidle-e500.c
new file mode 100644
index 0000000..1919cea
--- /dev/null
+++ b/drivers/cpuidle/cpuidle-e500.c
@@ -0,0 +1,222 @@ 
+/*
+ * Copyright 2013 Freescale Semiconductor, Inc.
+ *
+ * CPU Idle driver for Freescale PowerPC e500 family processors.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Author: Wang Dongsheng <dongsheng.wang@freescale.com>
+ */
+
+#include <linux/cpu.h>
+#include <linux/cpuidle.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/notifier.h>
+
+#include <asm/machdep.h>
+
+static struct cpuidle_driver e500_idle_driver = {
+	.name = "e500_idle",
+	.owner = THIS_MODULE,
+};
+
+static struct cpuidle_device __percpu *e500_cpuidle_devices;
+
+static void e500_cpuidle(void)
+{
+	/*
+	 * This would call on the cpuidle framework, and the back-end
+	 * driver to go to idle states.
+	 */
+	if (cpuidle_idle_call()) {
+		/*
+		 * On error, execute default handler
+		 * to go into low thread priority and possibly
+		 * low power mode.
+		 */
+		HMT_low();
+		HMT_very_low();
+	}
+}
+
+static int pw10_enter(struct cpuidle_device *dev,
+			struct cpuidle_driver *drv, int index)
+{
+	fsl_cpuidle_wait();
+	return index;
+}
+
+static struct cpuidle_state fsl_pw_idle_states[] = {
+	{
+		.name = "pw10",
+		.desc = "pw10",
+		.flags = CPUIDLE_FLAG_TIME_VALID,
+		.exit_latency = 0,
+		.target_residency = 0,
+		.enter = &pw10_enter
+	},
+};
+
+static int cpu_hotplug_notify(struct notifier_block *n,
+			unsigned long action, void *hcpu)
+{
+	unsigned long hotcpu = (unsigned long)hcpu;
+	struct cpuidle_device *dev =
+			per_cpu_ptr(e500_cpuidle_devices, hotcpu);
+
+	if (dev && cpuidle_get_driver()) {
+		switch (action) {
+		case CPU_ONLINE:
+		case CPU_ONLINE_FROZEN:
+			cpuidle_pause_and_lock();
+			cpuidle_enable_device(dev);
+			cpuidle_resume_and_unlock();
+			break;
+
+		case CPU_DEAD:
+		case CPU_DEAD_FROZEN:
+			cpuidle_pause_and_lock();
+			cpuidle_disable_device(dev);
+			cpuidle_resume_and_unlock();
+			break;
+
+		default:
+			return NOTIFY_DONE;
+		}
+	}
+
+	return NOTIFY_OK;
+}
+
+static struct notifier_block cpu_hotplug_notifier = {
+	.notifier_call = cpu_hotplug_notify,
+};
+
+/*
+ * e500_idle_devices_init(void)
+ * allocate, initialize and register cpuidle device
+ */
+static int e500_idle_devices_init(void)
+{
+	int i;
+	struct cpuidle_driver *drv = &e500_idle_driver;
+	struct cpuidle_device *dev;
+
+	e500_cpuidle_devices = alloc_percpu(struct cpuidle_device);
+	if (!e500_cpuidle_devices)
+		return -ENOMEM;
+
+	for_each_possible_cpu(i) {
+		dev = per_cpu_ptr(e500_cpuidle_devices, i);
+		dev->state_count = drv->state_count;
+		dev->cpu = i;
+
+		if (cpuidle_register_device(dev)) {
+			pr_err("cpuidle_register_device %d failed!\n", i);
+			return -EIO;
+		}
+	}
+
+	return 0;
+}
+
+/*
+ * e500_idle_devices_uninit(void)
+ * unregister cpuidle devices and de-allocate memory
+ */
+static void e500_idle_devices_uninit(void)
+{
+	int i;
+	struct cpuidle_device *dev;
+
+	if (!e500_cpuidle_devices)
+		return;
+
+	for_each_possible_cpu(i) {
+		dev = per_cpu_ptr(e500_cpuidle_devices, i);
+		cpuidle_unregister_device(dev);
+	}
+
+	free_percpu(e500_cpuidle_devices);
+}
+
+static void e500_cpuidle_driver_init(unsigned int max_idle_state,
+		struct cpuidle_state *cpuidle_state_table)
+{
+	int idle_state;
+	struct cpuidle_driver *drv = &e500_idle_driver;
+
+	drv->state_count = 0;
+
+	for (idle_state = 0; idle_state < max_idle_state; ++idle_state) {
+		if (!cpuidle_state_table[idle_state].enter)
+			break;
+
+		drv->states[drv->state_count] = cpuidle_state_table[idle_state];
+		drv->state_count++;
+	}
+}
+
+static int cpu_is_feature(unsigned long feature)
+{
+	return (cur_cpu_spec->cpu_features == feature);
+}
+
+static int __init e500_idle_init(void)
+{
+	struct cpuidle_state *cpuidle_state_table = NULL;
+	struct cpuidle_driver *drv = &e500_idle_driver;
+	int err;
+	unsigned int max_idle_state = 0;
+
+	if (cpuidle_disable != IDLE_NO_OVERRIDE)
+		return -ENODEV;
+
+	if (cpu_is_feature(CPU_FTRS_E500MC) || cpu_is_feature(CPU_FTRS_E5500) ||
+			cpu_is_feature(CPU_FTRS_E6500)) {
+		cpuidle_state_table = fsl_pw_idle_states;
+		max_idle_state = ARRAY_SIZE(fsl_pw_idle_states);
+	}
+
+	if (!cpuidle_state_table || !max_idle_state)
+		return -EPERM;
+
+	e500_cpuidle_driver_init(max_idle_state, cpuidle_state_table);
+
+	if (!drv->state_count)
+		return -EPERM;
+
+	err = cpuidle_register_driver(drv);
+	if (err) {
+		pr_err("Register e500 family cpuidle driver failed.\n");
+
+		return err;
+	}
+
+	err = e500_idle_devices_init();
+	if (err)
+		goto out;
+
+	err = register_cpu_notifier(&cpu_hotplug_notifier);
+	if (err)
+		goto out;
+
+	ppc_md.power_save = e500_cpuidle;
+
+	pr_info("e500_idle_driver registered.\n");
+
+	return 0;
+
+out:
+	e500_idle_devices_uninit();
+	cpuidle_unregister_driver(drv);
+
+	pr_err("Register e500 family cpuidle driver failed.\n");
+
+	return err;
+}
+device_initcall(e500_idle_init);