Message ID | 20221221224338.v4.1.I3e6b1f078ad0f1ca9358c573daa7b70ec132cdbe@changeid |
---|---|
State | Superseded |
Headers | show |
Series | Improve GPU reset sequence for Adreno GPU | expand |
On Wed, Dec 21, 2022 at 10:43:59PM +0530, Akhil P Oommen wrote: > From: Ulf Hansson <ulf.hansson@linaro.org> > > Some genpd providers doesn't ensure that it has turned off at hardware. > This is fine until the consumer really requires during some special > scenarios that the power domain collapse at hardware before it is > turned ON again. > > An example is the reset sequence of Adreno GPU which requires that the > 'gpucc cx gdsc' power domain should move to OFF state in hardware at > least once before turning in ON again to clear the internal state. > > Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org> > Signed-off-by: Akhil P Oommen <quic_akhilpo@quicinc.com> Reviewed-by: Bjorn Andersson <andersson@kernel.org> @Rafael, would you be willing to share an immutable branch with this change? Or would you be okay with me doing so from the qcom clock tree? Regards, Bjorn > --- > > Changes in v4: > - Update genpd function documentation (Ulf) > > Changes in v2: > - Minor formatting fix > > drivers/base/power/domain.c | 26 ++++++++++++++++++++++++++ > include/linux/pm_domain.h | 5 +++++ > 2 files changed, 31 insertions(+) > > diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c > index 967bcf9d415e..84662d338188 100644 > --- a/drivers/base/power/domain.c > +++ b/drivers/base/power/domain.c > @@ -519,6 +519,31 @@ ktime_t dev_pm_genpd_get_next_hrtimer(struct device *dev) > } > EXPORT_SYMBOL_GPL(dev_pm_genpd_get_next_hrtimer); > > +/* > + * dev_pm_genpd_synced_poweroff - Next power off should be synchronous > + * > + * @dev: A device that is attached to the genpd. > + * > + * Allows a consumer of the genpd to notify the provider that the next power off > + * should be synchronous. > + * > + * It is assumed that the users guarantee that the genpd wouldn't be detached > + * while this routine is getting called. > + */ > +void dev_pm_genpd_synced_poweroff(struct device *dev) > +{ > + struct generic_pm_domain *genpd; > + > + genpd = dev_to_genpd_safe(dev); > + if (!genpd) > + return; > + > + genpd_lock(genpd); > + genpd->synced_poweroff = true; > + genpd_unlock(genpd); > +} > +EXPORT_SYMBOL_GPL(dev_pm_genpd_synced_poweroff); > + > static int _genpd_power_on(struct generic_pm_domain *genpd, bool timed) > { > unsigned int state_idx = genpd->state_idx; > @@ -562,6 +587,7 @@ static int _genpd_power_on(struct generic_pm_domain *genpd, bool timed) > > out: > raw_notifier_call_chain(&genpd->power_notifiers, GENPD_NOTIFY_ON, NULL); > + genpd->synced_poweroff = false; > return 0; > err: > raw_notifier_call_chain(&genpd->power_notifiers, GENPD_NOTIFY_OFF, > diff --git a/include/linux/pm_domain.h b/include/linux/pm_domain.h > index 1cd41bdf73cf..f776fb93eaa0 100644 > --- a/include/linux/pm_domain.h > +++ b/include/linux/pm_domain.h > @@ -136,6 +136,7 @@ struct generic_pm_domain { > unsigned int prepared_count; /* Suspend counter of prepared devices */ > unsigned int performance_state; /* Aggregated max performance state */ > cpumask_var_t cpus; /* A cpumask of the attached CPUs */ > + bool synced_poweroff; /* A consumer needs a synced poweroff */ > int (*power_off)(struct generic_pm_domain *domain); > int (*power_on)(struct generic_pm_domain *domain); > struct raw_notifier_head power_notifiers; /* Power on/off notifiers */ > @@ -235,6 +236,7 @@ int dev_pm_genpd_add_notifier(struct device *dev, struct notifier_block *nb); > int dev_pm_genpd_remove_notifier(struct device *dev); > void dev_pm_genpd_set_next_wakeup(struct device *dev, ktime_t next); > ktime_t dev_pm_genpd_get_next_hrtimer(struct device *dev); > +void dev_pm_genpd_synced_poweroff(struct device *dev); > > extern struct dev_power_governor simple_qos_governor; > extern struct dev_power_governor pm_domain_always_on_gov; > @@ -300,6 +302,9 @@ static inline ktime_t dev_pm_genpd_get_next_hrtimer(struct device *dev) > { > return KTIME_MAX; > } > +static inline void dev_pm_genpd_synced_poweroff(struct device *dev) > +{ } > + > #define simple_qos_governor (*(struct dev_power_governor *)(NULL)) > #define pm_domain_always_on_gov (*(struct dev_power_governor *)(NULL)) > #endif > -- > 2.7.4 >
On 12/29/2022 12:13 AM, Bjorn Andersson wrote: > On Wed, Dec 21, 2022 at 10:43:59PM +0530, Akhil P Oommen wrote: >> From: Ulf Hansson <ulf.hansson@linaro.org> >> >> Some genpd providers doesn't ensure that it has turned off at hardware. >> This is fine until the consumer really requires during some special >> scenarios that the power domain collapse at hardware before it is >> turned ON again. >> >> An example is the reset sequence of Adreno GPU which requires that the >> 'gpucc cx gdsc' power domain should move to OFF state in hardware at >> least once before turning in ON again to clear the internal state. >> >> Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org> >> Signed-off-by: Akhil P Oommen <quic_akhilpo@quicinc.com> > Reviewed-by: Bjorn Andersson <andersson@kernel.org> > > @Rafael, would you be willing to share an immutable branch with this > change? Or would you be okay with me doing so from the qcom clock tree? > > Regards, > Bjorn Rafael, gentle ping. Could you please check Bjorn's question here? -Akhil. > >> --- >> >> Changes in v4: >> - Update genpd function documentation (Ulf) >> >> Changes in v2: >> - Minor formatting fix >> >> drivers/base/power/domain.c | 26 ++++++++++++++++++++++++++ >> include/linux/pm_domain.h | 5 +++++ >> 2 files changed, 31 insertions(+) >> >> diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c >> index 967bcf9d415e..84662d338188 100644 >> --- a/drivers/base/power/domain.c >> +++ b/drivers/base/power/domain.c >> @@ -519,6 +519,31 @@ ktime_t dev_pm_genpd_get_next_hrtimer(struct device *dev) >> } >> EXPORT_SYMBOL_GPL(dev_pm_genpd_get_next_hrtimer); >> >> +/* >> + * dev_pm_genpd_synced_poweroff - Next power off should be synchronous >> + * >> + * @dev: A device that is attached to the genpd. >> + * >> + * Allows a consumer of the genpd to notify the provider that the next power off >> + * should be synchronous. >> + * >> + * It is assumed that the users guarantee that the genpd wouldn't be detached >> + * while this routine is getting called. >> + */ >> +void dev_pm_genpd_synced_poweroff(struct device *dev) >> +{ >> + struct generic_pm_domain *genpd; >> + >> + genpd = dev_to_genpd_safe(dev); >> + if (!genpd) >> + return; >> + >> + genpd_lock(genpd); >> + genpd->synced_poweroff = true; >> + genpd_unlock(genpd); >> +} >> +EXPORT_SYMBOL_GPL(dev_pm_genpd_synced_poweroff); >> + >> static int _genpd_power_on(struct generic_pm_domain *genpd, bool timed) >> { >> unsigned int state_idx = genpd->state_idx; >> @@ -562,6 +587,7 @@ static int _genpd_power_on(struct generic_pm_domain *genpd, bool timed) >> >> out: >> raw_notifier_call_chain(&genpd->power_notifiers, GENPD_NOTIFY_ON, NULL); >> + genpd->synced_poweroff = false; >> return 0; >> err: >> raw_notifier_call_chain(&genpd->power_notifiers, GENPD_NOTIFY_OFF, >> diff --git a/include/linux/pm_domain.h b/include/linux/pm_domain.h >> index 1cd41bdf73cf..f776fb93eaa0 100644 >> --- a/include/linux/pm_domain.h >> +++ b/include/linux/pm_domain.h >> @@ -136,6 +136,7 @@ struct generic_pm_domain { >> unsigned int prepared_count; /* Suspend counter of prepared devices */ >> unsigned int performance_state; /* Aggregated max performance state */ >> cpumask_var_t cpus; /* A cpumask of the attached CPUs */ >> + bool synced_poweroff; /* A consumer needs a synced poweroff */ >> int (*power_off)(struct generic_pm_domain *domain); >> int (*power_on)(struct generic_pm_domain *domain); >> struct raw_notifier_head power_notifiers; /* Power on/off notifiers */ >> @@ -235,6 +236,7 @@ int dev_pm_genpd_add_notifier(struct device *dev, struct notifier_block *nb); >> int dev_pm_genpd_remove_notifier(struct device *dev); >> void dev_pm_genpd_set_next_wakeup(struct device *dev, ktime_t next); >> ktime_t dev_pm_genpd_get_next_hrtimer(struct device *dev); >> +void dev_pm_genpd_synced_poweroff(struct device *dev); >> >> extern struct dev_power_governor simple_qos_governor; >> extern struct dev_power_governor pm_domain_always_on_gov; >> @@ -300,6 +302,9 @@ static inline ktime_t dev_pm_genpd_get_next_hrtimer(struct device *dev) >> { >> return KTIME_MAX; >> } >> +static inline void dev_pm_genpd_synced_poweroff(struct device *dev) >> +{ } >> + >> #define simple_qos_governor (*(struct dev_power_governor *)(NULL)) >> #define pm_domain_always_on_gov (*(struct dev_power_governor *)(NULL)) >> #endif >> -- >> 2.7.4 >>
diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c index 967bcf9d415e..84662d338188 100644 --- a/drivers/base/power/domain.c +++ b/drivers/base/power/domain.c @@ -519,6 +519,31 @@ ktime_t dev_pm_genpd_get_next_hrtimer(struct device *dev) } EXPORT_SYMBOL_GPL(dev_pm_genpd_get_next_hrtimer); +/* + * dev_pm_genpd_synced_poweroff - Next power off should be synchronous + * + * @dev: A device that is attached to the genpd. + * + * Allows a consumer of the genpd to notify the provider that the next power off + * should be synchronous. + * + * It is assumed that the users guarantee that the genpd wouldn't be detached + * while this routine is getting called. + */ +void dev_pm_genpd_synced_poweroff(struct device *dev) +{ + struct generic_pm_domain *genpd; + + genpd = dev_to_genpd_safe(dev); + if (!genpd) + return; + + genpd_lock(genpd); + genpd->synced_poweroff = true; + genpd_unlock(genpd); +} +EXPORT_SYMBOL_GPL(dev_pm_genpd_synced_poweroff); + static int _genpd_power_on(struct generic_pm_domain *genpd, bool timed) { unsigned int state_idx = genpd->state_idx; @@ -562,6 +587,7 @@ static int _genpd_power_on(struct generic_pm_domain *genpd, bool timed) out: raw_notifier_call_chain(&genpd->power_notifiers, GENPD_NOTIFY_ON, NULL); + genpd->synced_poweroff = false; return 0; err: raw_notifier_call_chain(&genpd->power_notifiers, GENPD_NOTIFY_OFF, diff --git a/include/linux/pm_domain.h b/include/linux/pm_domain.h index 1cd41bdf73cf..f776fb93eaa0 100644 --- a/include/linux/pm_domain.h +++ b/include/linux/pm_domain.h @@ -136,6 +136,7 @@ struct generic_pm_domain { unsigned int prepared_count; /* Suspend counter of prepared devices */ unsigned int performance_state; /* Aggregated max performance state */ cpumask_var_t cpus; /* A cpumask of the attached CPUs */ + bool synced_poweroff; /* A consumer needs a synced poweroff */ int (*power_off)(struct generic_pm_domain *domain); int (*power_on)(struct generic_pm_domain *domain); struct raw_notifier_head power_notifiers; /* Power on/off notifiers */ @@ -235,6 +236,7 @@ int dev_pm_genpd_add_notifier(struct device *dev, struct notifier_block *nb); int dev_pm_genpd_remove_notifier(struct device *dev); void dev_pm_genpd_set_next_wakeup(struct device *dev, ktime_t next); ktime_t dev_pm_genpd_get_next_hrtimer(struct device *dev); +void dev_pm_genpd_synced_poweroff(struct device *dev); extern struct dev_power_governor simple_qos_governor; extern struct dev_power_governor pm_domain_always_on_gov; @@ -300,6 +302,9 @@ static inline ktime_t dev_pm_genpd_get_next_hrtimer(struct device *dev) { return KTIME_MAX; } +static inline void dev_pm_genpd_synced_poweroff(struct device *dev) +{ } + #define simple_qos_governor (*(struct dev_power_governor *)(NULL)) #define pm_domain_always_on_gov (*(struct dev_power_governor *)(NULL)) #endif