aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLeo Yan <leo.yan@linaro.org>2017-10-10 01:47:56 -0400
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>2017-10-13 19:01:11 -0400
commit7943bfaeb6bbbf595df4bd4087f5b890761c4898 (patch)
tree33bc6cbc6f66778cf4445363520813346983827e
parent0f87855d969a87f02048ff5ced7503465d5ab2f1 (diff)
ARM: cpuidle: Refactor rollback operations if init fails
If init fails, we need execute two levels rollback operations: the first level is for the failed CPU rollback operations, the second level is to iterate all succeeded CPUs to cancel their registration; currently the code uses one function to finish these two levels rollback operations. This commit is to refactor rollback operations, so it adds a new function arm_idle_init_cpu() to encapsulate one specified CPU driver registration and rollback the first level operations; and use function arm_idle_init() to iterate all CPUs and finish the second level's rollback operations. Suggested-by: Daniel Lezcano <daniel.lezcano@linaro.org> Signed-off-by: Leo Yan <leo.yan@linaro.org> Acked-by: Daniel Lezcano <daniel.lezcano@linaro.org> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
-rw-r--r--drivers/cpuidle/cpuidle-arm.c145
1 files changed, 82 insertions, 63 deletions
diff --git a/drivers/cpuidle/cpuidle-arm.c b/drivers/cpuidle/cpuidle-arm.c
index f47c54546752..ddee1b601b89 100644
--- a/drivers/cpuidle/cpuidle-arm.c
+++ b/drivers/cpuidle/cpuidle-arm.c
@@ -72,79 +72,74 @@ static const struct of_device_id arm_idle_state_match[] __initconst = {
72}; 72};
73 73
74/* 74/*
75 * arm_idle_init 75 * arm_idle_init_cpu
76 * 76 *
77 * Registers the arm specific cpuidle driver with the cpuidle 77 * Registers the arm specific cpuidle driver with the cpuidle
78 * framework. It relies on core code to parse the idle states 78 * framework. It relies on core code to parse the idle states
79 * and initialize them using driver data structures accordingly. 79 * and initialize them using driver data structures accordingly.
80 */ 80 */
81static int __init arm_idle_init(void) 81static int __init arm_idle_init_cpu(int cpu)
82{ 82{
83 int cpu, ret; 83 int ret;
84 struct cpuidle_driver *drv; 84 struct cpuidle_driver *drv;
85 struct cpuidle_device *dev; 85 struct cpuidle_device *dev;
86 86
87 for_each_possible_cpu(cpu) { 87 drv = kmemdup(&arm_idle_driver, sizeof(*drv), GFP_KERNEL);
88 if (!drv)
89 return -ENOMEM;
88 90
89 drv = kmemdup(&arm_idle_driver, sizeof(*drv), GFP_KERNEL); 91 drv->cpumask = (struct cpumask *)cpumask_of(cpu);
90 if (!drv) { 92
91 ret = -ENOMEM; 93 /*
92 goto out_fail; 94 * Initialize idle states data, starting at index 1. This
93 } 95 * driver is DT only, if no DT idle states are detected (ret
94 96 * == 0) let the driver initialization fail accordingly since
95 drv->cpumask = (struct cpumask *)cpumask_of(cpu); 97 * there is no reason to initialize the idle driver if only
96 98 * wfi is supported.
97 /* 99 */
98 * Initialize idle states data, starting at index 1. This 100 ret = dt_init_idle_driver(drv, arm_idle_state_match, 1);
99 * driver is DT only, if no DT idle states are detected (ret 101 if (ret <= 0) {
100 * == 0) let the driver initialization fail accordingly since 102 ret = ret ? : -ENODEV;
101 * there is no reason to initialize the idle driver if only 103 goto out_kfree_drv;
102 * wfi is supported. 104 }
103 */ 105
104 ret = dt_init_idle_driver(drv, arm_idle_state_match, 1); 106 ret = cpuidle_register_driver(drv);
105 if (ret <= 0) { 107 if (ret) {
106 ret = ret ? : -ENODEV; 108 pr_err("Failed to register cpuidle driver\n");
107 goto out_kfree_drv; 109 goto out_kfree_drv;
108 } 110 }
109 111
110 ret = cpuidle_register_driver(drv); 112 /*
111 if (ret) { 113 * Call arch CPU operations in order to initialize
112 pr_err("Failed to register cpuidle driver\n"); 114 * idle states suspend back-end specific data
113 goto out_kfree_drv; 115 */
114 } 116 ret = arm_cpuidle_init(cpu);
115 117
116 /* 118 /*
117 * Call arch CPU operations in order to initialize 119 * Skip the cpuidle device initialization if the reported
118 * idle states suspend back-end specific data 120 * failure is a HW misconfiguration/breakage (-ENXIO).
119 */ 121 */
120 ret = arm_cpuidle_init(cpu); 122 if (ret == -ENXIO)
121 123 return 0;
122 /* 124
123 * Skip the cpuidle device initialization if the reported 125 if (ret) {
124 * failure is a HW misconfiguration/breakage (-ENXIO). 126 pr_err("CPU %d failed to init idle CPU ops\n", cpu);
125 */ 127 goto out_unregister_drv;
126 if (ret == -ENXIO) 128 }
127 continue; 129
128 130 dev = kzalloc(sizeof(*dev), GFP_KERNEL);
129 if (ret) { 131 if (!dev) {
130 pr_err("CPU %d failed to init idle CPU ops\n", cpu); 132 pr_err("Failed to allocate cpuidle device\n");
131 goto out_unregister_drv; 133 ret = -ENOMEM;
132 } 134 goto out_unregister_drv;
133 135 }
134 dev = kzalloc(sizeof(*dev), GFP_KERNEL); 136 dev->cpu = cpu;
135 if (!dev) { 137
136 pr_err("Failed to allocate cpuidle device\n"); 138 ret = cpuidle_register_device(dev);
137 ret = -ENOMEM; 139 if (ret) {
138 goto out_unregister_drv; 140 pr_err("Failed to register cpuidle device for CPU %d\n",
139 } 141 cpu);
140 dev->cpu = cpu; 142 goto out_kfree_dev;
141
142 ret = cpuidle_register_device(dev);
143 if (ret) {
144 pr_err("Failed to register cpuidle device for CPU %d\n",
145 cpu);
146 goto out_kfree_dev;
147 }
148 } 143 }
149 144
150 return 0; 145 return 0;
@@ -155,6 +150,30 @@ out_unregister_drv:
155 cpuidle_unregister_driver(drv); 150 cpuidle_unregister_driver(drv);
156out_kfree_drv: 151out_kfree_drv:
157 kfree(drv); 152 kfree(drv);
153 return ret;
154}
155
156/*
157 * arm_idle_init - Initializes arm cpuidle driver
158 *
159 * Initializes arm cpuidle driver for all CPUs, if any CPU fails
160 * to register cpuidle driver then rollback to cancel all CPUs
161 * registeration.
162 */
163static int __init arm_idle_init(void)
164{
165 int cpu, ret;
166 struct cpuidle_driver *drv;
167 struct cpuidle_device *dev;
168
169 for_each_possible_cpu(cpu) {
170 ret = arm_idle_init_cpu(cpu);
171 if (ret)
172 goto out_fail;
173 }
174
175 return 0;
176
158out_fail: 177out_fail:
159 while (--cpu >= 0) { 178 while (--cpu >= 0) {
160 dev = per_cpu(cpuidle_devices, cpu); 179 dev = per_cpu(cpuidle_devices, cpu);