Skip to content

Commit cd3fa30

Browse files
committed
pmdomain: core: Introduce dev_pm_genpd_rpm_always_on()
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 <[email protected]> Signed-off-by: Shawn Lin <[email protected]> Acked-by: Manivannan Sadhasivam <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Ulf Hansson <[email protected]>
1 parent 184055a commit cd3fa30

File tree

2 files changed

+42
-0
lines changed

2 files changed

+42
-0
lines changed

drivers/pmdomain/core.c

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -697,6 +697,37 @@ bool dev_pm_genpd_get_hwmode(struct device *dev)
697697
}
698698
EXPORT_SYMBOL_GPL(dev_pm_genpd_get_hwmode);
699699

700+
/**
701+
* dev_pm_genpd_rpm_always_on() - Control if the PM domain can be powered off.
702+
*
703+
* @dev: Device for which the PM domain may need to stay on for.
704+
* @on: Value to set or unset for the condition.
705+
*
706+
* For some usecases a consumer driver requires its device to remain power-on
707+
* from the PM domain perspective during runtime. This function allows the
708+
* behaviour to be dynamically controlled for a device attached to a genpd.
709+
*
710+
* It is assumed that the users guarantee that the genpd wouldn't be detached
711+
* while this routine is getting called.
712+
*
713+
* Return: Returns 0 on success and negative error values on failures.
714+
*/
715+
int dev_pm_genpd_rpm_always_on(struct device *dev, bool on)
716+
{
717+
struct generic_pm_domain *genpd;
718+
719+
genpd = dev_to_genpd_safe(dev);
720+
if (!genpd)
721+
return -ENODEV;
722+
723+
genpd_lock(genpd);
724+
dev_gpd_data(dev)->rpm_always_on = on;
725+
genpd_unlock(genpd);
726+
727+
return 0;
728+
}
729+
EXPORT_SYMBOL_GPL(dev_pm_genpd_rpm_always_on);
730+
700731
static int _genpd_power_on(struct generic_pm_domain *genpd, bool timed)
701732
{
702733
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,
868899
if (!pm_runtime_suspended(pdd->dev) ||
869900
irq_safe_dev_in_sleep_domain(pdd->dev, genpd))
870901
not_suspended++;
902+
903+
/* The device may need its PM domain to stay powered on. */
904+
if (to_gpd_data(pdd)->rpm_always_on)
905+
return -EBUSY;
871906
}
872907

873908
if (not_suspended > 1 || (not_suspended == 1 && !one_dev_on))

include/linux/pm_domain.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -261,6 +261,7 @@ struct generic_pm_domain_data {
261261
unsigned int rpm_pstate;
262262
unsigned int opp_token;
263263
bool hw_mode;
264+
bool rpm_always_on;
264265
void *data;
265266
};
266267

@@ -293,6 +294,7 @@ ktime_t dev_pm_genpd_get_next_hrtimer(struct device *dev);
293294
void dev_pm_genpd_synced_poweroff(struct device *dev);
294295
int dev_pm_genpd_set_hwmode(struct device *dev, bool enable);
295296
bool dev_pm_genpd_get_hwmode(struct device *dev);
297+
int dev_pm_genpd_rpm_always_on(struct device *dev, bool on);
296298

297299
extern struct dev_power_governor simple_qos_governor;
298300
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)
376378
return false;
377379
}
378380

381+
static inline int dev_pm_genpd_rpm_always_on(struct device *dev, bool on)
382+
{
383+
return -EOPNOTSUPP;
384+
}
385+
379386
#define simple_qos_governor (*(struct dev_power_governor *)(NULL))
380387
#define pm_domain_always_on_gov (*(struct dev_power_governor *)(NULL))
381388
#endif

0 commit comments

Comments
 (0)