pmdomain: core: add genpd_for_each_child() helper

Add a new internal helper function genpd_for_each_child() that recursively
iterates over all devices in a PM domain and its child domains (subdomains).
This helper is useful for governors and other core PM domain code that needs
to examine or apply operations to all devices within a domain hierarchy.

The function takes a callback that is invoked for each device, and supports
early termination if the callback returns a non-zero value.

The helper is defined in a new internal header drivers/pmdomain/core.h and
implemented in drivers/pmdomain/core.c, making it available to other PM
domain subsystem components.

The first user of this helper is the cpu_system_power_down_ok() governor
function, which uses it to check device QoS latency constraints across the
entire domain hierarchy.

Reviewed-by: Abel Vesa <abel.vesa@oss.qualcomm.com>
Signed-off-by: Kevin Hilman (TI) <khilman@baylibre.com>
Signed-off-by: Ulf Hansson <ulfh@kernel.org>
This commit is contained in:
Kevin Hilman (TI) 2026-09-24 13:29:58 -07:00 committed by Ulf Hansson
parent b7cbbc33bc
commit 44ff5057d7
2 changed files with 62 additions and 0 deletions

View File

@ -27,6 +27,7 @@
#include <linux/debugfs.h>
#include <trace/events/ipi.h>
#include "core.h"
/* Provides a unique ID for each genpd device */
static DEFINE_IDA(genpd_ida);
@ -283,6 +284,49 @@ static void genpd_sd_counter_inc(struct generic_pm_domain *genpd)
smp_mb__after_atomic();
}
/**
* genpd_for_each_child - Recursively iterate over all devices
* in a PM domain and its subdomains.
* @genpd: PM domain to iterate over.
* @fn: Callback function to invoke for each device.
* @data: Data to pass to the callback function.
*
* This function recursively walks through all devices in the given PM domain
* and all devices in its child PM domains (subdomains). For each device found,
* the callback function @fn is invoked with the device and @data as arguments.
*
* Note: this function is inteded for use by the core and governors,
* not for pmdomain providers.
*
* Returns: 0 on success, or the first non-zero value returned by @fn.
*/
int genpd_for_each_child(struct generic_pm_domain *genpd,
int (*fn)(struct device *dev, void *data),
void *data)
{
struct pm_domain_data *pdd;
struct gpd_link *link;
int ret;
/* First, iterate over all devices in this domain */
list_for_each_entry(pdd, &genpd->dev_list, list_node) {
ret = fn(pdd->dev, data);
if (ret)
return ret;
}
/* Then, recursively iterate over all child domains (subdomains) */
list_for_each_entry(link, &genpd->parent_links, parent_node) {
struct generic_pm_domain *child_pd = link->child;
ret = genpd_for_each_child(child_pd, fn, data);
if (ret)
return ret;
}
return 0;
}
#ifdef CONFIG_DEBUG_FS
static struct dentry *genpd_debugfs_dir;

18
drivers/pmdomain/core.h Normal file
View File

@ -0,0 +1,18 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Internal header for PM domain core
*
* Copyright (C) 2026 Kevin Hilman <khilman@baylibre.com>, Texas Instruments
*/
#ifndef __PM_DOMAIN_CORE_H__
#define __PM_DOMAIN_CORE_H__
struct device;
struct generic_pm_domain;
int genpd_for_each_child(struct generic_pm_domain *genpd,
int (*fn)(struct device *dev, void *data),
void *data);
#endif /* __PM_DOMAIN_CORE_H__ */