Skip to content

Commit d30f83d

Browse files
Raviteja LaggyshettyGeorgi Djakov
authored andcommitted
interconnect: core: Add dynamic id allocation support
The current interconnect framework relies on static IDs for node creation and registration, which limits topologies with multiple instances of the same interconnect provider. To address this, introduce icc_node_create_dyn() and icc_link_nodes() APIs to dynamically allocate IDs for interconnect nodes during creation and link. This change removes the dependency on static IDs, allowing multiple instances of the same hardware, such as EPSS L3. Signed-off-by: Raviteja Laggyshetty <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Georgi Djakov <[email protected]>
1 parent 289198f commit d30f83d

File tree

3 files changed

+96
-1
lines changed

3 files changed

+96
-1
lines changed

drivers/interconnect/core.c

Lines changed: 81 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@
2020

2121
#include "internal.h"
2222

23+
#define ICC_DYN_ID_START 10000
24+
2325
#define CREATE_TRACE_POINTS
2426
#include "trace.h"
2527

@@ -826,7 +828,12 @@ static struct icc_node *icc_node_create_nolock(int id)
826828
if (!node)
827829
return ERR_PTR(-ENOMEM);
828830

829-
id = idr_alloc(&icc_idr, node, id, id + 1, GFP_KERNEL);
831+
/* dynamic id allocation */
832+
if (id == ICC_ALLOC_DYN_ID)
833+
id = idr_alloc(&icc_idr, node, ICC_DYN_ID_START, 0, GFP_KERNEL);
834+
else
835+
id = idr_alloc(&icc_idr, node, id, id + 1, GFP_KERNEL);
836+
830837
if (id < 0) {
831838
WARN(1, "%s: couldn't get idr\n", __func__);
832839
kfree(node);
@@ -838,6 +845,25 @@ static struct icc_node *icc_node_create_nolock(int id)
838845
return node;
839846
}
840847

848+
/**
849+
* icc_node_create_dyn() - create a node with dynamic id
850+
*
851+
* Return: icc_node pointer on success, or ERR_PTR() on error
852+
*/
853+
struct icc_node *icc_node_create_dyn(void)
854+
{
855+
struct icc_node *node;
856+
857+
mutex_lock(&icc_lock);
858+
859+
node = icc_node_create_nolock(ICC_ALLOC_DYN_ID);
860+
861+
mutex_unlock(&icc_lock);
862+
863+
return node;
864+
}
865+
EXPORT_SYMBOL_GPL(icc_node_create_dyn);
866+
841867
/**
842868
* icc_node_create() - create a node
843869
* @id: node id
@@ -884,6 +910,56 @@ void icc_node_destroy(int id)
884910
}
885911
EXPORT_SYMBOL_GPL(icc_node_destroy);
886912

913+
/**
914+
* icc_link_nodes() - create link between two nodes
915+
* @src_node: source node
916+
* @dst_node: destination node
917+
*
918+
* Create a link between two nodes. The nodes might belong to different
919+
* interconnect providers and the @dst_node might not exist (if the
920+
* provider driver has not probed yet). So just create the @dst_node
921+
* and when the actual provider driver is probed, the rest of the node
922+
* data is filled.
923+
*
924+
* Return: 0 on success, or an error code otherwise
925+
*/
926+
int icc_link_nodes(struct icc_node *src_node, struct icc_node **dst_node)
927+
{
928+
struct icc_node **new;
929+
int ret = 0;
930+
931+
if (!src_node->provider)
932+
return -EINVAL;
933+
934+
mutex_lock(&icc_lock);
935+
936+
if (!*dst_node) {
937+
*dst_node = icc_node_create_nolock(ICC_ALLOC_DYN_ID);
938+
939+
if (IS_ERR(*dst_node)) {
940+
ret = PTR_ERR(*dst_node);
941+
goto out;
942+
}
943+
}
944+
945+
new = krealloc(src_node->links,
946+
(src_node->num_links + 1) * sizeof(*src_node->links),
947+
GFP_KERNEL);
948+
if (!new) {
949+
ret = -ENOMEM;
950+
goto out;
951+
}
952+
953+
src_node->links = new;
954+
src_node->links[src_node->num_links++] = *dst_node;
955+
956+
out:
957+
mutex_unlock(&icc_lock);
958+
959+
return ret;
960+
}
961+
EXPORT_SYMBOL_GPL(icc_link_nodes);
962+
887963
/**
888964
* icc_link_create() - create a link between two nodes
889965
* @node: source node id
@@ -962,6 +1038,10 @@ void icc_node_add(struct icc_node *node, struct icc_provider *provider)
9621038
node->avg_bw = node->init_avg;
9631039
node->peak_bw = node->init_peak;
9641040

1041+
if (node->id >= ICC_DYN_ID_START)
1042+
node->name = devm_kasprintf(provider->dev, GFP_KERNEL, "%s@%s",
1043+
node->name, dev_name(provider->dev));
1044+
9651045
if (node->avg_bw || node->peak_bw) {
9661046
if (provider->pre_aggregate)
9671047
provider->pre_aggregate(node);

include/linux/interconnect-provider.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,8 +116,10 @@ struct icc_node {
116116

117117
int icc_std_aggregate(struct icc_node *node, u32 tag, u32 avg_bw,
118118
u32 peak_bw, u32 *agg_avg, u32 *agg_peak);
119+
struct icc_node *icc_node_create_dyn(void);
119120
struct icc_node *icc_node_create(int id);
120121
void icc_node_destroy(int id);
122+
int icc_link_nodes(struct icc_node *src_node, struct icc_node **dst_node);
121123
int icc_link_create(struct icc_node *node, const int dst_id);
122124
void icc_node_add(struct icc_node *node, struct icc_provider *provider);
123125
void icc_node_del(struct icc_node *node);
@@ -136,6 +138,11 @@ static inline int icc_std_aggregate(struct icc_node *node, u32 tag, u32 avg_bw,
136138
return -ENOTSUPP;
137139
}
138140

141+
static inline struct icc_node *icc_node_create_dyn(void)
142+
{
143+
return ERR_PTR(-EOPNOTSUPP);
144+
}
145+
139146
static inline struct icc_node *icc_node_create(int id)
140147
{
141148
return ERR_PTR(-ENOTSUPP);
@@ -145,6 +152,11 @@ static inline void icc_node_destroy(int id)
145152
{
146153
}
147154

155+
static inline int icc_link_nodes(struct icc_node *src_node, struct icc_node **dst_node)
156+
{
157+
return -EOPNOTSUPP;
158+
}
159+
148160
static inline int icc_link_create(struct icc_node *node, const int dst_id)
149161
{
150162
return -ENOTSUPP;

include/linux/interconnect.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@
2020
#define Mbps_to_icc(x) ((x) * 1000 / 8)
2121
#define Gbps_to_icc(x) ((x) * 1000 * 1000 / 8)
2222

23+
/* macro to indicate dynamic id allocation */
24+
#define ICC_ALLOC_DYN_ID -1
25+
2326
struct icc_path;
2427
struct device;
2528

0 commit comments

Comments
 (0)