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: Georgi Djakov <djakov@kernel.org>
This commit is contained in:
Georgi Djakov 2023-06-10 10:43:50 +03:00
commit 1400725e45
4 changed files with 103 additions and 83 deletions

View File

@ -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 @@ regmap_done:
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 @@ regmap_done:
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 @@ err_deregister_provider:
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;
}

View File

@ -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;

View File

@ -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");

View File

@ -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,
};