Commit 1400725e authored by Georgi Djakov's avatar Georgi Djakov
Browse files

Merge branch 'icc-qos' into icc-next

* icc-qos
  interconnect: qcom: rpm: Rename icc desc clocks to bus_blocks
  interconnect: qcom: rpm: Rename icc provider num_clocks to num_bus_clocks
  interconnect: qcom: rpm: Drop unused parameters
  interconnect: qcom: rpm: Set QoS registers only once
  interconnect: qcom: rpm: Handle interface clocks
  interconnect: qcom: icc-rpm: Enforce 2 or 0 bus clocks
  interconnect: qcom: rpm: Don't use clk_get_optional for bus clocks anymore
  interconnect: qcom: msm8996: Promote to core_initcall
  interconnect: qcom: rpm: allocate enough data in probe()

Link: https://lore.kernel.org/r/20230228-topic-qos-v8-0-ee696a2c15a9@linaro.org


Signed-off-by: default avatarGeorgi Djakov <djakov@kernel.org>
parents 7f1ed465 0ebee0a6
Loading
Loading
Loading
Loading
+59 −53
Original line number Diff line number Diff line
@@ -50,7 +50,7 @@
#define NOC_QOS_MODE_FIXED_VAL		0x0
#define NOC_QOS_MODE_BYPASS_VAL		0x2

static int qcom_icc_set_qnoc_qos(struct icc_node *src, u64 max_bw)
static int qcom_icc_set_qnoc_qos(struct icc_node *src)
{
	struct icc_provider *provider = src->provider;
	struct qcom_icc_provider *qp = to_qcom_provider(provider);
@@ -95,7 +95,7 @@ static int qcom_icc_bimc_set_qos_health(struct qcom_icc_provider *qp,
				  mask, val);
}

static int qcom_icc_set_bimc_qos(struct icc_node *src, u64 max_bw)
static int qcom_icc_set_bimc_qos(struct icc_node *src)
{
	struct qcom_icc_provider *qp;
	struct qcom_icc_node *qn;
@@ -150,7 +150,7 @@ static int qcom_icc_noc_set_qos_priority(struct qcom_icc_provider *qp,
				  NOC_QOS_PRIORITY_P0_MASK, qos->prio_level);
}

static int qcom_icc_set_noc_qos(struct icc_node *src, u64 max_bw)
static int qcom_icc_set_noc_qos(struct icc_node *src)
{
	struct qcom_icc_provider *qp;
	struct qcom_icc_node *qn;
@@ -187,7 +187,7 @@ static int qcom_icc_set_noc_qos(struct icc_node *src, u64 max_bw)
				  NOC_QOS_MODEn_MASK, mode);
}

static int qcom_icc_qos_set(struct icc_node *node, u64 sum_bw)
static int qcom_icc_qos_set(struct icc_node *node)
{
	struct qcom_icc_provider *qp = to_qcom_provider(node->provider);
	struct qcom_icc_node *qn = node->data;
@@ -196,38 +196,41 @@ static int qcom_icc_qos_set(struct icc_node *node, u64 sum_bw)

	switch (qp->type) {
	case QCOM_ICC_BIMC:
		return qcom_icc_set_bimc_qos(node, sum_bw);
		return qcom_icc_set_bimc_qos(node);
	case QCOM_ICC_QNOC:
		return qcom_icc_set_qnoc_qos(node, sum_bw);
		return qcom_icc_set_qnoc_qos(node);
	default:
		return qcom_icc_set_noc_qos(node, sum_bw);
		return qcom_icc_set_noc_qos(node);
	}
}

static int qcom_icc_rpm_set(int mas_rpm_id, int slv_rpm_id, u64 sum_bw)
static int qcom_icc_rpm_set(struct qcom_icc_node *qn, u64 sum_bw)
{
	int ret = 0;

	if (mas_rpm_id != -1) {
	if (qn->qos.ap_owned)
		return 0;

	if (qn->mas_rpm_id != -1) {
		ret = qcom_icc_rpm_smd_send(QCOM_SMD_RPM_ACTIVE_STATE,
					    RPM_BUS_MASTER_REQ,
					    mas_rpm_id,
					    qn->mas_rpm_id,
					    sum_bw);
		if (ret) {
			pr_err("qcom_icc_rpm_smd_send mas %d error %d\n",
			       mas_rpm_id, ret);
			       qn->mas_rpm_id, ret);
			return ret;
		}
	}

	if (slv_rpm_id != -1) {
	if (qn->slv_rpm_id != -1) {
		ret = qcom_icc_rpm_smd_send(QCOM_SMD_RPM_ACTIVE_STATE,
					    RPM_BUS_SLAVE_REQ,
					    slv_rpm_id,
					    qn->slv_rpm_id,
					    sum_bw);
		if (ret) {
			pr_err("qcom_icc_rpm_smd_send slv %d error %d\n",
			       slv_rpm_id, ret);
			       qn->slv_rpm_id, ret);
			return ret;
		}
	}
@@ -235,26 +238,6 @@ static int qcom_icc_rpm_set(int mas_rpm_id, int slv_rpm_id, u64 sum_bw)
	return ret;
}

static int __qcom_icc_set(struct icc_node *n, struct qcom_icc_node *qn,
			  u64 sum_bw)
{
	int ret;

	if (!qn->qos.ap_owned) {
		/* send bandwidth request message to the RPM processor */
		ret = qcom_icc_rpm_set(qn->mas_rpm_id, qn->slv_rpm_id, sum_bw);
		if (ret)
			return ret;
	} else if (qn->qos.qos_mode != NOC_QOS_MODE_INVALID) {
		/* set bandwidth directly from the AP */
		ret = qcom_icc_qos_set(n, sum_bw);
		if (ret)
			return ret;
	}

	return 0;
}

/**
 * qcom_icc_pre_bw_aggregate - cleans up values before re-aggregate requests
 * @node: icc node to operate on
@@ -370,16 +353,17 @@ static int qcom_icc_set(struct icc_node *src, struct icc_node *dst)

	sum_bw = icc_units_to_bps(max_agg_avg);

	ret = __qcom_icc_set(src, src_qn, sum_bw);
	ret = qcom_icc_rpm_set(src_qn, sum_bw);
	if (ret)
		return ret;

	if (dst_qn) {
		ret = __qcom_icc_set(dst, dst_qn, sum_bw);
		ret = qcom_icc_rpm_set(dst_qn, sum_bw);
		if (ret)
			return ret;
	}

	for (i = 0; i < qp->num_clks; i++) {
	for (i = 0; i < qp->num_bus_clks; i++) {
		/*
		 * Use WAKE bucket for active clock, otherwise, use SLEEP bucket
		 * for other clocks.  If a platform doesn't set interconnect
@@ -425,7 +409,7 @@ int qnoc_probe(struct platform_device *pdev)
	struct qcom_icc_provider *qp;
	struct icc_node *node;
	size_t num_nodes, i;
	const char * const *cds;
	const char * const *cds = NULL;
	int cd_num;
	int ret;

@@ -440,21 +424,20 @@ int qnoc_probe(struct platform_device *pdev)
	qnodes = desc->nodes;
	num_nodes = desc->num_nodes;

	if (desc->num_clocks) {
		cds = desc->clocks;
		cd_num = desc->num_clocks;
	if (desc->num_intf_clocks) {
		cds = desc->intf_clocks;
		cd_num = desc->num_intf_clocks;
	} else {
		cds = bus_clocks;
		cd_num = ARRAY_SIZE(bus_clocks);
		/* 0 intf clocks is perfectly fine */
		cd_num = 0;
	}

	qp = devm_kzalloc(dev, struct_size(qp, bus_clks, cd_num), GFP_KERNEL);
	qp = devm_kzalloc(dev, sizeof(*qp), GFP_KERNEL);
	if (!qp)
		return -ENOMEM;

	qp->bus_clk_rate = devm_kcalloc(dev, cd_num, sizeof(*qp->bus_clk_rate),
					GFP_KERNEL);
	if (!qp->bus_clk_rate)
	qp->intf_clks = devm_kcalloc(dev, cd_num, sizeof(*qp->intf_clks), GFP_KERNEL);
	if (!qp->intf_clks)
		return -ENOMEM;

	data = devm_kzalloc(dev, struct_size(data, nodes, num_nodes),
@@ -462,9 +445,13 @@ int qnoc_probe(struct platform_device *pdev)
	if (!data)
		return -ENOMEM;

	qp->num_intf_clks = cd_num;
	for (i = 0; i < cd_num; i++)
		qp->bus_clks[i].id = cds[i];
	qp->num_clks = cd_num;
		qp->intf_clks[i].id = cds[i];

	qp->num_bus_clks = desc->no_clk_scaling ? 0 : NUM_BUS_CLKS;
	for (i = 0; i < qp->num_bus_clks; i++)
		qp->bus_clks[i].id = bus_clocks[i];

	qp->type = desc->type;
	qp->qos_offset = desc->qos_offset;
@@ -494,11 +481,15 @@ int qnoc_probe(struct platform_device *pdev)
	}

regmap_done:
	ret = devm_clk_bulk_get_optional(dev, qp->num_clks, qp->bus_clks);
	ret = devm_clk_bulk_get(dev, qp->num_bus_clks, qp->bus_clks);
	if (ret)
		return ret;

	ret = clk_bulk_prepare_enable(qp->num_clks, qp->bus_clks);
	ret = clk_bulk_prepare_enable(qp->num_bus_clks, qp->bus_clks);
	if (ret)
		return ret;

	ret = devm_clk_bulk_get(dev, qp->num_intf_clks, qp->intf_clks);
	if (ret)
		return ret;

@@ -512,6 +503,11 @@ int qnoc_probe(struct platform_device *pdev)

	icc_provider_init(provider);

	/* If this fails, bus accesses will crash the platform! */
	ret = clk_bulk_prepare_enable(qp->num_intf_clks, qp->intf_clks);
	if (ret)
		return ret;

	for (i = 0; i < num_nodes; i++) {
		size_t j;

@@ -528,10 +524,20 @@ int qnoc_probe(struct platform_device *pdev)
		for (j = 0; j < qnodes[i]->num_links; j++)
			icc_link_create(node, qnodes[i]->links[j]);

		/* Set QoS registers (we only need to do it once, generally) */
		if (qnodes[i]->qos.ap_owned &&
		    qnodes[i]->qos.qos_mode != NOC_QOS_MODE_INVALID) {
			ret = qcom_icc_qos_set(node);
			if (ret)
				return ret;
		}

		data->nodes[i] = node;
	}
	data->num_nodes = num_nodes;

	clk_bulk_disable_unprepare(qp->num_intf_clks, qp->intf_clks);

	ret = icc_provider_register(provider);
	if (ret)
		goto err_remove_nodes;
@@ -551,7 +557,7 @@ int qnoc_probe(struct platform_device *pdev)
	icc_provider_deregister(provider);
err_remove_nodes:
	icc_nodes_remove(provider);
	clk_bulk_disable_unprepare(qp->num_clks, qp->bus_clks);
	clk_bulk_disable_unprepare(qp->num_bus_clks, qp->bus_clks);

	return ret;
}
@@ -563,7 +569,7 @@ int qnoc_remove(struct platform_device *pdev)

	icc_provider_deregister(&qp->provider);
	icc_nodes_remove(&qp->provider);
	clk_bulk_disable_unprepare(qp->num_clks, qp->bus_clks);
	clk_bulk_disable_unprepare(qp->num_bus_clks, qp->bus_clks);

	return 0;
}
+16 −6
Original line number Diff line number Diff line
@@ -20,24 +20,32 @@ enum qcom_icc_type {
	QCOM_ICC_QNOC,
};

#define NUM_BUS_CLKS	2

/**
 * struct qcom_icc_provider - Qualcomm specific interconnect provider
 * @provider: generic interconnect provider
 * @num_clks: the total number of clk_bulk_data entries
 * @num_bus_clks: the total number of bus_clks clk_bulk_data entries (0 or 2)
 * @num_intf_clks: the total number of intf_clks clk_bulk_data entries
 * @type: the ICC provider type
 * @regmap: regmap for QoS registers read/write access
 * @qos_offset: offset to QoS registers
 * @bus_clk_rate: bus clock rate in Hz
 * @bus_clks: the clk_bulk_data table of bus clocks
 * @intf_clks: a clk_bulk_data array of interface clocks
 * @is_on: whether the bus is powered on
 */
struct qcom_icc_provider {
	struct icc_provider provider;
	int num_clks;
	int num_bus_clks;
	int num_intf_clks;
	enum qcom_icc_type type;
	struct regmap *regmap;
	unsigned int qos_offset;
	u64 *bus_clk_rate;
	struct clk_bulk_data bus_clks[];
	u64 bus_clk_rate[NUM_BUS_CLKS];
	struct clk_bulk_data bus_clks[NUM_BUS_CLKS];
	struct clk_bulk_data *intf_clks;
	bool is_on;
};

/**
@@ -91,8 +99,10 @@ struct qcom_icc_node {
struct qcom_icc_desc {
	struct qcom_icc_node * const *nodes;
	size_t num_nodes;
	const char * const *clocks;
	size_t num_clocks;
	const char * const *bus_clocks;
	const char * const *intf_clocks;
	size_t num_intf_clocks;
	bool no_clk_scaling;
	enum qcom_icc_type type;
	const struct regmap_config *regmap_cfg;
	unsigned int qos_offset;
+21 −14
Original line number Diff line number Diff line
@@ -21,21 +21,17 @@
#include "smd-rpm.h"
#include "msm8996.h"

static const char * const bus_mm_clocks[] = {
	"bus",
	"bus_a",
static const char * const mm_intf_clocks[] = {
	"iface"
};

static const char * const bus_a0noc_clocks[] = {
static const char * const a0noc_intf_clocks[] = {
	"aggre0_snoc_axi",
	"aggre0_cnoc_ahb",
	"aggre0_noc_mpu_cfg"
};

static const char * const bus_a2noc_clocks[] = {
	"bus",
	"bus_a",
static const char * const a2noc_intf_clocks[] = {
	"aggre2_ufs_axi",
	"ufs_axi"
};
@@ -1821,8 +1817,9 @@ static const struct qcom_icc_desc msm8996_a0noc = {
	.type = QCOM_ICC_NOC,
	.nodes = a0noc_nodes,
	.num_nodes = ARRAY_SIZE(a0noc_nodes),
	.clocks = bus_a0noc_clocks,
	.num_clocks = ARRAY_SIZE(bus_a0noc_clocks),
	.intf_clocks = a0noc_intf_clocks,
	.num_intf_clocks = ARRAY_SIZE(a0noc_intf_clocks),
	.no_clk_scaling = true,
	.regmap_cfg = &msm8996_a0noc_regmap_config
};

@@ -1865,8 +1862,8 @@ static const struct qcom_icc_desc msm8996_a2noc = {
	.type = QCOM_ICC_NOC,
	.nodes = a2noc_nodes,
	.num_nodes = ARRAY_SIZE(a2noc_nodes),
	.clocks = bus_a2noc_clocks,
	.num_clocks = ARRAY_SIZE(bus_a2noc_clocks),
	.intf_clocks = a2noc_intf_clocks,
	.num_intf_clocks = ARRAY_SIZE(a2noc_intf_clocks),
	.regmap_cfg = &msm8996_a2noc_regmap_config
};

@@ -2004,8 +2001,8 @@ static const struct qcom_icc_desc msm8996_mnoc = {
	.type = QCOM_ICC_NOC,
	.nodes = mnoc_nodes,
	.num_nodes = ARRAY_SIZE(mnoc_nodes),
	.clocks = bus_mm_clocks,
	.num_clocks = ARRAY_SIZE(bus_mm_clocks),
	.intf_clocks = mm_intf_clocks,
	.num_intf_clocks = ARRAY_SIZE(mm_intf_clocks),
	.regmap_cfg = &msm8996_mnoc_regmap_config
};

@@ -2111,7 +2108,17 @@ static struct platform_driver qnoc_driver = {
		.sync_state = icc_sync_state,
	}
};
module_platform_driver(qnoc_driver);
static int __init qnoc_driver_init(void)
{
	return platform_driver_register(&qnoc_driver);
}
core_initcall(qnoc_driver_init);

static void __exit qnoc_driver_exit(void)
{
	platform_driver_unregister(&qnoc_driver);
}
module_exit(qnoc_driver_exit);

MODULE_AUTHOR("Yassine Oudjana <y.oudjana@protonmail.com>");
MODULE_DESCRIPTION("Qualcomm MSM8996 NoC driver");
+7 −10
Original line number Diff line number Diff line
@@ -127,15 +127,11 @@ enum {
	SDM660_SNOC,
};

static const char * const bus_mm_clocks[] = {
	"bus",
	"bus_a",
static const char * const mm_intf_clocks[] = {
	"iface",
};

static const char * const bus_a2noc_clocks[] = {
	"bus",
	"bus_a",
static const char * const a2noc_intf_clocks[] = {
	"ipa",
	"ufs_axi",
	"aggre2_ufs_axi",
@@ -1516,8 +1512,8 @@ static const struct qcom_icc_desc sdm660_a2noc = {
	.type = QCOM_ICC_NOC,
	.nodes = sdm660_a2noc_nodes,
	.num_nodes = ARRAY_SIZE(sdm660_a2noc_nodes),
	.clocks = bus_a2noc_clocks,
	.num_clocks = ARRAY_SIZE(bus_a2noc_clocks),
	.intf_clocks = a2noc_intf_clocks,
	.num_intf_clocks = ARRAY_SIZE(a2noc_intf_clocks),
	.regmap_cfg = &sdm660_a2noc_regmap_config,
};

@@ -1620,6 +1616,7 @@ static const struct qcom_icc_desc sdm660_gnoc = {
	.nodes = sdm660_gnoc_nodes,
	.num_nodes = ARRAY_SIZE(sdm660_gnoc_nodes),
	.regmap_cfg = &sdm660_gnoc_regmap_config,
	.no_clk_scaling = true,
};

static struct qcom_icc_node * const sdm660_mnoc_nodes[] = {
@@ -1659,8 +1656,8 @@ static const struct qcom_icc_desc sdm660_mnoc = {
	.type = QCOM_ICC_NOC,
	.nodes = sdm660_mnoc_nodes,
	.num_nodes = ARRAY_SIZE(sdm660_mnoc_nodes),
	.clocks = bus_mm_clocks,
	.num_clocks = ARRAY_SIZE(bus_mm_clocks),
	.intf_clocks = mm_intf_clocks,
	.num_intf_clocks = ARRAY_SIZE(mm_intf_clocks),
	.regmap_cfg = &sdm660_mnoc_regmap_config,
};