diff options
author | Rafael J. Wysocki <rafael.j.wysocki@intel.com> | 2016-10-01 19:41:29 -0400 |
---|---|---|
committer | Rafael J. Wysocki <rafael.j.wysocki@intel.com> | 2016-10-01 19:41:29 -0400 |
commit | 2dc3c72cd0a3ea85b8b7ae469904cfc24af1de60 (patch) | |
tree | f86f376dabe37631eea57ca81c7403820fccefe8 /drivers/base | |
parent | 08895a8b6b06ed2323cd97a36ee40a116b3db8ed (diff) | |
parent | eefdee07074db61764408583a23e96cf60d5a0a7 (diff) |
Merge branch 'pm-domains'
* pm-domains:
PM / Domains: Rename pm_genpd_sync_poweron|poweroff()
PM / Domains: Don't measure latency of ->power_on|off() during system PM
PM / Domains: Remove redundant system PM callbacks
PM / Domains: Simplify detaching a device from its genpd
PM / Domains: Allow holes in genpd_data.domains array
PM / Domains: Add support for removing nested PM domains by provider
PM / Domains: Add support for removing PM domains
PM / Domains: Store the provider in the PM domain structure
PM / Domains: Prepare for adding support to remove PM domains
PM / Domains: Verify the PM domain is present when adding a provider
PM / Domains: Don't expose xlate and provider helper functions
PM / Domains: Don't expose generic_pm_domain structure to clients
staging: board: Remove calls to of_genpd_get_from_provider()
ARM: EXYNOS: Remove calls to of_genpd_get_from_provider()
PM / Domains: Add new helper functions for device-tree
PM / Domains: Always enable debugfs support if available
Diffstat (limited to 'drivers/base')
-rw-r--r-- | drivers/base/power/domain.c | 430 |
1 files changed, 352 insertions, 78 deletions
diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c index a1f2aff33997..e023066e4215 100644 --- a/drivers/base/power/domain.c +++ b/drivers/base/power/domain.c | |||
@@ -45,7 +45,7 @@ static DEFINE_MUTEX(gpd_list_lock); | |||
45 | * and checks that the PM domain pointer is a real generic PM domain. | 45 | * and checks that the PM domain pointer is a real generic PM domain. |
46 | * Any failure results in NULL being returned. | 46 | * Any failure results in NULL being returned. |
47 | */ | 47 | */ |
48 | struct generic_pm_domain *pm_genpd_lookup_dev(struct device *dev) | 48 | static struct generic_pm_domain *genpd_lookup_dev(struct device *dev) |
49 | { | 49 | { |
50 | struct generic_pm_domain *genpd = NULL, *gpd; | 50 | struct generic_pm_domain *genpd = NULL, *gpd; |
51 | 51 | ||
@@ -586,7 +586,7 @@ static int __init genpd_poweroff_unused(void) | |||
586 | } | 586 | } |
587 | late_initcall(genpd_poweroff_unused); | 587 | late_initcall(genpd_poweroff_unused); |
588 | 588 | ||
589 | #ifdef CONFIG_PM_SLEEP | 589 | #if defined(CONFIG_PM_SLEEP) || defined(CONFIG_PM_GENERIC_DOMAINS_OF) |
590 | 590 | ||
591 | /** | 591 | /** |
592 | * pm_genpd_present - Check if the given PM domain has been initialized. | 592 | * pm_genpd_present - Check if the given PM domain has been initialized. |
@@ -606,6 +606,10 @@ static bool pm_genpd_present(const struct generic_pm_domain *genpd) | |||
606 | return false; | 606 | return false; |
607 | } | 607 | } |
608 | 608 | ||
609 | #endif | ||
610 | |||
611 | #ifdef CONFIG_PM_SLEEP | ||
612 | |||
609 | static bool genpd_dev_active_wakeup(struct generic_pm_domain *genpd, | 613 | static bool genpd_dev_active_wakeup(struct generic_pm_domain *genpd, |
610 | struct device *dev) | 614 | struct device *dev) |
611 | { | 615 | { |
@@ -613,9 +617,8 @@ static bool genpd_dev_active_wakeup(struct generic_pm_domain *genpd, | |||
613 | } | 617 | } |
614 | 618 | ||
615 | /** | 619 | /** |
616 | * pm_genpd_sync_poweroff - Synchronously power off a PM domain and its masters. | 620 | * genpd_sync_poweroff - Synchronously power off a PM domain and its masters. |
617 | * @genpd: PM domain to power off, if possible. | 621 | * @genpd: PM domain to power off, if possible. |
618 | * @timed: True if latency measurements are allowed. | ||
619 | * | 622 | * |
620 | * Check if the given PM domain can be powered off (during system suspend or | 623 | * Check if the given PM domain can be powered off (during system suspend or |
621 | * hibernation) and do that if so. Also, in that case propagate to its masters. | 624 | * hibernation) and do that if so. Also, in that case propagate to its masters. |
@@ -625,8 +628,7 @@ static bool genpd_dev_active_wakeup(struct generic_pm_domain *genpd, | |||
625 | * executed sequentially, so it is guaranteed that it will never run twice in | 628 | * executed sequentially, so it is guaranteed that it will never run twice in |
626 | * parallel). | 629 | * parallel). |
627 | */ | 630 | */ |
628 | static void pm_genpd_sync_poweroff(struct generic_pm_domain *genpd, | 631 | static void genpd_sync_poweroff(struct generic_pm_domain *genpd) |
629 | bool timed) | ||
630 | { | 632 | { |
631 | struct gpd_link *link; | 633 | struct gpd_link *link; |
632 | 634 | ||
@@ -639,28 +641,26 @@ static void pm_genpd_sync_poweroff(struct generic_pm_domain *genpd, | |||
639 | 641 | ||
640 | /* Choose the deepest state when suspending */ | 642 | /* Choose the deepest state when suspending */ |
641 | genpd->state_idx = genpd->state_count - 1; | 643 | genpd->state_idx = genpd->state_count - 1; |
642 | genpd_power_off(genpd, timed); | 644 | genpd_power_off(genpd, false); |
643 | 645 | ||
644 | genpd->status = GPD_STATE_POWER_OFF; | 646 | genpd->status = GPD_STATE_POWER_OFF; |
645 | 647 | ||
646 | list_for_each_entry(link, &genpd->slave_links, slave_node) { | 648 | list_for_each_entry(link, &genpd->slave_links, slave_node) { |
647 | genpd_sd_counter_dec(link->master); | 649 | genpd_sd_counter_dec(link->master); |
648 | pm_genpd_sync_poweroff(link->master, timed); | 650 | genpd_sync_poweroff(link->master); |
649 | } | 651 | } |
650 | } | 652 | } |
651 | 653 | ||
652 | /** | 654 | /** |
653 | * pm_genpd_sync_poweron - Synchronously power on a PM domain and its masters. | 655 | * genpd_sync_poweron - Synchronously power on a PM domain and its masters. |
654 | * @genpd: PM domain to power on. | 656 | * @genpd: PM domain to power on. |
655 | * @timed: True if latency measurements are allowed. | ||
656 | * | 657 | * |
657 | * This function is only called in "noirq" and "syscore" stages of system power | 658 | * This function is only called in "noirq" and "syscore" stages of system power |
658 | * transitions, so it need not acquire locks (all of the "noirq" callbacks are | 659 | * transitions, so it need not acquire locks (all of the "noirq" callbacks are |
659 | * executed sequentially, so it is guaranteed that it will never run twice in | 660 | * executed sequentially, so it is guaranteed that it will never run twice in |
660 | * parallel). | 661 | * parallel). |
661 | */ | 662 | */ |
662 | static void pm_genpd_sync_poweron(struct generic_pm_domain *genpd, | 663 | static void genpd_sync_poweron(struct generic_pm_domain *genpd) |
663 | bool timed) | ||
664 | { | 664 | { |
665 | struct gpd_link *link; | 665 | struct gpd_link *link; |
666 | 666 | ||
@@ -668,11 +668,11 @@ static void pm_genpd_sync_poweron(struct generic_pm_domain *genpd, | |||
668 | return; | 668 | return; |
669 | 669 | ||
670 | list_for_each_entry(link, &genpd->slave_links, slave_node) { | 670 | list_for_each_entry(link, &genpd->slave_links, slave_node) { |
671 | pm_genpd_sync_poweron(link->master, timed); | 671 | genpd_sync_poweron(link->master); |
672 | genpd_sd_counter_inc(link->master); | 672 | genpd_sd_counter_inc(link->master); |
673 | } | 673 | } |
674 | 674 | ||
675 | genpd_power_on(genpd, timed); | 675 | genpd_power_on(genpd, false); |
676 | 676 | ||
677 | genpd->status = GPD_STATE_ACTIVE; | 677 | genpd->status = GPD_STATE_ACTIVE; |
678 | } | 678 | } |
@@ -784,7 +784,7 @@ static int pm_genpd_suspend_noirq(struct device *dev) | |||
784 | * the same PM domain, so it is not necessary to use locking here. | 784 | * the same PM domain, so it is not necessary to use locking here. |
785 | */ | 785 | */ |
786 | genpd->suspended_count++; | 786 | genpd->suspended_count++; |
787 | pm_genpd_sync_poweroff(genpd, true); | 787 | genpd_sync_poweroff(genpd); |
788 | 788 | ||
789 | return 0; | 789 | return 0; |
790 | } | 790 | } |
@@ -814,7 +814,7 @@ static int pm_genpd_resume_noirq(struct device *dev) | |||
814 | * guaranteed that this function will never run twice in parallel for | 814 | * guaranteed that this function will never run twice in parallel for |
815 | * the same PM domain, so it is not necessary to use locking here. | 815 | * the same PM domain, so it is not necessary to use locking here. |
816 | */ | 816 | */ |
817 | pm_genpd_sync_poweron(genpd, true); | 817 | genpd_sync_poweron(genpd); |
818 | genpd->suspended_count--; | 818 | genpd->suspended_count--; |
819 | 819 | ||
820 | if (genpd->dev_ops.stop && genpd->dev_ops.start) | 820 | if (genpd->dev_ops.stop && genpd->dev_ops.start) |
@@ -902,12 +902,12 @@ static int pm_genpd_restore_noirq(struct device *dev) | |||
902 | if (genpd->suspended_count++ == 0) | 902 | if (genpd->suspended_count++ == 0) |
903 | /* | 903 | /* |
904 | * The boot kernel might put the domain into arbitrary state, | 904 | * The boot kernel might put the domain into arbitrary state, |
905 | * so make it appear as powered off to pm_genpd_sync_poweron(), | 905 | * so make it appear as powered off to genpd_sync_poweron(), |
906 | * so that it tries to power it on in case it was really off. | 906 | * so that it tries to power it on in case it was really off. |
907 | */ | 907 | */ |
908 | genpd->status = GPD_STATE_POWER_OFF; | 908 | genpd->status = GPD_STATE_POWER_OFF; |
909 | 909 | ||
910 | pm_genpd_sync_poweron(genpd, true); | 910 | genpd_sync_poweron(genpd); |
911 | 911 | ||
912 | if (genpd->dev_ops.stop && genpd->dev_ops.start) | 912 | if (genpd->dev_ops.stop && genpd->dev_ops.start) |
913 | ret = pm_runtime_force_resume(dev); | 913 | ret = pm_runtime_force_resume(dev); |
@@ -962,9 +962,9 @@ static void genpd_syscore_switch(struct device *dev, bool suspend) | |||
962 | 962 | ||
963 | if (suspend) { | 963 | if (suspend) { |
964 | genpd->suspended_count++; | 964 | genpd->suspended_count++; |
965 | pm_genpd_sync_poweroff(genpd, false); | 965 | genpd_sync_poweroff(genpd); |
966 | } else { | 966 | } else { |
967 | pm_genpd_sync_poweron(genpd, false); | 967 | genpd_sync_poweron(genpd); |
968 | genpd->suspended_count--; | 968 | genpd->suspended_count--; |
969 | } | 969 | } |
970 | } | 970 | } |
@@ -1056,14 +1056,8 @@ static void genpd_free_dev_data(struct device *dev, | |||
1056 | dev_pm_put_subsys_data(dev); | 1056 | dev_pm_put_subsys_data(dev); |
1057 | } | 1057 | } |
1058 | 1058 | ||
1059 | /** | 1059 | static int genpd_add_device(struct generic_pm_domain *genpd, struct device *dev, |
1060 | * __pm_genpd_add_device - Add a device to an I/O PM domain. | 1060 | struct gpd_timing_data *td) |
1061 | * @genpd: PM domain to add the device to. | ||
1062 | * @dev: Device to be added. | ||
1063 | * @td: Set of PM QoS timing parameters to attach to the device. | ||
1064 | */ | ||
1065 | int __pm_genpd_add_device(struct generic_pm_domain *genpd, struct device *dev, | ||
1066 | struct gpd_timing_data *td) | ||
1067 | { | 1061 | { |
1068 | struct generic_pm_domain_data *gpd_data; | 1062 | struct generic_pm_domain_data *gpd_data; |
1069 | int ret = 0; | 1063 | int ret = 0; |
@@ -1103,15 +1097,28 @@ int __pm_genpd_add_device(struct generic_pm_domain *genpd, struct device *dev, | |||
1103 | 1097 | ||
1104 | return ret; | 1098 | return ret; |
1105 | } | 1099 | } |
1106 | EXPORT_SYMBOL_GPL(__pm_genpd_add_device); | ||
1107 | 1100 | ||
1108 | /** | 1101 | /** |
1109 | * pm_genpd_remove_device - Remove a device from an I/O PM domain. | 1102 | * __pm_genpd_add_device - Add a device to an I/O PM domain. |
1110 | * @genpd: PM domain to remove the device from. | 1103 | * @genpd: PM domain to add the device to. |
1111 | * @dev: Device to be removed. | 1104 | * @dev: Device to be added. |
1105 | * @td: Set of PM QoS timing parameters to attach to the device. | ||
1112 | */ | 1106 | */ |
1113 | int pm_genpd_remove_device(struct generic_pm_domain *genpd, | 1107 | int __pm_genpd_add_device(struct generic_pm_domain *genpd, struct device *dev, |
1114 | struct device *dev) | 1108 | struct gpd_timing_data *td) |
1109 | { | ||
1110 | int ret; | ||
1111 | |||
1112 | mutex_lock(&gpd_list_lock); | ||
1113 | ret = genpd_add_device(genpd, dev, td); | ||
1114 | mutex_unlock(&gpd_list_lock); | ||
1115 | |||
1116 | return ret; | ||
1117 | } | ||
1118 | EXPORT_SYMBOL_GPL(__pm_genpd_add_device); | ||
1119 | |||
1120 | static int genpd_remove_device(struct generic_pm_domain *genpd, | ||
1121 | struct device *dev) | ||
1115 | { | 1122 | { |
1116 | struct generic_pm_domain_data *gpd_data; | 1123 | struct generic_pm_domain_data *gpd_data; |
1117 | struct pm_domain_data *pdd; | 1124 | struct pm_domain_data *pdd; |
@@ -1119,10 +1126,6 @@ int pm_genpd_remove_device(struct generic_pm_domain *genpd, | |||
1119 | 1126 | ||
1120 | dev_dbg(dev, "%s()\n", __func__); | 1127 | dev_dbg(dev, "%s()\n", __func__); |
1121 | 1128 | ||
1122 | if (!genpd || genpd != pm_genpd_lookup_dev(dev)) | ||
1123 | return -EINVAL; | ||
1124 | |||
1125 | /* The above validation also means we have existing domain_data. */ | ||
1126 | pdd = dev->power.subsys_data->domain_data; | 1129 | pdd = dev->power.subsys_data->domain_data; |
1127 | gpd_data = to_gpd_data(pdd); | 1130 | gpd_data = to_gpd_data(pdd); |
1128 | dev_pm_qos_remove_notifier(dev, &gpd_data->nb); | 1131 | dev_pm_qos_remove_notifier(dev, &gpd_data->nb); |
@@ -1154,15 +1157,24 @@ int pm_genpd_remove_device(struct generic_pm_domain *genpd, | |||
1154 | 1157 | ||
1155 | return ret; | 1158 | return ret; |
1156 | } | 1159 | } |
1157 | EXPORT_SYMBOL_GPL(pm_genpd_remove_device); | ||
1158 | 1160 | ||
1159 | /** | 1161 | /** |
1160 | * pm_genpd_add_subdomain - Add a subdomain to an I/O PM domain. | 1162 | * pm_genpd_remove_device - Remove a device from an I/O PM domain. |
1161 | * @genpd: Master PM domain to add the subdomain to. | 1163 | * @genpd: PM domain to remove the device from. |
1162 | * @subdomain: Subdomain to be added. | 1164 | * @dev: Device to be removed. |
1163 | */ | 1165 | */ |
1164 | int pm_genpd_add_subdomain(struct generic_pm_domain *genpd, | 1166 | int pm_genpd_remove_device(struct generic_pm_domain *genpd, |
1165 | struct generic_pm_domain *subdomain) | 1167 | struct device *dev) |
1168 | { | ||
1169 | if (!genpd || genpd != genpd_lookup_dev(dev)) | ||
1170 | return -EINVAL; | ||
1171 | |||
1172 | return genpd_remove_device(genpd, dev); | ||
1173 | } | ||
1174 | EXPORT_SYMBOL_GPL(pm_genpd_remove_device); | ||
1175 | |||
1176 | static int genpd_add_subdomain(struct generic_pm_domain *genpd, | ||
1177 | struct generic_pm_domain *subdomain) | ||
1166 | { | 1178 | { |
1167 | struct gpd_link *link, *itr; | 1179 | struct gpd_link *link, *itr; |
1168 | int ret = 0; | 1180 | int ret = 0; |
@@ -1205,6 +1217,23 @@ int pm_genpd_add_subdomain(struct generic_pm_domain *genpd, | |||
1205 | kfree(link); | 1217 | kfree(link); |
1206 | return ret; | 1218 | return ret; |
1207 | } | 1219 | } |
1220 | |||
1221 | /** | ||
1222 | * pm_genpd_add_subdomain - Add a subdomain to an I/O PM domain. | ||
1223 | * @genpd: Master PM domain to add the subdomain to. | ||
1224 | * @subdomain: Subdomain to be added. | ||
1225 | */ | ||
1226 | int pm_genpd_add_subdomain(struct generic_pm_domain *genpd, | ||
1227 | struct generic_pm_domain *subdomain) | ||
1228 | { | ||
1229 | int ret; | ||
1230 | |||
1231 | mutex_lock(&gpd_list_lock); | ||
1232 | ret = genpd_add_subdomain(genpd, subdomain); | ||
1233 | mutex_unlock(&gpd_list_lock); | ||
1234 | |||
1235 | return ret; | ||
1236 | } | ||
1208 | EXPORT_SYMBOL_GPL(pm_genpd_add_subdomain); | 1237 | EXPORT_SYMBOL_GPL(pm_genpd_add_subdomain); |
1209 | 1238 | ||
1210 | /** | 1239 | /** |
@@ -1278,27 +1307,17 @@ int pm_genpd_init(struct generic_pm_domain *genpd, | |||
1278 | genpd->device_count = 0; | 1307 | genpd->device_count = 0; |
1279 | genpd->max_off_time_ns = -1; | 1308 | genpd->max_off_time_ns = -1; |
1280 | genpd->max_off_time_changed = true; | 1309 | genpd->max_off_time_changed = true; |
1310 | genpd->provider = NULL; | ||
1311 | genpd->has_provider = false; | ||
1281 | genpd->domain.ops.runtime_suspend = genpd_runtime_suspend; | 1312 | genpd->domain.ops.runtime_suspend = genpd_runtime_suspend; |
1282 | genpd->domain.ops.runtime_resume = genpd_runtime_resume; | 1313 | genpd->domain.ops.runtime_resume = genpd_runtime_resume; |
1283 | genpd->domain.ops.prepare = pm_genpd_prepare; | 1314 | genpd->domain.ops.prepare = pm_genpd_prepare; |
1284 | genpd->domain.ops.suspend = pm_generic_suspend; | ||
1285 | genpd->domain.ops.suspend_late = pm_generic_suspend_late; | ||
1286 | genpd->domain.ops.suspend_noirq = pm_genpd_suspend_noirq; | 1315 | genpd->domain.ops.suspend_noirq = pm_genpd_suspend_noirq; |
1287 | genpd->domain.ops.resume_noirq = pm_genpd_resume_noirq; | 1316 | genpd->domain.ops.resume_noirq = pm_genpd_resume_noirq; |
1288 | genpd->domain.ops.resume_early = pm_generic_resume_early; | ||
1289 | genpd->domain.ops.resume = pm_generic_resume; | ||
1290 | genpd->domain.ops.freeze = pm_generic_freeze; | ||
1291 | genpd->domain.ops.freeze_late = pm_generic_freeze_late; | ||
1292 | genpd->domain.ops.freeze_noirq = pm_genpd_freeze_noirq; | 1317 | genpd->domain.ops.freeze_noirq = pm_genpd_freeze_noirq; |
1293 | genpd->domain.ops.thaw_noirq = pm_genpd_thaw_noirq; | 1318 | genpd->domain.ops.thaw_noirq = pm_genpd_thaw_noirq; |
1294 | genpd->domain.ops.thaw_early = pm_generic_thaw_early; | ||
1295 | genpd->domain.ops.thaw = pm_generic_thaw; | ||
1296 | genpd->domain.ops.poweroff = pm_generic_poweroff; | ||
1297 | genpd->domain.ops.poweroff_late = pm_generic_poweroff_late; | ||
1298 | genpd->domain.ops.poweroff_noirq = pm_genpd_suspend_noirq; | 1319 | genpd->domain.ops.poweroff_noirq = pm_genpd_suspend_noirq; |
1299 | genpd->domain.ops.restore_noirq = pm_genpd_restore_noirq; | 1320 | genpd->domain.ops.restore_noirq = pm_genpd_restore_noirq; |
1300 | genpd->domain.ops.restore_early = pm_generic_restore_early; | ||
1301 | genpd->domain.ops.restore = pm_generic_restore; | ||
1302 | genpd->domain.ops.complete = pm_genpd_complete; | 1321 | genpd->domain.ops.complete = pm_genpd_complete; |
1303 | 1322 | ||
1304 | if (genpd->flags & GENPD_FLAG_PM_CLK) { | 1323 | if (genpd->flags & GENPD_FLAG_PM_CLK) { |
@@ -1328,7 +1347,71 @@ int pm_genpd_init(struct generic_pm_domain *genpd, | |||
1328 | } | 1347 | } |
1329 | EXPORT_SYMBOL_GPL(pm_genpd_init); | 1348 | EXPORT_SYMBOL_GPL(pm_genpd_init); |
1330 | 1349 | ||
1350 | static int genpd_remove(struct generic_pm_domain *genpd) | ||
1351 | { | ||
1352 | struct gpd_link *l, *link; | ||
1353 | |||
1354 | if (IS_ERR_OR_NULL(genpd)) | ||
1355 | return -EINVAL; | ||
1356 | |||
1357 | mutex_lock(&genpd->lock); | ||
1358 | |||
1359 | if (genpd->has_provider) { | ||
1360 | mutex_unlock(&genpd->lock); | ||
1361 | pr_err("Provider present, unable to remove %s\n", genpd->name); | ||
1362 | return -EBUSY; | ||
1363 | } | ||
1364 | |||
1365 | if (!list_empty(&genpd->master_links) || genpd->device_count) { | ||
1366 | mutex_unlock(&genpd->lock); | ||
1367 | pr_err("%s: unable to remove %s\n", __func__, genpd->name); | ||
1368 | return -EBUSY; | ||
1369 | } | ||
1370 | |||
1371 | list_for_each_entry_safe(link, l, &genpd->slave_links, slave_node) { | ||
1372 | list_del(&link->master_node); | ||
1373 | list_del(&link->slave_node); | ||
1374 | kfree(link); | ||
1375 | } | ||
1376 | |||
1377 | list_del(&genpd->gpd_list_node); | ||
1378 | mutex_unlock(&genpd->lock); | ||
1379 | cancel_work_sync(&genpd->power_off_work); | ||
1380 | pr_debug("%s: removed %s\n", __func__, genpd->name); | ||
1381 | |||
1382 | return 0; | ||
1383 | } | ||
1384 | |||
1385 | /** | ||
1386 | * pm_genpd_remove - Remove a generic I/O PM domain | ||
1387 | * @genpd: Pointer to PM domain that is to be removed. | ||
1388 | * | ||
1389 | * To remove the PM domain, this function: | ||
1390 | * - Removes the PM domain as a subdomain to any parent domains, | ||
1391 | * if it was added. | ||
1392 | * - Removes the PM domain from the list of registered PM domains. | ||
1393 | * | ||
1394 | * The PM domain will only be removed, if the associated provider has | ||
1395 | * been removed, it is not a parent to any other PM domain and has no | ||
1396 | * devices associated with it. | ||
1397 | */ | ||
1398 | int pm_genpd_remove(struct generic_pm_domain *genpd) | ||
1399 | { | ||
1400 | int ret; | ||
1401 | |||
1402 | mutex_lock(&gpd_list_lock); | ||
1403 | ret = genpd_remove(genpd); | ||
1404 | mutex_unlock(&gpd_list_lock); | ||
1405 | |||
1406 | return ret; | ||
1407 | } | ||
1408 | EXPORT_SYMBOL_GPL(pm_genpd_remove); | ||
1409 | |||
1331 | #ifdef CONFIG_PM_GENERIC_DOMAINS_OF | 1410 | #ifdef CONFIG_PM_GENERIC_DOMAINS_OF |
1411 | |||
1412 | typedef struct generic_pm_domain *(*genpd_xlate_t)(struct of_phandle_args *args, | ||
1413 | void *data); | ||
1414 | |||
1332 | /* | 1415 | /* |
1333 | * Device Tree based PM domain providers. | 1416 | * Device Tree based PM domain providers. |
1334 | * | 1417 | * |
@@ -1340,8 +1423,8 @@ EXPORT_SYMBOL_GPL(pm_genpd_init); | |||
1340 | * maps a PM domain specifier retrieved from the device tree to a PM domain. | 1423 | * maps a PM domain specifier retrieved from the device tree to a PM domain. |
1341 | * | 1424 | * |
1342 | * Two simple mapping functions have been provided for convenience: | 1425 | * Two simple mapping functions have been provided for convenience: |
1343 | * - __of_genpd_xlate_simple() for 1:1 device tree node to PM domain mapping. | 1426 | * - genpd_xlate_simple() for 1:1 device tree node to PM domain mapping. |
1344 | * - __of_genpd_xlate_onecell() for mapping of multiple PM domains per node by | 1427 | * - genpd_xlate_onecell() for mapping of multiple PM domains per node by |
1345 | * index. | 1428 | * index. |
1346 | */ | 1429 | */ |
1347 | 1430 | ||
@@ -1366,7 +1449,7 @@ static LIST_HEAD(of_genpd_providers); | |||
1366 | static DEFINE_MUTEX(of_genpd_mutex); | 1449 | static DEFINE_MUTEX(of_genpd_mutex); |
1367 | 1450 | ||
1368 | /** | 1451 | /** |
1369 | * __of_genpd_xlate_simple() - Xlate function for direct node-domain mapping | 1452 | * genpd_xlate_simple() - Xlate function for direct node-domain mapping |
1370 | * @genpdspec: OF phandle args to map into a PM domain | 1453 | * @genpdspec: OF phandle args to map into a PM domain |
1371 | * @data: xlate function private data - pointer to struct generic_pm_domain | 1454 | * @data: xlate function private data - pointer to struct generic_pm_domain |
1372 | * | 1455 | * |
@@ -1374,7 +1457,7 @@ static DEFINE_MUTEX(of_genpd_mutex); | |||
1374 | * have their own device tree nodes. The private data of xlate function needs | 1457 | * have their own device tree nodes. The private data of xlate function needs |
1375 | * to be a valid pointer to struct generic_pm_domain. | 1458 | * to be a valid pointer to struct generic_pm_domain. |
1376 | */ | 1459 | */ |
1377 | struct generic_pm_domain *__of_genpd_xlate_simple( | 1460 | static struct generic_pm_domain *genpd_xlate_simple( |
1378 | struct of_phandle_args *genpdspec, | 1461 | struct of_phandle_args *genpdspec, |
1379 | void *data) | 1462 | void *data) |
1380 | { | 1463 | { |
@@ -1382,10 +1465,9 @@ struct generic_pm_domain *__of_genpd_xlate_simple( | |||
1382 | return ERR_PTR(-EINVAL); | 1465 | return ERR_PTR(-EINVAL); |
1383 | return data; | 1466 | return data; |
1384 | } | 1467 | } |
1385 | EXPORT_SYMBOL_GPL(__of_genpd_xlate_simple); | ||
1386 | 1468 | ||
1387 | /** | 1469 | /** |
1388 | * __of_genpd_xlate_onecell() - Xlate function using a single index. | 1470 | * genpd_xlate_onecell() - Xlate function using a single index. |
1389 | * @genpdspec: OF phandle args to map into a PM domain | 1471 | * @genpdspec: OF phandle args to map into a PM domain |
1390 | * @data: xlate function private data - pointer to struct genpd_onecell_data | 1472 | * @data: xlate function private data - pointer to struct genpd_onecell_data |
1391 | * | 1473 | * |
@@ -1394,7 +1476,7 @@ EXPORT_SYMBOL_GPL(__of_genpd_xlate_simple); | |||
1394 | * A single cell is used as an index into an array of PM domains specified in | 1476 | * A single cell is used as an index into an array of PM domains specified in |
1395 | * the genpd_onecell_data struct when registering the provider. | 1477 | * the genpd_onecell_data struct when registering the provider. |
1396 | */ | 1478 | */ |
1397 | struct generic_pm_domain *__of_genpd_xlate_onecell( | 1479 | static struct generic_pm_domain *genpd_xlate_onecell( |
1398 | struct of_phandle_args *genpdspec, | 1480 | struct of_phandle_args *genpdspec, |
1399 | void *data) | 1481 | void *data) |
1400 | { | 1482 | { |
@@ -1414,16 +1496,15 @@ struct generic_pm_domain *__of_genpd_xlate_onecell( | |||
1414 | 1496 | ||
1415 | return genpd_data->domains[idx]; | 1497 | return genpd_data->domains[idx]; |
1416 | } | 1498 | } |
1417 | EXPORT_SYMBOL_GPL(__of_genpd_xlate_onecell); | ||
1418 | 1499 | ||
1419 | /** | 1500 | /** |
1420 | * __of_genpd_add_provider() - Register a PM domain provider for a node | 1501 | * genpd_add_provider() - Register a PM domain provider for a node |
1421 | * @np: Device node pointer associated with the PM domain provider. | 1502 | * @np: Device node pointer associated with the PM domain provider. |
1422 | * @xlate: Callback for decoding PM domain from phandle arguments. | 1503 | * @xlate: Callback for decoding PM domain from phandle arguments. |
1423 | * @data: Context pointer for @xlate callback. | 1504 | * @data: Context pointer for @xlate callback. |
1424 | */ | 1505 | */ |
1425 | int __of_genpd_add_provider(struct device_node *np, genpd_xlate_t xlate, | 1506 | static int genpd_add_provider(struct device_node *np, genpd_xlate_t xlate, |
1426 | void *data) | 1507 | void *data) |
1427 | { | 1508 | { |
1428 | struct of_genpd_provider *cp; | 1509 | struct of_genpd_provider *cp; |
1429 | 1510 | ||
@@ -1442,7 +1523,83 @@ int __of_genpd_add_provider(struct device_node *np, genpd_xlate_t xlate, | |||
1442 | 1523 | ||
1443 | return 0; | 1524 | return 0; |
1444 | } | 1525 | } |
1445 | EXPORT_SYMBOL_GPL(__of_genpd_add_provider); | 1526 | |
1527 | /** | ||
1528 | * of_genpd_add_provider_simple() - Register a simple PM domain provider | ||
1529 | * @np: Device node pointer associated with the PM domain provider. | ||
1530 | * @genpd: Pointer to PM domain associated with the PM domain provider. | ||
1531 | */ | ||
1532 | int of_genpd_add_provider_simple(struct device_node *np, | ||
1533 | struct generic_pm_domain *genpd) | ||
1534 | { | ||
1535 | int ret = -EINVAL; | ||
1536 | |||
1537 | if (!np || !genpd) | ||
1538 | return -EINVAL; | ||
1539 | |||
1540 | mutex_lock(&gpd_list_lock); | ||
1541 | |||
1542 | if (pm_genpd_present(genpd)) | ||
1543 | ret = genpd_add_provider(np, genpd_xlate_simple, genpd); | ||
1544 | |||
1545 | if (!ret) { | ||
1546 | genpd->provider = &np->fwnode; | ||
1547 | genpd->has_provider = true; | ||
1548 | } | ||
1549 | |||
1550 | mutex_unlock(&gpd_list_lock); | ||
1551 | |||
1552 | return ret; | ||
1553 | } | ||
1554 | EXPORT_SYMBOL_GPL(of_genpd_add_provider_simple); | ||
1555 | |||
1556 | /** | ||
1557 | * of_genpd_add_provider_onecell() - Register a onecell PM domain provider | ||
1558 | * @np: Device node pointer associated with the PM domain provider. | ||
1559 | * @data: Pointer to the data associated with the PM domain provider. | ||
1560 | */ | ||
1561 | int of_genpd_add_provider_onecell(struct device_node *np, | ||
1562 | struct genpd_onecell_data *data) | ||
1563 | { | ||
1564 | unsigned int i; | ||
1565 | int ret = -EINVAL; | ||
1566 | |||
1567 | if (!np || !data) | ||
1568 | return -EINVAL; | ||
1569 | |||
1570 | mutex_lock(&gpd_list_lock); | ||
1571 | |||
1572 | for (i = 0; i < data->num_domains; i++) { | ||
1573 | if (!data->domains[i]) | ||
1574 | continue; | ||
1575 | if (!pm_genpd_present(data->domains[i])) | ||
1576 | goto error; | ||
1577 | |||
1578 | data->domains[i]->provider = &np->fwnode; | ||
1579 | data->domains[i]->has_provider = true; | ||
1580 | } | ||
1581 | |||
1582 | ret = genpd_add_provider(np, genpd_xlate_onecell, data); | ||
1583 | if (ret < 0) | ||
1584 | goto error; | ||
1585 | |||
1586 | mutex_unlock(&gpd_list_lock); | ||
1587 | |||
1588 | return 0; | ||
1589 | |||
1590 | error: | ||
1591 | while (i--) { | ||
1592 | if (!data->domains[i]) | ||
1593 | continue; | ||
1594 | data->domains[i]->provider = NULL; | ||
1595 | data->domains[i]->has_provider = false; | ||
1596 | } | ||
1597 | |||
1598 | mutex_unlock(&gpd_list_lock); | ||
1599 | |||
1600 | return ret; | ||
1601 | } | ||
1602 | EXPORT_SYMBOL_GPL(of_genpd_add_provider_onecell); | ||
1446 | 1603 | ||
1447 | /** | 1604 | /** |
1448 | * of_genpd_del_provider() - Remove a previously registered PM domain provider | 1605 | * of_genpd_del_provider() - Remove a previously registered PM domain provider |
@@ -1451,10 +1608,21 @@ EXPORT_SYMBOL_GPL(__of_genpd_add_provider); | |||
1451 | void of_genpd_del_provider(struct device_node *np) | 1608 | void of_genpd_del_provider(struct device_node *np) |
1452 | { | 1609 | { |
1453 | struct of_genpd_provider *cp; | 1610 | struct of_genpd_provider *cp; |
1611 | struct generic_pm_domain *gpd; | ||
1454 | 1612 | ||
1613 | mutex_lock(&gpd_list_lock); | ||
1455 | mutex_lock(&of_genpd_mutex); | 1614 | mutex_lock(&of_genpd_mutex); |
1456 | list_for_each_entry(cp, &of_genpd_providers, link) { | 1615 | list_for_each_entry(cp, &of_genpd_providers, link) { |
1457 | if (cp->node == np) { | 1616 | if (cp->node == np) { |
1617 | /* | ||
1618 | * For each PM domain associated with the | ||
1619 | * provider, set the 'has_provider' to false | ||
1620 | * so that the PM domain can be safely removed. | ||
1621 | */ | ||
1622 | list_for_each_entry(gpd, &gpd_list, gpd_list_node) | ||
1623 | if (gpd->provider == &np->fwnode) | ||
1624 | gpd->has_provider = false; | ||
1625 | |||
1458 | list_del(&cp->link); | 1626 | list_del(&cp->link); |
1459 | of_node_put(cp->node); | 1627 | of_node_put(cp->node); |
1460 | kfree(cp); | 1628 | kfree(cp); |
@@ -1462,11 +1630,12 @@ void of_genpd_del_provider(struct device_node *np) | |||
1462 | } | 1630 | } |
1463 | } | 1631 | } |
1464 | mutex_unlock(&of_genpd_mutex); | 1632 | mutex_unlock(&of_genpd_mutex); |
1633 | mutex_unlock(&gpd_list_lock); | ||
1465 | } | 1634 | } |
1466 | EXPORT_SYMBOL_GPL(of_genpd_del_provider); | 1635 | EXPORT_SYMBOL_GPL(of_genpd_del_provider); |
1467 | 1636 | ||
1468 | /** | 1637 | /** |
1469 | * of_genpd_get_from_provider() - Look-up PM domain | 1638 | * genpd_get_from_provider() - Look-up PM domain |
1470 | * @genpdspec: OF phandle args to use for look-up | 1639 | * @genpdspec: OF phandle args to use for look-up |
1471 | * | 1640 | * |
1472 | * Looks for a PM domain provider under the node specified by @genpdspec and if | 1641 | * Looks for a PM domain provider under the node specified by @genpdspec and if |
@@ -1476,7 +1645,7 @@ EXPORT_SYMBOL_GPL(of_genpd_del_provider); | |||
1476 | * Returns a valid pointer to struct generic_pm_domain on success or ERR_PTR() | 1645 | * Returns a valid pointer to struct generic_pm_domain on success or ERR_PTR() |
1477 | * on failure. | 1646 | * on failure. |
1478 | */ | 1647 | */ |
1479 | struct generic_pm_domain *of_genpd_get_from_provider( | 1648 | static struct generic_pm_domain *genpd_get_from_provider( |
1480 | struct of_phandle_args *genpdspec) | 1649 | struct of_phandle_args *genpdspec) |
1481 | { | 1650 | { |
1482 | struct generic_pm_domain *genpd = ERR_PTR(-ENOENT); | 1651 | struct generic_pm_domain *genpd = ERR_PTR(-ENOENT); |
@@ -1499,7 +1668,109 @@ struct generic_pm_domain *of_genpd_get_from_provider( | |||
1499 | 1668 | ||
1500 | return genpd; | 1669 | return genpd; |
1501 | } | 1670 | } |
1502 | EXPORT_SYMBOL_GPL(of_genpd_get_from_provider); | 1671 | |
1672 | /** | ||
1673 | * of_genpd_add_device() - Add a device to an I/O PM domain | ||
1674 | * @genpdspec: OF phandle args to use for look-up PM domain | ||
1675 | * @dev: Device to be added. | ||
1676 | * | ||
1677 | * Looks-up an I/O PM domain based upon phandle args provided and adds | ||
1678 | * the device to the PM domain. Returns a negative error code on failure. | ||
1679 | */ | ||
1680 | int of_genpd_add_device(struct of_phandle_args *genpdspec, struct device *dev) | ||
1681 | { | ||
1682 | struct generic_pm_domain *genpd; | ||
1683 | int ret; | ||
1684 | |||
1685 | mutex_lock(&gpd_list_lock); | ||
1686 | |||
1687 | genpd = genpd_get_from_provider(genpdspec); | ||
1688 | if (IS_ERR(genpd)) { | ||
1689 | ret = PTR_ERR(genpd); | ||
1690 | goto out; | ||
1691 | } | ||
1692 | |||
1693 | ret = genpd_add_device(genpd, dev, NULL); | ||
1694 | |||
1695 | out: | ||
1696 | mutex_unlock(&gpd_list_lock); | ||
1697 | |||
1698 | return ret; | ||
1699 | } | ||
1700 | EXPORT_SYMBOL_GPL(of_genpd_add_device); | ||
1701 | |||
1702 | /** | ||
1703 | * of_genpd_add_subdomain - Add a subdomain to an I/O PM domain. | ||
1704 | * @parent_spec: OF phandle args to use for parent PM domain look-up | ||
1705 | * @subdomain_spec: OF phandle args to use for subdomain look-up | ||
1706 | * | ||
1707 | * Looks-up a parent PM domain and subdomain based upon phandle args | ||
1708 | * provided and adds the subdomain to the parent PM domain. Returns a | ||
1709 | * negative error code on failure. | ||
1710 | */ | ||
1711 | int of_genpd_add_subdomain(struct of_phandle_args *parent_spec, | ||
1712 | struct of_phandle_args *subdomain_spec) | ||
1713 | { | ||
1714 | struct generic_pm_domain *parent, *subdomain; | ||
1715 | int ret; | ||
1716 | |||
1717 | mutex_lock(&gpd_list_lock); | ||
1718 | |||
1719 | parent = genpd_get_from_provider(parent_spec); | ||
1720 | if (IS_ERR(parent)) { | ||
1721 | ret = PTR_ERR(parent); | ||
1722 | goto out; | ||
1723 | } | ||
1724 | |||
1725 | subdomain = genpd_get_from_provider(subdomain_spec); | ||
1726 | if (IS_ERR(subdomain)) { | ||
1727 | ret = PTR_ERR(subdomain); | ||
1728 | goto out; | ||
1729 | } | ||
1730 | |||
1731 | ret = genpd_add_subdomain(parent, subdomain); | ||
1732 | |||
1733 | out: | ||
1734 | mutex_unlock(&gpd_list_lock); | ||
1735 | |||
1736 | return ret; | ||
1737 | } | ||
1738 | EXPORT_SYMBOL_GPL(of_genpd_add_subdomain); | ||
1739 | |||
1740 | /** | ||
1741 | * of_genpd_remove_last - Remove the last PM domain registered for a provider | ||
1742 | * @provider: Pointer to device structure associated with provider | ||
1743 | * | ||
1744 | * Find the last PM domain that was added by a particular provider and | ||
1745 | * remove this PM domain from the list of PM domains. The provider is | ||
1746 | * identified by the 'provider' device structure that is passed. The PM | ||
1747 | * domain will only be removed, if the provider associated with domain | ||
1748 | * has been removed. | ||
1749 | * | ||
1750 | * Returns a valid pointer to struct generic_pm_domain on success or | ||
1751 | * ERR_PTR() on failure. | ||
1752 | */ | ||
1753 | struct generic_pm_domain *of_genpd_remove_last(struct device_node *np) | ||
1754 | { | ||
1755 | struct generic_pm_domain *gpd, *genpd = ERR_PTR(-ENOENT); | ||
1756 | int ret; | ||
1757 | |||
1758 | if (IS_ERR_OR_NULL(np)) | ||
1759 | return ERR_PTR(-EINVAL); | ||
1760 | |||
1761 | mutex_lock(&gpd_list_lock); | ||
1762 | list_for_each_entry(gpd, &gpd_list, gpd_list_node) { | ||
1763 | if (gpd->provider == &np->fwnode) { | ||
1764 | ret = genpd_remove(gpd); | ||
1765 | genpd = ret ? ERR_PTR(ret) : gpd; | ||
1766 | break; | ||
1767 | } | ||
1768 | } | ||
1769 | mutex_unlock(&gpd_list_lock); | ||
1770 | |||
1771 | return genpd; | ||
1772 | } | ||
1773 | EXPORT_SYMBOL_GPL(of_genpd_remove_last); | ||
1503 | 1774 | ||
1504 | /** | 1775 | /** |
1505 | * genpd_dev_pm_detach - Detach a device from its PM domain. | 1776 | * genpd_dev_pm_detach - Detach a device from its PM domain. |
@@ -1515,14 +1786,14 @@ static void genpd_dev_pm_detach(struct device *dev, bool power_off) | |||
1515 | unsigned int i; | 1786 | unsigned int i; |
1516 | int ret = 0; | 1787 | int ret = 0; |
1517 | 1788 | ||
1518 | pd = pm_genpd_lookup_dev(dev); | 1789 | pd = dev_to_genpd(dev); |
1519 | if (!pd) | 1790 | if (IS_ERR(pd)) |
1520 | return; | 1791 | return; |
1521 | 1792 | ||
1522 | dev_dbg(dev, "removing from PM domain %s\n", pd->name); | 1793 | dev_dbg(dev, "removing from PM domain %s\n", pd->name); |
1523 | 1794 | ||
1524 | for (i = 1; i < GENPD_RETRY_MAX_MS; i <<= 1) { | 1795 | for (i = 1; i < GENPD_RETRY_MAX_MS; i <<= 1) { |
1525 | ret = pm_genpd_remove_device(pd, dev); | 1796 | ret = genpd_remove_device(pd, dev); |
1526 | if (ret != -EAGAIN) | 1797 | if (ret != -EAGAIN) |
1527 | break; | 1798 | break; |
1528 | 1799 | ||
@@ -1596,9 +1867,11 @@ int genpd_dev_pm_attach(struct device *dev) | |||
1596 | return -ENOENT; | 1867 | return -ENOENT; |
1597 | } | 1868 | } |
1598 | 1869 | ||
1599 | pd = of_genpd_get_from_provider(&pd_args); | 1870 | mutex_lock(&gpd_list_lock); |
1871 | pd = genpd_get_from_provider(&pd_args); | ||
1600 | of_node_put(pd_args.np); | 1872 | of_node_put(pd_args.np); |
1601 | if (IS_ERR(pd)) { | 1873 | if (IS_ERR(pd)) { |
1874 | mutex_unlock(&gpd_list_lock); | ||
1602 | dev_dbg(dev, "%s() failed to find PM domain: %ld\n", | 1875 | dev_dbg(dev, "%s() failed to find PM domain: %ld\n", |
1603 | __func__, PTR_ERR(pd)); | 1876 | __func__, PTR_ERR(pd)); |
1604 | return -EPROBE_DEFER; | 1877 | return -EPROBE_DEFER; |
@@ -1607,13 +1880,14 @@ int genpd_dev_pm_attach(struct device *dev) | |||
1607 | dev_dbg(dev, "adding to PM domain %s\n", pd->name); | 1880 | dev_dbg(dev, "adding to PM domain %s\n", pd->name); |
1608 | 1881 | ||
1609 | for (i = 1; i < GENPD_RETRY_MAX_MS; i <<= 1) { | 1882 | for (i = 1; i < GENPD_RETRY_MAX_MS; i <<= 1) { |
1610 | ret = pm_genpd_add_device(pd, dev); | 1883 | ret = genpd_add_device(pd, dev, NULL); |
1611 | if (ret != -EAGAIN) | 1884 | if (ret != -EAGAIN) |
1612 | break; | 1885 | break; |
1613 | 1886 | ||
1614 | mdelay(i); | 1887 | mdelay(i); |
1615 | cond_resched(); | 1888 | cond_resched(); |
1616 | } | 1889 | } |
1890 | mutex_unlock(&gpd_list_lock); | ||
1617 | 1891 | ||
1618 | if (ret < 0) { | 1892 | if (ret < 0) { |
1619 | dev_err(dev, "failed to add to PM domain %s: %d", | 1893 | dev_err(dev, "failed to add to PM domain %s: %d", |
@@ -1636,7 +1910,7 @@ EXPORT_SYMBOL_GPL(genpd_dev_pm_attach); | |||
1636 | 1910 | ||
1637 | /*** debugfs support ***/ | 1911 | /*** debugfs support ***/ |
1638 | 1912 | ||
1639 | #ifdef CONFIG_PM_ADVANCED_DEBUG | 1913 | #ifdef CONFIG_DEBUG_FS |
1640 | #include <linux/pm.h> | 1914 | #include <linux/pm.h> |
1641 | #include <linux/device.h> | 1915 | #include <linux/device.h> |
1642 | #include <linux/debugfs.h> | 1916 | #include <linux/debugfs.h> |
@@ -1784,4 +2058,4 @@ static void __exit pm_genpd_debug_exit(void) | |||
1784 | debugfs_remove_recursive(pm_genpd_debugfs_dir); | 2058 | debugfs_remove_recursive(pm_genpd_debugfs_dir); |
1785 | } | 2059 | } |
1786 | __exitcall(pm_genpd_debug_exit); | 2060 | __exitcall(pm_genpd_debug_exit); |
1787 | #endif /* CONFIG_PM_ADVANCED_DEBUG */ | 2061 | #endif /* CONFIG_DEBUG_FS */ |