mirror of
https://github.com/torvalds/linux.git
synced 2026-07-31 03:27:03 +02:00
Merge "interconnect: qcom: icc-rpmh: Vote for keepalive BCMs during init"
This commit is contained in:
commit
95b3213a29
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user