1212#include <linux/cpu.h>
1313#include <linux/device.h>
1414#include <linux/kernel.h>
15+ #include <linux/platform_device.h>
1516#include <linux/pm_domain.h>
1617#include <linux/pm_runtime.h>
1718#include <linux/psci.h>
@@ -26,7 +27,7 @@ struct psci_pd_provider {
2627};
2728
2829static LIST_HEAD (psci_pd_providers );
29- static bool osi_mode_enabled __initdata ;
30+ static bool psci_pd_allow_domain_state ;
3031
3132static int psci_pd_power_off (struct generic_pm_domain * pd )
3233{
@@ -36,15 +37,18 @@ static int psci_pd_power_off(struct generic_pm_domain *pd)
3637 if (!state -> data )
3738 return 0 ;
3839
40+ if (!psci_pd_allow_domain_state )
41+ return - EBUSY ;
42+
3943 /* OSI mode is enabled, set the corresponding domain state. */
4044 pd_state = state -> data ;
4145 psci_set_domain_state (* pd_state );
4246
4347 return 0 ;
4448}
4549
46- static int __init psci_pd_parse_state_nodes (struct genpd_power_state * states ,
47- int state_count )
50+ static int psci_pd_parse_state_nodes (struct genpd_power_state * states ,
51+ int state_count )
4852{
4953 int i , ret ;
5054 u32 psci_state , * psci_state_buf ;
@@ -73,7 +77,7 @@ static int __init psci_pd_parse_state_nodes(struct genpd_power_state *states,
7377 return ret ;
7478}
7579
76- static int __init psci_pd_parse_states (struct device_node * np ,
80+ static int psci_pd_parse_states (struct device_node * np ,
7781 struct genpd_power_state * * states , int * state_count )
7882{
7983 int ret ;
@@ -101,7 +105,7 @@ static void psci_pd_free_states(struct genpd_power_state *states,
101105 kfree (states );
102106}
103107
104- static int __init psci_pd_init (struct device_node * np )
108+ static int psci_pd_init (struct device_node * np )
105109{
106110 struct generic_pm_domain * pd ;
107111 struct psci_pd_provider * pd_provider ;
@@ -168,7 +172,7 @@ static int __init psci_pd_init(struct device_node *np)
168172 return ret ;
169173}
170174
171- static void __init psci_pd_remove (void )
175+ static void psci_pd_remove (void )
172176{
173177 struct psci_pd_provider * pd_provider , * it ;
174178 struct generic_pm_domain * genpd ;
@@ -186,7 +190,7 @@ static void __init psci_pd_remove(void)
186190 }
187191}
188192
189- static int __init psci_pd_init_topology (struct device_node * np , bool add )
193+ static int psci_pd_init_topology (struct device_node * np , bool add )
190194{
191195 struct device_node * node ;
192196 struct of_phandle_args child , parent ;
@@ -212,24 +216,33 @@ static int __init psci_pd_init_topology(struct device_node *np, bool add)
212216 return 0 ;
213217}
214218
215- static int __init psci_pd_add_topology (struct device_node * np )
219+ static int psci_pd_add_topology (struct device_node * np )
216220{
217221 return psci_pd_init_topology (np , true);
218222}
219223
220- static void __init psci_pd_remove_topology (struct device_node * np )
224+ static void psci_pd_remove_topology (struct device_node * np )
221225{
222226 psci_pd_init_topology (np , false);
223227}
224228
225- static const struct of_device_id psci_of_match [] __initconst = {
229+ static void psci_cpuidle_domain_sync_state (struct device * dev )
230+ {
231+ /*
232+ * All devices have now been attached/probed to the PM domain topology,
233+ * hence it's fine to allow domain states to be picked.
234+ */
235+ psci_pd_allow_domain_state = true;
236+ }
237+
238+ static const struct of_device_id psci_of_match [] = {
226239 { .compatible = "arm,psci-1.0" },
227240 {}
228241};
229242
230- static int __init psci_idle_init_domains ( void )
243+ static int psci_cpuidle_domain_probe ( struct platform_device * pdev )
231244{
232- struct device_node * np = of_find_matching_node ( NULL , psci_of_match ) ;
245+ struct device_node * np = pdev -> dev . of_node ;
233246 struct device_node * node ;
234247 int ret = 0 , pd_count = 0 ;
235248
@@ -238,7 +251,7 @@ static int __init psci_idle_init_domains(void)
238251
239252 /* Currently limit the hierarchical topology to be used in OSI mode. */
240253 if (!psci_has_osi_support ())
241- goto out ;
254+ return 0 ;
242255
243256 /*
244257 * Parse child nodes for the "#power-domain-cells" property and
@@ -257,7 +270,7 @@ static int __init psci_idle_init_domains(void)
257270
258271 /* Bail out if not using the hierarchical CPU topology. */
259272 if (!pd_count )
260- goto out ;
273+ return 0 ;
261274
262275 /* Link genpd masters/subdomains to model the CPU topology. */
263276 ret = psci_pd_add_topology (np );
@@ -272,30 +285,37 @@ static int __init psci_idle_init_domains(void)
272285 goto remove_pd ;
273286 }
274287
275- osi_mode_enabled = true;
276- of_node_put (np );
277288 pr_info ("Initialized CPU PM domain topology\n" );
278- return pd_count ;
289+ return 0 ;
279290
280291put_node :
281292 of_node_put (node );
282293remove_pd :
283294 if (pd_count )
284295 psci_pd_remove ();
285296 pr_err ("failed to create CPU PM domains ret=%d\n" , ret );
286- out :
287- of_node_put (np );
288297 return ret ;
289298}
299+
300+ static struct platform_driver psci_cpuidle_domain_driver = {
301+ .probe = psci_cpuidle_domain_probe ,
302+ .driver = {
303+ .name = "psci-cpuidle-domain" ,
304+ .of_match_table = psci_of_match ,
305+ .sync_state = psci_cpuidle_domain_sync_state ,
306+ },
307+ };
308+
309+ static int __init psci_idle_init_domains (void )
310+ {
311+ return platform_driver_register (& psci_cpuidle_domain_driver );
312+ }
290313subsys_initcall (psci_idle_init_domains );
291314
292- struct device __init * psci_dt_attach_cpu (int cpu )
315+ struct device * psci_dt_attach_cpu (int cpu )
293316{
294317 struct device * dev ;
295318
296- if (!osi_mode_enabled )
297- return NULL ;
298-
299319 dev = dev_pm_domain_attach_by_name (get_cpu_device (cpu ), "psci" );
300320 if (IS_ERR_OR_NULL (dev ))
301321 return dev ;
@@ -306,3 +326,11 @@ struct device __init *psci_dt_attach_cpu(int cpu)
306326
307327 return dev ;
308328}
329+
330+ void psci_dt_detach_cpu (struct device * dev )
331+ {
332+ if (IS_ERR_OR_NULL (dev ))
333+ return ;
334+
335+ dev_pm_domain_detach (dev , false);
336+ }
0 commit comments