Message ID | 1738736156-119203-4-git-send-email-shawn.lin@rock-chips.com |
---|---|
State | New |
Headers | show |
Series | None | expand |
On Wed, Feb 05, 2025 at 02:15:52PM +0800, Shawn Lin wrote: > From: Ulf Hansson <ulf.hansson@linaro.org> > > For some usecases a consumer driver requires its device to remain power-on > from the PM domain perspective during runtime. Using dev PM qos along with > the genpd governors, doesn't work for this case as would potentially > prevent the device from being runtime suspended too. > > To support these usecases, let's introduce dev_pm_genpd_rpm_always_on() to > allow consumers drivers to dynamically control the behaviour in genpd for a > device that is attached to it. > > Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org> > Signed-off-by: Shawn Lin <shawn.lin@rock-chips.com> Acked-by: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org> - Mani > --- > > Changes in v7: None > Changes in v6: > - export dev_pm_genpd_rpm_always_on() > > Changes in v5: None > Changes in v4: None > Changes in v3: None > Changes in v2: None > > drivers/pmdomain/core.c | 35 +++++++++++++++++++++++++++++++++++ > include/linux/pm_domain.h | 7 +++++++ > 2 files changed, 42 insertions(+) > > diff --git a/drivers/pmdomain/core.c b/drivers/pmdomain/core.c > index 6c94137..9b2f28b 100644 > --- a/drivers/pmdomain/core.c > +++ b/drivers/pmdomain/core.c > @@ -697,6 +697,37 @@ bool dev_pm_genpd_get_hwmode(struct device *dev) > } > EXPORT_SYMBOL_GPL(dev_pm_genpd_get_hwmode); > > +/** > + * dev_pm_genpd_rpm_always_on() - Control if the PM domain can be powered off. > + * > + * @dev: Device for which the PM domain may need to stay on for. > + * @on: Value to set or unset for the condition. > + * > + * For some usecases a consumer driver requires its device to remain power-on > + * from the PM domain perspective during runtime. This function allows the > + * behaviour to be dynamically controlled for a device attached to a genpd. > + * > + * It is assumed that the users guarantee that the genpd wouldn't be detached > + * while this routine is getting called. > + * > + * Return: Returns 0 on success and negative error values on failures. > + */ > +int dev_pm_genpd_rpm_always_on(struct device *dev, bool on) > +{ > + struct generic_pm_domain *genpd; > + > + genpd = dev_to_genpd_safe(dev); > + if (!genpd) > + return -ENODEV; > + > + genpd_lock(genpd); > + dev_gpd_data(dev)->rpm_always_on = on; > + genpd_unlock(genpd); > + > + return 0; > +} > +EXPORT_SYMBOL_GPL(dev_pm_genpd_rpm_always_on); > + > static int _genpd_power_on(struct generic_pm_domain *genpd, bool timed) > { > unsigned int state_idx = genpd->state_idx; > @@ -868,6 +899,10 @@ static int genpd_power_off(struct generic_pm_domain *genpd, bool one_dev_on, > if (!pm_runtime_suspended(pdd->dev) || > irq_safe_dev_in_sleep_domain(pdd->dev, genpd)) > not_suspended++; > + > + /* The device may need its PM domain to stay powered on. */ > + if (to_gpd_data(pdd)->rpm_always_on) > + return -EBUSY; > } > > if (not_suspended > 1 || (not_suspended == 1 && !one_dev_on)) > diff --git a/include/linux/pm_domain.h b/include/linux/pm_domain.h > index 1aab313..d56a78a 100644 > --- a/include/linux/pm_domain.h > +++ b/include/linux/pm_domain.h > @@ -261,6 +261,7 @@ struct generic_pm_domain_data { > unsigned int rpm_pstate; > unsigned int opp_token; > bool hw_mode; > + bool rpm_always_on; > void *data; > }; > > @@ -293,6 +294,7 @@ ktime_t dev_pm_genpd_get_next_hrtimer(struct device *dev); > void dev_pm_genpd_synced_poweroff(struct device *dev); > int dev_pm_genpd_set_hwmode(struct device *dev, bool enable); > bool dev_pm_genpd_get_hwmode(struct device *dev); > +int dev_pm_genpd_rpm_always_on(struct device *dev, bool on); > > extern struct dev_power_governor simple_qos_governor; > extern struct dev_power_governor pm_domain_always_on_gov; > @@ -376,6 +378,11 @@ static inline bool dev_pm_genpd_get_hwmode(struct device *dev) > return false; > } > > +static inline int dev_pm_genpd_rpm_always_on(struct device *dev, bool on) > +{ > + return -EOPNOTSUPP; > +} > + > #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/pmdomain/core.c b/drivers/pmdomain/core.c index 6c94137..9b2f28b 100644 --- a/drivers/pmdomain/core.c +++ b/drivers/pmdomain/core.c @@ -697,6 +697,37 @@ bool dev_pm_genpd_get_hwmode(struct device *dev) } EXPORT_SYMBOL_GPL(dev_pm_genpd_get_hwmode); +/** + * dev_pm_genpd_rpm_always_on() - Control if the PM domain can be powered off. + * + * @dev: Device for which the PM domain may need to stay on for. + * @on: Value to set or unset for the condition. + * + * For some usecases a consumer driver requires its device to remain power-on + * from the PM domain perspective during runtime. This function allows the + * behaviour to be dynamically controlled for a device attached to a genpd. + * + * It is assumed that the users guarantee that the genpd wouldn't be detached + * while this routine is getting called. + * + * Return: Returns 0 on success and negative error values on failures. + */ +int dev_pm_genpd_rpm_always_on(struct device *dev, bool on) +{ + struct generic_pm_domain *genpd; + + genpd = dev_to_genpd_safe(dev); + if (!genpd) + return -ENODEV; + + genpd_lock(genpd); + dev_gpd_data(dev)->rpm_always_on = on; + genpd_unlock(genpd); + + return 0; +} +EXPORT_SYMBOL_GPL(dev_pm_genpd_rpm_always_on); + static int _genpd_power_on(struct generic_pm_domain *genpd, bool timed) { unsigned int state_idx = genpd->state_idx; @@ -868,6 +899,10 @@ static int genpd_power_off(struct generic_pm_domain *genpd, bool one_dev_on, if (!pm_runtime_suspended(pdd->dev) || irq_safe_dev_in_sleep_domain(pdd->dev, genpd)) not_suspended++; + + /* The device may need its PM domain to stay powered on. */ + if (to_gpd_data(pdd)->rpm_always_on) + return -EBUSY; } if (not_suspended > 1 || (not_suspended == 1 && !one_dev_on)) diff --git a/include/linux/pm_domain.h b/include/linux/pm_domain.h index 1aab313..d56a78a 100644 --- a/include/linux/pm_domain.h +++ b/include/linux/pm_domain.h @@ -261,6 +261,7 @@ struct generic_pm_domain_data { unsigned int rpm_pstate; unsigned int opp_token; bool hw_mode; + bool rpm_always_on; void *data; }; @@ -293,6 +294,7 @@ ktime_t dev_pm_genpd_get_next_hrtimer(struct device *dev); void dev_pm_genpd_synced_poweroff(struct device *dev); int dev_pm_genpd_set_hwmode(struct device *dev, bool enable); bool dev_pm_genpd_get_hwmode(struct device *dev); +int dev_pm_genpd_rpm_always_on(struct device *dev, bool on); extern struct dev_power_governor simple_qos_governor; extern struct dev_power_governor pm_domain_always_on_gov; @@ -376,6 +378,11 @@ static inline bool dev_pm_genpd_get_hwmode(struct device *dev) return false; } +static inline int dev_pm_genpd_rpm_always_on(struct device *dev, bool on) +{ + return -EOPNOTSUPP; +} + #define simple_qos_governor (*(struct dev_power_governor *)(NULL)) #define pm_domain_always_on_gov (*(struct dev_power_governor *)(NULL)) #endif