Merge "interconnect: qcom: icc-rpmh: Vote for keepalive BCMs during init"

This commit is contained in:
qctecmdr 2022-05-07 22:33:20 -07:00 committed by Gerrit - the friendly Code Review server
commit 95b3213a29
5 changed files with 125 additions and 13 deletions

View File

@ -97,12 +97,21 @@ static void bcm_aggregate(struct qcom_icc_bcm *bcm, bool init)
}
}
if (bcm->keepalive) {
if (bcm->keepalive || bcm->keepalive_early) {
/*
* Keepalive should normally only be enforced for AMC/WAKE so
* that BCMs are only kept alive when HLOS is active. But early
* during init all clients haven't had a chance to vot yet, and
* some have use cases that persist when HLOS is asleep. So
* during init vote to all sets, including SLEEP.
*/
if (init) {
bcm->vote_x[QCOM_ICC_BUCKET_AMC] = 16000;
bcm->vote_x[QCOM_ICC_BUCKET_WAKE] = 16000;
bcm->vote_x[QCOM_ICC_BUCKET_SLEEP] = 16000;
bcm->vote_y[QCOM_ICC_BUCKET_AMC] = 16000;
bcm->vote_y[QCOM_ICC_BUCKET_WAKE] = 16000;
bcm->vote_y[QCOM_ICC_BUCKET_SLEEP] = 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;

View File

@ -167,11 +167,14 @@ EXPORT_SYMBOL_GPL(qcom_icc_xlate_extended);
*
* Return: 0 on success, or an error code otherwise
*/
int qcom_icc_bcm_init(struct qcom_icc_bcm *bcm, struct device *dev)
int qcom_icc_bcm_init(struct qcom_icc_provider *qp, struct qcom_icc_bcm *bcm,
struct device *dev)
{
struct qcom_icc_node *qn;
const struct bcm_db *data;
struct bcm_voter *voter;
size_t data_count;
int ret;
int i;
/* BCM is already initialised*/
@ -214,10 +217,91 @@ int qcom_icc_bcm_init(struct qcom_icc_bcm *bcm, struct device *dev)
qn->num_bcms++;
}
if (bcm->keepalive || bcm->keepalive_early) {
voter = qp->voters[bcm->voter_idx];
qcom_icc_bcm_voter_add(voter, bcm);
ret = qcom_icc_bcm_voter_commit(voter);
if (ret) {
dev_err(dev, "failed to place initial vote for %s\n",
bcm->name);
return ret;
}
}
return 0;
}
EXPORT_SYMBOL_GPL(qcom_icc_bcm_init);
static bool bcm_needs_qos_proxy(struct qcom_icc_bcm *bcm)
{
int i;
if (bcm->qos_proxy)
return true;
if (bcm->voter_idx == 0)
for (i = 0; i < bcm->num_nodes; i++)
if (bcm->nodes[i]->qosbox)
return true;
return false;
}
static int enable_qos_deps(struct qcom_icc_provider *qp)
{
struct qcom_icc_bcm *bcm;
struct bcm_voter *voter;
bool keepalive;
int ret, i;
for (i = 0; i < qp->num_bcms; i++) {
bcm = qp->bcms[i];
if (bcm_needs_qos_proxy(bcm)) {
keepalive = bcm->keepalive;
bcm->keepalive = true;
voter = qp->voters[bcm->voter_idx];
qcom_icc_bcm_voter_add(voter, bcm);
ret = qcom_icc_bcm_voter_commit(voter);
bcm->keepalive = keepalive;
if (ret) {
dev_err(qp->dev, "failed to vote BW to %s for QoS\n",
bcm->name);
return ret;
}
}
}
ret = clk_bulk_prepare_enable(qp->num_clks, qp->clks);
if (ret) {
dev_err(qp->dev, "failed to enable clocks for QoS\n");
return ret;
}
return 0;
}
static void disable_qos_deps(struct qcom_icc_provider *qp)
{
struct qcom_icc_bcm *bcm;
struct bcm_voter *voter;
int i;
clk_bulk_disable_unprepare(qp->num_clks, qp->clks);
for (i = 0; i < qp->num_bcms; i++) {
bcm = qp->bcms[i];
if (bcm_needs_qos_proxy(bcm)) {
voter = qp->voters[bcm->voter_idx];
qcom_icc_bcm_voter_add(voter, bcm);
qcom_icc_bcm_voter_commit(voter);
}
}
}
static struct regmap *qcom_icc_rpmh_map(struct platform_device *pdev,
const struct qcom_icc_desc *desc)
{
@ -229,7 +313,7 @@ static struct regmap *qcom_icc_rpmh_map(struct platform_device *pdev,
if (!res)
return NULL;
base = devm_ioremap_resource(dev, res);
base = devm_ioremap(dev, res->start, resource_size(res));
if (IS_ERR(base))
return ERR_CAST(base);
@ -264,6 +348,7 @@ int qcom_icc_rpmh_probe(struct platform_device *pdev)
return -ENOMEM;
qp->stub = of_property_read_bool(pdev->dev.of_node, "qcom,stub");
qp->skip_qos = of_property_read_bool(pdev->dev.of_node, "qcom,skip-qos");
provider = &qp->provider;
provider->dev = dev;
@ -307,14 +392,14 @@ int qcom_icc_rpmh_probe(struct platform_device *pdev)
if (qp->num_clks < 0)
return qp->num_clks;
ret = clk_bulk_prepare_enable(qp->num_clks, qp->clks);
if (ret) {
dev_err(&pdev->dev, "failed to enable clocks\n");
return ret;
}
for (i = 0; i < qp->num_bcms; i++)
qcom_icc_bcm_init(qp->bcms[i], dev);
qcom_icc_bcm_init(qp, qp->bcms[i], dev);
if (!qp->skip_qos) {
ret = enable_qos_deps(qp);
if (ret)
return ret;
}
for (i = 0; i < num_nodes; i++) {
qn = qnodes[i];
@ -329,7 +414,7 @@ int qcom_icc_rpmh_probe(struct platform_device *pdev)
goto err;
}
if (qn->qosbox)
if (qn->qosbox && !qp->skip_qos)
qn->noc_ops->set_qos(qn);
node->name = qn->name;
@ -342,6 +427,9 @@ int qcom_icc_rpmh_probe(struct platform_device *pdev)
data->nodes[i] = node;
}
if (!qp->skip_qos)
disable_qos_deps(qp);
data->num_nodes = num_nodes;
platform_set_drvdata(pdev, qp);
@ -407,9 +495,11 @@ void qcom_icc_rpmh_sync_state(struct device *dev)
for (i = 0; i < qp->num_bcms; i++) {
bcm = qp->bcms[i];
if (!bcm->keepalive)
if (!bcm->keepalive && !bcm->keepalive_early)
continue;
bcm->keepalive_early = false;
voter = qp->voters[bcm->voter_idx];
qcom_icc_bcm_voter_add(voter, bcm);
qcom_icc_bcm_voter_commit(voter);

View File

@ -33,6 +33,7 @@ struct qcom_icc_provider {
struct bcm_voter **voters;
size_t num_voters;
bool stub;
bool skip_qos;
};
/**
@ -98,6 +99,9 @@ struct qcom_icc_node {
* @perf_mode_mask: mask to OR with enable_mask when QCOM_ICC_TAG_PERF_MODE is set
* @dirty: flag used to indicate whether the bcm needs to be committed
* @keepalive: flag used to indicate whether a keepalive is required
* @keepalive_early: keepalive only prior to sync-state
* @qos_proxy: flag used to indicate whether a proxy vote needed as part of
* qos configuration
* @aux_data: auxiliary data used when calculating threshold values and
* communicating with RPMh
* @list: used to link to other bcms when compiling lists for commit
@ -116,6 +120,8 @@ struct qcom_icc_bcm {
u32 perf_mode_mask;
bool dirty;
bool keepalive;
bool keepalive_early;
bool qos_proxy;
struct bcm_db aux_data;
struct list_head list;
struct list_head ws_list;
@ -156,7 +162,7 @@ int qcom_icc_aggregate_stub(struct icc_node *node, u32 tag, u32 avg_bw,
int qcom_icc_set(struct icc_node *src, struct icc_node *dst);
int qcom_icc_set_stub(struct icc_node *src, struct icc_node *dst);
struct icc_node_data *qcom_icc_xlate_extended(struct of_phandle_args *spec, void *data);
int qcom_icc_bcm_init(struct qcom_icc_bcm *bcm, struct device *dev);
int qcom_icc_bcm_init(struct qcom_icc_provider *qp, 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);

View File

@ -16,6 +16,8 @@
#define QOS_SLV_URG_MSG_EN_SHFT 3
# define QOS_DFLT_PRIO_MASK 0x7
# define QOS_DFLT_PRIO_SHFT 4
#define QOS_DISABLE_SHIFT 24
const u8 icc_qnoc_qos_regs[][QOSGEN_OFF_MAX_REGS] = {
[ICC_QNOC_QOSGEN_TYPE_RPMH] = {
@ -45,6 +47,10 @@ static void qcom_icc_set_qos(struct qcom_icc_node *node)
return;
for (port = 0; port < qos->num_ports; port++) {
regmap_update_bits(node->regmap, QOSGEN_MAINCTL_LO(qos, port),
BIT(QOS_DISABLE_SHIFT),
qos->config->prio_fwd_disable << QOS_DISABLE_SHIFT);
regmap_update_bits(node->regmap, QOSGEN_MAINCTL_LO(qos, port),
QOS_DFLT_PRIO_MASK << QOS_DFLT_PRIO_SHFT,
qos->config->prio << QOS_DFLT_PRIO_SHFT);

View File

@ -32,6 +32,7 @@ struct qcom_icc_noc_ops {
struct qos_config {
u32 prio;
u32 urg_fwd;
bool prio_fwd_disable;
};
struct qcom_icc_qosbox {