aboutsummaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorMark Brown <broonie@kernel.org>2015-01-18 13:12:48 +0000
committerMark Brown <broonie@kernel.org>2015-01-18 13:12:48 +0000
commitcc43a17507644ad34d07a3e95d7376d55fd82b15 (patch)
treeaa6c48a80f001853e780d0738b5a8d843250ff46 /drivers
parent71220c39c683cc0eb4d5300268cd061dd249933e (diff)
parent4bb26215c07fb204ae1d66e54406dd6bae793c20 (diff)
Merge remote-tracking branch 'lsk/v3.10/topic/arm64-cpuidle' into linux-linaro-lsk
Conflicts: arch/arm64/kernel/Makefile drivers/cpuidle/Makefile
Diffstat (limited to 'drivers')
-rw-r--r--drivers/cpuidle/Kconfig20
-rw-r--r--drivers/cpuidle/Kconfig.arm649
-rw-r--r--drivers/cpuidle/Makefile2
-rw-r--r--drivers/cpuidle/cpuidle-arm64.c162
-rw-r--r--drivers/cpuidle/dt_idle_states.c213
-rw-r--r--drivers/cpuidle/dt_idle_states.h7
-rw-r--r--drivers/cpuidle/of_idle_states.c274
-rw-r--r--drivers/cpuidle/of_idle_states.h8
8 files changed, 301 insertions, 394 deletions
diff --git a/drivers/cpuidle/Kconfig b/drivers/cpuidle/Kconfig
index 842d7ba83101..9625ce7ed5f8 100644
--- a/drivers/cpuidle/Kconfig
+++ b/drivers/cpuidle/Kconfig
@@ -31,26 +31,20 @@ config CPU_IDLE_GOV_MENU
config ARCH_NEEDS_CPU_IDLE_COUPLED
def_bool n
-config OF_IDLE_STATES
- bool "Idle states DT support"
- depends on ARM || ARM64
- default n
- help
- Allows the CPU idle framework to initialize CPU idle drivers
- state data by using DT provided nodes compliant with idle states
- device tree bindings.
+config DT_IDLE_STATES
+ bool
if CPU_IDLE
+menu "ARM64 CPU Idle Drivers"
+depends on ARM64
+source "drivers/cpuidle/Kconfig.arm64"
+endmenu
+
config CPU_IDLE_CALXEDA
bool "CPU Idle Driver for Calxeda processors"
depends on ARCH_HIGHBANK
help
Select this to enable cpuidle on Calxeda processors.
-menu "ARM64 CPU Idle Drivers"
-depends on ARM64
-source "drivers/cpuidle/Kconfig.arm64"
-endmenu
-
endif
diff --git a/drivers/cpuidle/Kconfig.arm64 b/drivers/cpuidle/Kconfig.arm64
index b83612c67e6d..d0a08ed1b2ee 100644
--- a/drivers/cpuidle/Kconfig.arm64
+++ b/drivers/cpuidle/Kconfig.arm64
@@ -4,10 +4,11 @@
config ARM64_CPUIDLE
bool "Generic ARM64 CPU idle Driver"
- select OF_IDLE_STATES
+ select ARM64_CPU_SUSPEND
+ select DT_IDLE_STATES
help
- Select this to enable generic cpuidle driver for ARM v8.
+ 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 the device tree parsing code on matching the entry
- method to the respective CPU operations.
+ initialized by calling the CPU operations init idle hook
+ provided by architecture code.
diff --git a/drivers/cpuidle/Makefile b/drivers/cpuidle/Makefile
index 2d97bcfecd00..0bd32cd03f0a 100644
--- a/drivers/cpuidle/Makefile
+++ b/drivers/cpuidle/Makefile
@@ -5,7 +5,7 @@
obj-y += cpuidle.o driver.o governor.o sysfs.o governors/
obj-$(CONFIG_ARCH_NEEDS_CPU_IDLE_COUPLED) += coupled.o
obj-$(CONFIG_BIG_LITTLE) += arm_big_little.o
-obj-$(CONFIG_OF_IDLE_STATES) += of_idle_states.o
+obj-$(CONFIG_DT_IDLE_STATES) += dt_idle_states.o
obj-$(CONFIG_CPU_IDLE_CALXEDA) += cpuidle-calxeda.o
obj-$(CONFIG_ARCH_KIRKWOOD) += cpuidle-kirkwood.o
diff --git a/drivers/cpuidle/cpuidle-arm64.c b/drivers/cpuidle/cpuidle-arm64.c
index 2cfde6ce3086..50997ea942fc 100644
--- a/drivers/cpuidle/cpuidle-arm64.c
+++ b/drivers/cpuidle/cpuidle-arm64.c
@@ -9,6 +9,8 @@
* published by the Free Software Foundation.
*/
+#define pr_fmt(fmt) "CPUidle arm64: " fmt
+
#include <linux/cpuidle.h>
#include <linux/cpumask.h>
#include <linux/cpu_pm.h>
@@ -16,50 +18,23 @@
#include <linux/module.h>
#include <linux/of.h>
-#include <asm/psci.h>
+#include <asm/cpuidle.h>
#include <asm/suspend.h>
-#include "of_idle_states.h"
-
-typedef int (*suspend_init_fn)(struct cpuidle_driver *,
- struct device_node *[]);
-
-struct cpu_suspend_ops {
- const char *id;
- suspend_init_fn init_fn;
-};
-
-static const struct cpu_suspend_ops suspend_operations[] __initconst = {
- {"arm,psci", psci_dt_register_idle_states},
- {}
-};
-
-static __init const struct cpu_suspend_ops *get_suspend_ops(const char *str)
-{
- int i;
-
- if (!str)
- return NULL;
-
- for (i = 0; suspend_operations[i].id; i++)
- if (!strcmp(suspend_operations[i].id, str))
- return &suspend_operations[i];
-
- return NULL;
-}
+#include "dt_idle_states.h"
/*
- * arm_enter_idle_state - Programs CPU to enter the specified state
+ * arm64_enter_idle_state - Programs CPU to enter the specified state
*
- * @dev: cpuidle device
- * @drv: cpuidle driver
- * @idx: state index
+ * dev: cpuidle device
+ * drv: cpuidle driver
+ * idx: state index
*
* Called from the CPUidle framework to program the device to the
* specified target state selected by the governor.
*/
-static int arm_enter_idle_state(struct cpuidle_device *dev,
- struct cpuidle_driver *drv, int idx)
+static int arm64_enter_idle_state(struct cpuidle_device *dev,
+ struct cpuidle_driver *drv, int idx)
{
int ret;
@@ -68,30 +43,47 @@ static int arm_enter_idle_state(struct cpuidle_device *dev,
return idx;
}
- cpu_pm_enter();
- /*
- * Pass idle state index to cpu_suspend which in turn will call
- * the CPU ops suspend protocol with idle index as a parameter.
- *
- * Some states would not require context to be saved and flushed
- * to DRAM, so calling cpu_suspend would not be stricly necessary.
- * When power domains specifications for ARM CPUs are finalized then
- * this code can be optimized to prevent saving registers if not
- * needed.
- */
- ret = cpu_suspend(idx);
+ ret = cpu_pm_enter();
+ if (!ret) {
+ /*
+ * Pass idle state index to cpu_suspend which in turn will
+ * call the CPU ops suspend protocol with idle index as a
+ * parameter.
+ */
+ ret = cpu_suspend(idx);
- cpu_pm_exit();
+ cpu_pm_exit();
+ }
return ret ? -1 : idx;
}
-struct cpuidle_driver arm64_idle_driver = {
+static struct cpuidle_driver arm64_idle_driver = {
.name = "arm64_idle",
.owner = THIS_MODULE,
+ /*
+ * State at index 0 is standby wfi and considered standard
+ * on all ARM platforms. If in some platforms simple wfi
+ * can't be used as "state 0", DT bindings must be implemented
+ * to work around this issue and allow installing a special
+ * handler for idle state index 0.
+ */
+ .states[0] = {
+ .enter = arm64_enter_idle_state,
+ .exit_latency = 1,
+ .target_residency = 1,
+ .power_usage = UINT_MAX,
+ .flags = CPUIDLE_FLAG_TIME_VALID,
+ .name = "WFI",
+ .desc = "ARM64 WFI",
+ }
};
-static struct device_node *state_nodes[CPUIDLE_STATE_MAX] __initdata;
+static const struct of_device_id arm64_idle_state_match[] __initconst = {
+ { .compatible = "arm,idle-state",
+ .data = arm64_enter_idle_state },
+ { },
+};
/*
* arm64_idle_init
@@ -102,58 +94,40 @@ static struct device_node *state_nodes[CPUIDLE_STATE_MAX] __initdata;
*/
static int __init arm64_idle_init(void)
{
- int i, ret;
- const char *entry_method;
- struct device_node *idle_states_node;
- const struct cpu_suspend_ops *suspend_init;
+ int cpu, ret;
struct cpuidle_driver *drv = &arm64_idle_driver;
- idle_states_node = of_find_node_by_path("/cpus/idle-states");
- if (!idle_states_node)
- return -ENOENT;
-
- if (of_property_read_string(idle_states_node, "entry-method",
- &entry_method)) {
- pr_warn(" * %s missing entry-method property\n",
- idle_states_node->full_name);
- of_node_put(idle_states_node);
- return -EOPNOTSUPP;
- }
-
- suspend_init = get_suspend_ops(entry_method);
- if (!suspend_init) {
- pr_warn("Missing suspend initializer\n");
- of_node_put(idle_states_node);
- return -EOPNOTSUPP;
- }
-
/*
- * State at index 0 is standby wfi and considered standard
- * on all ARM platforms. If in some platforms simple wfi
- * can't be used as "state 0", DT bindings must be implemented
- * to work around this issue and allow installing a special
- * handler for idle state index 0.
+ * Initialize idle states data, starting at index 1.
+ * This driver is DT only, if no DT idle states are detected (ret == 0)
+ * let the driver initialization fail accordingly since there is no
+ * reason to initialize the idle driver if only wfi is supported.
*/
- drv->states[0].exit_latency = 1;
- drv->states[0].target_residency = 1;
- drv->states[0].flags = CPUIDLE_FLAG_TIME_VALID;
- strncpy(drv->states[0].name, "ARM WFI", CPUIDLE_NAME_LEN);
- strncpy(drv->states[0].desc, "ARM WFI", CPUIDLE_DESC_LEN);
+ ret = dt_init_idle_driver(drv, arm64_idle_state_match, 1);
+ if (ret <= 0) {
+ if (ret)
+ pr_err("failed to initialize idle states\n");
+ return ret ? : -ENODEV;
+ }
- drv->cpumask = (struct cpumask *) cpu_possible_mask;
/*
- * Start at index 1, request idle state nodes to be filled
+ * Call arch CPU operations in order to initialize
+ * idle states suspend back-end specific data
*/
- ret = of_init_idle_driver(drv, state_nodes, 1, true);
- if (ret)
- return ret;
-
- if (suspend_init->init_fn(drv, state_nodes))
- return -EOPNOTSUPP;
+ for_each_possible_cpu(cpu) {
+ ret = cpu_init_idle(cpu);
+ if (ret) {
+ pr_err("CPU %d failed to init idle CPU ops\n", cpu);
+ return ret;
+ }
+ }
- for (i = 0; i < drv->state_count; i++)
- drv->states[i].enter = arm_enter_idle_state;
+ ret = cpuidle_register(drv, NULL);
+ if (ret) {
+ pr_err("failed to register cpuidle driver\n");
+ return ret;
+ }
- return cpuidle_register(drv, NULL);
+ return 0;
}
device_initcall(arm64_idle_init);
diff --git a/drivers/cpuidle/dt_idle_states.c b/drivers/cpuidle/dt_idle_states.c
new file mode 100644
index 000000000000..52f4d11bbf3f
--- /dev/null
+++ b/drivers/cpuidle/dt_idle_states.c
@@ -0,0 +1,213 @@
+/*
+ * DT idle states parsing code.
+ *
+ * Copyright (C) 2014 ARM Ltd.
+ * Author: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#define pr_fmt(fmt) "DT idle-states: " fmt
+
+#include <linux/cpuidle.h>
+#include <linux/cpumask.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+
+#include "dt_idle_states.h"
+
+static int init_state_node(struct cpuidle_state *idle_state,
+ const struct of_device_id *matches,
+ struct device_node *state_node)
+{
+ int err;
+ const struct of_device_id *match_id;
+
+ match_id = of_match_node(matches, state_node);
+ if (!match_id)
+ return -ENODEV;
+ /*
+ * CPUidle drivers are expected to initialize the const void *data
+ * pointer of the passed in struct of_device_id array to the idle
+ * state enter function.
+ */
+ idle_state->enter = match_id->data;
+
+ err = of_property_read_u32(state_node, "wakeup-latency-us",
+ &idle_state->exit_latency);
+ if (err) {
+ u32 entry_latency, exit_latency;
+
+ err = of_property_read_u32(state_node, "entry-latency-us",
+ &entry_latency);
+ if (err) {
+ pr_debug(" * %s missing entry-latency-us property\n",
+ state_node->full_name);
+ return -EINVAL;
+ }
+
+ err = of_property_read_u32(state_node, "exit-latency-us",
+ &exit_latency);
+ if (err) {
+ pr_debug(" * %s missing exit-latency-us property\n",
+ state_node->full_name);
+ return -EINVAL;
+ }
+ /*
+ * If wakeup-latency-us is missing, default to entry+exit
+ * latencies as defined in idle states bindings
+ */
+ idle_state->exit_latency = entry_latency + exit_latency;
+ }
+
+ err = of_property_read_u32(state_node, "min-residency-us",
+ &idle_state->target_residency);
+ if (err) {
+ pr_debug(" * %s missing min-residency-us property\n",
+ state_node->full_name);
+ return -EINVAL;
+ }
+
+ idle_state->flags = CPUIDLE_FLAG_TIME_VALID;
+ if (of_property_read_bool(state_node, "local-timer-stop"))
+ idle_state->flags |= CPUIDLE_FLAG_TIMER_STOP;
+ /*
+ * TODO:
+ * replace with kstrdup and pointer assignment when name
+ * and desc become string pointers
+ */
+ strncpy(idle_state->name, state_node->name, CPUIDLE_NAME_LEN - 1);
+ strncpy(idle_state->desc, state_node->name, CPUIDLE_DESC_LEN - 1);
+ return 0;
+}
+
+/*
+ * Check that the idle state is uniform across all CPUs in the CPUidle driver
+ * cpumask
+ */
+static bool idle_state_valid(struct device_node *state_node, unsigned int idx,
+ const cpumask_t *cpumask)
+{
+ int cpu;
+ struct device_node *cpu_node, *curr_state_node;
+ bool valid = true;
+
+ /*
+ * Compare idle state phandles for index idx on all CPUs in the
+ * CPUidle driver cpumask. Start from next logical cpu following
+ * cpumask_first(cpumask) since that's the CPU state_node was
+ * retrieved from. If a mismatch is found bail out straight
+ * away since we certainly hit a firmware misconfiguration.
+ */
+ for (cpu = cpumask_next(cpumask_first(cpumask), cpumask);
+ cpu < nr_cpu_ids; cpu = cpumask_next(cpu, cpumask)) {
+ cpu_node = of_cpu_device_node_get(cpu);
+ curr_state_node = of_parse_phandle(cpu_node, "cpu-idle-states",
+ idx);
+ if (state_node != curr_state_node)
+ valid = false;
+
+ of_node_put(curr_state_node);
+ of_node_put(cpu_node);
+ if (!valid)
+ break;
+ }
+
+ return valid;
+}
+
+/**
+ * dt_init_idle_driver() - Parse the DT idle states and initialize the
+ * idle driver states array
+ * @drv: Pointer to CPU idle driver to be initialized
+ * @matches: Array of of_device_id match structures to search in for
+ * compatible idle state nodes. The data pointer for each valid
+ * struct of_device_id entry in the matches array must point to
+ * a function with the following signature, that corresponds to
+ * the CPUidle state enter function signature:
+ *
+ * int (*)(struct cpuidle_device *dev,
+ * struct cpuidle_driver *drv,
+ * int index);
+ *
+ * @start_idx: First idle state index to be initialized
+ *
+ * If DT idle states are detected and are valid the state count and states
+ * array entries in the cpuidle driver are initialized accordingly starting
+ * from index start_idx.
+ *
+ * Return: number of valid DT idle states parsed, <0 on failure
+ */
+int dt_init_idle_driver(struct cpuidle_driver *drv,
+ const struct of_device_id *matches,
+ unsigned int start_idx)
+{
+ struct cpuidle_state *idle_state;
+ struct device_node *state_node, *cpu_node;
+ int i, err = 0;
+ const cpumask_t *cpumask;
+ unsigned int state_idx = start_idx;
+
+ if (state_idx >= CPUIDLE_STATE_MAX)
+ return -EINVAL;
+ /*
+ * We get the idle states for the first logical cpu in the
+ * driver mask (or cpu_possible_mask if the driver cpumask is not set)
+ * and we check through idle_state_valid() if they are uniform
+ * across CPUs, otherwise we hit a firmware misconfiguration.
+ */
+ cpumask = drv->cpumask ? : cpu_possible_mask;
+ cpu_node = of_cpu_device_node_get(cpumask_first(cpumask));
+
+ for (i = 0; ; i++) {
+ state_node = of_parse_phandle(cpu_node, "cpu-idle-states", i);
+ if (!state_node)
+ break;
+
+ if (!idle_state_valid(state_node, i, cpumask)) {
+ pr_warn("%s idle state not valid, bailing out\n",
+ state_node->full_name);
+ err = -EINVAL;
+ break;
+ }
+
+ if (state_idx == CPUIDLE_STATE_MAX) {
+ pr_warn("State index reached static CPU idle driver states array size\n");
+ break;
+ }
+
+ idle_state = &drv->states[state_idx++];
+ err = init_state_node(idle_state, matches, state_node);
+ if (err) {
+ pr_err("Parsing idle state node %s failed with err %d\n",
+ state_node->full_name, err);
+ err = -EINVAL;
+ break;
+ }
+ of_node_put(state_node);
+ }
+
+ of_node_put(state_node);
+ of_node_put(cpu_node);
+ if (err)
+ return err;
+ /*
+ * Update the driver state count only if some valid DT idle states
+ * were detected
+ */
+ if (i)
+ drv->state_count = state_idx;
+
+ /*
+ * Return the number of present and valid DT idle states, which can
+ * also be 0 on platforms with missing DT idle states or legacy DT
+ * configuration predating the DT idle states bindings.
+ */
+ return i;
+}
+EXPORT_SYMBOL_GPL(dt_init_idle_driver);
diff --git a/drivers/cpuidle/dt_idle_states.h b/drivers/cpuidle/dt_idle_states.h
new file mode 100644
index 000000000000..4818134bc65b
--- /dev/null
+++ b/drivers/cpuidle/dt_idle_states.h
@@ -0,0 +1,7 @@
+#ifndef __DT_IDLE_STATES
+#define __DT_IDLE_STATES
+
+int dt_init_idle_driver(struct cpuidle_driver *drv,
+ const struct of_device_id *matches,
+ unsigned int start_idx);
+#endif
diff --git a/drivers/cpuidle/of_idle_states.c b/drivers/cpuidle/of_idle_states.c
deleted file mode 100644
index eceb1b4c4657..000000000000
--- a/drivers/cpuidle/of_idle_states.c
+++ /dev/null
@@ -1,274 +0,0 @@
-/*
- * OF idle states parsing code.
- *
- * Copyright (C) 2014 ARM Ltd.
- * Author: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#include <linux/cpuidle.h>
-#include <linux/cpumask.h>
-#include <linux/errno.h>
-#include <linux/kernel.h>
-#include <linux/list.h>
-#include <linux/list_sort.h>
-#include <linux/module.h>
-#include <linux/of.h>
-#include <linux/slab.h>
-
-#include "of_idle_states.h"
-
-struct state_elem {
- struct list_head list;
- struct device_node *node;
- int val;
-};
-
-static struct list_head head __initdata = LIST_HEAD_INIT(head);
-
-static bool __init state_cpu_valid(struct device_node *state_node,
- struct device_node *cpu_node)
-{
- int i = 0;
- struct device_node *cpu_state;
-
- while ((cpu_state = of_parse_phandle(cpu_node,
- "cpu-idle-states", i++))) {
- if (cpu_state && state_node == cpu_state) {
- of_node_put(cpu_state);
- return true;
- }
- of_node_put(cpu_state);
- }
- return false;
-}
-
-static bool __init state_cpus_valid(const cpumask_t *cpus,
- struct device_node *state_node)
-{
- int cpu;
- struct device_node *cpu_node;
-
- /*
- * Check if state is valid on driver cpumask cpus
- */
- for_each_cpu(cpu, cpus) {
- cpu_node = of_get_cpu_node(cpu, NULL);
-
- if (!cpu_node) {
- pr_err("Missing device node for CPU %d\n", cpu);
- return false;
- }
-
- if (!state_cpu_valid(state_node, cpu_node))
- return false;
- }
-
- return true;
-}
-
-static int __init state_cmp(void *priv, struct list_head *a,
- struct list_head *b)
-{
- struct state_elem *ela, *elb;
-
- ela = container_of(a, struct state_elem, list);
- elb = container_of(b, struct state_elem, list);
-
- return ela->val - elb->val;
-}
-
-static int __init add_state_node(cpumask_t *cpumask,
- struct device_node *state_node)
-{
- struct state_elem *el;
- u32 val;
-
- pr_debug(" * %s...\n", state_node->full_name);
-
- if (!state_cpus_valid(cpumask, state_node))
- return -EINVAL;
- /*
- * Parse just the value required to sort the states.
- */
- if (of_property_read_u32(state_node, "min-residency-us",
- &val)) {
- pr_debug(" * %s missing min-residency-us property\n",
- state_node->full_name);
- return -EINVAL;
- }
-
- el = kmalloc(sizeof(*el), GFP_KERNEL);
- if (!el) {
- pr_err("%s failed to allocate memory\n", __func__);
- return -ENOMEM;
- }
-
- el->node = state_node;
- el->val = val;
- list_add_tail(&el->list, &head);
-
- return 0;
-}
-
-static void __init init_state_node(struct cpuidle_driver *drv,
- struct device_node *state_node,
- int *cnt)
-{
- struct cpuidle_state *idle_state;
-
- pr_debug(" * %s...\n", state_node->full_name);
-
- idle_state = &drv->states[*cnt];
-
- if (of_property_read_u32(state_node, "exit-latency-us",
- &idle_state->exit_latency)) {
- pr_debug(" * %s missing exit-latency-us property\n",
- state_node->full_name);
- return;
- }
-
- if (of_property_read_u32(state_node, "min-residency-us",
- &idle_state->target_residency)) {
- pr_debug(" * %s missing min-residency-us property\n",
- state_node->full_name);
- return;
- }
- /*
- * It is unknown to the idle driver if and when the tick_device
- * loses context when the CPU enters the idle states. To solve
- * this issue the tick device must be linked to a power domain
- * so that the idle driver can check on which states the device
- * loses its context. Current code takes the conservative choice
- * of defining the idle state as one where the tick device always
- * loses its context. On platforms where tick device never loses
- * its context (ie it is not a C3STOP device) this turns into
- * a nop. On platforms where the tick device does lose context in some
- * states, this code can be optimized, when power domain specifications
- * for ARM CPUs are finalized.
- */
- idle_state->flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TIMER_STOP;
-
- strncpy(idle_state->name, state_node->name, CPUIDLE_NAME_LEN);
- strncpy(idle_state->desc, state_node->name, CPUIDLE_NAME_LEN);
-
- (*cnt)++;
-}
-
-static int __init init_idle_states(struct cpuidle_driver *drv,
- struct device_node *state_nodes[],
- unsigned int start_idx, bool init_nodes)
-{
- struct state_elem *el;
- struct list_head *curr, *tmp;
- unsigned int cnt = start_idx;
-
- list_for_each_entry(el, &head, list) {
- /*
- * Check if the init function has to fill the
- * state_nodes array on behalf of the CPUidle driver.
- */
- if (init_nodes)
- state_nodes[cnt] = el->node;
- /*
- * cnt is updated on return if a state was added.
- */
- init_state_node(drv, el->node, &cnt);
-
- if (cnt == CPUIDLE_STATE_MAX) {
- pr_warn("State index reached static CPU idle state limit\n");
- break;
- }
- }
-
- drv->state_count = cnt;
-
- list_for_each_safe(curr, tmp, &head) {
- list_del(curr);
- kfree(container_of(curr, struct state_elem, list));
- }
-
- /*
- * If no idle states are detected, return an error and let the idle
- * driver initialization fail accordingly.
- */
- return (cnt > start_idx) ? 0 : -ENODATA;
-}
-
-static void __init add_idle_states(struct cpuidle_driver *drv,
- struct device_node *idle_states)
-{
- struct device_node *state_node;
-
- for_each_child_of_node(idle_states, state_node) {
- if ((!of_device_is_compatible(state_node, "arm,idle-state"))) {
- pr_warn(" * %s: children of /cpus/idle-states must be \"arm,idle-state\" compatible\n",
- state_node->full_name);
- continue;
- }
- /*
- * If memory allocation fails, better bail out.
- * Initialized nodes are freed at initialization
- * completion in of_init_idle_driver().
- */
- if ((add_state_node(drv->cpumask, state_node) == -ENOMEM))
- break;
- }
- /*
- * Sort the states list before initializing the CPUidle driver
- * states array.
- */
- list_sort(NULL, &head, state_cmp);
-}
-
-/*
- * of_init_idle_driver - Parse the DT idle states and initialize the
- * idle driver states array
- *
- * @drv: Pointer to CPU idle driver to be initialized
- * @state_nodes: Array of struct device_nodes to be initialized if
- * init_nodes == true. Must be sized CPUIDLE_STATE_MAX
- * @start_idx: First idle state index to be initialized
- * @init_nodes: Boolean to request device nodes initialization
- *
- * Returns:
- * 0 on success
- * <0 on failure
- *
- * On success the states array in the cpuidle driver contains
- * initialized entries in the states array, starting from index start_idx.
- * If init_nodes == true, on success the state_nodes array is initialized
- * with idle state DT node pointers, starting from index start_idx,
- * in a 1:1 relation with the idle driver states array.
- */
-int __init of_init_idle_driver(struct cpuidle_driver *drv,
- struct device_node *state_nodes[],
- unsigned int start_idx, bool init_nodes)
-{
- struct device_node *idle_states_node;
- int ret;
-
- if (start_idx >= CPUIDLE_STATE_MAX) {
- pr_warn("State index exceeds static CPU idle driver states array size\n");
- return -EINVAL;
- }
-
- if (WARN(init_nodes && !state_nodes,
- "Requested nodes stashing in an invalid nodes container\n"))
- return -EINVAL;
-
- idle_states_node = of_find_node_by_path("/cpus/idle-states");
- if (!idle_states_node)
- return -ENOENT;
-
- add_idle_states(drv, idle_states_node);
-
- ret = init_idle_states(drv, state_nodes, start_idx, init_nodes);
-
- of_node_put(idle_states_node);
-
- return ret;
-}
diff --git a/drivers/cpuidle/of_idle_states.h b/drivers/cpuidle/of_idle_states.h
deleted file mode 100644
index 049f94ff4428..000000000000
--- a/drivers/cpuidle/of_idle_states.h
+++ /dev/null
@@ -1,8 +0,0 @@
-#ifndef __OF_IDLE_STATES
-#define __OF_IDLE_STATES
-
-int __init of_init_idle_driver(struct cpuidle_driver *drv,
- struct device_node *state_nodes[],
- unsigned int start_idx,
- bool init_nodes);
-#endif