diff options
-rw-r--r-- | arch/arm/include/asm/cpuidle.h | 21 | ||||
-rw-r--r-- | arch/arm/kernel/cpuidle.c | 72 | ||||
-rw-r--r-- | arch/arm64/include/asm/cpuidle.h | 5 | ||||
-rw-r--r-- | include/asm-generic/vmlinux.lds.h | 2 |
4 files changed, 99 insertions, 1 deletions
diff --git a/arch/arm/include/asm/cpuidle.h b/arch/arm/include/asm/cpuidle.h index 348dc817b9f3..0f8424924902 100644 --- a/arch/arm/include/asm/cpuidle.h +++ b/arch/arm/include/asm/cpuidle.h | |||
@@ -27,4 +27,25 @@ static inline int arm_cpuidle_simple_enter(struct cpuidle_device *dev, | |||
27 | */ | 27 | */ |
28 | #define ARM_CPUIDLE_WFI_STATE ARM_CPUIDLE_WFI_STATE_PWR(UINT_MAX) | 28 | #define ARM_CPUIDLE_WFI_STATE ARM_CPUIDLE_WFI_STATE_PWR(UINT_MAX) |
29 | 29 | ||
30 | struct device_node; | ||
31 | |||
32 | struct cpuidle_ops { | ||
33 | int (*suspend)(int cpu, unsigned long arg); | ||
34 | int (*init)(struct device_node *, int cpu); | ||
35 | }; | ||
36 | |||
37 | struct of_cpuidle_method { | ||
38 | const char *method; | ||
39 | struct cpuidle_ops *ops; | ||
40 | }; | ||
41 | |||
42 | #define CPUIDLE_METHOD_OF_DECLARE(name, _method, _ops) \ | ||
43 | static const struct of_cpuidle_method __cpuidle_method_of_table_##name \ | ||
44 | __used __section(__cpuidle_method_of_table) \ | ||
45 | = { .method = _method, .ops = _ops } | ||
46 | |||
47 | extern int arm_cpuidle_suspend(int index); | ||
48 | |||
49 | extern int arm_cpuidle_init(int cpu); | ||
50 | |||
30 | #endif | 51 | #endif |
diff --git a/arch/arm/kernel/cpuidle.c b/arch/arm/kernel/cpuidle.c index 45969f89f05c..2b0dae3cd058 100644 --- a/arch/arm/kernel/cpuidle.c +++ b/arch/arm/kernel/cpuidle.c | |||
@@ -10,8 +10,17 @@ | |||
10 | */ | 10 | */ |
11 | 11 | ||
12 | #include <linux/cpuidle.h> | 12 | #include <linux/cpuidle.h> |
13 | #include <linux/of.h> | ||
14 | #include <linux/of_device.h> | ||
13 | #include <asm/cpuidle.h> | 15 | #include <asm/cpuidle.h> |
14 | 16 | ||
17 | extern struct of_cpuidle_method __cpuidle_method_of_table[]; | ||
18 | |||
19 | static const struct of_cpuidle_method __cpuidle_method_of_table_sentinel | ||
20 | __used __section(__cpuidle_method_of_table_end); | ||
21 | |||
22 | static struct cpuidle_ops cpuidle_ops[NR_CPUS]; | ||
23 | |||
15 | int arm_cpuidle_simple_enter(struct cpuidle_device *dev, | 24 | int arm_cpuidle_simple_enter(struct cpuidle_device *dev, |
16 | struct cpuidle_driver *drv, int index) | 25 | struct cpuidle_driver *drv, int index) |
17 | { | 26 | { |
@@ -19,3 +28,66 @@ int arm_cpuidle_simple_enter(struct cpuidle_device *dev, | |||
19 | 28 | ||
20 | return index; | 29 | return index; |
21 | } | 30 | } |
31 | |||
32 | int arm_cpuidle_suspend(int index) | ||
33 | { | ||
34 | int ret = -EOPNOTSUPP; | ||
35 | int cpu = smp_processor_id(); | ||
36 | |||
37 | if (cpuidle_ops[cpu].suspend) | ||
38 | ret = cpuidle_ops[cpu].suspend(cpu, index); | ||
39 | |||
40 | return ret; | ||
41 | } | ||
42 | |||
43 | static struct cpuidle_ops *__init arm_cpuidle_get_ops(const char *method) | ||
44 | { | ||
45 | struct of_cpuidle_method *m = __cpuidle_method_of_table; | ||
46 | |||
47 | for (; m->method; m++) | ||
48 | if (!strcmp(m->method, method)) | ||
49 | return m->ops; | ||
50 | |||
51 | return NULL; | ||
52 | } | ||
53 | |||
54 | static int __init arm_cpuidle_read_ops(struct device_node *dn, int cpu) | ||
55 | { | ||
56 | const char *enable_method; | ||
57 | struct cpuidle_ops *ops; | ||
58 | |||
59 | enable_method = of_get_property(dn, "enable-method", NULL); | ||
60 | if (!enable_method) | ||
61 | return -ENOENT; | ||
62 | |||
63 | ops = arm_cpuidle_get_ops(enable_method); | ||
64 | if (!ops) { | ||
65 | pr_warn("%s: unsupported enable-method property: %s\n", | ||
66 | dn->full_name, enable_method); | ||
67 | return -EOPNOTSUPP; | ||
68 | } | ||
69 | |||
70 | cpuidle_ops[cpu] = *ops; /* structure copy */ | ||
71 | |||
72 | pr_notice("cpuidle: enable-method property '%s'" | ||
73 | " found operations\n", enable_method); | ||
74 | |||
75 | return 0; | ||
76 | } | ||
77 | |||
78 | int __init arm_cpuidle_init(int cpu) | ||
79 | { | ||
80 | struct device_node *cpu_node = of_cpu_device_node_get(cpu); | ||
81 | int ret; | ||
82 | |||
83 | if (!cpu_node) | ||
84 | return -ENODEV; | ||
85 | |||
86 | ret = arm_cpuidle_read_ops(cpu_node, cpu); | ||
87 | if (!ret && cpuidle_ops[cpu].init) | ||
88 | ret = cpuidle_ops[cpu].init(cpu_node, cpu); | ||
89 | |||
90 | of_node_put(cpu_node); | ||
91 | |||
92 | return ret; | ||
93 | } | ||
diff --git a/arch/arm64/include/asm/cpuidle.h b/arch/arm64/include/asm/cpuidle.h index c60643f14cda..460a38bb84b9 100644 --- a/arch/arm64/include/asm/cpuidle.h +++ b/arch/arm64/include/asm/cpuidle.h | |||
@@ -17,5 +17,8 @@ static inline int cpu_suspend(unsigned long arg) | |||
17 | return -EOPNOTSUPP; | 17 | return -EOPNOTSUPP; |
18 | } | 18 | } |
19 | #endif | 19 | #endif |
20 | 20 | static inline int arm_cpuidle_suspend(int index) | |
21 | { | ||
22 | return cpu_suspend(index); | ||
23 | } | ||
21 | #endif | 24 | #endif |
diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h index ac78910d7416..91c09305106d 100644 --- a/include/asm-generic/vmlinux.lds.h +++ b/include/asm-generic/vmlinux.lds.h | |||
@@ -167,6 +167,7 @@ | |||
167 | #define IOMMU_OF_TABLES() OF_TABLE(CONFIG_OF_IOMMU, iommu) | 167 | #define IOMMU_OF_TABLES() OF_TABLE(CONFIG_OF_IOMMU, iommu) |
168 | #define RESERVEDMEM_OF_TABLES() OF_TABLE(CONFIG_OF_RESERVED_MEM, reservedmem) | 168 | #define RESERVEDMEM_OF_TABLES() OF_TABLE(CONFIG_OF_RESERVED_MEM, reservedmem) |
169 | #define CPU_METHOD_OF_TABLES() OF_TABLE(CONFIG_SMP, cpu_method) | 169 | #define CPU_METHOD_OF_TABLES() OF_TABLE(CONFIG_SMP, cpu_method) |
170 | #define CPUIDLE_METHOD_OF_TABLES() OF_TABLE(CONFIG_CPU_IDLE, cpuidle_method) | ||
170 | #define EARLYCON_OF_TABLES() OF_TABLE(CONFIG_SERIAL_EARLYCON, earlycon) | 171 | #define EARLYCON_OF_TABLES() OF_TABLE(CONFIG_SERIAL_EARLYCON, earlycon) |
171 | 172 | ||
172 | #define KERNEL_DTB() \ | 173 | #define KERNEL_DTB() \ |
@@ -501,6 +502,7 @@ | |||
501 | CLKSRC_OF_TABLES() \ | 502 | CLKSRC_OF_TABLES() \ |
502 | IOMMU_OF_TABLES() \ | 503 | IOMMU_OF_TABLES() \ |
503 | CPU_METHOD_OF_TABLES() \ | 504 | CPU_METHOD_OF_TABLES() \ |
505 | CPUIDLE_METHOD_OF_TABLES() \ | ||
504 | KERNEL_DTB() \ | 506 | KERNEL_DTB() \ |
505 | IRQCHIP_OF_MATCH_TABLE() \ | 507 | IRQCHIP_OF_MATCH_TABLE() \ |
506 | EARLYCON_OF_TABLES() | 508 | EARLYCON_OF_TABLES() |