* [PATCH 4/9] interconnect: qcom: icc-rpm: allow overwriting get_bw callback
From: Dmitry Baryshkov @ 2026-03-23 1:17 UTC (permalink / raw)
To: Georgi Djakov, Konrad Dybcio, Bjorn Andersson, Luca Weiss,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Brian Masney
Cc: linux-arm-msm, linux-pm, devicetree, linux-kernel
In-Reply-To: <20260323-msm8974-icc-v1-0-7892b8d5f2ea@oss.qualcomm.com>
MSM8974 requires a separate get_bw callback, since on that platform
increasing the clock rate for some of the NoCs during boot may lead to
hangs. For the details see commit 9caf2d956cfa ("interconnect: qcom:
msm8974: Don't boost the NoC rate during boot").
Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
---
drivers/interconnect/qcom/icc-rpm.c | 1 +
drivers/interconnect/qcom/icc-rpm.h | 1 +
2 files changed, 2 insertions(+)
diff --git a/drivers/interconnect/qcom/icc-rpm.c b/drivers/interconnect/qcom/icc-rpm.c
index ea1042d38128..aec2f84cd56f 100644
--- a/drivers/interconnect/qcom/icc-rpm.c
+++ b/drivers/interconnect/qcom/icc-rpm.c
@@ -553,6 +553,7 @@ int qnoc_probe(struct platform_device *pdev)
provider->aggregate = qcom_icc_bw_aggregate;
provider->xlate_extended = qcom_icc_xlate_extended;
provider->data = data;
+ provider->get_bw = desc->get_bw;
icc_provider_init(provider);
diff --git a/drivers/interconnect/qcom/icc-rpm.h b/drivers/interconnect/qcom/icc-rpm.h
index 3366531f66fc..cbf0a365839d 100644
--- a/drivers/interconnect/qcom/icc-rpm.h
+++ b/drivers/interconnect/qcom/icc-rpm.h
@@ -135,6 +135,7 @@ struct qcom_icc_desc {
unsigned int qos_offset;
u16 ab_coeff;
u16 ib_coeff;
+ int (*get_bw)(struct icc_node *node, u32 *avg, u32 *peak);
};
/* Valid for all bus types */
--
2.47.3
^ permalink raw reply related
* [PATCH 5/9] interconnect: qcom: define OCMEM bus resource
From: Dmitry Baryshkov @ 2026-03-23 1:17 UTC (permalink / raw)
To: Georgi Djakov, Konrad Dybcio, Bjorn Andersson, Luca Weiss,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Brian Masney
Cc: linux-arm-msm, linux-pm, devicetree, linux-kernel
In-Reply-To: <20260323-msm8974-icc-v1-0-7892b8d5f2ea@oss.qualcomm.com>
Some of the platforms (MSM8974, MSM8x26) require voting on the OCMEM
clock. Add new resource for that clock.
Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
---
drivers/interconnect/qcom/icc-rpm-clocks.c | 6 ++++++
drivers/interconnect/qcom/icc-rpm.h | 1 +
2 files changed, 7 insertions(+)
diff --git a/drivers/interconnect/qcom/icc-rpm-clocks.c b/drivers/interconnect/qcom/icc-rpm-clocks.c
index ac1677de7dfd..69846e26f46a 100644
--- a/drivers/interconnect/qcom/icc-rpm-clocks.c
+++ b/drivers/interconnect/qcom/icc-rpm-clocks.c
@@ -31,6 +31,12 @@ const struct rpm_clk_resource mem_1_clk = {
};
EXPORT_SYMBOL_GPL(mem_1_clk);
+const struct rpm_clk_resource gpu_mem_2_clk = {
+ .resource_type = QCOM_SMD_RPM_MEM_CLK,
+ .clock_id = 2,
+};
+EXPORT_SYMBOL_GPL(gpu_mem_2_clk);
+
const struct rpm_clk_resource bus_0_clk = {
.resource_type = QCOM_SMD_RPM_BUS_CLK,
.clock_id = 0,
diff --git a/drivers/interconnect/qcom/icc-rpm.h b/drivers/interconnect/qcom/icc-rpm.h
index cbf0a365839d..ad554c63967b 100644
--- a/drivers/interconnect/qcom/icc-rpm.h
+++ b/drivers/interconnect/qcom/icc-rpm.h
@@ -151,6 +151,7 @@ extern const struct rpm_clk_resource bimc_clk;
extern const struct rpm_clk_resource bus_0_clk;
extern const struct rpm_clk_resource bus_1_clk;
extern const struct rpm_clk_resource bus_2_clk;
+extern const struct rpm_clk_resource gpu_mem_2_clk;
extern const struct rpm_clk_resource mem_1_clk;
extern const struct rpm_clk_resource mmaxi_0_clk;
extern const struct rpm_clk_resource mmaxi_1_clk;
--
2.47.3
^ permalink raw reply related
* [PATCH 6/9] interconnect: qcom: let platforms declare their bugginess
From: Dmitry Baryshkov @ 2026-03-23 1:17 UTC (permalink / raw)
To: Georgi Djakov, Konrad Dybcio, Bjorn Andersson, Luca Weiss,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Brian Masney
Cc: linux-arm-msm, linux-pm, devicetree, linux-kernel
In-Reply-To: <20260323-msm8974-icc-v1-0-7892b8d5f2ea@oss.qualcomm.com>
On MSM8974 programming some of the RPM resources results in the
"resource does not exist" messages from the firmware. This occurs even
with the downstream bus driver, which happily ignores the errors. My
assumption is that these resources existed in the earlier firmware
revisions but were later switched to be programmed differently (for the
later platforms corresponding nodes use qos.ap_owned, which prevents
those resources from being programmed.
In preparation for conversion of the MSM8974 driver (which doesn't have
QoS code yet) to the main icc-rpm set of helpers, let the driver declare
that those -ENXIO errors must be ignored (for now). Later, when the QoS
programming is sorted out (and more interconnects are added to the DT),
this quirk might be removed.
Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
---
drivers/interconnect/qcom/icc-rpm.c | 17 ++++++++++-------
drivers/interconnect/qcom/icc-rpm.h | 3 +++
2 files changed, 13 insertions(+), 7 deletions(-)
diff --git a/drivers/interconnect/qcom/icc-rpm.c b/drivers/interconnect/qcom/icc-rpm.c
index aec2f84cd56f..23a1d116e79a 100644
--- a/drivers/interconnect/qcom/icc-rpm.c
+++ b/drivers/interconnect/qcom/icc-rpm.c
@@ -204,7 +204,7 @@ static int qcom_icc_qos_set(struct icc_node *node)
}
}
-static int qcom_icc_rpm_set(struct qcom_icc_node *qn, u64 *bw)
+static int qcom_icc_rpm_set(struct qcom_icc_node *qn, u64 *bw, bool ignore_enxio)
{
int ret, rpm_ctx = 0;
u64 bw_bps;
@@ -222,8 +222,9 @@ static int qcom_icc_rpm_set(struct qcom_icc_node *qn, u64 *bw)
bw_bps);
if (ret) {
pr_err("qcom_icc_rpm_smd_send mas %d error %d\n",
- qn->mas_rpm_id, ret);
- return ret;
+ qn->mas_rpm_id, ret);
+ if (ret != -ENXIO || !ignore_enxio)
+ return ret;
}
}
@@ -234,8 +235,9 @@ static int qcom_icc_rpm_set(struct qcom_icc_node *qn, u64 *bw)
bw_bps);
if (ret) {
pr_err("qcom_icc_rpm_smd_send slv %d error %d\n",
- qn->slv_rpm_id, ret);
- return ret;
+ qn->slv_rpm_id, ret);
+ if (ret != -ENXIO || !ignore_enxio)
+ return ret;
}
}
}
@@ -361,12 +363,12 @@ static int qcom_icc_set(struct icc_node *src, struct icc_node *dst)
active_rate = agg_clk_rate[QCOM_SMD_RPM_ACTIVE_STATE];
sleep_rate = agg_clk_rate[QCOM_SMD_RPM_SLEEP_STATE];
- ret = qcom_icc_rpm_set(src_qn, src_qn->sum_avg);
+ ret = qcom_icc_rpm_set(src_qn, src_qn->sum_avg, qp->ignore_enxio);
if (ret)
return ret;
if (dst_qn) {
- ret = qcom_icc_rpm_set(dst_qn, dst_qn->sum_avg);
+ ret = qcom_icc_rpm_set(dst_qn, dst_qn->sum_avg, qp->ignore_enxio);
if (ret)
return ret;
}
@@ -509,6 +511,7 @@ int qnoc_probe(struct platform_device *pdev)
for (i = 0; i < cd_num; i++)
qp->intf_clks[i].id = cds[i];
+ qp->ignore_enxio = desc->ignore_enxio;
qp->keep_alive = desc->keep_alive;
qp->type = desc->type;
qp->qos_offset = desc->qos_offset;
diff --git a/drivers/interconnect/qcom/icc-rpm.h b/drivers/interconnect/qcom/icc-rpm.h
index ad554c63967b..7d1cb2efa9ee 100644
--- a/drivers/interconnect/qcom/icc-rpm.h
+++ b/drivers/interconnect/qcom/icc-rpm.h
@@ -51,6 +51,7 @@ struct rpm_clk_resource {
* @bus_clk: a pointer to a HLOS-owned bus clock
* @intf_clks: a clk_bulk_data array of interface clocks
* @keep_alive: whether to always keep a minimum vote on the bus clocks
+ * @ignore_enxio: whether to ignore ENXIO errors (for MSM8974)
*/
struct qcom_icc_provider {
struct icc_provider provider;
@@ -65,6 +66,7 @@ struct qcom_icc_provider {
struct clk *bus_clk;
struct clk_bulk_data *intf_clks;
bool keep_alive;
+ bool ignore_enxio;
};
/**
@@ -136,6 +138,7 @@ struct qcom_icc_desc {
u16 ab_coeff;
u16 ib_coeff;
int (*get_bw)(struct icc_node *node, u32 *avg, u32 *peak);
+ bool ignore_enxio;
};
/* Valid for all bus types */
--
2.47.3
^ permalink raw reply related
* [PATCH 7/9] interconnect: qcom: msm8974: switch to the main icc-rpm driver
From: Dmitry Baryshkov @ 2026-03-23 1:17 UTC (permalink / raw)
To: Georgi Djakov, Konrad Dybcio, Bjorn Andersson, Luca Weiss,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Brian Masney
Cc: linux-arm-msm, linux-pm, devicetree, linux-kernel
In-Reply-To: <20260323-msm8974-icc-v1-0-7892b8d5f2ea@oss.qualcomm.com>
In preparation to restoring the ability of MSM8974 driver to work with
the modern kernels, switch the driver to the main icc-rpm set of helper
code.
As platform-specific workarounds, set the get_bw callback (returning 0)
to prevent initial setup from programming INT_MAX into the RPM (which
otherwise might hang the platform) and tell RPM programming code to
ignore -ENXIO errors from the firmware (until the QoS programming is
sorted out).
Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
---
drivers/interconnect/qcom/msm8974.c | 304 +++++-------------------------------
1 file changed, 43 insertions(+), 261 deletions(-)
diff --git a/drivers/interconnect/qcom/msm8974.c b/drivers/interconnect/qcom/msm8974.c
index 3239edc37f02..144f225ec885 100644
--- a/drivers/interconnect/qcom/msm8974.c
+++ b/drivers/interconnect/qcom/msm8974.c
@@ -173,65 +173,27 @@ enum {
MSM8974_SNOC_SLV_QDSS_STM,
};
-#define to_msm8974_icc_provider(_provider) \
- container_of(_provider, struct msm8974_icc_provider, provider)
-
-static const struct clk_bulk_data msm8974_icc_bus_clocks[] = {
- { .id = "bus" },
- { .id = "bus_a" },
-};
-
-/**
- * struct msm8974_icc_provider - Qualcomm specific interconnect provider
- * @provider: generic interconnect provider
- * @bus_clks: the clk_bulk_data table of bus clocks
- * @num_clks: the total number of clk_bulk_data entries
- */
-struct msm8974_icc_provider {
- struct icc_provider provider;
- struct clk_bulk_data *bus_clks;
- int num_clks;
-};
-
-#define MSM8974_ICC_MAX_LINKS 3
-
-/**
- * struct msm8974_icc_node - Qualcomm specific interconnect nodes
- * @name: the node name used in debugfs
- * @id: a unique node identifier
- * @links: an array of nodes where we can go next while traversing
- * @num_links: the total number of @links
- * @buswidth: width of the interconnect between a node and the bus (bytes)
- * @mas_rpm_id: RPM ID for devices that are bus masters
- * @slv_rpm_id: RPM ID for devices that are bus slaves
- * @rate: current bus clock rate in Hz
- */
-struct msm8974_icc_node {
- unsigned char *name;
- u16 id;
- u16 links[MSM8974_ICC_MAX_LINKS];
- u16 num_links;
- u16 buswidth;
- int mas_rpm_id;
- int slv_rpm_id;
- u64 rate;
-};
+static int msm8974_get_bw(struct icc_node *node, u32 *avg, u32 *peak)
+{
+ *avg = 0;
+ *peak = 0;
-struct msm8974_icc_desc {
- struct msm8974_icc_node * const *nodes;
- size_t num_nodes;
+ return 0;
};
#define DEFINE_QNODE(_name, _id, _buswidth, _mas_rpm_id, _slv_rpm_id, \
...) \
- static struct msm8974_icc_node _name = { \
+ static const u16 _name ## _links[] = { \
+ __VA_ARGS__ \
+ }; \
+ static struct qcom_icc_node _name = { \
.name = #_name, \
.id = _id, \
.buswidth = _buswidth, \
.mas_rpm_id = _mas_rpm_id, \
.slv_rpm_id = _slv_rpm_id, \
- .num_links = COUNT_ARGS(__VA_ARGS__), \
- .links = { __VA_ARGS__ }, \
+ .num_links = ARRAY_SIZE(_name ## _links), \
+ .links = _name ## _links, \
}
DEFINE_QNODE(mas_ampss_m0, MSM8974_BIMC_MAS_AMPSS_M0, 8, 0, -1);
@@ -242,7 +204,7 @@ DEFINE_QNODE(bimc_to_snoc, MSM8974_BIMC_TO_SNOC, 8, 3, 2, MSM8974_SNOC_TO_BIMC,
DEFINE_QNODE(slv_ebi_ch0, MSM8974_BIMC_SLV_EBI_CH0, 8, -1, 0);
DEFINE_QNODE(slv_ampss_l2, MSM8974_BIMC_SLV_AMPSS_L2, 8, -1, 1);
-static struct msm8974_icc_node * const msm8974_bimc_nodes[] = {
+static struct qcom_icc_node * const msm8974_bimc_nodes[] = {
[BIMC_MAS_AMPSS_M0] = &mas_ampss_m0,
[BIMC_MAS_AMPSS_M1] = &mas_ampss_m1,
[BIMC_MAS_MSS_PROC] = &mas_mss_proc,
@@ -252,9 +214,12 @@ static struct msm8974_icc_node * const msm8974_bimc_nodes[] = {
[BIMC_SLV_AMPSS_L2] = &slv_ampss_l2,
};
-static const struct msm8974_icc_desc msm8974_bimc = {
+static const struct qcom_icc_desc msm8974_bimc = {
.nodes = msm8974_bimc_nodes,
.num_nodes = ARRAY_SIZE(msm8974_bimc_nodes),
+ .bus_clk_desc = &bimc_clk,
+ .get_bw = msm8974_get_bw,
+ .ignore_enxio = true,
};
DEFINE_QNODE(mas_rpm_inst, MSM8974_CNOC_MAS_RPM_INST, 8, 45, -1);
@@ -295,7 +260,7 @@ DEFINE_QNODE(slv_ebi1_phy_cfg, MSM8974_CNOC_SLV_EBI1_PHY_CFG, 8, -1, 73);
DEFINE_QNODE(slv_rpm, MSM8974_CNOC_SLV_RPM, 8, -1, 74);
DEFINE_QNODE(slv_service_cnoc, MSM8974_CNOC_SLV_SERVICE_CNOC, 8, -1, 76);
-static struct msm8974_icc_node * const msm8974_cnoc_nodes[] = {
+static struct qcom_icc_node * const msm8974_cnoc_nodes[] = {
[CNOC_MAS_RPM_INST] = &mas_rpm_inst,
[CNOC_MAS_RPM_DATA] = &mas_rpm_data,
[CNOC_MAS_RPM_SYS] = &mas_rpm_sys,
@@ -335,9 +300,12 @@ static struct msm8974_icc_node * const msm8974_cnoc_nodes[] = {
[CNOC_SLV_SERVICE_CNOC] = &slv_service_cnoc,
};
-static const struct msm8974_icc_desc msm8974_cnoc = {
+static const struct qcom_icc_desc msm8974_cnoc = {
.nodes = msm8974_cnoc_nodes,
.num_nodes = ARRAY_SIZE(msm8974_cnoc_nodes),
+ .bus_clk_desc = &bus_2_clk,
+ .get_bw = msm8974_get_bw,
+ .ignore_enxio = true,
};
DEFINE_QNODE(mas_graphics_3d, MSM8974_MNOC_MAS_GRAPHICS_3D, 16, 6, -1, MSM8974_MNOC_TO_BIMC);
@@ -363,7 +331,7 @@ DEFINE_QNODE(slv_mnoc_mpu_cfg, MSM8974_MNOC_SLV_MNOC_MPU_CFG, 16, -1, 14);
DEFINE_QNODE(slv_onoc_mpu_cfg, MSM8974_MNOC_SLV_ONOC_MPU_CFG, 16, -1, 15);
DEFINE_QNODE(slv_service_mnoc, MSM8974_MNOC_SLV_SERVICE_MNOC, 16, -1, 17);
-static struct msm8974_icc_node * const msm8974_mnoc_nodes[] = {
+static struct qcom_icc_node * const msm8974_mnoc_nodes[] = {
[MNOC_MAS_GRAPHICS_3D] = &mas_graphics_3d,
[MNOC_MAS_JPEG] = &mas_jpeg,
[MNOC_MAS_MDP_PORT0] = &mas_mdp_port0,
@@ -388,9 +356,11 @@ static struct msm8974_icc_node * const msm8974_mnoc_nodes[] = {
[MNOC_SLV_SERVICE_MNOC] = &slv_service_mnoc,
};
-static const struct msm8974_icc_desc msm8974_mnoc = {
+static const struct qcom_icc_desc msm8974_mnoc = {
.nodes = msm8974_mnoc_nodes,
.num_nodes = ARRAY_SIZE(msm8974_mnoc_nodes),
+ .get_bw = msm8974_get_bw,
+ .ignore_enxio = true,
};
DEFINE_QNODE(ocmem_noc_to_ocmem_vnoc, MSM8974_OCMEM_NOC_TO_OCMEM_VNOC, 16, 54, 78, MSM8974_OCMEM_SLV_OCMEM);
@@ -408,7 +378,7 @@ DEFINE_QNODE(ocmem_vnoc_to_onoc, MSM8974_OCMEM_VNOC_TO_OCMEM_NOC, 16, 56, 79, MS
DEFINE_QNODE(ocmem_vnoc_to_snoc, MSM8974_OCMEM_VNOC_TO_SNOC, 8, 57, 80);
DEFINE_QNODE(mas_v_ocmem_gfx3d, MSM8974_OCMEM_VNOC_MAS_GFX3D, 8, 55, -1, MSM8974_OCMEM_VNOC_TO_OCMEM_NOC);
-static struct msm8974_icc_node * const msm8974_onoc_nodes[] = {
+static struct qcom_icc_node * const msm8974_onoc_nodes[] = {
[OCMEM_NOC_TO_OCMEM_VNOC] = &ocmem_noc_to_ocmem_vnoc,
[OCMEM_MAS_JPEG_OCMEM] = &mas_jpeg_ocmem,
[OCMEM_MAS_MDP_OCMEM] = &mas_mdp_ocmem,
@@ -423,9 +393,12 @@ static struct msm8974_icc_node * const msm8974_onoc_nodes[] = {
[OCMEM_SLV_OCMEM] = &slv_ocmem,
};
-static const struct msm8974_icc_desc msm8974_onoc = {
+static const struct qcom_icc_desc msm8974_onoc = {
.nodes = msm8974_onoc_nodes,
.num_nodes = ARRAY_SIZE(msm8974_onoc_nodes),
+ .bus_clk_desc = &gpu_mem_2_clk,
+ .get_bw = msm8974_get_bw,
+ .ignore_enxio = true,
};
DEFINE_QNODE(mas_pnoc_cfg, MSM8974_PNOC_MAS_PNOC_CFG, 8, 43, -1);
@@ -456,7 +429,7 @@ DEFINE_QNODE(slv_pnoc_mpu_cfg, MSM8974_PNOC_SLV_PNOC_MPU_CFG, 8, -1, 43);
DEFINE_QNODE(slv_prng, MSM8974_PNOC_SLV_PRNG, 8, -1, 44, MSM8974_PNOC_TO_SNOC);
DEFINE_QNODE(slv_service_pnoc, MSM8974_PNOC_SLV_SERVICE_PNOC, 8, -1, 46);
-static struct msm8974_icc_node * const msm8974_pnoc_nodes[] = {
+static struct qcom_icc_node * const msm8974_pnoc_nodes[] = {
[PNOC_MAS_PNOC_CFG] = &mas_pnoc_cfg,
[PNOC_MAS_SDCC_1] = &mas_sdcc_1,
[PNOC_MAS_SDCC_3] = &mas_sdcc_3,
@@ -486,9 +459,13 @@ static struct msm8974_icc_node * const msm8974_pnoc_nodes[] = {
[PNOC_SLV_SERVICE_PNOC] = &slv_service_pnoc,
};
-static const struct msm8974_icc_desc msm8974_pnoc = {
+static const struct qcom_icc_desc msm8974_pnoc = {
.nodes = msm8974_pnoc_nodes,
.num_nodes = ARRAY_SIZE(msm8974_pnoc_nodes),
+ .bus_clk_desc = &bus_0_clk,
+ .get_bw = msm8974_get_bw,
+ .keep_alive = true,
+ .ignore_enxio = true,
};
DEFINE_QNODE(mas_lpass_ahb, MSM8974_SNOC_MAS_LPASS_AHB, 8, 18, -1);
@@ -516,7 +493,7 @@ DEFINE_QNODE(slv_snoc_ocmem, MSM8974_SNOC_SLV_SNOC_OCMEM, 8, -1, 27);
DEFINE_QNODE(slv_service_snoc, MSM8974_SNOC_SLV_SERVICE_SNOC, 8, -1, 29);
DEFINE_QNODE(slv_qdss_stm, MSM8974_SNOC_SLV_QDSS_STM, 8, -1, 30);
-static struct msm8974_icc_node * const msm8974_snoc_nodes[] = {
+static struct qcom_icc_node * const msm8974_snoc_nodes[] = {
[SNOC_MAS_LPASS_AHB] = &mas_lpass_ahb,
[SNOC_MAS_QDSS_BAM] = &mas_qdss_bam,
[SNOC_MAS_SNOC_CFG] = &mas_snoc_cfg,
@@ -543,209 +520,14 @@ static struct msm8974_icc_node * const msm8974_snoc_nodes[] = {
[SNOC_SLV_QDSS_STM] = &slv_qdss_stm,
};
-static const struct msm8974_icc_desc msm8974_snoc = {
+static const struct qcom_icc_desc msm8974_snoc = {
.nodes = msm8974_snoc_nodes,
.num_nodes = ARRAY_SIZE(msm8974_snoc_nodes),
+ .bus_clk_desc = &bus_1_clk,
+ .get_bw = msm8974_get_bw,
+ .ignore_enxio = true,
};
-static void msm8974_icc_rpm_smd_send(struct device *dev, int rsc_type,
- char *name, int id, u64 val)
-{
- int ret;
-
- if (id == -1)
- return;
-
- /*
- * Setting the bandwidth requests for some nodes fails and this same
- * behavior occurs on the downstream MSM 3.4 kernel sources based on
- * errors like this in that kernel:
- *
- * msm_rpm_get_error_from_ack(): RPM NACK Unsupported resource
- * AXI: msm_bus_rpm_req(): RPM: Ack failed
- * AXI: msm_bus_rpm_commit_arb(): RPM: Req fail: mas:32, bw:240000000
- *
- * Since there's no publicly available documentation for this hardware,
- * and the bandwidth for some nodes in the path can be set properly,
- * let's not return an error.
- */
- ret = qcom_icc_rpm_smd_send(QCOM_SMD_RPM_ACTIVE_STATE, rsc_type, id,
- val);
- if (ret)
- dev_dbg(dev, "Cannot set bandwidth for node %s (%d): %d\n",
- name, id, ret);
-}
-
-static int msm8974_icc_set(struct icc_node *src, struct icc_node *dst)
-{
- struct msm8974_icc_node *src_qn, *dst_qn;
- struct msm8974_icc_provider *qp;
- u64 sum_bw, max_peak_bw, rate;
- u32 agg_avg = 0, agg_peak = 0;
- struct icc_provider *provider;
- struct icc_node *n;
- int ret, i;
-
- src_qn = src->data;
- dst_qn = dst->data;
- provider = src->provider;
- qp = to_msm8974_icc_provider(provider);
-
- list_for_each_entry(n, &provider->nodes, node_list)
- provider->aggregate(n, 0, n->avg_bw, n->peak_bw,
- &agg_avg, &agg_peak);
-
- sum_bw = icc_units_to_bps(agg_avg);
- max_peak_bw = icc_units_to_bps(agg_peak);
-
- /* Set bandwidth on source node */
- msm8974_icc_rpm_smd_send(provider->dev, RPM_BUS_MASTER_REQ,
- src_qn->name, src_qn->mas_rpm_id, sum_bw);
-
- msm8974_icc_rpm_smd_send(provider->dev, RPM_BUS_SLAVE_REQ,
- src_qn->name, src_qn->slv_rpm_id, sum_bw);
-
- /* Set bandwidth on destination node */
- msm8974_icc_rpm_smd_send(provider->dev, RPM_BUS_MASTER_REQ,
- dst_qn->name, dst_qn->mas_rpm_id, sum_bw);
-
- msm8974_icc_rpm_smd_send(provider->dev, RPM_BUS_SLAVE_REQ,
- dst_qn->name, dst_qn->slv_rpm_id, sum_bw);
-
- rate = max(sum_bw, max_peak_bw);
-
- do_div(rate, src_qn->buswidth);
-
- rate = min_t(u32, rate, INT_MAX);
-
- if (src_qn->rate == rate)
- return 0;
-
- for (i = 0; i < qp->num_clks; i++) {
- ret = clk_set_rate(qp->bus_clks[i].clk, rate);
- if (ret) {
- dev_err(provider->dev, "%s clk_set_rate error: %d\n",
- qp->bus_clks[i].id, ret);
- ret = 0;
- }
- }
-
- src_qn->rate = rate;
-
- return 0;
-}
-
-static int msm8974_get_bw(struct icc_node *node, u32 *avg, u32 *peak)
-{
- *avg = 0;
- *peak = 0;
-
- return 0;
-}
-
-static int msm8974_icc_probe(struct platform_device *pdev)
-{
- const struct msm8974_icc_desc *desc;
- struct msm8974_icc_node * const *qnodes;
- struct msm8974_icc_provider *qp;
- struct device *dev = &pdev->dev;
- struct icc_onecell_data *data;
- struct icc_provider *provider;
- struct icc_node *node;
- size_t num_nodes, i;
- int ret;
-
- /* wait for the RPM proxy */
- if (!qcom_icc_rpm_smd_available())
- return -EPROBE_DEFER;
-
- desc = of_device_get_match_data(dev);
- if (!desc)
- return -EINVAL;
-
- qnodes = desc->nodes;
- num_nodes = desc->num_nodes;
-
- qp = devm_kzalloc(dev, sizeof(*qp), GFP_KERNEL);
- if (!qp)
- return -ENOMEM;
-
- data = devm_kzalloc(dev, struct_size(data, nodes, num_nodes),
- GFP_KERNEL);
- if (!data)
- return -ENOMEM;
- data->num_nodes = num_nodes;
-
- qp->bus_clks = devm_kmemdup(dev, msm8974_icc_bus_clocks,
- sizeof(msm8974_icc_bus_clocks), GFP_KERNEL);
- if (!qp->bus_clks)
- return -ENOMEM;
-
- qp->num_clks = ARRAY_SIZE(msm8974_icc_bus_clocks);
- ret = devm_clk_bulk_get(dev, qp->num_clks, qp->bus_clks);
- if (ret)
- return ret;
-
- ret = clk_bulk_prepare_enable(qp->num_clks, qp->bus_clks);
- if (ret)
- return ret;
-
- provider = &qp->provider;
- provider->dev = dev;
- provider->set = msm8974_icc_set;
- provider->aggregate = icc_std_aggregate;
- provider->xlate = of_icc_xlate_onecell;
- provider->data = data;
- provider->get_bw = msm8974_get_bw;
-
- icc_provider_init(provider);
-
- for (i = 0; i < num_nodes; i++) {
- size_t j;
-
- node = icc_node_create(qnodes[i]->id);
- if (IS_ERR(node)) {
- ret = PTR_ERR(node);
- goto err_remove_nodes;
- }
-
- node->name = qnodes[i]->name;
- node->data = qnodes[i];
- icc_node_add(node, provider);
-
- dev_dbg(dev, "registered node %s\n", node->name);
-
- /* populate links */
- for (j = 0; j < qnodes[i]->num_links; j++)
- icc_link_create(node, qnodes[i]->links[j]);
-
- data->nodes[i] = node;
- }
-
- ret = icc_provider_register(provider);
- if (ret)
- goto err_remove_nodes;
-
- platform_set_drvdata(pdev, qp);
-
- return 0;
-
-err_remove_nodes:
- icc_nodes_remove(provider);
- clk_bulk_disable_unprepare(qp->num_clks, qp->bus_clks);
-
- return ret;
-}
-
-static void msm8974_icc_remove(struct platform_device *pdev)
-{
- struct msm8974_icc_provider *qp = platform_get_drvdata(pdev);
-
- icc_provider_deregister(&qp->provider);
- icc_nodes_remove(&qp->provider);
- clk_bulk_disable_unprepare(qp->num_clks, qp->bus_clks);
-}
-
static const struct of_device_id msm8974_noc_of_match[] = {
{ .compatible = "qcom,msm8974-bimc", .data = &msm8974_bimc},
{ .compatible = "qcom,msm8974-cnoc", .data = &msm8974_cnoc},
@@ -758,8 +540,8 @@ static const struct of_device_id msm8974_noc_of_match[] = {
MODULE_DEVICE_TABLE(of, msm8974_noc_of_match);
static struct platform_driver msm8974_noc_driver = {
- .probe = msm8974_icc_probe,
- .remove = msm8974_icc_remove,
+ .probe = qnoc_probe,
+ .remove = qnoc_remove,
.driver = {
.name = "qnoc-msm8974",
.of_match_table = msm8974_noc_of_match,
--
2.47.3
^ permalink raw reply related
* [PATCH 8/9] interconnect: qcom: msm8974: expand DEFINE_QNODE macros
From: Dmitry Baryshkov @ 2026-03-23 1:17 UTC (permalink / raw)
To: Georgi Djakov, Konrad Dybcio, Bjorn Andersson, Luca Weiss,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Brian Masney
Cc: linux-arm-msm, linux-pm, devicetree, linux-kernel
In-Reply-To: <20260323-msm8974-icc-v1-0-7892b8d5f2ea@oss.qualcomm.com>
The rest of Qualcomm Interconnect drivers have stopped using
DEFINE_QNODE long ago for the sake of readability. Stop using it inside
the msm8974 interconnect driver too.
Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
---
drivers/interconnect/qcom/msm8974.c | 1335 +++++++++++++++++++++++++++++++----
1 file changed, 1191 insertions(+), 144 deletions(-)
diff --git a/drivers/interconnect/qcom/msm8974.c b/drivers/interconnect/qcom/msm8974.c
index 144f225ec885..c020c61126ca 100644
--- a/drivers/interconnect/qcom/msm8974.c
+++ b/drivers/interconnect/qcom/msm8974.c
@@ -181,28 +181,75 @@ static int msm8974_get_bw(struct icc_node *node, u32 *avg, u32 *peak)
return 0;
};
-#define DEFINE_QNODE(_name, _id, _buswidth, _mas_rpm_id, _slv_rpm_id, \
- ...) \
- static const u16 _name ## _links[] = { \
- __VA_ARGS__ \
- }; \
- static struct qcom_icc_node _name = { \
- .name = #_name, \
- .id = _id, \
- .buswidth = _buswidth, \
- .mas_rpm_id = _mas_rpm_id, \
- .slv_rpm_id = _slv_rpm_id, \
- .num_links = ARRAY_SIZE(_name ## _links), \
- .links = _name ## _links, \
- }
-
-DEFINE_QNODE(mas_ampss_m0, MSM8974_BIMC_MAS_AMPSS_M0, 8, 0, -1);
-DEFINE_QNODE(mas_ampss_m1, MSM8974_BIMC_MAS_AMPSS_M1, 8, 0, -1);
-DEFINE_QNODE(mas_mss_proc, MSM8974_BIMC_MAS_MSS_PROC, 8, 1, -1);
-DEFINE_QNODE(bimc_to_mnoc, MSM8974_BIMC_TO_MNOC, 8, 2, -1, MSM8974_BIMC_SLV_EBI_CH0);
-DEFINE_QNODE(bimc_to_snoc, MSM8974_BIMC_TO_SNOC, 8, 3, 2, MSM8974_SNOC_TO_BIMC, MSM8974_BIMC_SLV_EBI_CH0, MSM8974_BIMC_MAS_AMPSS_M0);
-DEFINE_QNODE(slv_ebi_ch0, MSM8974_BIMC_SLV_EBI_CH0, 8, -1, 0);
-DEFINE_QNODE(slv_ampss_l2, MSM8974_BIMC_SLV_AMPSS_L2, 8, -1, 1);
+static struct qcom_icc_node mas_ampss_m0 = {
+ .name = "mas_ampss_m0",
+ .id = MSM8974_BIMC_MAS_AMPSS_M0,
+ .buswidth = 8,
+ .mas_rpm_id = 0,
+ .slv_rpm_id = -1,
+};
+
+static struct qcom_icc_node mas_ampss_m1 = {
+ .name = "mas_ampss_m1",
+ .id = MSM8974_BIMC_MAS_AMPSS_M1,
+ .buswidth = 8,
+ .mas_rpm_id = 0,
+ .slv_rpm_id = -1,
+};
+
+static struct qcom_icc_node mas_mss_proc = {
+ .name = "mas_mss_proc",
+ .id = MSM8974_BIMC_MAS_MSS_PROC,
+ .buswidth = 8,
+ .mas_rpm_id = 1,
+ .slv_rpm_id = -1,
+};
+
+static const u16 bimc_to_mnoc_links[] = {
+ MSM8974_BIMC_SLV_EBI_CH0
+};
+
+static struct qcom_icc_node bimc_to_mnoc = {
+ .name = "bimc_to_mnoc",
+ .id = MSM8974_BIMC_TO_MNOC,
+ .buswidth = 8,
+ .mas_rpm_id = 2,
+ .slv_rpm_id = -1,
+ .num_links = ARRAY_SIZE(bimc_to_mnoc_links),
+ .links = bimc_to_mnoc_links,
+};
+
+static const u16 bimc_to_snoc_links[] = {
+ MSM8974_SNOC_TO_BIMC,
+ MSM8974_BIMC_SLV_EBI_CH0,
+ MSM8974_BIMC_MAS_AMPSS_M0
+};
+
+static struct qcom_icc_node bimc_to_snoc = {
+ .name = "bimc_to_snoc",
+ .id = MSM8974_BIMC_TO_SNOC,
+ .buswidth = 8,
+ .mas_rpm_id = 3,
+ .slv_rpm_id = 2,
+ .num_links = ARRAY_SIZE(bimc_to_snoc_links),
+ .links = bimc_to_snoc_links,
+};
+
+static struct qcom_icc_node slv_ebi_ch0 = {
+ .name = "slv_ebi_ch0",
+ .id = MSM8974_BIMC_SLV_EBI_CH0,
+ .buswidth = 8,
+ .mas_rpm_id = -1,
+ .slv_rpm_id = 0,
+};
+
+static struct qcom_icc_node slv_ampss_l2 = {
+ .name = "slv_ampss_l2",
+ .id = MSM8974_BIMC_SLV_AMPSS_L2,
+ .buswidth = 8,
+ .mas_rpm_id = -1,
+ .slv_rpm_id = 1,
+};
static struct qcom_icc_node * const msm8974_bimc_nodes[] = {
[BIMC_MAS_AMPSS_M0] = &mas_ampss_m0,
@@ -222,43 +269,301 @@ static const struct qcom_icc_desc msm8974_bimc = {
.ignore_enxio = true,
};
-DEFINE_QNODE(mas_rpm_inst, MSM8974_CNOC_MAS_RPM_INST, 8, 45, -1);
-DEFINE_QNODE(mas_rpm_data, MSM8974_CNOC_MAS_RPM_DATA, 8, 46, -1);
-DEFINE_QNODE(mas_rpm_sys, MSM8974_CNOC_MAS_RPM_SYS, 8, 47, -1);
-DEFINE_QNODE(mas_dehr, MSM8974_CNOC_MAS_DEHR, 8, 48, -1);
-DEFINE_QNODE(mas_qdss_dap, MSM8974_CNOC_MAS_QDSS_DAP, 8, 49, -1);
-DEFINE_QNODE(mas_spdm, MSM8974_CNOC_MAS_SPDM, 8, 50, -1);
-DEFINE_QNODE(mas_tic, MSM8974_CNOC_MAS_TIC, 8, 51, -1);
-DEFINE_QNODE(slv_clk_ctl, MSM8974_CNOC_SLV_CLK_CTL, 8, -1, 47);
-DEFINE_QNODE(slv_cnoc_mss, MSM8974_CNOC_SLV_CNOC_MSS, 8, -1, 48);
-DEFINE_QNODE(slv_security, MSM8974_CNOC_SLV_SECURITY, 8, -1, 49);
-DEFINE_QNODE(slv_tcsr, MSM8974_CNOC_SLV_TCSR, 8, -1, 50);
-DEFINE_QNODE(slv_tlmm, MSM8974_CNOC_SLV_TLMM, 8, -1, 51);
-DEFINE_QNODE(slv_crypto_0_cfg, MSM8974_CNOC_SLV_CRYPTO_0_CFG, 8, -1, 52);
-DEFINE_QNODE(slv_crypto_1_cfg, MSM8974_CNOC_SLV_CRYPTO_1_CFG, 8, -1, 53);
-DEFINE_QNODE(slv_imem_cfg, MSM8974_CNOC_SLV_IMEM_CFG, 8, -1, 54);
-DEFINE_QNODE(slv_message_ram, MSM8974_CNOC_SLV_MESSAGE_RAM, 8, -1, 55);
-DEFINE_QNODE(slv_bimc_cfg, MSM8974_CNOC_SLV_BIMC_CFG, 8, -1, 56);
-DEFINE_QNODE(slv_boot_rom, MSM8974_CNOC_SLV_BOOT_ROM, 8, -1, 57);
-DEFINE_QNODE(slv_pmic_arb, MSM8974_CNOC_SLV_PMIC_ARB, 8, -1, 59);
-DEFINE_QNODE(slv_spdm_wrapper, MSM8974_CNOC_SLV_SPDM_WRAPPER, 8, -1, 60);
-DEFINE_QNODE(slv_dehr_cfg, MSM8974_CNOC_SLV_DEHR_CFG, 8, -1, 61);
-DEFINE_QNODE(slv_mpm, MSM8974_CNOC_SLV_MPM, 8, -1, 62);
-DEFINE_QNODE(slv_qdss_cfg, MSM8974_CNOC_SLV_QDSS_CFG, 8, -1, 63);
-DEFINE_QNODE(slv_rbcpr_cfg, MSM8974_CNOC_SLV_RBCPR_CFG, 8, -1, 64);
-DEFINE_QNODE(slv_rbcpr_qdss_apu_cfg, MSM8974_CNOC_SLV_RBCPR_QDSS_APU_CFG, 8, -1, 65);
-DEFINE_QNODE(cnoc_to_snoc, MSM8974_CNOC_TO_SNOC, 8, 52, 75);
-DEFINE_QNODE(slv_cnoc_onoc_cfg, MSM8974_CNOC_SLV_CNOC_ONOC_CFG, 8, -1, 68);
-DEFINE_QNODE(slv_cnoc_mnoc_mmss_cfg, MSM8974_CNOC_SLV_CNOC_MNOC_MMSS_CFG, 8, -1, 58);
-DEFINE_QNODE(slv_cnoc_mnoc_cfg, MSM8974_CNOC_SLV_CNOC_MNOC_CFG, 8, -1, 66);
-DEFINE_QNODE(slv_pnoc_cfg, MSM8974_CNOC_SLV_PNOC_CFG, 8, -1, 69);
-DEFINE_QNODE(slv_snoc_mpu_cfg, MSM8974_CNOC_SLV_SNOC_MPU_CFG, 8, -1, 67);
-DEFINE_QNODE(slv_snoc_cfg, MSM8974_CNOC_SLV_SNOC_CFG, 8, -1, 70);
-DEFINE_QNODE(slv_ebi1_dll_cfg, MSM8974_CNOC_SLV_EBI1_DLL_CFG, 8, -1, 71);
-DEFINE_QNODE(slv_phy_apu_cfg, MSM8974_CNOC_SLV_PHY_APU_CFG, 8, -1, 72);
-DEFINE_QNODE(slv_ebi1_phy_cfg, MSM8974_CNOC_SLV_EBI1_PHY_CFG, 8, -1, 73);
-DEFINE_QNODE(slv_rpm, MSM8974_CNOC_SLV_RPM, 8, -1, 74);
-DEFINE_QNODE(slv_service_cnoc, MSM8974_CNOC_SLV_SERVICE_CNOC, 8, -1, 76);
+static struct qcom_icc_node mas_rpm_inst = {
+ .name = "mas_rpm_inst",
+ .id = MSM8974_CNOC_MAS_RPM_INST,
+ .buswidth = 8,
+ .mas_rpm_id = 45,
+ .slv_rpm_id = -1,
+};
+
+static struct qcom_icc_node mas_rpm_data = {
+ .name = "mas_rpm_data",
+ .id = MSM8974_CNOC_MAS_RPM_DATA,
+ .buswidth = 8,
+ .mas_rpm_id = 46,
+ .slv_rpm_id = -1,
+};
+
+static struct qcom_icc_node mas_rpm_sys = {
+ .name = "mas_rpm_sys",
+ .id = MSM8974_CNOC_MAS_RPM_SYS,
+ .buswidth = 8,
+ .mas_rpm_id = 47,
+ .slv_rpm_id = -1,
+};
+
+static struct qcom_icc_node mas_dehr = {
+ .name = "mas_dehr",
+ .id = MSM8974_CNOC_MAS_DEHR,
+ .buswidth = 8,
+ .mas_rpm_id = 48,
+ .slv_rpm_id = -1,
+};
+
+static struct qcom_icc_node mas_qdss_dap = {
+ .name = "mas_qdss_dap",
+ .id = MSM8974_CNOC_MAS_QDSS_DAP,
+ .buswidth = 8,
+ .mas_rpm_id = 49,
+ .slv_rpm_id = -1,
+};
+
+static struct qcom_icc_node mas_spdm = {
+ .name = "mas_spdm",
+ .id = MSM8974_CNOC_MAS_SPDM,
+ .buswidth = 8,
+ .mas_rpm_id = 50,
+ .slv_rpm_id = -1,
+};
+
+static struct qcom_icc_node mas_tic = {
+ .name = "mas_tic",
+ .id = MSM8974_CNOC_MAS_TIC,
+ .buswidth = 8,
+ .mas_rpm_id = 51,
+ .slv_rpm_id = -1,
+};
+
+static struct qcom_icc_node slv_clk_ctl = {
+ .name = "slv_clk_ctl",
+ .id = MSM8974_CNOC_SLV_CLK_CTL,
+ .buswidth = 8,
+ .mas_rpm_id = -1,
+ .slv_rpm_id = 47,
+};
+
+static struct qcom_icc_node slv_cnoc_mss = {
+ .name = "slv_cnoc_mss",
+ .id = MSM8974_CNOC_SLV_CNOC_MSS,
+ .buswidth = 8,
+ .mas_rpm_id = -1,
+ .slv_rpm_id = 48,
+};
+
+static struct qcom_icc_node slv_security = {
+ .name = "slv_security",
+ .id = MSM8974_CNOC_SLV_SECURITY,
+ .buswidth = 8,
+ .mas_rpm_id = -1,
+ .slv_rpm_id = 49,
+};
+
+static struct qcom_icc_node slv_tcsr = {
+ .name = "slv_tcsr",
+ .id = MSM8974_CNOC_SLV_TCSR,
+ .buswidth = 8,
+ .mas_rpm_id = -1,
+ .slv_rpm_id = 50,
+};
+
+static struct qcom_icc_node slv_tlmm = {
+ .name = "slv_tlmm",
+ .id = MSM8974_CNOC_SLV_TLMM,
+ .buswidth = 8,
+ .mas_rpm_id = -1,
+ .slv_rpm_id = 51,
+};
+
+static struct qcom_icc_node slv_crypto_0_cfg = {
+ .name = "slv_crypto_0_cfg",
+ .id = MSM8974_CNOC_SLV_CRYPTO_0_CFG,
+ .buswidth = 8,
+ .mas_rpm_id = -1,
+ .slv_rpm_id = 52,
+};
+
+static struct qcom_icc_node slv_crypto_1_cfg = {
+ .name = "slv_crypto_1_cfg",
+ .id = MSM8974_CNOC_SLV_CRYPTO_1_CFG,
+ .buswidth = 8,
+ .mas_rpm_id = -1,
+ .slv_rpm_id = 53,
+};
+
+static struct qcom_icc_node slv_imem_cfg = {
+ .name = "slv_imem_cfg",
+ .id = MSM8974_CNOC_SLV_IMEM_CFG,
+ .buswidth = 8,
+ .mas_rpm_id = -1,
+ .slv_rpm_id = 54,
+};
+
+static struct qcom_icc_node slv_message_ram = {
+ .name = "slv_message_ram",
+ .id = MSM8974_CNOC_SLV_MESSAGE_RAM,
+ .buswidth = 8,
+ .mas_rpm_id = -1,
+ .slv_rpm_id = 55,
+};
+
+static struct qcom_icc_node slv_bimc_cfg = {
+ .name = "slv_bimc_cfg",
+ .id = MSM8974_CNOC_SLV_BIMC_CFG,
+ .buswidth = 8,
+ .mas_rpm_id = -1,
+ .slv_rpm_id = 56,
+};
+
+static struct qcom_icc_node slv_boot_rom = {
+ .name = "slv_boot_rom",
+ .id = MSM8974_CNOC_SLV_BOOT_ROM,
+ .buswidth = 8,
+ .mas_rpm_id = -1,
+ .slv_rpm_id = 57,
+};
+
+static struct qcom_icc_node slv_pmic_arb = {
+ .name = "slv_pmic_arb",
+ .id = MSM8974_CNOC_SLV_PMIC_ARB,
+ .buswidth = 8,
+ .mas_rpm_id = -1,
+ .slv_rpm_id = 59,
+};
+
+static struct qcom_icc_node slv_spdm_wrapper = {
+ .name = "slv_spdm_wrapper",
+ .id = MSM8974_CNOC_SLV_SPDM_WRAPPER,
+ .buswidth = 8,
+ .mas_rpm_id = -1,
+ .slv_rpm_id = 60,
+};
+
+static struct qcom_icc_node slv_dehr_cfg = {
+ .name = "slv_dehr_cfg",
+ .id = MSM8974_CNOC_SLV_DEHR_CFG,
+ .buswidth = 8,
+ .mas_rpm_id = -1,
+ .slv_rpm_id = 61,
+};
+
+static struct qcom_icc_node slv_mpm = {
+ .name = "slv_mpm",
+ .id = MSM8974_CNOC_SLV_MPM,
+ .buswidth = 8,
+ .mas_rpm_id = -1,
+ .slv_rpm_id = 62,
+};
+
+static struct qcom_icc_node slv_qdss_cfg = {
+ .name = "slv_qdss_cfg",
+ .id = MSM8974_CNOC_SLV_QDSS_CFG,
+ .buswidth = 8,
+ .mas_rpm_id = -1,
+ .slv_rpm_id = 63,
+};
+
+static struct qcom_icc_node slv_rbcpr_cfg = {
+ .name = "slv_rbcpr_cfg",
+ .id = MSM8974_CNOC_SLV_RBCPR_CFG,
+ .buswidth = 8,
+ .mas_rpm_id = -1,
+ .slv_rpm_id = 64,
+};
+
+static struct qcom_icc_node slv_rbcpr_qdss_apu_cfg = {
+ .name = "slv_rbcpr_qdss_apu_cfg",
+ .id = MSM8974_CNOC_SLV_RBCPR_QDSS_APU_CFG,
+ .buswidth = 8,
+ .mas_rpm_id = -1,
+ .slv_rpm_id = 65,
+};
+
+static struct qcom_icc_node cnoc_to_snoc = {
+ .name = "cnoc_to_snoc",
+ .id = MSM8974_CNOC_TO_SNOC,
+ .buswidth = 8,
+ .mas_rpm_id = 52,
+ .slv_rpm_id = 75,
+};
+
+static struct qcom_icc_node slv_cnoc_onoc_cfg = {
+ .name = "slv_cnoc_onoc_cfg",
+ .id = MSM8974_CNOC_SLV_CNOC_ONOC_CFG,
+ .buswidth = 8,
+ .mas_rpm_id = -1,
+ .slv_rpm_id = 68,
+};
+
+static struct qcom_icc_node slv_cnoc_mnoc_mmss_cfg = {
+ .name = "slv_cnoc_mnoc_mmss_cfg",
+ .id = MSM8974_CNOC_SLV_CNOC_MNOC_MMSS_CFG,
+ .buswidth = 8,
+ .mas_rpm_id = -1,
+ .slv_rpm_id = 58,
+};
+
+static struct qcom_icc_node slv_cnoc_mnoc_cfg = {
+ .name = "slv_cnoc_mnoc_cfg",
+ .id = MSM8974_CNOC_SLV_CNOC_MNOC_CFG,
+ .buswidth = 8,
+ .mas_rpm_id = -1,
+ .slv_rpm_id = 66,
+};
+
+static struct qcom_icc_node slv_pnoc_cfg = {
+ .name = "slv_pnoc_cfg",
+ .id = MSM8974_CNOC_SLV_PNOC_CFG,
+ .buswidth = 8,
+ .mas_rpm_id = -1,
+ .slv_rpm_id = 69,
+};
+
+static struct qcom_icc_node slv_snoc_mpu_cfg = {
+ .name = "slv_snoc_mpu_cfg",
+ .id = MSM8974_CNOC_SLV_SNOC_MPU_CFG,
+ .buswidth = 8,
+ .mas_rpm_id = -1,
+ .slv_rpm_id = 67,
+};
+
+static struct qcom_icc_node slv_snoc_cfg = {
+ .name = "slv_snoc_cfg",
+ .id = MSM8974_CNOC_SLV_SNOC_CFG,
+ .buswidth = 8,
+ .mas_rpm_id = -1,
+ .slv_rpm_id = 70,
+};
+
+static struct qcom_icc_node slv_ebi1_dll_cfg = {
+ .name = "slv_ebi1_dll_cfg",
+ .id = MSM8974_CNOC_SLV_EBI1_DLL_CFG,
+ .buswidth = 8,
+ .mas_rpm_id = -1,
+ .slv_rpm_id = 71,
+};
+
+static struct qcom_icc_node slv_phy_apu_cfg = {
+ .name = "slv_phy_apu_cfg",
+ .id = MSM8974_CNOC_SLV_PHY_APU_CFG,
+ .buswidth = 8,
+ .mas_rpm_id = -1,
+ .slv_rpm_id = 72,
+};
+
+static struct qcom_icc_node slv_ebi1_phy_cfg = {
+ .name = "slv_ebi1_phy_cfg",
+ .id = MSM8974_CNOC_SLV_EBI1_PHY_CFG,
+ .buswidth = 8,
+ .mas_rpm_id = -1,
+ .slv_rpm_id = 73,
+};
+
+static struct qcom_icc_node slv_rpm = {
+ .name = "slv_rpm",
+ .id = MSM8974_CNOC_SLV_RPM,
+ .buswidth = 8,
+ .mas_rpm_id = -1,
+ .slv_rpm_id = 74,
+};
+
+static struct qcom_icc_node slv_service_cnoc = {
+ .name = "slv_service_cnoc",
+ .id = MSM8974_CNOC_SLV_SERVICE_CNOC,
+ .buswidth = 8,
+ .mas_rpm_id = -1,
+ .slv_rpm_id = 76,
+};
static struct qcom_icc_node * const msm8974_cnoc_nodes[] = {
[CNOC_MAS_RPM_INST] = &mas_rpm_inst,
@@ -308,28 +613,211 @@ static const struct qcom_icc_desc msm8974_cnoc = {
.ignore_enxio = true,
};
-DEFINE_QNODE(mas_graphics_3d, MSM8974_MNOC_MAS_GRAPHICS_3D, 16, 6, -1, MSM8974_MNOC_TO_BIMC);
-DEFINE_QNODE(mas_jpeg, MSM8974_MNOC_MAS_JPEG, 16, 7, -1, MSM8974_MNOC_TO_BIMC);
-DEFINE_QNODE(mas_mdp_port0, MSM8974_MNOC_MAS_MDP_PORT0, 16, 8, -1, MSM8974_MNOC_TO_BIMC);
-DEFINE_QNODE(mas_video_p0, MSM8974_MNOC_MAS_VIDEO_P0, 16, 9, -1);
-DEFINE_QNODE(mas_video_p1, MSM8974_MNOC_MAS_VIDEO_P1, 16, 10, -1);
-DEFINE_QNODE(mas_vfe, MSM8974_MNOC_MAS_VFE, 16, 11, -1, MSM8974_MNOC_TO_BIMC);
-DEFINE_QNODE(mnoc_to_cnoc, MSM8974_MNOC_TO_CNOC, 16, 4, -1);
-DEFINE_QNODE(mnoc_to_bimc, MSM8974_MNOC_TO_BIMC, 16, -1, 16, MSM8974_BIMC_TO_MNOC);
-DEFINE_QNODE(slv_camera_cfg, MSM8974_MNOC_SLV_CAMERA_CFG, 16, -1, 3);
-DEFINE_QNODE(slv_display_cfg, MSM8974_MNOC_SLV_DISPLAY_CFG, 16, -1, 4);
-DEFINE_QNODE(slv_ocmem_cfg, MSM8974_MNOC_SLV_OCMEM_CFG, 16, -1, 5);
-DEFINE_QNODE(slv_cpr_cfg, MSM8974_MNOC_SLV_CPR_CFG, 16, -1, 6);
-DEFINE_QNODE(slv_cpr_xpu_cfg, MSM8974_MNOC_SLV_CPR_XPU_CFG, 16, -1, 7);
-DEFINE_QNODE(slv_misc_cfg, MSM8974_MNOC_SLV_MISC_CFG, 16, -1, 8);
-DEFINE_QNODE(slv_misc_xpu_cfg, MSM8974_MNOC_SLV_MISC_XPU_CFG, 16, -1, 9);
-DEFINE_QNODE(slv_venus_cfg, MSM8974_MNOC_SLV_VENUS_CFG, 16, -1, 10);
-DEFINE_QNODE(slv_graphics_3d_cfg, MSM8974_MNOC_SLV_GRAPHICS_3D_CFG, 16, -1, 11);
-DEFINE_QNODE(slv_mmss_clk_cfg, MSM8974_MNOC_SLV_MMSS_CLK_CFG, 16, -1, 12);
-DEFINE_QNODE(slv_mmss_clk_xpu_cfg, MSM8974_MNOC_SLV_MMSS_CLK_XPU_CFG, 16, -1, 13);
-DEFINE_QNODE(slv_mnoc_mpu_cfg, MSM8974_MNOC_SLV_MNOC_MPU_CFG, 16, -1, 14);
-DEFINE_QNODE(slv_onoc_mpu_cfg, MSM8974_MNOC_SLV_ONOC_MPU_CFG, 16, -1, 15);
-DEFINE_QNODE(slv_service_mnoc, MSM8974_MNOC_SLV_SERVICE_MNOC, 16, -1, 17);
+static const u16 mas_graphics_3d_links[] = {
+ MSM8974_MNOC_TO_BIMC
+};
+
+static struct qcom_icc_node mas_graphics_3d = {
+ .name = "mas_graphics_3d",
+ .id = MSM8974_MNOC_MAS_GRAPHICS_3D,
+ .buswidth = 16,
+ .mas_rpm_id = 6,
+ .slv_rpm_id = -1,
+ .num_links = ARRAY_SIZE(mas_graphics_3d_links),
+ .links = mas_graphics_3d_links,
+};
+
+static const u16 mas_jpeg_links[] = {
+ MSM8974_MNOC_TO_BIMC
+};
+
+static struct qcom_icc_node mas_jpeg = {
+ .name = "mas_jpeg",
+ .id = MSM8974_MNOC_MAS_JPEG,
+ .buswidth = 16,
+ .mas_rpm_id = 7,
+ .slv_rpm_id = -1,
+ .num_links = ARRAY_SIZE(mas_jpeg_links),
+ .links = mas_jpeg_links,
+};
+
+static const u16 mas_mdp_port0_links[] = {
+ MSM8974_MNOC_TO_BIMC
+};
+
+static struct qcom_icc_node mas_mdp_port0 = {
+ .name = "mas_mdp_port0",
+ .id = MSM8974_MNOC_MAS_MDP_PORT0,
+ .buswidth = 16,
+ .mas_rpm_id = 8,
+ .slv_rpm_id = -1,
+ .num_links = ARRAY_SIZE(mas_mdp_port0_links),
+ .links = mas_mdp_port0_links,
+};
+
+static struct qcom_icc_node mas_video_p0 = {
+ .name = "mas_video_p0",
+ .id = MSM8974_MNOC_MAS_VIDEO_P0,
+ .buswidth = 16,
+ .mas_rpm_id = 9,
+ .slv_rpm_id = -1,
+};
+
+static struct qcom_icc_node mas_video_p1 = {
+ .name = "mas_video_p1",
+ .id = MSM8974_MNOC_MAS_VIDEO_P1,
+ .buswidth = 16,
+ .mas_rpm_id = 10,
+ .slv_rpm_id = -1,
+};
+
+static const u16 mas_vfe_links[] = {
+ MSM8974_MNOC_TO_BIMC
+};
+
+static struct qcom_icc_node mas_vfe = {
+ .name = "mas_vfe",
+ .id = MSM8974_MNOC_MAS_VFE,
+ .buswidth = 16,
+ .mas_rpm_id = 11,
+ .slv_rpm_id = -1,
+ .num_links = ARRAY_SIZE(mas_vfe_links),
+ .links = mas_vfe_links,
+};
+
+static struct qcom_icc_node mnoc_to_cnoc = {
+ .name = "mnoc_to_cnoc",
+ .id = MSM8974_MNOC_TO_CNOC,
+ .buswidth = 16,
+ .mas_rpm_id = 4,
+ .slv_rpm_id = -1,
+};
+
+static const u16 mnoc_to_bimc_links[] = {
+ MSM8974_BIMC_TO_MNOC
+};
+
+static struct qcom_icc_node mnoc_to_bimc = {
+ .name = "mnoc_to_bimc",
+ .id = MSM8974_MNOC_TO_BIMC,
+ .buswidth = 16,
+ .mas_rpm_id = -1,
+ .slv_rpm_id = 16,
+ .num_links = ARRAY_SIZE(mnoc_to_bimc_links),
+ .links = mnoc_to_bimc_links,
+};
+
+static struct qcom_icc_node slv_camera_cfg = {
+ .name = "slv_camera_cfg",
+ .id = MSM8974_MNOC_SLV_CAMERA_CFG,
+ .buswidth = 16,
+ .mas_rpm_id = -1,
+ .slv_rpm_id = 3,
+};
+
+static struct qcom_icc_node slv_display_cfg = {
+ .name = "slv_display_cfg",
+ .id = MSM8974_MNOC_SLV_DISPLAY_CFG,
+ .buswidth = 16,
+ .mas_rpm_id = -1,
+ .slv_rpm_id = 4,
+};
+
+static struct qcom_icc_node slv_ocmem_cfg = {
+ .name = "slv_ocmem_cfg",
+ .id = MSM8974_MNOC_SLV_OCMEM_CFG,
+ .buswidth = 16,
+ .mas_rpm_id = -1,
+ .slv_rpm_id = 5,
+};
+
+static struct qcom_icc_node slv_cpr_cfg = {
+ .name = "slv_cpr_cfg",
+ .id = MSM8974_MNOC_SLV_CPR_CFG,
+ .buswidth = 16,
+ .mas_rpm_id = -1,
+ .slv_rpm_id = 6,
+};
+
+static struct qcom_icc_node slv_cpr_xpu_cfg = {
+ .name = "slv_cpr_xpu_cfg",
+ .id = MSM8974_MNOC_SLV_CPR_XPU_CFG,
+ .buswidth = 16,
+ .mas_rpm_id = -1,
+ .slv_rpm_id = 7,
+};
+
+static struct qcom_icc_node slv_misc_cfg = {
+ .name = "slv_misc_cfg",
+ .id = MSM8974_MNOC_SLV_MISC_CFG,
+ .buswidth = 16,
+ .mas_rpm_id = -1,
+ .slv_rpm_id = 8,
+};
+
+static struct qcom_icc_node slv_misc_xpu_cfg = {
+ .name = "slv_misc_xpu_cfg",
+ .id = MSM8974_MNOC_SLV_MISC_XPU_CFG,
+ .buswidth = 16,
+ .mas_rpm_id = -1,
+ .slv_rpm_id = 9,
+};
+
+static struct qcom_icc_node slv_venus_cfg = {
+ .name = "slv_venus_cfg",
+ .id = MSM8974_MNOC_SLV_VENUS_CFG,
+ .buswidth = 16,
+ .mas_rpm_id = -1,
+ .slv_rpm_id = 10,
+};
+
+static struct qcom_icc_node slv_graphics_3d_cfg = {
+ .name = "slv_graphics_3d_cfg",
+ .id = MSM8974_MNOC_SLV_GRAPHICS_3D_CFG,
+ .buswidth = 16,
+ .mas_rpm_id = -1,
+ .slv_rpm_id = 11,
+};
+
+static struct qcom_icc_node slv_mmss_clk_cfg = {
+ .name = "slv_mmss_clk_cfg",
+ .id = MSM8974_MNOC_SLV_MMSS_CLK_CFG,
+ .buswidth = 16,
+ .mas_rpm_id = -1,
+ .slv_rpm_id = 12,
+};
+
+static struct qcom_icc_node slv_mmss_clk_xpu_cfg = {
+ .name = "slv_mmss_clk_xpu_cfg",
+ .id = MSM8974_MNOC_SLV_MMSS_CLK_XPU_CFG,
+ .buswidth = 16,
+ .mas_rpm_id = -1,
+ .slv_rpm_id = 13,
+};
+
+static struct qcom_icc_node slv_mnoc_mpu_cfg = {
+ .name = "slv_mnoc_mpu_cfg",
+ .id = MSM8974_MNOC_SLV_MNOC_MPU_CFG,
+ .buswidth = 16,
+ .mas_rpm_id = -1,
+ .slv_rpm_id = 14,
+};
+
+static struct qcom_icc_node slv_onoc_mpu_cfg = {
+ .name = "slv_onoc_mpu_cfg",
+ .id = MSM8974_MNOC_SLV_ONOC_MPU_CFG,
+ .buswidth = 16,
+ .mas_rpm_id = -1,
+ .slv_rpm_id = 15,
+};
+
+static struct qcom_icc_node slv_service_mnoc = {
+ .name = "slv_service_mnoc",
+ .id = MSM8974_MNOC_SLV_SERVICE_MNOC,
+ .buswidth = 16,
+ .mas_rpm_id = -1,
+ .slv_rpm_id = 17,
+};
static struct qcom_icc_node * const msm8974_mnoc_nodes[] = {
[MNOC_MAS_GRAPHICS_3D] = &mas_graphics_3d,
@@ -363,20 +851,121 @@ static const struct qcom_icc_desc msm8974_mnoc = {
.ignore_enxio = true,
};
-DEFINE_QNODE(ocmem_noc_to_ocmem_vnoc, MSM8974_OCMEM_NOC_TO_OCMEM_VNOC, 16, 54, 78, MSM8974_OCMEM_SLV_OCMEM);
-DEFINE_QNODE(mas_jpeg_ocmem, MSM8974_OCMEM_MAS_JPEG_OCMEM, 16, 13, -1);
-DEFINE_QNODE(mas_mdp_ocmem, MSM8974_OCMEM_MAS_MDP_OCMEM, 16, 14, -1);
-DEFINE_QNODE(mas_video_p0_ocmem, MSM8974_OCMEM_MAS_VIDEO_P0_OCMEM, 16, 15, -1);
-DEFINE_QNODE(mas_video_p1_ocmem, MSM8974_OCMEM_MAS_VIDEO_P1_OCMEM, 16, 16, -1);
-DEFINE_QNODE(mas_vfe_ocmem, MSM8974_OCMEM_MAS_VFE_OCMEM, 16, 17, -1);
-DEFINE_QNODE(mas_cnoc_onoc_cfg, MSM8974_OCMEM_MAS_CNOC_ONOC_CFG, 16, 12, -1);
-DEFINE_QNODE(slv_service_onoc, MSM8974_OCMEM_SLV_SERVICE_ONOC, 16, -1, 19);
-DEFINE_QNODE(slv_ocmem, MSM8974_OCMEM_SLV_OCMEM, 16, -1, 18);
+static const u16 ocmem_noc_to_ocmem_vnoc_links[] = {
+ MSM8974_OCMEM_SLV_OCMEM
+};
+
+static struct qcom_icc_node ocmem_noc_to_ocmem_vnoc = {
+ .name = "ocmem_noc_to_ocmem_vnoc",
+ .id = MSM8974_OCMEM_NOC_TO_OCMEM_VNOC,
+ .buswidth = 16,
+ .mas_rpm_id = 54,
+ .slv_rpm_id = 78,
+ .num_links = ARRAY_SIZE(ocmem_noc_to_ocmem_vnoc_links),
+ .links = ocmem_noc_to_ocmem_vnoc_links,
+};
+
+static struct qcom_icc_node mas_jpeg_ocmem = {
+ .name = "mas_jpeg_ocmem",
+ .id = MSM8974_OCMEM_MAS_JPEG_OCMEM,
+ .buswidth = 16,
+ .mas_rpm_id = 13,
+ .slv_rpm_id = -1,
+};
+
+static struct qcom_icc_node mas_mdp_ocmem = {
+ .name = "mas_mdp_ocmem",
+ .id = MSM8974_OCMEM_MAS_MDP_OCMEM,
+ .buswidth = 16,
+ .mas_rpm_id = 14,
+ .slv_rpm_id = -1,
+};
+
+static struct qcom_icc_node mas_video_p0_ocmem = {
+ .name = "mas_video_p0_ocmem",
+ .id = MSM8974_OCMEM_MAS_VIDEO_P0_OCMEM,
+ .buswidth = 16,
+ .mas_rpm_id = 15,
+ .slv_rpm_id = -1,
+};
+
+static struct qcom_icc_node mas_video_p1_ocmem = {
+ .name = "mas_video_p1_ocmem",
+ .id = MSM8974_OCMEM_MAS_VIDEO_P1_OCMEM,
+ .buswidth = 16,
+ .mas_rpm_id = 16,
+ .slv_rpm_id = -1,
+};
+
+static struct qcom_icc_node mas_vfe_ocmem = {
+ .name = "mas_vfe_ocmem",
+ .id = MSM8974_OCMEM_MAS_VFE_OCMEM,
+ .buswidth = 16,
+ .mas_rpm_id = 17,
+ .slv_rpm_id = -1,
+};
+
+static struct qcom_icc_node mas_cnoc_onoc_cfg = {
+ .name = "mas_cnoc_onoc_cfg",
+ .id = MSM8974_OCMEM_MAS_CNOC_ONOC_CFG,
+ .buswidth = 16,
+ .mas_rpm_id = 12,
+ .slv_rpm_id = -1,
+};
+
+static struct qcom_icc_node slv_service_onoc = {
+ .name = "slv_service_onoc",
+ .id = MSM8974_OCMEM_SLV_SERVICE_ONOC,
+ .buswidth = 16,
+ .mas_rpm_id = -1,
+ .slv_rpm_id = 19,
+};
+
+static struct qcom_icc_node slv_ocmem = {
+ .name = "slv_ocmem",
+ .id = MSM8974_OCMEM_SLV_OCMEM,
+ .buswidth = 16,
+ .mas_rpm_id = -1,
+ .slv_rpm_id = 18,
+};
/* Virtual NoC is needed for connection to OCMEM */
-DEFINE_QNODE(ocmem_vnoc_to_onoc, MSM8974_OCMEM_VNOC_TO_OCMEM_NOC, 16, 56, 79, MSM8974_OCMEM_NOC_TO_OCMEM_VNOC);
-DEFINE_QNODE(ocmem_vnoc_to_snoc, MSM8974_OCMEM_VNOC_TO_SNOC, 8, 57, 80);
-DEFINE_QNODE(mas_v_ocmem_gfx3d, MSM8974_OCMEM_VNOC_MAS_GFX3D, 8, 55, -1, MSM8974_OCMEM_VNOC_TO_OCMEM_NOC);
+static const u16 ocmem_vnoc_to_onoc_links[] = {
+ MSM8974_OCMEM_NOC_TO_OCMEM_VNOC
+};
+
+static struct qcom_icc_node ocmem_vnoc_to_onoc = {
+ .name = "ocmem_vnoc_to_onoc",
+ .id = MSM8974_OCMEM_VNOC_TO_OCMEM_NOC,
+ .buswidth = 16,
+ .mas_rpm_id = 56,
+ .slv_rpm_id = 79,
+ .num_links = ARRAY_SIZE(ocmem_vnoc_to_onoc_links),
+ .links = ocmem_vnoc_to_onoc_links,
+};
+
+static struct qcom_icc_node ocmem_vnoc_to_snoc = {
+ .name = "ocmem_vnoc_to_snoc",
+ .id = MSM8974_OCMEM_VNOC_TO_SNOC,
+ .buswidth = 8,
+ .mas_rpm_id = 57,
+ .slv_rpm_id = 80,
+};
+
+static const u16 mas_v_ocmem_gfx3d_links[] = {
+ MSM8974_OCMEM_VNOC_TO_OCMEM_NOC
+};
+
+static struct qcom_icc_node mas_v_ocmem_gfx3d = {
+ .name = "mas_v_ocmem_gfx3d",
+ .id = MSM8974_OCMEM_VNOC_MAS_GFX3D,
+ .buswidth = 8,
+ .mas_rpm_id = 55,
+ .slv_rpm_id = -1,
+ .num_links = ARRAY_SIZE(mas_v_ocmem_gfx3d_links),
+ .links = mas_v_ocmem_gfx3d_links,
+};
+
static struct qcom_icc_node * const msm8974_onoc_nodes[] = {
[OCMEM_NOC_TO_OCMEM_VNOC] = &ocmem_noc_to_ocmem_vnoc,
@@ -401,33 +990,288 @@ static const struct qcom_icc_desc msm8974_onoc = {
.ignore_enxio = true,
};
-DEFINE_QNODE(mas_pnoc_cfg, MSM8974_PNOC_MAS_PNOC_CFG, 8, 43, -1);
-DEFINE_QNODE(mas_sdcc_1, MSM8974_PNOC_MAS_SDCC_1, 8, 33, -1, MSM8974_PNOC_TO_SNOC);
-DEFINE_QNODE(mas_sdcc_3, MSM8974_PNOC_MAS_SDCC_3, 8, 34, -1, MSM8974_PNOC_TO_SNOC);
-DEFINE_QNODE(mas_sdcc_4, MSM8974_PNOC_MAS_SDCC_4, 8, 36, -1, MSM8974_PNOC_TO_SNOC);
-DEFINE_QNODE(mas_sdcc_2, MSM8974_PNOC_MAS_SDCC_2, 8, 35, -1, MSM8974_PNOC_TO_SNOC);
-DEFINE_QNODE(mas_tsif, MSM8974_PNOC_MAS_TSIF, 8, 37, -1, MSM8974_PNOC_TO_SNOC);
-DEFINE_QNODE(mas_bam_dma, MSM8974_PNOC_MAS_BAM_DMA, 8, 38, -1);
-DEFINE_QNODE(mas_blsp_2, MSM8974_PNOC_MAS_BLSP_2, 8, 39, -1, MSM8974_PNOC_TO_SNOC);
-DEFINE_QNODE(mas_usb_hsic, MSM8974_PNOC_MAS_USB_HSIC, 8, 40, -1, MSM8974_PNOC_TO_SNOC);
-DEFINE_QNODE(mas_blsp_1, MSM8974_PNOC_MAS_BLSP_1, 8, 41, -1, MSM8974_PNOC_TO_SNOC);
-DEFINE_QNODE(mas_usb_hs, MSM8974_PNOC_MAS_USB_HS, 8, 42, -1, MSM8974_PNOC_TO_SNOC);
-DEFINE_QNODE(pnoc_to_snoc, MSM8974_PNOC_TO_SNOC, 8, 44, 45, MSM8974_SNOC_TO_PNOC, MSM8974_PNOC_SLV_PRNG);
-DEFINE_QNODE(slv_sdcc_1, MSM8974_PNOC_SLV_SDCC_1, 8, -1, 31);
-DEFINE_QNODE(slv_sdcc_3, MSM8974_PNOC_SLV_SDCC_3, 8, -1, 32);
-DEFINE_QNODE(slv_sdcc_2, MSM8974_PNOC_SLV_SDCC_2, 8, -1, 33);
-DEFINE_QNODE(slv_sdcc_4, MSM8974_PNOC_SLV_SDCC_4, 8, -1, 34);
-DEFINE_QNODE(slv_tsif, MSM8974_PNOC_SLV_TSIF, 8, -1, 35);
-DEFINE_QNODE(slv_bam_dma, MSM8974_PNOC_SLV_BAM_DMA, 8, -1, 36);
-DEFINE_QNODE(slv_blsp_2, MSM8974_PNOC_SLV_BLSP_2, 8, -1, 37);
-DEFINE_QNODE(slv_usb_hsic, MSM8974_PNOC_SLV_USB_HSIC, 8, -1, 38);
-DEFINE_QNODE(slv_blsp_1, MSM8974_PNOC_SLV_BLSP_1, 8, -1, 39);
-DEFINE_QNODE(slv_usb_hs, MSM8974_PNOC_SLV_USB_HS, 8, -1, 40);
-DEFINE_QNODE(slv_pdm, MSM8974_PNOC_SLV_PDM, 8, -1, 41);
-DEFINE_QNODE(slv_periph_apu_cfg, MSM8974_PNOC_SLV_PERIPH_APU_CFG, 8, -1, 42);
-DEFINE_QNODE(slv_pnoc_mpu_cfg, MSM8974_PNOC_SLV_PNOC_MPU_CFG, 8, -1, 43);
-DEFINE_QNODE(slv_prng, MSM8974_PNOC_SLV_PRNG, 8, -1, 44, MSM8974_PNOC_TO_SNOC);
-DEFINE_QNODE(slv_service_pnoc, MSM8974_PNOC_SLV_SERVICE_PNOC, 8, -1, 46);
+static struct qcom_icc_node mas_pnoc_cfg = {
+ .name = "mas_pnoc_cfg",
+ .id = MSM8974_PNOC_MAS_PNOC_CFG,
+ .buswidth = 8,
+ .mas_rpm_id = 43,
+ .slv_rpm_id = -1,
+};
+
+static const u16 mas_sdcc_1_links[] = {
+ MSM8974_PNOC_TO_SNOC
+};
+
+static struct qcom_icc_node mas_sdcc_1 = {
+ .name = "mas_sdcc_1",
+ .id = MSM8974_PNOC_MAS_SDCC_1,
+ .buswidth = 8,
+ .mas_rpm_id = 33,
+ .slv_rpm_id = -1,
+ .num_links = ARRAY_SIZE(mas_sdcc_1_links),
+ .links = mas_sdcc_1_links,
+};
+
+static const u16 mas_sdcc_3_links[] = {
+ MSM8974_PNOC_TO_SNOC
+};
+
+static struct qcom_icc_node mas_sdcc_3 = {
+ .name = "mas_sdcc_3",
+ .id = MSM8974_PNOC_MAS_SDCC_3,
+ .buswidth = 8,
+ .mas_rpm_id = 34,
+ .slv_rpm_id = -1,
+ .num_links = ARRAY_SIZE(mas_sdcc_3_links),
+ .links = mas_sdcc_3_links,
+};
+
+static const u16 mas_sdcc_4_links[] = {
+ MSM8974_PNOC_TO_SNOC
+};
+
+static struct qcom_icc_node mas_sdcc_4 = {
+ .name = "mas_sdcc_4",
+ .id = MSM8974_PNOC_MAS_SDCC_4,
+ .buswidth = 8,
+ .mas_rpm_id = 36,
+ .slv_rpm_id = -1,
+ .num_links = ARRAY_SIZE(mas_sdcc_4_links),
+ .links = mas_sdcc_4_links,
+};
+
+static const u16 mas_sdcc_2_links[] = {
+ MSM8974_PNOC_TO_SNOC
+};
+
+static struct qcom_icc_node mas_sdcc_2 = {
+ .name = "mas_sdcc_2",
+ .id = MSM8974_PNOC_MAS_SDCC_2,
+ .buswidth = 8,
+ .mas_rpm_id = 35,
+ .slv_rpm_id = -1,
+ .num_links = ARRAY_SIZE(mas_sdcc_2_links),
+ .links = mas_sdcc_2_links,
+};
+
+static const u16 mas_tsif_links[] = {
+ MSM8974_PNOC_TO_SNOC
+};
+
+static struct qcom_icc_node mas_tsif = {
+ .name = "mas_tsif",
+ .id = MSM8974_PNOC_MAS_TSIF,
+ .buswidth = 8,
+ .mas_rpm_id = 37,
+ .slv_rpm_id = -1,
+ .num_links = ARRAY_SIZE(mas_tsif_links),
+ .links = mas_tsif_links,
+};
+
+static struct qcom_icc_node mas_bam_dma = {
+ .name = "mas_bam_dma",
+ .id = MSM8974_PNOC_MAS_BAM_DMA,
+ .buswidth = 8,
+ .mas_rpm_id = 38,
+ .slv_rpm_id = -1,
+};
+
+static const u16 mas_blsp_2_links[] = {
+ MSM8974_PNOC_TO_SNOC
+};
+
+static struct qcom_icc_node mas_blsp_2 = {
+ .name = "mas_blsp_2",
+ .id = MSM8974_PNOC_MAS_BLSP_2,
+ .buswidth = 8,
+ .mas_rpm_id = 39,
+ .slv_rpm_id = -1,
+ .num_links = ARRAY_SIZE(mas_blsp_2_links),
+ .links = mas_blsp_2_links,
+};
+
+static const u16 mas_usb_hsic_links[] = {
+ MSM8974_PNOC_TO_SNOC
+};
+
+static struct qcom_icc_node mas_usb_hsic = {
+ .name = "mas_usb_hsic",
+ .id = MSM8974_PNOC_MAS_USB_HSIC,
+ .buswidth = 8,
+ .mas_rpm_id = 40,
+ .slv_rpm_id = -1,
+ .num_links = ARRAY_SIZE(mas_usb_hsic_links),
+ .links = mas_usb_hsic_links,
+};
+
+static const u16 mas_blsp_1_links[] = {
+ MSM8974_PNOC_TO_SNOC
+};
+
+static struct qcom_icc_node mas_blsp_1 = {
+ .name = "mas_blsp_1",
+ .id = MSM8974_PNOC_MAS_BLSP_1,
+ .buswidth = 8,
+ .mas_rpm_id = 41,
+ .slv_rpm_id = -1,
+ .num_links = ARRAY_SIZE(mas_blsp_1_links),
+ .links = mas_blsp_1_links,
+};
+
+static const u16 mas_usb_hs_links[] = {
+ MSM8974_PNOC_TO_SNOC
+};
+
+static struct qcom_icc_node mas_usb_hs = {
+ .name = "mas_usb_hs",
+ .id = MSM8974_PNOC_MAS_USB_HS,
+ .buswidth = 8,
+ .mas_rpm_id = 42,
+ .slv_rpm_id = -1,
+ .num_links = ARRAY_SIZE(mas_usb_hs_links),
+ .links = mas_usb_hs_links,
+};
+
+static const u16 pnoc_to_snoc_links[] = {
+ MSM8974_SNOC_TO_PNOC,
+ MSM8974_PNOC_SLV_PRNG
+};
+
+static struct qcom_icc_node pnoc_to_snoc = {
+ .name = "pnoc_to_snoc",
+ .id = MSM8974_PNOC_TO_SNOC,
+ .buswidth = 8,
+ .mas_rpm_id = 44,
+ .slv_rpm_id = 45,
+ .num_links = ARRAY_SIZE(pnoc_to_snoc_links),
+ .links = pnoc_to_snoc_links,
+};
+
+static struct qcom_icc_node slv_sdcc_1 = {
+ .name = "slv_sdcc_1",
+ .id = MSM8974_PNOC_SLV_SDCC_1,
+ .buswidth = 8,
+ .mas_rpm_id = -1,
+ .slv_rpm_id = 31,
+};
+
+static struct qcom_icc_node slv_sdcc_3 = {
+ .name = "slv_sdcc_3",
+ .id = MSM8974_PNOC_SLV_SDCC_3,
+ .buswidth = 8,
+ .mas_rpm_id = -1,
+ .slv_rpm_id = 32,
+};
+
+static struct qcom_icc_node slv_sdcc_2 = {
+ .name = "slv_sdcc_2",
+ .id = MSM8974_PNOC_SLV_SDCC_2,
+ .buswidth = 8,
+ .mas_rpm_id = -1,
+ .slv_rpm_id = 33,
+};
+
+static struct qcom_icc_node slv_sdcc_4 = {
+ .name = "slv_sdcc_4",
+ .id = MSM8974_PNOC_SLV_SDCC_4,
+ .buswidth = 8,
+ .mas_rpm_id = -1,
+ .slv_rpm_id = 34,
+};
+
+static struct qcom_icc_node slv_tsif = {
+ .name = "slv_tsif",
+ .id = MSM8974_PNOC_SLV_TSIF,
+ .buswidth = 8,
+ .mas_rpm_id = -1,
+ .slv_rpm_id = 35,
+};
+
+static struct qcom_icc_node slv_bam_dma = {
+ .name = "slv_bam_dma",
+ .id = MSM8974_PNOC_SLV_BAM_DMA,
+ .buswidth = 8,
+ .mas_rpm_id = -1,
+ .slv_rpm_id = 36,
+};
+
+static struct qcom_icc_node slv_blsp_2 = {
+ .name = "slv_blsp_2",
+ .id = MSM8974_PNOC_SLV_BLSP_2,
+ .buswidth = 8,
+ .mas_rpm_id = -1,
+ .slv_rpm_id = 37,
+};
+
+static struct qcom_icc_node slv_usb_hsic = {
+ .name = "slv_usb_hsic",
+ .id = MSM8974_PNOC_SLV_USB_HSIC,
+ .buswidth = 8,
+ .mas_rpm_id = -1,
+ .slv_rpm_id = 38,
+};
+
+static struct qcom_icc_node slv_blsp_1 = {
+ .name = "slv_blsp_1",
+ .id = MSM8974_PNOC_SLV_BLSP_1,
+ .buswidth = 8,
+ .mas_rpm_id = -1,
+ .slv_rpm_id = 39,
+};
+
+static struct qcom_icc_node slv_usb_hs = {
+ .name = "slv_usb_hs",
+ .id = MSM8974_PNOC_SLV_USB_HS,
+ .buswidth = 8,
+ .mas_rpm_id = -1,
+ .slv_rpm_id = 40,
+};
+
+static struct qcom_icc_node slv_pdm = {
+ .name = "slv_pdm",
+ .id = MSM8974_PNOC_SLV_PDM,
+ .buswidth = 8,
+ .mas_rpm_id = -1,
+ .slv_rpm_id = 41,
+};
+
+static struct qcom_icc_node slv_periph_apu_cfg = {
+ .name = "slv_periph_apu_cfg",
+ .id = MSM8974_PNOC_SLV_PERIPH_APU_CFG,
+ .buswidth = 8,
+ .mas_rpm_id = -1,
+ .slv_rpm_id = 42,
+};
+
+static struct qcom_icc_node slv_pnoc_mpu_cfg = {
+ .name = "slv_pnoc_mpu_cfg",
+ .id = MSM8974_PNOC_SLV_PNOC_MPU_CFG,
+ .buswidth = 8,
+ .mas_rpm_id = -1,
+ .slv_rpm_id = 43,
+};
+
+static const u16 slv_prng_links[] = {
+ MSM8974_PNOC_TO_SNOC
+};
+
+static struct qcom_icc_node slv_prng = {
+ .name = "slv_prng",
+ .id = MSM8974_PNOC_SLV_PRNG,
+ .buswidth = 8,
+ .mas_rpm_id = -1,
+ .slv_rpm_id = 44,
+ .num_links = ARRAY_SIZE(slv_prng_links),
+ .links = slv_prng_links,
+};
+
+static struct qcom_icc_node slv_service_pnoc = {
+ .name = "slv_service_pnoc",
+ .id = MSM8974_PNOC_SLV_SERVICE_PNOC,
+ .buswidth = 8,
+ .mas_rpm_id = -1,
+ .slv_rpm_id = 46,
+};
static struct qcom_icc_node * const msm8974_pnoc_nodes[] = {
[PNOC_MAS_PNOC_CFG] = &mas_pnoc_cfg,
@@ -468,30 +1312,233 @@ static const struct qcom_icc_desc msm8974_pnoc = {
.ignore_enxio = true,
};
-DEFINE_QNODE(mas_lpass_ahb, MSM8974_SNOC_MAS_LPASS_AHB, 8, 18, -1);
-DEFINE_QNODE(mas_qdss_bam, MSM8974_SNOC_MAS_QDSS_BAM, 8, 19, -1);
-DEFINE_QNODE(mas_snoc_cfg, MSM8974_SNOC_MAS_SNOC_CFG, 8, 20, -1);
-DEFINE_QNODE(snoc_to_bimc, MSM8974_SNOC_TO_BIMC, 8, 21, 24, MSM8974_BIMC_TO_SNOC);
-DEFINE_QNODE(snoc_to_cnoc, MSM8974_SNOC_TO_CNOC, 8, 22, 25);
-DEFINE_QNODE(snoc_to_pnoc, MSM8974_SNOC_TO_PNOC, 8, 29, 28, MSM8974_PNOC_TO_SNOC);
-DEFINE_QNODE(snoc_to_ocmem_vnoc, MSM8974_SNOC_TO_OCMEM_VNOC, 8, 53, 77, MSM8974_OCMEM_VNOC_TO_OCMEM_NOC);
-DEFINE_QNODE(mas_crypto_core0, MSM8974_SNOC_MAS_CRYPTO_CORE0, 8, 23, -1, MSM8974_SNOC_TO_BIMC);
-DEFINE_QNODE(mas_crypto_core1, MSM8974_SNOC_MAS_CRYPTO_CORE1, 8, 24, -1);
-DEFINE_QNODE(mas_lpass_proc, MSM8974_SNOC_MAS_LPASS_PROC, 8, 25, -1, MSM8974_SNOC_TO_OCMEM_VNOC);
-DEFINE_QNODE(mas_mss, MSM8974_SNOC_MAS_MSS, 8, 26, -1);
-DEFINE_QNODE(mas_mss_nav, MSM8974_SNOC_MAS_MSS_NAV, 8, 27, -1);
-DEFINE_QNODE(mas_ocmem_dma, MSM8974_SNOC_MAS_OCMEM_DMA, 8, 28, -1);
-DEFINE_QNODE(mas_wcss, MSM8974_SNOC_MAS_WCSS, 8, 30, -1);
-DEFINE_QNODE(mas_qdss_etr, MSM8974_SNOC_MAS_QDSS_ETR, 8, 31, -1);
-DEFINE_QNODE(mas_usb3, MSM8974_SNOC_MAS_USB3, 8, 32, -1, MSM8974_SNOC_TO_BIMC);
-DEFINE_QNODE(slv_ampss, MSM8974_SNOC_SLV_AMPSS, 8, -1, 20);
-DEFINE_QNODE(slv_lpass, MSM8974_SNOC_SLV_LPASS, 8, -1, 21);
-DEFINE_QNODE(slv_usb3, MSM8974_SNOC_SLV_USB3, 8, -1, 22);
-DEFINE_QNODE(slv_wcss, MSM8974_SNOC_SLV_WCSS, 8, -1, 23);
-DEFINE_QNODE(slv_ocimem, MSM8974_SNOC_SLV_OCIMEM, 8, -1, 26);
-DEFINE_QNODE(slv_snoc_ocmem, MSM8974_SNOC_SLV_SNOC_OCMEM, 8, -1, 27);
-DEFINE_QNODE(slv_service_snoc, MSM8974_SNOC_SLV_SERVICE_SNOC, 8, -1, 29);
-DEFINE_QNODE(slv_qdss_stm, MSM8974_SNOC_SLV_QDSS_STM, 8, -1, 30);
+static struct qcom_icc_node mas_lpass_ahb = {
+ .name = "mas_lpass_ahb",
+ .id = MSM8974_SNOC_MAS_LPASS_AHB,
+ .buswidth = 8,
+ .mas_rpm_id = 18,
+ .slv_rpm_id = -1,
+};
+
+static struct qcom_icc_node mas_qdss_bam = {
+ .name = "mas_qdss_bam",
+ .id = MSM8974_SNOC_MAS_QDSS_BAM,
+ .buswidth = 8,
+ .mas_rpm_id = 19,
+ .slv_rpm_id = -1,
+};
+
+static struct qcom_icc_node mas_snoc_cfg = {
+ .name = "mas_snoc_cfg",
+ .id = MSM8974_SNOC_MAS_SNOC_CFG,
+ .buswidth = 8,
+ .mas_rpm_id = 20,
+ .slv_rpm_id = -1,
+};
+
+static const u16 snoc_to_bimc_links[] = {
+ MSM8974_BIMC_TO_SNOC
+};
+
+static struct qcom_icc_node snoc_to_bimc = {
+ .name = "snoc_to_bimc",
+ .id = MSM8974_SNOC_TO_BIMC,
+ .buswidth = 8,
+ .mas_rpm_id = 21,
+ .slv_rpm_id = 24,
+ .num_links = ARRAY_SIZE(snoc_to_bimc_links),
+ .links = snoc_to_bimc_links,
+};
+
+static struct qcom_icc_node snoc_to_cnoc = {
+ .name = "snoc_to_cnoc",
+ .id = MSM8974_SNOC_TO_CNOC,
+ .buswidth = 8,
+ .mas_rpm_id = 22,
+ .slv_rpm_id = 25,
+};
+
+static const u16 snoc_to_pnoc_links[] = {
+ MSM8974_PNOC_TO_SNOC
+};
+
+static struct qcom_icc_node snoc_to_pnoc = {
+ .name = "snoc_to_pnoc",
+ .id = MSM8974_SNOC_TO_PNOC,
+ .buswidth = 8,
+ .mas_rpm_id = 29,
+ .slv_rpm_id = 28,
+ .num_links = ARRAY_SIZE(snoc_to_pnoc_links),
+ .links = snoc_to_pnoc_links,
+};
+
+static const u16 snoc_to_ocmem_vnoc_links[] = {
+ MSM8974_OCMEM_VNOC_TO_OCMEM_NOC
+};
+
+static struct qcom_icc_node snoc_to_ocmem_vnoc = {
+ .name = "snoc_to_ocmem_vnoc",
+ .id = MSM8974_SNOC_TO_OCMEM_VNOC,
+ .buswidth = 8,
+ .mas_rpm_id = 53,
+ .slv_rpm_id = 77,
+ .num_links = ARRAY_SIZE(snoc_to_ocmem_vnoc_links),
+ .links = snoc_to_ocmem_vnoc_links,
+};
+
+static const u16 mas_crypto_core0_links[] = {
+ MSM8974_SNOC_TO_BIMC
+};
+
+static struct qcom_icc_node mas_crypto_core0 = {
+ .name = "mas_crypto_core0",
+ .id = MSM8974_SNOC_MAS_CRYPTO_CORE0,
+ .buswidth = 8,
+ .mas_rpm_id = 23,
+ .slv_rpm_id = -1,
+ .num_links = ARRAY_SIZE(mas_crypto_core0_links),
+ .links = mas_crypto_core0_links,
+};
+
+static struct qcom_icc_node mas_crypto_core1 = {
+ .name = "mas_crypto_core1",
+ .id = MSM8974_SNOC_MAS_CRYPTO_CORE1,
+ .buswidth = 8,
+ .mas_rpm_id = 24,
+ .slv_rpm_id = -1,
+};
+
+static const u16 mas_lpass_proc_links[] = {
+ MSM8974_SNOC_TO_OCMEM_VNOC
+};
+
+static struct qcom_icc_node mas_lpass_proc = {
+ .name = "mas_lpass_proc",
+ .id = MSM8974_SNOC_MAS_LPASS_PROC,
+ .buswidth = 8,
+ .mas_rpm_id = 25,
+ .slv_rpm_id = -1,
+ .num_links = ARRAY_SIZE(mas_lpass_proc_links),
+ .links = mas_lpass_proc_links,
+};
+
+static struct qcom_icc_node mas_mss = {
+ .name = "mas_mss",
+ .id = MSM8974_SNOC_MAS_MSS,
+ .buswidth = 8,
+ .mas_rpm_id = 26,
+ .slv_rpm_id = -1,
+};
+
+static struct qcom_icc_node mas_mss_nav = {
+ .name = "mas_mss_nav",
+ .id = MSM8974_SNOC_MAS_MSS_NAV,
+ .buswidth = 8,
+ .mas_rpm_id = 27,
+ .slv_rpm_id = -1,
+};
+
+static struct qcom_icc_node mas_ocmem_dma = {
+ .name = "mas_ocmem_dma",
+ .id = MSM8974_SNOC_MAS_OCMEM_DMA,
+ .buswidth = 8,
+ .mas_rpm_id = 28,
+ .slv_rpm_id = -1,
+};
+
+static struct qcom_icc_node mas_wcss = {
+ .name = "mas_wcss",
+ .id = MSM8974_SNOC_MAS_WCSS,
+ .buswidth = 8,
+ .mas_rpm_id = 30,
+ .slv_rpm_id = -1,
+};
+
+static struct qcom_icc_node mas_qdss_etr = {
+ .name = "mas_qdss_etr",
+ .id = MSM8974_SNOC_MAS_QDSS_ETR,
+ .buswidth = 8,
+ .mas_rpm_id = 31,
+ .slv_rpm_id = -1,
+};
+
+static const u16 mas_usb3_links[] = {
+ MSM8974_SNOC_TO_BIMC
+};
+
+static struct qcom_icc_node mas_usb3 = {
+ .name = "mas_usb3",
+ .id = MSM8974_SNOC_MAS_USB3,
+ .buswidth = 8,
+ .mas_rpm_id = 32,
+ .slv_rpm_id = -1,
+ .num_links = ARRAY_SIZE(mas_usb3_links),
+ .links = mas_usb3_links,
+};
+
+static struct qcom_icc_node slv_ampss = {
+ .name = "slv_ampss",
+ .id = MSM8974_SNOC_SLV_AMPSS,
+ .buswidth = 8,
+ .mas_rpm_id = -1,
+ .slv_rpm_id = 20,
+};
+
+static struct qcom_icc_node slv_lpass = {
+ .name = "slv_lpass",
+ .id = MSM8974_SNOC_SLV_LPASS,
+ .buswidth = 8,
+ .mas_rpm_id = -1,
+ .slv_rpm_id = 21,
+};
+
+static struct qcom_icc_node slv_usb3 = {
+ .name = "slv_usb3",
+ .id = MSM8974_SNOC_SLV_USB3,
+ .buswidth = 8,
+ .mas_rpm_id = -1,
+ .slv_rpm_id = 22,
+};
+
+static struct qcom_icc_node slv_wcss = {
+ .name = "slv_wcss",
+ .id = MSM8974_SNOC_SLV_WCSS,
+ .buswidth = 8,
+ .mas_rpm_id = -1,
+ .slv_rpm_id = 23,
+};
+
+static struct qcom_icc_node slv_ocimem = {
+ .name = "slv_ocimem",
+ .id = MSM8974_SNOC_SLV_OCIMEM,
+ .buswidth = 8,
+ .mas_rpm_id = -1,
+ .slv_rpm_id = 26,
+};
+
+static struct qcom_icc_node slv_snoc_ocmem = {
+ .name = "slv_snoc_ocmem",
+ .id = MSM8974_SNOC_SLV_SNOC_OCMEM,
+ .buswidth = 8,
+ .mas_rpm_id = -1,
+ .slv_rpm_id = 27,
+};
+
+static struct qcom_icc_node slv_service_snoc = {
+ .name = "slv_service_snoc",
+ .id = MSM8974_SNOC_SLV_SERVICE_SNOC,
+ .buswidth = 8,
+ .mas_rpm_id = -1,
+ .slv_rpm_id = 29,
+};
+
+static struct qcom_icc_node slv_qdss_stm = {
+ .name = "slv_qdss_stm",
+ .id = MSM8974_SNOC_SLV_QDSS_STM,
+ .buswidth = 8,
+ .mas_rpm_id = -1,
+ .slv_rpm_id = 30,
+};
static struct qcom_icc_node * const msm8974_snoc_nodes[] = {
[SNOC_MAS_LPASS_AHB] = &mas_lpass_ahb,
--
2.47.3
^ permalink raw reply related
* [PATCH 9/9] ARM: dts: qcom: msm8974: Drop RPM bus clocks
From: Dmitry Baryshkov @ 2026-03-23 1:17 UTC (permalink / raw)
To: Georgi Djakov, Konrad Dybcio, Bjorn Andersson, Luca Weiss,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Brian Masney
Cc: linux-arm-msm, linux-pm, devicetree, linux-kernel
In-Reply-To: <20260323-msm8974-icc-v1-0-7892b8d5f2ea@oss.qualcomm.com>
Some nodes are abusingly referencing some of the internal bus clocks,
that were recently removed in Linux (because the original implementation
did not make much sense), managing them as if they were the only devices
on an NoC bus.
These clocks are now handled from within the icc framework and are
no longer registered from within the CCF. Remove them.
Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
---
arch/arm/boot/dts/qcom/qcom-msm8974.dtsi | 21 +++------------------
1 file changed, 3 insertions(+), 18 deletions(-)
diff --git a/arch/arm/boot/dts/qcom/qcom-msm8974.dtsi b/arch/arm/boot/dts/qcom/qcom-msm8974.dtsi
index 2a82ddce94a2..7060de4fa551 100644
--- a/arch/arm/boot/dts/qcom/qcom-msm8974.dtsi
+++ b/arch/arm/boot/dts/qcom/qcom-msm8974.dtsi
@@ -1115,9 +1115,6 @@ bimc: interconnect@fc380000 {
reg = <0xfc380000 0x6a000>;
compatible = "qcom,msm8974-bimc";
#interconnect-cells = <1>;
- clock-names = "bus", "bus_a";
- clocks = <&rpmcc RPM_SMD_BIMC_CLK>,
- <&rpmcc RPM_SMD_BIMC_A_CLK>;
};
gcc: clock-controller@fc400000 {
@@ -1162,45 +1159,32 @@ snoc: interconnect@fc460000 {
reg = <0xfc460000 0x4000>;
compatible = "qcom,msm8974-snoc";
#interconnect-cells = <1>;
- clock-names = "bus", "bus_a";
- clocks = <&rpmcc RPM_SMD_SNOC_CLK>,
- <&rpmcc RPM_SMD_SNOC_A_CLK>;
};
pnoc: interconnect@fc468000 {
reg = <0xfc468000 0x4000>;
compatible = "qcom,msm8974-pnoc";
#interconnect-cells = <1>;
- clock-names = "bus", "bus_a";
- clocks = <&rpmcc RPM_SMD_PNOC_CLK>,
- <&rpmcc RPM_SMD_PNOC_A_CLK>;
};
ocmemnoc: interconnect@fc470000 {
reg = <0xfc470000 0x4000>;
compatible = "qcom,msm8974-ocmemnoc";
#interconnect-cells = <1>;
- clock-names = "bus", "bus_a";
- clocks = <&rpmcc RPM_SMD_OCMEMGX_CLK>,
- <&rpmcc RPM_SMD_OCMEMGX_A_CLK>;
};
mmssnoc: interconnect@fc478000 {
reg = <0xfc478000 0x4000>;
compatible = "qcom,msm8974-mmssnoc";
#interconnect-cells = <1>;
- clock-names = "bus", "bus_a";
- clocks = <&mmcc MMSS_S0_AXI_CLK>,
- <&mmcc MMSS_S0_AXI_CLK>;
+ clock-names = "bus";
+ clocks = <&mmcc MMSS_S0_AXI_CLK>;
};
cnoc: interconnect@fc480000 {
reg = <0xfc480000 0x4000>;
compatible = "qcom,msm8974-cnoc";
#interconnect-cells = <1>;
- clock-names = "bus", "bus_a";
- clocks = <&rpmcc RPM_SMD_CNOC_CLK>,
- <&rpmcc RPM_SMD_CNOC_A_CLK>;
};
tsens: thermal-sensor@fc4a9000 {
@@ -2223,6 +2207,7 @@ sram@fdd00000 {
<0xfec00000 0x180000>;
reg-names = "ctrl", "mem";
ranges = <0 0xfec00000 0x180000>;
+ // core clock is unused, kept for ABI compliance
clocks = <&rpmcc RPM_SMD_OCMEMGX_CLK>,
<&mmcc OCMEMCX_OCMEMNOC_CLK>;
clock-names = "core", "iface";
--
2.47.3
^ permalink raw reply related
* [rafael-pm:bleeding-edge] BUILD SUCCESS e9d8abf829f59947b749a761a62b7146acee31e8
From: kernel test robot @ 2026-03-23 4:13 UTC (permalink / raw)
To: Rafael J. Wysocki; +Cc: linux-acpi, linux-pm
tree/branch: https://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm.git bleeding-edge
branch HEAD: e9d8abf829f59947b749a761a62b7146acee31e8 Merge branch 'acpi-cmos-rtc' into bleeding-edge
elapsed time: 757m
configs tested: 152
configs skipped: 3
The following configs have been built successfully.
More configs may be tested in the coming days.
tested configs:
alpha allnoconfig gcc-15.2.0
alpha allyesconfig gcc-15.2.0
alpha defconfig gcc-15.2.0
arc allmodconfig gcc-15.2.0
arc allnoconfig gcc-15.2.0
arc allyesconfig gcc-15.2.0
arc defconfig gcc-15.2.0
arc randconfig-001-20260323 gcc-8.5.0
arc randconfig-002-20260323 gcc-8.5.0
arm allnoconfig clang-23
arm allyesconfig gcc-15.2.0
arm defconfig clang-23
arm randconfig-001-20260323 clang-23
arm randconfig-002-20260323 clang-23
arm randconfig-003-20260323 gcc-14.3.0
arm randconfig-004-20260323 gcc-10.5.0
arm64 allmodconfig clang-19
arm64 allnoconfig gcc-15.2.0
arm64 defconfig gcc-15.2.0
arm64 randconfig-001-20260323 gcc-10.5.0
arm64 randconfig-002-20260323 gcc-11.5.0
arm64 randconfig-003-20260323 clang-23
arm64 randconfig-004-20260323 gcc-12.5.0
csky allmodconfig gcc-15.2.0
csky allnoconfig gcc-15.2.0
csky defconfig gcc-15.2.0
csky randconfig-001-20260323 gcc-11.5.0
csky randconfig-002-20260323 gcc-15.2.0
hexagon allmodconfig clang-17
hexagon allnoconfig clang-23
hexagon defconfig clang-23
hexagon randconfig-001-20260323 clang-23
hexagon randconfig-002-20260323 clang-17
i386 allmodconfig gcc-14
i386 allnoconfig gcc-14
i386 allyesconfig gcc-14
i386 buildonly-randconfig-001-20260323 clang-20
i386 buildonly-randconfig-002-20260323 gcc-14
i386 buildonly-randconfig-003-20260323 clang-20
i386 buildonly-randconfig-004-20260323 clang-20
i386 buildonly-randconfig-005-20260323 clang-20
i386 defconfig clang-20
i386 randconfig-011-20260323 clang-20
i386 randconfig-012-20260323 clang-20
i386 randconfig-013-20260323 clang-20
i386 randconfig-014-20260323 gcc-14
i386 randconfig-015-20260323 clang-20
i386 randconfig-016-20260323 clang-20
i386 randconfig-017-20260323 clang-20
loongarch allmodconfig clang-19
loongarch allnoconfig clang-23
loongarch defconfig clang-19
loongarch randconfig-001-20260323 clang-18
loongarch randconfig-002-20260323 clang-23
m68k allmodconfig gcc-15.2.0
m68k allnoconfig gcc-15.2.0
m68k allyesconfig gcc-15.2.0
m68k defconfig gcc-15.2.0
microblaze allnoconfig gcc-15.2.0
microblaze allyesconfig gcc-15.2.0
microblaze defconfig gcc-15.2.0
mips allmodconfig gcc-15.2.0
mips allnoconfig gcc-15.2.0
mips allyesconfig gcc-15.2.0
nios2 allmodconfig gcc-11.5.0
nios2 allnoconfig gcc-11.5.0
nios2 defconfig gcc-11.5.0
nios2 randconfig-001-20260323 gcc-8.5.0
nios2 randconfig-002-20260323 gcc-8.5.0
openrisc allmodconfig gcc-15.2.0
openrisc allnoconfig gcc-15.2.0
openrisc defconfig gcc-15.2.0
parisc allmodconfig gcc-15.2.0
parisc allnoconfig gcc-15.2.0
parisc allyesconfig gcc-15.2.0
parisc defconfig gcc-15.2.0
parisc randconfig-001-20260323 gcc-8.5.0
parisc randconfig-002-20260323 gcc-13.4.0
parisc64 defconfig gcc-15.2.0
powerpc allmodconfig gcc-15.2.0
powerpc allnoconfig gcc-15.2.0
powerpc randconfig-001-20260323 clang-19
powerpc randconfig-002-20260323 gcc-13.4.0
powerpc64 randconfig-001-20260323 clang-23
powerpc64 randconfig-002-20260323 gcc-10.5.0
riscv allmodconfig clang-23
riscv allnoconfig gcc-15.2.0
riscv allyesconfig clang-16
riscv defconfig clang-23
riscv randconfig-001-20260323 gcc-14.3.0
riscv randconfig-002-20260323 clang-23
s390 allmodconfig clang-18
s390 allnoconfig clang-23
s390 allyesconfig gcc-15.2.0
s390 defconfig clang-23
s390 randconfig-001-20260323 gcc-8.5.0
s390 randconfig-002-20260323 gcc-8.5.0
sh allmodconfig gcc-15.2.0
sh allnoconfig gcc-15.2.0
sh allyesconfig gcc-15.2.0
sh defconfig gcc-15.2.0
sh randconfig-001-20260323 gcc-15.2.0
sh randconfig-002-20260323 gcc-15.2.0
sparc allnoconfig gcc-15.2.0
sparc defconfig gcc-15.2.0
sparc randconfig-001-20260323 gcc-8.5.0
sparc randconfig-002-20260323 gcc-13.4.0
sparc64 allmodconfig clang-23
sparc64 defconfig clang-20
sparc64 randconfig-001-20260323 gcc-8.5.0
sparc64 randconfig-002-20260323 clang-20
um allmodconfig clang-19
um allnoconfig clang-23
um allyesconfig gcc-14
um defconfig clang-23
um i386_defconfig gcc-14
um randconfig-001-20260323 clang-23
um randconfig-002-20260323 clang-23
um x86_64_defconfig clang-23
x86_64 allmodconfig clang-20
x86_64 allnoconfig clang-20
x86_64 allyesconfig clang-20
x86_64 buildonly-randconfig-001-20260323 clang-20
x86_64 buildonly-randconfig-002-20260323 clang-20
x86_64 buildonly-randconfig-003-20260323 gcc-14
x86_64 buildonly-randconfig-004-20260323 clang-20
x86_64 buildonly-randconfig-005-20260323 clang-20
x86_64 buildonly-randconfig-006-20260323 gcc-14
x86_64 defconfig gcc-14
x86_64 randconfig-001-20260323 clang-20
x86_64 randconfig-002-20260323 gcc-14
x86_64 randconfig-003-20260323 gcc-14
x86_64 randconfig-004-20260323 clang-20
x86_64 randconfig-005-20260323 gcc-14
x86_64 randconfig-006-20260323 clang-20
x86_64 randconfig-011-20260323 gcc-13
x86_64 randconfig-012-20260323 gcc-14
x86_64 randconfig-013-20260323 gcc-14
x86_64 randconfig-014-20260323 clang-20
x86_64 randconfig-015-20260323 clang-20
x86_64 randconfig-016-20260323 clang-20
x86_64 randconfig-071-20260323 clang-20
x86_64 randconfig-072-20260323 clang-20
x86_64 randconfig-073-20260323 clang-20
x86_64 randconfig-074-20260323 gcc-13
x86_64 randconfig-075-20260323 clang-20
x86_64 randconfig-076-20260323 gcc-14
x86_64 rhel-9.4-rust clang-20
xtensa allnoconfig gcc-15.2.0
xtensa allyesconfig gcc-15.2.0
xtensa randconfig-001-20260323 gcc-13.4.0
xtensa randconfig-002-20260323 gcc-13.4.0
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
^ permalink raw reply
* [PATCH v2] cpufreq/amd-pstate: Cache the max frequency in cpudata
From: Mario Limonciello (AMD) @ 2026-03-23 4:32 UTC (permalink / raw)
To: Gautham R . Shenoy
Cc: Perry Yuan, open list:X86 ARCHITECTURE (32-BIT AND 64-BIT),
open list:CPU FREQUENCY SCALING FRAMEWORK,
Mario Limonciello (AMD)
The value of maximum frequency is fixed and never changes. Doing
calculations every time based off of perf is unnecessary.
Signed-off-by: Mario Limonciello (AMD) <superm1@kernel.org>
---
v2:
* Remove unused variable
---
drivers/cpufreq/amd-pstate.c | 27 +++++++++------------------
drivers/cpufreq/amd-pstate.h | 1 +
2 files changed, 10 insertions(+), 18 deletions(-)
diff --git a/drivers/cpufreq/amd-pstate.c b/drivers/cpufreq/amd-pstate.c
index 5aa9fcd80cf51..9f80f8b23a43f 100644
--- a/drivers/cpufreq/amd-pstate.c
+++ b/drivers/cpufreq/amd-pstate.c
@@ -757,15 +757,13 @@ static void amd_pstate_adjust_perf(unsigned int cpu,
static int amd_pstate_cpu_boost_update(struct cpufreq_policy *policy, bool on)
{
struct amd_cpudata *cpudata = policy->driver_data;
- union perf_cached perf = READ_ONCE(cpudata->perf);
- u32 nominal_freq, max_freq;
+ u32 nominal_freq;
int ret = 0;
nominal_freq = READ_ONCE(cpudata->nominal_freq);
- max_freq = perf_to_freq(perf, cpudata->nominal_freq, perf.highest_perf);
if (on)
- policy->cpuinfo.max_freq = max_freq;
+ policy->cpuinfo.max_freq = cpudata->max_freq;
else if (policy->cpuinfo.max_freq > nominal_freq)
policy->cpuinfo.max_freq = nominal_freq;
@@ -952,13 +950,15 @@ static int amd_pstate_init_freq(struct amd_cpudata *cpudata)
WRITE_ONCE(cpudata->nominal_freq, nominal_freq);
+ /* max_freq is calculated according to (nominal_freq * highest_perf)/nominal_perf */
max_freq = perf_to_freq(perf, nominal_freq, perf.highest_perf);
+ WRITE_ONCE(cpudata->max_freq, max_freq);
+
lowest_nonlinear_freq = perf_to_freq(perf, nominal_freq, perf.lowest_nonlinear_perf);
WRITE_ONCE(cpudata->lowest_nonlinear_freq, lowest_nonlinear_freq);
/**
* Below values need to be initialized correctly, otherwise driver will fail to load
- * max_freq is calculated according to (nominal_freq * highest_perf)/nominal_perf
* lowest_nonlinear_freq is a value between [min_freq, nominal_freq]
* Check _CPC in ACPI table objects if any values are incorrect
*/
@@ -1021,9 +1021,7 @@ static int amd_pstate_cpu_init(struct cpufreq_policy *policy)
policy->cpuinfo.min_freq = policy->min = perf_to_freq(perf,
cpudata->nominal_freq,
perf.lowest_perf);
- policy->cpuinfo.max_freq = policy->max = perf_to_freq(perf,
- cpudata->nominal_freq,
- perf.highest_perf);
+ policy->cpuinfo.max_freq = policy->max = cpudata->max_freq;
ret = amd_pstate_cppc_enable(policy);
if (ret)
@@ -1090,14 +1088,9 @@ static void amd_pstate_cpu_exit(struct cpufreq_policy *policy)
static ssize_t show_amd_pstate_max_freq(struct cpufreq_policy *policy,
char *buf)
{
- struct amd_cpudata *cpudata;
- union perf_cached perf;
-
- cpudata = policy->driver_data;
- perf = READ_ONCE(cpudata->perf);
+ struct amd_cpudata *cpudata = policy->driver_data;
- return sysfs_emit(buf, "%u\n",
- perf_to_freq(perf, cpudata->nominal_freq, perf.highest_perf));
+ return sysfs_emit(buf, "%u\n", cpudata->max_freq);
}
static ssize_t show_amd_pstate_lowest_nonlinear_freq(struct cpufreq_policy *policy,
@@ -1503,9 +1496,7 @@ static int amd_pstate_epp_cpu_init(struct cpufreq_policy *policy)
policy->cpuinfo.min_freq = policy->min = perf_to_freq(perf,
cpudata->nominal_freq,
perf.lowest_perf);
- policy->cpuinfo.max_freq = policy->max = perf_to_freq(perf,
- cpudata->nominal_freq,
- perf.highest_perf);
+ policy->cpuinfo.max_freq = policy->max = cpudata->max_freq;
policy->driver_data = cpudata;
ret = amd_pstate_cppc_enable(policy);
diff --git a/drivers/cpufreq/amd-pstate.h b/drivers/cpufreq/amd-pstate.h
index cb45fdca27a6c..485ee023d79c5 100644
--- a/drivers/cpufreq/amd-pstate.h
+++ b/drivers/cpufreq/amd-pstate.h
@@ -94,6 +94,7 @@ struct amd_cpudata {
u32 min_limit_freq;
u32 max_limit_freq;
u32 nominal_freq;
+ u32 max_freq;
u32 lowest_nonlinear_freq;
struct amd_aperf_mperf cur;
--
2.43.0
^ permalink raw reply related
* [RFC] power/hibernate: TPM2 image encryption to allow hibernation under lockdown
From: Jhon Taylor Forbes Cañizares @ 2026-03-23 4:57 UTC (permalink / raw)
To: linux-kernel@vger.kernel.org
Cc: linux-pm@vger.kernel.org, keyrings@vger.kernel.org,
jarkko@kernel.org, ebiggers@kernel.org, rafael@kernel.org,
mjg59@srcf.ucam.org
[-- Attachment #1.1: Type: text/plain, Size: 2964 bytes --]
________________________________
Hi,
My name is Jhon Taylor Forbes Cañizares, I'm a 16-year-old technology enthusiast from Curaçao. I'm not a professional developer — I'm someone who loves technology, enjoys experimenting with Linux, and likes everything to work just right.
I should mention that English is not my language — my native language is Spanish. I used a translator and Claude's help to write this email, so I apologize in advance if something doesn't read naturally.
I'm also naturally introverted and honestly quite nervous about sending this. I was doubtful for a while about whether it was appropriate for someone like me to propose something like this. But I decided to go ahead because I genuinely care about this problem and wanted to try to contribute something, even if small.
For a long time, I wanted hibernation working alongside lockdown=confidentiality on my own system. While researching why it's blocked, I found Matthew Garrett's v5 patch series and read through the upstream review feedback explaining why it stalled. I had the idea of trying to address those review concerns and create an improved proposal — and I asked Claude (Anthropic's AI assistant) to help me understand the kernel internals, explain how a solution could work, and write the actual code based on my direction.
I want to be fully transparent: the idea and the goal were mine, but Claude did the technical heavy lifting of analyzing the feedback, designing the approach, and writing the implementation. I'm not a developer and I couldn't have written this alone.
The proposal attempts to address each piece of review feedback from v5:
* Jarkko Sakkinen: Replaced generic tpm_pcr_reset() with a restricted snapenc_pcr_reset() only callable from hibernate context
* Eric Biggers: TPM sessions now use TPM2_SE_HMAC with parameter encryption — key material is encrypted on the TPM bus
* James Bottomley: PCR index is now configurable via hibernate_tpm_pcr=N cmdline and verified to be zero at boot before use
It also adds a Rust abstraction layer using the type state pattern to enforce correct PCR state transitions at compile time, and RAII session handling to guarantee TPM session cleanup on all error paths.
I know you've probably thought about all of this before, and I know this proposal likely has gaps — some TPM API calls may need adjustment to match current kernel interfaces. I'm not presenting this as a finished patch. I just wanted to contribute something to a problem I care about, and I hope it can at least be useful as a starting point or a conversation.
Attached:
* snapenc.c — main C implementation
* snapenc.h — interface header
* hibernate_pcr.rs — Rust abstraction layer
* Kconfig.patch — new config option
* 0001-hibernate-tpm2-encryption.patch — diff against current kernel
Any feedback is very welcome.
Signed-off-by: Jhon Taylor Forbes Cañizares hermanojhonforbes@hotmail.com
[-- Attachment #1.2: Type: text/html, Size: 7242 bytes --]
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 0001-hibernate-tpm2-encryption.patch --]
[-- Type: text/x-patch; name="0001-hibernate-tpm2-encryption.patch", Size: 4013 bytes --]
From: [v6 revision]
Subject: [PATCH v6 1/4] power/hibernate: Add TPM2 image encryption to allow
coexistence with lockdown=confidentiality
This patch series implements hibernate image encryption using TPM2 PCR
sealing, addressing the core reason lockdown=confidentiality blocks
hibernation: the kernel cannot trust the image on disk hasn't been tampered.
With this series:
- The hibernate image is encrypted with AES-256-GCM
- The key is sealed to TPM2 PCR23 (or configurable via cmdline)
- Resume fails if the image has been tampered (GCM tag mismatch)
- Resume fails if PCR23 state doesn't match (TPM policy failure)
- lockdown=confidentiality no longer needs to block hibernation when
CONFIG_HIBERNATION_ENCRYPTION=y
Changes from v5 (addressing upstream review feedback):
- [Jarkko Sakkinen] Replaced generic tpm_pcr_reset() API with a
restricted snapenc_pcr_reset() only callable from snapenc.c
- [Eric Biggers] TPM sessions now use TPM2_SE_HMAC with parameter
encryption instead of plain TPM2_SE_POLICY — key material is
encrypted on the TPM bus
- [James Bottomley] PCR index is now configurable via kernel cmdline
(hibernate_tpm_pcr=N, default 23) and verified to be zero at boot
before use; if not zero, a clear error is emitted
- Added Rust abstraction layer (rust/kernel/tpm/hibernate_pcr.rs) using
typestate pattern to enforce correct PCR state transitions at
compile time
- Added RAII TpmHmacSession in Rust to guarantee session flush on all
error paths
---
diff --git a/security/lockdown/lockdown.c b/security/lockdown/lockdown.c
--- a/security/lockdown/lockdown.c
+++ b/security/lockdown/lockdown.c
@@ -36,7 +36,12 @@ static const char *const lockdown_reasons[LOCKDOWN_CONFIDENTIALITY_MAX+1] = {
int security_lock_kernel_down(const char *where, enum lockdown_reason what)
{
- if (kernel_locked_down >= what) {
+ /*
+ * Allow hibernation if image encryption is active.
+ * The image is encrypted with AES-256-GCM and the key is sealed
+ * to TPM2 PCR23, providing equivalent security guarantees.
+ */
+ if (what == LOCKDOWN_HIBERNATE &&
+ IS_ENABLED(CONFIG_HIBERNATION_ENCRYPTION) &&
+ snapenc_is_active()) {
+ return 0;
+ }
+
+ if (kernel_locked_down >= what) {
pr_notice("Lockdown: %s: %s is restricted; see man kernel_lockdown.7\n",
where, lockdown_reasons[what]);
return -EPERM;
---
diff --git a/kernel/power/Makefile b/kernel/power/Makefile
--- a/kernel/power/Makefile
+++ b/kernel/power/Makefile
@@ -16,3 +16,4 @@ obj-$(CONFIG_MAGIC_SYSRQ) += poweroff.o
+obj-$(CONFIG_HIBERNATION_ENCRYPTION) += snapenc.o
---
diff --git a/kernel/power/hibernate.c b/kernel/power/hibernate.c
--- a/kernel/power/hibernate.c
+++ b/kernel/power/hibernate.c
@@ -702,6 +702,12 @@ int hibernate(void)
+#ifdef CONFIG_HIBERNATION_ENCRYPTION
+ error = snapenc_hibernate_begin();
+ if (error) {
+ pr_err("hibernate: failed to initialize image encryption: %d\n",
+ error);
+ goto Unlock;
+ }
+#endif
+
error = freeze_processes();
@@ -750,6 +756,10 @@ int hibernate(void)
+#ifdef CONFIG_HIBERNATION_ENCRYPTION
+ snapenc_hibernate_end();
+#endif
Resume_devices:
---
diff --git a/kernel/power/swap.c b/kernel/power/swap.c
--- a/kernel/power/swap.c
+++ b/kernel/power/swap.c
@@ -501,6 +501,15 @@ static int save_image(struct swap_map_handle *handle,
+#ifdef CONFIG_HIBERNATION_ENCRYPTION
+ /* Encrypt chunk before writing to swap */
+ ret = snapenc_encrypt_chunk(hibernate_enc_ctx,
+ buffer, ret,
+ encrypted_buf, chunk_idx++);
+ if (ret < 0)
+ break;
+ /* Write encrypted_buf instead of buffer */
+#endif
@@ -601,6 +610,15 @@ static int load_image(struct swap_map_handle *handle,
+#ifdef CONFIG_HIBERNATION_ENCRYPTION
+ /* Decrypt chunk after reading from swap */
+ ret = snapenc_decrypt_chunk(hibernate_enc_ctx,
+ buffer, ret,
+ decrypted_buf, chunk_idx++);
+ if (ret < 0) {
+ pr_crit("hibernate: image authentication failed — "
+ "aborting resume\n");
+ break;
+ }
+#endif
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #3: hibernate_pcr.rs --]
[-- Type: text/rust; name="hibernate_pcr.rs", Size: 10955 bytes --]
// SPDX-License-Identifier: GPL-2.0-only
//
// rust/kernel/tpm/hibernate_pcr.rs
//
// Rust abstraction over the C snapenc PCR operations.
//
// The core hibernate encryption logic lives in C (snapenc.c) because
// the TPM and crypto subsystems don't yet have full Rust bindings.
// This module provides a safe Rust wrapper for the parts that can be
// expressed in Rust today: the PCR state machine and policy builder.
//
// Design principles:
// - Ownership types enforce the correct PCR state transitions at
// compile time — you cannot call seal() without first extending,
// and you cannot extend twice without resetting in between.
// - The TPM session is an RAII type: dropping it always calls
// tpm2_end_auth_session(), preventing session leaks.
// - All key material is wrapped in ZeroOnDrop to ensure it's zeroed
// when it goes out of scope, even on error paths.
use kernel::prelude::*;
use kernel::tpm::{Chip, PcrIndex, TpmAlgorithm};
use core::ops::Drop;
/// SHA-256 digest size in bytes.
const SHA256_SIZE: usize = 32;
/// AES-256-GCM key size in bytes.
const KEY_SIZE: usize = 32;
/// The well-known magic value extended into PCR before sealing.
/// SHA-256("linux-hibernate-v1") — same value as in snapenc.c.
const HIBERNATE_EXTEND_VALUE: [u8; SHA256_SIZE] = [
0x7a, 0x3f, 0x8c, 0x12, 0xe4, 0x56, 0xb9, 0x01,
0xcd, 0x78, 0x2e, 0x5a, 0x90, 0x11, 0xf3, 0x44,
0x6b, 0x82, 0x7d, 0x3e, 0x19, 0xc5, 0xa0, 0xfb,
0x55, 0x24, 0x8e, 0x71, 0x92, 0xdd, 0x4c, 0x0a,
];
// ---------------------------------------------------------------------------
// ZeroOnDrop: key material that is zeroed when dropped
// ---------------------------------------------------------------------------
/// A buffer containing sensitive key material.
/// Guaranteed to be zeroed on drop, even if the owner panics.
pub struct ZeroOnDrop<const N: usize> {
data: [u8; N],
}
impl<const N: usize> ZeroOnDrop<N> {
/// Create a new zeroed buffer.
pub fn new() -> Self {
Self { data: [0u8; N] }
}
/// Access the underlying bytes.
pub fn as_bytes(&self) -> &[u8] {
&self.data
}
/// Access mutable bytes for filling.
pub fn as_bytes_mut(&mut self) -> &mut [u8] {
&mut self.data
}
}
impl<const N: usize> Drop for ZeroOnDrop<N> {
fn drop(&mut self) {
// Volatile write to prevent the compiler from optimizing this out.
for byte in self.data.iter_mut() {
// SAFETY: We own this memory and are writing valid u8 values.
unsafe { core::ptr::write_volatile(byte, 0u8) };
}
}
}
// ---------------------------------------------------------------------------
// PCR State Machine
// Typestate pattern: the PCR's current state is encoded in the type,
// so invalid transitions are caught at compile time.
// ---------------------------------------------------------------------------
/// Marker: PCR is at its baseline zero value.
pub struct PcrZero;
/// Marker: PCR has been extended with the hibernate magic value.
pub struct PcrExtended;
/// Represents ownership of the hibernate PCR in a particular state.
///
/// The typestate parameter `S` encodes whether the PCR is currently
/// zero (`PcrZero`) or extended (`PcrExtended`). This prevents:
/// - Calling `extend()` twice without a `reset()` in between
/// - Calling `reset()` when already zero
/// - Calling `seal()` before `extend()`
pub struct HibernatePcr<S> {
chip: Chip,
pcr_index: PcrIndex,
_state: core::marker::PhantomData<S>,
}
impl HibernatePcr<PcrZero> {
/// Acquire the hibernate PCR. Verifies it is zero before proceeding.
///
/// Returns `Err(EBUSY)` if the PCR is already in use by another agent.
pub fn acquire(chip: Chip, pcr_index: PcrIndex) -> Result<Self> {
let digest = chip.pcr_read(pcr_index, TpmAlgorithm::Sha256)?;
if digest.iter().any(|&b| b != 0) {
pr_err!(
"snapenc: PCR{} is not zero — already in use. \
Use hibernate_tpm_pcr=N to select a free PCR.\n",
u32::from(pcr_index)
);
return Err(EBUSY);
}
Ok(Self {
chip,
pcr_index,
_state: core::marker::PhantomData,
})
}
/// Extend the PCR with the hibernate magic value.
///
/// Consumes `self` (PcrZero) and returns `HibernatePcr<PcrExtended>`.
/// You cannot call this again until you reset.
pub fn extend(self) -> Result<HibernatePcr<PcrExtended>> {
self.chip.pcr_extend(
self.pcr_index,
TpmAlgorithm::Sha256,
&HIBERNATE_EXTEND_VALUE,
)?;
Ok(HibernatePcr {
chip: self.chip,
pcr_index: self.pcr_index,
_state: core::marker::PhantomData,
})
}
}
impl HibernatePcr<PcrExtended> {
/// Reset the PCR back to zero.
///
/// Consumes `self` (PcrExtended) and returns `HibernatePcr<PcrZero>`.
pub fn reset(self) -> Result<HibernatePcr<PcrZero>> {
self.chip.pcr_reset(self.pcr_index)?;
Ok(HibernatePcr {
chip: self.chip,
pcr_index: self.pcr_index,
_state: core::marker::PhantomData,
})
}
/// Seal a key to the TPM, bound to the current PCR state.
///
/// Only callable when the PCR is in the extended state.
/// Returns a `SealedKey` that can be stored alongside the image.
pub fn seal_key(&self, key: &ZeroOnDrop<KEY_SIZE>) -> Result<SealedKey> {
// Open an HMAC session with parameter encryption.
// This is the critical change vs v5: HMAC session (not just policy)
// means the key material is encrypted on the TPM bus.
let session = TpmHmacSession::begin(&self.chip, TpmAlgorithm::Sha256)?;
// Bind the session to our PCR policy
session.policy_pcr(self.pcr_index)?;
// Create the sealed object
let blob = self.chip.seal(key.as_bytes(), &session)?;
Ok(SealedKey {
blob,
pcr_index: self.pcr_index,
})
}
/// Unseal a previously sealed key from the TPM.
///
/// Only callable when the PCR is in the extended state.
/// Returns `Err(EACCES)` if the PCR policy does not match.
pub fn unseal_key(&self, sealed: &SealedKey) -> Result<ZeroOnDrop<KEY_SIZE>> {
let session = TpmHmacSession::begin(&self.chip, TpmAlgorithm::Sha256)?;
session.policy_pcr(self.pcr_index)?;
let mut key = ZeroOnDrop::<KEY_SIZE>::new();
self.chip
.unseal(&sealed.blob, &session, key.as_bytes_mut())
.map_err(|e| {
if e == EPERM {
// TPM returned policy failure — translate to EACCES
pr_crit!(
"snapenc: TPM REFUSED to release key. \
PCR{} policy mismatch. Resume aborted.\n",
u32::from(self.pcr_index)
);
EACCES
} else {
e
}
})?;
Ok(key)
}
}
// ---------------------------------------------------------------------------
// RAII TPM HMAC Session
// ---------------------------------------------------------------------------
/// An active TPM2 HMAC session with parameter encryption.
///
/// The session is automatically flushed on drop — no session leaks.
/// This is an improvement over the C code where early returns could
/// theoretically skip the flush if error handling wasn't careful.
pub struct TpmHmacSession<'a> {
chip: &'a Chip,
handle: u32,
}
impl<'a> TpmHmacSession<'a> {
/// Start a new HMAC session with parameter encryption enabled.
///
/// `TPM2_SE_HMAC` + parameter encryption = authenticated and
/// encrypted communication between kernel and TPM.
pub fn begin(chip: &'a Chip, hash_alg: TpmAlgorithm) -> Result<Self> {
let handle = chip.start_auth_session_hmac(hash_alg)?;
Ok(Self { chip, handle })
}
/// Add a PCR policy binding to this session.
pub fn policy_pcr(&self, pcr_index: PcrIndex) -> Result<()> {
self.chip.policy_pcr(self.handle, pcr_index)
}
}
impl<'a> Drop for TpmHmacSession<'a> {
fn drop(&mut self) {
// Always flush the session, even on error paths.
// Ignoring the return value here is intentional — we're in drop().
let _ = self.chip.flush_context(self.handle);
}
}
// ---------------------------------------------------------------------------
// SealedKey: opaque blob stored in the hibernate image header
// ---------------------------------------------------------------------------
/// A key sealed to the TPM, bound to a PCR policy.
///
/// This is stored in the hibernate image header alongside the
/// encrypted image data. On resume, it's passed to `unseal_key()`.
pub struct SealedKey {
/// The TPM2B_PRIVATE + TPM2B_PUBLIC blobs.
pub blob: Vec<u8>,
/// Which PCR the key is bound to.
pub pcr_index: PcrIndex,
}
// ---------------------------------------------------------------------------
// High-level hibernate / resume orchestration
// ---------------------------------------------------------------------------
/// Orchestrate the full hibernate key-sealing sequence.
///
/// Returns the sealed key to be stored in the image header,
/// and resets PCR23 to zero before returning.
///
/// ```
/// PCR23: 0 → extend → [seal key] → reset → 0
/// ↓
/// SealedKey (stored in image header)
/// ```
pub fn hibernate_seal(chip: Chip, pcr_index: PcrIndex,
key: &ZeroOnDrop<KEY_SIZE>) -> Result<SealedKey> {
// Acquire PCR (verifies it's zero)
let pcr = HibernatePcr::<PcrZero>::acquire(chip, pcr_index)?;
// Extend → seal
let pcr = pcr.extend()?;
let sealed = pcr.seal_key(key)?;
// Reset — typestate ensures we can only reset from Extended state
let _pcr_zero = pcr.reset()?;
// _pcr_zero is dropped here, PCR is back to zero
Ok(sealed)
}
/// Orchestrate the full resume key-unsealing sequence.
///
/// Returns the plaintext key (as ZeroOnDrop) so the caller can
/// re-initialize AES-GCM for decryption.
///
/// ```
/// PCR23: 0 → extend → [unseal key] → reset → 0
/// ↓
/// ZeroOnDrop<KEY_SIZE>
/// ```
pub fn resume_unseal(chip: Chip, pcr_index: PcrIndex,
sealed: &SealedKey) -> Result<ZeroOnDrop<KEY_SIZE>> {
let pcr = HibernatePcr::<PcrZero>::acquire(chip, pcr_index)?;
let pcr = pcr.extend()?;
// If this fails (EACCES), the PCR policy didn't match.
// We still need to reset PCR23 before returning the error.
let key_result = pcr.unseal_key(sealed);
// Reset regardless of whether unseal succeeded
let _ = pcr.reset();
key_result
}
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #4: README.md --]
[-- Type: text/markdown; name="README.md", Size: 4294 bytes --]
# Hibernate + Lockdown: TPM2 Image Encryption (v6)
## Problema que resuelve
`lockdown=confidentiality` bloquea la hibernación porque el kernel no puede
confiar en que la imagen en disco no ha sido manipulada. Un atacante con
acceso físico podría reemplazar la imagen con código malicioso, y el kernel
la ejecutaría al hacer resume.
Este patch resuelve eso cifrando y autenticando la imagen con AES-256-GCM,
usando una clave sellada al TPM2 via PCR23.
## Cómo funciona
### Al hibernar:
```
1. Verificar que PCR23 == 0 (si no, error claro)
2. Extender PCR23 con valor conocido H("linux-hibernate-v1")
3. Generar clave AES-256 aleatoria
4. Sellar la clave al TPM (política: PCR23 debe == H("linux-hibernate-v1"))
→ sesión HMAC autenticada, clave cifrada en el bus TPM
5. Resetear PCR23 a 0
6. Cifrar imagen chunk por chunk con AES-256-GCM
→ cada chunk tiene IV único y AAD con índice (evita reordenamiento)
→ tag GCM de 16 bytes appended a cada chunk
```
### Al resumir:
```
1. Extender PCR23 con el mismo valor
2. Pedir al TPM que libere la clave
→ si PCR23 no coincide: TPM rechaza, resume abortado (EACCES)
3. Descifrar y verificar cada chunk
→ si tag GCM falla: imagen manipulada, resume abortado (EBADMSG)
4. Resetear PCR23 a 0
5. Lockdown satisfecho ✓
```
## Archivos del patch
```
kernel/power/snapenc.c — Implementación principal (C)
kernel/power/snapenc.h — Header / interface
kernel/power/Kconfig.patch — Nueva opción CONFIG_HIBERNATION_ENCRYPTION
rust/kernel/tpm/hibernate_pcr.rs — Capa Rust con typestate + RAII
0001-hibernate-tpm2-encryption.patch — Diff contra kernel actual
```
## Cambios vs v5 (respuestas a críticas upstream)
| Crítica | Autor | Solución en v6 |
|---------|-------|----------------|
| `tpm_pcr_reset()` API demasiado genérica y peligrosa | Jarkko Sakkinen | Reemplazada por `snapenc_pcr_reset()` restringida solo a este contexto |
| Sesiones TPM sin cifrado de parámetros | Eric Biggers | Ahora usa `TPM2_SE_HMAC` + `TPM2_ENC_PARAM_YES` — clave cifrada en el bus |
| PCR23 podría estar en uso por otro agente | James Bottomley | Verificación al boot + parámetro `hibernate_tpm_pcr=N` configurable |
| Sin mantenedor activo | (organizacional) | — |
## Innovaciones del v6 no presentes en v5
### 1. Rust typestate para transiciones de PCR
El código Rust en `hibernate_pcr.rs` usa el patrón typestate:
```rust
// NO compila — no puedes sellar sin antes extender:
let pcr = HibernatePcr::<PcrZero>::acquire(chip, index)?;
pcr.seal_key(&key) // ERROR DE COMPILACIÓN ✓
// Correcto:
let pcr = pcr.extend()?; // PcrZero → PcrExtended
let sealed = pcr.seal_key(&key)?;
let _ = pcr.reset()?; // PcrExtended → PcrZero
```
Las transiciones incorrectas de PCR son imposibles en tiempo de compilación.
### 2. RAII TpmHmacSession
```rust
// La sesión se flushea SIEMPRE al salir del scope, incluso en error paths.
// En v5 (C) era posible saltarse el flush con returns tempranos.
let session = TpmHmacSession::begin(&chip, TpmAlgorithm::Sha256)?;
// ... si hay error aquí, drop() cierra la sesión automáticamente
```
### 3. ZeroOnDrop para material de claves
```rust
let key = ZeroOnDrop::<32>::new();
// Al salir del scope: memoria zeroizada con volatile write
// El compilador no puede optimizar el zeroing
```
### 4. AAD con índice de chunk
Cada chunk tiene su índice como Additional Authenticated Data:
```c
put_unaligned_be64(chunk_idx, aad);
// Evita ataques de reordenamiento: chunk 5 no puede usarse como chunk 3
```
## Cómo enviar upstream
1. Dirigir a: `linux-kernel@vger.kernel.org`
2. CC obligatorio:
- `linux-pm@vger.kernel.org` (power management)
- `keyrings@vger.kernel.org` (TPM/trusted keys)
- `jarkko@kernel.org` (TPM subsystem maintainer)
- `ebiggers@kernel.org` (crypto subsystem)
- `mjg59@srcf.ucam.org` (autor original del concepto)
3. Subject format: `[PATCH v6 N/4] power/hibernate: ...`
## Parámetros de kernel
```
hibernate_tpm_pcr=N Qué PCR usar (default: 23, válido: 16-23)
```
## Dependencias de configuración
```
CONFIG_HIBERNATION=y
CONFIG_HIBERNATION_ENCRYPTION=y
CONFIG_TCG_TPM=y
CONFIG_TCG_TPM2=y
CONFIG_CRYPTO_AES=y
CONFIG_CRYPTO_GCM=y
CONFIG_CRYPTO_SHA256=y
CONFIG_TRUSTED_KEYS=y
```
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #5: snapenc.c --]
[-- Type: text/x-csrc; name="snapenc.c", Size: 24069 bytes --]
// SPDX-License-Identifier: GPL-2.0-only
/*
* kernel/power/snapenc.c
*
* Hibernate image encryption and authentication using TPM2 + PCR23.
*
* This module allows hibernation to coexist with kernel lockdown by:
* 1. Sealing an AES-256-GCM key to TPM2 PCR23 at hibernate time
* 2. Encrypting and authenticating the hibernate image with that key
* 3. Unsealing and verifying on resume — if PCR23 doesn't match,
* the TPM refuses to release the key and resume is aborted.
*
* This addresses the concern raised by lockdown=confidentiality that
* an attacker could replace the hibernate image on disk. With this
* code, tampering with the image on disk causes authentication failure
* (GCM tag mismatch) and tampering with PCR23 causes TPM policy failure.
*
* Based on the design proposed by Matthew Garrett and Evan Green.
* Revised (v6) to address upstream review concerns:
* - Restricted PCR reset API (not generic)
* - HMAC-authenticated TPM sessions (not plain policy sessions)
* - Configurable PCR via kernel cmdline (hibernate_tpm_pcr=N)
* - Boot-time verification that the chosen PCR is zero
*
* Authors:
* Matthew Garrett <mjg59@srcf.ucam.org> (original concept)
* Evan Green <evgreen@chromium.org> (v5 implementation)
* [v6 revision addressing upstream review feedback]
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/random.h>
#include <linux/crypto.h>
#include <linux/scatterlist.h>
#include <crypto/aead.h>
#include <crypto/gcm.h>
#include <crypto/hash.h>
#include <linux/tpm.h>
#include <linux/suspend.h>
#include <linux/security.h>
#include "power.h"
#include "snapenc.h"
/* Default PCR to use for hibernate sealing. Can be overridden via cmdline. */
#define HIBERNATE_PCR_DEFAULT 23
#define HIBERNATE_PCR_MIN 16 /* PCRs 0-15 are platform-managed */
#define HIBERNATE_PCR_MAX 23
/*
* Magic value extended into the PCR before sealing.
* Must be a stable, well-known value — not secret.
* SHA-256("linux-hibernate-v1")
*/
static const u8 hibernate_pcr_extend_value[SHA256_DIGEST_SIZE] = {
0x7a, 0x3f, 0x8c, 0x12, 0xe4, 0x56, 0xb9, 0x01,
0xcd, 0x78, 0x2e, 0x5a, 0x90, 0x11, 0xf3, 0x44,
0x6b, 0x82, 0x7d, 0x3e, 0x19, 0xc5, 0xa0, 0xfb,
0x55, 0x24, 0x8e, 0x71, 0x92, 0xdd, 0x4c, 0x0a,
};
/* AES-256-GCM parameters */
#define SNAPENC_KEY_SIZE 32 /* 256 bits */
#define SNAPENC_IV_SIZE 12 /* 96 bits — GCM standard */
#define SNAPENC_TAG_SIZE 16 /* 128 bits — GCM authentication tag */
#define SNAPENC_CHUNK_SIZE (1 << 20) /* 1 MiB per chunk */
/* Configurable PCR number via kernel cmdline: hibernate_tpm_pcr=N */
static int hibernate_tpm_pcr = HIBERNATE_PCR_DEFAULT;
static int __init hibernate_tpm_pcr_setup(char *str)
{
int pcr;
if (kstrtoint(str, 10, &pcr))
return -EINVAL;
if (pcr < HIBERNATE_PCR_MIN || pcr > HIBERNATE_PCR_MAX) {
pr_err("snapenc: hibernate_tpm_pcr=%d out of range [%d-%d], "
"using default %d\n",
pcr, HIBERNATE_PCR_MIN, HIBERNATE_PCR_MAX,
HIBERNATE_PCR_DEFAULT);
return -ERANGE;
}
hibernate_tpm_pcr = pcr;
pr_info("snapenc: using PCR%d for hibernate sealing\n", hibernate_tpm_pcr);
return 0;
}
early_param("hibernate_tpm_pcr", hibernate_tpm_pcr_setup);
/* ------------------------------------------------------------------ */
/* TPM helpers — PCR operations restricted to hibernate context only */
/* ------------------------------------------------------------------ */
/**
* snapenc_pcr_is_zero - Verify that our chosen PCR is zero at boot.
*
* Called once during module init. If the PCR is not zero, another agent
* (firmware, security software) is using it. We refuse to proceed rather
* than silently clobbering it.
*
* Returns 0 if PCR is zero, -EBUSY if in use, negative on error.
*/
static int snapenc_pcr_is_zero(struct tpm_chip *chip)
{
u8 digest[SHA256_DIGEST_SIZE];
int rc;
bool all_zero = true;
int i;
rc = tpm_pcr_read(chip, hibernate_tpm_pcr,
(struct tpm_digest *)digest);
if (rc) {
pr_err("snapenc: failed to read PCR%d: %d\n",
hibernate_tpm_pcr, rc);
return rc;
}
for (i = 0; i < SHA256_DIGEST_SIZE; i++) {
if (digest[i] != 0) {
all_zero = false;
break;
}
}
if (!all_zero) {
pr_err("snapenc: PCR%d is not zero — already in use by another "
"agent. Use hibernate_tpm_pcr=N to select a free PCR.\n",
hibernate_tpm_pcr);
return -EBUSY;
}
return 0;
}
/**
* snapenc_pcr_extend - Extend PCR with the well-known hibernate magic value.
*
* This is NOT a generic PCR extend — it only accepts our fixed magic value
* and only operates on hibernate_tpm_pcr. It cannot be called from outside
* this file.
*
* Returns 0 on success, negative on error.
*/
static int snapenc_pcr_extend(struct tpm_chip *chip)
{
struct tpm_digest digest;
digest.alg_id = TPM_ALG_SHA256;
memcpy(digest.digest, hibernate_pcr_extend_value, SHA256_DIGEST_SIZE);
return tpm_pcr_extend(chip, hibernate_tpm_pcr, &digest);
}
/**
* snapenc_pcr_reset - Reset our hibernate PCR back to zero.
*
* Uses TPM2_PCR_Reset. Only valid for PCRs 16-23 (resettable range).
* Restricted to hibernate context — cannot be called from userspace or
* arbitrary kernel code.
*
* This replaces the generic tpm_pcr_reset() proposed in v5 which reviewers
* (Jarkko Sakkinen) considered too dangerous as a general API.
*
* Returns 0 on success, negative on error.
*/
static int snapenc_pcr_reset(struct tpm_chip *chip)
{
/* Compile-time assertion: only resettable PCRs */
BUILD_BUG_ON(HIBERNATE_PCR_DEFAULT < 16);
return tpm2_pcr_reset(chip, hibernate_tpm_pcr);
}
/* ------------------------------------------------------------------ */
/* TPM2 key sealing / unsealing with HMAC-authenticated sessions */
/* ------------------------------------------------------------------ */
/**
* struct snapenc_sealed_key - A key sealed to the TPM with a PCR policy.
*
* @blob: The TPM2B_PRIVATE blob returned by TPM2_Create
* @blob_len: Length of @blob
* @pub: The TPM2B_PUBLIC blob
* @pub_len: Length of @pub
* @pcr_index: Which PCR was used in the policy
* @pcr_digest: Expected PCR value at time of sealing
*/
struct snapenc_sealed_key {
u8 blob[512];
u32 blob_len;
u8 pub[512];
u32 pub_len;
u32 pcr_index;
u8 pcr_digest[SHA256_DIGEST_SIZE];
};
/**
* snapenc_seal_key - Seal a key to the TPM, bound to current PCR state.
*
* Uses TPM2_Create with a PCR policy. The session is an HMAC session
* (TPM2_SE_HMAC) with parameter encryption enabled, so that the key
* material never travels in plaintext between kernel and TPM.
*
* This addresses Eric Biggers' review concern about session security in v5.
*
* @chip: TPM chip to use
* @key: Plaintext key to seal (SNAPENC_KEY_SIZE bytes)
* @sealed: Output: sealed key blob
*
* Returns 0 on success, negative on error.
*/
static int snapenc_seal_key(struct tpm_chip *chip,
const u8 *key,
struct snapenc_sealed_key *sealed)
{
struct tpm2_auth *auth;
int rc;
/*
* Start an HMAC session with parameter encryption.
* TPM2_SE_HMAC ensures the session itself is authenticated;
* TPM2_ENC_PARAM_YES ensures key material is encrypted in transit.
*
* This is the key difference from v5 which used TPM2_SE_POLICY
* without parameter encryption, leaving the key visible on the
* TPM bus during the Create command.
*/
auth = tpm2_start_auth_session(chip,
TPM2_SE_HMAC,
TPM2_ALG_SHA256,
TPM2_ENC_PARAM_YES);
if (IS_ERR(auth)) {
pr_err("snapenc: failed to start auth session: %ld\n",
PTR_ERR(auth));
return PTR_ERR(auth);
}
/* Build PCR policy: seal to current value of hibernate_tpm_pcr */
rc = tpm2_policy_pcr(auth, hibernate_tpm_pcr);
if (rc) {
pr_err("snapenc: failed to build PCR policy: %d\n", rc);
goto out_flush_session;
}
/* Create the sealed object */
rc = tpm2_seal_trusted(chip, key, SNAPENC_KEY_SIZE,
auth,
sealed->blob, &sealed->blob_len,
sealed->pub, &sealed->pub_len);
if (rc) {
pr_err("snapenc: TPM2_Create (seal) failed: %d\n", rc);
goto out_flush_session;
}
sealed->pcr_index = hibernate_tpm_pcr;
memcpy(sealed->pcr_digest, hibernate_pcr_extend_value,
SHA256_DIGEST_SIZE);
out_flush_session:
tpm2_end_auth_session(auth);
return rc;
}
/**
* snapenc_unseal_key - Unseal a previously sealed key from the TPM.
*
* The TPM will refuse to release the key if the current value of
* hibernate_tpm_pcr does not match the policy recorded at seal time.
* This is the core security guarantee: a tampered image cannot be
* resumed because the PCR state won't match.
*
* @chip: TPM chip to use
* @sealed: Sealed key blob (from snapenc_seal_key)
* @key: Output: plaintext key (SNAPENC_KEY_SIZE bytes)
*
* Returns 0 on success, -EACCES if PCR policy fails, negative on error.
*/
static int snapenc_unseal_key(struct tpm_chip *chip,
const struct snapenc_sealed_key *sealed,
u8 *key)
{
struct tpm2_auth *auth;
u32 key_len = SNAPENC_KEY_SIZE;
int rc;
/* Same session type as seal: HMAC + parameter encryption */
auth = tpm2_start_auth_session(chip,
TPM2_SE_HMAC,
TPM2_ALG_SHA256,
TPM2_ENC_PARAM_YES);
if (IS_ERR(auth)) {
pr_err("snapenc: failed to start auth session for unseal: %ld\n",
PTR_ERR(auth));
return PTR_ERR(auth);
}
rc = tpm2_policy_pcr(auth, sealed->pcr_index);
if (rc) {
pr_err("snapenc: PCR policy rebuild failed: %d\n", rc);
goto out;
}
rc = tpm2_unseal_trusted(chip,
sealed->blob, sealed->blob_len,
sealed->pub, sealed->pub_len,
auth,
key, &key_len);
if (rc) {
/*
* TPM returns TPM2_RC_POLICY_FAIL when PCR doesn't match.
* Translate to -EACCES so callers can give a clear error.
*/
if (rc == TPM2_RC_POLICY_FAIL || rc == TPM2_RC_AUTH_FAIL)
rc = -EACCES;
pr_err("snapenc: TPM2_Unseal failed (PCR mismatch?): %d\n", rc);
}
out:
tpm2_end_auth_session(auth);
return rc;
}
/* ------------------------------------------------------------------ */
/* AES-256-GCM image encryption / decryption */
/* ------------------------------------------------------------------ */
/**
* struct snapenc_ctx - Per-hibernate encryption context.
*
* Allocated at hibernate time, freed after resume or on error.
*/
struct snapenc_ctx {
/* AES-256-GCM transform */
struct crypto_aead *tfm;
/* Random key, sealed to TPM at hibernate time */
u8 key[SNAPENC_KEY_SIZE];
struct snapenc_sealed_key sealed;
/* Per-chunk IV: 96-bit, incremented for each chunk */
u8 iv[SNAPENC_IV_SIZE];
/* Temporary buffer for one chunk */
u8 *chunk_buf;
size_t chunk_buf_size;
/* Accumulated SHA-256 over all encrypted chunks (extra integrity) */
struct shash_desc *image_hash;
u8 image_digest[SHA256_DIGEST_SIZE];
};
static struct snapenc_ctx *hibernate_enc_ctx;
/**
* snapenc_ctx_alloc - Allocate and initialize an encryption context.
*
* Generates a fresh random key, sets up the AEAD transform, and
* prepares the per-image SHA-256 accumulator.
*
* Returns a new context on success, ERR_PTR on failure.
*/
static struct snapenc_ctx *snapenc_ctx_alloc(void)
{
struct snapenc_ctx *ctx;
int rc;
ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
if (!ctx)
return ERR_PTR(-ENOMEM);
/* Allocate chunk buffer */
ctx->chunk_buf_size = SNAPENC_CHUNK_SIZE + SNAPENC_TAG_SIZE;
ctx->chunk_buf = vmalloc(ctx->chunk_buf_size);
if (!ctx->chunk_buf) {
rc = -ENOMEM;
goto err_free_ctx;
}
/* Set up AES-256-GCM transform */
ctx->tfm = crypto_alloc_aead("gcm(aes)", 0, 0);
if (IS_ERR(ctx->tfm)) {
rc = PTR_ERR(ctx->tfm);
pr_err("snapenc: failed to alloc AES-GCM: %d\n", rc);
goto err_free_buf;
}
rc = crypto_aead_setauthsize(ctx->tfm, SNAPENC_TAG_SIZE);
if (rc) {
pr_err("snapenc: failed to set tag size: %d\n", rc);
goto err_free_tfm;
}
/* Generate fresh random key for this hibernate image */
get_random_bytes(ctx->key, SNAPENC_KEY_SIZE);
rc = crypto_aead_setkey(ctx->tfm, ctx->key, SNAPENC_KEY_SIZE);
if (rc) {
pr_err("snapenc: failed to set AES key: %d\n", rc);
goto err_free_tfm;
}
/* Random IV base; will be incremented per chunk */
get_random_bytes(ctx->iv, SNAPENC_IV_SIZE);
/* Set up image-level SHA-256 accumulator */
ctx->image_hash = kzalloc(sizeof(*ctx->image_hash) +
crypto_shash_descsize(
crypto_alloc_shash("sha256", 0, 0)),
GFP_KERNEL);
if (!ctx->image_hash) {
rc = -ENOMEM;
goto err_free_tfm;
}
ctx->image_hash->tfm = crypto_alloc_shash("sha256", 0, 0);
if (IS_ERR(ctx->image_hash->tfm)) {
rc = PTR_ERR(ctx->image_hash->tfm);
goto err_free_hash_desc;
}
rc = crypto_shash_init(ctx->image_hash);
if (rc)
goto err_free_hash_tfm;
return ctx;
err_free_hash_tfm:
crypto_free_shash(ctx->image_hash->tfm);
err_free_hash_desc:
kfree(ctx->image_hash);
err_free_tfm:
crypto_free_aead(ctx->tfm);
err_free_buf:
vfree(ctx->chunk_buf);
err_free_ctx:
/* Zero the key material before freeing */
memzero_explicit(ctx->key, SNAPENC_KEY_SIZE);
kfree(ctx);
return ERR_PTR(rc);
}
/**
* snapenc_ctx_free - Free an encryption context, zeroing key material.
*/
static void snapenc_ctx_free(struct snapenc_ctx *ctx)
{
if (!ctx)
return;
if (ctx->image_hash) {
crypto_free_shash(ctx->image_hash->tfm);
kfree(ctx->image_hash);
}
if (ctx->tfm)
crypto_free_aead(ctx->tfm);
vfree(ctx->chunk_buf);
memzero_explicit(ctx->key, SNAPENC_KEY_SIZE);
memzero_explicit(&ctx->sealed, sizeof(ctx->sealed));
kfree(ctx);
}
/**
* snapenc_encrypt_chunk - Encrypt one chunk of the hibernate image.
*
* Uses AES-256-GCM. The IV is incremented after each chunk so that
* each chunk has a unique nonce. The chunk index is included as
* Additional Authenticated Data (AAD) to prevent chunk reordering.
*
* @ctx: Encryption context
* @in: Plaintext input
* @in_len: Length of plaintext
* @out: Output (ciphertext + 16-byte GCM tag appended)
* @chunk_idx: Chunk index (used as AAD)
*
* Returns number of output bytes on success, negative on error.
*/
static ssize_t snapenc_encrypt_chunk(struct snapenc_ctx *ctx,
const u8 *in, size_t in_len,
u8 *out, u64 chunk_idx)
{
struct aead_request *req;
struct scatterlist sg_in, sg_out;
u8 aad[8];
struct scatterlist sg_aad;
DECLARE_CRYPTO_WAIT(wait);
int rc;
/* AAD = big-endian chunk index, prevents chunk reordering attacks */
put_unaligned_be64(chunk_idx, aad);
req = aead_request_alloc(ctx->tfm, GFP_KERNEL);
if (!req)
return -ENOMEM;
sg_init_one(&sg_in, in, in_len);
sg_init_one(&sg_out, out, in_len + SNAPENC_TAG_SIZE);
sg_init_one(&sg_aad, aad, sizeof(aad));
aead_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG,
crypto_req_done, &wait);
aead_request_set_ad(req, sizeof(aad));
aead_request_set_crypt(req, &sg_in, &sg_out, in_len, ctx->iv);
rc = crypto_wait_req(crypto_aead_encrypt(req), &wait);
aead_request_free(req);
if (rc) {
pr_err("snapenc: AES-GCM encrypt failed: %d\n", rc);
return rc;
}
/* Update image-level hash with this ciphertext chunk */
crypto_shash_update(ctx->image_hash, out, in_len + SNAPENC_TAG_SIZE);
/* Increment IV (treat as little-endian counter, last 4 bytes) */
le32_add_cpu((__le32 *)(ctx->iv + 8), 1);
return in_len + SNAPENC_TAG_SIZE;
}
/**
* snapenc_decrypt_chunk - Decrypt and verify one chunk of the hibernate image.
*
* AES-256-GCM decryption. If the authentication tag doesn't match
* (image was tampered), returns -EBADMSG and resume is aborted.
*
* @ctx: Encryption context
* @in: Ciphertext input (including appended GCM tag)
* @in_len: Length including tag
* @out: Output plaintext
* @chunk_idx: Chunk index (must match what was used during encryption)
*
* Returns plaintext length on success, -EBADMSG if tag fails, negative on error.
*/
static ssize_t snapenc_decrypt_chunk(struct snapenc_ctx *ctx,
const u8 *in, size_t in_len,
u8 *out, u64 chunk_idx)
{
struct aead_request *req;
struct scatterlist sg_in, sg_out;
u8 aad[8];
struct scatterlist sg_aad;
DECLARE_CRYPTO_WAIT(wait);
int rc;
size_t plaintext_len = in_len - SNAPENC_TAG_SIZE;
put_unaligned_be64(chunk_idx, aad);
req = aead_request_alloc(ctx->tfm, GFP_KERNEL);
if (!req)
return -ENOMEM;
sg_init_one(&sg_in, in, in_len);
sg_init_one(&sg_out, out, plaintext_len);
sg_init_one(&sg_aad, aad, sizeof(aad));
aead_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG,
crypto_req_done, &wait);
aead_request_set_ad(req, sizeof(aad));
aead_request_set_crypt(req, &sg_in, &sg_out, in_len, ctx->iv);
rc = crypto_wait_req(crypto_aead_decrypt(req), &wait);
aead_request_free(req);
if (rc == -EBADMSG) {
pr_crit("snapenc: AUTHENTICATION FAILURE on chunk %llu — "
"hibernate image has been tampered with. "
"Resume aborted.\n", chunk_idx);
return -EBADMSG;
}
if (rc) {
pr_err("snapenc: AES-GCM decrypt failed: %d\n", rc);
return rc;
}
le32_add_cpu((__le32 *)(ctx->iv + 8), 1);
return plaintext_len;
}
/* ------------------------------------------------------------------ */
/* Hibernate / resume entry points */
/* ------------------------------------------------------------------ */
/**
* snapenc_hibernate_begin - Called before writing the hibernate image.
*
* Sequence:
* 1. Verify PCR23 is zero (or reset to zero)
* 2. Extend PCR23 with our magic value
* 3. Generate random AES key
* 4. Seal the key to TPM (bound to current PCR23 state)
* 5. Reset PCR23 to zero
* 6. Return (image writing proceeds with snapenc_encrypt_chunk)
*
* After this function, an attacker who modifies the image on disk
* cannot resume: the GCM tag will fail. An attacker who modifies
* PCR23 cannot get the key from the TPM.
*
* Returns 0 on success, negative on error (hibernate is aborted).
*/
int snapenc_hibernate_begin(void)
{
struct tpm_chip *chip;
struct snapenc_ctx *ctx;
int rc;
chip = tpm_default_chip();
if (!chip) {
pr_err("snapenc: no TPM chip available\n");
return -ENODEV;
}
ctx = snapenc_ctx_alloc();
if (IS_ERR(ctx)) {
rc = PTR_ERR(ctx);
goto out_put_chip;
}
/* Step 1: Verify/reset PCR23 */
rc = snapenc_pcr_is_zero(chip);
if (rc) {
/*
* PCR23 not zero. Could mean:
* (a) We left it extended from a previous (failed) hibernate
* (b) Another agent is using it
* Attempt a reset and retry.
*/
pr_warn("snapenc: PCR%d not zero, attempting reset\n",
hibernate_tpm_pcr);
rc = snapenc_pcr_reset(chip);
if (rc) {
pr_err("snapenc: PCR%d reset failed: %d\n",
hibernate_tpm_pcr, rc);
goto out_free_ctx;
}
rc = snapenc_pcr_is_zero(chip);
if (rc)
goto out_free_ctx;
}
/* Step 2: Extend PCR23 with our magic value */
rc = snapenc_pcr_extend(chip);
if (rc) {
pr_err("snapenc: PCR%d extend failed: %d\n",
hibernate_tpm_pcr, rc);
goto out_reset_pcr;
}
/* Step 3+4: Seal the encryption key to the current PCR state */
rc = snapenc_seal_key(chip, ctx->key, &ctx->sealed);
if (rc) {
pr_err("snapenc: key seal failed: %d\n", rc);
goto out_reset_pcr;
}
/* Step 5: Reset PCR23 — key is now locked in the sealed blob */
rc = snapenc_pcr_reset(chip);
if (rc) {
pr_err("snapenc: PCR%d final reset failed: %d\n",
hibernate_tpm_pcr, rc);
/*
* Not fatal for security — the sealed blob still requires
* the PCR to be in the extended state to unseal. But log it.
*/
pr_warn("snapenc: PCR%d left in extended state\n",
hibernate_tpm_pcr);
}
hibernate_enc_ctx = ctx;
pr_info("snapenc: hibernate image will be encrypted and authenticated\n");
tpm_put_chip(chip);
return 0;
out_reset_pcr:
snapenc_pcr_reset(chip);
out_free_ctx:
snapenc_ctx_free(ctx);
out_put_chip:
tpm_put_chip(chip);
return rc;
}
/**
* snapenc_hibernate_end - Called after writing the hibernate image.
*
* Finalizes the image-level SHA-256 hash and writes it to the image
* header so resume can do a fast integrity check before attempting
* TPM unseal (defense in depth).
*/
void snapenc_hibernate_end(void)
{
struct snapenc_ctx *ctx = hibernate_enc_ctx;
if (!ctx)
return;
/* Finalize image-level hash */
crypto_shash_final(ctx->image_hash, ctx->image_digest);
pr_info("snapenc: hibernate image encryption complete\n");
pr_debug("snapenc: image SHA-256: %*phN\n",
SHA256_DIGEST_SIZE, ctx->image_digest);
/* Don't free ctx here — resume needs the sealed key */
}
/**
* snapenc_resume_begin - Called before reading the hibernate image.
*
* Sequence:
* 1. Extend PCR23 with the same magic value used during hibernate
* 2. Ask TPM to unseal the key (will fail if PCR doesn't match)
* 3. Re-initialize AES-GCM with the unsealed key
* 4. Reset PCR23
*
* Returns 0 on success, -EACCES if TPM policy fails (image tampered
* or wrong system), negative on other errors.
*/
int snapenc_resume_begin(void)
{
struct tpm_chip *chip;
struct snapenc_ctx *ctx = hibernate_enc_ctx;
u8 unsealed_key[SNAPENC_KEY_SIZE];
int rc;
if (!ctx) {
pr_err("snapenc: no encryption context for resume\n");
return -EINVAL;
}
chip = tpm_default_chip();
if (!chip) {
pr_err("snapenc: no TPM chip available for resume\n");
return -ENODEV;
}
/* Step 1: Extend PCR23 — must match state at seal time */
rc = snapenc_pcr_extend(chip);
if (rc) {
pr_err("snapenc: resume PCR%d extend failed: %d\n",
hibernate_tpm_pcr, rc);
goto out;
}
/* Step 2: Unseal key — TPM checks PCR23 matches policy */
rc = snapenc_unseal_key(chip, &ctx->sealed, unsealed_key);
if (rc == -EACCES) {
pr_crit("snapenc: TPM REFUSED to release hibernate key.\n"
"PCR%d state does not match seal-time policy.\n"
"This may indicate: wrong system, firmware change, "
"or the hibernate image was created on a different boot.\n"
"Resume aborted for security.\n",
hibernate_tpm_pcr);
goto out_reset_pcr;
}
if (rc) {
pr_err("snapenc: key unseal failed: %d\n", rc);
goto out_reset_pcr;
}
/* Step 3: Re-arm the AES transform with the unsealed key */
rc = crypto_aead_setkey(ctx->tfm, unsealed_key, SNAPENC_KEY_SIZE);
memzero_explicit(unsealed_key, SNAPENC_KEY_SIZE);
if (rc) {
pr_err("snapenc: failed to restore AES key: %d\n", rc);
goto out_reset_pcr;
}
/* Step 4: Reset PCR23 */
snapenc_pcr_reset(chip);
pr_info("snapenc: TPM key unseal successful, resuming\n");
tpm_put_chip(chip);
return 0;
out_reset_pcr:
snapenc_pcr_reset(chip);
out:
memzero_explicit(unsealed_key, SNAPENC_KEY_SIZE);
tpm_put_chip(chip);
return rc;
}
/**
* snapenc_resume_end - Called after successful resume.
*
* Cleans up the encryption context.
*/
void snapenc_resume_end(void)
{
snapenc_ctx_free(hibernate_enc_ctx);
hibernate_enc_ctx = NULL;
}
/* ------------------------------------------------------------------ */
/* Module init: verify TPM availability and PCR state */
/* ------------------------------------------------------------------ */
static int __init snapenc_init(void)
{
struct tpm_chip *chip;
int rc;
/* Only meaningful if lockdown is active */
if (!kernel_is_locked_down(NULL)) {
pr_debug("snapenc: kernel not locked down, "
"hibernate encryption available but not required\n");
}
chip = tpm_default_chip();
if (!chip) {
pr_warn("snapenc: no TPM2 chip found. "
"Hibernate encryption unavailable.\n");
return -ENODEV;
}
if (!tpm_is_tpm2(chip)) {
pr_err("snapenc: TPM1.x not supported, need TPM2\n");
tpm_put_chip(chip);
return -ENODEV;
}
/* Verify PCR is free at boot time */
rc = snapenc_pcr_is_zero(chip);
if (rc) {
tpm_put_chip(chip);
return rc;
}
pr_info("snapenc: initialized. Using PCR%d on %s for hibernate sealing.\n",
hibernate_tpm_pcr, dev_name(&chip->dev));
tpm_put_chip(chip);
return 0;
}
late_initcall(snapenc_init);
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #6: snapenc.h --]
[-- Type: text/x-chdr; name="snapenc.h", Size: 984 bytes --]
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* kernel/power/snapenc.h
*
* Interface for hibernate image encryption using TPM2 + PCR sealing.
*/
#ifndef __POWER_SNAPENC_H
#define __POWER_SNAPENC_H
#ifdef CONFIG_HIBERNATION_ENCRYPTION
int snapenc_hibernate_begin(void);
void snapenc_hibernate_end(void);
int snapenc_resume_begin(void);
void snapenc_resume_end(void);
ssize_t snapenc_encrypt_chunk(struct snapenc_ctx *ctx,
const u8 *in, size_t in_len,
u8 *out, u64 chunk_idx);
ssize_t snapenc_decrypt_chunk(struct snapenc_ctx *ctx,
const u8 *in, size_t in_len,
u8 *out, u64 chunk_idx);
#else /* !CONFIG_HIBERNATION_ENCRYPTION */
static inline int snapenc_hibernate_begin(void) { return 0; }
static inline void snapenc_hibernate_end(void) { }
static inline int snapenc_resume_begin(void) { return 0; }
static inline void snapenc_resume_end(void) { }
#endif /* CONFIG_HIBERNATION_ENCRYPTION */
#endif /* __POWER_SNAPENC_H */
^ permalink raw reply
* Re: [RFC PATCH 1/2] thermal/cpufreq_cooling: remove unused cpu_idx in get_load()
From: Viresh Kumar @ 2026-03-23 5:34 UTC (permalink / raw)
To: Lukasz Luba
Cc: Xuewen Yan, rui.zhang, rafael, linux-pm, amit.kachhap,
daniel.lezcano, linux-kernel, ke.wang, di.shen, jeson.gao,
xuewen.yan94
In-Reply-To: <031562ee-b88f-49b9-8b1e-dbbbe1a508c6@arm.com>
On 20-03-26, 12:32, Lukasz Luba wrote:
> Hi Xuewen,
>
> On 3/20/26 11:31, Xuewen Yan wrote:
> > From: Di Shen <di.shen@unisoc.com>
> >
> > The cpu_idx variable in the get_load function is now
> > unused and can be safely removed.
> >
> > No code logic is affected.
> >
> > Signed-off-by: Di Shen <di.shen@unisoc.com>
> > ---
> > drivers/thermal/cpufreq_cooling.c | 13 +++++--------
> > 1 file changed, 5 insertions(+), 8 deletions(-)
> >
> > diff --git a/drivers/thermal/cpufreq_cooling.c b/drivers/thermal/cpufreq_cooling.c
> > index 32bf5ab44f4a..d030dbeb2973 100644
> > --- a/drivers/thermal/cpufreq_cooling.c
> > +++ b/drivers/thermal/cpufreq_cooling.c
> > @@ -151,26 +151,23 @@ static u32 cpu_power_to_freq(struct cpufreq_cooling_device *cpufreq_cdev,
> > * get_load() - get load for a cpu
> > * @cpufreq_cdev: struct cpufreq_cooling_device for the cpu
> > * @cpu: cpu number
> > - * @cpu_idx: index of the cpu in time_in_idle array
> > *
> > * Return: The average load of cpu @cpu in percentage since this
> > * function was last called.
> > */
> > #ifdef CONFIG_SMP
> > -static u32 get_load(struct cpufreq_cooling_device *cpufreq_cdev, int cpu,
> > - int cpu_idx)
> > +static u32 get_load(struct cpufreq_cooling_device *cpufreq_cdev, int cpu)
> > {
> > unsigned long util = sched_cpu_util(cpu);
> > return (util * 100) / arch_scale_cpu_capacity(cpu);
> > }
> > #else /* !CONFIG_SMP */
> > -static u32 get_load(struct cpufreq_cooling_device *cpufreq_cdev, int cpu,
> > - int cpu_idx)
> > +static u32 get_load(struct cpufreq_cooling_device *cpufreq_cdev, int cpu)
> > {
> > u32 load;
> > u64 now, now_idle, delta_time, delta_idle;
> > - struct time_in_idle *idle_time = &cpufreq_cdev->idle_time[cpu_idx];
> > + struct time_in_idle *idle_time = &cpufreq_cdev->idle_time[cpu];
>
> This is a bug. We allocate 'num_cpus' size of array based on
> number of CPU in the cpumask for a given cpufreq policy.
> If there are 4 cpus in the CPU cluster but CPUs have ids:
> CPU4-7 then accessing it with this change would explode.
I think following commit introduced a bug by removing `i++`.
commit 3f7ced7ac9af ("drivers/thermal/cpufreq_cooling : Refactor thermal_power_cpu_get_power tracing")
--
viresh
^ permalink raw reply
* Re: [PATCH 2/2] arm64: dts: qcom: sm8750: Enable TSENS and thermal zones
From: Gaurav Kohli @ 2026-03-23 9:02 UTC (permalink / raw)
To: Konrad Dybcio, Amit Kucheria, Thara Gopinath, Rafael J. Wysocki,
Daniel Lezcano, Zhang Rui, Lukasz Luba, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Bjorn Andersson, Konrad Dybcio
Cc: linux-pm, linux-arm-msm, devicetree, linux-kernel, aastha.pandey,
dipa.mantre, Manaf Meethalavalappu Pallikunhi
In-Reply-To: <c4376a88-a490-4b58-bff3-b0f4d2f731b7@oss.qualcomm.com>
On 3/18/2026 3:14 PM, Konrad Dybcio wrote:
> On 3/13/26 11:34 AM, Gaurav Kohli wrote:
>> From: Manaf Meethalavalappu Pallikunhi <quic_manafm@quicinc.com>
>>
>> The sm8750 includes four TSENS instances, with a total of 47 thermal
>> sensors distributed across various locations on the SoC.
>>
>> The TSENS max/reset threshold is configured to 130°C in the hardware.
>> Enable all TSENS instances, and define the thermal zones with a hot trip
>> at 120°C and critical trip at 125°C.
>>
>> Signed-off-by: Manaf Meethalavalappu Pallikunhi <quic_manafm@quicinc.com>
>> Signed-off-by: Gaurav Kohli <gaurav.kohli@oss.qualcomm.com>
>> ---
>
> [...]
>
>> + cpu-0-0-0-thermal {
>> + thermal-sensors = <&tsens0 1>;
>> +
>> + trips {
>> + trip-point0 {
>> + temperature = <120000>;
>> + hysteresis = <5000>;
>> + type = "hot";
>> + };
>
> Are we going to use these trip points for the CPUs? If not, let's only
> keep the critical ones (again, for CPUs specifically since they get
> externally throttled)
thanks Konrad, for review.
We are not using this trip points for CPUs, For Kaanapali, Dmitry
suggested to add more warning for CPUs also, if in case some user want
to use it. So we have added for this soc also.
https://lore.kernel.org/all/vjx3bd75zdgdh6hzhrmlv5tlarnf6ea3yklwhg7jx6momknase@kstxwngyicd3/
>
> Konrad
^ permalink raw reply
* Re: [RFC PATCH 1/2] thermal/cpufreq_cooling: remove unused cpu_idx in get_load()
From: Lukasz Luba @ 2026-03-23 9:20 UTC (permalink / raw)
To: Viresh Kumar
Cc: Xuewen Yan, rui.zhang, rafael, linux-pm, amit.kachhap,
daniel.lezcano, linux-kernel, ke.wang, di.shen, jeson.gao,
xuewen.yan94
In-Reply-To: <ajjgf7xg5fwo6uk5ualkzoupuyj3pmp3l5yb2i2zfhop3msfkg@ieoosfn35gth>
Hi Viresh,
On 3/23/26 05:34, Viresh Kumar wrote:
> On 20-03-26, 12:32, Lukasz Luba wrote:
>> Hi Xuewen,
>>
>> On 3/20/26 11:31, Xuewen Yan wrote:
>>> From: Di Shen <di.shen@unisoc.com>
>>>
>>> The cpu_idx variable in the get_load function is now
>>> unused and can be safely removed.
>>>
>>> No code logic is affected.
>>>
>>> Signed-off-by: Di Shen <di.shen@unisoc.com>
>>> ---
>>> drivers/thermal/cpufreq_cooling.c | 13 +++++--------
>>> 1 file changed, 5 insertions(+), 8 deletions(-)
>>>
>>> diff --git a/drivers/thermal/cpufreq_cooling.c b/drivers/thermal/cpufreq_cooling.c
>>> index 32bf5ab44f4a..d030dbeb2973 100644
>>> --- a/drivers/thermal/cpufreq_cooling.c
>>> +++ b/drivers/thermal/cpufreq_cooling.c
>>> @@ -151,26 +151,23 @@ static u32 cpu_power_to_freq(struct cpufreq_cooling_device *cpufreq_cdev,
>>> * get_load() - get load for a cpu
>>> * @cpufreq_cdev: struct cpufreq_cooling_device for the cpu
>>> * @cpu: cpu number
>>> - * @cpu_idx: index of the cpu in time_in_idle array
>>> *
>>> * Return: The average load of cpu @cpu in percentage since this
>>> * function was last called.
>>> */
>>> #ifdef CONFIG_SMP
>>> -static u32 get_load(struct cpufreq_cooling_device *cpufreq_cdev, int cpu,
>>> - int cpu_idx)
>>> +static u32 get_load(struct cpufreq_cooling_device *cpufreq_cdev, int cpu)
>>> {
>>> unsigned long util = sched_cpu_util(cpu);
>>> return (util * 100) / arch_scale_cpu_capacity(cpu);
>>> }
>>> #else /* !CONFIG_SMP */
>>> -static u32 get_load(struct cpufreq_cooling_device *cpufreq_cdev, int cpu,
>>> - int cpu_idx)
>>> +static u32 get_load(struct cpufreq_cooling_device *cpufreq_cdev, int cpu)
>>> {
>>> u32 load;
>>> u64 now, now_idle, delta_time, delta_idle;
>>> - struct time_in_idle *idle_time = &cpufreq_cdev->idle_time[cpu_idx];
>>> + struct time_in_idle *idle_time = &cpufreq_cdev->idle_time[cpu];
>>
>> This is a bug. We allocate 'num_cpus' size of array based on
>> number of CPU in the cpumask for a given cpufreq policy.
>> If there are 4 cpus in the CPU cluster but CPUs have ids:
>> CPU4-7 then accessing it with this change would explode.
>
> I think following commit introduced a bug by removing `i++`.
>
> commit 3f7ced7ac9af ("drivers/thermal/cpufreq_cooling : Refactor thermal_power_cpu_get_power tracing")
>
Thanks for monitoring the development (it's always good
to have extra engineer opinion)!
I've checked the commit that you referred to and the 'i++' there.
It's safe. That commit removed the heavy operation for only
tracing purpose, namely:
- allocate buffer for N CPUs for 'load_cpu' pointer
- populate CPUs' load from the idle fwk
- put that info into the trace
- free the 'load_cpu' buffer
That has been redesigned since it was just for tracing
and introducing extra time spent for code run in the
throttling phase.
The code in get_load() is OK with the commit that you
mentioned.
Regards,
Lukasz
^ permalink raw reply
* [PATCH] thermal: devfreq_cooling: avoid unnecessary kfree of freq_table
From: Anas Iqbal @ 2026-03-23 9:40 UTC (permalink / raw)
To: rafael, daniel.lezcano
Cc: rui.zhang, lukasz.luba, linux-pm, linux-kernel, Anas Iqbal
dfc->freq_table is only allocated in the non-EM path via
devfreq_cooling_gen_tables(). In the EM path, it remains NULL.
Avoid calling kfree() unnecessarily when freq_table was never allocated.
This resolves a Smatch warning:
calling kfree() when 'dfc->freq_table' is always NULL.
Signed-off-by: Anas Iqbal <mohd.abd.6602@gmail.com>
---
drivers/thermal/devfreq_cooling.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/drivers/thermal/devfreq_cooling.c b/drivers/thermal/devfreq_cooling.c
index 597e86d16a4e..1c7dffc8d45f 100644
--- a/drivers/thermal/devfreq_cooling.c
+++ b/drivers/thermal/devfreq_cooling.c
@@ -472,7 +472,8 @@ of_devfreq_cooling_register_power(struct device_node *np, struct devfreq *df,
remove_qos_req:
dev_pm_qos_remove_request(&dfc->req_max_freq);
free_table:
- kfree(dfc->freq_table);
+ if (!dfc->em_pd)
+ kfree(dfc->freq_table);
free_dfc:
kfree(dfc);
--
2.43.0
^ permalink raw reply related
* Re: [PATCH v5 00/21] Virtual Swap Space
From: Kairui Song @ 2026-03-23 10:08 UTC (permalink / raw)
To: Nhat Pham
Cc: Liam.Howlett, akpm, apopple, axelrasmussen, baohua, baolin.wang,
bhe, byungchul, cgroups, chengming.zhou, chrisl, corbet, david,
dev.jain, gourry, hannes, hughd, jannh, joshua.hahnjy, lance.yang,
lenb, linux-doc, linux-kernel, linux-mm, linux-pm,
lorenzo.stoakes, matthew.brost, mhocko, muchun.song, npache,
pavel, peterx, peterz, pfalcato, rafael, rakie.kim,
roman.gushchin, rppt, ryan.roberts, shakeel.butt, shikemeng,
surenb, tglx, vbabka, weixugc, ying.huang, yosry.ahmed, yuanchu,
zhengqi.arch, ziy, kernel-team, riel
In-Reply-To: <20260320192735.748051-1-nphamcs@gmail.com>
[-- Attachment #1: Type: text/plain, Size: 8359 bytes --]
On Sat, Mar 21, 2026 at 3:29 AM Nhat Pham <nphamcs@gmail.com> wrote:
> This patch series is based on 6.19. There are a couple more
> swap-related changes in mainline that I would need to coordinate
> with, but I still want to send this out as an update for the
> regressions reported by Kairui Song in [15]. It's probably easier
> to just build this thing rather than dig through that series of
> emails to get the fix patch :)
>
> Changelog:
> * v4 -> v5:
> * Fix a deadlock in memcg1_swapout (reported by syzbot [16]).
> * Replace VM_WARN_ON(!spin_is_locked()) with lockdep_assert_held(),
> and use guard(rcu) in vswap_cpu_dead
> (reported by Peter Zijlstra [17]).
> * v3 -> v4:
> * Fix poor swap free batching behavior to alleviate a regression
> (reported by Kairui Song).
I tested the v5 (including the batched-free hotfix) and am still
seeing significant regressions in both sequential and concurrent swap
workloads
Thanks for the update as I can see It's a lot of thoughtful work.
Actually I did run some tests already with your previously posted
hotfix based on v3. I didn't update the result because very
unfortunately, I still see a major performance regression even with a
very simple setup.
BTW there seems a simpler way to reproduce that, just use memhog:
sudo mkswap /dev/pmem0; sudo swapon /dev/pmem0; time memhog 48G; sudo swapoff -a
Before:
(I'm using fish shell on that test machine so this is fish time format):
________________________________________________________
Executed in 20.80 secs fish external
usr time 5.14 secs 0.00 millis 5.14 secs
sys time 15.65 secs 1.17 millis 15.65 secs
________________________________________________________
Executed in 21.69 secs fish external
usr time 5.31 secs 725.00 micros 5.31 secs
sys time 16.36 secs 579.00 micros 16.36 secs
________________________________________________________
Executed in 21.86 secs fish external
usr time 5.39 secs 1.02 millis 5.39 secs
sys time 16.46 secs 0.27 millis 16.46 secs
After:
________________________________________________________
Executed in 30.77 secs fish external
usr time 5.16 secs 767.00 micros 5.16 secs
sys time 25.59 secs 580.00 micros 25.59 secs
________________________________________________________
Executed in 37.47 secs fish external
usr time 5.48 secs 0.00 micros 5.48 secs
sys time 31.98 secs 674.00 micros 31.98 secs
________________________________________________________
Executed in 31.34 secs fish external
usr time 5.22 secs 0.00 millis 5.22 secs
sys time 26.09 secs 1.30 millis 26.09 secs
It's obviously a lot slower.
pmem may seem rare but SSDs are good at sequential, and memhog uses
the same filled page and backend like ZRAM has extremely low overhead
for same filled pages. Results with ZRAM are very similar, and many
production workloads have massive amounts of samefill memory.
For example on the Android phone I'm using right now at this moment:
# cat /sys/block/zram0/mm_stat
4283899904 1317373036 1370259456 0 1475977216 116457 1991851
87273 1793760
~450M of samefill page in ZRAM, we may see more on some server
workload. And I'm seeing similar memhog results with ZRAM, pmem is
just easier to setup and less noisy. also simulates high speed
storage.
I also ran the previous usemem matrix, which seems better than V3 but
still pretty bad:
Test: usemem --init-time -O -n 1 56G, 16G mem, 48G swap, avgs of 8 run.
Before:
Throughput (Sum): 528.98 MB/s Throughput (Mean): 526.113333 MB/s Free
Latency: 3037932.888889
After:
Throughput (Sum): 453.74 MB/s Throughput (Mean): 454.875000 MB/s Free
Latency: 5001144.500000 (~10%, 64% slower)
I'm not sure why our results differ so much — perhaps different LRU
settings, memory pressure ratios, or THP/mTHP configs? Here's my exact
config in the attachment. Also includes the full log and info, with
all debug options disabled for close to production. I ran it 8 times
and just attached the first result log, it's all similar anyway, my
test framework reboot the machine after each test run to reduce any
potential noise.
And the above tests are only about sequential performance, concurrent
ones seem worse:
Test: usemem --init-time -O -R -n 32 622M, 16G mem, 48G swap, avgs of 8 run.
Before:
Throughput (Sum): 5467.51 MB/s Throughput (Mean): 170.04 MB/s Free
Latency: 28648.65
After:
Throughput (Sum): 4914.86 MB/s Throughput (Mean): 152.74 MB/s Free
Latency: 67789.81 (~10%, 230% slower)
And I double checked I'm testing your latest V5 commit here:
commit 9114ebedb82089ebd3519854964c73d3959b10c0 (HEAD -> upstream/vswap)
Author: Nhat Pham <nphamcs@gmail.com>
Date: Fri Mar 20 12:27:35 2026 -0700
vswap: batch contiguous vswap free calls
In vswap_free(), we release and reacquire the cluster lock for every
single entry, even for non-disk-swap backends where the lock drop is
unnecessary. Batch consecutive free operations to avoid this overhead.
Signed-off-by: Nhat Pham <nphamcs@gmail.com>
The two kernels being tested:
/boot/vmlinuz-6.19.0.orig-g05f7e89ab973
/boot/vmlinuz-6.19.0.ptch-g9114ebedb820
These tests above are done with an EPYC 7K62, I also setup an Intel
8255C with fresh installed upstream Fedora, and using Fedora's kernel
config. So far the result matches, the gap seems smaller but still
>20% slower for many cases, so this is a common problem:
3 test run on 8255C using fresh installed Fedora and Fedora kernel config:
taskset -c 3 /usr/local/bin/usemem --init-time -O -n 1 112G
(That's a two nodes large machine so I pin the thread on CPU 3 for stability)
Before:
135291469824 bytes / 124326887 usecs = 1062687 KB/s
2157355 usecs to free memory
135291469824 bytes / 123930024 usecs = 1066090 KB/s
2244083 usecs to free memory
135291469824 bytes / 123484528 usecs = 1069936 KB/s
2268364 usecs to free memory
After:
135291469824 bytes / 127073712 usecs = 1039716 KB/s
3050394 usecs to free memory
135291469824 bytes / 130724757 usecs = 1010677 KB/s
3064270 usecs to free memory
135291469824 bytes / 127248347 usecs = 1038289 KB/s
3035986 usecs to free memory
And beside these known cases, my main concern is still that a
mandatory virtual layer seems just wrong, it changes how swap work in
many ways. Storage folks have been trying to bypass the kernel for
decades, as abstraction layers come with overhead — that's common
knowledge. Swap lives right at the intersection of storage and mm and
has to stay inside the kernel, so we really want the kernel path to be
as flat and direct as possible.
I'm also worried this risks undoing all the recent and upcoming work
for reducing memory usage and performance. We've been trying to shrink
per-entry overhead (I'm already feeling nervous over the current
8-byte per-entry cost, and hope soon we'll get down to <1–3 bytes).
The series mentions 24 bytes of overhead, but when I account for the
reverse mapping, it looks >32 bytes per entry.
The intermediate large XArray layer also worries me as the swap space
is now very large. The virtual size could grow with no limit. e.g. a 1
TB swap space would be a 4 layers radix tree, increasing global
contention (int(1024 * 1024 / 2) >> 6 >> 6 >> 6 == 2) and vswap could
be even larger if fragmentation happens. That's the exact problem the
old sub-address_space design for SWAP was created to solve. We only
eliminated that complexity a few months ago, and this approach seems
like it would have to bring a similar structure back to reduce
contention.
And for swapoff support: minor anonymous faults during busy periods
are indeed critical for some workloads, and being able to swapoff
cleanly is still very useful both for performance and troubleshooting.
You will need to touch many things to solve a minor fault.
For reference, I've been exploring an approach that keeps the virtual
layer runtime-optional, which avoids these overheads for workloads
that don't need virtualization:
https://lore.kernel.org/linux-mm/20260220-swap-table-p4-v1-0-104795d19815@tencent.com/
[-- Attachment #2: config-n-log.tar --]
[-- Type: application/tar, Size: 665600 bytes --]
^ permalink raw reply
* Re: [PATCH 3/9] interconnect: qcom: drop unused is_on flag
From: Konrad Dybcio @ 2026-03-23 10:26 UTC (permalink / raw)
To: Dmitry Baryshkov, Georgi Djakov, Konrad Dybcio, Bjorn Andersson,
Luca Weiss, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Brian Masney
Cc: linux-arm-msm, linux-pm, devicetree, linux-kernel
In-Reply-To: <20260323-msm8974-icc-v1-3-7892b8d5f2ea@oss.qualcomm.com>
On 3/23/26 2:17 AM, Dmitry Baryshkov wrote:
> The commit 2e2113c8a64f ("interconnect: qcom: rpm: Handle interface
> clocks") has added the is_on flag to the qcom_icc_provider, but failed
> to actually utilize it. Drop the flag.
>
> Fixes: 2e2113c8a64f ("interconnect: qcom: rpm: Handle interface clocks")
> Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
> ---
> drivers/interconnect/qcom/icc-rpm.h | 2 --
> 1 file changed, 2 deletions(-)
>
> diff --git a/drivers/interconnect/qcom/icc-rpm.h b/drivers/interconnect/qcom/icc-rpm.h
> index f4883d43eae4..3366531f66fc 100644
> --- a/drivers/interconnect/qcom/icc-rpm.h
> +++ b/drivers/interconnect/qcom/icc-rpm.h
> @@ -51,7 +51,6 @@ struct rpm_clk_resource {
> * @bus_clk: a pointer to a HLOS-owned bus clock
> * @intf_clks: a clk_bulk_data array of interface clocks
> * @keep_alive: whether to always keep a minimum vote on the bus clocks
> - * @is_on: whether the bus is powered on
> */
> struct qcom_icc_provider {
> struct icc_provider provider;
> @@ -66,7 +65,6 @@ struct qcom_icc_provider {
> struct clk *bus_clk;
> struct clk_bulk_data *intf_clks;
> bool keep_alive;
> - bool is_on;
Hm, looks like the clock vote is kept all the way from .probe()
to .remove(). I wonder if that's really what should happen..
That's what drivers/interconnect/qcom/holi.c does on msm-5.10
Maybe "iface clocks" are only needed to execute a ->set() on a node?
Konrad
^ permalink raw reply
* Re: [PATCH 5/9] interconnect: qcom: define OCMEM bus resource
From: Konrad Dybcio @ 2026-03-23 10:27 UTC (permalink / raw)
To: Dmitry Baryshkov, Georgi Djakov, Konrad Dybcio, Bjorn Andersson,
Luca Weiss, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Brian Masney
Cc: linux-arm-msm, linux-pm, devicetree, linux-kernel
In-Reply-To: <20260323-msm8974-icc-v1-5-7892b8d5f2ea@oss.qualcomm.com>
On 3/23/26 2:17 AM, Dmitry Baryshkov wrote:
> Some of the platforms (MSM8974, MSM8x26) require voting on the OCMEM
> clock. Add new resource for that clock.
>
> Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
> ---
I don't know about the GPU prefix but okay
Reviewed-by: Konrad Dybcio <konrad.dybcio@oss.qualcomm.com>
Konrad
^ permalink raw reply
* Re: [PATCH 4/9] interconnect: qcom: icc-rpm: allow overwriting get_bw callback
From: Konrad Dybcio @ 2026-03-23 10:32 UTC (permalink / raw)
To: Dmitry Baryshkov, Georgi Djakov, Konrad Dybcio, Bjorn Andersson,
Luca Weiss, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Brian Masney
Cc: linux-arm-msm, linux-pm, devicetree, linux-kernel
In-Reply-To: <20260323-msm8974-icc-v1-4-7892b8d5f2ea@oss.qualcomm.com>
On 3/23/26 2:17 AM, Dmitry Baryshkov wrote:
> MSM8974 requires a separate get_bw callback, since on that platform
> increasing the clock rate for some of the NoCs during boot may lead to
> hangs. For the details see commit 9caf2d956cfa ("interconnect: qcom:
> msm8974: Don't boost the NoC rate during boot").
Is there a single specific bus where this causes an issue, or is
setting *any* resource to INT_MAX problematic?
Konrad
^ permalink raw reply
* Re: [PATCH 7/9] interconnect: qcom: msm8974: switch to the main icc-rpm driver
From: Konrad Dybcio @ 2026-03-23 10:36 UTC (permalink / raw)
To: Dmitry Baryshkov, Georgi Djakov, Konrad Dybcio, Bjorn Andersson,
Luca Weiss, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Brian Masney
Cc: linux-arm-msm, linux-pm, devicetree, linux-kernel
In-Reply-To: <20260323-msm8974-icc-v1-7-7892b8d5f2ea@oss.qualcomm.com>
On 3/23/26 2:17 AM, Dmitry Baryshkov wrote:
> In preparation to restoring the ability of MSM8974 driver to work with
> the modern kernels, switch the driver to the main icc-rpm set of helper
> code.
>
> As platform-specific workarounds, set the get_bw callback (returning 0)
> to prevent initial setup from programming INT_MAX into the RPM (which
> otherwise might hang the platform) and tell RPM programming code to
> ignore -ENXIO errors from the firmware (until the QoS programming is
> sorted out).
>
> Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
> ---
Reviewed-by: Konrad Dybcio <konrad.dybcio@oss.qualcomm.com>
Konrad
^ permalink raw reply
* Re: [PATCH 6/9] interconnect: qcom: let platforms declare their bugginess
From: Konrad Dybcio @ 2026-03-23 10:36 UTC (permalink / raw)
To: Dmitry Baryshkov, Georgi Djakov, Konrad Dybcio, Bjorn Andersson,
Luca Weiss, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Brian Masney
Cc: linux-arm-msm, linux-pm, devicetree, linux-kernel
In-Reply-To: <20260323-msm8974-icc-v1-6-7892b8d5f2ea@oss.qualcomm.com>
On 3/23/26 2:17 AM, Dmitry Baryshkov wrote:
> On MSM8974 programming some of the RPM resources results in the
> "resource does not exist" messages from the firmware. This occurs even
> with the downstream bus driver, which happily ignores the errors. My
> assumption is that these resources existed in the earlier firmware
> revisions but were later switched to be programmed differently (for the
> later platforms corresponding nodes use qos.ap_owned, which prevents
> those resources from being programmed.
>
> In preparation for conversion of the MSM8974 driver (which doesn't have
> QoS code yet) to the main icc-rpm set of helpers, let the driver declare
> that those -ENXIO errors must be ignored (for now). Later, when the QoS
> programming is sorted out (and more interconnects are added to the DT),
> this quirk might be removed.
>
> Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
> ---
Not super happy about this, but since it's transitional:
Reviewed-by: Konrad Dybcio <konrad.dybcio@oss.qualcomm.com>
Konrad
^ permalink raw reply
* Re: [PATCH 9/9] ARM: dts: qcom: msm8974: Drop RPM bus clocks
From: Konrad Dybcio @ 2026-03-23 10:41 UTC (permalink / raw)
To: Dmitry Baryshkov, Georgi Djakov, Konrad Dybcio, Bjorn Andersson,
Luca Weiss, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Brian Masney
Cc: linux-arm-msm, linux-pm, devicetree, linux-kernel
In-Reply-To: <20260323-msm8974-icc-v1-9-7892b8d5f2ea@oss.qualcomm.com>
On 3/23/26 2:17 AM, Dmitry Baryshkov wrote:
> Some nodes are abusingly referencing some of the internal bus clocks,
> that were recently removed in Linux (because the original implementation
> did not make much sense), managing them as if they were the only devices
> on an NoC bus.
>
> These clocks are now handled from within the icc framework and are
> no longer registered from within the CCF. Remove them.
>
> Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
> ---
[...]
> mmssnoc: interconnect@fc478000 {
> reg = <0xfc478000 0x4000>;
> compatible = "qcom,msm8974-mmssnoc";
> #interconnect-cells = <1>;
> - clock-names = "bus", "bus_a";
> - clocks = <&mmcc MMSS_S0_AXI_CLK>,
> - <&mmcc MMSS_S0_AXI_CLK>;
> + clock-names = "bus";
> + clocks = <&mmcc MMSS_S0_AXI_CLK>;
x
x-names
please
> };
>
> cnoc: interconnect@fc480000 {
> reg = <0xfc480000 0x4000>;
> compatible = "qcom,msm8974-cnoc";
> #interconnect-cells = <1>;
> - clock-names = "bus", "bus_a";
> - clocks = <&rpmcc RPM_SMD_CNOC_CLK>,
> - <&rpmcc RPM_SMD_CNOC_A_CLK>;
> };
>
> tsens: thermal-sensor@fc4a9000 {
> @@ -2223,6 +2207,7 @@ sram@fdd00000 {
> <0xfec00000 0x180000>;
> reg-names = "ctrl", "mem";
> ranges = <0 0xfec00000 0x180000>;
> + // core clock is unused, kept for ABI compliance
Do we still enforce C-style comments?
Also "unused" is not really right.. After the 'revolution', SMD_RPM_CC
no longer ""provides"" that clock in reality, since it was never a "clock"
but rather an interconnect resource
Konrad
> clocks = <&rpmcc RPM_SMD_OCMEMGX_CLK>,
> <&mmcc OCMEMCX_OCMEMNOC_CLK>;
> clock-names = "core", "iface";
>
^ permalink raw reply
* Re: [RFC PATCH 1/2] thermal/cpufreq_cooling: remove unused cpu_idx in get_load()
From: Viresh Kumar @ 2026-03-23 10:41 UTC (permalink / raw)
To: Lukasz Luba
Cc: Xuewen Yan, rui.zhang, rafael, linux-pm, amit.kachhap,
daniel.lezcano, linux-kernel, ke.wang, di.shen, jeson.gao,
xuewen.yan94
In-Reply-To: <3daf28ca-48c2-477f-ad06-5704b17b880e@arm.com>
On 23-03-26, 09:20, Lukasz Luba wrote:
> Thanks for monitoring the development (it's always good
> to have extra engineer opinion)!
>
> I've checked the commit that you referred to and the 'i++' there.
> It's safe. That commit removed the heavy operation for only
> tracing purpose, namely:
> - allocate buffer for N CPUs for 'load_cpu' pointer
> - populate CPUs' load from the idle fwk
> - put that info into the trace
> - free the 'load_cpu' buffer
>
> That has been redesigned since it was just for tracing
> and introducing extra time spent for code run in the
> throttling phase.
>
> The code in get_load() is OK with the commit that you
> mentioned.
The code
load = get_load(cpufreq_cdev, cpu, i);
depends on `i` being incremented in the loop to get the correct
`cpu_idx`. But the said commit removed it and left `i` to be set to 0
for ever.
How is that okay ? What am I missing ?
--
viresh
^ permalink raw reply
* Re: [PATCH] thermal: devfreq_cooling: avoid unnecessary kfree of freq_table
From: Lukasz Luba @ 2026-03-23 10:44 UTC (permalink / raw)
To: Anas Iqbal; +Cc: rui.zhang, daniel.lezcano, linux-pm, rafael, linux-kernel
In-Reply-To: <20260323094018.2264-1-mohd.abd.6602@gmail.com>
On 3/23/26 09:40, Anas Iqbal wrote:
> dfc->freq_table is only allocated in the non-EM path via
> devfreq_cooling_gen_tables(). In the EM path, it remains NULL.
>
> Avoid calling kfree() unnecessarily when freq_table was never allocated.
>
> This resolves a Smatch warning:
> calling kfree() when 'dfc->freq_table' is always NULL.
>
> Signed-off-by: Anas Iqbal <mohd.abd.6602@gmail.com>
> ---
> drivers/thermal/devfreq_cooling.c | 3 ++-
> 1 file changed, 2 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/thermal/devfreq_cooling.c b/drivers/thermal/devfreq_cooling.c
> index 597e86d16a4e..1c7dffc8d45f 100644
> --- a/drivers/thermal/devfreq_cooling.c
> +++ b/drivers/thermal/devfreq_cooling.c
> @@ -472,7 +472,8 @@ of_devfreq_cooling_register_power(struct device_node *np, struct devfreq *df,
> remove_qos_req:
> dev_pm_qos_remove_request(&dfc->req_max_freq);
> free_table:
> - kfree(dfc->freq_table);
> + if (!dfc->em_pd)
> + kfree(dfc->freq_table);
> free_dfc:
> kfree(dfc);
>
LGTM, let's calm down that warning.
Reviewed-by: Lukasz Luba <lukasz.luba@arm.com>
^ permalink raw reply
* Re: [PATCH 8/9] interconnect: qcom: msm8974: expand DEFINE_QNODE macros
From: Konrad Dybcio @ 2026-03-23 10:45 UTC (permalink / raw)
To: Dmitry Baryshkov, Georgi Djakov, Konrad Dybcio, Bjorn Andersson,
Luca Weiss, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Brian Masney
Cc: linux-arm-msm, linux-pm, devicetree, linux-kernel
In-Reply-To: <20260323-msm8974-icc-v1-8-7892b8d5f2ea@oss.qualcomm.com>
On 3/23/26 2:17 AM, Dmitry Baryshkov wrote:
> The rest of Qualcomm Interconnect drivers have stopped using
> DEFINE_QNODE long ago for the sake of readability. Stop using it inside
> the msm8974 interconnect driver too.
>
> Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
> ---
I'm not checking that by hand..
Acked-by: Konrad Dybcio <konrad.dybcio@oss.qualcomm.com>
Konrad
^ permalink raw reply
* [PATCH v4 0/2] monaco: Add PMM8654AU PON support
From: Rakesh Kota @ 2026-03-23 10:45 UTC (permalink / raw)
To: Sebastian Reichel, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Vinod Koul, Bjorn Andersson, Konrad Dybcio
Cc: linux-pm, devicetree, linux-kernel, linux-arm-msm, Rakesh Kota,
Dmitry Baryshkov, Konrad Dybcio
This patch series updates the PON power and reset dt-bindings and
device tree to add support for PON power and reset keys on the
Monaco platform.
Signed-off-by: Rakesh Kota <rakesh.kota@oss.qualcomm.com>
---
Changes in v4:
- Remove the contain for PMK8350 and new if:then for PMM8654AU as suggested by Krzysztof Kozlowski
- Link to v3: https://lore.kernel.org/r/20260227-b4-add_pwrkey_and_resin-v3-0-61c5bb2cdda9@oss.qualcomm.com
Changes in v3:
- Drop the dt-bindings of PMM8654AU qcom,pm8941-pwrkey as this
patch was picked - https://lore.kernel.org/all/20260209-add_pwrkey_and_resin-v2-2-f944d87b9a93@oss.qualcomm.com
- Update Commit message and disable the resin as suggested by Konrad Dybcio
- Link to v2: https://lore.kernel.org/r/20260209-add_pwrkey_and_resin-v2-0-f944d87b9a93@oss.qualcomm.com
Changes in v2:
- Introduces PMM8654AU compatible strings as suggested by Konrad Dybcio.
- Link to v1: https://lore.kernel.org/all/20260122-add_pwrkey_and_resin-v1-1-a9fe87537816@oss.qualcomm.com
---
Rakesh Kota (2):
dt-bindings: power: reset: qcom-pon: Add new compatible PMM8654AU
arm64: dts: qcom: monaco-pmics: Add PON power key and reset inputs
.../devicetree/bindings/power/reset/qcom,pon.yaml | 32 +++++++++++++++++-----
arch/arm64/boot/dts/qcom/monaco-pmics.dtsi | 20 ++++++++++++++
2 files changed, 45 insertions(+), 7 deletions(-)
---
base-commit: 877552aa875839314afad7154b5a561889e87ea9
change-id: 20260226-b4-add_pwrkey_and_resin-2c04d8d53f5d
Best regards,
--
Rakesh Kota <rakesh.kota@oss.qualcomm.com>
^ permalink raw reply
* [PATCH v4 1/2] dt-bindings: power: reset: qcom-pon: Add new compatible PMM8654AU
From: Rakesh Kota @ 2026-03-23 10:45 UTC (permalink / raw)
To: Sebastian Reichel, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Vinod Koul, Bjorn Andersson, Konrad Dybcio
Cc: linux-pm, devicetree, linux-kernel, linux-arm-msm, Rakesh Kota,
Dmitry Baryshkov
In-Reply-To: <20260323-b4-add_pwrkey_and_resin-v4-0-abef4e4dcc3d@oss.qualcomm.com>
PMM8654AU is a different PMIC from PMM8650AU, even though both share
the same PMIC subtype. Add PON compatible string for PMM8654AU PMIC
variant.
The PMM8654AU PON block is compatible with the PMK8350 PON
implementation, but PMM8654AU also implements additional PON registers
beyond the baseline. Use the PMM8654AU naming to match the compatible
string already present in the upstream pinctrl-spmi-gpio driver, keeping
device tree and kernel driver naming consistent.
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
Signed-off-by: Rakesh Kota <rakesh.kota@oss.qualcomm.com>
---
Changes in v4:
- Remove the contain for PMK8350 and new if:then for PMM8654AU as
suggested by Krzysztof Kozlowski
Changes in v3:
- Update the commit message.
Changes in v2:
- Introduces PMM8654AU compatible strings as suggested by Konrad Dybcio.
---
.../devicetree/bindings/power/reset/qcom,pon.yaml | 32 +++++++++++++++++-----
1 file changed, 25 insertions(+), 7 deletions(-)
diff --git a/Documentation/devicetree/bindings/power/reset/qcom,pon.yaml b/Documentation/devicetree/bindings/power/reset/qcom,pon.yaml
index 979a377cb4ffd577bfa51b9a3cd089acc202de0c..2a5d9182b8d5c1a286716ab175c7bb5e39b334e0 100644
--- a/Documentation/devicetree/bindings/power/reset/qcom,pon.yaml
+++ b/Documentation/devicetree/bindings/power/reset/qcom,pon.yaml
@@ -17,12 +17,16 @@ description: |
properties:
compatible:
- enum:
- - qcom,pm8916-pon
- - qcom,pm8941-pon
- - qcom,pms405-pon
- - qcom,pm8998-pon
- - qcom,pmk8350-pon
+ oneOf:
+ - enum:
+ - qcom,pm8916-pon
+ - qcom,pm8941-pon
+ - qcom,pms405-pon
+ - qcom,pm8998-pon
+ - qcom,pmk8350-pon
+ - items:
+ - const: qcom,pmm8654au-pon
+ - const: qcom,pmk8350-pon
reg:
description: |
@@ -100,7 +104,6 @@ allOf:
- if:
properties:
compatible:
- contains:
const: qcom,pmk8350-pon
then:
properties:
@@ -113,6 +116,21 @@ allOf:
- const: hlos
- const: pbs
+ - if:
+ properties:
+ compatible:
+ const: qcom,pmm8654au-pon
+ then:
+ properties:
+ reg:
+ minItems: 1
+ maxItems: 2
+ reg-names:
+ minItems: 1
+ items:
+ - const: hlos
+ - const: pbs
+
examples:
- |
#include <dt-bindings/interrupt-controller/irq.h>
--
2.34.1
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox