From ce501003002fda4a325791def8e8a10cc52cfc3a Mon Sep 17 00:00:00 2001 From: Georgi Djakov Date: Wed, 4 Mar 2020 04:51:48 -0800 Subject: [PATCH] interconnect: qcom: Set QoS on the first bandwidth request Move the QoS configuration to happen on the first non-zero bandwidth request from the consumer driver. This allows configuring QoS also for consumers like IPA, which can probe asynchronously and their clock should not be touched until the firmware has completed booting. Change-Id: I2a8e385d99f3c489d920a7c85e9415d540f6df87 Signed-off-by: Georgi Djakov Signed-off-by: Mike Tipton --- drivers/interconnect/qcom/icc-rpmh.c | 13 +++++++++++++ drivers/interconnect/qcom/lahaina.c | 18 ++++-------------- drivers/interconnect/qcom/qnoc-qos.h | 1 + 3 files changed, 18 insertions(+), 14 deletions(-) diff --git a/drivers/interconnect/qcom/icc-rpmh.c b/drivers/interconnect/qcom/icc-rpmh.c index ed2774b36472..01be3a3138d3 100644 --- a/drivers/interconnect/qcom/icc-rpmh.c +++ b/drivers/interconnect/qcom/icc-rpmh.c @@ -6,11 +6,13 @@ #include #include +#include #include #include #include "icc-rpmh.h" #include "bcm-voter.h" +#include "qnoc-qos.h" /** * qcom_icc_pre_aggregate - cleans up stale values from prior icc_set @@ -80,6 +82,7 @@ EXPORT_SYMBOL(qcom_icc_aggregate); int qcom_icc_set(struct icc_node *src, struct icc_node *dst) { struct qcom_icc_provider *qp; + struct qcom_icc_node *qn; struct icc_node *node; int i; @@ -89,10 +92,20 @@ int qcom_icc_set(struct icc_node *src, struct icc_node *dst) node = src; qp = to_qcom_provider(node->provider); + qn = node->data; for (i = 0; i < qp->num_voters; i++) qcom_icc_bcm_voter_commit(qp->voters[i]); + /* Defer setting QoS until the first non-zero bandwidth request. */ + if (qn && qn->qosbox && !qn->qosbox->initialized && + (node->avg_bw || node->peak_bw)) { + clk_bulk_prepare_enable(qp->num_clks, qp->clks); + qn->noc_ops->set_qos(qn); + clk_bulk_disable_unprepare(qp->num_clks, qp->clks); + qn->qosbox->initialized = true; + } + return 0; } EXPORT_SYMBOL(qcom_icc_set); diff --git a/drivers/interconnect/qcom/lahaina.c b/drivers/interconnect/qcom/lahaina.c index a961247a7881..a5e926154844 100644 --- a/drivers/interconnect/qcom/lahaina.c +++ b/drivers/interconnect/qcom/lahaina.c @@ -991,6 +991,8 @@ err: icc_node_destroy(node->id); } + clk_bulk_put_all(qp->num_clks, qp->clks); + icc_provider_del(provider); return ret; } @@ -1006,6 +1008,8 @@ static int qnoc_remove(struct platform_device *pdev) icc_node_destroy(n->id); } + clk_bulk_put_all(qp->num_clks, qp->clks); + return icc_provider_del(provider); } @@ -1040,26 +1044,12 @@ static void qnoc_sync_state(struct device *dev) { struct platform_device *pdev = to_platform_device(dev); struct qcom_icc_provider *qp = platform_get_drvdata(pdev); - struct icc_provider *provider = &qp->provider; - struct qcom_icc_node *qnode; struct qcom_icc_bcm *bcm; struct bcm_voter *voter; - struct icc_node *node; mutex_lock(&probe_list_lock); probe_count++; - clk_bulk_prepare_enable(qp->num_clks, qp->clks); - - list_for_each_entry(node, &provider->nodes, node_list) { - qnode = node->data; - if (qnode && qnode->noc_ops) - qnode->noc_ops->set_qos(qnode); - } - - clk_bulk_disable_unprepare(qp->num_clks, qp->clks); - clk_bulk_put_all(qp->num_clks, qp->clks); - if (probe_count < ARRAY_SIZE(qnoc_of_match) - 1) { mutex_unlock(&probe_list_lock); return; diff --git a/drivers/interconnect/qcom/qnoc-qos.h b/drivers/interconnect/qcom/qnoc-qos.h index f22d0cd0e3ac..0c55c95f36a4 100644 --- a/drivers/interconnect/qcom/qnoc-qos.h +++ b/drivers/interconnect/qcom/qnoc-qos.h @@ -37,6 +37,7 @@ struct qos_config { struct qcom_icc_qosbox { u32 num_ports; const u8 *regs; + bool initialized; struct qos_config *config; u32 offsets[]; };