diff options
39 files changed, 362 insertions, 757 deletions
diff --git a/Documentation/cpuidle/driver.txt b/Documentation/cpuidle/driver.txt index 7a9e09ece931..1b0d81d92583 100644 --- a/Documentation/cpuidle/driver.txt +++ b/Documentation/cpuidle/driver.txt | |||
| @@ -15,11 +15,17 @@ has mechanisms in place to support actual entry-exit into CPU idle states. | |||
| 15 | cpuidle driver initializes the cpuidle_device structure for each CPU device | 15 | cpuidle driver initializes the cpuidle_device structure for each CPU device |
| 16 | and registers with cpuidle using cpuidle_register_device. | 16 | and registers with cpuidle using cpuidle_register_device. |
| 17 | 17 | ||
| 18 | If all the idle states are the same, the wrapper function cpuidle_register | ||
| 19 | could be used instead. | ||
| 20 | |||
| 18 | It can also support the dynamic changes (like battery <-> AC), by using | 21 | It can also support the dynamic changes (like battery <-> AC), by using |
| 19 | cpuidle_pause_and_lock, cpuidle_disable_device and cpuidle_enable_device, | 22 | cpuidle_pause_and_lock, cpuidle_disable_device and cpuidle_enable_device, |
| 20 | cpuidle_resume_and_unlock. | 23 | cpuidle_resume_and_unlock. |
| 21 | 24 | ||
| 22 | Interfaces: | 25 | Interfaces: |
| 26 | extern int cpuidle_register(struct cpuidle_driver *drv, | ||
| 27 | const struct cpumask *const coupled_cpus); | ||
| 28 | extern int cpuidle_unregister(struct cpuidle_driver *drv); | ||
| 23 | extern int cpuidle_register_driver(struct cpuidle_driver *drv); | 29 | extern int cpuidle_register_driver(struct cpuidle_driver *drv); |
| 24 | extern void cpuidle_unregister_driver(struct cpuidle_driver *drv); | 30 | extern void cpuidle_unregister_driver(struct cpuidle_driver *drv); |
| 25 | extern int cpuidle_register_device(struct cpuidle_device *dev); | 31 | extern int cpuidle_register_device(struct cpuidle_device *dev); |
diff --git a/MAINTAINERS b/MAINTAINERS index 8bdd7a7ef2f4..1bef08d407f3 100644 --- a/MAINTAINERS +++ b/MAINTAINERS | |||
| @@ -2206,6 +2206,15 @@ S: Maintained | |||
| 2206 | F: drivers/cpufreq/ | 2206 | F: drivers/cpufreq/ |
| 2207 | F: include/linux/cpufreq.h | 2207 | F: include/linux/cpufreq.h |
| 2208 | 2208 | ||
| 2209 | CPUIDLE DRIVERS | ||
| 2210 | M: Rafael J. Wysocki <rjw@sisk.pl> | ||
| 2211 | M: Daniel Lezcano <daniel.lezcano@linaro.org> | ||
| 2212 | L: linux-pm@vger.kernel.org | ||
| 2213 | S: Maintained | ||
| 2214 | T: git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm.git | ||
| 2215 | F: drivers/cpuidle/* | ||
| 2216 | F: include/linux/cpuidle.h | ||
| 2217 | |||
| 2209 | CPUID/MSR DRIVER | 2218 | CPUID/MSR DRIVER |
| 2210 | M: "H. Peter Anvin" <hpa@zytor.com> | 2219 | M: "H. Peter Anvin" <hpa@zytor.com> |
| 2211 | S: Maintained | 2220 | S: Maintained |
diff --git a/arch/arm/configs/kirkwood_defconfig b/arch/arm/configs/kirkwood_defconfig index 13482ea58b09..93f3794ba5cb 100644 --- a/arch/arm/configs/kirkwood_defconfig +++ b/arch/arm/configs/kirkwood_defconfig | |||
| @@ -56,7 +56,6 @@ CONFIG_AEABI=y | |||
| 56 | CONFIG_ZBOOT_ROM_TEXT=0x0 | 56 | CONFIG_ZBOOT_ROM_TEXT=0x0 |
| 57 | CONFIG_ZBOOT_ROM_BSS=0x0 | 57 | CONFIG_ZBOOT_ROM_BSS=0x0 |
| 58 | CONFIG_CPU_IDLE=y | 58 | CONFIG_CPU_IDLE=y |
| 59 | CONFIG_CPU_IDLE_KIRKWOOD=y | ||
| 60 | CONFIG_NET=y | 59 | CONFIG_NET=y |
| 61 | CONFIG_PACKET=y | 60 | CONFIG_PACKET=y |
| 62 | CONFIG_UNIX=y | 61 | CONFIG_UNIX=y |
diff --git a/arch/arm/mach-at91/cpuidle.c b/arch/arm/mach-at91/cpuidle.c index 0c6381516a5a..48f1228c611c 100644 --- a/arch/arm/mach-at91/cpuidle.c +++ b/arch/arm/mach-at91/cpuidle.c | |||
| @@ -27,8 +27,6 @@ | |||
| 27 | 27 | ||
| 28 | #define AT91_MAX_STATES 2 | 28 | #define AT91_MAX_STATES 2 |
| 29 | 29 | ||
| 30 | static DEFINE_PER_CPU(struct cpuidle_device, at91_cpuidle_device); | ||
| 31 | |||
| 32 | /* Actual code that puts the SoC in different idle states */ | 30 | /* Actual code that puts the SoC in different idle states */ |
| 33 | static int at91_enter_idle(struct cpuidle_device *dev, | 31 | static int at91_enter_idle(struct cpuidle_device *dev, |
| 34 | struct cpuidle_driver *drv, | 32 | struct cpuidle_driver *drv, |
| @@ -47,7 +45,6 @@ static int at91_enter_idle(struct cpuidle_device *dev, | |||
| 47 | static struct cpuidle_driver at91_idle_driver = { | 45 | static struct cpuidle_driver at91_idle_driver = { |
| 48 | .name = "at91_idle", | 46 | .name = "at91_idle", |
| 49 | .owner = THIS_MODULE, | 47 | .owner = THIS_MODULE, |
| 50 | .en_core_tk_irqen = 1, | ||
| 51 | .states[0] = ARM_CPUIDLE_WFI_STATE, | 48 | .states[0] = ARM_CPUIDLE_WFI_STATE, |
| 52 | .states[1] = { | 49 | .states[1] = { |
| 53 | .enter = at91_enter_idle, | 50 | .enter = at91_enter_idle, |
| @@ -61,20 +58,9 @@ static struct cpuidle_driver at91_idle_driver = { | |||
| 61 | }; | 58 | }; |
| 62 | 59 | ||
| 63 | /* Initialize CPU idle by registering the idle states */ | 60 | /* Initialize CPU idle by registering the idle states */ |
| 64 | static int at91_init_cpuidle(void) | 61 | static int __init at91_init_cpuidle(void) |
| 65 | { | 62 | { |
| 66 | struct cpuidle_device *device; | 63 | return cpuidle_register(&at91_idle_driver, NULL); |
| 67 | |||
| 68 | device = &per_cpu(at91_cpuidle_device, smp_processor_id()); | ||
| 69 | device->state_count = AT91_MAX_STATES; | ||
| 70 | |||
| 71 | cpuidle_register_driver(&at91_idle_driver); | ||
| 72 | |||
| 73 | if (cpuidle_register_device(device)) { | ||
| 74 | printk(KERN_ERR "at91_init_cpuidle: Failed registering\n"); | ||
| 75 | return -EIO; | ||
| 76 | } | ||
| 77 | return 0; | ||
| 78 | } | 64 | } |
| 79 | 65 | ||
| 80 | device_initcall(at91_init_cpuidle); | 66 | device_initcall(at91_init_cpuidle); |
diff --git a/arch/arm/mach-davinci/cpuidle.c b/arch/arm/mach-davinci/cpuidle.c index 5ac9e9384b15..36aef3a7dedb 100644 --- a/arch/arm/mach-davinci/cpuidle.c +++ b/arch/arm/mach-davinci/cpuidle.c | |||
| @@ -25,7 +25,6 @@ | |||
| 25 | 25 | ||
| 26 | #define DAVINCI_CPUIDLE_MAX_STATES 2 | 26 | #define DAVINCI_CPUIDLE_MAX_STATES 2 |
| 27 | 27 | ||
| 28 | static DEFINE_PER_CPU(struct cpuidle_device, davinci_cpuidle_device); | ||
| 29 | static void __iomem *ddr2_reg_base; | 28 | static void __iomem *ddr2_reg_base; |
| 30 | static bool ddr2_pdown; | 29 | static bool ddr2_pdown; |
| 31 | 30 | ||
| @@ -50,14 +49,10 @@ static void davinci_save_ddr_power(int enter, bool pdown) | |||
| 50 | 49 | ||
| 51 | /* Actual code that puts the SoC in different idle states */ | 50 | /* Actual code that puts the SoC in different idle states */ |
| 52 | static int davinci_enter_idle(struct cpuidle_device *dev, | 51 | static int davinci_enter_idle(struct cpuidle_device *dev, |
| 53 | struct cpuidle_driver *drv, | 52 | struct cpuidle_driver *drv, int index) |
| 54 | int index) | ||
| 55 | { | 53 | { |
| 56 | davinci_save_ddr_power(1, ddr2_pdown); | 54 | davinci_save_ddr_power(1, ddr2_pdown); |
| 57 | 55 | cpu_do_idle(); | |
| 58 | index = cpuidle_wrap_enter(dev, drv, index, | ||
| 59 | arm_cpuidle_simple_enter); | ||
| 60 | |||
| 61 | davinci_save_ddr_power(0, ddr2_pdown); | 56 | davinci_save_ddr_power(0, ddr2_pdown); |
| 62 | 57 | ||
| 63 | return index; | 58 | return index; |
| @@ -66,7 +61,6 @@ static int davinci_enter_idle(struct cpuidle_device *dev, | |||
| 66 | static struct cpuidle_driver davinci_idle_driver = { | 61 | static struct cpuidle_driver davinci_idle_driver = { |
| 67 | .name = "cpuidle-davinci", | 62 | .name = "cpuidle-davinci", |
| 68 | .owner = THIS_MODULE, | 63 | .owner = THIS_MODULE, |
| 69 | .en_core_tk_irqen = 1, | ||
| 70 | .states[0] = ARM_CPUIDLE_WFI_STATE, | 64 | .states[0] = ARM_CPUIDLE_WFI_STATE, |
| 71 | .states[1] = { | 65 | .states[1] = { |
| 72 | .enter = davinci_enter_idle, | 66 | .enter = davinci_enter_idle, |
| @@ -81,12 +75,8 @@ static struct cpuidle_driver davinci_idle_driver = { | |||
| 81 | 75 | ||
| 82 | static int __init davinci_cpuidle_probe(struct platform_device *pdev) | 76 | static int __init davinci_cpuidle_probe(struct platform_device *pdev) |
| 83 | { | 77 | { |
| 84 | int ret; | ||
| 85 | struct cpuidle_device *device; | ||
| 86 | struct davinci_cpuidle_config *pdata = pdev->dev.platform_data; | 78 | struct davinci_cpuidle_config *pdata = pdev->dev.platform_data; |
| 87 | 79 | ||
| 88 | device = &per_cpu(davinci_cpuidle_device, smp_processor_id()); | ||
| 89 | |||
| 90 | if (!pdata) { | 80 | if (!pdata) { |
| 91 | dev_err(&pdev->dev, "cannot get platform data\n"); | 81 | dev_err(&pdev->dev, "cannot get platform data\n"); |
| 92 | return -ENOENT; | 82 | return -ENOENT; |
| @@ -96,20 +86,7 @@ static int __init davinci_cpuidle_probe(struct platform_device *pdev) | |||
| 96 | 86 | ||
| 97 | ddr2_pdown = pdata->ddr2_pdown; | 87 | ddr2_pdown = pdata->ddr2_pdown; |
| 98 | 88 | ||
| 99 | ret = cpuidle_register_driver(&davinci_idle_driver); | 89 | return cpuidle_register(&davinci_idle_driver, NULL); |
| 100 | if (ret) { | ||
| 101 | dev_err(&pdev->dev, "failed to register driver\n"); | ||
| 102 | return ret; | ||
| 103 | } | ||
| 104 | |||
| 105 | ret = cpuidle_register_device(device); | ||
| 106 | if (ret) { | ||
| 107 | dev_err(&pdev->dev, "failed to register device\n"); | ||
| 108 | cpuidle_unregister_driver(&davinci_idle_driver); | ||
| 109 | return ret; | ||
| 110 | } | ||
| 111 | |||
| 112 | return 0; | ||
| 113 | } | 90 | } |
| 114 | 91 | ||
| 115 | static struct platform_driver davinci_cpuidle_driver = { | 92 | static struct platform_driver davinci_cpuidle_driver = { |
diff --git a/arch/arm/mach-exynos/cpuidle.c b/arch/arm/mach-exynos/cpuidle.c index fcfe0251aa3e..498a7a23e260 100644 --- a/arch/arm/mach-exynos/cpuidle.c +++ b/arch/arm/mach-exynos/cpuidle.c | |||
| @@ -58,7 +58,6 @@ static DEFINE_PER_CPU(struct cpuidle_device, exynos4_cpuidle_device); | |||
| 58 | static struct cpuidle_driver exynos4_idle_driver = { | 58 | static struct cpuidle_driver exynos4_idle_driver = { |
| 59 | .name = "exynos4_idle", | 59 | .name = "exynos4_idle", |
| 60 | .owner = THIS_MODULE, | 60 | .owner = THIS_MODULE, |
| 61 | .en_core_tk_irqen = 1, | ||
| 62 | }; | 61 | }; |
| 63 | 62 | ||
| 64 | /* Ext-GIC nIRQ/nFIQ is the only wakeup source in AFTR */ | 63 | /* Ext-GIC nIRQ/nFIQ is the only wakeup source in AFTR */ |
diff --git a/arch/arm/mach-imx/Makefile b/arch/arm/mach-imx/Makefile index c4ce0906d76a..cb70961b6239 100644 --- a/arch/arm/mach-imx/Makefile +++ b/arch/arm/mach-imx/Makefile | |||
| @@ -30,7 +30,7 @@ obj-$(CONFIG_MXC_DEBUG_BOARD) += 3ds_debugboard.o | |||
| 30 | obj-$(CONFIG_CPU_FREQ_IMX) += cpufreq.o | 30 | obj-$(CONFIG_CPU_FREQ_IMX) += cpufreq.o |
| 31 | 31 | ||
| 32 | ifeq ($(CONFIG_CPU_IDLE),y) | 32 | ifeq ($(CONFIG_CPU_IDLE),y) |
| 33 | obj-y += cpuidle.o | 33 | obj-$(CONFIG_SOC_IMX5) += cpuidle-imx5.o |
| 34 | obj-$(CONFIG_SOC_IMX6Q) += cpuidle-imx6q.o | 34 | obj-$(CONFIG_SOC_IMX6Q) += cpuidle-imx6q.o |
| 35 | endif | 35 | endif |
| 36 | 36 | ||
diff --git a/arch/arm/mach-imx/cpuidle-imx5.c b/arch/arm/mach-imx/cpuidle-imx5.c new file mode 100644 index 000000000000..5a47e3c6172f --- /dev/null +++ b/arch/arm/mach-imx/cpuidle-imx5.c | |||
| @@ -0,0 +1,37 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2012 Freescale Semiconductor, Inc. | ||
| 3 | * | ||
| 4 | * This program is free software; you can redistribute it and/or modify | ||
| 5 | * it under the terms of the GNU General Public License version 2 as | ||
| 6 | * published by the Free Software Foundation. | ||
| 7 | */ | ||
| 8 | |||
| 9 | #include <linux/cpuidle.h> | ||
| 10 | #include <linux/module.h> | ||
| 11 | #include <asm/system_misc.h> | ||
| 12 | |||
| 13 | static int imx5_cpuidle_enter(struct cpuidle_device *dev, | ||
| 14 | struct cpuidle_driver *drv, int index) | ||
| 15 | { | ||
| 16 | arm_pm_idle(); | ||
| 17 | return index; | ||
| 18 | } | ||
| 19 | |||
| 20 | static struct cpuidle_driver imx5_cpuidle_driver = { | ||
| 21 | .name = "imx5_cpuidle", | ||
| 22 | .owner = THIS_MODULE, | ||
| 23 | .states[0] = { | ||
| 24 | .enter = imx5_cpuidle_enter, | ||
| 25 | .exit_latency = 2, | ||
| 26 | .target_residency = 1, | ||
| 27 | .flags = CPUIDLE_FLAG_TIME_VALID, | ||
| 28 | .name = "IMX5 SRPG", | ||
| 29 | .desc = "CPU state retained,powered off", | ||
| 30 | }, | ||
| 31 | .state_count = 1, | ||
| 32 | }; | ||
| 33 | |||
| 34 | int __init imx5_cpuidle_init(void) | ||
| 35 | { | ||
| 36 | return cpuidle_register(&imx5_cpuidle_driver, NULL); | ||
| 37 | } | ||
diff --git a/arch/arm/mach-imx/cpuidle-imx6q.c b/arch/arm/mach-imx/cpuidle-imx6q.c index d533e2695f0e..23ddfb693b2d 100644 --- a/arch/arm/mach-imx/cpuidle-imx6q.c +++ b/arch/arm/mach-imx/cpuidle-imx6q.c | |||
| @@ -6,7 +6,6 @@ | |||
| 6 | * published by the Free Software Foundation. | 6 | * published by the Free Software Foundation. |
| 7 | */ | 7 | */ |
| 8 | 8 | ||
| 9 | #include <linux/clockchips.h> | ||
| 10 | #include <linux/cpuidle.h> | 9 | #include <linux/cpuidle.h> |
| 11 | #include <linux/module.h> | 10 | #include <linux/module.h> |
| 12 | #include <asm/cpuidle.h> | 11 | #include <asm/cpuidle.h> |
| @@ -21,10 +20,6 @@ static DEFINE_SPINLOCK(master_lock); | |||
| 21 | static int imx6q_enter_wait(struct cpuidle_device *dev, | 20 | static int imx6q_enter_wait(struct cpuidle_device *dev, |
| 22 | struct cpuidle_driver *drv, int index) | 21 | struct cpuidle_driver *drv, int index) |
| 23 | { | 22 | { |
| 24 | int cpu = dev->cpu; | ||
| 25 | |||
| 26 | clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_ENTER, &cpu); | ||
| 27 | |||
| 28 | if (atomic_inc_return(&master) == num_online_cpus()) { | 23 | if (atomic_inc_return(&master) == num_online_cpus()) { |
| 29 | /* | 24 | /* |
| 30 | * With this lock, we prevent other cpu to exit and enter | 25 | * With this lock, we prevent other cpu to exit and enter |
| @@ -43,26 +38,13 @@ idle: | |||
| 43 | cpu_do_idle(); | 38 | cpu_do_idle(); |
| 44 | done: | 39 | done: |
| 45 | atomic_dec(&master); | 40 | atomic_dec(&master); |
| 46 | clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_EXIT, &cpu); | ||
| 47 | 41 | ||
| 48 | return index; | 42 | return index; |
| 49 | } | 43 | } |
| 50 | 44 | ||
| 51 | /* | ||
| 52 | * For each cpu, setup the broadcast timer because local timer | ||
| 53 | * stops for the states other than WFI. | ||
| 54 | */ | ||
| 55 | static void imx6q_setup_broadcast_timer(void *arg) | ||
| 56 | { | ||
| 57 | int cpu = smp_processor_id(); | ||
| 58 | |||
| 59 | clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_ON, &cpu); | ||
| 60 | } | ||
| 61 | |||
| 62 | static struct cpuidle_driver imx6q_cpuidle_driver = { | 45 | static struct cpuidle_driver imx6q_cpuidle_driver = { |
| 63 | .name = "imx6q_cpuidle", | 46 | .name = "imx6q_cpuidle", |
| 64 | .owner = THIS_MODULE, | 47 | .owner = THIS_MODULE, |
| 65 | .en_core_tk_irqen = 1, | ||
| 66 | .states = { | 48 | .states = { |
| 67 | /* WFI */ | 49 | /* WFI */ |
| 68 | ARM_CPUIDLE_WFI_STATE, | 50 | ARM_CPUIDLE_WFI_STATE, |
| @@ -70,7 +52,8 @@ static struct cpuidle_driver imx6q_cpuidle_driver = { | |||
| 70 | { | 52 | { |
| 71 | .exit_latency = 50, | 53 | .exit_latency = 50, |
| 72 | .target_residency = 75, | 54 | .target_residency = 75, |
| 73 | .flags = CPUIDLE_FLAG_TIME_VALID, | 55 | .flags = CPUIDLE_FLAG_TIME_VALID | |
| 56 | CPUIDLE_FLAG_TIMER_STOP, | ||
| 74 | .enter = imx6q_enter_wait, | 57 | .enter = imx6q_enter_wait, |
| 75 | .name = "WAIT", | 58 | .name = "WAIT", |
| 76 | .desc = "Clock off", | 59 | .desc = "Clock off", |
| @@ -88,8 +71,5 @@ int __init imx6q_cpuidle_init(void) | |||
| 88 | /* Set chicken bit to get a reliable WAIT mode support */ | 71 | /* Set chicken bit to get a reliable WAIT mode support */ |
| 89 | imx6q_set_chicken_bit(); | 72 | imx6q_set_chicken_bit(); |
| 90 | 73 | ||
| 91 | /* Configure the broadcast timer on each cpu */ | 74 | return cpuidle_register(&imx6q_cpuidle_driver, NULL); |
| 92 | on_each_cpu(imx6q_setup_broadcast_timer, NULL, 1); | ||
| 93 | |||
| 94 | return imx_cpuidle_init(&imx6q_cpuidle_driver); | ||
| 95 | } | 75 | } |
diff --git a/arch/arm/mach-imx/cpuidle.c b/arch/arm/mach-imx/cpuidle.c deleted file mode 100644 index d4cb511a44a8..000000000000 --- a/arch/arm/mach-imx/cpuidle.c +++ /dev/null | |||
| @@ -1,80 +0,0 @@ | |||
| 1 | /* | ||
| 2 | * Copyright 2012 Freescale Semiconductor, Inc. | ||
| 3 | * Copyright 2012 Linaro Ltd. | ||
| 4 | * | ||
| 5 | * The code contained herein is licensed under the GNU General Public | ||
| 6 | * License. You may obtain a copy of the GNU General Public License | ||
| 7 | * Version 2 or later at the following locations: | ||
| 8 | * | ||
| 9 | * http://www.opensource.org/licenses/gpl-license.html | ||
| 10 | * http://www.gnu.org/copyleft/gpl.html | ||
| 11 | */ | ||
| 12 | |||
| 13 | #include <linux/cpuidle.h> | ||
| 14 | #include <linux/err.h> | ||
| 15 | #include <linux/hrtimer.h> | ||
| 16 | #include <linux/io.h> | ||
| 17 | #include <linux/kernel.h> | ||
| 18 | #include <linux/slab.h> | ||
| 19 | |||
| 20 | static struct cpuidle_device __percpu * imx_cpuidle_devices; | ||
| 21 | |||
| 22 | static void __init imx_cpuidle_devices_uninit(void) | ||
| 23 | { | ||
| 24 | int cpu_id; | ||
| 25 | struct cpuidle_device *dev; | ||
| 26 | |||
| 27 | for_each_possible_cpu(cpu_id) { | ||
| 28 | dev = per_cpu_ptr(imx_cpuidle_devices, cpu_id); | ||
| 29 | cpuidle_unregister_device(dev); | ||
| 30 | } | ||
| 31 | |||
| 32 | free_percpu(imx_cpuidle_devices); | ||
| 33 | } | ||
| 34 | |||
| 35 | int __init imx_cpuidle_init(struct cpuidle_driver *drv) | ||
| 36 | { | ||
| 37 | struct cpuidle_device *dev; | ||
| 38 | int cpu_id, ret; | ||
| 39 | |||
| 40 | if (drv->state_count > CPUIDLE_STATE_MAX) { | ||
| 41 | pr_err("%s: state_count exceeds maximum\n", __func__); | ||
| 42 | return -EINVAL; | ||
| 43 | } | ||
| 44 | |||
| 45 | ret = cpuidle_register_driver(drv); | ||
| 46 | if (ret) { | ||
| 47 | pr_err("%s: Failed to register cpuidle driver with error: %d\n", | ||
| 48 | __func__, ret); | ||
| 49 | return ret; | ||
| 50 | } | ||
| 51 | |||
| 52 | imx_cpuidle_devices = alloc_percpu(struct cpuidle_device); | ||
| 53 | if (imx_cpuidle_devices == NULL) { | ||
| 54 | ret = -ENOMEM; | ||
| 55 | goto unregister_drv; | ||
| 56 | } | ||
| 57 | |||
| 58 | /* initialize state data for each cpuidle_device */ | ||
| 59 | for_each_possible_cpu(cpu_id) { | ||
| 60 | dev = per_cpu_ptr(imx_cpuidle_devices, cpu_id); | ||
| 61 | dev->cpu = cpu_id; | ||
| 62 | dev->state_count = drv->state_count; | ||
| 63 | |||
| 64 | ret = cpuidle_register_device(dev); | ||
| 65 | if (ret) { | ||
| 66 | pr_err("%s: Failed to register cpu %u, error: %d\n", | ||
| 67 | __func__, cpu_id, ret); | ||
| 68 | goto uninit; | ||
| 69 | } | ||
| 70 | } | ||
| 71 | |||
| 72 | return 0; | ||
| 73 | |||
| 74 | uninit: | ||
| 75 | imx_cpuidle_devices_uninit(); | ||
| 76 | |||
| 77 | unregister_drv: | ||
| 78 | cpuidle_unregister_driver(drv); | ||
| 79 | return ret; | ||
| 80 | } | ||
diff --git a/arch/arm/mach-imx/cpuidle.h b/arch/arm/mach-imx/cpuidle.h index e092d1359d94..786f98ecc145 100644 --- a/arch/arm/mach-imx/cpuidle.h +++ b/arch/arm/mach-imx/cpuidle.h | |||
| @@ -10,18 +10,16 @@ | |||
| 10 | * http://www.gnu.org/copyleft/gpl.html | 10 | * http://www.gnu.org/copyleft/gpl.html |
| 11 | */ | 11 | */ |
| 12 | 12 | ||
| 13 | #include <linux/cpuidle.h> | ||
| 14 | |||
| 15 | #ifdef CONFIG_CPU_IDLE | 13 | #ifdef CONFIG_CPU_IDLE |
| 16 | extern int imx_cpuidle_init(struct cpuidle_driver *drv); | 14 | extern int imx5_cpuidle_init(void); |
| 17 | extern int imx6q_cpuidle_init(void); | 15 | extern int imx6q_cpuidle_init(void); |
| 18 | #else | 16 | #else |
| 19 | static inline int imx_cpuidle_init(struct cpuidle_driver *drv) | 17 | static inline int imx5_cpuidle_init(void) |
| 20 | { | 18 | { |
| 21 | return -ENODEV; | 19 | return 0; |
| 22 | } | 20 | } |
| 23 | static inline int imx6q_cpuidle_init(void) | 21 | static inline int imx6q_cpuidle_init(void) |
| 24 | { | 22 | { |
| 25 | return -ENODEV; | 23 | return 0; |
| 26 | } | 24 | } |
| 27 | #endif | 25 | #endif |
diff --git a/arch/arm/mach-imx/pm-imx5.c b/arch/arm/mach-imx/pm-imx5.c index f67fd7ee8127..82e79c658eb2 100644 --- a/arch/arm/mach-imx/pm-imx5.c +++ b/arch/arm/mach-imx/pm-imx5.c | |||
| @@ -149,33 +149,6 @@ static void imx5_pm_idle(void) | |||
| 149 | imx5_cpu_do_idle(); | 149 | imx5_cpu_do_idle(); |
| 150 | } | 150 | } |
| 151 | 151 | ||
| 152 | static int imx5_cpuidle_enter(struct cpuidle_device *dev, | ||
| 153 | struct cpuidle_driver *drv, int idx) | ||
| 154 | { | ||
| 155 | int ret; | ||
| 156 | |||
| 157 | ret = imx5_cpu_do_idle(); | ||
| 158 | if (ret < 0) | ||
| 159 | return ret; | ||
| 160 | |||
| 161 | return idx; | ||
| 162 | } | ||
| 163 | |||
| 164 | static struct cpuidle_driver imx5_cpuidle_driver = { | ||
| 165 | .name = "imx5_cpuidle", | ||
| 166 | .owner = THIS_MODULE, | ||
| 167 | .en_core_tk_irqen = 1, | ||
| 168 | .states[0] = { | ||
| 169 | .enter = imx5_cpuidle_enter, | ||
| 170 | .exit_latency = 2, | ||
| 171 | .target_residency = 1, | ||
| 172 | .flags = CPUIDLE_FLAG_TIME_VALID, | ||
| 173 | .name = "IMX5 SRPG", | ||
| 174 | .desc = "CPU state retained,powered off", | ||
| 175 | }, | ||
| 176 | .state_count = 1, | ||
| 177 | }; | ||
| 178 | |||
| 179 | static int __init imx5_pm_common_init(void) | 152 | static int __init imx5_pm_common_init(void) |
| 180 | { | 153 | { |
| 181 | int ret; | 154 | int ret; |
| @@ -193,8 +166,7 @@ static int __init imx5_pm_common_init(void) | |||
| 193 | /* Set the registers to the default cpu idle state. */ | 166 | /* Set the registers to the default cpu idle state. */ |
| 194 | mx5_cpu_lp_set(IMX5_DEFAULT_CPU_IDLE_STATE); | 167 | mx5_cpu_lp_set(IMX5_DEFAULT_CPU_IDLE_STATE); |
| 195 | 168 | ||
| 196 | imx_cpuidle_init(&imx5_cpuidle_driver); | 169 | return imx5_cpuidle_init(); |
| 197 | return 0; | ||
| 198 | } | 170 | } |
| 199 | 171 | ||
| 200 | void __init imx51_pm_init(void) | 172 | void __init imx51_pm_init(void) |
diff --git a/arch/arm/mach-omap2/common.h b/arch/arm/mach-omap2/common.h index d6ba13e1c540..14522d077c88 100644 --- a/arch/arm/mach-omap2/common.h +++ b/arch/arm/mach-omap2/common.h | |||
| @@ -249,7 +249,6 @@ extern int omap4_enter_lowpower(unsigned int cpu, unsigned int power_state); | |||
| 249 | extern int omap4_finish_suspend(unsigned long cpu_state); | 249 | extern int omap4_finish_suspend(unsigned long cpu_state); |
| 250 | extern void omap4_cpu_resume(void); | 250 | extern void omap4_cpu_resume(void); |
| 251 | extern int omap4_hotplug_cpu(unsigned int cpu, unsigned int power_state); | 251 | extern int omap4_hotplug_cpu(unsigned int cpu, unsigned int power_state); |
| 252 | extern u32 omap4_mpuss_read_prev_context_state(void); | ||
| 253 | #else | 252 | #else |
| 254 | static inline int omap4_enter_lowpower(unsigned int cpu, | 253 | static inline int omap4_enter_lowpower(unsigned int cpu, |
| 255 | unsigned int power_state) | 254 | unsigned int power_state) |
| @@ -277,10 +276,6 @@ static inline int omap4_finish_suspend(unsigned long cpu_state) | |||
| 277 | static inline void omap4_cpu_resume(void) | 276 | static inline void omap4_cpu_resume(void) |
| 278 | {} | 277 | {} |
| 279 | 278 | ||
| 280 | static inline u32 omap4_mpuss_read_prev_context_state(void) | ||
| 281 | { | ||
| 282 | return 0; | ||
| 283 | } | ||
| 284 | #endif | 279 | #endif |
| 285 | 280 | ||
| 286 | struct omap_sdrc_params; | 281 | struct omap_sdrc_params; |
diff --git a/arch/arm/mach-omap2/cpuidle34xx.c b/arch/arm/mach-omap2/cpuidle34xx.c index 80392fca86c6..cca045c95fbf 100644 --- a/arch/arm/mach-omap2/cpuidle34xx.c +++ b/arch/arm/mach-omap2/cpuidle34xx.c | |||
| @@ -26,6 +26,7 @@ | |||
| 26 | #include <linux/cpuidle.h> | 26 | #include <linux/cpuidle.h> |
| 27 | #include <linux/export.h> | 27 | #include <linux/export.h> |
| 28 | #include <linux/cpu_pm.h> | 28 | #include <linux/cpu_pm.h> |
| 29 | #include <asm/cpuidle.h> | ||
| 29 | 30 | ||
| 30 | #include "powerdomain.h" | 31 | #include "powerdomain.h" |
| 31 | #include "clockdomain.h" | 32 | #include "clockdomain.h" |
| @@ -99,11 +100,15 @@ static struct omap3_idle_statedata omap3_idle_data[] = { | |||
| 99 | }, | 100 | }, |
| 100 | }; | 101 | }; |
| 101 | 102 | ||
| 102 | /* Private functions */ | 103 | /** |
| 103 | 104 | * omap3_enter_idle - Programs OMAP3 to enter the specified state | |
| 104 | static int __omap3_enter_idle(struct cpuidle_device *dev, | 105 | * @dev: cpuidle device |
| 105 | struct cpuidle_driver *drv, | 106 | * @drv: cpuidle driver |
| 106 | int index) | 107 | * @index: the index of state to be entered |
| 108 | */ | ||
| 109 | static int omap3_enter_idle(struct cpuidle_device *dev, | ||
| 110 | struct cpuidle_driver *drv, | ||
| 111 | int index) | ||
| 107 | { | 112 | { |
| 108 | struct omap3_idle_statedata *cx = &omap3_idle_data[index]; | 113 | struct omap3_idle_statedata *cx = &omap3_idle_data[index]; |
| 109 | 114 | ||
| @@ -149,22 +154,6 @@ return_sleep_time: | |||
| 149 | } | 154 | } |
| 150 | 155 | ||
| 151 | /** | 156 | /** |
| 152 | * omap3_enter_idle - Programs OMAP3 to enter the specified state | ||
| 153 | * @dev: cpuidle device | ||
| 154 | * @drv: cpuidle driver | ||
| 155 | * @index: the index of state to be entered | ||
| 156 | * | ||
| 157 | * Called from the CPUidle framework to program the device to the | ||
| 158 | * specified target state selected by the governor. | ||
| 159 | */ | ||
| 160 | static inline int omap3_enter_idle(struct cpuidle_device *dev, | ||
| 161 | struct cpuidle_driver *drv, | ||
| 162 | int index) | ||
| 163 | { | ||
| 164 | return cpuidle_wrap_enter(dev, drv, index, __omap3_enter_idle); | ||
| 165 | } | ||
| 166 | |||
| 167 | /** | ||
| 168 | * next_valid_state - Find next valid C-state | 157 | * next_valid_state - Find next valid C-state |
| 169 | * @dev: cpuidle device | 158 | * @dev: cpuidle device |
| 170 | * @drv: cpuidle driver | 159 | * @drv: cpuidle driver |
| @@ -271,11 +260,9 @@ static int omap3_enter_idle_bm(struct cpuidle_device *dev, | |||
| 271 | return ret; | 260 | return ret; |
| 272 | } | 261 | } |
| 273 | 262 | ||
| 274 | static DEFINE_PER_CPU(struct cpuidle_device, omap3_idle_dev); | ||
| 275 | |||
| 276 | static struct cpuidle_driver omap3_idle_driver = { | 263 | static struct cpuidle_driver omap3_idle_driver = { |
| 277 | .name = "omap3_idle", | 264 | .name = "omap3_idle", |
| 278 | .owner = THIS_MODULE, | 265 | .owner = THIS_MODULE, |
| 279 | .states = { | 266 | .states = { |
| 280 | { | 267 | { |
| 281 | .enter = omap3_enter_idle_bm, | 268 | .enter = omap3_enter_idle_bm, |
| @@ -348,8 +335,6 @@ static struct cpuidle_driver omap3_idle_driver = { | |||
| 348 | */ | 335 | */ |
| 349 | int __init omap3_idle_init(void) | 336 | int __init omap3_idle_init(void) |
| 350 | { | 337 | { |
| 351 | struct cpuidle_device *dev; | ||
| 352 | |||
| 353 | mpu_pd = pwrdm_lookup("mpu_pwrdm"); | 338 | mpu_pd = pwrdm_lookup("mpu_pwrdm"); |
| 354 | core_pd = pwrdm_lookup("core_pwrdm"); | 339 | core_pd = pwrdm_lookup("core_pwrdm"); |
| 355 | per_pd = pwrdm_lookup("per_pwrdm"); | 340 | per_pd = pwrdm_lookup("per_pwrdm"); |
| @@ -358,16 +343,5 @@ int __init omap3_idle_init(void) | |||
| 358 | if (!mpu_pd || !core_pd || !per_pd || !cam_pd) | 343 | if (!mpu_pd || !core_pd || !per_pd || !cam_pd) |
| 359 | return -ENODEV; | 344 | return -ENODEV; |
| 360 | 345 | ||
| 361 | cpuidle_register_driver(&omap3_idle_driver); | 346 | return cpuidle_register(&omap3_idle_driver, NULL); |
| 362 | |||
| 363 | dev = &per_cpu(omap3_idle_dev, smp_processor_id()); | ||
| 364 | dev->cpu = 0; | ||
| 365 | |||
| 366 | if (cpuidle_register_device(dev)) { | ||
| 367 | printk(KERN_ERR "%s: CPUidle register device failed\n", | ||
| 368 | __func__); | ||
| 369 | return -EIO; | ||
| 370 | } | ||
| 371 | |||
| 372 | return 0; | ||
| 373 | } | 347 | } |
diff --git a/arch/arm/mach-omap2/cpuidle44xx.c b/arch/arm/mach-omap2/cpuidle44xx.c index d639aef0deda..5a286b56205e 100644 --- a/arch/arm/mach-omap2/cpuidle44xx.c +++ b/arch/arm/mach-omap2/cpuidle44xx.c | |||
| @@ -1,7 +1,7 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * OMAP4 CPU idle Routines | 2 | * OMAP4+ CPU idle Routines |
| 3 | * | 3 | * |
| 4 | * Copyright (C) 2011 Texas Instruments, Inc. | 4 | * Copyright (C) 2011-2013 Texas Instruments, Inc. |
| 5 | * Santosh Shilimkar <santosh.shilimkar@ti.com> | 5 | * Santosh Shilimkar <santosh.shilimkar@ti.com> |
| 6 | * Rajendra Nayak <rnayak@ti.com> | 6 | * Rajendra Nayak <rnayak@ti.com> |
| 7 | * | 7 | * |
| @@ -14,8 +14,8 @@ | |||
| 14 | #include <linux/cpuidle.h> | 14 | #include <linux/cpuidle.h> |
| 15 | #include <linux/cpu_pm.h> | 15 | #include <linux/cpu_pm.h> |
| 16 | #include <linux/export.h> | 16 | #include <linux/export.h> |
| 17 | #include <linux/clockchips.h> | ||
| 18 | 17 | ||
| 18 | #include <asm/cpuidle.h> | ||
| 19 | #include <asm/proc-fns.h> | 19 | #include <asm/proc-fns.h> |
| 20 | 20 | ||
| 21 | #include "common.h" | 21 | #include "common.h" |
| @@ -24,13 +24,13 @@ | |||
| 24 | #include "clockdomain.h" | 24 | #include "clockdomain.h" |
| 25 | 25 | ||
| 26 | /* Machine specific information */ | 26 | /* Machine specific information */ |
| 27 | struct omap4_idle_statedata { | 27 | struct idle_statedata { |
| 28 | u32 cpu_state; | 28 | u32 cpu_state; |
| 29 | u32 mpu_logic_state; | 29 | u32 mpu_logic_state; |
| 30 | u32 mpu_state; | 30 | u32 mpu_state; |
| 31 | }; | 31 | }; |
| 32 | 32 | ||
| 33 | static struct omap4_idle_statedata omap4_idle_data[] = { | 33 | static struct idle_statedata omap4_idle_data[] = { |
| 34 | { | 34 | { |
| 35 | .cpu_state = PWRDM_POWER_ON, | 35 | .cpu_state = PWRDM_POWER_ON, |
| 36 | .mpu_state = PWRDM_POWER_ON, | 36 | .mpu_state = PWRDM_POWER_ON, |
| @@ -53,11 +53,12 @@ static struct clockdomain *cpu_clkdm[NR_CPUS]; | |||
| 53 | 53 | ||
| 54 | static atomic_t abort_barrier; | 54 | static atomic_t abort_barrier; |
| 55 | static bool cpu_done[NR_CPUS]; | 55 | static bool cpu_done[NR_CPUS]; |
| 56 | static struct idle_statedata *state_ptr = &omap4_idle_data[0]; | ||
| 56 | 57 | ||
| 57 | /* Private functions */ | 58 | /* Private functions */ |
| 58 | 59 | ||
| 59 | /** | 60 | /** |
| 60 | * omap4_enter_idle_coupled_[simple/coupled] - OMAP4 cpuidle entry functions | 61 | * omap_enter_idle_[simple/coupled] - OMAP4PLUS cpuidle entry functions |
| 61 | * @dev: cpuidle device | 62 | * @dev: cpuidle device |
| 62 | * @drv: cpuidle driver | 63 | * @drv: cpuidle driver |
| 63 | * @index: the index of state to be entered | 64 | * @index: the index of state to be entered |
| @@ -66,7 +67,7 @@ static bool cpu_done[NR_CPUS]; | |||
| 66 | * specified low power state selected by the governor. | 67 | * specified low power state selected by the governor. |
| 67 | * Returns the amount of time spent in the low power state. | 68 | * Returns the amount of time spent in the low power state. |
| 68 | */ | 69 | */ |
| 69 | static int omap4_enter_idle_simple(struct cpuidle_device *dev, | 70 | static int omap_enter_idle_simple(struct cpuidle_device *dev, |
| 70 | struct cpuidle_driver *drv, | 71 | struct cpuidle_driver *drv, |
| 71 | int index) | 72 | int index) |
| 72 | { | 73 | { |
| @@ -77,12 +78,11 @@ static int omap4_enter_idle_simple(struct cpuidle_device *dev, | |||
| 77 | return index; | 78 | return index; |
| 78 | } | 79 | } |
| 79 | 80 | ||
| 80 | static int omap4_enter_idle_coupled(struct cpuidle_device *dev, | 81 | static int omap_enter_idle_coupled(struct cpuidle_device *dev, |
| 81 | struct cpuidle_driver *drv, | 82 | struct cpuidle_driver *drv, |
| 82 | int index) | 83 | int index) |
| 83 | { | 84 | { |
| 84 | struct omap4_idle_statedata *cx = &omap4_idle_data[index]; | 85 | struct idle_statedata *cx = state_ptr + index; |
| 85 | int cpu_id = smp_processor_id(); | ||
| 86 | 86 | ||
| 87 | local_fiq_disable(); | 87 | local_fiq_disable(); |
| 88 | 88 | ||
| @@ -109,8 +109,6 @@ static int omap4_enter_idle_coupled(struct cpuidle_device *dev, | |||
| 109 | } | 109 | } |
| 110 | } | 110 | } |
| 111 | 111 | ||
| 112 | clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_ENTER, &cpu_id); | ||
| 113 | |||
| 114 | /* | 112 | /* |
| 115 | * Call idle CPU PM enter notifier chain so that | 113 | * Call idle CPU PM enter notifier chain so that |
| 116 | * VFP and per CPU interrupt context is saved. | 114 | * VFP and per CPU interrupt context is saved. |
| @@ -149,11 +147,10 @@ static int omap4_enter_idle_coupled(struct cpuidle_device *dev, | |||
| 149 | * Call idle CPU cluster PM exit notifier chain | 147 | * Call idle CPU cluster PM exit notifier chain |
| 150 | * to restore GIC and wakeupgen context. | 148 | * to restore GIC and wakeupgen context. |
| 151 | */ | 149 | */ |
| 152 | if (omap4_mpuss_read_prev_context_state()) | 150 | if ((cx->mpu_state == PWRDM_POWER_RET) && |
| 151 | (cx->mpu_logic_state == PWRDM_POWER_OFF)) | ||
| 153 | cpu_cluster_pm_exit(); | 152 | cpu_cluster_pm_exit(); |
| 154 | 153 | ||
| 155 | clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_EXIT, &cpu_id); | ||
| 156 | |||
| 157 | fail: | 154 | fail: |
| 158 | cpuidle_coupled_parallel_barrier(dev, &abort_barrier); | 155 | cpuidle_coupled_parallel_barrier(dev, &abort_barrier); |
| 159 | cpu_done[dev->cpu] = false; | 156 | cpu_done[dev->cpu] = false; |
| @@ -163,49 +160,38 @@ fail: | |||
| 163 | return index; | 160 | return index; |
| 164 | } | 161 | } |
| 165 | 162 | ||
| 166 | /* | ||
| 167 | * For each cpu, setup the broadcast timer because local timers | ||
| 168 | * stops for the states above C1. | ||
| 169 | */ | ||
| 170 | static void omap_setup_broadcast_timer(void *arg) | ||
| 171 | { | ||
| 172 | int cpu = smp_processor_id(); | ||
| 173 | clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_ON, &cpu); | ||
| 174 | } | ||
| 175 | |||
| 176 | static DEFINE_PER_CPU(struct cpuidle_device, omap4_idle_dev); | ||
| 177 | |||
| 178 | static struct cpuidle_driver omap4_idle_driver = { | 163 | static struct cpuidle_driver omap4_idle_driver = { |
| 179 | .name = "omap4_idle", | 164 | .name = "omap4_idle", |
| 180 | .owner = THIS_MODULE, | 165 | .owner = THIS_MODULE, |
| 181 | .en_core_tk_irqen = 1, | ||
| 182 | .states = { | 166 | .states = { |
| 183 | { | 167 | { |
| 184 | /* C1 - CPU0 ON + CPU1 ON + MPU ON */ | 168 | /* C1 - CPU0 ON + CPU1 ON + MPU ON */ |
| 185 | .exit_latency = 2 + 2, | 169 | .exit_latency = 2 + 2, |
| 186 | .target_residency = 5, | 170 | .target_residency = 5, |
| 187 | .flags = CPUIDLE_FLAG_TIME_VALID, | 171 | .flags = CPUIDLE_FLAG_TIME_VALID, |
| 188 | .enter = omap4_enter_idle_simple, | 172 | .enter = omap_enter_idle_simple, |
| 189 | .name = "C1", | 173 | .name = "C1", |
| 190 | .desc = "MPUSS ON" | 174 | .desc = "CPUx ON, MPUSS ON" |
| 191 | }, | 175 | }, |
| 192 | { | 176 | { |
| 193 | /* C2 - CPU0 OFF + CPU1 OFF + MPU CSWR */ | 177 | /* C2 - CPU0 OFF + CPU1 OFF + MPU CSWR */ |
| 194 | .exit_latency = 328 + 440, | 178 | .exit_latency = 328 + 440, |
| 195 | .target_residency = 960, | 179 | .target_residency = 960, |
| 196 | .flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_COUPLED, | 180 | .flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_COUPLED | |
| 197 | .enter = omap4_enter_idle_coupled, | 181 | CPUIDLE_FLAG_TIMER_STOP, |
| 182 | .enter = omap_enter_idle_coupled, | ||
| 198 | .name = "C2", | 183 | .name = "C2", |
| 199 | .desc = "MPUSS CSWR", | 184 | .desc = "CPUx OFF, MPUSS CSWR", |
| 200 | }, | 185 | }, |
| 201 | { | 186 | { |
| 202 | /* C3 - CPU0 OFF + CPU1 OFF + MPU OSWR */ | 187 | /* C3 - CPU0 OFF + CPU1 OFF + MPU OSWR */ |
| 203 | .exit_latency = 460 + 518, | 188 | .exit_latency = 460 + 518, |
| 204 | .target_residency = 1100, | 189 | .target_residency = 1100, |
| 205 | .flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_COUPLED, | 190 | .flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_COUPLED | |
| 206 | .enter = omap4_enter_idle_coupled, | 191 | CPUIDLE_FLAG_TIMER_STOP, |
| 192 | .enter = omap_enter_idle_coupled, | ||
| 207 | .name = "C3", | 193 | .name = "C3", |
| 208 | .desc = "MPUSS OSWR", | 194 | .desc = "CPUx OFF, MPUSS OSWR", |
| 209 | }, | 195 | }, |
| 210 | }, | 196 | }, |
| 211 | .state_count = ARRAY_SIZE(omap4_idle_data), | 197 | .state_count = ARRAY_SIZE(omap4_idle_data), |
| @@ -215,16 +201,13 @@ static struct cpuidle_driver omap4_idle_driver = { | |||
| 215 | /* Public functions */ | 201 | /* Public functions */ |
| 216 | 202 | ||
| 217 | /** | 203 | /** |
| 218 | * omap4_idle_init - Init routine for OMAP4 idle | 204 | * omap4_idle_init - Init routine for OMAP4+ idle |
| 219 | * | 205 | * |
| 220 | * Registers the OMAP4 specific cpuidle driver to the cpuidle | 206 | * Registers the OMAP4+ specific cpuidle driver to the cpuidle |
| 221 | * framework with the valid set of states. | 207 | * framework with the valid set of states. |
| 222 | */ | 208 | */ |
| 223 | int __init omap4_idle_init(void) | 209 | int __init omap4_idle_init(void) |
| 224 | { | 210 | { |
| 225 | struct cpuidle_device *dev; | ||
| 226 | unsigned int cpu_id = 0; | ||
| 227 | |||
| 228 | mpu_pd = pwrdm_lookup("mpu_pwrdm"); | 211 | mpu_pd = pwrdm_lookup("mpu_pwrdm"); |
| 229 | cpu_pd[0] = pwrdm_lookup("cpu0_pwrdm"); | 212 | cpu_pd[0] = pwrdm_lookup("cpu0_pwrdm"); |
| 230 | cpu_pd[1] = pwrdm_lookup("cpu1_pwrdm"); | 213 | cpu_pd[1] = pwrdm_lookup("cpu1_pwrdm"); |
| @@ -236,22 +219,5 @@ int __init omap4_idle_init(void) | |||
| 236 | if (!cpu_clkdm[0] || !cpu_clkdm[1]) | 219 | if (!cpu_clkdm[0] || !cpu_clkdm[1]) |
| 237 | return -ENODEV; | 220 | return -ENODEV; |
| 238 | 221 | ||
| 239 | /* Configure the broadcast timer on each cpu */ | 222 | return cpuidle_register(&omap4_idle_driver, cpu_online_mask); |
| 240 | on_each_cpu(omap_setup_broadcast_timer, NULL, 1); | ||
| 241 | |||
| 242 | for_each_cpu(cpu_id, cpu_online_mask) { | ||
| 243 | dev = &per_cpu(omap4_idle_dev, cpu_id); | ||
| 244 | dev->cpu = cpu_id; | ||
| 245 | #ifdef CONFIG_ARCH_NEEDS_CPU_IDLE_COUPLED | ||
| 246 | dev->coupled_cpus = *cpu_online_mask; | ||
| 247 | #endif | ||
| 248 | cpuidle_register_driver(&omap4_idle_driver); | ||
| 249 | |||
| 250 | if (cpuidle_register_device(dev)) { | ||
| 251 | pr_err("%s: CPUidle register failed\n", __func__); | ||
| 252 | return -EIO; | ||
| 253 | } | ||
| 254 | } | ||
| 255 | |||
| 256 | return 0; | ||
| 257 | } | 223 | } |
diff --git a/arch/arm/mach-omap2/omap-mpuss-lowpower.c b/arch/arm/mach-omap2/omap-mpuss-lowpower.c index 8bcb64bcdcdb..e80327b6c81f 100644 --- a/arch/arm/mach-omap2/omap-mpuss-lowpower.c +++ b/arch/arm/mach-omap2/omap-mpuss-lowpower.c | |||
| @@ -139,20 +139,6 @@ static inline void cpu_clear_prev_logic_pwrst(unsigned int cpu_id) | |||
| 139 | } | 139 | } |
| 140 | } | 140 | } |
| 141 | 141 | ||
| 142 | /** | ||
| 143 | * omap4_mpuss_read_prev_context_state: | ||
| 144 | * Function returns the MPUSS previous context state | ||
| 145 | */ | ||
| 146 | u32 omap4_mpuss_read_prev_context_state(void) | ||
| 147 | { | ||
| 148 | u32 reg; | ||
| 149 | |||
| 150 | reg = omap4_prminst_read_inst_reg(OMAP4430_PRM_PARTITION, | ||
| 151 | OMAP4430_PRM_MPU_INST, OMAP4_RM_MPU_MPU_CONTEXT_OFFSET); | ||
| 152 | reg &= OMAP4430_LOSTCONTEXT_DFF_MASK; | ||
| 153 | return reg; | ||
| 154 | } | ||
| 155 | |||
| 156 | /* | 142 | /* |
| 157 | * Store the CPU cluster state for L2X0 low power operations. | 143 | * Store the CPU cluster state for L2X0 low power operations. |
| 158 | */ | 144 | */ |
diff --git a/arch/arm/mach-s3c64xx/cpuidle.c b/arch/arm/mach-s3c64xx/cpuidle.c index ead5fab0dbb5..3c8ab07c2012 100644 --- a/arch/arm/mach-s3c64xx/cpuidle.c +++ b/arch/arm/mach-s3c64xx/cpuidle.c | |||
| @@ -40,12 +40,9 @@ static int s3c64xx_enter_idle(struct cpuidle_device *dev, | |||
| 40 | return index; | 40 | return index; |
| 41 | } | 41 | } |
| 42 | 42 | ||
| 43 | static DEFINE_PER_CPU(struct cpuidle_device, s3c64xx_cpuidle_device); | ||
| 44 | |||
| 45 | static struct cpuidle_driver s3c64xx_cpuidle_driver = { | 43 | static struct cpuidle_driver s3c64xx_cpuidle_driver = { |
| 46 | .name = "s3c64xx_cpuidle", | 44 | .name = "s3c64xx_cpuidle", |
| 47 | .owner = THIS_MODULE, | 45 | .owner = THIS_MODULE, |
| 48 | .en_core_tk_irqen = 1, | ||
| 49 | .states = { | 46 | .states = { |
| 50 | { | 47 | { |
| 51 | .enter = s3c64xx_enter_idle, | 48 | .enter = s3c64xx_enter_idle, |
| @@ -61,16 +58,6 @@ static struct cpuidle_driver s3c64xx_cpuidle_driver = { | |||
| 61 | 58 | ||
| 62 | static int __init s3c64xx_init_cpuidle(void) | 59 | static int __init s3c64xx_init_cpuidle(void) |
| 63 | { | 60 | { |
| 64 | int ret; | 61 | return cpuidle_register(&s3c64xx_cpuidle_driver, NULL); |
| 65 | |||
| 66 | cpuidle_register_driver(&s3c64xx_cpuidle_driver); | ||
| 67 | |||
| 68 | ret = cpuidle_register_device(&s3c64xx_cpuidle_device); | ||
| 69 | if (ret) { | ||
| 70 | pr_err("Failed to register cpuidle device: %d\n", ret); | ||
| 71 | return ret; | ||
| 72 | } | ||
| 73 | |||
| 74 | return 0; | ||
| 75 | } | 62 | } |
| 76 | device_initcall(s3c64xx_init_cpuidle); | 63 | device_initcall(s3c64xx_init_cpuidle); |
diff --git a/arch/arm/mach-shmobile/cpuidle.c b/arch/arm/mach-shmobile/cpuidle.c index 9e050268cde4..0afeb5c7061c 100644 --- a/arch/arm/mach-shmobile/cpuidle.c +++ b/arch/arm/mach-shmobile/cpuidle.c | |||
| @@ -16,39 +16,22 @@ | |||
| 16 | #include <asm/cpuidle.h> | 16 | #include <asm/cpuidle.h> |
| 17 | #include <asm/io.h> | 17 | #include <asm/io.h> |
| 18 | 18 | ||
| 19 | int shmobile_enter_wfi(struct cpuidle_device *dev, struct cpuidle_driver *drv, | ||
| 20 | int index) | ||
| 21 | { | ||
| 22 | cpu_do_idle(); | ||
| 23 | return 0; | ||
| 24 | } | ||
| 25 | |||
| 26 | static struct cpuidle_device shmobile_cpuidle_dev; | ||
| 27 | static struct cpuidle_driver shmobile_cpuidle_default_driver = { | 19 | static struct cpuidle_driver shmobile_cpuidle_default_driver = { |
| 28 | .name = "shmobile_cpuidle", | 20 | .name = "shmobile_cpuidle", |
| 29 | .owner = THIS_MODULE, | 21 | .owner = THIS_MODULE, |
| 30 | .en_core_tk_irqen = 1, | ||
| 31 | .states[0] = ARM_CPUIDLE_WFI_STATE, | 22 | .states[0] = ARM_CPUIDLE_WFI_STATE, |
| 32 | .states[0].enter = shmobile_enter_wfi, | ||
| 33 | .safe_state_index = 0, /* C1 */ | 23 | .safe_state_index = 0, /* C1 */ |
| 34 | .state_count = 1, | 24 | .state_count = 1, |
| 35 | }; | 25 | }; |
| 36 | 26 | ||
| 37 | static struct cpuidle_driver *cpuidle_drv = &shmobile_cpuidle_default_driver; | 27 | static struct cpuidle_driver *cpuidle_drv = &shmobile_cpuidle_default_driver; |
| 38 | 28 | ||
| 39 | void shmobile_cpuidle_set_driver(struct cpuidle_driver *drv) | 29 | void __init shmobile_cpuidle_set_driver(struct cpuidle_driver *drv) |
| 40 | { | 30 | { |
| 41 | cpuidle_drv = drv; | 31 | cpuidle_drv = drv; |
| 42 | } | 32 | } |
| 43 | 33 | ||
| 44 | int shmobile_cpuidle_init(void) | 34 | int __init shmobile_cpuidle_init(void) |
| 45 | { | 35 | { |
| 46 | struct cpuidle_device *dev = &shmobile_cpuidle_dev; | 36 | return cpuidle_register(cpuidle_drv, NULL); |
| 47 | |||
| 48 | cpuidle_register_driver(cpuidle_drv); | ||
| 49 | |||
| 50 | dev->state_count = cpuidle_drv->state_count; | ||
| 51 | cpuidle_register_device(dev); | ||
| 52 | |||
| 53 | return 0; | ||
| 54 | } | 37 | } |
diff --git a/arch/arm/mach-shmobile/include/mach/common.h b/arch/arm/mach-shmobile/include/mach/common.h index e48606d8a2be..362f9b2d2c02 100644 --- a/arch/arm/mach-shmobile/include/mach/common.h +++ b/arch/arm/mach-shmobile/include/mach/common.h | |||
| @@ -13,9 +13,6 @@ extern int shmobile_clk_init(void); | |||
| 13 | extern void shmobile_handle_irq_intc(struct pt_regs *); | 13 | extern void shmobile_handle_irq_intc(struct pt_regs *); |
| 14 | extern struct platform_suspend_ops shmobile_suspend_ops; | 14 | extern struct platform_suspend_ops shmobile_suspend_ops; |
| 15 | struct cpuidle_driver; | 15 | struct cpuidle_driver; |
| 16 | struct cpuidle_device; | ||
| 17 | extern int shmobile_enter_wfi(struct cpuidle_device *dev, | ||
| 18 | struct cpuidle_driver *drv, int index); | ||
| 19 | extern void shmobile_cpuidle_set_driver(struct cpuidle_driver *drv); | 16 | extern void shmobile_cpuidle_set_driver(struct cpuidle_driver *drv); |
| 20 | 17 | ||
| 21 | extern void sh7372_init_irq(void); | 18 | extern void sh7372_init_irq(void); |
diff --git a/arch/arm/mach-shmobile/pm-sh7372.c b/arch/arm/mach-shmobile/pm-sh7372.c index a0826a48dd08..dec9293bb90d 100644 --- a/arch/arm/mach-shmobile/pm-sh7372.c +++ b/arch/arm/mach-shmobile/pm-sh7372.c | |||
| @@ -410,11 +410,9 @@ static int sh7372_enter_a4s(struct cpuidle_device *dev, | |||
| 410 | static struct cpuidle_driver sh7372_cpuidle_driver = { | 410 | static struct cpuidle_driver sh7372_cpuidle_driver = { |
| 411 | .name = "sh7372_cpuidle", | 411 | .name = "sh7372_cpuidle", |
| 412 | .owner = THIS_MODULE, | 412 | .owner = THIS_MODULE, |
| 413 | .en_core_tk_irqen = 1, | ||
| 414 | .state_count = 5, | 413 | .state_count = 5, |
| 415 | .safe_state_index = 0, /* C1 */ | 414 | .safe_state_index = 0, /* C1 */ |
| 416 | .states[0] = ARM_CPUIDLE_WFI_STATE, | 415 | .states[0] = ARM_CPUIDLE_WFI_STATE, |
| 417 | .states[0].enter = shmobile_enter_wfi, | ||
| 418 | .states[1] = { | 416 | .states[1] = { |
| 419 | .name = "C2", | 417 | .name = "C2", |
| 420 | .desc = "Core Standby Mode", | 418 | .desc = "Core Standby Mode", |
| @@ -450,12 +448,12 @@ static struct cpuidle_driver sh7372_cpuidle_driver = { | |||
| 450 | }, | 448 | }, |
| 451 | }; | 449 | }; |
| 452 | 450 | ||
| 453 | static void sh7372_cpuidle_init(void) | 451 | static void __init sh7372_cpuidle_init(void) |
| 454 | { | 452 | { |
| 455 | shmobile_cpuidle_set_driver(&sh7372_cpuidle_driver); | 453 | shmobile_cpuidle_set_driver(&sh7372_cpuidle_driver); |
| 456 | } | 454 | } |
| 457 | #else | 455 | #else |
| 458 | static void sh7372_cpuidle_init(void) {} | 456 | static void __init sh7372_cpuidle_init(void) {} |
| 459 | #endif | 457 | #endif |
| 460 | 458 | ||
| 461 | #ifdef CONFIG_SUSPEND | 459 | #ifdef CONFIG_SUSPEND |
diff --git a/arch/arm/mach-tegra/cpuidle-tegra114.c b/arch/arm/mach-tegra/cpuidle-tegra114.c index 0f4e8c483b34..1d1c6023f4a2 100644 --- a/arch/arm/mach-tegra/cpuidle-tegra114.c +++ b/arch/arm/mach-tegra/cpuidle-tegra114.c | |||
| @@ -23,39 +23,13 @@ | |||
| 23 | static struct cpuidle_driver tegra_idle_driver = { | 23 | static struct cpuidle_driver tegra_idle_driver = { |
| 24 | .name = "tegra_idle", | 24 | .name = "tegra_idle", |
| 25 | .owner = THIS_MODULE, | 25 | .owner = THIS_MODULE, |
| 26 | .en_core_tk_irqen = 1, | ||
| 27 | .state_count = 1, | 26 | .state_count = 1, |
| 28 | .states = { | 27 | .states = { |
| 29 | [0] = ARM_CPUIDLE_WFI_STATE_PWR(600), | 28 | [0] = ARM_CPUIDLE_WFI_STATE_PWR(600), |
| 30 | }, | 29 | }, |
| 31 | }; | 30 | }; |
| 32 | 31 | ||
| 33 | static DEFINE_PER_CPU(struct cpuidle_device, tegra_idle_device); | ||
| 34 | |||
| 35 | int __init tegra114_cpuidle_init(void) | 32 | int __init tegra114_cpuidle_init(void) |
| 36 | { | 33 | { |
| 37 | int ret; | 34 | return cpuidle_register(&tegra_idle_driver, NULL); |
| 38 | unsigned int cpu; | ||
| 39 | struct cpuidle_device *dev; | ||
| 40 | struct cpuidle_driver *drv = &tegra_idle_driver; | ||
| 41 | |||
| 42 | ret = cpuidle_register_driver(&tegra_idle_driver); | ||
| 43 | if (ret) { | ||
| 44 | pr_err("CPUidle driver registration failed\n"); | ||
| 45 | return ret; | ||
| 46 | } | ||
| 47 | |||
| 48 | for_each_possible_cpu(cpu) { | ||
| 49 | dev = &per_cpu(tegra_idle_device, cpu); | ||
| 50 | dev->cpu = cpu; | ||
| 51 | |||
| 52 | dev->state_count = drv->state_count; | ||
| 53 | ret = cpuidle_register_device(dev); | ||
| 54 | if (ret) { | ||
| 55 | pr_err("CPU%u: CPUidle device registration failed\n", | ||
| 56 | cpu); | ||
| 57 | return ret; | ||
| 58 | } | ||
| 59 | } | ||
| 60 | return 0; | ||
| 61 | } | 35 | } |
diff --git a/arch/arm/mach-tegra/cpuidle-tegra20.c b/arch/arm/mach-tegra/cpuidle-tegra20.c index 825ced4f7a40..590ec25855dd 100644 --- a/arch/arm/mach-tegra/cpuidle-tegra20.c +++ b/arch/arm/mach-tegra/cpuidle-tegra20.c | |||
| @@ -43,32 +43,33 @@ static atomic_t abort_barrier; | |||
| 43 | static int tegra20_idle_lp2_coupled(struct cpuidle_device *dev, | 43 | static int tegra20_idle_lp2_coupled(struct cpuidle_device *dev, |
| 44 | struct cpuidle_driver *drv, | 44 | struct cpuidle_driver *drv, |
| 45 | int index); | 45 | int index); |
| 46 | #define TEGRA20_MAX_STATES 2 | ||
| 47 | #else | ||
| 48 | #define TEGRA20_MAX_STATES 1 | ||
| 46 | #endif | 49 | #endif |
| 47 | 50 | ||
| 48 | static struct cpuidle_state tegra_idle_states[] = { | ||
| 49 | [0] = ARM_CPUIDLE_WFI_STATE_PWR(600), | ||
| 50 | #ifdef CONFIG_PM_SLEEP | ||
| 51 | [1] = { | ||
| 52 | .enter = tegra20_idle_lp2_coupled, | ||
| 53 | .exit_latency = 5000, | ||
| 54 | .target_residency = 10000, | ||
| 55 | .power_usage = 0, | ||
| 56 | .flags = CPUIDLE_FLAG_TIME_VALID | | ||
| 57 | CPUIDLE_FLAG_COUPLED, | ||
| 58 | .name = "powered-down", | ||
| 59 | .desc = "CPU power gated", | ||
| 60 | }, | ||
| 61 | #endif | ||
| 62 | }; | ||
| 63 | |||
| 64 | static struct cpuidle_driver tegra_idle_driver = { | 51 | static struct cpuidle_driver tegra_idle_driver = { |
| 65 | .name = "tegra_idle", | 52 | .name = "tegra_idle", |
| 66 | .owner = THIS_MODULE, | 53 | .owner = THIS_MODULE, |
| 67 | .en_core_tk_irqen = 1, | 54 | .states = { |
| 55 | ARM_CPUIDLE_WFI_STATE_PWR(600), | ||
| 56 | #ifdef CONFIG_PM_SLEEP | ||
| 57 | { | ||
| 58 | .enter = tegra20_idle_lp2_coupled, | ||
| 59 | .exit_latency = 5000, | ||
| 60 | .target_residency = 10000, | ||
| 61 | .power_usage = 0, | ||
| 62 | .flags = CPUIDLE_FLAG_TIME_VALID | | ||
| 63 | CPUIDLE_FLAG_COUPLED, | ||
| 64 | .name = "powered-down", | ||
| 65 | .desc = "CPU power gated", | ||
| 66 | }, | ||
| 67 | #endif | ||
| 68 | }, | ||
| 69 | .state_count = TEGRA20_MAX_STATES, | ||
| 70 | .safe_state_index = 0, | ||
| 68 | }; | 71 | }; |
| 69 | 72 | ||
| 70 | static DEFINE_PER_CPU(struct cpuidle_device, tegra_idle_device); | ||
| 71 | |||
| 72 | #ifdef CONFIG_PM_SLEEP | 73 | #ifdef CONFIG_PM_SLEEP |
| 73 | #ifdef CONFIG_SMP | 74 | #ifdef CONFIG_SMP |
| 74 | static void __iomem *pmc = IO_ADDRESS(TEGRA_PMC_BASE); | 75 | static void __iomem *pmc = IO_ADDRESS(TEGRA_PMC_BASE); |
| @@ -217,39 +218,8 @@ static int tegra20_idle_lp2_coupled(struct cpuidle_device *dev, | |||
| 217 | 218 | ||
| 218 | int __init tegra20_cpuidle_init(void) | 219 | int __init tegra20_cpuidle_init(void) |
| 219 | { | 220 | { |
| 220 | int ret; | ||
| 221 | unsigned int cpu; | ||
| 222 | struct cpuidle_device *dev; | ||
| 223 | struct cpuidle_driver *drv = &tegra_idle_driver; | ||
| 224 | |||
| 225 | #ifdef CONFIG_PM_SLEEP | 221 | #ifdef CONFIG_PM_SLEEP |
| 226 | tegra_tear_down_cpu = tegra20_tear_down_cpu; | 222 | tegra_tear_down_cpu = tegra20_tear_down_cpu; |
| 227 | #endif | 223 | #endif |
| 228 | 224 | return cpuidle_register(&tegra_idle_driver, cpu_possible_mask); | |
| 229 | drv->state_count = ARRAY_SIZE(tegra_idle_states); | ||
| 230 | memcpy(drv->states, tegra_idle_states, | ||
| 231 | drv->state_count * sizeof(drv->states[0])); | ||
| 232 | |||
| 233 | ret = cpuidle_register_driver(&tegra_idle_driver); | ||
| 234 | if (ret) { | ||
| 235 | pr_err("CPUidle driver registration failed\n"); | ||
| 236 | return ret; | ||
| 237 | } | ||
| 238 | |||
| 239 | for_each_possible_cpu(cpu) { | ||
| 240 | dev = &per_cpu(tegra_idle_device, cpu); | ||
| 241 | dev->cpu = cpu; | ||
| 242 | #ifdef CONFIG_ARCH_NEEDS_CPU_IDLE_COUPLED | ||
| 243 | dev->coupled_cpus = *cpu_possible_mask; | ||
| 244 | #endif | ||
| 245 | |||
| 246 | dev->state_count = drv->state_count; | ||
| 247 | ret = cpuidle_register_device(dev); | ||
| 248 | if (ret) { | ||
| 249 | pr_err("CPU%u: CPUidle device registration failed\n", | ||
| 250 | cpu); | ||
| 251 | return ret; | ||
| 252 | } | ||
| 253 | } | ||
| 254 | return 0; | ||
| 255 | } | 225 | } |
diff --git a/arch/arm/mach-tegra/cpuidle-tegra30.c b/arch/arm/mach-tegra/cpuidle-tegra30.c index 8b50cf4ddd6f..36dc2befa9d8 100644 --- a/arch/arm/mach-tegra/cpuidle-tegra30.c +++ b/arch/arm/mach-tegra/cpuidle-tegra30.c | |||
| @@ -43,7 +43,6 @@ static int tegra30_idle_lp2(struct cpuidle_device *dev, | |||
| 43 | static struct cpuidle_driver tegra_idle_driver = { | 43 | static struct cpuidle_driver tegra_idle_driver = { |
| 44 | .name = "tegra_idle", | 44 | .name = "tegra_idle", |
| 45 | .owner = THIS_MODULE, | 45 | .owner = THIS_MODULE, |
| 46 | .en_core_tk_irqen = 1, | ||
| 47 | #ifdef CONFIG_PM_SLEEP | 46 | #ifdef CONFIG_PM_SLEEP |
| 48 | .state_count = 2, | 47 | .state_count = 2, |
| 49 | #else | 48 | #else |
| @@ -65,8 +64,6 @@ static struct cpuidle_driver tegra_idle_driver = { | |||
| 65 | }, | 64 | }, |
| 66 | }; | 65 | }; |
| 67 | 66 | ||
| 68 | static DEFINE_PER_CPU(struct cpuidle_device, tegra_idle_device); | ||
| 69 | |||
| 70 | #ifdef CONFIG_PM_SLEEP | 67 | #ifdef CONFIG_PM_SLEEP |
| 71 | static bool tegra30_cpu_cluster_power_down(struct cpuidle_device *dev, | 68 | static bool tegra30_cpu_cluster_power_down(struct cpuidle_device *dev, |
| 72 | struct cpuidle_driver *drv, | 69 | struct cpuidle_driver *drv, |
| @@ -157,32 +154,8 @@ static int tegra30_idle_lp2(struct cpuidle_device *dev, | |||
| 157 | 154 | ||
| 158 | int __init tegra30_cpuidle_init(void) | 155 | int __init tegra30_cpuidle_init(void) |
| 159 | { | 156 | { |
| 160 | int ret; | ||
| 161 | unsigned int cpu; | ||
| 162 | struct cpuidle_device *dev; | ||
| 163 | struct cpuidle_driver *drv = &tegra_idle_driver; | ||
| 164 | |||
| 165 | #ifdef CONFIG_PM_SLEEP | 157 | #ifdef CONFIG_PM_SLEEP |
| 166 | tegra_tear_down_cpu = tegra30_tear_down_cpu; | 158 | tegra_tear_down_cpu = tegra30_tear_down_cpu; |
| 167 | #endif | 159 | #endif |
| 168 | 160 | return cpuidle_register(&tegra_idle_driver, NULL); | |
| 169 | ret = cpuidle_register_driver(&tegra_idle_driver); | ||
| 170 | if (ret) { | ||
| 171 | pr_err("CPUidle driver registration failed\n"); | ||
| 172 | return ret; | ||
| 173 | } | ||
| 174 | |||
| 175 | for_each_possible_cpu(cpu) { | ||
| 176 | dev = &per_cpu(tegra_idle_device, cpu); | ||
| 177 | dev->cpu = cpu; | ||
| 178 | |||
| 179 | dev->state_count = drv->state_count; | ||
| 180 | ret = cpuidle_register_device(dev); | ||
| 181 | if (ret) { | ||
| 182 | pr_err("CPU%u: CPUidle device registration failed\n", | ||
| 183 | cpu); | ||
| 184 | return ret; | ||
| 185 | } | ||
| 186 | } | ||
| 187 | return 0; | ||
| 188 | } | 161 | } |
diff --git a/arch/arm/mach-ux500/cpuidle.c b/arch/arm/mach-ux500/cpuidle.c index ce9149302cc3..488e07472d98 100644 --- a/arch/arm/mach-ux500/cpuidle.c +++ b/arch/arm/mach-ux500/cpuidle.c | |||
| @@ -11,7 +11,6 @@ | |||
| 11 | 11 | ||
| 12 | #include <linux/module.h> | 12 | #include <linux/module.h> |
| 13 | #include <linux/cpuidle.h> | 13 | #include <linux/cpuidle.h> |
| 14 | #include <linux/clockchips.h> | ||
| 15 | #include <linux/spinlock.h> | 14 | #include <linux/spinlock.h> |
| 16 | #include <linux/atomic.h> | 15 | #include <linux/atomic.h> |
| 17 | #include <linux/smp.h> | 16 | #include <linux/smp.h> |
| @@ -22,7 +21,6 @@ | |||
| 22 | 21 | ||
| 23 | static atomic_t master = ATOMIC_INIT(0); | 22 | static atomic_t master = ATOMIC_INIT(0); |
| 24 | static DEFINE_SPINLOCK(master_lock); | 23 | static DEFINE_SPINLOCK(master_lock); |
| 25 | static DEFINE_PER_CPU(struct cpuidle_device, ux500_cpuidle_device); | ||
| 26 | 24 | ||
| 27 | static inline int ux500_enter_idle(struct cpuidle_device *dev, | 25 | static inline int ux500_enter_idle(struct cpuidle_device *dev, |
| 28 | struct cpuidle_driver *drv, int index) | 26 | struct cpuidle_driver *drv, int index) |
| @@ -30,8 +28,6 @@ static inline int ux500_enter_idle(struct cpuidle_device *dev, | |||
| 30 | int this_cpu = smp_processor_id(); | 28 | int this_cpu = smp_processor_id(); |
| 31 | bool recouple = false; | 29 | bool recouple = false; |
| 32 | 30 | ||
| 33 | clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_ENTER, &this_cpu); | ||
| 34 | |||
| 35 | if (atomic_inc_return(&master) == num_online_cpus()) { | 31 | if (atomic_inc_return(&master) == num_online_cpus()) { |
| 36 | 32 | ||
| 37 | /* With this lock, we prevent the other cpu to exit and enter | 33 | /* With this lock, we prevent the other cpu to exit and enter |
| @@ -91,22 +87,20 @@ out: | |||
| 91 | spin_unlock(&master_lock); | 87 | spin_unlock(&master_lock); |
| 92 | } | 88 | } |
| 93 | 89 | ||
| 94 | clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_EXIT, &this_cpu); | ||
| 95 | |||
| 96 | return index; | 90 | return index; |
| 97 | } | 91 | } |
| 98 | 92 | ||
| 99 | static struct cpuidle_driver ux500_idle_driver = { | 93 | static struct cpuidle_driver ux500_idle_driver = { |
| 100 | .name = "ux500_idle", | 94 | .name = "ux500_idle", |
| 101 | .owner = THIS_MODULE, | 95 | .owner = THIS_MODULE, |
| 102 | .en_core_tk_irqen = 1, | ||
| 103 | .states = { | 96 | .states = { |
| 104 | ARM_CPUIDLE_WFI_STATE, | 97 | ARM_CPUIDLE_WFI_STATE, |
| 105 | { | 98 | { |
| 106 | .enter = ux500_enter_idle, | 99 | .enter = ux500_enter_idle, |
| 107 | .exit_latency = 70, | 100 | .exit_latency = 70, |
| 108 | .target_residency = 260, | 101 | .target_residency = 260, |
| 109 | .flags = CPUIDLE_FLAG_TIME_VALID, | 102 | .flags = CPUIDLE_FLAG_TIME_VALID | |
| 103 | CPUIDLE_FLAG_TIMER_STOP, | ||
| 110 | .name = "ApIdle", | 104 | .name = "ApIdle", |
| 111 | .desc = "ARM Retention", | 105 | .desc = "ARM Retention", |
| 112 | }, | 106 | }, |
| @@ -115,59 +109,13 @@ static struct cpuidle_driver ux500_idle_driver = { | |||
| 115 | .state_count = 2, | 109 | .state_count = 2, |
| 116 | }; | 110 | }; |
| 117 | 111 | ||
| 118 | /* | ||
| 119 | * For each cpu, setup the broadcast timer because we will | ||
| 120 | * need to migrate the timers for the states >= ApIdle. | ||
| 121 | */ | ||
| 122 | static void ux500_setup_broadcast_timer(void *arg) | ||
| 123 | { | ||
| 124 | int cpu = smp_processor_id(); | ||
| 125 | clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_ON, &cpu); | ||
| 126 | } | ||
| 127 | |||
| 128 | int __init ux500_idle_init(void) | 112 | int __init ux500_idle_init(void) |
| 129 | { | 113 | { |
| 130 | int ret, cpu; | ||
| 131 | struct cpuidle_device *device; | ||
| 132 | |||
| 133 | /* Configure wake up reasons */ | 114 | /* Configure wake up reasons */ |
| 134 | prcmu_enable_wakeups(PRCMU_WAKEUP(ARM) | PRCMU_WAKEUP(RTC) | | 115 | prcmu_enable_wakeups(PRCMU_WAKEUP(ARM) | PRCMU_WAKEUP(RTC) | |
| 135 | PRCMU_WAKEUP(ABB)); | 116 | PRCMU_WAKEUP(ABB)); |
| 136 | 117 | ||
| 137 | /* | 118 | return cpuidle_register(&ux500_idle_driver, NULL); |
| 138 | * Configure the timer broadcast for each cpu, that must | ||
| 139 | * be done from the cpu context, so we use a smp cross | ||
| 140 | * call with 'on_each_cpu'. | ||
| 141 | */ | ||
| 142 | on_each_cpu(ux500_setup_broadcast_timer, NULL, 1); | ||
| 143 | |||
| 144 | ret = cpuidle_register_driver(&ux500_idle_driver); | ||
| 145 | if (ret) { | ||
| 146 | printk(KERN_ERR "failed to register ux500 idle driver\n"); | ||
| 147 | return ret; | ||
| 148 | } | ||
| 149 | |||
| 150 | for_each_online_cpu(cpu) { | ||
| 151 | device = &per_cpu(ux500_cpuidle_device, cpu); | ||
| 152 | device->cpu = cpu; | ||
| 153 | ret = cpuidle_register_device(device); | ||
| 154 | if (ret) { | ||
| 155 | printk(KERN_ERR "Failed to register cpuidle " | ||
| 156 | "device for cpu%d\n", cpu); | ||
| 157 | goto out_unregister; | ||
| 158 | } | ||
| 159 | } | ||
| 160 | out: | ||
| 161 | return ret; | ||
| 162 | |||
| 163 | out_unregister: | ||
| 164 | for_each_online_cpu(cpu) { | ||
| 165 | device = &per_cpu(ux500_cpuidle_device, cpu); | ||
| 166 | cpuidle_unregister_device(device); | ||
| 167 | } | ||
| 168 | |||
| 169 | cpuidle_unregister_driver(&ux500_idle_driver); | ||
| 170 | goto out; | ||
| 171 | } | 119 | } |
| 172 | 120 | ||
| 173 | device_initcall(ux500_idle_init); | 121 | device_initcall(ux500_idle_init); |
diff --git a/arch/powerpc/platforms/pseries/processor_idle.c b/arch/powerpc/platforms/pseries/processor_idle.c index 4d806b419606..4644efa06941 100644 --- a/arch/powerpc/platforms/pseries/processor_idle.c +++ b/arch/powerpc/platforms/pseries/processor_idle.c | |||
| @@ -23,8 +23,8 @@ | |||
| 23 | #include "pseries.h" | 23 | #include "pseries.h" |
| 24 | 24 | ||
| 25 | struct cpuidle_driver pseries_idle_driver = { | 25 | struct cpuidle_driver pseries_idle_driver = { |
| 26 | .name = "pseries_idle", | 26 | .name = "pseries_idle", |
| 27 | .owner = THIS_MODULE, | 27 | .owner = THIS_MODULE, |
| 28 | }; | 28 | }; |
| 29 | 29 | ||
| 30 | #define MAX_IDLE_STATE_COUNT 2 | 30 | #define MAX_IDLE_STATE_COUNT 2 |
| @@ -33,10 +33,8 @@ static int max_idle_state = MAX_IDLE_STATE_COUNT - 1; | |||
| 33 | static struct cpuidle_device __percpu *pseries_cpuidle_devices; | 33 | static struct cpuidle_device __percpu *pseries_cpuidle_devices; |
| 34 | static struct cpuidle_state *cpuidle_state_table; | 34 | static struct cpuidle_state *cpuidle_state_table; |
| 35 | 35 | ||
| 36 | static inline void idle_loop_prolog(unsigned long *in_purr, ktime_t *kt_before) | 36 | static inline void idle_loop_prolog(unsigned long *in_purr) |
| 37 | { | 37 | { |
| 38 | |||
| 39 | *kt_before = ktime_get(); | ||
| 40 | *in_purr = mfspr(SPRN_PURR); | 38 | *in_purr = mfspr(SPRN_PURR); |
| 41 | /* | 39 | /* |
| 42 | * Indicate to the HV that we are idle. Now would be | 40 | * Indicate to the HV that we are idle. Now would be |
| @@ -45,12 +43,10 @@ static inline void idle_loop_prolog(unsigned long *in_purr, ktime_t *kt_before) | |||
| 45 | get_lppaca()->idle = 1; | 43 | get_lppaca()->idle = 1; |
| 46 | } | 44 | } |
| 47 | 45 | ||
| 48 | static inline s64 idle_loop_epilog(unsigned long in_purr, ktime_t kt_before) | 46 | static inline void idle_loop_epilog(unsigned long in_purr) |
| 49 | { | 47 | { |
| 50 | get_lppaca()->wait_state_cycles += mfspr(SPRN_PURR) - in_purr; | 48 | get_lppaca()->wait_state_cycles += mfspr(SPRN_PURR) - in_purr; |
| 51 | get_lppaca()->idle = 0; | 49 | get_lppaca()->idle = 0; |
| 52 | |||
| 53 | return ktime_to_us(ktime_sub(ktime_get(), kt_before)); | ||
| 54 | } | 50 | } |
| 55 | 51 | ||
| 56 | static int snooze_loop(struct cpuidle_device *dev, | 52 | static int snooze_loop(struct cpuidle_device *dev, |
| @@ -58,10 +54,9 @@ static int snooze_loop(struct cpuidle_device *dev, | |||
| 58 | int index) | 54 | int index) |
| 59 | { | 55 | { |
| 60 | unsigned long in_purr; | 56 | unsigned long in_purr; |
| 61 | ktime_t kt_before; | ||
| 62 | int cpu = dev->cpu; | 57 | int cpu = dev->cpu; |
| 63 | 58 | ||
| 64 | idle_loop_prolog(&in_purr, &kt_before); | 59 | idle_loop_prolog(&in_purr); |
| 65 | local_irq_enable(); | 60 | local_irq_enable(); |
| 66 | set_thread_flag(TIF_POLLING_NRFLAG); | 61 | set_thread_flag(TIF_POLLING_NRFLAG); |
| 67 | 62 | ||
| @@ -75,8 +70,8 @@ static int snooze_loop(struct cpuidle_device *dev, | |||
| 75 | clear_thread_flag(TIF_POLLING_NRFLAG); | 70 | clear_thread_flag(TIF_POLLING_NRFLAG); |
| 76 | smp_mb(); | 71 | smp_mb(); |
| 77 | 72 | ||
| 78 | dev->last_residency = | 73 | idle_loop_epilog(in_purr); |
| 79 | (int)idle_loop_epilog(in_purr, kt_before); | 74 | |
| 80 | return index; | 75 | return index; |
| 81 | } | 76 | } |
| 82 | 77 | ||
| @@ -102,9 +97,8 @@ static int dedicated_cede_loop(struct cpuidle_device *dev, | |||
| 102 | int index) | 97 | int index) |
| 103 | { | 98 | { |
| 104 | unsigned long in_purr; | 99 | unsigned long in_purr; |
| 105 | ktime_t kt_before; | ||
| 106 | 100 | ||
| 107 | idle_loop_prolog(&in_purr, &kt_before); | 101 | idle_loop_prolog(&in_purr); |
| 108 | get_lppaca()->donate_dedicated_cpu = 1; | 102 | get_lppaca()->donate_dedicated_cpu = 1; |
| 109 | 103 | ||
| 110 | ppc64_runlatch_off(); | 104 | ppc64_runlatch_off(); |
| @@ -112,8 +106,9 @@ static int dedicated_cede_loop(struct cpuidle_device *dev, | |||
| 112 | check_and_cede_processor(); | 106 | check_and_cede_processor(); |
| 113 | 107 | ||
| 114 | get_lppaca()->donate_dedicated_cpu = 0; | 108 | get_lppaca()->donate_dedicated_cpu = 0; |
| 115 | dev->last_residency = | 109 | |
| 116 | (int)idle_loop_epilog(in_purr, kt_before); | 110 | idle_loop_epilog(in_purr); |
| 111 | |||
| 117 | return index; | 112 | return index; |
| 118 | } | 113 | } |
| 119 | 114 | ||
| @@ -122,9 +117,8 @@ static int shared_cede_loop(struct cpuidle_device *dev, | |||
| 122 | int index) | 117 | int index) |
| 123 | { | 118 | { |
| 124 | unsigned long in_purr; | 119 | unsigned long in_purr; |
| 125 | ktime_t kt_before; | ||
| 126 | 120 | ||
| 127 | idle_loop_prolog(&in_purr, &kt_before); | 121 | idle_loop_prolog(&in_purr); |
| 128 | 122 | ||
| 129 | /* | 123 | /* |
| 130 | * Yield the processor to the hypervisor. We return if | 124 | * Yield the processor to the hypervisor. We return if |
| @@ -135,8 +129,8 @@ static int shared_cede_loop(struct cpuidle_device *dev, | |||
| 135 | */ | 129 | */ |
| 136 | check_and_cede_processor(); | 130 | check_and_cede_processor(); |
| 137 | 131 | ||
| 138 | dev->last_residency = | 132 | idle_loop_epilog(in_purr); |
| 139 | (int)idle_loop_epilog(in_purr, kt_before); | 133 | |
| 140 | return index; | 134 | return index; |
| 141 | } | 135 | } |
| 142 | 136 | ||
diff --git a/arch/sh/include/asm/suspend.h b/arch/sh/include/asm/suspend.h index e14567a7e9a1..70ae0b2888ab 100644 --- a/arch/sh/include/asm/suspend.h +++ b/arch/sh/include/asm/suspend.h | |||
| @@ -14,9 +14,9 @@ struct swsusp_arch_regs { | |||
| 14 | void sh_mobile_call_standby(unsigned long mode); | 14 | void sh_mobile_call_standby(unsigned long mode); |
| 15 | 15 | ||
| 16 | #ifdef CONFIG_CPU_IDLE | 16 | #ifdef CONFIG_CPU_IDLE |
| 17 | void sh_mobile_setup_cpuidle(void); | 17 | int sh_mobile_setup_cpuidle(void); |
| 18 | #else | 18 | #else |
| 19 | static inline void sh_mobile_setup_cpuidle(void) {} | 19 | static inline int sh_mobile_setup_cpuidle(void) { return 0; } |
| 20 | #endif | 20 | #endif |
| 21 | 21 | ||
| 22 | /* notifier chains for pre/post sleep hooks */ | 22 | /* notifier chains for pre/post sleep hooks */ |
diff --git a/arch/sh/kernel/cpu/shmobile/cpuidle.c b/arch/sh/kernel/cpu/shmobile/cpuidle.c index 1ddc876d3b26..d30622592116 100644 --- a/arch/sh/kernel/cpu/shmobile/cpuidle.c +++ b/arch/sh/kernel/cpu/shmobile/cpuidle.c | |||
| @@ -51,70 +51,53 @@ static int cpuidle_sleep_enter(struct cpuidle_device *dev, | |||
| 51 | return k; | 51 | return k; |
| 52 | } | 52 | } |
| 53 | 53 | ||
| 54 | static struct cpuidle_device cpuidle_dev; | ||
| 55 | static struct cpuidle_driver cpuidle_driver = { | 54 | static struct cpuidle_driver cpuidle_driver = { |
| 56 | .name = "sh_idle", | 55 | .name = "sh_idle", |
| 57 | .owner = THIS_MODULE, | 56 | .owner = THIS_MODULE, |
| 58 | .en_core_tk_irqen = 1, | 57 | .states = { |
| 58 | { | ||
| 59 | .exit_latency = 1, | ||
| 60 | .target_residency = 1 * 2, | ||
| 61 | .power_usage = 3, | ||
| 62 | .flags = CPUIDLE_FLAG_TIME_VALID, | ||
| 63 | .enter = cpuidle_sleep_enter, | ||
| 64 | .name = "C1", | ||
| 65 | .desc = "SuperH Sleep Mode", | ||
| 66 | }, | ||
| 67 | { | ||
| 68 | .exit_latency = 100, | ||
| 69 | .target_residency = 1 * 2, | ||
| 70 | .power_usage = 1, | ||
| 71 | .flags = CPUIDLE_FLAG_TIME_VALID, | ||
| 72 | .enter = cpuidle_sleep_enter, | ||
| 73 | .name = "C2", | ||
| 74 | .desc = "SuperH Sleep Mode [SF]", | ||
| 75 | .disabled = true, | ||
| 76 | }, | ||
| 77 | { | ||
| 78 | .exit_latency = 2300, | ||
| 79 | .target_residency = 1 * 2, | ||
| 80 | .power_usage = 1, | ||
| 81 | .flags = CPUIDLE_FLAG_TIME_VALID, | ||
| 82 | .enter = cpuidle_sleep_enter, | ||
| 83 | .name = "C3", | ||
| 84 | .desc = "SuperH Mobile Standby Mode [SF]", | ||
| 85 | .disabled = true, | ||
| 86 | }, | ||
| 87 | }, | ||
| 88 | .safe_state_index = 0, | ||
| 89 | .state_count = 3, | ||
| 59 | }; | 90 | }; |
| 60 | 91 | ||
| 61 | void sh_mobile_setup_cpuidle(void) | 92 | int __init sh_mobile_setup_cpuidle(void) |
| 62 | { | 93 | { |
| 63 | struct cpuidle_device *dev = &cpuidle_dev; | 94 | int ret; |
| 64 | struct cpuidle_driver *drv = &cpuidle_driver; | ||
| 65 | struct cpuidle_state *state; | ||
| 66 | int i; | ||
| 67 | 95 | ||
| 96 | if (sh_mobile_sleep_supported & SUSP_SH_SF) | ||
| 97 | cpuidle_driver.states[1].disabled = false; | ||
| 68 | 98 | ||
| 69 | for (i = 0; i < CPUIDLE_STATE_MAX; i++) { | 99 | if (sh_mobile_sleep_supported & SUSP_SH_STANDBY) |
| 70 | drv->states[i].name[0] = '\0'; | 100 | cpuidle_driver.states[2].disabled = false; |
| 71 | drv->states[i].desc[0] = '\0'; | ||
| 72 | } | ||
| 73 | 101 | ||
| 74 | i = CPUIDLE_DRIVER_STATE_START; | 102 | return cpuidle_register(&cpuidle_driver); |
| 75 | |||
| 76 | state = &drv->states[i++]; | ||
| 77 | snprintf(state->name, CPUIDLE_NAME_LEN, "C1"); | ||
| 78 | strncpy(state->desc, "SuperH Sleep Mode", CPUIDLE_DESC_LEN); | ||
| 79 | state->exit_latency = 1; | ||
| 80 | state->target_residency = 1 * 2; | ||
| 81 | state->power_usage = 3; | ||
| 82 | state->flags = 0; | ||
| 83 | state->flags |= CPUIDLE_FLAG_TIME_VALID; | ||
| 84 | state->enter = cpuidle_sleep_enter; | ||
| 85 | |||
| 86 | drv->safe_state_index = i-1; | ||
| 87 | |||
| 88 | if (sh_mobile_sleep_supported & SUSP_SH_SF) { | ||
| 89 | state = &drv->states[i++]; | ||
| 90 | snprintf(state->name, CPUIDLE_NAME_LEN, "C2"); | ||
| 91 | strncpy(state->desc, "SuperH Sleep Mode [SF]", | ||
| 92 | CPUIDLE_DESC_LEN); | ||
| 93 | state->exit_latency = 100; | ||
| 94 | state->target_residency = 1 * 2; | ||
| 95 | state->power_usage = 1; | ||
| 96 | state->flags = 0; | ||
| 97 | state->flags |= CPUIDLE_FLAG_TIME_VALID; | ||
| 98 | state->enter = cpuidle_sleep_enter; | ||
| 99 | } | ||
| 100 | |||
| 101 | if (sh_mobile_sleep_supported & SUSP_SH_STANDBY) { | ||
| 102 | state = &drv->states[i++]; | ||
| 103 | snprintf(state->name, CPUIDLE_NAME_LEN, "C3"); | ||
| 104 | strncpy(state->desc, "SuperH Mobile Standby Mode [SF]", | ||
| 105 | CPUIDLE_DESC_LEN); | ||
| 106 | state->exit_latency = 2300; | ||
| 107 | state->target_residency = 1 * 2; | ||
| 108 | state->power_usage = 1; | ||
| 109 | state->flags = 0; | ||
| 110 | state->flags |= CPUIDLE_FLAG_TIME_VALID; | ||
| 111 | state->enter = cpuidle_sleep_enter; | ||
| 112 | } | ||
| 113 | |||
| 114 | drv->state_count = i; | ||
| 115 | dev->state_count = i; | ||
| 116 | |||
| 117 | cpuidle_register_driver(&cpuidle_driver); | ||
| 118 | |||
| 119 | cpuidle_register_device(dev); | ||
| 120 | } | 103 | } |
diff --git a/arch/sh/kernel/cpu/shmobile/pm.c b/arch/sh/kernel/cpu/shmobile/pm.c index 08d27fac8d08..ac37b7234f85 100644 --- a/arch/sh/kernel/cpu/shmobile/pm.c +++ b/arch/sh/kernel/cpu/shmobile/pm.c | |||
| @@ -150,8 +150,7 @@ static const struct platform_suspend_ops sh_pm_ops = { | |||
| 150 | static int __init sh_pm_init(void) | 150 | static int __init sh_pm_init(void) |
| 151 | { | 151 | { |
| 152 | suspend_set_ops(&sh_pm_ops); | 152 | suspend_set_ops(&sh_pm_ops); |
| 153 | sh_mobile_setup_cpuidle(); | 153 | return sh_mobile_setup_cpuidle(); |
| 154 | return 0; | ||
| 155 | } | 154 | } |
| 156 | 155 | ||
| 157 | late_initcall(sh_pm_init); | 156 | late_initcall(sh_pm_init); |
diff --git a/arch/x86/kernel/apm_32.c b/arch/x86/kernel/apm_32.c index 66b5faffe14a..53a4e2744846 100644 --- a/arch/x86/kernel/apm_32.c +++ b/arch/x86/kernel/apm_32.c | |||
| @@ -373,7 +373,6 @@ static int apm_cpu_idle(struct cpuidle_device *dev, | |||
| 373 | static struct cpuidle_driver apm_idle_driver = { | 373 | static struct cpuidle_driver apm_idle_driver = { |
| 374 | .name = "apm_idle", | 374 | .name = "apm_idle", |
| 375 | .owner = THIS_MODULE, | 375 | .owner = THIS_MODULE, |
| 376 | .en_core_tk_irqen = 1, | ||
| 377 | .states = { | 376 | .states = { |
| 378 | { /* entry 0 is for polling */ }, | 377 | { /* entry 0 is for polling */ }, |
| 379 | { /* entry 1 is for APM idle */ | 378 | { /* entry 1 is for APM idle */ |
diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c index ee255c60bdac..f0df2c9434d2 100644 --- a/drivers/acpi/processor_idle.c +++ b/drivers/acpi/processor_idle.c | |||
| @@ -918,7 +918,6 @@ static int acpi_idle_enter_bm(struct cpuidle_device *dev, | |||
| 918 | struct cpuidle_driver acpi_idle_driver = { | 918 | struct cpuidle_driver acpi_idle_driver = { |
| 919 | .name = "acpi_idle", | 919 | .name = "acpi_idle", |
| 920 | .owner = THIS_MODULE, | 920 | .owner = THIS_MODULE, |
| 921 | .en_core_tk_irqen = 1, | ||
| 922 | }; | 921 | }; |
| 923 | 922 | ||
| 924 | /** | 923 | /** |
diff --git a/drivers/cpuidle/Kconfig b/drivers/cpuidle/Kconfig index 071e2c3eec4f..c4cc27e5c8a5 100644 --- a/drivers/cpuidle/Kconfig +++ b/drivers/cpuidle/Kconfig | |||
| @@ -39,10 +39,4 @@ config CPU_IDLE_CALXEDA | |||
| 39 | help | 39 | help |
| 40 | Select this to enable cpuidle on Calxeda processors. | 40 | Select this to enable cpuidle on Calxeda processors. |
| 41 | 41 | ||
| 42 | config CPU_IDLE_KIRKWOOD | ||
| 43 | bool "CPU Idle Driver for Kirkwood processors" | ||
| 44 | depends on ARCH_KIRKWOOD | ||
| 45 | help | ||
| 46 | Select this to enable cpuidle on Kirkwood processors. | ||
| 47 | |||
| 48 | endif | 42 | endif |
diff --git a/drivers/cpuidle/Makefile b/drivers/cpuidle/Makefile index 24c6e7d945ed..0d8bd55e776f 100644 --- a/drivers/cpuidle/Makefile +++ b/drivers/cpuidle/Makefile | |||
| @@ -6,4 +6,4 @@ obj-y += cpuidle.o driver.o governor.o sysfs.o governors/ | |||
| 6 | obj-$(CONFIG_ARCH_NEEDS_CPU_IDLE_COUPLED) += coupled.o | 6 | obj-$(CONFIG_ARCH_NEEDS_CPU_IDLE_COUPLED) += coupled.o |
| 7 | 7 | ||
| 8 | obj-$(CONFIG_CPU_IDLE_CALXEDA) += cpuidle-calxeda.o | 8 | obj-$(CONFIG_CPU_IDLE_CALXEDA) += cpuidle-calxeda.o |
| 9 | obj-$(CONFIG_CPU_IDLE_KIRKWOOD) += cpuidle-kirkwood.o | 9 | obj-$(CONFIG_ARCH_KIRKWOOD) += cpuidle-kirkwood.o |
diff --git a/drivers/cpuidle/cpuidle-calxeda.c b/drivers/cpuidle/cpuidle-calxeda.c index e1aab38c5a8d..223379169cb0 100644 --- a/drivers/cpuidle/cpuidle-calxeda.c +++ b/drivers/cpuidle/cpuidle-calxeda.c | |||
| @@ -1,7 +1,7 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * Copyright 2012 Calxeda, Inc. | 2 | * Copyright 2012 Calxeda, Inc. |
| 3 | * | 3 | * |
| 4 | * Based on arch/arm/plat-mxc/cpuidle.c: | 4 | * Based on arch/arm/plat-mxc/cpuidle.c: #v3.7 |
| 5 | * Copyright 2012 Freescale Semiconductor, Inc. | 5 | * Copyright 2012 Freescale Semiconductor, Inc. |
| 6 | * Copyright 2012 Linaro Ltd. | 6 | * Copyright 2012 Linaro Ltd. |
| 7 | * | 7 | * |
| @@ -16,6 +16,8 @@ | |||
| 16 | * | 16 | * |
| 17 | * You should have received a copy of the GNU General Public License along with | 17 | * You should have received a copy of the GNU General Public License along with |
| 18 | * this program. If not, see <http://www.gnu.org/licenses/>. | 18 | * this program. If not, see <http://www.gnu.org/licenses/>. |
| 19 | * | ||
| 20 | * Maintainer: Rob Herring <rob.herring@calxeda.com> | ||
| 19 | */ | 21 | */ |
| 20 | 22 | ||
| 21 | #include <linux/cpuidle.h> | 23 | #include <linux/cpuidle.h> |
| @@ -35,8 +37,6 @@ | |||
| 35 | extern void highbank_set_cpu_jump(int cpu, void *jump_addr); | 37 | extern void highbank_set_cpu_jump(int cpu, void *jump_addr); |
| 36 | extern void *scu_base_addr; | 38 | extern void *scu_base_addr; |
| 37 | 39 | ||
| 38 | static struct cpuidle_device __percpu *calxeda_idle_cpuidle_devices; | ||
| 39 | |||
| 40 | static inline unsigned int get_auxcr(void) | 40 | static inline unsigned int get_auxcr(void) |
| 41 | { | 41 | { |
| 42 | unsigned int val; | 42 | unsigned int val; |
| @@ -85,22 +85,8 @@ static int calxeda_pwrdown_idle(struct cpuidle_device *dev, | |||
| 85 | return index; | 85 | return index; |
| 86 | } | 86 | } |
| 87 | 87 | ||
| 88 | static void calxeda_idle_cpuidle_devices_uninit(void) | ||
| 89 | { | ||
| 90 | int i; | ||
| 91 | struct cpuidle_device *dev; | ||
| 92 | |||
| 93 | for_each_possible_cpu(i) { | ||
| 94 | dev = per_cpu_ptr(calxeda_idle_cpuidle_devices, i); | ||
| 95 | cpuidle_unregister_device(dev); | ||
| 96 | } | ||
| 97 | |||
| 98 | free_percpu(calxeda_idle_cpuidle_devices); | ||
| 99 | } | ||
| 100 | |||
| 101 | static struct cpuidle_driver calxeda_idle_driver = { | 88 | static struct cpuidle_driver calxeda_idle_driver = { |
| 102 | .name = "calxeda_idle", | 89 | .name = "calxeda_idle", |
| 103 | .en_core_tk_irqen = 1, | ||
| 104 | .states = { | 90 | .states = { |
| 105 | ARM_CPUIDLE_WFI_STATE, | 91 | ARM_CPUIDLE_WFI_STATE, |
| 106 | { | 92 | { |
| @@ -118,44 +104,9 @@ static struct cpuidle_driver calxeda_idle_driver = { | |||
| 118 | 104 | ||
| 119 | static int __init calxeda_cpuidle_init(void) | 105 | static int __init calxeda_cpuidle_init(void) |
| 120 | { | 106 | { |
| 121 | int cpu_id; | ||
| 122 | int ret; | ||
| 123 | struct cpuidle_device *dev; | ||
| 124 | struct cpuidle_driver *drv = &calxeda_idle_driver; | ||
| 125 | |||
| 126 | if (!of_machine_is_compatible("calxeda,highbank")) | 107 | if (!of_machine_is_compatible("calxeda,highbank")) |
| 127 | return -ENODEV; | 108 | return -ENODEV; |
| 128 | 109 | ||
| 129 | ret = cpuidle_register_driver(drv); | 110 | return cpuidle_register(&calxeda_idle_driver, NULL); |
| 130 | if (ret) | ||
| 131 | return ret; | ||
| 132 | |||
| 133 | calxeda_idle_cpuidle_devices = alloc_percpu(struct cpuidle_device); | ||
| 134 | if (calxeda_idle_cpuidle_devices == NULL) { | ||
| 135 | ret = -ENOMEM; | ||
| 136 | goto unregister_drv; | ||
| 137 | } | ||
| 138 | |||
| 139 | /* initialize state data for each cpuidle_device */ | ||
| 140 | for_each_possible_cpu(cpu_id) { | ||
| 141 | dev = per_cpu_ptr(calxeda_idle_cpuidle_devices, cpu_id); | ||
| 142 | dev->cpu = cpu_id; | ||
| 143 | dev->state_count = drv->state_count; | ||
| 144 | |||
| 145 | ret = cpuidle_register_device(dev); | ||
| 146 | if (ret) { | ||
| 147 | pr_err("Failed to register cpu %u, error: %d\n", | ||
| 148 | cpu_id, ret); | ||
| 149 | goto uninit; | ||
| 150 | } | ||
| 151 | } | ||
| 152 | |||
| 153 | return 0; | ||
| 154 | |||
| 155 | uninit: | ||
| 156 | calxeda_idle_cpuidle_devices_uninit(); | ||
| 157 | unregister_drv: | ||
| 158 | cpuidle_unregister_driver(drv); | ||
| 159 | return ret; | ||
| 160 | } | 111 | } |
| 161 | module_init(calxeda_cpuidle_init); | 112 | module_init(calxeda_cpuidle_init); |
diff --git a/drivers/cpuidle/cpuidle-kirkwood.c b/drivers/cpuidle/cpuidle-kirkwood.c index 670aa1e55cd6..521b0a7fdd89 100644 --- a/drivers/cpuidle/cpuidle-kirkwood.c +++ b/drivers/cpuidle/cpuidle-kirkwood.c | |||
| @@ -1,6 +1,4 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * arch/arm/mach-kirkwood/cpuidle.c | ||
| 3 | * | ||
| 4 | * CPU idle Marvell Kirkwood SoCs | 2 | * CPU idle Marvell Kirkwood SoCs |
| 5 | * | 3 | * |
| 6 | * This file is licensed under the terms of the GNU General Public | 4 | * This file is licensed under the terms of the GNU General Public |
| @@ -11,6 +9,9 @@ | |||
| 11 | * to implement two idle states - | 9 | * to implement two idle states - |
| 12 | * #1 wait-for-interrupt | 10 | * #1 wait-for-interrupt |
| 13 | * #2 wait-for-interrupt and DDR self refresh | 11 | * #2 wait-for-interrupt and DDR self refresh |
| 12 | * | ||
| 13 | * Maintainer: Jason Cooper <jason@lakedaemon.net> | ||
| 14 | * Maintainer: Andrew Lunn <andrew@lunn.ch> | ||
| 14 | */ | 15 | */ |
| 15 | 16 | ||
| 16 | #include <linux/kernel.h> | 17 | #include <linux/kernel.h> |
| @@ -41,7 +42,6 @@ static int kirkwood_enter_idle(struct cpuidle_device *dev, | |||
| 41 | static struct cpuidle_driver kirkwood_idle_driver = { | 42 | static struct cpuidle_driver kirkwood_idle_driver = { |
| 42 | .name = "kirkwood_idle", | 43 | .name = "kirkwood_idle", |
| 43 | .owner = THIS_MODULE, | 44 | .owner = THIS_MODULE, |
| 44 | .en_core_tk_irqen = 1, | ||
| 45 | .states[0] = ARM_CPUIDLE_WFI_STATE, | 45 | .states[0] = ARM_CPUIDLE_WFI_STATE, |
| 46 | .states[1] = { | 46 | .states[1] = { |
| 47 | .enter = kirkwood_enter_idle, | 47 | .enter = kirkwood_enter_idle, |
| @@ -53,9 +53,6 @@ static struct cpuidle_driver kirkwood_idle_driver = { | |||
| 53 | }, | 53 | }, |
| 54 | .state_count = KIRKWOOD_MAX_STATES, | 54 | .state_count = KIRKWOOD_MAX_STATES, |
| 55 | }; | 55 | }; |
| 56 | static struct cpuidle_device *device; | ||
| 57 | |||
| 58 | static DEFINE_PER_CPU(struct cpuidle_device, kirkwood_cpuidle_device); | ||
| 59 | 56 | ||
| 60 | /* Initialize CPU idle by registering the idle states */ | 57 | /* Initialize CPU idle by registering the idle states */ |
| 61 | static int kirkwood_cpuidle_probe(struct platform_device *pdev) | 58 | static int kirkwood_cpuidle_probe(struct platform_device *pdev) |
| @@ -66,26 +63,16 @@ static int kirkwood_cpuidle_probe(struct platform_device *pdev) | |||
| 66 | if (res == NULL) | 63 | if (res == NULL) |
| 67 | return -EINVAL; | 64 | return -EINVAL; |
| 68 | 65 | ||
| 69 | ddr_operation_base = devm_request_and_ioremap(&pdev->dev, res); | 66 | ddr_operation_base = devm_ioremap_resource(&pdev->dev, res); |
| 70 | if (!ddr_operation_base) | 67 | if (IS_ERR(ddr_operation_base)) |
| 71 | return -EADDRNOTAVAIL; | 68 | return PTR_ERR(ddr_operation_base); |
| 72 | 69 | ||
| 73 | device = &per_cpu(kirkwood_cpuidle_device, smp_processor_id()); | 70 | return cpuidle_register(&kirkwood_idle_driver, NULL); |
| 74 | device->state_count = KIRKWOOD_MAX_STATES; | ||
| 75 | |||
| 76 | cpuidle_register_driver(&kirkwood_idle_driver); | ||
| 77 | if (cpuidle_register_device(device)) { | ||
| 78 | pr_err("kirkwood_init_cpuidle: Failed registering\n"); | ||
| 79 | return -EIO; | ||
| 80 | } | ||
| 81 | return 0; | ||
| 82 | } | 71 | } |
| 83 | 72 | ||
| 84 | int kirkwood_cpuidle_remove(struct platform_device *pdev) | 73 | int kirkwood_cpuidle_remove(struct platform_device *pdev) |
| 85 | { | 74 | { |
| 86 | cpuidle_unregister_device(device); | 75 | cpuidle_unregister(&kirkwood_idle_driver); |
| 87 | cpuidle_unregister_driver(&kirkwood_idle_driver); | ||
| 88 | |||
| 89 | return 0; | 76 | return 0; |
| 90 | } | 77 | } |
| 91 | 78 | ||
diff --git a/drivers/cpuidle/cpuidle.c b/drivers/cpuidle/cpuidle.c index eba69290e074..c3a93fece819 100644 --- a/drivers/cpuidle/cpuidle.c +++ b/drivers/cpuidle/cpuidle.c | |||
| @@ -8,6 +8,7 @@ | |||
| 8 | * This code is licenced under the GPL. | 8 | * This code is licenced under the GPL. |
| 9 | */ | 9 | */ |
| 10 | 10 | ||
| 11 | #include <linux/clockchips.h> | ||
| 11 | #include <linux/kernel.h> | 12 | #include <linux/kernel.h> |
| 12 | #include <linux/mutex.h> | 13 | #include <linux/mutex.h> |
| 13 | #include <linux/sched.h> | 14 | #include <linux/sched.h> |
| @@ -23,6 +24,7 @@ | |||
| 23 | #include "cpuidle.h" | 24 | #include "cpuidle.h" |
| 24 | 25 | ||
| 25 | DEFINE_PER_CPU(struct cpuidle_device *, cpuidle_devices); | 26 | DEFINE_PER_CPU(struct cpuidle_device *, cpuidle_devices); |
| 27 | DEFINE_PER_CPU(struct cpuidle_device, cpuidle_dev); | ||
| 26 | 28 | ||
| 27 | DEFINE_MUTEX(cpuidle_lock); | 29 | DEFINE_MUTEX(cpuidle_lock); |
| 28 | LIST_HEAD(cpuidle_detected_devices); | 30 | LIST_HEAD(cpuidle_detected_devices); |
| @@ -42,24 +44,6 @@ void disable_cpuidle(void) | |||
| 42 | 44 | ||
| 43 | static int __cpuidle_register_device(struct cpuidle_device *dev); | 45 | static int __cpuidle_register_device(struct cpuidle_device *dev); |
| 44 | 46 | ||
| 45 | static inline int cpuidle_enter(struct cpuidle_device *dev, | ||
| 46 | struct cpuidle_driver *drv, int index) | ||
| 47 | { | ||
| 48 | struct cpuidle_state *target_state = &drv->states[index]; | ||
| 49 | return target_state->enter(dev, drv, index); | ||
| 50 | } | ||
| 51 | |||
| 52 | static inline int cpuidle_enter_tk(struct cpuidle_device *dev, | ||
| 53 | struct cpuidle_driver *drv, int index) | ||
| 54 | { | ||
| 55 | return cpuidle_wrap_enter(dev, drv, index, cpuidle_enter); | ||
| 56 | } | ||
| 57 | |||
| 58 | typedef int (*cpuidle_enter_t)(struct cpuidle_device *dev, | ||
| 59 | struct cpuidle_driver *drv, int index); | ||
| 60 | |||
| 61 | static cpuidle_enter_t cpuidle_enter_ops; | ||
| 62 | |||
| 63 | /** | 47 | /** |
| 64 | * cpuidle_play_dead - cpu off-lining | 48 | * cpuidle_play_dead - cpu off-lining |
| 65 | * | 49 | * |
| @@ -89,11 +73,27 @@ int cpuidle_play_dead(void) | |||
| 89 | * @next_state: index into drv->states of the state to enter | 73 | * @next_state: index into drv->states of the state to enter |
| 90 | */ | 74 | */ |
| 91 | int cpuidle_enter_state(struct cpuidle_device *dev, struct cpuidle_driver *drv, | 75 | int cpuidle_enter_state(struct cpuidle_device *dev, struct cpuidle_driver *drv, |
| 92 | int next_state) | 76 | int index) |
| 93 | { | 77 | { |
| 94 | int entered_state; | 78 | int entered_state; |
| 95 | 79 | ||
| 96 | entered_state = cpuidle_enter_ops(dev, drv, next_state); | 80 | struct cpuidle_state *target_state = &drv->states[index]; |
| 81 | ktime_t time_start, time_end; | ||
| 82 | s64 diff; | ||
| 83 | |||
| 84 | time_start = ktime_get(); | ||
| 85 | |||
| 86 | entered_state = target_state->enter(dev, drv, index); | ||
| 87 | |||
| 88 | time_end = ktime_get(); | ||
| 89 | |||
| 90 | local_irq_enable(); | ||
| 91 | |||
| 92 | diff = ktime_to_us(ktime_sub(time_end, time_start)); | ||
| 93 | if (diff > INT_MAX) | ||
| 94 | diff = INT_MAX; | ||
| 95 | |||
| 96 | dev->last_residency = (int) diff; | ||
| 97 | 97 | ||
| 98 | if (entered_state >= 0) { | 98 | if (entered_state >= 0) { |
| 99 | /* Update cpuidle counters */ | 99 | /* Update cpuidle counters */ |
| @@ -146,12 +146,20 @@ int cpuidle_idle_call(void) | |||
| 146 | 146 | ||
| 147 | trace_cpu_idle_rcuidle(next_state, dev->cpu); | 147 | trace_cpu_idle_rcuidle(next_state, dev->cpu); |
| 148 | 148 | ||
| 149 | if (drv->states[next_state].flags & CPUIDLE_FLAG_TIMER_STOP) | ||
| 150 | clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_ENTER, | ||
| 151 | &dev->cpu); | ||
| 152 | |||
| 149 | if (cpuidle_state_is_coupled(dev, drv, next_state)) | 153 | if (cpuidle_state_is_coupled(dev, drv, next_state)) |
| 150 | entered_state = cpuidle_enter_state_coupled(dev, drv, | 154 | entered_state = cpuidle_enter_state_coupled(dev, drv, |
| 151 | next_state); | 155 | next_state); |
| 152 | else | 156 | else |
| 153 | entered_state = cpuidle_enter_state(dev, drv, next_state); | 157 | entered_state = cpuidle_enter_state(dev, drv, next_state); |
| 154 | 158 | ||
| 159 | if (drv->states[next_state].flags & CPUIDLE_FLAG_TIMER_STOP) | ||
| 160 | clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_EXIT, | ||
| 161 | &dev->cpu); | ||
| 162 | |||
| 155 | trace_cpu_idle_rcuidle(PWR_EVENT_EXIT, dev->cpu); | 163 | trace_cpu_idle_rcuidle(PWR_EVENT_EXIT, dev->cpu); |
| 156 | 164 | ||
| 157 | /* give the governor an opportunity to reflect on the outcome */ | 165 | /* give the governor an opportunity to reflect on the outcome */ |
| @@ -222,37 +230,6 @@ void cpuidle_resume(void) | |||
| 222 | mutex_unlock(&cpuidle_lock); | 230 | mutex_unlock(&cpuidle_lock); |
| 223 | } | 231 | } |
| 224 | 232 | ||
| 225 | /** | ||
| 226 | * cpuidle_wrap_enter - performs timekeeping and irqen around enter function | ||
| 227 | * @dev: pointer to a valid cpuidle_device object | ||
| 228 | * @drv: pointer to a valid cpuidle_driver object | ||
| 229 | * @index: index of the target cpuidle state. | ||
| 230 | */ | ||
| 231 | int cpuidle_wrap_enter(struct cpuidle_device *dev, | ||
| 232 | struct cpuidle_driver *drv, int index, | ||
| 233 | int (*enter)(struct cpuidle_device *dev, | ||
| 234 | struct cpuidle_driver *drv, int index)) | ||
| 235 | { | ||
| 236 | ktime_t time_start, time_end; | ||
| 237 | s64 diff; | ||
| 238 | |||
| 239 | time_start = ktime_get(); | ||
| 240 | |||
| 241 | index = enter(dev, drv, index); | ||
| 242 | |||
| 243 | time_end = ktime_get(); | ||
| 244 | |||
| 245 | local_irq_enable(); | ||
| 246 | |||
| 247 | diff = ktime_to_us(ktime_sub(time_end, time_start)); | ||
| 248 | if (diff > INT_MAX) | ||
| 249 | diff = INT_MAX; | ||
| 250 | |||
| 251 | dev->last_residency = (int) diff; | ||
| 252 | |||
| 253 | return index; | ||
| 254 | } | ||
| 255 | |||
| 256 | #ifdef CONFIG_ARCH_HAS_CPU_RELAX | 233 | #ifdef CONFIG_ARCH_HAS_CPU_RELAX |
| 257 | static int poll_idle(struct cpuidle_device *dev, | 234 | static int poll_idle(struct cpuidle_device *dev, |
| 258 | struct cpuidle_driver *drv, int index) | 235 | struct cpuidle_driver *drv, int index) |
| @@ -324,9 +301,6 @@ int cpuidle_enable_device(struct cpuidle_device *dev) | |||
| 324 | return ret; | 301 | return ret; |
| 325 | } | 302 | } |
| 326 | 303 | ||
| 327 | cpuidle_enter_ops = drv->en_core_tk_irqen ? | ||
| 328 | cpuidle_enter_tk : cpuidle_enter; | ||
| 329 | |||
| 330 | poll_idle_init(drv); | 304 | poll_idle_init(drv); |
| 331 | 305 | ||
| 332 | ret = cpuidle_add_device_sysfs(dev); | 306 | ret = cpuidle_add_device_sysfs(dev); |
| @@ -480,6 +454,77 @@ void cpuidle_unregister_device(struct cpuidle_device *dev) | |||
| 480 | 454 | ||
| 481 | EXPORT_SYMBOL_GPL(cpuidle_unregister_device); | 455 | EXPORT_SYMBOL_GPL(cpuidle_unregister_device); |
| 482 | 456 | ||
| 457 | /** | ||
| 458 | * cpuidle_unregister: unregister a driver and the devices. This function | ||
| 459 | * can be used only if the driver has been previously registered through | ||
| 460 | * the cpuidle_register function. | ||
| 461 | * | ||
| 462 | * @drv: a valid pointer to a struct cpuidle_driver | ||
| 463 | */ | ||
| 464 | void cpuidle_unregister(struct cpuidle_driver *drv) | ||
| 465 | { | ||
| 466 | int cpu; | ||
| 467 | struct cpuidle_device *device; | ||
| 468 | |||
| 469 | for_each_possible_cpu(cpu) { | ||
| 470 | device = &per_cpu(cpuidle_dev, cpu); | ||
| 471 | cpuidle_unregister_device(device); | ||
| 472 | } | ||
| 473 | |||
| 474 | cpuidle_unregister_driver(drv); | ||
| 475 | } | ||
| 476 | EXPORT_SYMBOL_GPL(cpuidle_unregister); | ||
| 477 | |||
| 478 | /** | ||
| 479 | * cpuidle_register: registers the driver and the cpu devices with the | ||
| 480 | * coupled_cpus passed as parameter. This function is used for all common | ||
| 481 | * initialization pattern there are in the arch specific drivers. The | ||
| 482 | * devices is globally defined in this file. | ||
| 483 | * | ||
| 484 | * @drv : a valid pointer to a struct cpuidle_driver | ||
| 485 | * @coupled_cpus: a cpumask for the coupled states | ||
| 486 | * | ||
| 487 | * Returns 0 on success, < 0 otherwise | ||
| 488 | */ | ||
| 489 | int cpuidle_register(struct cpuidle_driver *drv, | ||
| 490 | const struct cpumask *const coupled_cpus) | ||
| 491 | { | ||
| 492 | int ret, cpu; | ||
| 493 | struct cpuidle_device *device; | ||
| 494 | |||
| 495 | ret = cpuidle_register_driver(drv); | ||
| 496 | if (ret) { | ||
| 497 | pr_err("failed to register cpuidle driver\n"); | ||
| 498 | return ret; | ||
| 499 | } | ||
| 500 | |||
| 501 | for_each_possible_cpu(cpu) { | ||
| 502 | device = &per_cpu(cpuidle_dev, cpu); | ||
| 503 | device->cpu = cpu; | ||
| 504 | |||
| 505 | #ifdef CONFIG_ARCH_NEEDS_CPU_IDLE_COUPLED | ||
| 506 | /* | ||
| 507 | * On multiplatform for ARM, the coupled idle states could | ||
| 508 | * enabled in the kernel even if the cpuidle driver does not | ||
| 509 | * use it. Note, coupled_cpus is a struct copy. | ||
| 510 | */ | ||
| 511 | if (coupled_cpus) | ||
| 512 | device->coupled_cpus = *coupled_cpus; | ||
| 513 | #endif | ||
| 514 | ret = cpuidle_register_device(device); | ||
| 515 | if (!ret) | ||
| 516 | continue; | ||
| 517 | |||
| 518 | pr_err("Failed to register cpuidle device for cpu%d\n", cpu); | ||
| 519 | |||
| 520 | cpuidle_unregister(drv); | ||
| 521 | break; | ||
| 522 | } | ||
| 523 | |||
| 524 | return ret; | ||
| 525 | } | ||
| 526 | EXPORT_SYMBOL_GPL(cpuidle_register); | ||
| 527 | |||
| 483 | #ifdef CONFIG_SMP | 528 | #ifdef CONFIG_SMP |
| 484 | 529 | ||
| 485 | static void smp_callback(void *v) | 530 | static void smp_callback(void *v) |
diff --git a/drivers/cpuidle/driver.c b/drivers/cpuidle/driver.c index 422c7b69ba7c..8dfaaae94444 100644 --- a/drivers/cpuidle/driver.c +++ b/drivers/cpuidle/driver.c | |||
| @@ -11,6 +11,8 @@ | |||
| 11 | #include <linux/mutex.h> | 11 | #include <linux/mutex.h> |
| 12 | #include <linux/module.h> | 12 | #include <linux/module.h> |
| 13 | #include <linux/cpuidle.h> | 13 | #include <linux/cpuidle.h> |
| 14 | #include <linux/cpumask.h> | ||
| 15 | #include <linux/clockchips.h> | ||
| 14 | 16 | ||
| 15 | #include "cpuidle.h" | 17 | #include "cpuidle.h" |
| 16 | 18 | ||
| @@ -19,9 +21,28 @@ DEFINE_SPINLOCK(cpuidle_driver_lock); | |||
| 19 | static void __cpuidle_set_cpu_driver(struct cpuidle_driver *drv, int cpu); | 21 | static void __cpuidle_set_cpu_driver(struct cpuidle_driver *drv, int cpu); |
| 20 | static struct cpuidle_driver * __cpuidle_get_cpu_driver(int cpu); | 22 | static struct cpuidle_driver * __cpuidle_get_cpu_driver(int cpu); |
| 21 | 23 | ||
| 22 | static void __cpuidle_driver_init(struct cpuidle_driver *drv) | 24 | static void cpuidle_setup_broadcast_timer(void *arg) |
| 23 | { | 25 | { |
| 26 | int cpu = smp_processor_id(); | ||
| 27 | clockevents_notify((long)(arg), &cpu); | ||
| 28 | } | ||
| 29 | |||
| 30 | static void __cpuidle_driver_init(struct cpuidle_driver *drv, int cpu) | ||
| 31 | { | ||
| 32 | int i; | ||
| 33 | |||
| 24 | drv->refcnt = 0; | 34 | drv->refcnt = 0; |
| 35 | |||
| 36 | for (i = drv->state_count - 1; i >= 0 ; i--) { | ||
| 37 | |||
| 38 | if (!(drv->states[i].flags & CPUIDLE_FLAG_TIMER_STOP)) | ||
| 39 | continue; | ||
| 40 | |||
| 41 | drv->bctimer = 1; | ||
| 42 | on_each_cpu_mask(get_cpu_mask(cpu), cpuidle_setup_broadcast_timer, | ||
| 43 | (void *)CLOCK_EVT_NOTIFY_BROADCAST_ON, 1); | ||
| 44 | break; | ||
| 45 | } | ||
| 25 | } | 46 | } |
| 26 | 47 | ||
| 27 | static int __cpuidle_register_driver(struct cpuidle_driver *drv, int cpu) | 48 | static int __cpuidle_register_driver(struct cpuidle_driver *drv, int cpu) |
| @@ -35,7 +56,7 @@ static int __cpuidle_register_driver(struct cpuidle_driver *drv, int cpu) | |||
| 35 | if (__cpuidle_get_cpu_driver(cpu)) | 56 | if (__cpuidle_get_cpu_driver(cpu)) |
| 36 | return -EBUSY; | 57 | return -EBUSY; |
| 37 | 58 | ||
| 38 | __cpuidle_driver_init(drv); | 59 | __cpuidle_driver_init(drv, cpu); |
| 39 | 60 | ||
| 40 | __cpuidle_set_cpu_driver(drv, cpu); | 61 | __cpuidle_set_cpu_driver(drv, cpu); |
| 41 | 62 | ||
| @@ -49,6 +70,12 @@ static void __cpuidle_unregister_driver(struct cpuidle_driver *drv, int cpu) | |||
| 49 | 70 | ||
| 50 | if (!WARN_ON(drv->refcnt > 0)) | 71 | if (!WARN_ON(drv->refcnt > 0)) |
| 51 | __cpuidle_set_cpu_driver(NULL, cpu); | 72 | __cpuidle_set_cpu_driver(NULL, cpu); |
| 73 | |||
| 74 | if (drv->bctimer) { | ||
| 75 | drv->bctimer = 0; | ||
| 76 | on_each_cpu_mask(get_cpu_mask(cpu), cpuidle_setup_broadcast_timer, | ||
| 77 | (void *)CLOCK_EVT_NOTIFY_BROADCAST_OFF, 1); | ||
| 78 | } | ||
| 52 | } | 79 | } |
| 53 | 80 | ||
| 54 | #ifdef CONFIG_CPU_IDLE_MULTIPLE_DRIVERS | 81 | #ifdef CONFIG_CPU_IDLE_MULTIPLE_DRIVERS |
diff --git a/drivers/idle/intel_idle.c b/drivers/idle/intel_idle.c index 1a38dd7dfe4e..0e8fab1913df 100644 --- a/drivers/idle/intel_idle.c +++ b/drivers/idle/intel_idle.c | |||
| @@ -71,7 +71,6 @@ | |||
| 71 | static struct cpuidle_driver intel_idle_driver = { | 71 | static struct cpuidle_driver intel_idle_driver = { |
| 72 | .name = "intel_idle", | 72 | .name = "intel_idle", |
| 73 | .owner = THIS_MODULE, | 73 | .owner = THIS_MODULE, |
| 74 | .en_core_tk_irqen = 1, | ||
| 75 | }; | 74 | }; |
| 76 | /* intel_idle.max_cstate=0 disables driver */ | 75 | /* intel_idle.max_cstate=0 disables driver */ |
| 77 | static int max_cstate = CPUIDLE_STATE_MAX - 1; | 76 | static int max_cstate = CPUIDLE_STATE_MAX - 1; |
| @@ -339,7 +338,6 @@ static int intel_idle(struct cpuidle_device *dev, | |||
| 339 | if (!(lapic_timer_reliable_states & (1 << (cstate)))) | 338 | if (!(lapic_timer_reliable_states & (1 << (cstate)))) |
| 340 | clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_ENTER, &cpu); | 339 | clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_ENTER, &cpu); |
| 341 | 340 | ||
| 342 | stop_critical_timings(); | ||
| 343 | if (!need_resched()) { | 341 | if (!need_resched()) { |
| 344 | 342 | ||
| 345 | __monitor((void *)¤t_thread_info()->flags, 0, 0); | 343 | __monitor((void *)¤t_thread_info()->flags, 0, 0); |
| @@ -348,8 +346,6 @@ static int intel_idle(struct cpuidle_device *dev, | |||
| 348 | __mwait(eax, ecx); | 346 | __mwait(eax, ecx); |
| 349 | } | 347 | } |
| 350 | 348 | ||
| 351 | start_critical_timings(); | ||
| 352 | |||
| 353 | if (!(lapic_timer_reliable_states & (1 << (cstate)))) | 349 | if (!(lapic_timer_reliable_states & (1 << (cstate)))) |
| 354 | clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_EXIT, &cpu); | 350 | clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_EXIT, &cpu); |
| 355 | 351 | ||
diff --git a/include/linux/clockchips.h b/include/linux/clockchips.h index 66346521cb65..f9fd93758333 100644 --- a/include/linux/clockchips.h +++ b/include/linux/clockchips.h | |||
| @@ -8,6 +8,20 @@ | |||
| 8 | #ifndef _LINUX_CLOCKCHIPS_H | 8 | #ifndef _LINUX_CLOCKCHIPS_H |
| 9 | #define _LINUX_CLOCKCHIPS_H | 9 | #define _LINUX_CLOCKCHIPS_H |
| 10 | 10 | ||
| 11 | /* Clock event notification values */ | ||
| 12 | enum clock_event_nofitiers { | ||
| 13 | CLOCK_EVT_NOTIFY_ADD, | ||
| 14 | CLOCK_EVT_NOTIFY_BROADCAST_ON, | ||
| 15 | CLOCK_EVT_NOTIFY_BROADCAST_OFF, | ||
| 16 | CLOCK_EVT_NOTIFY_BROADCAST_FORCE, | ||
| 17 | CLOCK_EVT_NOTIFY_BROADCAST_ENTER, | ||
| 18 | CLOCK_EVT_NOTIFY_BROADCAST_EXIT, | ||
| 19 | CLOCK_EVT_NOTIFY_SUSPEND, | ||
| 20 | CLOCK_EVT_NOTIFY_RESUME, | ||
| 21 | CLOCK_EVT_NOTIFY_CPU_DYING, | ||
| 22 | CLOCK_EVT_NOTIFY_CPU_DEAD, | ||
| 23 | }; | ||
| 24 | |||
| 11 | #ifdef CONFIG_GENERIC_CLOCKEVENTS_BUILD | 25 | #ifdef CONFIG_GENERIC_CLOCKEVENTS_BUILD |
| 12 | 26 | ||
| 13 | #include <linux/clocksource.h> | 27 | #include <linux/clocksource.h> |
| @@ -26,20 +40,6 @@ enum clock_event_mode { | |||
| 26 | CLOCK_EVT_MODE_RESUME, | 40 | CLOCK_EVT_MODE_RESUME, |
| 27 | }; | 41 | }; |
| 28 | 42 | ||
| 29 | /* Clock event notification values */ | ||
| 30 | enum clock_event_nofitiers { | ||
| 31 | CLOCK_EVT_NOTIFY_ADD, | ||
| 32 | CLOCK_EVT_NOTIFY_BROADCAST_ON, | ||
| 33 | CLOCK_EVT_NOTIFY_BROADCAST_OFF, | ||
| 34 | CLOCK_EVT_NOTIFY_BROADCAST_FORCE, | ||
| 35 | CLOCK_EVT_NOTIFY_BROADCAST_ENTER, | ||
| 36 | CLOCK_EVT_NOTIFY_BROADCAST_EXIT, | ||
| 37 | CLOCK_EVT_NOTIFY_SUSPEND, | ||
| 38 | CLOCK_EVT_NOTIFY_RESUME, | ||
| 39 | CLOCK_EVT_NOTIFY_CPU_DYING, | ||
| 40 | CLOCK_EVT_NOTIFY_CPU_DEAD, | ||
| 41 | }; | ||
| 42 | |||
| 43 | /* | 43 | /* |
| 44 | * Clock event features | 44 | * Clock event features |
| 45 | */ | 45 | */ |
| @@ -173,7 +173,7 @@ extern int tick_receive_broadcast(void); | |||
| 173 | #ifdef CONFIG_GENERIC_CLOCKEVENTS | 173 | #ifdef CONFIG_GENERIC_CLOCKEVENTS |
| 174 | extern void clockevents_notify(unsigned long reason, void *arg); | 174 | extern void clockevents_notify(unsigned long reason, void *arg); |
| 175 | #else | 175 | #else |
| 176 | # define clockevents_notify(reason, arg) do { } while (0) | 176 | static inline void clockevents_notify(unsigned long reason, void *arg) {} |
| 177 | #endif | 177 | #endif |
| 178 | 178 | ||
| 179 | #else /* CONFIG_GENERIC_CLOCKEVENTS_BUILD */ | 179 | #else /* CONFIG_GENERIC_CLOCKEVENTS_BUILD */ |
| @@ -181,7 +181,7 @@ extern void clockevents_notify(unsigned long reason, void *arg); | |||
| 181 | static inline void clockevents_suspend(void) {} | 181 | static inline void clockevents_suspend(void) {} |
| 182 | static inline void clockevents_resume(void) {} | 182 | static inline void clockevents_resume(void) {} |
| 183 | 183 | ||
| 184 | #define clockevents_notify(reason, arg) do { } while (0) | 184 | static inline void clockevents_notify(unsigned long reason, void *arg) {} |
| 185 | 185 | ||
| 186 | #endif | 186 | #endif |
| 187 | 187 | ||
diff --git a/include/linux/cpuidle.h b/include/linux/cpuidle.h index 480c14dc1ddd..3c86faa59798 100644 --- a/include/linux/cpuidle.h +++ b/include/linux/cpuidle.h | |||
| @@ -57,6 +57,7 @@ struct cpuidle_state { | |||
| 57 | /* Idle State Flags */ | 57 | /* Idle State Flags */ |
| 58 | #define CPUIDLE_FLAG_TIME_VALID (0x01) /* is residency time measurable? */ | 58 | #define CPUIDLE_FLAG_TIME_VALID (0x01) /* is residency time measurable? */ |
| 59 | #define CPUIDLE_FLAG_COUPLED (0x02) /* state applies to multiple cpus */ | 59 | #define CPUIDLE_FLAG_COUPLED (0x02) /* state applies to multiple cpus */ |
| 60 | #define CPUIDLE_FLAG_TIMER_STOP (0x04) /* timer is stopped on this state */ | ||
| 60 | 61 | ||
| 61 | #define CPUIDLE_DRIVER_FLAGS_MASK (0xFFFF0000) | 62 | #define CPUIDLE_DRIVER_FLAGS_MASK (0xFFFF0000) |
| 62 | 63 | ||
| @@ -104,8 +105,8 @@ struct cpuidle_driver { | |||
| 104 | struct module *owner; | 105 | struct module *owner; |
| 105 | int refcnt; | 106 | int refcnt; |
| 106 | 107 | ||
| 107 | /* set to 1 to use the core cpuidle time keeping (for all states). */ | 108 | /* used by the cpuidle framework to setup the broadcast timer */ |
| 108 | unsigned int en_core_tk_irqen:1; | 109 | unsigned int bctimer:1; |
| 109 | /* states array must be ordered in decreasing power consumption */ | 110 | /* states array must be ordered in decreasing power consumption */ |
| 110 | struct cpuidle_state states[CPUIDLE_STATE_MAX]; | 111 | struct cpuidle_state states[CPUIDLE_STATE_MAX]; |
| 111 | int state_count; | 112 | int state_count; |
| @@ -122,17 +123,15 @@ extern void cpuidle_driver_unref(void); | |||
| 122 | extern void cpuidle_unregister_driver(struct cpuidle_driver *drv); | 123 | extern void cpuidle_unregister_driver(struct cpuidle_driver *drv); |
| 123 | extern int cpuidle_register_device(struct cpuidle_device *dev); | 124 | extern int cpuidle_register_device(struct cpuidle_device *dev); |
| 124 | extern void cpuidle_unregister_device(struct cpuidle_device *dev); | 125 | extern void cpuidle_unregister_device(struct cpuidle_device *dev); |
| 125 | 126 | extern int cpuidle_register(struct cpuidle_driver *drv, | |
| 127 | const struct cpumask *const coupled_cpus); | ||
| 128 | extern void cpuidle_unregister(struct cpuidle_driver *drv); | ||
| 126 | extern void cpuidle_pause_and_lock(void); | 129 | extern void cpuidle_pause_and_lock(void); |
| 127 | extern void cpuidle_resume_and_unlock(void); | 130 | extern void cpuidle_resume_and_unlock(void); |
| 128 | extern void cpuidle_pause(void); | 131 | extern void cpuidle_pause(void); |
| 129 | extern void cpuidle_resume(void); | 132 | extern void cpuidle_resume(void); |
| 130 | extern int cpuidle_enable_device(struct cpuidle_device *dev); | 133 | extern int cpuidle_enable_device(struct cpuidle_device *dev); |
| 131 | extern void cpuidle_disable_device(struct cpuidle_device *dev); | 134 | extern void cpuidle_disable_device(struct cpuidle_device *dev); |
| 132 | extern int cpuidle_wrap_enter(struct cpuidle_device *dev, | ||
| 133 | struct cpuidle_driver *drv, int index, | ||
| 134 | int (*enter)(struct cpuidle_device *dev, | ||
| 135 | struct cpuidle_driver *drv, int index)); | ||
| 136 | extern int cpuidle_play_dead(void); | 135 | extern int cpuidle_play_dead(void); |
| 137 | 136 | ||
| 138 | extern struct cpuidle_driver *cpuidle_get_cpu_driver(struct cpuidle_device *dev); | 137 | extern struct cpuidle_driver *cpuidle_get_cpu_driver(struct cpuidle_device *dev); |
| @@ -151,7 +150,10 @@ static inline void cpuidle_unregister_driver(struct cpuidle_driver *drv) { } | |||
| 151 | static inline int cpuidle_register_device(struct cpuidle_device *dev) | 150 | static inline int cpuidle_register_device(struct cpuidle_device *dev) |
| 152 | {return -ENODEV; } | 151 | {return -ENODEV; } |
| 153 | static inline void cpuidle_unregister_device(struct cpuidle_device *dev) { } | 152 | static inline void cpuidle_unregister_device(struct cpuidle_device *dev) { } |
| 154 | 153 | static inline int cpuidle_register(struct cpuidle_driver *drv, | |
| 154 | const struct cpumask *const coupled_cpus) | ||
| 155 | {return -ENODEV; } | ||
| 156 | static inline void cpuidle_unregister(struct cpuidle_driver *drv) { } | ||
| 155 | static inline void cpuidle_pause_and_lock(void) { } | 157 | static inline void cpuidle_pause_and_lock(void) { } |
| 156 | static inline void cpuidle_resume_and_unlock(void) { } | 158 | static inline void cpuidle_resume_and_unlock(void) { } |
| 157 | static inline void cpuidle_pause(void) { } | 159 | static inline void cpuidle_pause(void) { } |
| @@ -159,11 +161,6 @@ static inline void cpuidle_resume(void) { } | |||
| 159 | static inline int cpuidle_enable_device(struct cpuidle_device *dev) | 161 | static inline int cpuidle_enable_device(struct cpuidle_device *dev) |
| 160 | {return -ENODEV; } | 162 | {return -ENODEV; } |
| 161 | static inline void cpuidle_disable_device(struct cpuidle_device *dev) { } | 163 | static inline void cpuidle_disable_device(struct cpuidle_device *dev) { } |
| 162 | static inline int cpuidle_wrap_enter(struct cpuidle_device *dev, | ||
| 163 | struct cpuidle_driver *drv, int index, | ||
| 164 | int (*enter)(struct cpuidle_device *dev, | ||
| 165 | struct cpuidle_driver *drv, int index)) | ||
| 166 | { return -ENODEV; } | ||
| 167 | static inline int cpuidle_play_dead(void) {return -ENODEV; } | 164 | static inline int cpuidle_play_dead(void) {return -ENODEV; } |
| 168 | #endif | 165 | #endif |
| 169 | 166 | ||
