interconnect: qcom: Add sync_state for 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 <daidavid1@codeaurora.org>
Signed-off-by: Mike Tipton <mdtipton@codeaurora.org>
This commit is contained in:
David Dai 2020-01-14 17:16:26 -08:00 committed by Mike Tipton
parent 9787cfc9b5
commit 0a20a2a4e7
4 changed files with 85 additions and 7 deletions

View File

@ -28,6 +28,7 @@ static DEFINE_MUTEX(bcm_voter_lock);
* @ws_list: list containing bcms that have different wake/sleep votes
* @voter_node: list of bcm voters
* @tcs_wait: mask for which buckets require TCS completion
* @init: flag to determine when init has completed.
*/
struct bcm_voter {
struct device *dev;
@ -37,6 +38,7 @@ struct bcm_voter {
struct list_head ws_list;
struct list_head voter_node;
u32 tcs_wait;
bool init;
};
static int cmp_vcd(void *priv, const struct list_head *a, const struct list_head *b)
@ -58,7 +60,7 @@ static u64 bcm_div(u64 num, u32 base)
return num;
}
static void bcm_aggregate(struct qcom_icc_bcm *bcm)
static void bcm_aggregate(struct qcom_icc_bcm *bcm, bool init)
{
struct qcom_icc_node *node;
size_t i, bucket;
@ -86,10 +88,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;
}
}
}
@ -255,7 +265,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
@ -332,6 +342,21 @@ int qcom_icc_bcm_voter_commit(struct bcm_voter *voter)
}
EXPORT_SYMBOL_GPL(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 device_node *np = pdev->dev.of_node;
@ -343,6 +368,7 @@ static int qcom_icc_bcm_voter_probe(struct platform_device *pdev)
voter->dev = &pdev->dev;
voter->np = np;
voter->init = true;
if (of_property_read_u32(np, "qcom,tcs-wait", &voter->tcs_wait))
voter->tcs_wait = QCOM_ICC_TAG_ACTIVE_ONLY;

View File

@ -23,5 +23,6 @@ static struct qcom_icc_bcm _name = { \
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

View File

@ -7,12 +7,16 @@
#include <linux/interconnect-provider.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_platform.h>
#include <linux/of_device.h>
#include <linux/slab.h>
#include "bcm-voter.h"
#include "icc-rpmh.h"
static LIST_HEAD(qnoc_probe_list);
static DEFINE_MUTEX(probe_list_lock);
/**
* qcom_icc_pre_aggregate - cleans up stale values from prior icc_set
* @node: icc node to operate on
@ -258,6 +262,10 @@ int qcom_icc_rpmh_probe(struct platform_device *pdev)
data->num_nodes = num_nodes;
platform_set_drvdata(pdev, qp);
mutex_lock(&probe_list_lock);
list_add_tail(&qp->probe_list, &qnoc_probe_list);
mutex_unlock(&probe_list_lock);
return 0;
err:
icc_nodes_remove(provider);
@ -275,4 +283,46 @@ int qcom_icc_rpmh_remove(struct platform_device *pdev)
}
EXPORT_SYMBOL_GPL(qcom_icc_rpmh_remove);
void qcom_icc_rpmh_sync_state(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
const struct of_device_id *oft = dev->driver->of_match_table;
struct qcom_icc_provider *qp = platform_get_drvdata(pdev);
struct qcom_icc_bcm *bcm;
struct bcm_voter *voter;
static int probe_count;
int num_providers;
for (num_providers = 0; oft[num_providers].data; num_providers++)
;
mutex_lock(&probe_list_lock);
probe_count++;
if (probe_count < num_providers) {
mutex_unlock(&probe_list_lock);
return;
}
list_for_each_entry(qp, &qnoc_probe_list, probe_list) {
int i;
for (i = 0; i < qp->num_voters; i++)
qcom_icc_bcm_voter_clear_init(qp->voters[i]);
for (i = 0; i < qp->num_bcms; i++) {
bcm = qp->bcms[i];
if (!bcm->keepalive)
continue;
voter = qp->voters[bcm->voter_idx];
qcom_icc_bcm_voter_add(voter, bcm);
qcom_icc_bcm_voter_commit(voter);
}
}
mutex_unlock(&probe_list_lock);
}
EXPORT_SYMBOL(qcom_icc_rpmh_sync_state);
MODULE_LICENSE("GPL v2");

View File

@ -25,6 +25,7 @@ struct qcom_icc_provider {
struct qcom_icc_bcm **bcms;
size_t num_bcms;
struct bcm_voter *voter;
struct list_head probe_list;
};
/**
@ -136,5 +137,5 @@ int qcom_icc_bcm_init(struct qcom_icc_bcm *bcm, struct device *dev);
void qcom_icc_pre_aggregate(struct icc_node *node);
int qcom_icc_rpmh_probe(struct platform_device *pdev);
int qcom_icc_rpmh_remove(struct platform_device *pdev);
void qcom_icc_rpmh_sync_state(struct device *dev);
#endif