aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/base/power/domain.c38
-rw-r--r--drivers/cpuidle/coupled.c22
-rw-r--r--drivers/cpuidle/cpuidle.h6
-rw-r--r--drivers/cpuidle/driver.c4
-rw-r--r--drivers/staging/board/armadillo800eva.c2
-rw-r--r--drivers/staging/board/board.c36
-rw-r--r--kernel/cpu_pm.c2
7 files changed, 94 insertions, 16 deletions
diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c
index 416720159e96..16550c63d611 100644
--- a/drivers/base/power/domain.c
+++ b/drivers/base/power/domain.c
@@ -213,6 +213,18 @@ static int genpd_power_off(struct generic_pm_domain *genpd, bool timed)
213} 213}
214 214
215/** 215/**
216 * genpd_queue_power_off_work - Queue up the execution of pm_genpd_poweroff().
217 * @genpd: PM domait to power off.
218 *
219 * Queue up the execution of pm_genpd_poweroff() unless it's already been done
220 * before.
221 */
222static void genpd_queue_power_off_work(struct generic_pm_domain *genpd)
223{
224 queue_work(pm_wq, &genpd->power_off_work);
225}
226
227/**
216 * __pm_genpd_poweron - Restore power to a given PM domain and its masters. 228 * __pm_genpd_poweron - Restore power to a given PM domain and its masters.
217 * @genpd: PM domain to power up. 229 * @genpd: PM domain to power up.
218 * 230 *
@@ -259,8 +271,12 @@ static int __pm_genpd_poweron(struct generic_pm_domain *genpd)
259 return 0; 271 return 0;
260 272
261 err: 273 err:
262 list_for_each_entry_continue_reverse(link, &genpd->slave_links, slave_node) 274 list_for_each_entry_continue_reverse(link,
275 &genpd->slave_links,
276 slave_node) {
263 genpd_sd_counter_dec(link->master); 277 genpd_sd_counter_dec(link->master);
278 genpd_queue_power_off_work(link->master);
279 }
264 280
265 return ret; 281 return ret;
266} 282}
@@ -349,18 +365,6 @@ static int genpd_dev_pm_qos_notifier(struct notifier_block *nb,
349} 365}
350 366
351/** 367/**
352 * genpd_queue_power_off_work - Queue up the execution of pm_genpd_poweroff().
353 * @genpd: PM domait to power off.
354 *
355 * Queue up the execution of pm_genpd_poweroff() unless it's already been done
356 * before.
357 */
358static void genpd_queue_power_off_work(struct generic_pm_domain *genpd)
359{
360 queue_work(pm_wq, &genpd->power_off_work);
361}
362
363/**
364 * pm_genpd_poweroff - Remove power from a given PM domain. 368 * pm_genpd_poweroff - Remove power from a given PM domain.
365 * @genpd: PM domain to power down. 369 * @genpd: PM domain to power down.
366 * 370 *
@@ -1469,6 +1473,13 @@ int pm_genpd_remove_subdomain(struct generic_pm_domain *genpd,
1469 1473
1470 mutex_lock(&genpd->lock); 1474 mutex_lock(&genpd->lock);
1471 1475
1476 if (!list_empty(&subdomain->slave_links) || subdomain->device_count) {
1477 pr_warn("%s: unable to remove subdomain %s\n", genpd->name,
1478 subdomain->name);
1479 ret = -EBUSY;
1480 goto out;
1481 }
1482
1472 list_for_each_entry(link, &genpd->master_links, master_node) { 1483 list_for_each_entry(link, &genpd->master_links, master_node) {
1473 if (link->slave != subdomain) 1484 if (link->slave != subdomain)
1474 continue; 1485 continue;
@@ -1487,6 +1498,7 @@ int pm_genpd_remove_subdomain(struct generic_pm_domain *genpd,
1487 break; 1498 break;
1488 } 1499 }
1489 1500
1501out:
1490 mutex_unlock(&genpd->lock); 1502 mutex_unlock(&genpd->lock);
1491 1503
1492 return ret; 1504 return ret;
diff --git a/drivers/cpuidle/coupled.c b/drivers/cpuidle/coupled.c
index 1523e2d745eb..344058f8501a 100644
--- a/drivers/cpuidle/coupled.c
+++ b/drivers/cpuidle/coupled.c
@@ -187,6 +187,28 @@ bool cpuidle_state_is_coupled(struct cpuidle_driver *drv, int state)
187} 187}
188 188
189/** 189/**
190 * cpuidle_coupled_state_verify - check if the coupled states are correctly set.
191 * @drv: struct cpuidle_driver for the platform
192 *
193 * Returns 0 for valid state values, a negative error code otherwise:
194 * * -EINVAL if any coupled state(safe_state_index) is wrongly set.
195 */
196int cpuidle_coupled_state_verify(struct cpuidle_driver *drv)
197{
198 int i;
199
200 for (i = drv->state_count - 1; i >= 0; i--) {
201 if (cpuidle_state_is_coupled(drv, i) &&
202 (drv->safe_state_index == i ||
203 drv->safe_state_index < 0 ||
204 drv->safe_state_index >= drv->state_count))
205 return -EINVAL;
206 }
207
208 return 0;
209}
210
211/**
190 * cpuidle_coupled_set_ready - mark a cpu as ready 212 * cpuidle_coupled_set_ready - mark a cpu as ready
191 * @coupled: the struct coupled that contains the current cpu 213 * @coupled: the struct coupled that contains the current cpu
192 */ 214 */
diff --git a/drivers/cpuidle/cpuidle.h b/drivers/cpuidle/cpuidle.h
index 178c5ad3d568..f87f399b0540 100644
--- a/drivers/cpuidle/cpuidle.h
+++ b/drivers/cpuidle/cpuidle.h
@@ -35,6 +35,7 @@ extern void cpuidle_remove_sysfs(struct cpuidle_device *dev);
35 35
36#ifdef CONFIG_ARCH_NEEDS_CPU_IDLE_COUPLED 36#ifdef CONFIG_ARCH_NEEDS_CPU_IDLE_COUPLED
37bool cpuidle_state_is_coupled(struct cpuidle_driver *drv, int state); 37bool cpuidle_state_is_coupled(struct cpuidle_driver *drv, int state);
38int cpuidle_coupled_state_verify(struct cpuidle_driver *drv);
38int cpuidle_enter_state_coupled(struct cpuidle_device *dev, 39int cpuidle_enter_state_coupled(struct cpuidle_device *dev,
39 struct cpuidle_driver *drv, int next_state); 40 struct cpuidle_driver *drv, int next_state);
40int cpuidle_coupled_register_device(struct cpuidle_device *dev); 41int cpuidle_coupled_register_device(struct cpuidle_device *dev);
@@ -46,6 +47,11 @@ bool cpuidle_state_is_coupled(struct cpuidle_driver *drv, int state)
46 return false; 47 return false;
47} 48}
48 49
50static inline int cpuidle_coupled_state_verify(struct cpuidle_driver *drv)
51{
52 return 0;
53}
54
49static inline int cpuidle_enter_state_coupled(struct cpuidle_device *dev, 55static inline int cpuidle_enter_state_coupled(struct cpuidle_device *dev,
50 struct cpuidle_driver *drv, int next_state) 56 struct cpuidle_driver *drv, int next_state)
51{ 57{
diff --git a/drivers/cpuidle/driver.c b/drivers/cpuidle/driver.c
index 5db147859b90..389ade4572be 100644
--- a/drivers/cpuidle/driver.c
+++ b/drivers/cpuidle/driver.c
@@ -227,6 +227,10 @@ static int __cpuidle_register_driver(struct cpuidle_driver *drv)
227 if (!drv || !drv->state_count) 227 if (!drv || !drv->state_count)
228 return -EINVAL; 228 return -EINVAL;
229 229
230 ret = cpuidle_coupled_state_verify(drv);
231 if (ret)
232 return ret;
233
230 if (cpuidle_disabled()) 234 if (cpuidle_disabled())
231 return -ENODEV; 235 return -ENODEV;
232 236
diff --git a/drivers/staging/board/armadillo800eva.c b/drivers/staging/board/armadillo800eva.c
index 81df77bd55cc..9c41652ee908 100644
--- a/drivers/staging/board/armadillo800eva.c
+++ b/drivers/staging/board/armadillo800eva.c
@@ -91,7 +91,7 @@ static const struct board_staging_dev armadillo800eva_devices[] __initconst = {
91 .pdev = &lcdc0_device, 91 .pdev = &lcdc0_device,
92 .clocks = lcdc0_clocks, 92 .clocks = lcdc0_clocks,
93 .nclocks = ARRAY_SIZE(lcdc0_clocks), 93 .nclocks = ARRAY_SIZE(lcdc0_clocks),
94 .domain = "a4lc", 94 .domain = "/system-controller@e6180000/pm-domains/c5/a4lc@1"
95 }, 95 },
96}; 96};
97 97
diff --git a/drivers/staging/board/board.c b/drivers/staging/board/board.c
index 29d456e29f38..3eb5eb8f069c 100644
--- a/drivers/staging/board/board.c
+++ b/drivers/staging/board/board.c
@@ -135,6 +135,40 @@ int __init board_staging_register_clock(const struct board_staging_clk *bsc)
135 return error; 135 return error;
136} 136}
137 137
138#ifdef CONFIG_PM_GENERIC_DOMAINS_OF
139static int board_staging_add_dev_domain(struct platform_device *pdev,
140 const char *domain)
141{
142 struct of_phandle_args pd_args;
143 struct generic_pm_domain *pd;
144 struct device_node *np;
145
146 np = of_find_node_by_path(domain);
147 if (!np) {
148 pr_err("Cannot find domain node %s\n", domain);
149 return -ENOENT;
150 }
151
152 pd_args.np = np;
153 pd_args.args_count = 0;
154 pd = of_genpd_get_from_provider(&pd_args);
155 if (IS_ERR(pd)) {
156 pr_err("Cannot find genpd %s (%ld)\n", domain, PTR_ERR(pd));
157 return PTR_ERR(pd);
158
159 }
160 pr_debug("Found genpd %s for device %s\n", pd->name, pdev->name);
161
162 return pm_genpd_add_device(pd, &pdev->dev);
163}
164#else
165static inline int board_staging_add_dev_domain(struct platform_device *pdev,
166 const char *domain)
167{
168 return 0;
169}
170#endif
171
138int __init board_staging_register_device(const struct board_staging_dev *dev) 172int __init board_staging_register_device(const struct board_staging_dev *dev)
139{ 173{
140 struct platform_device *pdev = dev->pdev; 174 struct platform_device *pdev = dev->pdev;
@@ -161,7 +195,7 @@ int __init board_staging_register_device(const struct board_staging_dev *dev)
161 } 195 }
162 196
163 if (dev->domain) 197 if (dev->domain)
164 __pm_genpd_name_add_device(dev->domain, &pdev->dev, NULL); 198 board_staging_add_dev_domain(pdev, dev->domain);
165 199
166 return error; 200 return error;
167} 201}
diff --git a/kernel/cpu_pm.c b/kernel/cpu_pm.c
index 9656a3c36503..009cc9a17d95 100644
--- a/kernel/cpu_pm.c
+++ b/kernel/cpu_pm.c
@@ -180,7 +180,7 @@ EXPORT_SYMBOL_GPL(cpu_cluster_pm_enter);
180 * low power state that may have caused some blocks in the same power domain 180 * low power state that may have caused some blocks in the same power domain
181 * to reset. 181 * to reset.
182 * 182 *
183 * Must be called after cpu_pm_exit has been called on all cpus in the power 183 * Must be called after cpu_cluster_pm_enter has been called for the power
184 * domain, and before cpu_pm_exit has been called on any cpu in the power 184 * domain, and before cpu_pm_exit has been called on any cpu in the power
185 * domain. Notified drivers can include VFP co-processor, interrupt controller 185 * domain. Notified drivers can include VFP co-processor, interrupt controller
186 * and its PM extensions, local CPU timers context save/restore which 186 * and its PM extensions, local CPU timers context save/restore which