linux/drivers/cpuidle/cpuidle-e2k.c

142 lines
3.0 KiB
C

/*
* CPU idle for E2K machines ES2, E2S, E8C.
*
* This file is licensed under the terms of the GNU General Public
* License version 2. This program is licensed "as is" without any
* warranty of any kind, whether express or implied.
*
* Maintainer: Evgeny Kravtsunov <kravtsunov_e@mcst.ru>
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/cpuidle.h>
#include <linux/io.h>
#include <linux/export.h>
#include <asm/cpuidle_legacy.h>
#define E2K_MAX_STATES 2
static struct platform_device *pdev;
static int e2k_enter_idle(struct cpuidle_device *dev,
struct cpuidle_driver *drv,
int index)
{
thread_info_t *thread_info = current_thread_info();
thread_info->wtrap_jump_addr = PG_JMP;
if (index == 0) {
while (!need_resched()) {
default_idle();
}
} else if (index == 1) {
if (!IS_MACHINE_ES2 &&
!IS_MACHINE_E2S &&
!IS_MACHINE_E8C) {
while (!need_resched()) {
default_idle();
}
} else {
SET_WTRAP_JUMP_ADDR("jump_over_wtrap", "1f");
local_irq_enable();
wtrap();
JUMP_OVER_WTRAP_LABEL("jump_over_wtrap", "1:");
}
}
return index;
}
static struct cpuidle_driver e2k_idle_driver = {
.name = "e2k_idle",
.owner = THIS_MODULE,
.states[0] = {
.enter = e2k_enter_idle,
.exit_latency = 1,
.target_residency = 10000,
.flags = CPUIDLE_FLAG_TIME_VALID,
.name = "C0",
.desc = "Idle busy loop",
},
.states[1] = {
.enter = e2k_enter_idle,
.exit_latency = 10,
.target_residency = 10000,
.flags = CPUIDLE_FLAG_TIME_VALID,
.name = "C1",
.desc = "CPU clock gating",
},
.state_count = E2K_MAX_STATES,
};
/* Initialize CPU idle by registering the idle states */
static int e2k_cpuidle_probe(struct platform_device *pdev)
{
return cpuidle_register(&e2k_idle_driver, NULL);
}
static int e2k_cpuidle_remove(struct platform_device *pdev)
{
cpuidle_unregister(&e2k_idle_driver);
return 0;
}
static struct platform_driver e2k_cpuidle_driver = {
.probe = e2k_cpuidle_probe,
.remove = e2k_cpuidle_remove,
.driver = {
.name = "e2k_cpuidle",
.owner = THIS_MODULE,
},
};
static int __init e2k_cpuidle_init(void)
{
int rc;
pdev = platform_device_alloc("e2k_cpuidle", 0);
if (!pdev)
return -ENOMEM;
rc = platform_device_add(pdev);
if (rc) {
rc = -ENODEV;
goto undo_platform_dev_alloc;
}
rc = platform_driver_register(&e2k_cpuidle_driver);
if (rc) {
goto undo_platform_dev_add;
}
return 0;
undo_platform_dev_add:
platform_device_del(pdev);
undo_platform_dev_alloc:
platform_device_put(pdev);
return rc;
}
static void __exit e2k_cpuidle_exit(void)
{
platform_driver_unregister(&e2k_cpuidle_driver);
if (pdev) {
platform_device_del(pdev);
platform_device_put(pdev);
}
}
MODULE_AUTHOR("Evgeny Kravtsunov <kravtsunov_e@mcst.ru>");
MODULE_DESCRIPTION("E2K cpu idle driver");
MODULE_LICENSE("GPL v2");
MODULE_ALIAS("platform:e2k-cpuidle");
module_init(e2k_cpuidle_init);
module_exit(e2k_cpuidle_exit);