Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 9a0e01de authored by Mike Tipton's avatar Mike Tipton
Browse files

interconnect: qcom: Fix BW requests to L3_SHARED returning -EINVAL



The qcom,lahaina-epss-l3-shared provider currently only defines a single
endpoint: SLAVE_EPSS_L3_SHARED. The framework only calls the set()
callback for pairs of nodes. If there is no valid pair belonging to the
provider, then apply_constraints() and icc_set_bw() will return -EINVAL.
The lahaina-epss-l3-shared provider would need an additional master
endpoint for these requests to work.

However, even if that problem is fixed, there's another problem in
qcom_icc_l3_shared_set() that prevents the requested level from taking
effect in HW. This function writes the required level into the
PERF_STATE_DESIRED register, which is ignored when per-CPU L3 voting is
enabled in HW. When per-CPU L3 voting is enabled, only the L3_VOTE
register is counted.

To fix both of these problems, just remove the separate
qcom,lahaina-epss-l3-shared provider entirely and move
SLAVE_EPSS_L3_SHARED as an endpoint on qcom,lahaina-epss-l3-cpu. The
qcom_icc_l3_cpu_set() function uses the L3_VOTE register and can be used
for the shared L3 vote as-is. The only reason we'd ever need to use
PERF_STATE_DESIRED is if per-CPU L3 voting is disabled, but that will
likely never happen. All use cases can already be supported with per-CPU
voting enabled (per-CPU, shared, or a mix of both).

Change-Id: Ia67aadf26896a3a819aba8f2e4196d78d0c5c1f5
Signed-off-by: default avatarMike Tipton <mdtipton@codeaurora.org>
parent fcc93653
Loading
Loading
Loading
Loading
+2 −37
Original line number Original line Diff line number Diff line
// SPDX-License-Identifier: GPL-2.0-only
// 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.
 *
 *
 */
 */


@@ -121,6 +121,7 @@ static struct qcom_icc_node *lahaina_epss_l3_nodes[] = {
	[SLAVE_EPSS_L3_CPU5] = &slv_epss_l3_cpu5,
	[SLAVE_EPSS_L3_CPU5] = &slv_epss_l3_cpu5,
	[SLAVE_EPSS_L3_CPU6] = &slv_epss_l3_cpu6,
	[SLAVE_EPSS_L3_CPU6] = &slv_epss_l3_cpu6,
	[SLAVE_EPSS_L3_CPU7] = &slv_epss_l3_cpu7,
	[SLAVE_EPSS_L3_CPU7] = &slv_epss_l3_cpu7,
	[SLAVE_EPSS_L3_SHARED] = &slv_epss_l3_shared,
};
};


static struct qcom_icc_desc lahaina_epss_l3 = {
static struct qcom_icc_desc lahaina_epss_l3 = {
@@ -128,15 +129,6 @@ static struct qcom_icc_desc lahaina_epss_l3 = {
	.num_nodes = ARRAY_SIZE(lahaina_epss_l3_nodes),
	.num_nodes = ARRAY_SIZE(lahaina_epss_l3_nodes),
};
};


static struct qcom_icc_node *lahaina_epss_l3_shared_nodes[] = {
	[SLAVE_EPSS_L3_SHARED] = &slv_epss_l3_shared,
};

static struct qcom_icc_desc lahaina_epss_l3_shared = {
	.nodes = lahaina_epss_l3_shared_nodes,
	.num_nodes = ARRAY_SIZE(lahaina_epss_l3_shared_nodes),
};

static int qcom_icc_aggregate(struct icc_node *node, u32 tag, u32 avg_bw,
static int qcom_icc_aggregate(struct icc_node *node, u32 tag, u32 avg_bw,
			      u32 peak_bw, u32 *agg_avg, u32 *agg_peak)
			      u32 peak_bw, u32 *agg_avg, u32 *agg_peak)
{
{
@@ -169,29 +161,6 @@ static int qcom_icc_l3_cpu_set(struct icc_node *src, struct icc_node *dst)
	return 0;
	return 0;
}
}


static int qcom_icc_l3_shared_set(struct icc_node *src, struct icc_node *dst)
{
	struct qcom_epss_l3_icc_provider *qp;
	struct icc_provider *provider;
	struct qcom_icc_node *qn;
	unsigned int index;
	u64 rate;

	qn = dst->data;
	provider = src->provider;
	qp = to_qcom_provider(provider);

	rate = dst->peak_bw;

	for (index = 0; index < qp->max_state; index++) {
		if (qp->lut_freqs[index] >= rate)
			break;
	}

	writel_relaxed(index, qp->base + REG_PERF_STATE);
	return 0;
}

static int qcom_epss_l3_remove(struct platform_device *pdev)
static int qcom_epss_l3_remove(struct platform_device *pdev)
{
{
	struct qcom_epss_l3_icc_provider *qp = platform_get_drvdata(pdev);
	struct qcom_epss_l3_icc_provider *qp = platform_get_drvdata(pdev);
@@ -292,8 +261,6 @@ static int qcom_epss_l3_probe(struct platform_device *pdev)
	compat = of_get_property(pdev->dev.of_node, "compatible", &compatlen);
	compat = of_get_property(pdev->dev.of_node, "compatible", &compatlen);
	if (!compat || (compatlen <= 0))
	if (!compat || (compatlen <= 0))
		return -EINVAL;
		return -EINVAL;
	if (!strcmp(compat, "qcom,lahaina-epss-l3-shared"))
		provider->set = qcom_icc_l3_shared_set;


	ret = icc_provider_add(provider);
	ret = icc_provider_add(provider);
	if (ret) {
	if (ret) {
@@ -335,8 +302,6 @@ static int qcom_epss_l3_probe(struct platform_device *pdev)


static const struct of_device_id epss_l3_of_match[] = {
static const struct of_device_id epss_l3_of_match[] = {
	{ .compatible = "qcom,lahaina-epss-l3-cpu", .data = &lahaina_epss_l3 },
	{ .compatible = "qcom,lahaina-epss-l3-cpu", .data = &lahaina_epss_l3 },
	{ .compatible = "qcom,lahaina-epss-l3-shared",
		.data = &lahaina_epss_l3_shared },
	{ },
	{ },
};
};
MODULE_DEVICE_TABLE(of, epss_l3_of_match);
MODULE_DEVICE_TABLE(of, epss_l3_of_match);