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>pull/1259/head
commit
5fed7fe33c
|
|
@ -28,6 +28,7 @@ properties:
|
|||
- const: qcom,osm-l3
|
||||
- items:
|
||||
- enum:
|
||||
- qcom,sa8775p-epss-l3
|
||||
- qcom,sc7280-epss-l3
|
||||
- qcom,sc8280xp-epss-l3
|
||||
- qcom,sm6375-cpucp-l3
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
@ -838,6 +845,25 @@ static struct icc_node *icc_node_create_nolock(int id)
|
|||
return node;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
|
|
@ -884,6 +910,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
|
||||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -280,7 +280,14 @@ int qcom_icc_rpmh_probe(struct platform_device *pdev)
|
|||
if (!qn)
|
||||
continue;
|
||||
|
||||
node = icc_node_create(qn->id);
|
||||
if (desc->alloc_dyn_id) {
|
||||
if (!qn->node)
|
||||
qn->node = icc_node_create_dyn();
|
||||
node = qn->node;
|
||||
} else {
|
||||
node = icc_node_create(qn->id);
|
||||
}
|
||||
|
||||
if (IS_ERR(node)) {
|
||||
ret = PTR_ERR(node);
|
||||
goto err_remove_nodes;
|
||||
|
|
@ -290,8 +297,12 @@ int qcom_icc_rpmh_probe(struct platform_device *pdev)
|
|||
node->data = qn;
|
||||
icc_node_add(node, provider);
|
||||
|
||||
for (j = 0; j < qn->num_links; j++)
|
||||
icc_link_create(node, qn->links[j]);
|
||||
for (j = 0; j < qn->num_links; j++) {
|
||||
if (desc->alloc_dyn_id)
|
||||
icc_link_nodes(node, &qn->link_nodes[j]->node);
|
||||
else
|
||||
icc_link_create(node, qn->links[j]);
|
||||
}
|
||||
|
||||
data->nodes[i] = node;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -83,6 +83,8 @@ struct qcom_icc_qosbox {
|
|||
* @name: the node name used in debugfs
|
||||
* @links: an array of nodes where we can go next while traversing
|
||||
* @id: a unique node identifier
|
||||
* @link_nodes: links associated with this node
|
||||
* @node: icc_node associated with this node
|
||||
* @num_links: the total number of @links
|
||||
* @channels: num of channels at this node
|
||||
* @buswidth: width of the interconnect between a node and the bus
|
||||
|
|
@ -96,6 +98,8 @@ struct qcom_icc_node {
|
|||
const char *name;
|
||||
u16 links[MAX_LINKS];
|
||||
u16 id;
|
||||
struct qcom_icc_node **link_nodes;
|
||||
struct icc_node *node;
|
||||
u16 num_links;
|
||||
u16 channels;
|
||||
u16 buswidth;
|
||||
|
|
@ -154,6 +158,7 @@ struct qcom_icc_desc {
|
|||
struct qcom_icc_bcm * const *bcms;
|
||||
size_t num_bcms;
|
||||
bool qos_requires_clocks;
|
||||
bool alloc_dyn_id;
|
||||
};
|
||||
|
||||
int qcom_icc_aggregate(struct icc_node *node, u32 tag, u32 avg_bw,
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Copyright (c) 2020-2021, The Linux Foundation. All rights reserved.
|
||||
* Copyright (c) 2025 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
*/
|
||||
|
||||
#include <linux/args.h>
|
||||
|
|
@ -32,8 +33,6 @@
|
|||
#define EPSS_REG_FREQ_LUT 0x100
|
||||
#define EPSS_REG_PERF_STATE 0x320
|
||||
|
||||
#define OSM_L3_MAX_LINKS 1
|
||||
|
||||
#define to_osm_l3_provider(_provider) \
|
||||
container_of(_provider, struct qcom_osm_l3_icc_provider, provider)
|
||||
|
||||
|
|
@ -48,16 +47,10 @@ struct qcom_osm_l3_icc_provider {
|
|||
/**
|
||||
* struct qcom_osm_l3_node - Qualcomm specific interconnect nodes
|
||||
* @name: the node name used in debugfs
|
||||
* @links: an array of nodes where we can go next while traversing
|
||||
* @id: a unique node identifier
|
||||
* @num_links: the total number of @links
|
||||
* @buswidth: width of the interconnect between a node and the bus
|
||||
*/
|
||||
struct qcom_osm_l3_node {
|
||||
const char *name;
|
||||
u16 links[OSM_L3_MAX_LINKS];
|
||||
u16 id;
|
||||
u16 num_links;
|
||||
u16 buswidth;
|
||||
};
|
||||
|
||||
|
|
@ -69,30 +62,22 @@ struct qcom_osm_l3_desc {
|
|||
unsigned int reg_perf_state;
|
||||
};
|
||||
|
||||
enum {
|
||||
OSM_L3_MASTER_NODE = 10000,
|
||||
OSM_L3_SLAVE_NODE,
|
||||
};
|
||||
|
||||
#define DEFINE_QNODE(_name, _id, _buswidth, ...) \
|
||||
#define DEFINE_QNODE(_name, _buswidth) \
|
||||
static const struct qcom_osm_l3_node _name = { \
|
||||
.name = #_name, \
|
||||
.id = _id, \
|
||||
.buswidth = _buswidth, \
|
||||
.num_links = COUNT_ARGS(__VA_ARGS__), \
|
||||
.links = { __VA_ARGS__ }, \
|
||||
}
|
||||
|
||||
DEFINE_QNODE(osm_l3_master, OSM_L3_MASTER_NODE, 16, OSM_L3_SLAVE_NODE);
|
||||
DEFINE_QNODE(osm_l3_slave, OSM_L3_SLAVE_NODE, 16);
|
||||
DEFINE_QNODE(osm_l3_slave, 16);
|
||||
DEFINE_QNODE(osm_l3_master, 16);
|
||||
|
||||
static const struct qcom_osm_l3_node * const osm_l3_nodes[] = {
|
||||
[MASTER_OSM_L3_APPS] = &osm_l3_master,
|
||||
[SLAVE_OSM_L3] = &osm_l3_slave,
|
||||
};
|
||||
|
||||
DEFINE_QNODE(epss_l3_master, OSM_L3_MASTER_NODE, 32, OSM_L3_SLAVE_NODE);
|
||||
DEFINE_QNODE(epss_l3_slave, OSM_L3_SLAVE_NODE, 32);
|
||||
DEFINE_QNODE(epss_l3_slave, 32);
|
||||
DEFINE_QNODE(epss_l3_master, 32);
|
||||
|
||||
static const struct qcom_osm_l3_node * const epss_l3_nodes[] = {
|
||||
[MASTER_EPSS_L3_APPS] = &epss_l3_master,
|
||||
|
|
@ -242,10 +227,10 @@ static int qcom_osm_l3_probe(struct platform_device *pdev)
|
|||
|
||||
icc_provider_init(provider);
|
||||
|
||||
/* Create nodes */
|
||||
for (i = 0; i < num_nodes; i++) {
|
||||
size_t j;
|
||||
node = icc_node_create_dyn();
|
||||
|
||||
node = icc_node_create(qnodes[i]->id);
|
||||
if (IS_ERR(node)) {
|
||||
ret = PTR_ERR(node);
|
||||
goto err;
|
||||
|
|
@ -256,12 +241,12 @@ static int qcom_osm_l3_probe(struct platform_device *pdev)
|
|||
node->data = (void *)qnodes[i];
|
||||
icc_node_add(node, provider);
|
||||
|
||||
for (j = 0; j < qnodes[i]->num_links; j++)
|
||||
icc_link_create(node, qnodes[i]->links[j]);
|
||||
|
||||
data->nodes[i] = node;
|
||||
}
|
||||
|
||||
/* Create link */
|
||||
icc_link_nodes(data->nodes[MASTER_OSM_L3_APPS], &data->nodes[SLAVE_OSM_L3]);
|
||||
|
||||
ret = icc_provider_register(provider);
|
||||
if (ret)
|
||||
goto err;
|
||||
|
|
@ -278,6 +263,7 @@ err:
|
|||
static const struct of_device_id osm_l3_of_match[] = {
|
||||
{ .compatible = "qcom,epss-l3", .data = &epss_l3_l3_vote },
|
||||
{ .compatible = "qcom,osm-l3", .data = &osm_l3 },
|
||||
{ .compatible = "qcom,sa8775p-epss-l3", .data = &epss_l3_perf_state },
|
||||
{ .compatible = "qcom,sc7180-osm-l3", .data = &osm_l3 },
|
||||
{ .compatible = "qcom,sc7280-epss-l3", .data = &epss_l3_perf_state },
|
||||
{ .compatible = "qcom,sdm845-osm-l3", .data = &osm_l3 },
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -116,8 +116,10 @@ struct icc_node {
|
|||
|
||||
int icc_std_aggregate(struct icc_node *node, u32 tag, u32 avg_bw,
|
||||
u32 peak_bw, u32 *agg_avg, u32 *agg_peak);
|
||||
struct icc_node *icc_node_create_dyn(void);
|
||||
struct icc_node *icc_node_create(int id);
|
||||
void icc_node_destroy(int id);
|
||||
int icc_link_nodes(struct icc_node *src_node, struct icc_node **dst_node);
|
||||
int icc_link_create(struct icc_node *node, const int dst_id);
|
||||
void icc_node_add(struct icc_node *node, struct icc_provider *provider);
|
||||
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,
|
|||
return -ENOTSUPP;
|
||||
}
|
||||
|
||||
static inline struct icc_node *icc_node_create_dyn(void)
|
||||
{
|
||||
return ERR_PTR(-EOPNOTSUPP);
|
||||
}
|
||||
|
||||
static inline struct icc_node *icc_node_create(int id)
|
||||
{
|
||||
return ERR_PTR(-ENOTSUPP);
|
||||
|
|
@ -145,6 +152,11 @@ static inline void icc_node_destroy(int id)
|
|||
{
|
||||
}
|
||||
|
||||
static inline int icc_link_nodes(struct icc_node *src_node, struct icc_node **dst_node)
|
||||
{
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static inline int icc_link_create(struct icc_node *node, const int dst_id)
|
||||
{
|
||||
return -ENOTSUPP;
|
||||
|
|
|
|||
|
|
@ -20,6 +20,9 @@
|
|||
#define Mbps_to_icc(x) ((x) * 1000 / 8)
|
||||
#define Gbps_to_icc(x) ((x) * 1000 * 1000 / 8)
|
||||
|
||||
/* macro to indicate dynamic id allocation */
|
||||
#define ICC_ALLOC_DYN_ID -1
|
||||
|
||||
struct icc_path;
|
||||
struct device;
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue