aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorUlf Hansson <ulf.hansson@linaro.org>2016-05-30 05:43:07 -0400
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>2016-06-16 09:01:43 -0400
commit39dd0f234fc37da071dadbd9b49fe800d62139b4 (patch)
tree76db8e33fb5a74b6da4432eea1b210857d89db39
parent5edb56491d4812c42175980759da53388e5d86f5 (diff)
PM / Domains: Allow genpd to power on during system PM phases
If a PM domain is powered off when the first device starts its system PM prepare phase, genpd prevents any further attempts to power on the PM domain during the following system PM phases. Not until the system PM complete phase is finalized for all devices in the PM domain, genpd again allows it to be powered on. This behaviour needs to be changed, as a subsystem/driver for a device in the same PM domain may still need to be able to serve requests in some of the system PM phases. Accordingly, it may need to runtime resume its device and thus also request the corresponding PM domain to be powered on. To deal with these scenarios, let's make the device operational in the system PM prepare phase by runtime resuming it, no matter if the PM domain is powered on or off. Changing this also enables us to remove genpd's suspend_power_off flag, as it's being used to track this condition. Additionally, we must allow the PM domain to be powered on via runtime PM during the system PM phases. This change also requires a fix in the AMD ACP (Audio CoProcessor) drm driver. It registers a genpd to model the ACP as a PM domain, but unfortunately it's also abuses genpd's "internal" suspend_power_off flag to deal with a corner case at system PM resume. More precisely, the so called SMU block powers on the ACP at system PM resume, unconditionally if it's being used or not. This may lead to that genpd's internal status of the power state, may not correctly reflect the power state of the HW after a system PM resume. Because of changing the behaviour of genpd, by runtime resuming devices in the prepare phase, the AMD ACP drm driver no longer have to deal with this corner case. So let's just drop the related code in this driver. Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org> Reviewed-by: Kevin Hilman <khilman@baylibre.com> Acked-by: Maruthi Bayyavarapu <maruthi.bayyavarapu@amd.com> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
-rw-r--r--drivers/base/power/domain.c84
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_acp.c23
-rw-r--r--include/linux/pm_domain.h1
3 files changed, 31 insertions, 77 deletions
diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c
index de23b648fce3..a608f521e6fc 100644
--- a/drivers/base/power/domain.c
+++ b/drivers/base/power/domain.c
@@ -187,8 +187,7 @@ static int genpd_poweron(struct generic_pm_domain *genpd, unsigned int depth)
187 struct gpd_link *link; 187 struct gpd_link *link;
188 int ret = 0; 188 int ret = 0;
189 189
190 if (genpd->status == GPD_STATE_ACTIVE 190 if (genpd->status == GPD_STATE_ACTIVE)
191 || (genpd->prepared_count > 0 && genpd->suspend_power_off))
192 return 0; 191 return 0;
193 192
194 /* 193 /*
@@ -735,21 +734,22 @@ static int pm_genpd_prepare(struct device *dev)
735 734
736 mutex_lock(&genpd->lock); 735 mutex_lock(&genpd->lock);
737 736
738 if (genpd->prepared_count++ == 0) { 737 if (genpd->prepared_count++ == 0)
739 genpd->suspended_count = 0; 738 genpd->suspended_count = 0;
740 genpd->suspend_power_off = genpd->status == GPD_STATE_POWER_OFF;
741 }
742 739
743 mutex_unlock(&genpd->lock); 740 mutex_unlock(&genpd->lock);
744 741
745 if (genpd->suspend_power_off)
746 return 0;
747
748 /* 742 /*
749 * The PM domain must be in the GPD_STATE_ACTIVE state at this point, 743 * Even if the PM domain is powered off at this point, we can't expect
750 * so genpd_poweron() will return immediately, but if the device 744 * it to remain in that state during the entire system PM suspend
751 * is suspended (e.g. it's been stopped by genpd_stop_dev()), we need 745 * phase. Any subsystem/driver for a device in the PM domain, may still
752 * to make it operational. 746 * need to serve a request which may require the device to be runtime
747 * resumed and its PM domain to be powered.
748 *
749 * As we are disabling runtime PM at this point, we are preventing the
750 * subsystem/driver to decide themselves. For that reason, we need to
751 * make sure the device is operational as it may be required in some
752 * cases.
753 */ 753 */
754 pm_runtime_resume(dev); 754 pm_runtime_resume(dev);
755 __pm_runtime_disable(dev, false); 755 __pm_runtime_disable(dev, false);
@@ -758,8 +758,7 @@ static int pm_genpd_prepare(struct device *dev)
758 if (ret) { 758 if (ret) {
759 mutex_lock(&genpd->lock); 759 mutex_lock(&genpd->lock);
760 760
761 if (--genpd->prepared_count == 0) 761 genpd->prepared_count--;
762 genpd->suspend_power_off = false;
763 762
764 mutex_unlock(&genpd->lock); 763 mutex_unlock(&genpd->lock);
765 pm_runtime_enable(dev); 764 pm_runtime_enable(dev);
@@ -786,7 +785,7 @@ static int pm_genpd_suspend(struct device *dev)
786 if (IS_ERR(genpd)) 785 if (IS_ERR(genpd))
787 return -EINVAL; 786 return -EINVAL;
788 787
789 return genpd->suspend_power_off ? 0 : pm_generic_suspend(dev); 788 return pm_generic_suspend(dev);
790} 789}
791 790
792/** 791/**
@@ -807,7 +806,7 @@ static int pm_genpd_suspend_late(struct device *dev)
807 if (IS_ERR(genpd)) 806 if (IS_ERR(genpd))
808 return -EINVAL; 807 return -EINVAL;
809 808
810 return genpd->suspend_power_off ? 0 : pm_generic_suspend_late(dev); 809 return pm_generic_suspend_late(dev);
811} 810}
812 811
813/** 812/**
@@ -827,8 +826,7 @@ static int pm_genpd_suspend_noirq(struct device *dev)
827 if (IS_ERR(genpd)) 826 if (IS_ERR(genpd))
828 return -EINVAL; 827 return -EINVAL;
829 828
830 if (genpd->suspend_power_off 829 if (dev->power.wakeup_path && genpd_dev_active_wakeup(genpd, dev))
831 || (dev->power.wakeup_path && genpd_dev_active_wakeup(genpd, dev)))
832 return 0; 830 return 0;
833 831
834 genpd_stop_dev(genpd, dev); 832 genpd_stop_dev(genpd, dev);
@@ -860,8 +858,7 @@ static int pm_genpd_resume_noirq(struct device *dev)
860 if (IS_ERR(genpd)) 858 if (IS_ERR(genpd))
861 return -EINVAL; 859 return -EINVAL;
862 860
863 if (genpd->suspend_power_off 861 if (dev->power.wakeup_path && genpd_dev_active_wakeup(genpd, dev))
864 || (dev->power.wakeup_path && genpd_dev_active_wakeup(genpd, dev)))
865 return 0; 862 return 0;
866 863
867 /* 864 /*
@@ -894,7 +891,7 @@ static int pm_genpd_resume_early(struct device *dev)
894 if (IS_ERR(genpd)) 891 if (IS_ERR(genpd))
895 return -EINVAL; 892 return -EINVAL;
896 893
897 return genpd->suspend_power_off ? 0 : pm_generic_resume_early(dev); 894 return pm_generic_resume_early(dev);
898} 895}
899 896
900/** 897/**
@@ -915,7 +912,7 @@ static int pm_genpd_resume(struct device *dev)
915 if (IS_ERR(genpd)) 912 if (IS_ERR(genpd))
916 return -EINVAL; 913 return -EINVAL;
917 914
918 return genpd->suspend_power_off ? 0 : pm_generic_resume(dev); 915 return pm_generic_resume(dev);
919} 916}
920 917
921/** 918/**
@@ -936,7 +933,7 @@ static int pm_genpd_freeze(struct device *dev)
936 if (IS_ERR(genpd)) 933 if (IS_ERR(genpd))
937 return -EINVAL; 934 return -EINVAL;
938 935
939 return genpd->suspend_power_off ? 0 : pm_generic_freeze(dev); 936 return pm_generic_freeze(dev);
940} 937}
941 938
942/** 939/**
@@ -958,7 +955,7 @@ static int pm_genpd_freeze_late(struct device *dev)
958 if (IS_ERR(genpd)) 955 if (IS_ERR(genpd))
959 return -EINVAL; 956 return -EINVAL;
960 957
961 return genpd->suspend_power_off ? 0 : pm_generic_freeze_late(dev); 958 return pm_generic_freeze_late(dev);
962} 959}
963 960
964/** 961/**
@@ -980,7 +977,7 @@ static int pm_genpd_freeze_noirq(struct device *dev)
980 if (IS_ERR(genpd)) 977 if (IS_ERR(genpd))
981 return -EINVAL; 978 return -EINVAL;
982 979
983 return genpd->suspend_power_off ? 0 : genpd_stop_dev(genpd, dev); 980 return genpd_stop_dev(genpd, dev);
984} 981}
985 982
986/** 983/**
@@ -1000,8 +997,7 @@ static int pm_genpd_thaw_noirq(struct device *dev)
1000 if (IS_ERR(genpd)) 997 if (IS_ERR(genpd))
1001 return -EINVAL; 998 return -EINVAL;
1002 999
1003 return genpd->suspend_power_off ? 1000 return genpd_start_dev(genpd, dev);
1004 0 : genpd_start_dev(genpd, dev);
1005} 1001}
1006 1002
1007/** 1003/**
@@ -1023,7 +1019,7 @@ static int pm_genpd_thaw_early(struct device *dev)
1023 if (IS_ERR(genpd)) 1019 if (IS_ERR(genpd))
1024 return -EINVAL; 1020 return -EINVAL;
1025 1021
1026 return genpd->suspend_power_off ? 0 : pm_generic_thaw_early(dev); 1022 return pm_generic_thaw_early(dev);
1027} 1023}
1028 1024
1029/** 1025/**
@@ -1044,7 +1040,7 @@ static int pm_genpd_thaw(struct device *dev)
1044 if (IS_ERR(genpd)) 1040 if (IS_ERR(genpd))
1045 return -EINVAL; 1041 return -EINVAL;
1046 1042
1047 return genpd->suspend_power_off ? 0 : pm_generic_thaw(dev); 1043 return pm_generic_thaw(dev);
1048} 1044}
1049 1045
1050/** 1046/**
@@ -1072,26 +1068,13 @@ static int pm_genpd_restore_noirq(struct device *dev)
1072 * At this point suspended_count == 0 means we are being run for the 1068 * At this point suspended_count == 0 means we are being run for the
1073 * first time for the given domain in the present cycle. 1069 * first time for the given domain in the present cycle.
1074 */ 1070 */
1075 if (genpd->suspended_count++ == 0) { 1071 if (genpd->suspended_count++ == 0)
1076 /* 1072 /*
1077 * The boot kernel might put the domain into arbitrary state, 1073 * The boot kernel might put the domain into arbitrary state,
1078 * so make it appear as powered off to pm_genpd_sync_poweron(), 1074 * so make it appear as powered off to pm_genpd_sync_poweron(),
1079 * so that it tries to power it on in case it was really off. 1075 * so that it tries to power it on in case it was really off.
1080 */ 1076 */
1081 genpd->status = GPD_STATE_POWER_OFF; 1077 genpd->status = GPD_STATE_POWER_OFF;
1082 if (genpd->suspend_power_off) {
1083 /*
1084 * If the domain was off before the hibernation, make
1085 * sure it will be off going forward.
1086 */
1087 genpd_power_off(genpd, true);
1088
1089 return 0;
1090 }
1091 }
1092
1093 if (genpd->suspend_power_off)
1094 return 0;
1095 1078
1096 pm_genpd_sync_poweron(genpd, true); 1079 pm_genpd_sync_poweron(genpd, true);
1097 1080
@@ -1110,7 +1093,6 @@ static int pm_genpd_restore_noirq(struct device *dev)
1110static void pm_genpd_complete(struct device *dev) 1093static void pm_genpd_complete(struct device *dev)
1111{ 1094{
1112 struct generic_pm_domain *genpd; 1095 struct generic_pm_domain *genpd;
1113 bool run_complete;
1114 1096
1115 dev_dbg(dev, "%s()\n", __func__); 1097 dev_dbg(dev, "%s()\n", __func__);
1116 1098
@@ -1120,18 +1102,14 @@ static void pm_genpd_complete(struct device *dev)
1120 1102
1121 mutex_lock(&genpd->lock); 1103 mutex_lock(&genpd->lock);
1122 1104
1123 run_complete = !genpd->suspend_power_off; 1105 genpd->prepared_count--;
1124 if (--genpd->prepared_count == 0)
1125 genpd->suspend_power_off = false;
1126 1106
1127 mutex_unlock(&genpd->lock); 1107 mutex_unlock(&genpd->lock);
1128 1108
1129 if (run_complete) { 1109 pm_generic_complete(dev);
1130 pm_generic_complete(dev); 1110 pm_runtime_set_active(dev);
1131 pm_runtime_set_active(dev); 1111 pm_runtime_enable(dev);
1132 pm_runtime_enable(dev); 1112 pm_request_idle(dev);
1133 pm_request_idle(dev);
1134 }
1135} 1113}
1136 1114
1137/** 1115/**
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_acp.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_acp.c
index 252edba16e36..892d60fb225b 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_acp.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_acp.c
@@ -421,29 +421,6 @@ static int acp_suspend(void *handle)
421 421
422static int acp_resume(void *handle) 422static int acp_resume(void *handle)
423{ 423{
424 int i, ret;
425 struct acp_pm_domain *apd;
426 struct amdgpu_device *adev = (struct amdgpu_device *)handle;
427
428 /* return early if no ACP */
429 if (!adev->acp.acp_genpd)
430 return 0;
431
432 /* SMU block will power on ACP irrespective of ACP runtime status.
433 * Power off explicitly based on genpd ACP runtime status so that ACP
434 * hw and ACP-genpd status are in sync.
435 * 'suspend_power_off' represents "Power status before system suspend"
436 */
437 if (adev->acp.acp_genpd->gpd.suspend_power_off == true) {
438 apd = container_of(&adev->acp.acp_genpd->gpd,
439 struct acp_pm_domain, gpd);
440
441 for (i = 4; i >= 0 ; i--) {
442 ret = acp_suspend_tile(apd->cgs_dev, ACP_TILE_P1 + i);
443 if (ret)
444 pr_err("ACP tile %d tile suspend failed\n", i);
445 }
446 }
447 return 0; 424 return 0;
448} 425}
449 426
diff --git a/include/linux/pm_domain.h b/include/linux/pm_domain.h
index 39285c7bd3f5..dd5b0447d572 100644
--- a/include/linux/pm_domain.h
+++ b/include/linux/pm_domain.h
@@ -57,7 +57,6 @@ struct generic_pm_domain {
57 unsigned int device_count; /* Number of devices */ 57 unsigned int device_count; /* Number of devices */
58 unsigned int suspended_count; /* System suspend device counter */ 58 unsigned int suspended_count; /* System suspend device counter */
59 unsigned int prepared_count; /* Suspend counter of prepared devices */ 59 unsigned int prepared_count; /* Suspend counter of prepared devices */
60 bool suspend_power_off; /* Power status before system suspend */
61 int (*power_off)(struct generic_pm_domain *domain); 60 int (*power_off)(struct generic_pm_domain *domain);
62 int (*power_on)(struct generic_pm_domain *domain); 61 int (*power_on)(struct generic_pm_domain *domain);
63 struct gpd_dev_ops dev_ops; 62 struct gpd_dev_ops dev_ops;