diff options
Diffstat (limited to 'drivers/cpuidle')
-rw-r--r-- | drivers/cpuidle/Kconfig | 7 | ||||
-rw-r--r-- | drivers/cpuidle/Kconfig.arm | 28 | ||||
-rw-r--r-- | drivers/cpuidle/Kconfig.arm64 | 13 | ||||
-rw-r--r-- | drivers/cpuidle/Makefile | 5 | ||||
-rw-r--r-- | drivers/cpuidle/coupled.c | 6 | ||||
-rw-r--r-- | drivers/cpuidle/cpuidle-arm.c (renamed from drivers/cpuidle/cpuidle-arm64.c) | 83 | ||||
-rw-r--r-- | drivers/cpuidle/cpuidle-at91.c | 1 | ||||
-rw-r--r-- | drivers/cpuidle/cpuidle-exynos.c | 1 | ||||
-rw-r--r-- | drivers/cpuidle/cpuidle-kirkwood.c | 1 | ||||
-rw-r--r-- | drivers/cpuidle/cpuidle-mvebu-v7.c | 12 | ||||
-rw-r--r-- | drivers/cpuidle/cpuidle-ux500.c | 1 | ||||
-rw-r--r-- | drivers/cpuidle/cpuidle-zynq.c | 1 | ||||
-rw-r--r-- | drivers/cpuidle/cpuidle.c | 3 | ||||
-rw-r--r-- | drivers/cpuidle/driver.c | 23 | ||||
-rw-r--r-- | drivers/cpuidle/governors/menu.c | 8 | ||||
-rw-r--r-- | drivers/cpuidle/sysfs.c | 5 |
16 files changed, 107 insertions, 91 deletions
diff --git a/drivers/cpuidle/Kconfig b/drivers/cpuidle/Kconfig index c5029c1209b4..8c7930b5a65f 100644 --- a/drivers/cpuidle/Kconfig +++ b/drivers/cpuidle/Kconfig @@ -29,15 +29,10 @@ config DT_IDLE_STATES bool menu "ARM CPU Idle Drivers" -depends on ARM +depends on ARM || ARM64 source "drivers/cpuidle/Kconfig.arm" endmenu -menu "ARM64 CPU Idle Drivers" -depends on ARM64 -source "drivers/cpuidle/Kconfig.arm64" -endmenu - menu "MIPS CPU Idle Drivers" depends on MIPS source "drivers/cpuidle/Kconfig.mips" diff --git a/drivers/cpuidle/Kconfig.arm b/drivers/cpuidle/Kconfig.arm index 8e07c9419153..21340e0be73e 100644 --- a/drivers/cpuidle/Kconfig.arm +++ b/drivers/cpuidle/Kconfig.arm @@ -1,10 +1,20 @@ # # ARM CPU Idle drivers # +config ARM_CPUIDLE + bool "Generic ARM/ARM64 CPU idle Driver" + select DT_IDLE_STATES + help + Select this to enable generic cpuidle driver for ARM. + It provides a generic idle driver whose idle states are configured + at run-time through DT nodes. The CPUidle suspend backend is + initialized by calling the CPU operations init idle hook + provided by architecture code. + config ARM_BIG_LITTLE_CPUIDLE bool "Support for ARM big.LITTLE processors" depends on ARCH_VEXPRESS_TC2_PM || ARCH_EXYNOS - depends on MCPM + depends on MCPM && !ARM64 select ARM_CPU_SUSPEND select CPU_IDLE_MULTIPLE_DRIVERS select DT_IDLE_STATES @@ -16,51 +26,51 @@ config ARM_BIG_LITTLE_CPUIDLE config ARM_CLPS711X_CPUIDLE bool "CPU Idle Driver for CLPS711X processors" - depends on ARCH_CLPS711X || COMPILE_TEST + depends on ARCH_CLPS711X && !ARM64 || COMPILE_TEST help Select this to enable cpuidle on Cirrus Logic CLPS711X SOCs. config ARM_HIGHBANK_CPUIDLE bool "CPU Idle Driver for Calxeda processors" - depends on ARM_PSCI + depends on ARM_PSCI && !ARM64 select ARM_CPU_SUSPEND help Select this to enable cpuidle on Calxeda processors. config ARM_KIRKWOOD_CPUIDLE bool "CPU Idle Driver for Marvell Kirkwood SoCs" - depends on MACH_KIRKWOOD + depends on MACH_KIRKWOOD && !ARM64 help This adds the CPU Idle driver for Marvell Kirkwood SoCs. config ARM_ZYNQ_CPUIDLE bool "CPU Idle Driver for Xilinx Zynq processors" - depends on ARCH_ZYNQ + depends on ARCH_ZYNQ && !ARM64 help Select this to enable cpuidle on Xilinx Zynq processors. config ARM_U8500_CPUIDLE bool "Cpu Idle Driver for the ST-E u8500 processors" - depends on ARCH_U8500 + depends on ARCH_U8500 && !ARM64 help Select this to enable cpuidle for ST-E u8500 processors config ARM_AT91_CPUIDLE bool "Cpu Idle Driver for the AT91 processors" default y - depends on ARCH_AT91 + depends on ARCH_AT91 && !ARM64 help Select this to enable cpuidle for AT91 processors config ARM_EXYNOS_CPUIDLE bool "Cpu Idle Driver for the Exynos processors" - depends on ARCH_EXYNOS + depends on ARCH_EXYNOS && !ARM64 select ARCH_NEEDS_CPU_IDLE_COUPLED if SMP help Select this to enable cpuidle for Exynos processors config ARM_MVEBU_V7_CPUIDLE bool "CPU Idle Driver for mvebu v7 family processors" - depends on ARCH_MVEBU + depends on ARCH_MVEBU && !ARM64 help Select this to enable cpuidle on Armada 370, 38x and XP processors. diff --git a/drivers/cpuidle/Kconfig.arm64 b/drivers/cpuidle/Kconfig.arm64 deleted file mode 100644 index 6effb3656735..000000000000 --- a/drivers/cpuidle/Kconfig.arm64 +++ /dev/null @@ -1,13 +0,0 @@ -# -# ARM64 CPU Idle drivers -# - -config ARM64_CPUIDLE - bool "Generic ARM64 CPU idle Driver" - select DT_IDLE_STATES - help - Select this to enable generic cpuidle driver for ARM64. - It provides a generic idle driver whose idle states are configured - at run-time through DT nodes. The CPUidle suspend backend is - initialized by calling the CPU operations init idle hook - provided by architecture code. diff --git a/drivers/cpuidle/Makefile b/drivers/cpuidle/Makefile index 4d177b916f75..3ba81b1dffad 100644 --- a/drivers/cpuidle/Makefile +++ b/drivers/cpuidle/Makefile @@ -17,16 +17,13 @@ obj-$(CONFIG_ARM_ZYNQ_CPUIDLE) += cpuidle-zynq.o obj-$(CONFIG_ARM_U8500_CPUIDLE) += cpuidle-ux500.o obj-$(CONFIG_ARM_AT91_CPUIDLE) += cpuidle-at91.o obj-$(CONFIG_ARM_EXYNOS_CPUIDLE) += cpuidle-exynos.o +obj-$(CONFIG_ARM_CPUIDLE) += cpuidle-arm.o ############################################################################### # MIPS drivers obj-$(CONFIG_MIPS_CPS_CPUIDLE) += cpuidle-cps.o ############################################################################### -# ARM64 drivers -obj-$(CONFIG_ARM64_CPUIDLE) += cpuidle-arm64.o - -############################################################################### # POWERPC drivers obj-$(CONFIG_PSERIES_CPUIDLE) += cpuidle-pseries.o obj-$(CONFIG_POWERNV_CPUIDLE) += cpuidle-powernv.o diff --git a/drivers/cpuidle/coupled.c b/drivers/cpuidle/coupled.c index 73fe2f8d7f96..7936dce4b878 100644 --- a/drivers/cpuidle/coupled.c +++ b/drivers/cpuidle/coupled.c @@ -292,7 +292,7 @@ static inline int cpuidle_coupled_get_state(struct cpuidle_device *dev, */ smp_rmb(); - for_each_cpu_mask(i, coupled->coupled_cpus) + for_each_cpu(i, &coupled->coupled_cpus) if (cpu_online(i) && coupled->requested_state[i] < state) state = coupled->requested_state[i]; @@ -338,7 +338,7 @@ static void cpuidle_coupled_poke_others(int this_cpu, { int cpu; - for_each_cpu_mask(cpu, coupled->coupled_cpus) + for_each_cpu(cpu, &coupled->coupled_cpus) if (cpu != this_cpu && cpu_online(cpu)) cpuidle_coupled_poke(cpu); } @@ -638,7 +638,7 @@ int cpuidle_coupled_register_device(struct cpuidle_device *dev) if (cpumask_empty(&dev->coupled_cpus)) return 0; - for_each_cpu_mask(cpu, dev->coupled_cpus) { + for_each_cpu(cpu, &dev->coupled_cpus) { other_dev = per_cpu(cpuidle_devices, cpu); if (other_dev && other_dev->coupled) { coupled = other_dev->coupled; diff --git a/drivers/cpuidle/cpuidle-arm64.c b/drivers/cpuidle/cpuidle-arm.c index 39a2c62716c3..545069d5fdfb 100644 --- a/drivers/cpuidle/cpuidle-arm64.c +++ b/drivers/cpuidle/cpuidle-arm.c @@ -1,5 +1,5 @@ /* - * ARM64 generic CPU idle driver. + * ARM/ARM64 generic CPU idle driver. * * Copyright (C) 2014 ARM Ltd. * Author: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com> @@ -9,7 +9,7 @@ * published by the Free Software Foundation. */ -#define pr_fmt(fmt) "CPUidle arm64: " fmt +#define pr_fmt(fmt) "CPUidle arm: " fmt #include <linux/cpuidle.h> #include <linux/cpumask.h> @@ -17,13 +17,14 @@ #include <linux/kernel.h> #include <linux/module.h> #include <linux/of.h> +#include <linux/slab.h> #include <asm/cpuidle.h> #include "dt_idle_states.h" /* - * arm64_enter_idle_state - Programs CPU to enter the specified state + * arm_enter_idle_state - Programs CPU to enter the specified state * * dev: cpuidle device * drv: cpuidle driver @@ -32,8 +33,8 @@ * Called from the CPUidle framework to program the device to the * specified target state selected by the governor. */ -static int arm64_enter_idle_state(struct cpuidle_device *dev, - struct cpuidle_driver *drv, int idx) +static int arm_enter_idle_state(struct cpuidle_device *dev, + struct cpuidle_driver *drv, int idx) { int ret; @@ -49,7 +50,7 @@ static int arm64_enter_idle_state(struct cpuidle_device *dev, * call the CPU ops suspend protocol with idle index as a * parameter. */ - ret = cpu_suspend(idx); + arm_cpuidle_suspend(idx); cpu_pm_exit(); } @@ -57,8 +58,8 @@ static int arm64_enter_idle_state(struct cpuidle_device *dev, return ret ? -1 : idx; } -static struct cpuidle_driver arm64_idle_driver = { - .name = "arm64_idle", +static struct cpuidle_driver arm_idle_driver = { + .name = "arm_idle", .owner = THIS_MODULE, /* * State at index 0 is standby wfi and considered standard @@ -68,32 +69,33 @@ static struct cpuidle_driver arm64_idle_driver = { * handler for idle state index 0. */ .states[0] = { - .enter = arm64_enter_idle_state, + .enter = arm_enter_idle_state, .exit_latency = 1, .target_residency = 1, .power_usage = UINT_MAX, .name = "WFI", - .desc = "ARM64 WFI", + .desc = "ARM WFI", } }; -static const struct of_device_id arm64_idle_state_match[] __initconst = { +static const struct of_device_id arm_idle_state_match[] __initconst = { { .compatible = "arm,idle-state", - .data = arm64_enter_idle_state }, + .data = arm_enter_idle_state }, { }, }; /* - * arm64_idle_init + * arm_idle_init * - * Registers the arm64 specific cpuidle driver with the cpuidle + * Registers the arm specific cpuidle driver with the cpuidle * framework. It relies on core code to parse the idle states * and initialize them using driver data structures accordingly. */ -static int __init arm64_idle_init(void) +static int __init arm_idle_init(void) { int cpu, ret; - struct cpuidle_driver *drv = &arm64_idle_driver; + struct cpuidle_driver *drv = &arm_idle_driver; + struct cpuidle_device *dev; /* * Initialize idle states data, starting at index 1. @@ -101,22 +103,61 @@ static int __init arm64_idle_init(void) * let the driver initialization fail accordingly since there is no * reason to initialize the idle driver if only wfi is supported. */ - ret = dt_init_idle_driver(drv, arm64_idle_state_match, 1); + ret = dt_init_idle_driver(drv, arm_idle_state_match, 1); if (ret <= 0) return ret ? : -ENODEV; + ret = cpuidle_register_driver(drv); + if (ret) { + pr_err("Failed to register cpuidle driver\n"); + return ret; + } + /* * Call arch CPU operations in order to initialize * idle states suspend back-end specific data */ for_each_possible_cpu(cpu) { - ret = cpu_init_idle(cpu); + ret = arm_cpuidle_init(cpu); + + /* + * Skip the cpuidle device initialization if the reported + * failure is a HW misconfiguration/breakage (-ENXIO). + */ + if (ret == -ENXIO) + continue; + if (ret) { pr_err("CPU %d failed to init idle CPU ops\n", cpu); - return ret; + goto out_fail; + } + + dev = kzalloc(sizeof(*dev), GFP_KERNEL); + if (!dev) { + pr_err("Failed to allocate cpuidle device\n"); + goto out_fail; + } + dev->cpu = cpu; + + ret = cpuidle_register_device(dev); + if (ret) { + pr_err("Failed to register cpuidle device for CPU %d\n", + cpu); + kfree(dev); + goto out_fail; } } - return cpuidle_register(drv, NULL); + return 0; +out_fail: + while (--cpu >= 0) { + dev = per_cpu(cpuidle_devices, cpu); + cpuidle_unregister_device(dev); + kfree(dev); + } + + cpuidle_unregister_driver(drv); + + return ret; } -device_initcall(arm64_idle_init); +device_initcall(arm_idle_init); diff --git a/drivers/cpuidle/cpuidle-at91.c b/drivers/cpuidle/cpuidle-at91.c index aae7bfc1ea36..f2446c78d87c 100644 --- a/drivers/cpuidle/cpuidle-at91.c +++ b/drivers/cpuidle/cpuidle-at91.c @@ -19,7 +19,6 @@ #include <linux/cpuidle.h> #include <linux/io.h> #include <linux/export.h> -#include <asm/proc-fns.h> #include <asm/cpuidle.h> #define AT91_MAX_STATES 2 diff --git a/drivers/cpuidle/cpuidle-exynos.c b/drivers/cpuidle/cpuidle-exynos.c index 9bb5348995a9..b5f0a9cc8185 100644 --- a/drivers/cpuidle/cpuidle-exynos.c +++ b/drivers/cpuidle/cpuidle-exynos.c @@ -19,7 +19,6 @@ #include <linux/of.h> #include <linux/platform_data/cpuidle-exynos.h> -#include <asm/proc-fns.h> #include <asm/suspend.h> #include <asm/cpuidle.h> diff --git a/drivers/cpuidle/cpuidle-kirkwood.c b/drivers/cpuidle/cpuidle-kirkwood.c index cea0a6c4b1db..d23d8f468c12 100644 --- a/drivers/cpuidle/cpuidle-kirkwood.c +++ b/drivers/cpuidle/cpuidle-kirkwood.c @@ -21,7 +21,6 @@ #include <linux/cpuidle.h> #include <linux/io.h> #include <linux/export.h> -#include <asm/proc-fns.h> #include <asm/cpuidle.h> #define KIRKWOOD_MAX_STATES 2 diff --git a/drivers/cpuidle/cpuidle-mvebu-v7.c b/drivers/cpuidle/cpuidle-mvebu-v7.c index 38e68618513a..980151f34707 100644 --- a/drivers/cpuidle/cpuidle-mvebu-v7.c +++ b/drivers/cpuidle/cpuidle-mvebu-v7.c @@ -37,11 +37,11 @@ static int mvebu_v7_enter_idle(struct cpuidle_device *dev, deepidle = true; ret = mvebu_v7_cpu_suspend(deepidle); + cpu_pm_exit(); + if (ret) return ret; - cpu_pm_exit(); - return index; } @@ -50,17 +50,17 @@ static struct cpuidle_driver armadaxp_idle_driver = { .states[0] = ARM_CPUIDLE_WFI_STATE, .states[1] = { .enter = mvebu_v7_enter_idle, - .exit_latency = 10, + .exit_latency = 100, .power_usage = 50, - .target_residency = 100, + .target_residency = 1000, .name = "MV CPU IDLE", .desc = "CPU power down", }, .states[2] = { .enter = mvebu_v7_enter_idle, - .exit_latency = 100, + .exit_latency = 1000, .power_usage = 5, - .target_residency = 1000, + .target_residency = 10000, .flags = MVEBU_V7_FLAG_DEEP_IDLE, .name = "MV CPU DEEP IDLE", .desc = "CPU and L2 Fabric power down", diff --git a/drivers/cpuidle/cpuidle-ux500.c b/drivers/cpuidle/cpuidle-ux500.c index 66f81e410f0d..8bf895c0017d 100644 --- a/drivers/cpuidle/cpuidle-ux500.c +++ b/drivers/cpuidle/cpuidle-ux500.c @@ -19,7 +19,6 @@ #include <linux/platform_device.h> #include <asm/cpuidle.h> -#include <asm/proc-fns.h> static atomic_t master = ATOMIC_INIT(0); static DEFINE_SPINLOCK(master_lock); diff --git a/drivers/cpuidle/cpuidle-zynq.c b/drivers/cpuidle/cpuidle-zynq.c index 002b8c9f98f5..543292b1d38e 100644 --- a/drivers/cpuidle/cpuidle-zynq.c +++ b/drivers/cpuidle/cpuidle-zynq.c @@ -28,7 +28,6 @@ #include <linux/init.h> #include <linux/cpuidle.h> #include <linux/platform_device.h> -#include <asm/proc-fns.h> #include <asm/cpuidle.h> #define ZYNQ_MAX_STATES 2 diff --git a/drivers/cpuidle/cpuidle.c b/drivers/cpuidle/cpuidle.c index 080bd2dbde4b..7a73a279e179 100644 --- a/drivers/cpuidle/cpuidle.c +++ b/drivers/cpuidle/cpuidle.c @@ -330,9 +330,6 @@ int cpuidle_enable_device(struct cpuidle_device *dev) if (!dev->registered) return -EINVAL; - if (!dev->state_count) - dev->state_count = drv->state_count; - ret = cpuidle_add_device_sysfs(dev); if (ret) return ret; diff --git a/drivers/cpuidle/driver.c b/drivers/cpuidle/driver.c index 2697e87d5b34..5db147859b90 100644 --- a/drivers/cpuidle/driver.c +++ b/drivers/cpuidle/driver.c @@ -13,7 +13,7 @@ #include <linux/sched.h> #include <linux/cpuidle.h> #include <linux/cpumask.h> -#include <linux/clockchips.h> +#include <linux/tick.h> #include "cpuidle.h" @@ -130,21 +130,20 @@ static inline void __cpuidle_unset_driver(struct cpuidle_driver *drv) #endif /** - * cpuidle_setup_broadcast_timer - enable/disable the broadcast timer + * cpuidle_setup_broadcast_timer - enable/disable the broadcast timer on a cpu * @arg: a void pointer used to match the SMP cross call API * - * @arg is used as a value of type 'long' with one of the two values: - * - CLOCK_EVT_NOTIFY_BROADCAST_ON - * - CLOCK_EVT_NOTIFY_BROADCAST_OFF + * If @arg is NULL broadcast is disabled otherwise enabled * - * Set the broadcast timer notification for the current CPU. This function - * is executed per CPU by an SMP cross call. It not supposed to be called - * directly. + * This function is executed per CPU by an SMP cross call. It's not + * supposed to be called directly. */ static void cpuidle_setup_broadcast_timer(void *arg) { - int cpu = smp_processor_id(); - clockevents_notify((long)(arg), &cpu); + if (arg) + tick_broadcast_enable(); + else + tick_broadcast_disable(); } /** @@ -239,7 +238,7 @@ static int __cpuidle_register_driver(struct cpuidle_driver *drv) if (drv->bctimer) on_each_cpu_mask(drv->cpumask, cpuidle_setup_broadcast_timer, - (void *)CLOCK_EVT_NOTIFY_BROADCAST_ON, 1); + (void *)1, 1); poll_idle_init(drv); @@ -263,7 +262,7 @@ static void __cpuidle_unregister_driver(struct cpuidle_driver *drv) if (drv->bctimer) { drv->bctimer = 0; on_each_cpu_mask(drv->cpumask, cpuidle_setup_broadcast_timer, - (void *)CLOCK_EVT_NOTIFY_BROADCAST_OFF, 1); + NULL, 1); } __cpuidle_unset_driver(drv); diff --git a/drivers/cpuidle/governors/menu.c b/drivers/cpuidle/governors/menu.c index 40580794e23d..b8a5fa15ca24 100644 --- a/drivers/cpuidle/governors/menu.c +++ b/drivers/cpuidle/governors/menu.c @@ -190,12 +190,6 @@ static DEFINE_PER_CPU(struct menu_device, menu_devices); static void menu_update(struct cpuidle_driver *drv, struct cpuidle_device *dev); -/* This implements DIV_ROUND_CLOSEST but avoids 64 bit division */ -static u64 div_round64(u64 dividend, u32 divisor) -{ - return div_u64(dividend + (divisor / 2), divisor); -} - /* * Try detecting repeating patterns by keeping track of the last 8 * intervals, and checking if the standard deviation of that set @@ -317,7 +311,7 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev) * operands are 32 bits. * Make sure to round up for half microseconds. */ - data->predicted_us = div_round64((uint64_t)data->next_timer_us * + data->predicted_us = DIV_ROUND_CLOSEST_ULL((uint64_t)data->next_timer_us * data->correction_factor[data->bucket], RESOLUTION * DECAY); diff --git a/drivers/cpuidle/sysfs.c b/drivers/cpuidle/sysfs.c index 97c5903b4606..832a2c3f01ff 100644 --- a/drivers/cpuidle/sysfs.c +++ b/drivers/cpuidle/sysfs.c @@ -401,7 +401,7 @@ static int cpuidle_add_state_sysfs(struct cpuidle_device *device) struct cpuidle_driver *drv = cpuidle_get_cpu_driver(device); /* state statistics */ - for (i = 0; i < device->state_count; i++) { + for (i = 0; i < drv->state_count; i++) { kobj = kzalloc(sizeof(struct cpuidle_state_kobj), GFP_KERNEL); if (!kobj) goto error_state; @@ -433,9 +433,10 @@ error_state: */ static void cpuidle_remove_state_sysfs(struct cpuidle_device *device) { + struct cpuidle_driver *drv = cpuidle_get_cpu_driver(device); int i; - for (i = 0; i < device->state_count; i++) + for (i = 0; i < drv->state_count; i++) cpuidle_free_state_kobj(device, i); } |