From 0850035d439d703ace113a1166e4aa5de92f7885 Mon Sep 17 00:00:00 2001 From: David Dai Date: Tue, 14 Jan 2020 17:16:26 -0800 Subject: [PATCH] interconnect: qcom: Add sync_state for Lahaina QNOC Add sync_state functionality to remove threshold held during initial boot up and clean up any linger proxy resources that were voted for from bootloaders. Change-Id: Ib2fe3f3e54775b85c3ee8107c9aafdcd32841017 Signed-off-by: David Dai --- drivers/interconnect/qcom/bcm-voter.c | 38 ++++++++++++++++++++++----- drivers/interconnect/qcom/bcm-voter.h | 3 ++- drivers/interconnect/qcom/icc-rpmh.c | 2 +- drivers/interconnect/qcom/icc-rpmh.h | 3 ++- drivers/interconnect/qcom/lahaina.c | 36 ++++++++++++++++++++++++- 5 files changed, 72 insertions(+), 10 deletions(-) diff --git a/drivers/interconnect/qcom/bcm-voter.c b/drivers/interconnect/qcom/bcm-voter.c index 61858683c558..04f92675c99b 100644 --- a/drivers/interconnect/qcom/bcm-voter.c +++ b/drivers/interconnect/qcom/bcm-voter.c @@ -26,6 +26,7 @@ static LIST_HEAD(bcm_voters); * @commit_list: list containing bcms to be committed to hardware * @ws_list: list containing bcms that have different wake/sleep votes * @voter_node: list of bcm voters + * @init: flag to determine when init has completed. */ struct bcm_voter { struct device *dev; @@ -34,6 +35,7 @@ struct bcm_voter { struct list_head commit_list; struct list_head ws_list; struct list_head voter_node; + bool init; }; static int cmp_vcd(void *priv, struct list_head *a, struct list_head *b) @@ -51,7 +53,7 @@ static int cmp_vcd(void *priv, struct list_head *a, struct list_head *b) return 1; } -static void bcm_aggregate(struct qcom_icc_bcm *bcm) +static void bcm_aggregate(struct qcom_icc_bcm *bcm, bool init) { size_t i, bucket; u64 agg_avg[QCOM_ICC_NUM_BUCKETS] = {0}; @@ -82,10 +84,18 @@ static void bcm_aggregate(struct qcom_icc_bcm *bcm) } if (bcm->keepalive) { - bcm->vote_x[QCOM_ICC_BUCKET_AMC] = 16000; - bcm->vote_x[QCOM_ICC_BUCKET_WAKE] = 16000; - bcm->vote_y[QCOM_ICC_BUCKET_AMC] = 16000; - bcm->vote_y[QCOM_ICC_BUCKET_WAKE] = 16000; + if (init) { + bcm->vote_x[QCOM_ICC_BUCKET_AMC] = 16000; + bcm->vote_x[QCOM_ICC_BUCKET_WAKE] = 16000; + bcm->vote_y[QCOM_ICC_BUCKET_AMC] = 16000; + bcm->vote_y[QCOM_ICC_BUCKET_WAKE] = 16000; + } else if (bcm->vote_x[QCOM_ICC_BUCKET_AMC] == 0 && + bcm->vote_y[QCOM_ICC_BUCKET_AMC] == 0) { + bcm->vote_x[QCOM_ICC_BUCKET_AMC] = 1; + bcm->vote_x[QCOM_ICC_BUCKET_WAKE] = 1; + bcm->vote_y[QCOM_ICC_BUCKET_AMC] = 1; + bcm->vote_y[QCOM_ICC_BUCKET_WAKE] = 1; + } } } @@ -245,7 +255,7 @@ int qcom_icc_bcm_voter_commit(struct bcm_voter *voter) mutex_lock(&voter->lock); list_for_each_entry(bcm, &voter->commit_list, list) - bcm_aggregate(bcm); + bcm_aggregate(bcm, voter->init); /* * Pre sort the BCMs based on VCD for ease of generating a command list @@ -334,6 +344,21 @@ out: } EXPORT_SYMBOL(qcom_icc_bcm_voter_commit); +/** + * qcom_icc_bcm_voter_clear_init - clear init flag used during boot up + * @voter: voter that we need to clear the init flag for + */ +void qcom_icc_bcm_voter_clear_init(struct bcm_voter *voter) +{ + if (!voter) + return; + + mutex_lock(&voter->lock); + voter->init = false; + mutex_unlock(&voter->lock); +} +EXPORT_SYMBOL(qcom_icc_bcm_voter_clear_init); + static int qcom_icc_bcm_voter_probe(struct platform_device *pdev) { struct bcm_voter *voter; @@ -344,6 +369,7 @@ static int qcom_icc_bcm_voter_probe(struct platform_device *pdev) voter->dev = &pdev->dev; voter->np = pdev->dev.of_node; + voter->init = true; mutex_init(&voter->lock); INIT_LIST_HEAD(&voter->commit_list); INIT_LIST_HEAD(&voter->ws_list); diff --git a/drivers/interconnect/qcom/bcm-voter.h b/drivers/interconnect/qcom/bcm-voter.h index 9e0f878b8c4d..db4578446b51 100644 --- a/drivers/interconnect/qcom/bcm-voter.h +++ b/drivers/interconnect/qcom/bcm-voter.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2019-2020, The Linux Foundation. All rights reserved. * */ @@ -24,5 +24,6 @@ struct bcm_voter *of_bcm_voter_get(struct device *dev, const char *name); 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); +void qcom_icc_bcm_voter_clear_init(struct bcm_voter *voter); #endif diff --git a/drivers/interconnect/qcom/icc-rpmh.c b/drivers/interconnect/qcom/icc-rpmh.c index 4b6aecc143ac..39f2db9ef765 100644 --- a/drivers/interconnect/qcom/icc-rpmh.c +++ b/drivers/interconnect/qcom/icc-rpmh.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2019-2020, The Linux Foundation. All rights reserved. * */ diff --git a/drivers/interconnect/qcom/icc-rpmh.h b/drivers/interconnect/qcom/icc-rpmh.h index ec1fd08298ff..c656623b06ce 100644 --- a/drivers/interconnect/qcom/icc-rpmh.h +++ b/drivers/interconnect/qcom/icc-rpmh.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2019-2020, The Linux Foundation. All rights reserved. * */ @@ -23,6 +23,7 @@ struct qcom_icc_provider { struct qcom_icc_bcm **bcms; size_t num_bcms; struct bcm_voter *voter; + struct list_head probe_list; }; /** diff --git a/drivers/interconnect/qcom/lahaina.c b/drivers/interconnect/qcom/lahaina.c index e8f29a60c789..b83d593d8b45 100644 --- a/drivers/interconnect/qcom/lahaina.c +++ b/drivers/interconnect/qcom/lahaina.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2019-2020, The Linux Foundation. All rights reserved. * */ @@ -19,6 +19,11 @@ #include "icc-rpmh.h" #include "bcm-voter.h" +static LIST_HEAD(qnoc_probe_list); +static DEFINE_MUTEX(probe_list_lock); + +static int probe_count; + DEFINE_QNODE(qhm_qspi, MASTER_QSPI_0, 1, 4, 1, SLAVE_A1NOC_SNOC); DEFINE_QNODE(qhm_qup1, MASTER_QUP_1, 1, 4, 1, @@ -775,6 +780,10 @@ static int qnoc_probe(struct platform_device *pdev) dev_dbg(&pdev->dev, "Registered LAHAINA ICC\n"); + mutex_lock(&probe_list_lock); + list_add_tail(&qp->probe_list, &qnoc_probe_list); + mutex_unlock(&probe_list_lock); + return ret; err: list_for_each_entry(node, &provider->nodes, node_list) { @@ -829,12 +838,37 @@ static const struct of_device_id qnoc_of_match[] = { }; MODULE_DEVICE_TABLE(of, qnoc_of_match); +static void qnoc_sync_state(struct device *dev) +{ + struct qcom_icc_provider *qp; + + mutex_lock(&probe_list_lock); + probe_count++; + + if (probe_count < ARRAY_SIZE(qnoc_of_match) - 1) { + mutex_unlock(&probe_list_lock); + return; + } + + list_for_each_entry(qp, &qnoc_probe_list, probe_list) { + int i; + + for (i = 0; i < qp->num_bcms; i++) + qcom_icc_bcm_voter_add(qp->voter, qp->bcms[i]); + + qcom_icc_bcm_voter_clear_init(qp->voter); + qcom_icc_bcm_voter_commit(qp->voter); + } + mutex_unlock(&probe_list_lock); +} + static struct platform_driver qnoc_driver = { .probe = qnoc_probe, .remove = qnoc_remove, .driver = { .name = "qnoc-lahaina", .of_match_table = qnoc_of_match, + .sync_state = qnoc_sync_state, }, };