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 <gdjako@codeaurora.org>
Signed-off-by: Mike Tipton <mdtipton@codeaurora.org>
This commit is contained in:
Georgi Djakov 2020-03-04 04:51:48 -08:00 • committed by Mike Tipton
commit ce50100300
3 changed files with 18 additions and 14 deletions

View file

@ -6,11 +6,13 @@
#include <asm/div64.h>
#include <dt-bindings/interconnect/qcom,sdm845.h>
#include <linux/clk.h>
#include <linux/interconnect.h>
#include <linux/interconnect-provider.h>
#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);

View file

@ -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;

View file

@ -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[];
};