mirror of
https://github.com/torvalds/linux.git
synced 2026-11-07 06:17:02 +01:00
interconnect: qcom: implement get_bw with rpmh_read
Since we can actually read back the APPS rpmh interconnect BCM votes we can actually implement the get_bw() callback and provide a coherent average and peak bandwidth at probe time. The benefits of that are: - keep disabled BCMs disabled - avoid voting unused BCMs to INT_MAX If the interconnects are correctly described for a platform, all the required BCMs would be voted to the maximum bandwidth until sync_state is reached. Since we only get the BCM vote, we need to redistribute the vote values to the associated nodes. The initial BCM votes are read back at probe time in order to be ready when the get_bw() is called when a node is added. Tested-by: Georgi Djakov <djakov@kernel.org> #db845c Signed-off-by: Neil Armstrong <neil.armstrong@linaro.org> Reviewed-by: Abel Vesa <abel.vesa@oss.qualcomm.com> Link: https://patch.msgid.link/20260909-topic-sm8x50-icc-read-rpmh-v3-1-2bc65d7b25e5@linaro.org Signed-off-by: Georgi Djakov <djakov@kernel.org>
This commit is contained in:
parent
601a54f007
commit
11a44c6087
|
|
@ -261,6 +261,40 @@ void qcom_icc_bcm_voter_add(struct bcm_voter *voter, struct qcom_icc_bcm *bcm)
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(qcom_icc_bcm_voter_add);
|
||||
|
||||
/**
|
||||
* qcom_icc_bcm_get_bw - get current bcm vote
|
||||
* @voter: voter used to query bcm
|
||||
* @bcm: bcm to get current vote from
|
||||
*/
|
||||
void qcom_icc_bcm_get_bw(struct bcm_voter *voter,
|
||||
struct qcom_icc_bcm *bcm)
|
||||
{
|
||||
struct tcs_cmd cmd = { .addr = bcm->addr };
|
||||
int ret, i;
|
||||
u64 x, y;
|
||||
|
||||
mutex_lock(&voter->lock);
|
||||
|
||||
ret = rpmh_read(voter->dev, &cmd);
|
||||
if (ret) {
|
||||
pr_err("Error sending AMC RPMH requests (%d)\n", ret);
|
||||
goto out;
|
||||
}
|
||||
|
||||
x = FIELD_GET(BCM_TCS_CMD_VOTE_X_MASK, cmd.data);
|
||||
y = FIELD_GET(BCM_TCS_CMD_VOTE_Y_MASK, cmd.data);
|
||||
|
||||
/* For boot-up, fill the AMC vote in all buckets */
|
||||
for (i = 0; i < QCOM_ICC_NUM_BUCKETS; i++) {
|
||||
bcm->vote_x[i] = x;
|
||||
bcm->vote_y[i] = y;
|
||||
}
|
||||
|
||||
out:
|
||||
mutex_unlock(&voter->lock);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(qcom_icc_bcm_get_bw);
|
||||
|
||||
/**
|
||||
* qcom_icc_bcm_voter_commit - generates and commits tcs cmds based on bcms
|
||||
* @voter: voter that needs flushing
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@
|
|||
#include "icc-rpmh.h"
|
||||
|
||||
struct bcm_voter *of_bcm_voter_get(struct device *dev, const char *name);
|
||||
void qcom_icc_bcm_get_bw(struct bcm_voter *voter, struct qcom_icc_bcm *bcm);
|
||||
void qcom_icc_bcm_voter_add(struct bcm_voter *voter, struct qcom_icc_bcm *bcm);
|
||||
int qcom_icc_bcm_voter_commit(struct bcm_voter *voter);
|
||||
|
||||
|
|
|
|||
|
|
@ -136,6 +136,61 @@ int qcom_icc_set(struct icc_node *src, struct icc_node *dst)
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(qcom_icc_set);
|
||||
|
||||
static int qcom_icc_get_bw(struct icc_node *node, u32 *avg, u32 *peak)
|
||||
{
|
||||
struct qcom_icc_node *qn = node->data;
|
||||
u32 avg_max = 0;
|
||||
u32 peak_max = 0;
|
||||
u64 x, y;
|
||||
int i;
|
||||
|
||||
if (!qn->num_bcms) {
|
||||
*avg = INT_MAX;
|
||||
*peak = INT_MAX;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (i = 0; i < qn->num_bcms; ++i) {
|
||||
struct qcom_icc_bcm *bcm = qn->bcms[i];
|
||||
|
||||
/* Use AMC vote for boot-up */
|
||||
x = bcm->vote_x[QCOM_ICC_BUCKET_AMC];
|
||||
y = bcm->vote_y[QCOM_ICC_BUCKET_AMC];
|
||||
|
||||
/* Consider enable mask and convert to INT_MAX */
|
||||
if (bcm->enable_mask) {
|
||||
if (x & bcm->enable_mask)
|
||||
avg_max = INT_MAX;
|
||||
if (y & bcm->enable_mask)
|
||||
peak_max = INT_MAX;
|
||||
} else {
|
||||
if (x) {
|
||||
x *= bcm->aux_data.unit;
|
||||
do_div(x, bcm->vote_scale);
|
||||
x *= qn->buswidth * qn->channels;
|
||||
do_div(x, bcm->aux_data.width);
|
||||
|
||||
avg_max = max(avg_max, x);
|
||||
}
|
||||
|
||||
if (y) {
|
||||
y *= bcm->aux_data.unit;
|
||||
do_div(y, bcm->vote_scale);
|
||||
y *= qn->buswidth;
|
||||
do_div(y, bcm->aux_data.width);
|
||||
|
||||
peak_max = max(peak_max, y);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
*avg = avg_max;
|
||||
*peak = peak_max;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* qcom_icc_bcm_init - populates bcm aux data and connect qnodes
|
||||
* @bcm: bcm to be initialized
|
||||
|
|
@ -255,6 +310,7 @@ int qcom_icc_rpmh_probe(struct platform_device *pdev)
|
|||
provider = &qp->provider;
|
||||
provider->dev = dev;
|
||||
provider->set = qcom_icc_set;
|
||||
provider->get_bw = qcom_icc_get_bw;
|
||||
provider->pre_aggregate = qcom_icc_pre_aggregate;
|
||||
provider->aggregate = qcom_icc_aggregate;
|
||||
provider->xlate_extended = qcom_icc_xlate_extended;
|
||||
|
|
@ -272,8 +328,10 @@ int qcom_icc_rpmh_probe(struct platform_device *pdev)
|
|||
if (IS_ERR(qp->voter))
|
||||
return PTR_ERR(qp->voter);
|
||||
|
||||
for (i = 0; i < qp->num_bcms; i++)
|
||||
for (i = 0; i < qp->num_bcms; i++) {
|
||||
qcom_icc_bcm_init(qp->bcms[i], dev);
|
||||
qcom_icc_bcm_get_bw(qp->voter, qp->bcms[i]);
|
||||
}
|
||||
|
||||
for (i = 0; i < num_nodes; i++) {
|
||||
qn = qnodes[i];
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user