Re: [PATCH v5 3/9] remoteproc: qcom: pas: add support for TMD thermal cooling devices
Gaurav Kohli <[email protected]> Thu, 23 Jul 2026 20:05:05 +0530
| Newsgroups | org.kernel.vger.linux-remoteproc,org.kernel.vger.linux-arm-msm,org.kernel.vger.linux-devicetree,org.kernel.vger.linux-hardening,org.kernel.vger.linux-kernel,org.kernel.vger.linux-pm |
|---|---|
| Message-ID | <[email protected]> |
On 7/22/2026 4:37 AM, Dmitry Baryshkov wrote: > On Tue, Jul 21, 2026 at 11:59:00AM +0530, Gaurav Kohli wrote: >> Register Thermal Mitigation Devices (TMDs) for PAS-managed remote >> processors to enable thermal throttling through QMI. >> >> This allows the thermal framework to request mitigation when remote >> subsystems such as modem and CDSP contribute to thermal pressure. >> >> Signed-off-by: Gaurav Kohli <[email protected]> >> --- >> drivers/remoteproc/Kconfig | 1 + >> drivers/remoteproc/qcom_q6v5_pas.c | 90 +++++++++++++++++++++++++++++++++++++- >> 2 files changed, 90 insertions(+), 1 deletion(-) >> >> diff --git a/drivers/remoteproc/Kconfig b/drivers/remoteproc/Kconfig >> index 65befdbfa5f7..f7c02edf395f 100644 >> --- a/drivers/remoteproc/Kconfig >> +++ b/drivers/remoteproc/Kconfig >> @@ -229,6 +229,7 @@ config QCOM_Q6V5_PAS >> select QCOM_PIL_INFO >> select QCOM_MDT_LOADER >> select QCOM_Q6V5_COMMON >> + select QCOM_QMI_TMD > > Sashiko warned here about the missing NET dependencies. thanks for review, will fix this. > >> select QCOM_RPROC_COMMON >> select QCOM_SCM >> select QCOM_PAS >> diff --git a/drivers/remoteproc/qcom_q6v5_pas.c b/drivers/remoteproc/qcom_q6v5_pas.c >> index 25599d728208..dc5be2c030cf 100644 >> --- a/drivers/remoteproc/qcom_q6v5_pas.c >> +++ b/drivers/remoteproc/qcom_q6v5_pas.c >> @@ -5,6 +5,7 @@ >> * Copyright (C) 2016 Linaro Ltd >> * Copyright (C) 2014 Sony Mobile Communications AB >> * Copyright (c) 2012-2013, The Linux Foundation. All rights reserved. >> + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. >> */ >> >> #include <linux/clk.h> >> @@ -26,8 +27,10 @@ >> #include <linux/regulator/consumer.h> >> #include <linux/remoteproc.h> >> #include <linux/soc/qcom/mdt_loader.h> >> +#include <linux/soc/qcom/qmi_tmd.h> >> #include <linux/soc/qcom/smem.h> >> #include <linux/soc/qcom/smem_state.h> >> +#include <dt-bindings/thermal/qcom,qmi-tmd.h> >> >> #include "qcom_common.h" >> #include "qcom_pil_info.h" >> @@ -38,6 +41,16 @@ >> >> #define MAX_ASSIGN_COUNT 3 >> >> +/** >> + * struct tmd_name - TMD device name to cooling-device index mapping >> + * @name: TMD device name >> + * @id: Cooling-device index used as #cooling-cells cell 0 in DT >> + */ >> +struct tmd_name { >> + const char *name; >> + int id; >> +}; >> + >> struct qcom_pas_data { >> int crash_reason_smem; >> const char *firmware_name; >> @@ -58,6 +71,10 @@ struct qcom_pas_data { >> int ssctl_id; >> unsigned int smem_host_id; >> >> + unsigned int tmd_instance_id; >> + const struct tmd_name *tmd_name; >> + int num_tmd; >> + >> int region_assign_idx; >> int region_assign_count; >> bool region_assign_shared; >> @@ -122,6 +139,8 @@ struct qcom_pas { >> >> struct qcom_pas_context *pas_ctx; >> struct qcom_pas_context *dtb_pas_ctx; >> + >> + struct qmi_tmd_client *tmd_inst; >> }; >> >> static void qcom_pas_segment_dump(struct rproc *rproc, >> @@ -798,6 +817,64 @@ static void qcom_pas_unassign_memory_region(struct qcom_pas *pas) >> } >> } >> >> +static int qcom_pas_setup_tmd(struct qcom_pas *pas, const struct qcom_pas_data *desc) >> +{ >> + struct qmi_tmd_client *tmd_inst; >> + const struct tmd_name *tmd; >> + const char **tmd_names; >> + int i, ret; >> + >> + if (!device_property_present(pas->dev, "#cooling-cells")) >> + return 0; >> + >> + if (!desc->tmd_name || desc->num_tmd == 0) >> + return 0; >> + >> + tmd_names = devm_kcalloc(pas->dev, desc->num_tmd, >> + sizeof(*tmd_names), GFP_KERNEL); >> + if (!tmd_names) >> + return -ENOMEM; >> + >> + for (i = 0; i < desc->num_tmd; i++) { >> + tmd = &desc->tmd_name[i]; >> + >> + if (tmd->id < 0 || tmd->id >= desc->num_tmd) { > > The < 0 check is totally redundant. Ack, this is redundant only. > > For the second check, currently the driver will set num_tmd to > ARRAY_SIZE(desc->tmds), which makes second part either redundant or > invalid. I assume that here you want to compare to some maximum TMD > number to be supported rather than a fixed ARRAY_SIZE(). This is just a defensive check to prevent mistakes in the static mapping table. The current mappings use dense IDs starting from 0, so desc->num_tmd matches the valid ID range today. > >> + dev_err(pas->dev, "Invalid TMD id %d for '%s'\n", >> + tmd->id, tmd->name); >> + return -EINVAL; >> + } >> + >> + if (tmd_names[tmd->id]) { >> + dev_err(pas->dev, "Duplicate TMD id %d for '%s'\n", >> + tmd->id, tmd->name); >> + return -EINVAL; >> + } >> + >> + tmd_names[tmd->id] = tmd->name; >> + } >> + >> + for (i = 0; i < desc->num_tmd; i++) { >> + if (!tmd_names[i]) { >> + dev_err(pas->dev, "Missing TMD mapping for id %d\n", i); >> + return -EINVAL; >> + } >> + } >> + >> + tmd_inst = qmi_tmd_init(pas->dev, desc->tmd_instance_id, tmd_names, >> + desc->num_tmd); > > And this makes it even more strange. Can there be holes in the > tmd_names? Can platform omit some of the TMDs? Assumingly yes, this > is not correct (nor is devm_kcalloc). thanks for review. For example, if the static table contains: tmd1 -> id 0 tmd2 -> id 1 tmd3 -> id 2 but firmware reports only tmd1 and tmd3, then cooling devices are registered only for IDs 0 and 2. No cooling device is registered for tmd2, so the corresponding DT cooling-device binding will not happen. The devm_kcalloc() is still needed because qmi_tmd_init() expects an indexed name array matching the DT cooling-device IDs. The current static mapping assumes those IDs are dense, so there are no holes in the mapping array itself. > >> + if (IS_ERR(tmd_inst)) { >> + ret = PTR_ERR(tmd_inst); >> + if (ret == -ENODEV) >> + return 0; >> + >> + return ret; >> + } >> + >> + pas->tmd_inst = tmd_inst; >> + >> + return 0; >> +} >> + >> static int qcom_pas_probe(struct platform_device *pdev) >> { >> const struct qcom_pas_data *desc; >> @@ -925,16 +1002,24 @@ static int qcom_pas_probe(struct platform_device *pdev) >> if (desc->early_boot) >> pas->rproc->state = RPROC_DETACHED; >> >> - ret = rproc_add(rproc); >> + ret = qcom_pas_setup_tmd(pas, desc); >> if (ret) >> goto remove_ssr_sysmon; >> >> + ret = rproc_add(rproc); >> + if (ret) >> + goto remove_setup_tmd; >> + >> node = of_get_compatible_child(pdev->dev.of_node, "qcom,bam-dmux"); >> pas->bam_dmux = of_platform_device_create(node, NULL, &pdev->dev); >> of_node_put(node); >> >> return 0; >> >> +remove_setup_tmd: >> + if (pas->tmd_inst) >> + qmi_tmd_exit(pas->tmd_inst); >> + >> remove_ssr_sysmon: >> qcom_remove_ssr_subdev(rproc, &pas->ssr_subdev); >> qcom_remove_sysmon_subdev(pas->sysmon); >> @@ -960,6 +1045,9 @@ static void qcom_pas_remove(struct platform_device *pdev) >> if (pas->bam_dmux) >> of_platform_device_destroy(&pas->bam_dmux->dev, NULL); >> >> + if (pas->tmd_inst) >> + qmi_tmd_exit(pas->tmd_inst); >> + >> rproc_del(pas->rproc); >> >> qcom_q6v5_deinit(&pas->q6v5); >> >> -- >> 2.34.1 >> >