mirror of
https://github.com/torvalds/linux.git
synced 2024-11-25 21:51:40 +00:00
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:
commit
1400725e45
@ -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;
|
||||
}
|
||||
|
@ -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,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");
|
||||
|
@ -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,
|
||||
};
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user