[PATCH 20/20] interconnect: qcom: Divide clk rate by src node bus width

From: Konrad Dybcio
Date: Tue May 30 2023 - 06:22:45 EST


Ever since the introduction of SMD RPM ICC, we've been dividing the
clock rate by the wrong bus width. This has resulted in:

- setting wrong (mostly too low) rates, affecting performance
- most often /2 or /4
- things like DDR never hit their full potential
- the rates were only correct if src bus width == dst bus width
for all src, dst pairs on a given bus

- Qualcomm using the same wrong logic in their BSP driver in msm-5.x
that ships in production devices today

- me losing my sanity trying to find this

Resolve it by using dst_qn, if it exists.

Fixes: 5e4e6c4d3ae0 ("interconnect: qcom: Add QCS404 interconnect provider driver")
Signed-off-by: Konrad Dybcio <konrad.dybcio@xxxxxxxxxx>
---
drivers/interconnect/qcom/icc-rpm.c | 8 +++++---
1 file changed, 5 insertions(+), 3 deletions(-)

diff --git a/drivers/interconnect/qcom/icc-rpm.c b/drivers/interconnect/qcom/icc-rpm.c
index 59be704364bb..58e2a8b1b7c3 100644
--- a/drivers/interconnect/qcom/icc-rpm.c
+++ b/drivers/interconnect/qcom/icc-rpm.c
@@ -340,7 +340,7 @@ static void qcom_icc_bus_aggregate(struct icc_provider *provider,
static int qcom_icc_set(struct icc_node *src, struct icc_node *dst)
{
struct qcom_icc_provider *qp;
- struct qcom_icc_node *src_qn = NULL, *dst_qn = NULL;
+ struct qcom_icc_node *src_qn = NULL, *dst_qn = NULL, *qn = NULL;
struct icc_provider *provider;
u64 active_rate, sleep_rate;
u64 agg_avg[QCOM_SMD_RPM_STATE_NUM], agg_peak[QCOM_SMD_RPM_STATE_NUM];
@@ -353,6 +353,8 @@ static int qcom_icc_set(struct icc_node *src, struct icc_node *dst)
provider = src->provider;
qp = to_qcom_provider(provider);

+ qn = dst_qn ? dst_qn : src_qn;
+
qcom_icc_bus_aggregate(provider, agg_avg, agg_peak, &max_agg_avg);

ret = qcom_icc_rpm_set(src_qn, agg_avg);
@@ -372,11 +374,11 @@ static int qcom_icc_set(struct icc_node *src, struct icc_node *dst)
/* Intentionally keep the rates in kHz as that's what RPM accepts */
active_rate = max(agg_avg[QCOM_SMD_RPM_ACTIVE_STATE],
agg_peak[QCOM_SMD_RPM_ACTIVE_STATE]);
- do_div(active_rate, src_qn->buswidth);
+ do_div(active_rate, qn->buswidth);

sleep_rate = max(agg_avg[QCOM_SMD_RPM_SLEEP_STATE],
agg_peak[QCOM_SMD_RPM_SLEEP_STATE]);
- do_div(sleep_rate, src_qn->buswidth);
+ do_div(sleep_rate, qn->buswidth);

/*
* Downstream checks whether the requested rate is zero, but it makes little sense

--
2.40.1