diff options
| author | Georgi Djakov <djakov@kernel.org> | 2025-05-19 17:09:50 +0300 |
|---|---|---|
| committer | Georgi Djakov <djakov@kernel.org> | 2025-05-19 17:09:50 +0300 |
| commit | 5fed7fe33c2cd7104fc87b7bc699a7be892befa2 (patch) | |
| tree | 0b5de5a07078060f964bd64bdead3893f4b5926a /drivers/interconnect/core.c | |
| parent | b0779ea486061a1756892f4ea43e258e5dd559cd (diff) | |
| parent | b1244645ad6c79d89974c015abe552d47a42dbdc (diff) | |
Merge branch 'icc-sa8775p' into icc-next
Add Epoch Subsystem (EPSS) L3 provider support on SA8775P SoCs.
Current interconnect framework is based on static IDs for creating node
and registering with framework. This becomes a limitation for topologies
where there are multiple instances of same interconnect provider.
Modified interconnect framework APIs to create and link icc node with
dynamic IDs, this will help to overcome the dependency on static IDs.
* icc-sa8775p
dt-bindings: interconnect: Add EPSS L3 compatible for SA8775P
interconnect: core: Add dynamic id allocation support
interconnect: qcom: Add multidev EPSS L3 support
interconnect: qcom: icc-rpmh: Add dynamic icc node id support
interconnect: qcom: sa8775p: Add dynamic icc node id support
Link: https://lore.kernel.org/r/20250415095343.32125-1-quic_rlaggysh@quicinc.com
Signed-off-by: Georgi Djakov <djakov@kernel.org>
Diffstat (limited to 'drivers/interconnect/core.c')
| -rw-r--r-- | drivers/interconnect/core.c | 82 |
1 files changed, 81 insertions, 1 deletions
diff --git a/drivers/interconnect/core.c b/drivers/interconnect/core.c index 9d5404a07e8a..1a41e59c77f8 100644 --- a/drivers/interconnect/core.c +++ b/drivers/interconnect/core.c @@ -20,6 +20,8 @@ #include "internal.h" +#define ICC_DYN_ID_START 10000 + #define CREATE_TRACE_POINTS #include "trace.h" @@ -826,7 +828,12 @@ static struct icc_node *icc_node_create_nolock(int id) if (!node) return ERR_PTR(-ENOMEM); - id = idr_alloc(&icc_idr, node, id, id + 1, GFP_KERNEL); + /* dynamic id allocation */ + if (id == ICC_ALLOC_DYN_ID) + id = idr_alloc(&icc_idr, node, ICC_DYN_ID_START, 0, GFP_KERNEL); + else + id = idr_alloc(&icc_idr, node, id, id + 1, GFP_KERNEL); + if (id < 0) { WARN(1, "%s: couldn't get idr\n", __func__); kfree(node); @@ -839,6 +846,25 @@ static struct icc_node *icc_node_create_nolock(int id) } /** + * icc_node_create_dyn() - create a node with dynamic id + * + * Return: icc_node pointer on success, or ERR_PTR() on error + */ +struct icc_node *icc_node_create_dyn(void) +{ + struct icc_node *node; + + mutex_lock(&icc_lock); + + node = icc_node_create_nolock(ICC_ALLOC_DYN_ID); + + mutex_unlock(&icc_lock); + + return node; +} +EXPORT_SYMBOL_GPL(icc_node_create_dyn); + +/** * icc_node_create() - create a node * @id: node id * @@ -885,6 +911,56 @@ void icc_node_destroy(int id) EXPORT_SYMBOL_GPL(icc_node_destroy); /** + * icc_link_nodes() - create link between two nodes + * @src_node: source node + * @dst_node: destination node + * + * Create a link between two nodes. The nodes might belong to different + * interconnect providers and the @dst_node might not exist (if the + * provider driver has not probed yet). So just create the @dst_node + * and when the actual provider driver is probed, the rest of the node + * data is filled. + * + * Return: 0 on success, or an error code otherwise + */ +int icc_link_nodes(struct icc_node *src_node, struct icc_node **dst_node) +{ + struct icc_node **new; + int ret = 0; + + if (!src_node->provider) + return -EINVAL; + + mutex_lock(&icc_lock); + + if (!*dst_node) { + *dst_node = icc_node_create_nolock(ICC_ALLOC_DYN_ID); + + if (IS_ERR(*dst_node)) { + ret = PTR_ERR(*dst_node); + goto out; + } + } + + new = krealloc(src_node->links, + (src_node->num_links + 1) * sizeof(*src_node->links), + GFP_KERNEL); + if (!new) { + ret = -ENOMEM; + goto out; + } + + src_node->links = new; + src_node->links[src_node->num_links++] = *dst_node; + +out: + mutex_unlock(&icc_lock); + + return ret; +} +EXPORT_SYMBOL_GPL(icc_link_nodes); + +/** * icc_link_create() - create a link between two nodes * @node: source node id * @dst_id: destination node id @@ -962,6 +1038,10 @@ void icc_node_add(struct icc_node *node, struct icc_provider *provider) node->avg_bw = node->init_avg; node->peak_bw = node->init_peak; + if (node->id >= ICC_DYN_ID_START) + node->name = devm_kasprintf(provider->dev, GFP_KERNEL, "%s@%s", + node->name, dev_name(provider->dev)); + if (node->avg_bw || node->peak_bw) { if (provider->pre_aggregate) provider->pre_aggregate(node); |
