* [PATCH v3 0/8] Add support for Qualcomm remoteproc subsystem cooling
@ 2026-06-09 10:22 Gaurav Kohli
2026-06-09 10:22 ` [PATCH v3 1/8] dt-bindings: remoteproc: qcom,pas: add thermal mitigation properties Gaurav Kohli
` (7 more replies)
0 siblings, 8 replies; 18+ messages in thread
From: Gaurav Kohli @ 2026-06-09 10:22 UTC (permalink / raw)
To: Bjorn Andersson, Mathieu Poirier, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Daniel Lezcano, Amit Kucheria,
Manivannan Sadhasivam, Konrad Dybcio, Gaurav Kohli, Kees Cook,
Gustavo A. R. Silva, cros-qcom-dts-watchers
Cc: linux-arm-msm, linux-remoteproc, devicetree, linux-kernel,
linux-pm, linux-hardening, Manaf Meethalavalappu Pallikunhi,
Casey Connolly, Dipa Ramesh Mantre
This series introduces a QMI TMD (Qualcomm Messaging Interface-based
Thermal Mitigation Device) helper library to control thermal mitigation
devices on remote subsystems such as the Modem and CDSP.
The objective is to enable thermal mitigation for Qualcomm remote
subsystems (for example, modem and CDSP) by using subsystem
temperature data into the existing Linux thermal framework.
Major functionality provided by this series:
-> Initializes a QMI handle and performs TMD service discovery
-> Monitors TMD service availability (arrival/removal)
-> Creates cooling devices from DT-provided TMD names
-> Supports multiple mitigation devices per subsystem via index-based
binding
-> Sends cooling-state updates to remote TMD endpoints
To support cooling device with id (index-based binding), this series depends on:
https://lore.kernel.org/all/20260526140802.1059293-12-daniel.lezcano@oss.qualcomm.com/
This series also revives qmi-cooling from Casey’s earlier QMI cooling series:
https://lore.kernel.org/linux-devicetree/20230905-caleb-qmi_cooling-v1-0-5aa39d4164a7@linaro.org/
Key design differences from the earlier series:
->Integrates qmi-cooling as a library and hooks probe/unregister into
the remoteproc core framework
->Uses an index-based API for cooling-device binding
->Cleans up the macro name and removes unused code
---
Changes in v3:
- Removed the remoteproc-cooling abstraction approach.
- Integerated QMI TMD with remoteproc core framework.
- Cleaned the macro names and removed unused code.
- Switched to index-based thermal_of_cooling_device_register() api.
- Link to v2: https://lore.kernel.org/linux-devicetree/20260127155722.2797783-1-gaurav.kohli@oss.qualcomm.com/
Changes in v2:
- Update Remoreproc thermal config to tristate and removed unnecessary NULL checks.
- Fixed dt binding file format and added generic name support for cdsp.
- Fixed memory leak and cleaned up qmi-cooling driver file.
- Corrected DT formatting errors and commit descriptions for all targets.
- Link to v1: https://lore.kernel.org/linux-devicetree/20251223123227.1317244-1-gaurav.kohli@oss.qualcomm.com/
---
---
Casey Connolly (1):
soc: qcom: Add support for QMI TMD cooling devices
Dipa Ramesh Mantre (1):
arm64: dts: qcom: hamoa: Enable CDSP cooling
Gaurav Kohli (6):
dt-bindings: remoteproc: qcom,pas: add thermal mitigation properties
remoteproc: qcom: pas: register TMD thermal cooling devices
arm64: dts: qcom: kodiak: Enable CDSP & Modem cooling
arm64: dts: qcom: lemans: Enable CDSP cooling
arm64: dts: qcom: talos: Enable CDSP cooling
arm64: dts: qcom: monaco: Enable CDSP cooling
.../bindings/remoteproc/qcom,pas-common.yaml | 14 +
MAINTAINERS | 6 +
arch/arm64/boot/dts/qcom/hamoa.dtsi | 63 +++
arch/arm64/boot/dts/qcom/kodiak.dtsi | 127 ++++-
arch/arm64/boot/dts/qcom/lemans.dtsi | 126 ++++-
arch/arm64/boot/dts/qcom/monaco.dtsi | 99 ++++
.../boot/dts/qcom/qcs6490-radxa-dragon-q6a.dts | 17 +
.../dts/qcom/qcs6490-thundercomm-minipc-g1iot.dts | 17 +
.../boot/dts/qcom/qcs6490-thundercomm-rubikpi3.dts | 17 +
.../boot/dts/qcom/sc7280-herobrine-lte-sku.dtsi | 18 +
.../boot/dts/qcom/sc7280-herobrine-wifi-sku.dtsi | 16 +
arch/arm64/boot/dts/qcom/talos.dtsi | 19 +
drivers/remoteproc/Kconfig | 1 +
drivers/remoteproc/qcom_q6v5_pas.c | 61 ++-
drivers/soc/qcom/Kconfig | 10 +
drivers/soc/qcom/Makefile | 1 +
drivers/soc/qcom/qmi_tmd.c | 604 +++++++++++++++++++++
include/linux/soc/qcom/qmi.h | 1 +
include/linux/soc/qcom/qmi_tmd.h | 23 +
19 files changed, 1223 insertions(+), 17 deletions(-)
---
base-commit: a87737435cfa134f9cdcc696ba3080759d04cf72
change-id: 20260609-qmi-tmd-383d30e1a60a
Best regards,
--
Gaurav Kohli <gaurav.kohli@oss.qualcomm.com>
^ permalink raw reply [flat|nested] 18+ messages in thread
* [PATCH v3 1/8] dt-bindings: remoteproc: qcom,pas: add thermal mitigation properties
2026-06-09 10:22 [PATCH v3 0/8] Add support for Qualcomm remoteproc subsystem cooling Gaurav Kohli
@ 2026-06-09 10:22 ` Gaurav Kohli
2026-06-09 10:36 ` sashiko-bot
2026-06-09 10:47 ` Dmitry Baryshkov
2026-06-09 10:22 ` [PATCH v3 2/8] soc: qcom: Add support for QMI TMD cooling devices Gaurav Kohli
` (6 subsequent siblings)
7 siblings, 2 replies; 18+ messages in thread
From: Gaurav Kohli @ 2026-06-09 10:22 UTC (permalink / raw)
To: Bjorn Andersson, Mathieu Poirier, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Daniel Lezcano, Amit Kucheria,
Manivannan Sadhasivam, Konrad Dybcio, Gaurav Kohli, Kees Cook,
Gustavo A. R. Silva, cros-qcom-dts-watchers
Cc: linux-arm-msm, linux-remoteproc, devicetree, linux-kernel,
linux-pm, linux-hardening, Manaf Meethalavalappu Pallikunhi
Document Qualcomm PAS remoteproc thermal mitigation properties used for
QMI-based throttling.
Add:
- #cooling-cells (2 or 3)
- tmd-names (thermal mitigation device names)
Signed-off-by: Gaurav Kohli <gaurav.kohli@oss.qualcomm.com>
---
.../devicetree/bindings/remoteproc/qcom,pas-common.yaml | 14 ++++++++++++++
1 file changed, 14 insertions(+)
diff --git a/Documentation/devicetree/bindings/remoteproc/qcom,pas-common.yaml b/Documentation/devicetree/bindings/remoteproc/qcom,pas-common.yaml
index 4607b459131b..0d07a0750762 100644
--- a/Documentation/devicetree/bindings/remoteproc/qcom,pas-common.yaml
+++ b/Documentation/devicetree/bindings/remoteproc/qcom,pas-common.yaml
@@ -79,6 +79,20 @@ properties:
channels and devices related to the ADSP.
unevaluatedProperties: false
+ '#cooling-cells':
+ description:
+ Number of cooling cells; 2 for min/max cooling state and 3 when
+ selecting a thermal mitigation device index.
+ enum: [2, 3]
+
+ tmd-names:
+ $ref: /schemas/types.yaml#/definitions/string-array
+ description:
+ Names of the thermal mitigation devices available in remote processor
+ subsystem.
+ minItems: 1
+ maxItems: 5
+
glink-edge:
$ref: /schemas/remoteproc/qcom,glink-edge.yaml#
description:
--
2.34.1
^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCH v3 2/8] soc: qcom: Add support for QMI TMD cooling devices
2026-06-09 10:22 [PATCH v3 0/8] Add support for Qualcomm remoteproc subsystem cooling Gaurav Kohli
2026-06-09 10:22 ` [PATCH v3 1/8] dt-bindings: remoteproc: qcom,pas: add thermal mitigation properties Gaurav Kohli
@ 2026-06-09 10:22 ` Gaurav Kohli
2026-06-09 10:37 ` sashiko-bot
2026-06-09 11:30 ` Dmitry Baryshkov
2026-06-09 10:22 ` [PATCH v3 3/8] remoteproc: qcom: pas: register TMD thermal " Gaurav Kohli
` (5 subsequent siblings)
7 siblings, 2 replies; 18+ messages in thread
From: Gaurav Kohli @ 2026-06-09 10:22 UTC (permalink / raw)
To: Bjorn Andersson, Mathieu Poirier, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Daniel Lezcano, Amit Kucheria,
Manivannan Sadhasivam, Konrad Dybcio, Gaurav Kohli, Kees Cook,
Gustavo A. R. Silva, cros-qcom-dts-watchers
Cc: linux-arm-msm, linux-remoteproc, devicetree, linux-kernel,
linux-pm, linux-hardening, Manaf Meethalavalappu Pallikunhi,
Casey Connolly
From: Casey Connolly <casey.connolly@linaro.org>
Add a Qualcomm QMI Thermal Mitigation Device (TMD) to support thermal
cooling devices backed by remote subsystems.
On several Qualcomm platforms, remote processors (for example modem and
CDSP) expose thermal mitigation controls through the TMD QMI service.
Client drivers need a way to discover that service, map DT thermal
mitigation endpoints to cooling devices, and forward cooling state
updates to the remote subsystem.
Co-developed-by: Gaurav Kohli <gaurav.kohli@oss.qualcomm.com>
Signed-off-by: Gaurav Kohli <gaurav.kohli@oss.qualcomm.com>
Signed-off-by: Casey Connolly <casey.connolly@linaro.org>
Signed-off-by: Daniel Lezcano <daniel.lezcano@oss.qualcomm.com>
---
MAINTAINERS | 6 +
drivers/soc/qcom/Kconfig | 10 +
drivers/soc/qcom/Makefile | 1 +
drivers/soc/qcom/qmi_tmd.c | 604 +++++++++++++++++++++++++++++++++++++++
include/linux/soc/qcom/qmi.h | 1 +
include/linux/soc/qcom/qmi_tmd.h | 23 ++
6 files changed, 645 insertions(+)
diff --git a/MAINTAINERS b/MAINTAINERS
index 57656ec0e9d5..3d60702a655a 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -22286,6 +22286,12 @@ F: Documentation/devicetree/bindings/net/qcom,ipq9574-ppe.yaml
F: Documentation/networking/device_drivers/ethernet/qualcomm/ppe/ppe.rst
F: drivers/net/ethernet/qualcomm/ppe/
+QUALCOMM QMI (REMOTEPROC THERMAL MITIGATION) TMD
+M: Gaurav Kohli <gaurav.kohli@oss.qualcomm.com>
+L: linux-arm-msm@vger.kernel.org
+L: linux-pm@vger.kernel.org
+F: drivers/soc/qcom/qmi_tmd.c
+
QUALCOMM QSEECOM DRIVER
M: Maximilian Luz <luzmaximilian@gmail.com>
L: linux-arm-msm@vger.kernel.org
diff --git a/drivers/soc/qcom/Kconfig b/drivers/soc/qcom/Kconfig
index 2caadbbcf830..a292ce57fd4a 100644
--- a/drivers/soc/qcom/Kconfig
+++ b/drivers/soc/qcom/Kconfig
@@ -128,6 +128,16 @@ config QCOM_QMI_HELPERS
tristate
depends on NET
+config QCOM_QMI_TMD
+ bool "Qualcomm QMI TMD library" if COMPILE_TEST
+ depends on ARCH_QCOM
+ select QCOM_QMI_HELPERS
+ help
+ This enables the QMI-based Thermal Mitigation Device (TMD) library
+ for Qualcomm remote subsystems. The library manages TMD messaging and
+ handles QMI communication with remote processors (modem, CDSP) to
+ exchange mitigation state and apply thermal mitigation requests.
+
config QCOM_RAMP_CTRL
tristate "Qualcomm Ramp Controller driver"
depends on ARCH_QCOM || COMPILE_TEST
diff --git a/drivers/soc/qcom/Makefile b/drivers/soc/qcom/Makefile
index b7f1d2a57367..4544e61c74e7 100644
--- a/drivers/soc/qcom/Makefile
+++ b/drivers/soc/qcom/Makefile
@@ -14,6 +14,7 @@ obj-$(CONFIG_QCOM_PMIC_GLINK) += pmic_glink.o
obj-$(CONFIG_QCOM_PMIC_GLINK) += pmic_glink_altmode.o
obj-$(CONFIG_QCOM_PMIC_PDCHARGER_ULOG) += pmic_pdcharger_ulog.o
CFLAGS_pmic_pdcharger_ulog.o := -I$(src)
+obj-$(CONFIG_QCOM_QMI_TMD) += qmi_tmd.o
obj-$(CONFIG_QCOM_QMI_HELPERS) += qmi_helpers.o
qmi_helpers-y += qmi_encdec.o qmi_interface.o
obj-$(CONFIG_QCOM_RAMP_CTRL) += ramp_controller.o
diff --git a/drivers/soc/qcom/qmi_tmd.c b/drivers/soc/qcom/qmi_tmd.c
new file mode 100644
index 000000000000..9d88ae48c864
--- /dev/null
+++ b/drivers/soc/qcom/qmi_tmd.c
@@ -0,0 +1,604 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2025, Linaro Limited
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
+ *
+ * QMI Thermal Mitigation Device (TMD) library.
+ * This library provides cooling device support for remote subsystems
+ * (modem and CDSP) running the TMD service via QMI.
+ */
+#include <linux/cleanup.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/net.h>
+#include <linux/of.h>
+#include <linux/slab.h>
+#include <linux/soc/qcom/qmi.h>
+#include <linux/soc/qcom/qmi_tmd.h>
+#include <linux/thermal.h>
+
+#define QMI_TMD_INSTANCE_MODEM 0x0
+#define QMI_TMD_INSTANCE_CDSP 0x43
+#define QMI_TMD_INSTANCE_CDSP1 0x44
+
+#define QMI_TMD_SERVICE_VERS_V01 0x01
+
+#define QMI_TMD_SET_LEVEL_REQ 0x0021
+#define QMI_TMD_GET_DEV_LIST_REQ 0x0020
+
+#define QMI_TMD_DEV_ID_LEN_MAX 32
+#define QMI_TMD_DEV_LIST_MAX 32
+#define QMI_TMD_RESP_TIMEOUT msecs_to_jiffies(100)
+#define TMD_GET_LEVEL_REQ_MAX_LEN 36
+#define TMD_SET_LEVEL_REQ_MAX_LEN 40
+
+#define TMD_GET_DEV_LIST_REQ_MAX_LEN 0
+#define TMD_GET_DEV_LIST_RESP_MAX_LEN 1099
+
+struct tmd_dev_id {
+ char mitigation_dev_id[QMI_TMD_DEV_ID_LEN_MAX + 1];
+};
+
+static const struct qmi_elem_info tmd_dev_id_ei[] = {
+ {
+ .data_type = QMI_STRING,
+ .elem_len = QMI_TMD_DEV_ID_LEN_MAX + 1,
+ .elem_size = sizeof(char),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0,
+ .offset = offsetof(struct tmd_dev_id,
+ mitigation_dev_id),
+ },
+ {
+ .data_type = QMI_EOTI,
+ .array_type = NO_ARRAY,
+ .tlv_type = QMI_COMMON_TLV_TYPE,
+ },
+};
+
+struct tmd_dev_list {
+ struct tmd_dev_id mitigation_dev_id;
+ u8 max_mitigation_level;
+};
+
+static const struct qmi_elem_info tmd_dev_list_ei[] = {
+ {
+ .data_type = QMI_STRUCT,
+ .elem_len = 1,
+ .elem_size = sizeof(struct tmd_dev_id),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0,
+ .offset = offsetof(struct tmd_dev_list,
+ mitigation_dev_id),
+ .ei_array = tmd_dev_id_ei,
+ },
+ {
+ .data_type = QMI_UNSIGNED_1_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(uint8_t),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0,
+ .offset = offsetof(struct tmd_dev_list,
+ max_mitigation_level),
+ },
+ {
+ .data_type = QMI_EOTI,
+ .array_type = NO_ARRAY,
+ .tlv_type = QMI_COMMON_TLV_TYPE,
+ },
+};
+
+struct tmd_get_dev_list_req {
+ char placeholder;
+};
+
+static const struct qmi_elem_info tmd_get_dev_list_req_ei[] = {
+ {
+ .data_type = QMI_EOTI,
+ .array_type = NO_ARRAY,
+ .tlv_type = QMI_COMMON_TLV_TYPE,
+ },
+};
+
+struct tmd_get_dev_list_resp {
+ struct qmi_response_type_v01 resp;
+ u8 mitigation_device_list_valid;
+ u32 mitigation_device_list_len;
+ struct tmd_dev_list
+ mitigation_device_list[QMI_TMD_DEV_LIST_MAX];
+};
+
+static const struct qmi_elem_info tmd_get_dev_list_resp_ei[] = {
+ {
+ .data_type = QMI_STRUCT,
+ .elem_len = 1,
+ .elem_size = sizeof(struct qmi_response_type_v01),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x02,
+ .offset = offsetof(struct tmd_get_dev_list_resp,
+ resp),
+ .ei_array = qmi_response_type_v01_ei,
+ },
+ {
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(uint8_t),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x10,
+ .offset = offsetof(struct tmd_get_dev_list_resp,
+ mitigation_device_list_valid),
+ },
+ {
+ .data_type = QMI_DATA_LEN,
+ .elem_len = 1,
+ .elem_size = sizeof(uint8_t),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x10,
+ .offset = offsetof(struct tmd_get_dev_list_resp,
+ mitigation_device_list_len),
+ },
+ {
+ .data_type = QMI_STRUCT,
+ .elem_len = QMI_TMD_DEV_LIST_MAX,
+ .elem_size = sizeof(struct tmd_dev_list),
+ .array_type = VAR_LEN_ARRAY,
+ .tlv_type = 0x10,
+ .offset = offsetof(struct tmd_get_dev_list_resp,
+ mitigation_device_list),
+ .ei_array = tmd_dev_list_ei,
+ },
+ {
+ .data_type = QMI_EOTI,
+ .array_type = NO_ARRAY,
+ .tlv_type = QMI_COMMON_TLV_TYPE,
+ },
+};
+
+struct tmd_set_level_req {
+ struct tmd_dev_id mitigation_dev_id;
+ u8 mitigation_level;
+};
+
+static const struct qmi_elem_info tmd_set_level_req_ei[] = {
+ {
+ .data_type = QMI_STRUCT,
+ .elem_len = 1,
+ .elem_size = sizeof(struct tmd_dev_id),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x01,
+ .offset = offsetof(struct tmd_set_level_req,
+ mitigation_dev_id),
+ .ei_array = tmd_dev_id_ei,
+ },
+ {
+ .data_type = QMI_UNSIGNED_1_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(uint8_t),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x02,
+ .offset = offsetof(struct tmd_set_level_req,
+ mitigation_level),
+ },
+ {
+ .data_type = QMI_EOTI,
+ .array_type = NO_ARRAY,
+ .tlv_type = QMI_COMMON_TLV_TYPE,
+ },
+};
+
+struct tmd_set_level_resp {
+ struct qmi_response_type_v01 resp;
+};
+
+static const struct qmi_elem_info tmd_set_level_resp_ei[] = {
+ {
+ .data_type = QMI_STRUCT,
+ .elem_len = 1,
+ .elem_size = sizeof(struct qmi_response_type_v01),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x02,
+ .offset = offsetof(struct tmd_set_level_resp, resp),
+ .ei_array = qmi_response_type_v01_ei,
+ },
+ {
+ .data_type = QMI_EOTI,
+ .array_type = NO_ARRAY,
+ .tlv_type = QMI_COMMON_TLV_TYPE,
+ },
+};
+
+/**
+ * struct qmi_tmd - A TMD cooling device
+ * @name: The name of this tmd shared by the remote subsystem
+ * @cdev: Thermal cooling device handle
+ * @cur_state: The current mitigation state
+ * @max_state: The maximum state
+ * @qmi_tmd_cli: Parent QMI TMD client
+ */
+struct qmi_tmd {
+ const char *name;
+ struct thermal_cooling_device *cdev;
+ unsigned int cur_state;
+ unsigned int max_state;
+ struct qmi_tmd_client *qmi_tmd_cli;
+};
+
+/**
+ * struct qmi_tmd_client - QMI TMD client state
+ * @dev: Device associated with this instance
+ * @handle: QMI connection handle
+ * @mutex: Lock to synchronise QMI communication
+ * @connection_active: Whether or not we're connected to the QMI TMD service
+ * @svc_arrive_work: Work item for initialising when the TMD service starts
+ * @num_tmds: Number of tmds described in the device tree
+ * @tmds: An array of tmd structures
+ */
+struct qmi_tmd_client {
+ struct device *dev;
+ struct qmi_handle handle;
+ /* protects QMI transactions and connection_active */
+ struct mutex mutex;
+ bool connection_active;
+ struct work_struct svc_arrive_work;
+ int num_tmds;
+ struct qmi_tmd tmds[] __counted_by(num_tmds);
+};
+
+/* Notify the remote subsystem of the requested cooling state */
+static int qmi_tmd_send_state_request(struct qmi_tmd *tmd, int state)
+{
+ struct tmd_set_level_resp resp = { 0 };
+ struct tmd_set_level_req req = { 0 };
+ struct qmi_tmd_client *qmi_tmd_cli = tmd->qmi_tmd_cli;
+ struct qmi_txn txn;
+ int ret = 0;
+
+ guard(mutex)(&qmi_tmd_cli->mutex);
+
+ if (!qmi_tmd_cli->connection_active)
+ return 0;
+
+ strscpy(req.mitigation_dev_id.mitigation_dev_id, tmd->name,
+ QMI_TMD_DEV_ID_LEN_MAX + 1);
+ req.mitigation_level = state;
+
+ ret = qmi_txn_init(&qmi_tmd_cli->handle, &txn,
+ tmd_set_level_resp_ei, &resp);
+ if (ret < 0) {
+ dev_err(qmi_tmd_cli->dev, "qmi set state %d txn init failed for %s ret %d\n",
+ state, tmd->name, ret);
+ return ret;
+ }
+
+ ret = qmi_send_request(&qmi_tmd_cli->handle, NULL, &txn,
+ QMI_TMD_SET_LEVEL_REQ,
+ TMD_SET_LEVEL_REQ_MAX_LEN,
+ tmd_set_level_req_ei, &req);
+ if (ret < 0) {
+ dev_err(qmi_tmd_cli->dev, "qmi set state %d txn send failed for %s ret %d\n",
+ state, tmd->name, ret);
+ qmi_txn_cancel(&txn);
+ return ret;
+ }
+
+ ret = qmi_txn_wait(&txn, QMI_TMD_RESP_TIMEOUT);
+ if (ret < 0) {
+ dev_err(qmi_tmd_cli->dev, "qmi set state %d txn wait failed for %s ret %d\n",
+ state, tmd->name, ret);
+ return ret;
+ }
+
+ if (resp.resp.result != QMI_RESULT_SUCCESS_V01) {
+ dev_err(qmi_tmd_cli->dev,
+ "qmi set state %d failed for %s result %#x error %#x\n",
+ state, tmd->name,
+ resp.resp.result, resp.resp.error);
+ return -EREMOTEIO;
+ }
+
+ dev_dbg(qmi_tmd_cli->dev, "Requested state %d/%d for %s\n", state,
+ tmd->max_state, tmd->name);
+
+ return 0;
+}
+
+static int qmi_tmd_get_max_state(struct thermal_cooling_device *cdev,
+ unsigned long *state)
+{
+ struct qmi_tmd *tmd = cdev->devdata;
+
+ *state = tmd->max_state;
+
+ return 0;
+}
+
+static int qmi_tmd_get_cur_state(struct thermal_cooling_device *cdev,
+ unsigned long *state)
+{
+ struct qmi_tmd *tmd = cdev->devdata;
+
+ *state = tmd->cur_state;
+
+ return 0;
+}
+
+static int qmi_tmd_set_cur_state(struct thermal_cooling_device *cdev,
+ unsigned long state)
+{
+ struct qmi_tmd *tmd = cdev->devdata;
+ int ret;
+
+ if (state > tmd->max_state)
+ return -EINVAL;
+
+ if (tmd->cur_state == state)
+ return 0;
+
+ ret = qmi_tmd_send_state_request(tmd, state);
+ if (!ret)
+ tmd->cur_state = state;
+
+ return ret;
+}
+
+static const struct thermal_cooling_device_ops qmi_tmd_cooling_ops = {
+ .get_max_state = qmi_tmd_get_max_state,
+ .get_cur_state = qmi_tmd_get_cur_state,
+ .set_cur_state = qmi_tmd_set_cur_state,
+};
+
+static int qmi_tmd_register(struct qmi_tmd_client *qmi_tmd_cli,
+ const char *label, u8 max_state)
+{
+ struct device *dev = qmi_tmd_cli->dev;
+ struct qmi_tmd *tmd;
+ int index;
+
+ for (index = 0; index < qmi_tmd_cli->num_tmds; index++) {
+ tmd = &qmi_tmd_cli->tmds[index];
+
+ if (!strncasecmp(tmd->name, label,
+ QMI_TMD_DEV_ID_LEN_MAX + 1))
+ goto found;
+ }
+
+ dev_dbg(qmi_tmd_cli->dev,
+ "TMD '%s' available in firmware but not specified in DT\n",
+ label);
+ return 0;
+
+found:
+ tmd->max_state = max_state;
+
+ /*
+ * If the cooling device already exists then the QMI service went away and
+ * came back. So just make sure the current cooling device state is
+ * reflected on the remote side and then return.
+ */
+ if (tmd->cdev)
+ return qmi_tmd_send_state_request(tmd, tmd->cur_state);
+
+ tmd->cdev = thermal_of_cooling_device_register(dev->of_node, index,
+ label, tmd, &qmi_tmd_cooling_ops);
+ if (IS_ERR(tmd->cdev))
+ return PTR_ERR(tmd->cdev);
+
+ return 0;
+}
+
+static void qmi_tmd_unregister(struct qmi_tmd_client *qmi_tmd_cli)
+{
+ struct qmi_tmd *tmd;
+ int index;
+
+ for (index = 0; index < qmi_tmd_cli->num_tmds; index++) {
+ tmd = &qmi_tmd_cli->tmds[index];
+
+ if (!tmd->cdev)
+ continue;
+
+ thermal_cooling_device_unregister(tmd->cdev);
+ tmd->cdev = NULL;
+ }
+}
+
+static void qmi_tmd_svc_arrive(struct work_struct *work)
+{
+ struct qmi_tmd_client *qmi_tmd_cli =
+ container_of(work, struct qmi_tmd_client, svc_arrive_work);
+
+ struct tmd_get_dev_list_req req = { 0 };
+ struct tmd_get_dev_list_resp *resp __free(kfree) = NULL;
+ int ret, i;
+ struct qmi_txn txn;
+
+ resp = kzalloc_obj(*resp, GFP_KERNEL);
+ if (!resp) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ scoped_guard(mutex, &qmi_tmd_cli->mutex) {
+ ret = qmi_txn_init(&qmi_tmd_cli->handle, &txn,
+ tmd_get_dev_list_resp_ei, resp);
+ if (ret < 0)
+ goto out;
+
+ ret = qmi_send_request(&qmi_tmd_cli->handle, NULL, &txn,
+ QMI_TMD_GET_DEV_LIST_REQ,
+ TMD_GET_DEV_LIST_REQ_MAX_LEN,
+ tmd_get_dev_list_req_ei, &req);
+ if (ret < 0) {
+ qmi_txn_cancel(&txn);
+ goto out;
+ }
+
+ ret = qmi_txn_wait(&txn, QMI_TMD_RESP_TIMEOUT);
+ if (ret < 0)
+ goto out;
+
+ if (resp->resp.result != QMI_RESULT_SUCCESS_V01) {
+ ret = -EPROTO;
+ goto out;
+ }
+
+ qmi_tmd_cli->connection_active = true;
+ }
+
+ for (i = 0; i < resp->mitigation_device_list_len; i++) {
+ struct tmd_dev_list *device =
+ &resp->mitigation_device_list[i];
+
+ ret = qmi_tmd_register(qmi_tmd_cli,
+ device->mitigation_dev_id.mitigation_dev_id,
+ device->max_mitigation_level);
+ if (ret)
+ break;
+ }
+
+out:
+ if (ret)
+ dev_err(qmi_tmd_cli->dev, "Failed to initialize TMD service: %d\n", ret);
+}
+
+static void qmi_tmd_del_server(struct qmi_handle *qmi, struct qmi_service *service)
+{
+ struct qmi_tmd_client *qmi_tmd_cli =
+ container_of(qmi, struct qmi_tmd_client, handle);
+
+ kernel_sock_shutdown(qmi->sock, SHUT_RDWR);
+
+ scoped_guard(mutex, &qmi_tmd_cli->mutex)
+ qmi_tmd_cli->connection_active = false;
+}
+
+static int qmi_tmd_new_server(struct qmi_handle *qmi, struct qmi_service *service)
+{
+ struct sockaddr_qrtr sq = { AF_QIPCRTR, service->node, service->port };
+ struct qmi_tmd_client *qmi_tmd_cli;
+ int ret;
+
+ qmi_tmd_cli = container_of(qmi, struct qmi_tmd_client, handle);
+
+ scoped_guard(mutex, &qmi_tmd_cli->mutex) {
+ ret = kernel_connect(qmi->sock, (struct sockaddr_unsized *)&sq,
+ sizeof(sq), 0);
+ }
+
+ if (ret < 0) {
+ dev_err(qmi_tmd_cli->dev, "QMI connect failed for node %u port %u: %d\n",
+ service->node, service->port, ret);
+ return ret;
+ }
+
+ queue_work(system_highpri_wq, &qmi_tmd_cli->svc_arrive_work);
+
+ return 0;
+}
+
+static const struct qmi_ops qmi_tmd_ops = {
+ .new_server = qmi_tmd_new_server,
+ .del_server = qmi_tmd_del_server,
+};
+
+static int qmi_tmd_get_instance_id(const char *remoteproc_name)
+{
+ if (!strcmp(remoteproc_name, "modem"))
+ return QMI_TMD_INSTANCE_MODEM;
+
+ if (!strcmp(remoteproc_name, "cdsp"))
+ return QMI_TMD_INSTANCE_CDSP;
+
+ if (!strcmp(remoteproc_name, "cdsp1"))
+ return QMI_TMD_INSTANCE_CDSP1;
+
+ return -ENODEV;
+}
+
+/**
+ * qmi_tmd_init() - Initialize QMI TMD instance
+ * @dev: Device pointer
+ * @remoteproc_name: Remoteproc name (for example modem, cdsp)
+ * @tmd_names: Array of TMD names
+ * @num_tmds: Number of TMD names
+ *
+ * Return: Pointer to qmi_tmd_client on success, ERR_PTR on failure
+ */
+struct qmi_tmd_client *qmi_tmd_init(struct device *dev,
+ const char *remoteproc_name,
+ const char * const *tmd_names,
+ int num_tmds)
+{
+ struct qmi_tmd_client *qmi_tmd_cli;
+ int ret, i, instance_id;
+
+ if (!dev || !remoteproc_name || !tmd_names || num_tmds <= 0)
+ return ERR_PTR(-EINVAL);
+
+ instance_id = qmi_tmd_get_instance_id(remoteproc_name);
+ if (instance_id < 0) {
+ dev_err(dev, "Unsupported remoteproc name '%s' for TMD lookup\n",
+ remoteproc_name);
+ return ERR_PTR(instance_id);
+ }
+
+ qmi_tmd_cli = devm_kzalloc(dev, struct_size(qmi_tmd_cli, tmds, num_tmds), GFP_KERNEL);
+ if (!qmi_tmd_cli)
+ return ERR_PTR(-ENOMEM);
+
+ qmi_tmd_cli->dev = dev;
+ qmi_tmd_cli->num_tmds = num_tmds;
+ mutex_init(&qmi_tmd_cli->mutex);
+ INIT_WORK(&qmi_tmd_cli->svc_arrive_work, qmi_tmd_svc_arrive);
+
+ /* Initialize TMD structures */
+ for (i = 0; i < num_tmds; i++) {
+ qmi_tmd_cli->tmds[i].name = tmd_names[i];
+ qmi_tmd_cli->tmds[i].qmi_tmd_cli = qmi_tmd_cli;
+ }
+
+ ret = qmi_handle_init(&qmi_tmd_cli->handle,
+ TMD_GET_DEV_LIST_RESP_MAX_LEN,
+ &qmi_tmd_ops, NULL);
+ if (ret < 0) {
+ dev_err(dev, "QMI handle init failed: %d\n", ret);
+ return ERR_PTR(ret);
+ }
+
+ ret = qmi_add_lookup(&qmi_tmd_cli->handle, QMI_SERVICE_ID_TMD,
+ QMI_TMD_SERVICE_VERS_V01, instance_id);
+ if (ret < 0) {
+ dev_err(dev, "QMI add lookup failed: %d\n", ret);
+ goto err_release_handle;
+ }
+
+ return qmi_tmd_cli;
+
+err_release_handle:
+ qmi_handle_release(&qmi_tmd_cli->handle);
+
+ return ERR_PTR(ret);
+}
+EXPORT_SYMBOL_GPL(qmi_tmd_init);
+
+/**
+ * qmi_tmd_exit() - Deinitialize QMI TMD instance
+ * @qmi_tmd_cli: QMI TMD client to deinitialize
+ */
+void qmi_tmd_exit(struct qmi_tmd_client *qmi_tmd_cli)
+{
+ if (!qmi_tmd_cli)
+ return;
+
+ cancel_work_sync(&qmi_tmd_cli->svc_arrive_work);
+ qmi_handle_release(&qmi_tmd_cli->handle);
+ qmi_tmd_unregister(qmi_tmd_cli);
+
+ scoped_guard(mutex, &qmi_tmd_cli->mutex)
+ qmi_tmd_cli->connection_active = false;
+}
+EXPORT_SYMBOL_GPL(qmi_tmd_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Qualcomm QMI Thermal Mitigation library");
diff --git a/include/linux/soc/qcom/qmi.h b/include/linux/soc/qcom/qmi.h
index b9dcb437a0be..683d27cee413 100644
--- a/include/linux/soc/qcom/qmi.h
+++ b/include/linux/soc/qcom/qmi.h
@@ -96,6 +96,7 @@ struct qmi_elem_info {
* Enumerate the IDs of the QMI services
*/
#define QMI_SERVICE_ID_TEST 0x0f /* 15 */
+#define QMI_SERVICE_ID_TMD 0x18 /* 24 */
#define QMI_SERVICE_ID_SSCTL 0x2b /* 43 */
#define QMI_SERVICE_ID_IPA 0x31 /* 49 */
#define QMI_SERVICE_ID_SERVREG_LOC 0x40 /* 64 */
diff --git a/include/linux/soc/qcom/qmi_tmd.h b/include/linux/soc/qcom/qmi_tmd.h
new file mode 100644
index 000000000000..75373eb09d61
--- /dev/null
+++ b/include/linux/soc/qcom/qmi_tmd.h
@@ -0,0 +1,23 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) 2025, Linaro Limited
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
+ *
+ * QMI Thermal Mitigation Device (TMD) library header.
+ */
+
+#ifndef __QMI_TMD_H__
+#define __QMI_TMD_H__
+
+struct device;
+struct qmi_tmd_client;
+
+struct qmi_tmd_client *qmi_tmd_init(struct device *dev,
+ const char *remoteproc_name,
+ const char * const *tmd_names,
+ int num_tmds);
+
+void qmi_tmd_exit(struct qmi_tmd_client *tmd_cli);
+
+#endif /* __QMI_TMD_H__ */
+
--
2.34.1
^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCH v3 3/8] remoteproc: qcom: pas: register TMD thermal cooling devices
2026-06-09 10:22 [PATCH v3 0/8] Add support for Qualcomm remoteproc subsystem cooling Gaurav Kohli
2026-06-09 10:22 ` [PATCH v3 1/8] dt-bindings: remoteproc: qcom,pas: add thermal mitigation properties Gaurav Kohli
2026-06-09 10:22 ` [PATCH v3 2/8] soc: qcom: Add support for QMI TMD cooling devices Gaurav Kohli
@ 2026-06-09 10:22 ` Gaurav Kohli
2026-06-09 10:40 ` sashiko-bot
` (2 more replies)
2026-06-09 10:22 ` [PATCH v3 4/8] arm64: dts: qcom: kodiak: Enable CDSP & Modem cooling Gaurav Kohli
` (4 subsequent siblings)
7 siblings, 3 replies; 18+ messages in thread
From: Gaurav Kohli @ 2026-06-09 10:22 UTC (permalink / raw)
To: Bjorn Andersson, Mathieu Poirier, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Daniel Lezcano, Amit Kucheria,
Manivannan Sadhasivam, Konrad Dybcio, Gaurav Kohli, Kees Cook,
Gustavo A. R. Silva, cros-qcom-dts-watchers
Cc: linux-arm-msm, linux-remoteproc, devicetree, linux-kernel,
linux-pm, linux-hardening, Manaf Meethalavalappu Pallikunhi
Add support for Thermal Mitigation Devices (TMDs) to enable
thermal throttling of remote processors through QMI.
This enables the thermal framework to request mitigation when remote
subsystems (modem, CDSP) contribute to thermal issues.
Signed-off-by: Gaurav Kohli <gaurav.kohli@oss.qualcomm.com>
Signed-off-by: Daniel Lezcano <daniel.lezcano@oss.qualcomm.com>
---
drivers/remoteproc/Kconfig | 1 +
drivers/remoteproc/qcom_q6v5_pas.c | 61 +++++++++++++++++++++++++++++++++++++-
2 files changed, 61 insertions(+), 1 deletion(-)
diff --git a/drivers/remoteproc/Kconfig b/drivers/remoteproc/Kconfig
index c78e431b7b2d..cd8cc911e1be 100644
--- a/drivers/remoteproc/Kconfig
+++ b/drivers/remoteproc/Kconfig
@@ -228,6 +228,7 @@ config QCOM_Q6V5_PAS
select QCOM_PIL_INFO
select QCOM_MDT_LOADER
select QCOM_Q6V5_COMMON
+ select QCOM_QMI_TMD
select QCOM_RPROC_COMMON
select QCOM_SCM
help
diff --git a/drivers/remoteproc/qcom_q6v5_pas.c b/drivers/remoteproc/qcom_q6v5_pas.c
index da27d1d3c9da..1ad896de42fd 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>
@@ -24,6 +25,7 @@
#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>
@@ -120,6 +122,8 @@ struct qcom_pas {
struct qcom_scm_pas_context *pas_ctx;
struct qcom_scm_pas_context *dtb_pas_ctx;
+
+ struct qmi_tmd_client *tmd_inst;
};
static void qcom_pas_segment_dump(struct rproc *rproc,
@@ -733,6 +737,49 @@ static void qcom_pas_unassign_memory_region(struct qcom_pas *pas)
}
}
+static int qcom_pas_setup_tmd(struct qcom_pas *pas)
+{
+ struct device *dev = pas->dev;
+ struct device_node *np = dev->of_node;
+ const char **tmd_names;
+ int num_tmds, ret, i;
+
+ if (!of_find_property(np, "tmd-names", NULL))
+ return 0;
+
+ /* Get the TMD names array */
+ num_tmds = of_property_count_strings(np, "tmd-names");
+ if (num_tmds <= 0)
+ return 0;
+
+ tmd_names = devm_kcalloc(dev, num_tmds, sizeof(*tmd_names), GFP_KERNEL);
+ if (!tmd_names)
+ return -ENOMEM;
+
+ for (i = 0; i < num_tmds; i++) {
+ ret = of_property_read_string_index(np, "tmd-names", i,
+ &tmd_names[i]);
+ if (ret) {
+ dev_err(dev, "Failed to read tmd-names[%d]: %d\n", i, ret);
+ return ret;
+ }
+ }
+
+ pas->tmd_inst = qmi_tmd_init(dev, pas->info_name, tmd_names, num_tmds);
+ if (IS_ERR(pas->tmd_inst)) {
+ dev_err(dev, "Failed to register '%s'\n", pas->info_name);
+
+ ret = PTR_ERR(pas->tmd_inst);
+ if (ret == -ENODEV) {
+ pas->tmd_inst = NULL;
+ return 0;
+ }
+ return ret;
+ }
+
+ return 0;
+}
+
static int qcom_pas_probe(struct platform_device *pdev)
{
const struct qcom_pas_data *desc;
@@ -855,12 +902,21 @@ static int qcom_pas_probe(struct platform_device *pdev)
pas->pas_ctx->use_tzmem = rproc->has_iommu;
pas->dtb_pas_ctx->use_tzmem = rproc->has_iommu;
- ret = rproc_add(rproc);
+
+ ret = qcom_pas_setup_tmd(pas);
if (ret)
goto remove_ssr_sysmon;
+ ret = rproc_add(rproc);
+ if (ret)
+ goto remove_setup_tmd;
+
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);
@@ -883,6 +939,9 @@ static void qcom_pas_remove(struct platform_device *pdev)
{
struct qcom_pas *pas = platform_get_drvdata(pdev);
+ if (pas->tmd_inst)
+ qmi_tmd_exit(pas->tmd_inst);
+
rproc_del(pas->rproc);
qcom_q6v5_deinit(&pas->q6v5);
--
2.34.1
^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCH v3 4/8] arm64: dts: qcom: kodiak: Enable CDSP & Modem cooling
2026-06-09 10:22 [PATCH v3 0/8] Add support for Qualcomm remoteproc subsystem cooling Gaurav Kohli
` (2 preceding siblings ...)
2026-06-09 10:22 ` [PATCH v3 3/8] remoteproc: qcom: pas: register TMD thermal " Gaurav Kohli
@ 2026-06-09 10:22 ` Gaurav Kohli
2026-06-09 10:57 ` Dmitry Baryshkov
2026-06-09 10:23 ` [PATCH v3 5/8] arm64: dts: qcom: lemans: Enable CDSP cooling Gaurav Kohli
` (3 subsequent siblings)
7 siblings, 1 reply; 18+ messages in thread
From: Gaurav Kohli @ 2026-06-09 10:22 UTC (permalink / raw)
To: Bjorn Andersson, Mathieu Poirier, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Daniel Lezcano, Amit Kucheria,
Manivannan Sadhasivam, Konrad Dybcio, Gaurav Kohli, Kees Cook,
Gustavo A. R. Silva, cros-qcom-dts-watchers
Cc: linux-arm-msm, linux-remoteproc, devicetree, linux-kernel,
linux-pm, linux-hardening, Manaf Meethalavalappu Pallikunhi
Unlike the CPU, the CDSP/Modem does not throttle its speed automatically
when it reaches high temperatures in kodiak.
Set up CDSP cooling by throttling the cdsp when it reaches 100°C and
for modem when it reaches to 95°C.
Remove inherited mdmss cooling-map nodes for Non Modem kodiak variant.
Signed-off-by: Gaurav Kohli <gaurav.kohli@oss.qualcomm.com>
---
arch/arm64/boot/dts/qcom/kodiak.dtsi | 127 ++++++++++++++++++++-
.../boot/dts/qcom/qcs6490-radxa-dragon-q6a.dts | 17 +++
.../dts/qcom/qcs6490-thundercomm-minipc-g1iot.dts | 17 +++
.../boot/dts/qcom/qcs6490-thundercomm-rubikpi3.dts | 17 +++
.../boot/dts/qcom/sc7280-herobrine-lte-sku.dtsi | 18 +++
.../boot/dts/qcom/sc7280-herobrine-wifi-sku.dtsi | 16 +++
6 files changed, 208 insertions(+), 4 deletions(-)
diff --git a/arch/arm64/boot/dts/qcom/kodiak.dtsi b/arch/arm64/boot/dts/qcom/kodiak.dtsi
index fa540d8c2615..d345add2d8c8 100644
--- a/arch/arm64/boot/dts/qcom/kodiak.dtsi
+++ b/arch/arm64/boot/dts/qcom/kodiak.dtsi
@@ -3427,6 +3427,9 @@ remoteproc_mpss: remoteproc@4080000 {
qcom,smem-states = <&modem_smp2p_out 0>;
qcom,smem-state-names = "stop";
+ #cooling-cells = <3>;
+ tmd-names = "pa", "modem";
+
status = "disabled";
glink-edge {
@@ -4787,6 +4790,9 @@ remoteproc_cdsp: remoteproc@a300000 {
qcom,smem-states = <&cdsp_smp2p_out 0>;
qcom,smem-state-names = "stop";
+ #cooling-cells = <2>;
+ tmd-names = "cdsp_sw";
+
status = "disabled";
glink-edge {
@@ -4906,6 +4912,7 @@ compute-cb@14 {
};
};
};
+
};
usb_1: usb@a600000 {
@@ -7716,6 +7723,8 @@ map0 {
};
nspss0-thermal {
+ polling-delay-passive = <200>;
+
thermal-sensors = <&tsens1 3>;
trips {
@@ -7725,15 +7734,31 @@ nspss0_alert0: trip-point0 {
type = "hot";
};
+ nspss0_alert1: trip-point1 {
+ temperature = <100000>;
+ hysteresis = <5000>;
+ type = "passive";
+ };
+
nspss0_crit: nspss0-crit {
temperature = <110000>;
hysteresis = <0>;
type = "critical";
};
};
+
+ cooling-maps {
+ map0 {
+ trip = <&nspss0_alert1>;
+ cooling-device = <&remoteproc_cdsp THERMAL_NO_LIMIT
+ THERMAL_NO_LIMIT>;
+ };
+ };
};
nspss1-thermal {
+ polling-delay-passive = <200>;
+
thermal-sensors = <&tsens1 4>;
trips {
@@ -7743,12 +7768,26 @@ nspss1_alert0: trip-point0 {
type = "hot";
};
+ nspss1_alert1: trip-point1 {
+ temperature = <100000>;
+ hysteresis = <5000>;
+ type = "passive";
+ };
+
nspss1_crit: nspss1-crit {
temperature = <110000>;
hysteresis = <0>;
type = "critical";
};
};
+
+ cooling-maps {
+ map0 {
+ trip = <&nspss1_alert1>;
+ cooling-device = <&remoteproc_cdsp THERMAL_NO_LIMIT
+ THERMAL_NO_LIMIT>;
+ };
+ };
};
video-thermal {
@@ -7787,7 +7826,9 @@ ddr_crit: ddr-crit {
};
};
- mdmss0-thermal {
+ mdmss0_thermal: mdmss0-thermal {
+ polling-delay-passive = <200>;
+
thermal-sensors = <&tsens1 7>;
trips {
@@ -7797,15 +7838,35 @@ mdmss0_alert0: trip-point0 {
type = "hot";
};
+ mdmss0_alert1: trip-point1 {
+ temperature = <95000>;
+ hysteresis = <2000>;
+ type = "passive";
+ };
+
mdmss0_crit: mdmss0-crit {
temperature = <110000>;
hysteresis = <0>;
type = "critical";
};
};
+
+ cooling-maps {
+ map0 {
+ trip = <&mdmss0_alert1>;
+ cooling-device = <&remoteproc_mpss 0 0 2>;
+ };
+
+ map1 {
+ trip = <&mdmss0_alert1>;
+ cooling-device = <&remoteproc_mpss 1 0 2>;
+ };
+ };
};
- mdmss1-thermal {
+ mdmss1_thermal: mdmss1-thermal {
+ polling-delay-passive = <200>;
+
thermal-sensors = <&tsens1 8>;
trips {
@@ -7815,15 +7876,35 @@ mdmss1_alert0: trip-point0 {
type = "hot";
};
+ mdmss1_alert1: trip-point1 {
+ temperature = <95000>;
+ hysteresis = <2000>;
+ type = "passive";
+ };
+
mdmss1_crit: mdmss1-crit {
temperature = <110000>;
hysteresis = <0>;
type = "critical";
};
};
+
+ cooling-maps {
+ map0 {
+ trip = <&mdmss1_alert1>;
+ cooling-device = <&remoteproc_mpss 0 0 2>;
+ };
+
+ map1 {
+ trip = <&mdmss1_alert1>;
+ cooling-device = <&remoteproc_mpss 1 0 2>;
+ };
+ };
};
- mdmss2-thermal {
+ mdmss2_thermal: mdmss2-thermal {
+ polling-delay-passive = <200>;
+
thermal-sensors = <&tsens1 9>;
trips {
@@ -7833,15 +7914,35 @@ mdmss2_alert0: trip-point0 {
type = "hot";
};
+ mdmss2_alert1: trip-point1 {
+ temperature = <95000>;
+ hysteresis = <2000>;
+ type = "passive";
+ };
+
mdmss2_crit: mdmss2-crit {
temperature = <110000>;
hysteresis = <0>;
type = "critical";
};
};
+
+ cooling-maps {
+ map0 {
+ trip = <&mdmss2_alert1>;
+ cooling-device = <&remoteproc_mpss 0 0 2>;
+ };
+
+ map1 {
+ trip = <&mdmss2_alert1>;
+ cooling-device = <&remoteproc_mpss 1 0 2>;
+ };
+ };
};
- mdmss3-thermal {
+ mdmss3_thermal: mdmss3-thermal {
+ polling-delay-passive = <200>;
+
thermal-sensors = <&tsens1 10>;
trips {
@@ -7851,12 +7952,30 @@ mdmss3_alert0: trip-point0 {
type = "hot";
};
+ mdmss3_alert1: trip-point1 {
+ temperature = <95000>;
+ hysteresis = <2000>;
+ type = "passive";
+ };
+
mdmss3_crit: mdmss3-crit {
temperature = <110000>;
hysteresis = <0>;
type = "critical";
};
};
+
+ cooling-maps {
+ map0 {
+ trip = <&mdmss3_alert1>;
+ cooling-device = <&remoteproc_mpss 0 0 2>;
+ };
+
+ map1 {
+ trip = <&mdmss3_alert1>;
+ cooling-device = <&remoteproc_mpss 1 0 2>;
+ };
+ };
};
camera0-thermal {
diff --git a/arch/arm64/boot/dts/qcom/qcs6490-radxa-dragon-q6a.dts b/arch/arm64/boot/dts/qcom/qcs6490-radxa-dragon-q6a.dts
index bb5a42b038f1..400d128132fc 100644
--- a/arch/arm64/boot/dts/qcom/qcs6490-radxa-dragon-q6a.dts
+++ b/arch/arm64/boot/dts/qcom/qcs6490-radxa-dragon-q6a.dts
@@ -24,6 +24,23 @@
/delete-node/ &adsp_mem;
/delete-node/ &cdsp_mem;
/delete-node/ &ipa_fw_mem;
+
+&mdmss0_thermal {
+ /delete-node/ cooling-maps;
+};
+
+&mdmss1_thermal {
+ /delete-node/ cooling-maps;
+};
+
+&mdmss2_thermal {
+ /delete-node/ cooling-maps;
+};
+
+&mdmss3_thermal {
+ /delete-node/ cooling-maps;
+};
+
/delete-node/ &mpss_mem;
/delete-node/ &remoteproc_mpss;
/delete-node/ &remoteproc_wpss;
diff --git a/arch/arm64/boot/dts/qcom/qcs6490-thundercomm-minipc-g1iot.dts b/arch/arm64/boot/dts/qcom/qcs6490-thundercomm-minipc-g1iot.dts
index a5ad796cb65d..1e190ed18ae5 100644
--- a/arch/arm64/boot/dts/qcom/qcs6490-thundercomm-minipc-g1iot.dts
+++ b/arch/arm64/boot/dts/qcom/qcs6490-thundercomm-minipc-g1iot.dts
@@ -22,6 +22,23 @@
/delete-node/ &cdsp_mem;
/delete-node/ &ipa_fw_mem;
/delete-node/ &mpss_mem;
+
+&mdmss0_thermal {
+ /delete-node/ cooling-maps;
+};
+
+&mdmss1_thermal {
+ /delete-node/ cooling-maps;
+};
+
+&mdmss2_thermal {
+ /delete-node/ cooling-maps;
+};
+
+&mdmss3_thermal {
+ /delete-node/ cooling-maps;
+};
+
/delete-node/ &remoteproc_mpss;
/delete-node/ &remoteproc_wpss;
/delete-node/ &rmtfs_mem;
diff --git a/arch/arm64/boot/dts/qcom/qcs6490-thundercomm-rubikpi3.dts b/arch/arm64/boot/dts/qcom/qcs6490-thundercomm-rubikpi3.dts
index f47efca42d48..8e8dd4efd8c0 100644
--- a/arch/arm64/boot/dts/qcom/qcs6490-thundercomm-rubikpi3.dts
+++ b/arch/arm64/boot/dts/qcom/qcs6490-thundercomm-rubikpi3.dts
@@ -23,6 +23,23 @@
/delete-node/ &adsp_mem;
/delete-node/ &cdsp_mem;
/delete-node/ &ipa_fw_mem;
+
+&mdmss0_thermal {
+ /delete-node/ cooling-maps;
+};
+
+&mdmss1_thermal {
+ /delete-node/ cooling-maps;
+};
+
+&mdmss2_thermal {
+ /delete-node/ cooling-maps;
+};
+
+&mdmss3_thermal {
+ /delete-node/ cooling-maps;
+};
+
/delete-node/ &mpss_mem;
/delete-node/ &remoteproc_mpss;
/delete-node/ &remoteproc_wpss;
diff --git a/arch/arm64/boot/dts/qcom/sc7280-herobrine-lte-sku.dtsi b/arch/arm64/boot/dts/qcom/sc7280-herobrine-lte-sku.dtsi
index b721a8546800..e2c0a317ecb8 100644
--- a/arch/arm64/boot/dts/qcom/sc7280-herobrine-lte-sku.dtsi
+++ b/arch/arm64/boot/dts/qcom/sc7280-herobrine-lte-sku.dtsi
@@ -26,8 +26,26 @@ &ipa {
status = "okay";
};
+&mdmss0_thermal {
+ /delete-node/ cooling-maps;
+};
+
+&mdmss1_thermal {
+ /delete-node/ cooling-maps;
+};
+
+&mdmss2_thermal {
+ /delete-node/ cooling-maps;
+};
+
+&mdmss3_thermal {
+ /delete-node/ cooling-maps;
+};
+
&remoteproc_mpss {
compatible = "qcom,sc7280-mss-pil";
+ /delete-property/ tmd-names;
+ /delete-property/ #cooling-cells;
reg = <0 0x04080000 0 0x10000>, <0 0x04180000 0 0x48>;
reg-names = "qdsp6", "rmb";
diff --git a/arch/arm64/boot/dts/qcom/sc7280-herobrine-wifi-sku.dtsi b/arch/arm64/boot/dts/qcom/sc7280-herobrine-wifi-sku.dtsi
index 3ebc915f0dc2..6642076f62c4 100644
--- a/arch/arm64/boot/dts/qcom/sc7280-herobrine-wifi-sku.dtsi
+++ b/arch/arm64/boot/dts/qcom/sc7280-herobrine-wifi-sku.dtsi
@@ -7,6 +7,22 @@
/* WIFI SKUs save 256M by not having modem/mba/rmtfs memory regions defined. */
+&mdmss0_thermal {
+ /delete-node/ cooling-maps;
+};
+
+&mdmss1_thermal {
+ /delete-node/ cooling-maps;
+};
+
+&mdmss2_thermal {
+ /delete-node/ cooling-maps;
+};
+
+&mdmss3_thermal {
+ /delete-node/ cooling-maps;
+};
+
/delete-node/ &mpss_mem;
/delete-node/ &remoteproc_mpss;
/delete-node/ &rmtfs_mem;
--
2.34.1
^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCH v3 5/8] arm64: dts: qcom: lemans: Enable CDSP cooling
2026-06-09 10:22 [PATCH v3 0/8] Add support for Qualcomm remoteproc subsystem cooling Gaurav Kohli
` (3 preceding siblings ...)
2026-06-09 10:22 ` [PATCH v3 4/8] arm64: dts: qcom: kodiak: Enable CDSP & Modem cooling Gaurav Kohli
@ 2026-06-09 10:23 ` Gaurav Kohli
2026-06-09 10:23 ` [PATCH v3 6/8] arm64: dts: qcom: talos: " Gaurav Kohli
` (2 subsequent siblings)
7 siblings, 0 replies; 18+ messages in thread
From: Gaurav Kohli @ 2026-06-09 10:23 UTC (permalink / raw)
To: Bjorn Andersson, Mathieu Poirier, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Daniel Lezcano, Amit Kucheria,
Manivannan Sadhasivam, Konrad Dybcio, Gaurav Kohli, Kees Cook,
Gustavo A. R. Silva, cros-qcom-dts-watchers
Cc: linux-arm-msm, linux-remoteproc, devicetree, linux-kernel,
linux-pm, linux-hardening, Manaf Meethalavalappu Pallikunhi
Unlike the CPU, the CDSP does not throttle its speed automatically
when it reaches high temperatures in lemans.
Set up CDSP cooling for both instances by throttling the cdsp, when
it reaches 105°C.
Signed-off-by: Gaurav Kohli <gaurav.kohli@oss.qualcomm.com>
---
arch/arm64/boot/dts/qcom/lemans.dtsi | 126 +++++++++++++++++++++++++++++++----
1 file changed, 114 insertions(+), 12 deletions(-)
diff --git a/arch/arm64/boot/dts/qcom/lemans.dtsi b/arch/arm64/boot/dts/qcom/lemans.dtsi
index 353a6e6fd3ac..c55f95318707 100644
--- a/arch/arm64/boot/dts/qcom/lemans.dtsi
+++ b/arch/arm64/boot/dts/qcom/lemans.dtsi
@@ -7777,6 +7777,9 @@ remoteproc_cdsp0: remoteproc@26300000 {
qcom,smem-states = <&smp2p_cdsp0_out 0>;
qcom,smem-state-names = "stop";
+ #cooling-cells = <2>;
+ tmd-names = "cdsp_sw";
+
status = "disabled";
glink-edge {
@@ -7916,6 +7919,9 @@ remoteproc_cdsp1: remoteproc@2a300000 {
qcom,smem-states = <&smp2p_cdsp1_out 0>;
qcom,smem-state-names = "stop";
+ #cooling-cells = <2>;
+ tmd-names = "cdsp_sw";
+
status = "disabled";
glink-edge {
@@ -8764,7 +8770,7 @@ nsp-0-0-0-thermal {
thermal-sensors = <&tsens2 5>;
trips {
- trip-point0 {
+ nsp_0_0_0_alert0: trip-point0 {
temperature = <105000>;
hysteresis = <5000>;
type = "passive";
@@ -8776,6 +8782,14 @@ trip-point1 {
type = "passive";
};
};
+
+ cooling-maps {
+ map0 {
+ trip = <&nsp_0_0_0_alert0>;
+ cooling-device = <&remoteproc_cdsp0 THERMAL_NO_LIMIT
+ THERMAL_NO_LIMIT>;
+ };
+ };
};
nsp-0-1-0-thermal {
@@ -8784,7 +8798,7 @@ nsp-0-1-0-thermal {
thermal-sensors = <&tsens2 6>;
trips {
- trip-point0 {
+ nsp_0_1_0_alert0: trip-point0 {
temperature = <105000>;
hysteresis = <5000>;
type = "passive";
@@ -8796,6 +8810,14 @@ trip-point1 {
type = "passive";
};
};
+
+ cooling-maps {
+ map0 {
+ trip = <&nsp_0_1_0_alert0>;
+ cooling-device = <&remoteproc_cdsp0 THERMAL_NO_LIMIT
+ THERMAL_NO_LIMIT>;
+ };
+ };
};
nsp-0-2-0-thermal {
@@ -8804,7 +8826,7 @@ nsp-0-2-0-thermal {
thermal-sensors = <&tsens2 7>;
trips {
- trip-point0 {
+ nsp_0_2_0_alert0: trip-point0 {
temperature = <105000>;
hysteresis = <5000>;
type = "passive";
@@ -8816,6 +8838,14 @@ trip-point1 {
type = "passive";
};
};
+
+ cooling-maps {
+ map0 {
+ trip = <&nsp_0_2_0_alert0>;
+ cooling-device = <&remoteproc_cdsp0 THERMAL_NO_LIMIT
+ THERMAL_NO_LIMIT>;
+ };
+ };
};
nsp-1-0-0-thermal {
@@ -8824,7 +8854,7 @@ nsp-1-0-0-thermal {
thermal-sensors = <&tsens2 8>;
trips {
- trip-point0 {
+ nsp_1_0_0_alert0: trip-point0 {
temperature = <105000>;
hysteresis = <5000>;
type = "passive";
@@ -8836,6 +8866,14 @@ trip-point1 {
type = "passive";
};
};
+
+ cooling-maps {
+ map0 {
+ trip = <&nsp_1_0_0_alert0>;
+ cooling-device = <&remoteproc_cdsp1 THERMAL_NO_LIMIT
+ THERMAL_NO_LIMIT>;
+ };
+ };
};
nsp-1-1-0-thermal {
@@ -8844,7 +8882,7 @@ nsp-1-1-0-thermal {
thermal-sensors = <&tsens2 9>;
trips {
- trip-point0 {
+ nsp_1_1_0_alert0: trip-point0 {
temperature = <105000>;
hysteresis = <5000>;
type = "passive";
@@ -8856,6 +8894,14 @@ trip-point1 {
type = "passive";
};
};
+
+ cooling-maps {
+ map0 {
+ trip = <&nsp_1_1_0_alert0>;
+ cooling-device = <&remoteproc_cdsp1 THERMAL_NO_LIMIT
+ THERMAL_NO_LIMIT>;
+ };
+ };
};
nsp-1-2-0-thermal {
@@ -8864,7 +8910,7 @@ nsp-1-2-0-thermal {
thermal-sensors = <&tsens2 10>;
trips {
- trip-point0 {
+ nsp_1_2_0_alert0: trip-point0 {
temperature = <105000>;
hysteresis = <5000>;
type = "passive";
@@ -8876,6 +8922,14 @@ trip-point1 {
type = "passive";
};
};
+
+ cooling-maps {
+ map0 {
+ trip = <&nsp_1_2_0_alert0>;
+ cooling-device = <&remoteproc_cdsp1 THERMAL_NO_LIMIT
+ THERMAL_NO_LIMIT>;
+ };
+ };
};
ddrss-0-thermal {
@@ -9018,7 +9072,7 @@ nsp-0-0-1-thermal {
thermal-sensors = <&tsens3 5>;
trips {
- trip-point0 {
+ nsp_0_0_1_alert0: trip-point0 {
temperature = <105000>;
hysteresis = <5000>;
type = "passive";
@@ -9030,6 +9084,14 @@ trip-point1 {
type = "passive";
};
};
+
+ cooling-maps {
+ map0 {
+ trip = <&nsp_0_0_1_alert0>;
+ cooling-device = <&remoteproc_cdsp0 THERMAL_NO_LIMIT
+ THERMAL_NO_LIMIT>;
+ };
+ };
};
nsp-0-1-1-thermal {
@@ -9038,7 +9100,7 @@ nsp-0-1-1-thermal {
thermal-sensors = <&tsens3 6>;
trips {
- trip-point0 {
+ nsp_0_1_1_alert0: trip-point0 {
temperature = <105000>;
hysteresis = <5000>;
type = "passive";
@@ -9050,6 +9112,14 @@ trip-point1 {
type = "passive";
};
};
+
+ cooling-maps {
+ map0 {
+ trip = <&nsp_0_1_1_alert0>;
+ cooling-device = <&remoteproc_cdsp0 THERMAL_NO_LIMIT
+ THERMAL_NO_LIMIT>;
+ };
+ };
};
nsp-0-2-1-thermal {
@@ -9058,7 +9128,7 @@ nsp-0-2-1-thermal {
thermal-sensors = <&tsens3 7>;
trips {
- trip-point0 {
+ nsp_0_2_1_alert0: trip-point0 {
temperature = <105000>;
hysteresis = <5000>;
type = "passive";
@@ -9070,6 +9140,14 @@ trip-point1 {
type = "passive";
};
};
+
+ cooling-maps {
+ map0 {
+ trip = <&nsp_0_2_1_alert0>;
+ cooling-device = <&remoteproc_cdsp0 THERMAL_NO_LIMIT
+ THERMAL_NO_LIMIT>;
+ };
+ };
};
nsp-1-0-1-thermal {
@@ -9078,7 +9156,7 @@ nsp-1-0-1-thermal {
thermal-sensors = <&tsens3 8>;
trips {
- trip-point0 {
+ nsp_1_0_1_alert0: trip-point0 {
temperature = <105000>;
hysteresis = <5000>;
type = "passive";
@@ -9090,6 +9168,14 @@ trip-point1 {
type = "passive";
};
};
+
+ cooling-maps {
+ map0 {
+ trip = <&nsp_1_0_1_alert0>;
+ cooling-device = <&remoteproc_cdsp1 THERMAL_NO_LIMIT
+ THERMAL_NO_LIMIT>;
+ };
+ };
};
nsp-1-1-1-thermal {
@@ -9098,7 +9184,7 @@ nsp-1-1-1-thermal {
thermal-sensors = <&tsens3 9>;
trips {
- trip-point0 {
+ nsp_1_1_1_alert0: trip-point0 {
temperature = <105000>;
hysteresis = <5000>;
type = "passive";
@@ -9110,6 +9196,14 @@ trip-point1 {
type = "passive";
};
};
+
+ cooling-maps {
+ map0 {
+ trip = <&nsp_1_1_1_alert0>;
+ cooling-device = <&remoteproc_cdsp1 THERMAL_NO_LIMIT
+ THERMAL_NO_LIMIT>;
+ };
+ };
};
nsp-1-2-1-thermal {
@@ -9118,7 +9212,7 @@ nsp-1-2-1-thermal {
thermal-sensors = <&tsens3 10>;
trips {
- trip-point0 {
+ nsp_1_2_1_alert0: trip-point0 {
temperature = <105000>;
hysteresis = <5000>;
type = "passive";
@@ -9130,6 +9224,14 @@ trip-point1 {
type = "passive";
};
};
+
+ cooling-maps {
+ map0 {
+ trip = <&nsp_1_2_1_alert0>;
+ cooling-device = <&remoteproc_cdsp1 THERMAL_NO_LIMIT
+ THERMAL_NO_LIMIT>;
+ };
+ };
};
ddrss-1-thermal {
--
2.34.1
^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCH v3 6/8] arm64: dts: qcom: talos: Enable CDSP cooling
2026-06-09 10:22 [PATCH v3 0/8] Add support for Qualcomm remoteproc subsystem cooling Gaurav Kohli
` (4 preceding siblings ...)
2026-06-09 10:23 ` [PATCH v3 5/8] arm64: dts: qcom: lemans: Enable CDSP cooling Gaurav Kohli
@ 2026-06-09 10:23 ` Gaurav Kohli
2026-06-09 10:23 ` [PATCH v3 7/8] arm64: dts: qcom: monaco: " Gaurav Kohli
2026-06-09 10:23 ` [PATCH v3 8/8] arm64: dts: qcom: hamoa: " Gaurav Kohli
7 siblings, 0 replies; 18+ messages in thread
From: Gaurav Kohli @ 2026-06-09 10:23 UTC (permalink / raw)
To: Bjorn Andersson, Mathieu Poirier, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Daniel Lezcano, Amit Kucheria,
Manivannan Sadhasivam, Konrad Dybcio, Gaurav Kohli, Kees Cook,
Gustavo A. R. Silva, cros-qcom-dts-watchers
Cc: linux-arm-msm, linux-remoteproc, devicetree, linux-kernel,
linux-pm, linux-hardening, Manaf Meethalavalappu Pallikunhi
Unlike the CPU, the CDSP does not throttle its speed automatically
when it reaches high temperatures in talos.
Set up CDSP cooling by throttling the cdsp, when it reaches 105°C.
Signed-off-by: Gaurav Kohli <gaurav.kohli@oss.qualcomm.com>
---
arch/arm64/boot/dts/qcom/talos.dtsi | 19 +++++++++++++++++++
1 file changed, 19 insertions(+)
diff --git a/arch/arm64/boot/dts/qcom/talos.dtsi b/arch/arm64/boot/dts/qcom/talos.dtsi
index fb1bbc51bb8a..c105743764fa 100644
--- a/arch/arm64/boot/dts/qcom/talos.dtsi
+++ b/arch/arm64/boot/dts/qcom/talos.dtsi
@@ -3772,6 +3772,9 @@ remoteproc_cdsp: remoteproc@8300000 {
qcom,smem-states = <&cdsp_smp2p_out 0>;
qcom,smem-state-names = "stop";
+ #cooling-cells = <2>;
+ tmd-names = "cdsp_sw";
+
status = "disabled";
glink-edge {
@@ -5425,15 +5428,31 @@ map0 {
};
q6-hvx-thermal {
+ polling-delay-passive = <200>;
+
thermal-sensors = <&tsens0 10>;
trips {
+ q6_hvx_alert0: trip-point0 {
+ temperature = <105000>;
+ hysteresis = <5000>;
+ type = "passive";
+ };
+
q6-hvx-critical {
temperature = <115000>;
hysteresis = <1000>;
type = "critical";
};
};
+
+ cooling-maps {
+ map0 {
+ trip = <&q6_hvx_alert0>;
+ cooling-device = <&remoteproc_cdsp THERMAL_NO_LIMIT
+ THERMAL_NO_LIMIT>;
+ };
+ };
};
mdm-core-thermal {
--
2.34.1
^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCH v3 7/8] arm64: dts: qcom: monaco: Enable CDSP cooling
2026-06-09 10:22 [PATCH v3 0/8] Add support for Qualcomm remoteproc subsystem cooling Gaurav Kohli
` (5 preceding siblings ...)
2026-06-09 10:23 ` [PATCH v3 6/8] arm64: dts: qcom: talos: " Gaurav Kohli
@ 2026-06-09 10:23 ` Gaurav Kohli
2026-06-09 10:23 ` [PATCH v3 8/8] arm64: dts: qcom: hamoa: " Gaurav Kohli
7 siblings, 0 replies; 18+ messages in thread
From: Gaurav Kohli @ 2026-06-09 10:23 UTC (permalink / raw)
To: Bjorn Andersson, Mathieu Poirier, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Daniel Lezcano, Amit Kucheria,
Manivannan Sadhasivam, Konrad Dybcio, Gaurav Kohli, Kees Cook,
Gustavo A. R. Silva, cros-qcom-dts-watchers
Cc: linux-arm-msm, linux-remoteproc, devicetree, linux-kernel,
linux-pm, linux-hardening, Manaf Meethalavalappu Pallikunhi
Unlike the CPU, the CDSP does not throttle its speed automatically
when it reaches high temperatures in monaco.
Set up CDSP cooling for both instances by throttling the cdsp, when
it reaches 115°C.
Signed-off-by: Gaurav Kohli <gaurav.kohli@oss.qualcomm.com>
---
arch/arm64/boot/dts/qcom/monaco.dtsi | 99 ++++++++++++++++++++++++++++++++++++
1 file changed, 99 insertions(+)
diff --git a/arch/arm64/boot/dts/qcom/monaco.dtsi b/arch/arm64/boot/dts/qcom/monaco.dtsi
index e4c8466f941b..1756e8423a25 100644
--- a/arch/arm64/boot/dts/qcom/monaco.dtsi
+++ b/arch/arm64/boot/dts/qcom/monaco.dtsi
@@ -7728,6 +7728,9 @@ remoteproc_cdsp: remoteproc@26300000 {
qcom,smem-states = <&smp2p_cdsp_out 0>;
qcom,smem-state-names = "stop";
+ #cooling-cells = <2>;
+ tmd-names = "cdsp_sw";
+
status = "disabled";
glink-edge {
@@ -8160,39 +8163,87 @@ cpu-critical {
};
nsp-0-0-0-thermal {
+ polling-delay-passive = <200>;
+
thermal-sensors = <&tsens2 5>;
trips {
+ nsp_0_0_0_alert0: trip-point0 {
+ temperature = <115000>;
+ hysteresis = <5000>;
+ type = "passive";
+ };
+
nsp-critical {
temperature = <125000>;
hysteresis = <1000>;
type = "critical";
};
};
+
+ cooling-maps {
+ map0 {
+ trip = <&nsp_0_0_0_alert0>;
+ cooling-device = <&remoteproc_cdsp
+ THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
+ };
+ };
};
nsp-0-1-0-thermal {
+ polling-delay-passive = <200>;
+
thermal-sensors = <&tsens2 6>;
trips {
+ nsp_0_1_0_alert0: trip-point0 {
+ temperature = <115000>;
+ hysteresis = <5000>;
+ type = "passive";
+ };
+
nsp-critical {
temperature = <125000>;
hysteresis = <1000>;
type = "critical";
};
};
+
+ cooling-maps {
+ map0 {
+ trip = <&nsp_0_1_0_alert0>;
+ cooling-device = <&remoteproc_cdsp
+ THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
+ };
+ };
};
nsp-0-2-0-thermal {
+ polling-delay-passive = <200>;
+
thermal-sensors = <&tsens2 7>;
trips {
+ nsp_0_2_0_alert0: trip-point0 {
+ temperature = <115000>;
+ hysteresis = <5000>;
+ type = "passive";
+ };
+
nsp-critical {
temperature = <125000>;
hysteresis = <1000>;
type = "critical";
};
};
+
+ cooling-maps {
+ map0 {
+ trip = <&nsp_0_2_0_alert0>;
+ cooling-device = <&remoteproc_cdsp
+ THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
+ };
+ };
};
ddrss-0-thermal {
@@ -8280,39 +8331,87 @@ cpu-critical {
};
nsp-0-0-1-thermal {
+ polling-delay-passive = <200>;
+
thermal-sensors = <&tsens3 5>;
trips {
+ nsp_0_0_1_alert0: trip-point0 {
+ temperature = <115000>;
+ hysteresis = <5000>;
+ type = "passive";
+ };
+
nsp-critical {
temperature = <125000>;
hysteresis = <1000>;
type = "critical";
};
};
+
+ cooling-maps {
+ map0 {
+ trip = <&nsp_0_0_1_alert0>;
+ cooling-device = <&remoteproc_cdsp
+ THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
+ };
+ };
};
nsp-0-1-1-thermal {
+ polling-delay-passive = <200>;
+
thermal-sensors = <&tsens3 6>;
trips {
+ nsp_0_1_1_alert0: trip-point0 {
+ temperature = <115000>;
+ hysteresis = <5000>;
+ type = "passive";
+ };
+
nsp-critical {
temperature = <125000>;
hysteresis = <1000>;
type = "critical";
};
};
+
+ cooling-maps {
+ map0 {
+ trip = <&nsp_0_1_1_alert0>;
+ cooling-device = <&remoteproc_cdsp
+ THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
+ };
+ };
};
nsp-0-2-1-thermal {
+ polling-delay-passive = <200>;
+
thermal-sensors = <&tsens3 7>;
trips {
+ nsp_0_2_1_alert0: trip-point0 {
+ temperature = <115000>;
+ hysteresis = <5000>;
+ type = "passive";
+ };
+
nsp-critical {
temperature = <125000>;
hysteresis = <1000>;
type = "critical";
};
};
+
+ cooling-maps {
+ map0 {
+ trip = <&nsp_0_2_1_alert0>;
+ cooling-device = <&remoteproc_cdsp
+ THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
+ };
+ };
};
ddrss-1-thermal {
--
2.34.1
^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCH v3 8/8] arm64: dts: qcom: hamoa: Enable CDSP cooling
2026-06-09 10:22 [PATCH v3 0/8] Add support for Qualcomm remoteproc subsystem cooling Gaurav Kohli
` (6 preceding siblings ...)
2026-06-09 10:23 ` [PATCH v3 7/8] arm64: dts: qcom: monaco: " Gaurav Kohli
@ 2026-06-09 10:23 ` Gaurav Kohli
7 siblings, 0 replies; 18+ messages in thread
From: Gaurav Kohli @ 2026-06-09 10:23 UTC (permalink / raw)
To: Bjorn Andersson, Mathieu Poirier, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Daniel Lezcano, Amit Kucheria,
Manivannan Sadhasivam, Konrad Dybcio, Gaurav Kohli, Kees Cook,
Gustavo A. R. Silva, cros-qcom-dts-watchers
Cc: linux-arm-msm, linux-remoteproc, devicetree, linux-kernel,
linux-pm, linux-hardening, Manaf Meethalavalappu Pallikunhi,
Dipa Ramesh Mantre
From: Dipa Ramesh Mantre <dipa.mantre@oss.qualcomm.com>
Unlike the CPU, the CDSP does not throttle its speed automatically
when it reaches high temperatures in hamoa.
Set up CDSP cooling for both instances by throttling the cdsp, when
it reaches 95°C.
Signed-off-by: Dipa Ramesh Mantre <dipa.mantre@oss.qualcomm.com>
---
arch/arm64/boot/dts/qcom/hamoa.dtsi | 63 +++++++++++++++++++++++++++++++++++++
1 file changed, 63 insertions(+)
diff --git a/arch/arm64/boot/dts/qcom/hamoa.dtsi b/arch/arm64/boot/dts/qcom/hamoa.dtsi
index 4ba751a65142..92daaf4890aa 100644
--- a/arch/arm64/boot/dts/qcom/hamoa.dtsi
+++ b/arch/arm64/boot/dts/qcom/hamoa.dtsi
@@ -8815,6 +8815,9 @@ remoteproc_cdsp: remoteproc@32300000 {
status = "disabled";
+ #cooling-cells = <2>;
+ tmd-names = "cdsp_sw";
+
glink-edge {
interrupts-extended = <&ipcc IPCC_CLIENT_CDSP
IPCC_MPROC_SIGNAL_GLINK_QMP
@@ -9402,6 +9405,7 @@ aoss0-critical {
};
thermal_nsp0: nsp0-thermal {
+ polling-delay-passive = <200>;
thermal-sensors = <&tsens3 1>;
trips {
@@ -9411,15 +9415,30 @@ trip-point0 {
type = "hot";
};
+ nsp0_alert0: trip-point1 {
+ temperature = <95000>;
+ hysteresis = <5000>;
+ type = "passive";
+ };
+
nsp0-critical {
temperature = <115000>;
hysteresis = <1000>;
type = "critical";
};
};
+
+ cooling-maps {
+ map0 {
+ trip = <&nsp0_alert0>;
+ cooling-device = <&remoteproc_cdsp
+ THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
+ };
+ };
};
thermal_nsp1: nsp1-thermal {
+ polling-delay-passive = <200>;
thermal-sensors = <&tsens3 2>;
trips {
@@ -9429,15 +9448,30 @@ trip-point0 {
type = "hot";
};
+ nsp1_alert0: trip-point1 {
+ temperature = <95000>;
+ hysteresis = <5000>;
+ type = "passive";
+ };
+
nsp1-critical {
temperature = <115000>;
hysteresis = <1000>;
type = "critical";
};
};
+
+ cooling-maps {
+ map0 {
+ trip = <&nsp1_alert0>;
+ cooling-device = <&remoteproc_cdsp
+ THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
+ };
+ };
};
thermal_nsp2: nsp2-thermal {
+ polling-delay-passive = <200>;
thermal-sensors = <&tsens3 3>;
trips {
@@ -9447,15 +9481,30 @@ trip-point0 {
type = "hot";
};
+ nsp2_alert0: trip-point1 {
+ temperature = <95000>;
+ hysteresis = <5000>;
+ type = "passive";
+ };
+
nsp2-critical {
temperature = <115000>;
hysteresis = <1000>;
type = "critical";
};
};
+
+ cooling-maps {
+ map0 {
+ trip = <&nsp2_alert0>;
+ cooling-device = <&remoteproc_cdsp
+ THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
+ };
+ };
};
thermal_nsp3: nsp3-thermal {
+ polling-delay-passive = <200>;
thermal-sensors = <&tsens3 4>;
trips {
@@ -9465,12 +9514,26 @@ trip-point0 {
type = "hot";
};
+ nsp3_alert0: trip-point1 {
+ temperature = <95000>;
+ hysteresis = <5000>;
+ type = "passive";
+ };
+
nsp3-critical {
temperature = <115000>;
hysteresis = <1000>;
type = "critical";
};
};
+
+ cooling-maps {
+ map0 {
+ trip = <&nsp3_alert0>;
+ cooling-device = <&remoteproc_cdsp
+ THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
+ };
+ };
};
thermal_gpuss_0: gpuss-0-thermal {
--
2.34.1
^ permalink raw reply related [flat|nested] 18+ messages in thread
* Re: [PATCH v3 1/8] dt-bindings: remoteproc: qcom,pas: add thermal mitigation properties
2026-06-09 10:22 ` [PATCH v3 1/8] dt-bindings: remoteproc: qcom,pas: add thermal mitigation properties Gaurav Kohli
@ 2026-06-09 10:36 ` sashiko-bot
2026-06-09 10:47 ` Dmitry Baryshkov
1 sibling, 0 replies; 18+ messages in thread
From: sashiko-bot @ 2026-06-09 10:36 UTC (permalink / raw)
To: Gaurav Kohli; +Cc: robh, conor+dt, devicetree
Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
- [Medium] The `#cooling-cells` property uses an `enum` constraint instead of a hardware-matching `const` constraint.
- [Medium] Schema fails to enforce the mutual dependency between `#cooling-cells: 3` and `tmd-names`.
- [Low] The newly introduced 'tmd-names' property is missing the 'qcom,' vendor prefix.
--
commit ff18b7a7814a6d6f6545f74edd22e93602470084
Author: Gaurav Kohli <gaurav.kohli@oss.qualcomm.com>
Date: Tue Jun 9 10:22:56 2026 +0000
dt-bindings: remoteproc: qcom,pas: add thermal mitigation properties
Document Qualcomm PAS remoteproc thermal mitigation properties used for
QMI-based throttling.
> diff --git a/Documentation/devicetree/bindings/remoteproc/qcom,pas-common.yaml b/Documentation/devicetree/bindings/remoteproc/qcom,pas-common.yaml
> index 4607b459131b4..0d07a07507620 100644
> --- a/Documentation/devicetree/bindings/remoteproc/qcom,pas-common.yaml
> +++ b/Documentation/devicetree/bindings/remoteproc/qcom,pas-common.yaml
> @@ -79,6 +79,20 @@ properties:
> channels and devices related to the ADSP.
> unevaluatedProperties: false
>
> + '#cooling-cells':
> + description:
> + Number of cooling cells; 2 for min/max cooling state and 3 when
> + selecting a thermal mitigation device index.
> + enum: [2, 3]
[Severity: Medium]
The device tree bindings guidelines state that each cell-count property must
have a const constraint matching the hardware. Is it possible to enforce a
strict const constraint in the specific hardware variant schemas rather than
allowing an enum here, so we prevent misconfigured device tree nodes from
passing validation?
> +
> + tmd-names:
[Severity: Low]
Since this property is specific to Qualcomm's QMI-based thermal mitigation
device (TMD) throttling mechanism and not a standard core thermal binding,
should this have the "qcom," vendor prefix added to avoid namespace
collisions?
> + $ref: /schemas/types.yaml#/definitions/string-array
> + description:
> + Names of the thermal mitigation devices available in remote processor
> + subsystem.
> + minItems: 1
> + maxItems: 5
[Severity: Medium]
The #cooling-cells description mentions that a cell count of 3 is used to
select a thermal mitigation device index. Does this mean tmd-names should be
strictly required when #cooling-cells is 3?
If so, should we add an allOf or if-then conditional block tying these two
properties together to prevent validation of incomplete nodes?
> +
> glink-edge:
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260609-qmi-tmd-v3-0-291a2ff4c634@oss.qualcomm.com?part=1
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH v3 2/8] soc: qcom: Add support for QMI TMD cooling devices
2026-06-09 10:22 ` [PATCH v3 2/8] soc: qcom: Add support for QMI TMD cooling devices Gaurav Kohli
@ 2026-06-09 10:37 ` sashiko-bot
2026-06-09 11:30 ` Dmitry Baryshkov
1 sibling, 0 replies; 18+ messages in thread
From: sashiko-bot @ 2026-06-09 10:37 UTC (permalink / raw)
To: Gaurav Kohli; +Cc: devicetree, robh, conor+dt
Thank you for your contribution! Sashiko AI review found 5 potential issue(s) to consider:
- [High] Registration failure leaves an ERR_PTR in tmd->cdev, leading to an invalid pointer dereference during unregistration.
- [High] Incorrect teardown sequence in qmi_tmd_exit() allows Use-After-Free via concurrent sysfs accesses and re-queued QMI work.
- [Medium] QCOM_QMI_TMD selects QCOM_QMI_HELPERS without inheriting its NET dependency, leading to Kconfig unmet dependency warnings.
- [Medium] Mixing goto-based error handling with scope-based cleanup (__free).
- [Medium] Unprotected access to `tmd->cur_state` creates a TOCTOU race, causing the device mitigation state to permanently desynchronize from the kernel's state.
--
commit af63888f1125808b48046c97b93e006d9c65c730
Author: Casey Connolly <casey.connolly@linaro.org>
soc: qcom: Add support for QMI TMD cooling devices
Add a Qualcomm QMI Thermal Mitigation Device (TMD) to support thermal
cooling devices backed by remote subsystems.
> diff --git a/drivers/soc/qcom/Kconfig b/drivers/soc/qcom/Kconfig
> index 2caadbbcf8307..a292ce57fd4a4 100644
> --- a/drivers/soc/qcom/Kconfig
> +++ b/drivers/soc/qcom/Kconfig
> @@ -128,6 +128,16 @@ config QCOM_QMI_HELPERS
> tristate
> depends on NET
>
> +config QCOM_QMI_TMD
> + bool "Qualcomm QMI TMD library" if COMPILE_TEST
> + depends on ARCH_QCOM
> + select QCOM_QMI_HELPERS
[Severity: Medium]
Since QCOM_QMI_HELPERS specifies a dependency on NET, does selecting it here
without also inheriting the NET dependency risk unmet direct dependency warnings
at build time if CONFIG_NET=n?
> diff --git a/drivers/soc/qcom/qmi_tmd.c b/drivers/soc/qcom/qmi_tmd.c
> new file mode 100644
> index 0000000000000..9d88ae48c8647
> --- /dev/null
> +++ b/drivers/soc/qcom/qmi_tmd.c
[ ... ]
> +static int qmi_tmd_set_cur_state(struct thermal_cooling_device *cdev,
> + unsigned long state)
> +{
> + struct qmi_tmd *tmd = cdev->devdata;
> + int ret;
> +
> + if (state > tmd->max_state)
> + return -EINVAL;
> +
> + if (tmd->cur_state == state)
> + return 0;
> +
> + ret = qmi_tmd_send_state_request(tmd, state);
> + if (!ret)
> + tmd->cur_state = state;
[Severity: Medium]
Is there a potential TOCTOU race here when updating tmd->cur_state without
holding qmi_tmd_cli->mutex?
If the QMI server restarts concurrently, qmi_tmd_register() might read the old
state locklessly to send to the new server before this assignment completes,
permanently desynchronizing the kernel's recorded state from the actual
hardware state.
[ ... ]
> +static int qmi_tmd_register(struct qmi_tmd_client *qmi_tmd_cli,
> + const char *label, u8 max_state)
> +{
[ ... ]
> +found:
> + tmd->max_state = max_state;
> +
> + /*
> + * If the cooling device already exists then the QMI service went away and
> + * came back. So just make sure the current cooling device state is
> + * reflected on the remote side and then return.
> + */
> + if (tmd->cdev)
> + return qmi_tmd_send_state_request(tmd, tmd->cur_state);
> +
> + tmd->cdev = thermal_of_cooling_device_register(dev->of_node, index,
> + label, tmd, &qmi_tmd_cooling_ops);
> + if (IS_ERR(tmd->cdev))
> + return PTR_ERR(tmd->cdev);
> +
> + return 0;
> +}
[Severity: High]
If thermal_of_cooling_device_register() fails, could this leave an ERR_PTR
in tmd->cdev?
Later in qmi_tmd_unregister(), the check if (!tmd->cdev) will be bypassed
since an ERR_PTR evaluates to true, potentially causing a crash when
thermal_cooling_device_unregister() attempts to dereference it. Should
tmd->cdev be set back to NULL on failure?
[ ... ]
> +static void qmi_tmd_svc_arrive(struct work_struct *work)
> +{
> + struct qmi_tmd_client *qmi_tmd_cli =
> + container_of(work, struct qmi_tmd_client, svc_arrive_work);
> +
> + struct tmd_get_dev_list_req req = { 0 };
> + struct tmd_get_dev_list_resp *resp __free(kfree) = NULL;
> + int ret, i;
> + struct qmi_txn txn;
> +
> + resp = kzalloc_obj(*resp, GFP_KERNEL);
> + if (!resp) {
> + ret = -ENOMEM;
> + goto out;
> + }
[ ... ]
> +out:
> + if (ret)
> + dev_err(qmi_tmd_cli->dev, "Failed to initialize TMD service: %d\n", ret);
> +}
[Severity: Medium]
Does mixing the scope-based cleanup macro __free(kfree) with traditional
goto-based error handling (goto out;) in the same function violate the
cleanup subsystem guidelines? This mixture can lead to confusing ownership
semantics.
[ ... ]
> +void qmi_tmd_exit(struct qmi_tmd_client *qmi_tmd_cli)
> +{
> + if (!qmi_tmd_cli)
> + return;
> +
> + cancel_work_sync(&qmi_tmd_cli->svc_arrive_work);
> + qmi_handle_release(&qmi_tmd_cli->handle);
> + qmi_tmd_unregister(qmi_tmd_cli);
> +
> + scoped_guard(mutex, &qmi_tmd_cli->mutex)
> + qmi_tmd_cli->connection_active = false;
> +}
[Severity: High]
Can this teardown sequence cause a use-after-free or kernel crash?
Because qmi_handle_release() is called before qmi_tmd_unregister(), the
cooling device remains exposed to sysfs while the QMI handle is being
destroyed. A concurrent sysfs write could trigger qmi_tmd_set_cur_state(),
which would attempt to allocate a transaction ID in the destroyed qmi->txns
IDR because connection_active is still true.
Additionally, because cancel_work_sync() runs before qmi_handle_release(),
there is a window where incoming QMI events can re-queue svc_arrive_work,
potentially executing after the driver unbinds.
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260609-qmi-tmd-v3-0-291a2ff4c634@oss.qualcomm.com?part=2
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH v3 3/8] remoteproc: qcom: pas: register TMD thermal cooling devices
2026-06-09 10:22 ` [PATCH v3 3/8] remoteproc: qcom: pas: register TMD thermal " Gaurav Kohli
@ 2026-06-09 10:40 ` sashiko-bot
2026-06-09 11:05 ` Dmitry Baryshkov
2026-06-09 12:03 ` Konrad Dybcio
2 siblings, 0 replies; 18+ messages in thread
From: sashiko-bot @ 2026-06-09 10:40 UTC (permalink / raw)
To: Gaurav Kohli; +Cc: devicetree, conor+dt, robh
Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
- [High] Config QCOM_Q6V5_PAS and QCOM_QMI_TMD select QCOM_QMI_HELPERS without inheriting its dependency on NET, leading to Kconfig unmet dependency warnings and build failures.
- [High] In qmi_tmd_exit(), the QMI handle is released before unregistering the thermal cooling devices, exposing a race condition that leads to a Use-After-Free.
- [High] If thermal_of_cooling_device_register() fails, tmd->cdev holds an ERR_PTR which causes a kernel panic when passed to thermal_cooling_device_unregister().
--
commit 054962d4a1d3642bf94b2a883fba802967d5e58a
Author: Gaurav Kohli <gaurav.kohli@oss.qualcomm.com>
remoteproc: qcom: pas: register TMD thermal cooling devices
Add support for Thermal Mitigation Devices (TMDs) to enable thermal
throttling of remote processors through QMI. This enables the thermal
framework to request mitigation when remote subsystems contribute to thermal
issues.
> diff --git a/drivers/soc/qcom/Kconfig b/drivers/soc/qcom/Kconfig
> index 2caadbbcf8307..a292ce57fd4a4 100644
> --- a/drivers/soc/qcom/Kconfig
> +++ b/drivers/soc/qcom/Kconfig
> @@ -128,6 +128,16 @@ config QCOM_QMI_HELPERS
> tristate
> depends on NET
>
> +config QCOM_QMI_TMD
> + bool "Qualcomm QMI TMD library" if COMPILE_TEST
> + depends on ARCH_QCOM
> + select QCOM_QMI_HELPERS
[Severity: High]
Does this code need to inherit the dependency on NET?
Looking at QCOM_QMI_HELPERS, it strictly depends on NET. If QCOM_QMI_TMD is
enabled while NET is disabled, Kconfig will forcefully enable
QCOM_QMI_HELPERS with unsatisfied dependencies. This could trigger unmet
direct dependencies warnings and link-time errors due to missing socket
APIs.
> diff --git a/drivers/soc/qcom/qmi_tmd.c b/drivers/soc/qcom/qmi_tmd.c
> new file mode 100644
> index 0000000000000..9d88ae48c8647
> --- /dev/null
> +++ b/drivers/soc/qcom/qmi_tmd.c
[ ... ]
> +static int qmi_tmd_register(struct qmi_tmd_client *qmi_tmd_cli,
> + const char *label, u8 max_state)
> +{
[ ... ]
> + tmd->cdev = thermal_of_cooling_device_register(dev->of_node, index,
> + label, tmd, &qmi_tmd_cooling_ops);
> + if (IS_ERR(tmd->cdev))
> + return PTR_ERR(tmd->cdev);
[Severity: High]
Could this leave tmd->cdev containing an ERR_PTR if registration fails?
If thermal_of_cooling_device_register() returns an error, tmd->cdev will
hold that ERR_PTR. Later, when qmi_tmd_unregister() runs, the
if (!tmd->cdev) check won't catch the error pointer, causing
thermal_cooling_device_unregister() to dereference it and panic the kernel.
[ ... ]
> +void qmi_tmd_exit(struct qmi_tmd_client *qmi_tmd_cli)
> +{
> + if (!qmi_tmd_cli)
> + return;
> +
> + cancel_work_sync(&qmi_tmd_cli->svc_arrive_work);
> + qmi_handle_release(&qmi_tmd_cli->handle);
> + qmi_tmd_unregister(qmi_tmd_cli);
[Severity: High]
Does releasing the QMI handle before unregistering the thermal devices
create a race condition?
If the thermal core invokes qmi_tmd_set_cur_state() asynchronously between
qmi_handle_release() and qmi_tmd_unregister(), qmi_tmd_send_state_request()
will try to use the already destroyed QMI handle, which could result in a
use-after-free.
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260609-qmi-tmd-v3-0-291a2ff4c634@oss.qualcomm.com?part=3
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH v3 1/8] dt-bindings: remoteproc: qcom,pas: add thermal mitigation properties
2026-06-09 10:22 ` [PATCH v3 1/8] dt-bindings: remoteproc: qcom,pas: add thermal mitigation properties Gaurav Kohli
2026-06-09 10:36 ` sashiko-bot
@ 2026-06-09 10:47 ` Dmitry Baryshkov
1 sibling, 0 replies; 18+ messages in thread
From: Dmitry Baryshkov @ 2026-06-09 10:47 UTC (permalink / raw)
To: Gaurav Kohli
Cc: Bjorn Andersson, Mathieu Poirier, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Daniel Lezcano, Amit Kucheria,
Manivannan Sadhasivam, Konrad Dybcio, Kees Cook,
Gustavo A. R. Silva, cros-qcom-dts-watchers, linux-arm-msm,
linux-remoteproc, devicetree, linux-kernel, linux-pm,
linux-hardening, Manaf Meethalavalappu Pallikunhi
On Tue, Jun 09, 2026 at 03:52:56PM +0530, Gaurav Kohli wrote:
> Document Qualcomm PAS remoteproc thermal mitigation properties used for
> QMI-based throttling.
>
> Add:
> - #cooling-cells (2 or 3)
> - tmd-names (thermal mitigation device names)
Describe _why_ you are performing these changes. For example. why do we
need to handle two different cases for the #cooling-cells?
>
> Signed-off-by: Gaurav Kohli <gaurav.kohli@oss.qualcomm.com>
> ---
> .../devicetree/bindings/remoteproc/qcom,pas-common.yaml | 14 ++++++++++++++
> 1 file changed, 14 insertions(+)
>
> diff --git a/Documentation/devicetree/bindings/remoteproc/qcom,pas-common.yaml b/Documentation/devicetree/bindings/remoteproc/qcom,pas-common.yaml
> index 4607b459131b..0d07a0750762 100644
> --- a/Documentation/devicetree/bindings/remoteproc/qcom,pas-common.yaml
> +++ b/Documentation/devicetree/bindings/remoteproc/qcom,pas-common.yaml
> @@ -79,6 +79,20 @@ properties:
> channels and devices related to the ADSP.
> unevaluatedProperties: false
>
> + '#cooling-cells':
> + description:
> + Number of cooling cells; 2 for min/max cooling state and 3 when
> + selecting a thermal mitigation device index.
> + enum: [2, 3]
> +
> + tmd-names:
> + $ref: /schemas/types.yaml#/definitions/string-array
> + description:
> + Names of the thermal mitigation devices available in remote processor
> + subsystem.
> + minItems: 1
> + maxItems: 5
Missing example with these properties.
> +
> glink-edge:
> $ref: /schemas/remoteproc/qcom,glink-edge.yaml#
> description:
>
> --
> 2.34.1
>
--
With best wishes
Dmitry
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH v3 4/8] arm64: dts: qcom: kodiak: Enable CDSP & Modem cooling
2026-06-09 10:22 ` [PATCH v3 4/8] arm64: dts: qcom: kodiak: Enable CDSP & Modem cooling Gaurav Kohli
@ 2026-06-09 10:57 ` Dmitry Baryshkov
0 siblings, 0 replies; 18+ messages in thread
From: Dmitry Baryshkov @ 2026-06-09 10:57 UTC (permalink / raw)
To: Gaurav Kohli
Cc: Bjorn Andersson, Mathieu Poirier, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Daniel Lezcano, Amit Kucheria,
Manivannan Sadhasivam, Konrad Dybcio, Kees Cook,
Gustavo A. R. Silva, cros-qcom-dts-watchers, linux-arm-msm,
linux-remoteproc, devicetree, linux-kernel, linux-pm,
linux-hardening, Manaf Meethalavalappu Pallikunhi
On Tue, Jun 09, 2026 at 03:52:59PM +0530, Gaurav Kohli wrote:
> Unlike the CPU, the CDSP/Modem does not throttle its speed automatically
> when it reaches high temperatures in kodiak.
>
> Set up CDSP cooling by throttling the cdsp when it reaches 100°C and
> for modem when it reaches to 95°C.
>
> Remove inherited mdmss cooling-map nodes for Non Modem kodiak variant.
Why? If it is a GNSS-only MPSS, does it not provide any thermal
mitigation mechanisms? Does ADSP provide those? WPSS?
>
> Signed-off-by: Gaurav Kohli <gaurav.kohli@oss.qualcomm.com>
> ---
> arch/arm64/boot/dts/qcom/kodiak.dtsi | 127 ++++++++++++++++++++-
> .../boot/dts/qcom/qcs6490-radxa-dragon-q6a.dts | 17 +++
So, you removed those for Radxa Q6A, but not forRB3 Gen2. Why?
> .../dts/qcom/qcs6490-thundercomm-minipc-g1iot.dts | 17 +++
> .../boot/dts/qcom/qcs6490-thundercomm-rubikpi3.dts | 17 +++
> .../boot/dts/qcom/sc7280-herobrine-lte-sku.dtsi | 18 +++
> .../boot/dts/qcom/sc7280-herobrine-wifi-sku.dtsi | 16 +++
> 6 files changed, 208 insertions(+), 4 deletions(-)
>
> diff --git a/arch/arm64/boot/dts/qcom/kodiak.dtsi b/arch/arm64/boot/dts/qcom/kodiak.dtsi
> index fa540d8c2615..d345add2d8c8 100644
> --- a/arch/arm64/boot/dts/qcom/kodiak.dtsi
> +++ b/arch/arm64/boot/dts/qcom/kodiak.dtsi
> @@ -3427,6 +3427,9 @@ remoteproc_mpss: remoteproc@4080000 {
> qcom,smem-states = <&modem_smp2p_out 0>;
> qcom,smem-state-names = "stop";
>
> + #cooling-cells = <3>;
> + tmd-names = "pa", "modem";
> +
> status = "disabled";
>
> glink-edge {
> @@ -4787,6 +4790,9 @@ remoteproc_cdsp: remoteproc@a300000 {
> qcom,smem-states = <&cdsp_smp2p_out 0>;
> qcom,smem-state-names = "stop";
>
> + #cooling-cells = <2>;
> + tmd-names = "cdsp_sw";
I'm going to review only this DT, the comments apply to the rest of
them.
So, we have two cases, CDSP and MPSS. Why does CDSP have only 2 cells?
Just because tmd-names has only one name? What if we add another
mitigation (which can be added in the firmware), do we suddenly have to
change number of cells and all the cooling devices to reflect it?
Finally. If I understand correctly, these mitigtion mechanisms are
provided by the firmware. Firmware differs between the boards. Vendors
(in theory) can change them. Why do we list these names here, in the SoC
DT?
> +
> status = "disabled";
>
> glink-edge {
> + cooling-maps {
> + map0 {
> + trip = <&mdmss0_alert1>;
> + cooling-device = <&remoteproc_mpss 0 0 2>;
What does this mean? I assume that the first cell is one of the
mechanisms. What is the difference between them? Do we really need to
list them one by one here?
What do other cells mean? Why are they 0 and 2 rather than
THERMAL_NO_LIMIT? How does one come with those values? This should all
be documented and explained somewhere.
> + };
> +
> + map1 {
> + trip = <&mdmss0_alert1>;
> + cooling-device = <&remoteproc_mpss 1 0 2>;
> + };
> + };
> };
>
--
With best wishes
Dmitry
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH v3 3/8] remoteproc: qcom: pas: register TMD thermal cooling devices
2026-06-09 10:22 ` [PATCH v3 3/8] remoteproc: qcom: pas: register TMD thermal " Gaurav Kohli
2026-06-09 10:40 ` sashiko-bot
@ 2026-06-09 11:05 ` Dmitry Baryshkov
2026-06-09 12:03 ` Konrad Dybcio
2 siblings, 0 replies; 18+ messages in thread
From: Dmitry Baryshkov @ 2026-06-09 11:05 UTC (permalink / raw)
To: Gaurav Kohli
Cc: Bjorn Andersson, Mathieu Poirier, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Daniel Lezcano, Amit Kucheria,
Manivannan Sadhasivam, Konrad Dybcio, Kees Cook,
Gustavo A. R. Silva, cros-qcom-dts-watchers, linux-arm-msm,
linux-remoteproc, devicetree, linux-kernel, linux-pm,
linux-hardening, Manaf Meethalavalappu Pallikunhi
On Tue, Jun 09, 2026 at 03:52:58PM +0530, Gaurav Kohli wrote:
> Add support for Thermal Mitigation Devices (TMDs) to enable
> thermal throttling of remote processors through QMI.
>
> This enables the thermal framework to request mitigation when remote
> subsystems (modem, CDSP) contribute to thermal issues.
>
> Signed-off-by: Gaurav Kohli <gaurav.kohli@oss.qualcomm.com>
> Signed-off-by: Daniel Lezcano <daniel.lezcano@oss.qualcomm.com>
Wrong SoB chain. Yours should be the last one.
> ---
> drivers/remoteproc/Kconfig | 1 +
> drivers/remoteproc/qcom_q6v5_pas.c | 61 +++++++++++++++++++++++++++++++++++++-
> 2 files changed, 61 insertions(+), 1 deletion(-)
>
> @@ -733,6 +737,49 @@ static void qcom_pas_unassign_memory_region(struct qcom_pas *pas)
> }
> }
>
> +static int qcom_pas_setup_tmd(struct qcom_pas *pas)
> +{
> + struct device *dev = pas->dev;
> + struct device_node *np = dev->of_node;
> + const char **tmd_names;
> + int num_tmds, ret, i;
> +
> + if (!of_find_property(np, "tmd-names", NULL))
> + return 0;
> +
> + /* Get the TMD names array */
> + num_tmds = of_property_count_strings(np, "tmd-names");
> + if (num_tmds <= 0)
> + return 0;
Propagate the error?
> +
> + tmd_names = devm_kcalloc(dev, num_tmds, sizeof(*tmd_names), GFP_KERNEL);
> + if (!tmd_names)
> + return -ENOMEM;
> +
> + for (i = 0; i < num_tmds; i++) {
> + ret = of_property_read_string_index(np, "tmd-names", i,
> + &tmd_names[i]);
> + if (ret) {
> + dev_err(dev, "Failed to read tmd-names[%d]: %d\n", i, ret);
> + return ret;
> + }
> + }
> +
> + pas->tmd_inst = qmi_tmd_init(dev, pas->info_name, tmd_names, num_tmds);
> + if (IS_ERR(pas->tmd_inst)) {
> + dev_err(dev, "Failed to register '%s'\n", pas->info_name);
> +
> + ret = PTR_ERR(pas->tmd_inst);
> + if (ret == -ENODEV) {
> + pas->tmd_inst = NULL;
> + return 0;
> + }
> + return ret;
> + }
Assing to a temporal variable, check the result, assign afterwards.
Saves you from the nested ifs.
> +
> + return 0;
> +}
> +
> static int qcom_pas_probe(struct platform_device *pdev)
> {
> const struct qcom_pas_data *desc;
--
With best wishes
Dmitry
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH v3 2/8] soc: qcom: Add support for QMI TMD cooling devices
2026-06-09 10:22 ` [PATCH v3 2/8] soc: qcom: Add support for QMI TMD cooling devices Gaurav Kohli
2026-06-09 10:37 ` sashiko-bot
@ 2026-06-09 11:30 ` Dmitry Baryshkov
2026-06-09 12:08 ` Daniel Lezcano
1 sibling, 1 reply; 18+ messages in thread
From: Dmitry Baryshkov @ 2026-06-09 11:30 UTC (permalink / raw)
To: Gaurav Kohli
Cc: Bjorn Andersson, Mathieu Poirier, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Daniel Lezcano, Amit Kucheria,
Manivannan Sadhasivam, Konrad Dybcio, Kees Cook,
Gustavo A. R. Silva, cros-qcom-dts-watchers, linux-arm-msm,
linux-remoteproc, devicetree, linux-kernel, linux-pm,
linux-hardening, Manaf Meethalavalappu Pallikunhi, Casey Connolly
On Tue, Jun 09, 2026 at 03:52:57PM +0530, Gaurav Kohli wrote:
> From: Casey Connolly <casey.connolly@linaro.org>
>
> Add a Qualcomm QMI Thermal Mitigation Device (TMD) to support thermal
> cooling devices backed by remote subsystems.
>
> On several Qualcomm platforms, remote processors (for example modem and
> CDSP) expose thermal mitigation controls through the TMD QMI service.
> Client drivers need a way to discover that service, map DT thermal
> mitigation endpoints to cooling devices, and forward cooling state
> updates to the remote subsystem.
>
> Co-developed-by: Gaurav Kohli <gaurav.kohli@oss.qualcomm.com>
> Signed-off-by: Gaurav Kohli <gaurav.kohli@oss.qualcomm.com>
> Signed-off-by: Casey Connolly <casey.connolly@linaro.org>
> Signed-off-by: Daniel Lezcano <daniel.lezcano@oss.qualcomm.com>
Wrong SoB chain.
> ---
> MAINTAINERS | 6 +
> drivers/soc/qcom/Kconfig | 10 +
> drivers/soc/qcom/Makefile | 1 +
> drivers/soc/qcom/qmi_tmd.c | 604 +++++++++++++++++++++++++++++++++++++++
> include/linux/soc/qcom/qmi.h | 1 +
> include/linux/soc/qcom/qmi_tmd.h | 23 ++
> 6 files changed, 645 insertions(+)
>
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 57656ec0e9d5..3d60702a655a 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -22286,6 +22286,12 @@ F: Documentation/devicetree/bindings/net/qcom,ipq9574-ppe.yaml
> F: Documentation/networking/device_drivers/ethernet/qualcomm/ppe/ppe.rst
> F: drivers/net/ethernet/qualcomm/ppe/
>
> +QUALCOMM QMI (REMOTEPROC THERMAL MITIGATION) TMD
> +M: Gaurav Kohli <gaurav.kohli@oss.qualcomm.com>
> +L: linux-arm-msm@vger.kernel.org
> +L: linux-pm@vger.kernel.org
> +F: drivers/soc/qcom/qmi_tmd.c
> +
> QUALCOMM QSEECOM DRIVER
> M: Maximilian Luz <luzmaximilian@gmail.com>
> L: linux-arm-msm@vger.kernel.org
> diff --git a/drivers/soc/qcom/Kconfig b/drivers/soc/qcom/Kconfig
> index 2caadbbcf830..a292ce57fd4a 100644
> --- a/drivers/soc/qcom/Kconfig
> +++ b/drivers/soc/qcom/Kconfig
> @@ -128,6 +128,16 @@ config QCOM_QMI_HELPERS
> tristate
> depends on NET
>
> +config QCOM_QMI_TMD
> + bool "Qualcomm QMI TMD library" if COMPILE_TEST
> + depends on ARCH_QCOM
> + select QCOM_QMI_HELPERS
> + help
> + This enables the QMI-based Thermal Mitigation Device (TMD) library
> + for Qualcomm remote subsystems. The library manages TMD messaging and
> + handles QMI communication with remote processors (modem, CDSP) to
> + exchange mitigation state and apply thermal mitigation requests.
> +
> config QCOM_RAMP_CTRL
> tristate "Qualcomm Ramp Controller driver"
> depends on ARCH_QCOM || COMPILE_TEST
> diff --git a/drivers/soc/qcom/Makefile b/drivers/soc/qcom/Makefile
> index b7f1d2a57367..4544e61c74e7 100644
> --- a/drivers/soc/qcom/Makefile
> +++ b/drivers/soc/qcom/Makefile
> @@ -14,6 +14,7 @@ obj-$(CONFIG_QCOM_PMIC_GLINK) += pmic_glink.o
> obj-$(CONFIG_QCOM_PMIC_GLINK) += pmic_glink_altmode.o
> obj-$(CONFIG_QCOM_PMIC_PDCHARGER_ULOG) += pmic_pdcharger_ulog.o
> CFLAGS_pmic_pdcharger_ulog.o := -I$(src)
> +obj-$(CONFIG_QCOM_QMI_TMD) += qmi_tmd.o
> obj-$(CONFIG_QCOM_QMI_HELPERS) += qmi_helpers.o
> qmi_helpers-y += qmi_encdec.o qmi_interface.o
> obj-$(CONFIG_QCOM_RAMP_CTRL) += ramp_controller.o
> diff --git a/drivers/soc/qcom/qmi_tmd.c b/drivers/soc/qcom/qmi_tmd.c
> new file mode 100644
> index 000000000000..9d88ae48c864
> --- /dev/null
> +++ b/drivers/soc/qcom/qmi_tmd.c
> @@ -0,0 +1,604 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Copyright (c) 2025, Linaro Limited
> + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
> + *
> + * QMI Thermal Mitigation Device (TMD) library.
> + * This library provides cooling device support for remote subsystems
> + * (modem and CDSP) running the TMD service via QMI.
Why are you limiting it to these DSPs only? I quickly checked, my X13s
(sc8280xp) also has one on the ADSP.
> + */
> +#include <linux/cleanup.h>
> +#include <linux/device.h>
> +#include <linux/err.h>
> +#include <linux/module.h>
> +#include <linux/net.h>
> +#include <linux/of.h>
> +#include <linux/slab.h>
> +#include <linux/soc/qcom/qmi.h>
> +#include <linux/soc/qcom/qmi_tmd.h>
> +#include <linux/thermal.h>
> +
> +#define QMI_TMD_INSTANCE_MODEM 0x0
> +#define QMI_TMD_INSTANCE_CDSP 0x43
> +#define QMI_TMD_INSTANCE_CDSP1 0x44
Other instances? Are those numbers fixed?
Should we pass the instance ID from the PAS driver instead?
> +
> +#define QMI_TMD_SERVICE_VERS_V01 0x01
> +
> +#define QMI_TMD_SET_LEVEL_REQ 0x0021
> +#define QMI_TMD_GET_DEV_LIST_REQ 0x0020
> +
> +#define QMI_TMD_DEV_ID_LEN_MAX 32
> +#define QMI_TMD_DEV_LIST_MAX 32
> +#define QMI_TMD_RESP_TIMEOUT msecs_to_jiffies(100)
> +#define TMD_GET_LEVEL_REQ_MAX_LEN 36
> +#define TMD_SET_LEVEL_REQ_MAX_LEN 40
> +
> +#define TMD_GET_DEV_LIST_REQ_MAX_LEN 0
> +#define TMD_GET_DEV_LIST_RESP_MAX_LEN 1099
> +
> +struct tmd_dev_id {
> + char mitigation_dev_id[QMI_TMD_DEV_ID_LEN_MAX + 1];
> +};
> +
> +static const struct qmi_elem_info tmd_dev_id_ei[] = {
> + {
> + .data_type = QMI_STRING,
> + .elem_len = QMI_TMD_DEV_ID_LEN_MAX + 1,
> + .elem_size = sizeof(char),
> + .array_type = NO_ARRAY,
> + .tlv_type = 0,
> + .offset = offsetof(struct tmd_dev_id,
> + mitigation_dev_id),
> + },
> + {
> + .data_type = QMI_EOTI,
> + .array_type = NO_ARRAY,
> + .tlv_type = QMI_COMMON_TLV_TYPE,
> + },
> +};
> +
> +struct tmd_dev_list {
> + struct tmd_dev_id mitigation_dev_id;
> + u8 max_mitigation_level;
> +};
> +
> +static const struct qmi_elem_info tmd_dev_list_ei[] = {
> + {
> + .data_type = QMI_STRUCT,
> + .elem_len = 1,
> + .elem_size = sizeof(struct tmd_dev_id),
> + .array_type = NO_ARRAY,
> + .tlv_type = 0,
> + .offset = offsetof(struct tmd_dev_list,
> + mitigation_dev_id),
> + .ei_array = tmd_dev_id_ei,
> + },
> + {
> + .data_type = QMI_UNSIGNED_1_BYTE,
> + .elem_len = 1,
> + .elem_size = sizeof(uint8_t),
> + .array_type = NO_ARRAY,
> + .tlv_type = 0,
> + .offset = offsetof(struct tmd_dev_list,
> + max_mitigation_level),
> + },
> + {
> + .data_type = QMI_EOTI,
> + .array_type = NO_ARRAY,
> + .tlv_type = QMI_COMMON_TLV_TYPE,
> + },
> +};
> +
> +struct tmd_get_dev_list_req {
> + char placeholder;
> +};
> +
> +static const struct qmi_elem_info tmd_get_dev_list_req_ei[] = {
> + {
> + .data_type = QMI_EOTI,
> + .array_type = NO_ARRAY,
> + .tlv_type = QMI_COMMON_TLV_TYPE,
> + },
> +};
> +
> +struct tmd_get_dev_list_resp {
> + struct qmi_response_type_v01 resp;
> + u8 mitigation_device_list_valid;
> + u32 mitigation_device_list_len;
> + struct tmd_dev_list
> + mitigation_device_list[QMI_TMD_DEV_LIST_MAX];
> +};
> +
> +static const struct qmi_elem_info tmd_get_dev_list_resp_ei[] = {
> + {
> + .data_type = QMI_STRUCT,
> + .elem_len = 1,
> + .elem_size = sizeof(struct qmi_response_type_v01),
> + .array_type = NO_ARRAY,
> + .tlv_type = 0x02,
> + .offset = offsetof(struct tmd_get_dev_list_resp,
> + resp),
> + .ei_array = qmi_response_type_v01_ei,
> + },
> + {
> + .data_type = QMI_OPT_FLAG,
> + .elem_len = 1,
> + .elem_size = sizeof(uint8_t),
> + .array_type = NO_ARRAY,
> + .tlv_type = 0x10,
> + .offset = offsetof(struct tmd_get_dev_list_resp,
> + mitigation_device_list_valid),
> + },
> + {
> + .data_type = QMI_DATA_LEN,
> + .elem_len = 1,
> + .elem_size = sizeof(uint8_t),
> + .array_type = NO_ARRAY,
> + .tlv_type = 0x10,
> + .offset = offsetof(struct tmd_get_dev_list_resp,
> + mitigation_device_list_len),
> + },
> + {
> + .data_type = QMI_STRUCT,
> + .elem_len = QMI_TMD_DEV_LIST_MAX,
> + .elem_size = sizeof(struct tmd_dev_list),
> + .array_type = VAR_LEN_ARRAY,
> + .tlv_type = 0x10,
> + .offset = offsetof(struct tmd_get_dev_list_resp,
> + mitigation_device_list),
> + .ei_array = tmd_dev_list_ei,
> + },
> + {
> + .data_type = QMI_EOTI,
> + .array_type = NO_ARRAY,
> + .tlv_type = QMI_COMMON_TLV_TYPE,
> + },
> +};
> +
> +struct tmd_set_level_req {
> + struct tmd_dev_id mitigation_dev_id;
> + u8 mitigation_level;
> +};
> +
> +static const struct qmi_elem_info tmd_set_level_req_ei[] = {
> + {
> + .data_type = QMI_STRUCT,
> + .elem_len = 1,
> + .elem_size = sizeof(struct tmd_dev_id),
> + .array_type = NO_ARRAY,
> + .tlv_type = 0x01,
> + .offset = offsetof(struct tmd_set_level_req,
> + mitigation_dev_id),
> + .ei_array = tmd_dev_id_ei,
> + },
> + {
> + .data_type = QMI_UNSIGNED_1_BYTE,
> + .elem_len = 1,
> + .elem_size = sizeof(uint8_t),
> + .array_type = NO_ARRAY,
> + .tlv_type = 0x02,
> + .offset = offsetof(struct tmd_set_level_req,
> + mitigation_level),
> + },
> + {
> + .data_type = QMI_EOTI,
> + .array_type = NO_ARRAY,
> + .tlv_type = QMI_COMMON_TLV_TYPE,
> + },
> +};
> +
> +struct tmd_set_level_resp {
> + struct qmi_response_type_v01 resp;
> +};
> +
> +static const struct qmi_elem_info tmd_set_level_resp_ei[] = {
> + {
> + .data_type = QMI_STRUCT,
> + .elem_len = 1,
> + .elem_size = sizeof(struct qmi_response_type_v01),
> + .array_type = NO_ARRAY,
> + .tlv_type = 0x02,
> + .offset = offsetof(struct tmd_set_level_resp, resp),
> + .ei_array = qmi_response_type_v01_ei,
> + },
> + {
> + .data_type = QMI_EOTI,
> + .array_type = NO_ARRAY,
> + .tlv_type = QMI_COMMON_TLV_TYPE,
> + },
> +};
> +
> +/**
> + * struct qmi_tmd - A TMD cooling device
> + * @name: The name of this tmd shared by the remote subsystem
> + * @cdev: Thermal cooling device handle
> + * @cur_state: The current mitigation state
> + * @max_state: The maximum state
> + * @qmi_tmd_cli: Parent QMI TMD client
> + */
> +struct qmi_tmd {
> + const char *name;
> + struct thermal_cooling_device *cdev;
> + unsigned int cur_state;
> + unsigned int max_state;
> + struct qmi_tmd_client *qmi_tmd_cli;
> +};
> +
> +/**
> + * struct qmi_tmd_client - QMI TMD client state
> + * @dev: Device associated with this instance
> + * @handle: QMI connection handle
> + * @mutex: Lock to synchronise QMI communication
What is it protecting?
> + * @connection_active: Whether or not we're connected to the QMI TMD service
> + * @svc_arrive_work: Work item for initialising when the TMD service starts
> + * @num_tmds: Number of tmds described in the device tree
> + * @tmds: An array of tmd structures
> + */
> +struct qmi_tmd_client {
> + struct device *dev;
> + struct qmi_handle handle;
> + /* protects QMI transactions and connection_active */
> + struct mutex mutex;
> + bool connection_active;
> + struct work_struct svc_arrive_work;
> + int num_tmds;
> + struct qmi_tmd tmds[] __counted_by(num_tmds);
> +};
> +
> +/* Notify the remote subsystem of the requested cooling state */
> +static int qmi_tmd_send_state_request(struct qmi_tmd *tmd, int state)
> +{
> + struct tmd_set_level_resp resp = { 0 };
> + struct tmd_set_level_req req = { 0 };
> + struct qmi_tmd_client *qmi_tmd_cli = tmd->qmi_tmd_cli;
> + struct qmi_txn txn;
> + int ret = 0;
> +
> + guard(mutex)(&qmi_tmd_cli->mutex);
> +
> + if (!qmi_tmd_cli->connection_active)
> + return 0;
> +
> + strscpy(req.mitigation_dev_id.mitigation_dev_id, tmd->name,
> + QMI_TMD_DEV_ID_LEN_MAX + 1);
> + req.mitigation_level = state;
> +
> + ret = qmi_txn_init(&qmi_tmd_cli->handle, &txn,
> + tmd_set_level_resp_ei, &resp);
> + if (ret < 0) {
> + dev_err(qmi_tmd_cli->dev, "qmi set state %d txn init failed for %s ret %d\n",
> + state, tmd->name, ret);
> + return ret;
> + }
> +
> + ret = qmi_send_request(&qmi_tmd_cli->handle, NULL, &txn,
> + QMI_TMD_SET_LEVEL_REQ,
> + TMD_SET_LEVEL_REQ_MAX_LEN,
> + tmd_set_level_req_ei, &req);
> + if (ret < 0) {
> + dev_err(qmi_tmd_cli->dev, "qmi set state %d txn send failed for %s ret %d\n",
> + state, tmd->name, ret);
> + qmi_txn_cancel(&txn);
> + return ret;
> + }
> +
> + ret = qmi_txn_wait(&txn, QMI_TMD_RESP_TIMEOUT);
> + if (ret < 0) {
> + dev_err(qmi_tmd_cli->dev, "qmi set state %d txn wait failed for %s ret %d\n",
> + state, tmd->name, ret);
> + return ret;
> + }
> +
> + if (resp.resp.result != QMI_RESULT_SUCCESS_V01) {
> + dev_err(qmi_tmd_cli->dev,
> + "qmi set state %d failed for %s result %#x error %#x\n",
> + state, tmd->name,
> + resp.resp.result, resp.resp.error);
> + return -EREMOTEIO;
> + }
> +
> + dev_dbg(qmi_tmd_cli->dev, "Requested state %d/%d for %s\n", state,
> + tmd->max_state, tmd->name);
> +
> + return 0;
> +}
> +
> +static int qmi_tmd_get_max_state(struct thermal_cooling_device *cdev,
> + unsigned long *state)
> +{
> + struct qmi_tmd *tmd = cdev->devdata;
> +
> + *state = tmd->max_state;
> +
> + return 0;
> +}
> +
> +static int qmi_tmd_get_cur_state(struct thermal_cooling_device *cdev,
> + unsigned long *state)
> +{
> + struct qmi_tmd *tmd = cdev->devdata;
> +
> + *state = tmd->cur_state;
Mutex protection?
> +
> + return 0;
> +}
> +
> +static int qmi_tmd_set_cur_state(struct thermal_cooling_device *cdev,
> + unsigned long state)
> +{
> + struct qmi_tmd *tmd = cdev->devdata;
> + int ret;
> +
> + if (state > tmd->max_state)
> + return -EINVAL;
> +
> + if (tmd->cur_state == state)
> + return 0;
Hmm, again, mutex protection for the cur_state? Or is it provided by the
thermal core?
> +
> + ret = qmi_tmd_send_state_request(tmd, state);
> + if (!ret)
> + tmd->cur_state = state;
> +
> + return ret;
> +}
> +
> +static const struct thermal_cooling_device_ops qmi_tmd_cooling_ops = {
> + .get_max_state = qmi_tmd_get_max_state,
> + .get_cur_state = qmi_tmd_get_cur_state,
> + .set_cur_state = qmi_tmd_set_cur_state,
> +};
> +
> +static int qmi_tmd_register(struct qmi_tmd_client *qmi_tmd_cli,
> + const char *label, u8 max_state)
> +{
> + struct device *dev = qmi_tmd_cli->dev;
> + struct qmi_tmd *tmd;
> + int index;
> +
> + for (index = 0; index < qmi_tmd_cli->num_tmds; index++) {
> + tmd = &qmi_tmd_cli->tmds[index];
> +
> + if (!strncasecmp(tmd->name, label,
> + QMI_TMD_DEV_ID_LEN_MAX + 1))
> + goto found;
> + }
> +
> + dev_dbg(qmi_tmd_cli->dev,
> + "TMD '%s' available in firmware but not specified in DT\n",
> + label);
If we can read them from the firmware, why do you need to specify them
in DT?
> + return 0;
> +
> +found:
> + tmd->max_state = max_state;
> +
> + /*
> + * If the cooling device already exists then the QMI service went away and
> + * came back. So just make sure the current cooling device state is
> + * reflected on the remote side and then return.
> + */
> + if (tmd->cdev)
> + return qmi_tmd_send_state_request(tmd, tmd->cur_state);
> +
> + tmd->cdev = thermal_of_cooling_device_register(dev->of_node, index,
> + label, tmd, &qmi_tmd_cooling_ops);
> + if (IS_ERR(tmd->cdev))
> + return PTR_ERR(tmd->cdev);
> +
> + return 0;
> +}
> +
> +static void qmi_tmd_unregister(struct qmi_tmd_client *qmi_tmd_cli)
> +{
> + struct qmi_tmd *tmd;
> + int index;
> +
> + for (index = 0; index < qmi_tmd_cli->num_tmds; index++) {
> + tmd = &qmi_tmd_cli->tmds[index];
> +
> + if (!tmd->cdev)
> + continue;
> +
> + thermal_cooling_device_unregister(tmd->cdev);
> + tmd->cdev = NULL;
> + }
> +}
> +
> +static void qmi_tmd_svc_arrive(struct work_struct *work)
> +{
> + struct qmi_tmd_client *qmi_tmd_cli =
> + container_of(work, struct qmi_tmd_client, svc_arrive_work);
> +
> + struct tmd_get_dev_list_req req = { 0 };
> + struct tmd_get_dev_list_resp *resp __free(kfree) = NULL;
> + int ret, i;
> + struct qmi_txn txn;
> +
> + resp = kzalloc_obj(*resp, GFP_KERNEL);
> + if (!resp) {
> + ret = -ENOMEM;
> + goto out;
> + }
> +
> + scoped_guard(mutex, &qmi_tmd_cli->mutex) {
> + ret = qmi_txn_init(&qmi_tmd_cli->handle, &txn,
> + tmd_get_dev_list_resp_ei, resp);
> + if (ret < 0)
> + goto out;
> +
> + ret = qmi_send_request(&qmi_tmd_cli->handle, NULL, &txn,
> + QMI_TMD_GET_DEV_LIST_REQ,
> + TMD_GET_DEV_LIST_REQ_MAX_LEN,
> + tmd_get_dev_list_req_ei, &req);
> + if (ret < 0) {
> + qmi_txn_cancel(&txn);
> + goto out;
> + }
> +
> + ret = qmi_txn_wait(&txn, QMI_TMD_RESP_TIMEOUT);
> + if (ret < 0)
> + goto out;
> +
> + if (resp->resp.result != QMI_RESULT_SUCCESS_V01) {
> + ret = -EPROTO;
> + goto out;
> + }
> +
> + qmi_tmd_cli->connection_active = true;
> + }
> +
> + for (i = 0; i < resp->mitigation_device_list_len; i++) {
> + struct tmd_dev_list *device =
> + &resp->mitigation_device_list[i];
> +
> + ret = qmi_tmd_register(qmi_tmd_cli,
> + device->mitigation_dev_id.mitigation_dev_id,
> + device->max_mitigation_level);
> + if (ret)
> + break;
> + }
> +
> +out:
> + if (ret)
> + dev_err(qmi_tmd_cli->dev, "Failed to initialize TMD service: %d\n", ret);
> +}
> +
> +static void qmi_tmd_del_server(struct qmi_handle *qmi, struct qmi_service *service)
> +{
> + struct qmi_tmd_client *qmi_tmd_cli =
> + container_of(qmi, struct qmi_tmd_client, handle);
> +
> + kernel_sock_shutdown(qmi->sock, SHUT_RDWR);
So, connection is protected by the mutex, but socket shutdown isn't.
Why?
> +
> + scoped_guard(mutex, &qmi_tmd_cli->mutex)
> + qmi_tmd_cli->connection_active = false;
> +}
> +
> +static int qmi_tmd_new_server(struct qmi_handle *qmi, struct qmi_service *service)
> +{
> + struct sockaddr_qrtr sq = { AF_QIPCRTR, service->node, service->port };
> + struct qmi_tmd_client *qmi_tmd_cli;
> + int ret;
> +
> + qmi_tmd_cli = container_of(qmi, struct qmi_tmd_client, handle);
> +
> + scoped_guard(mutex, &qmi_tmd_cli->mutex) {
> + ret = kernel_connect(qmi->sock, (struct sockaddr_unsized *)&sq,
> + sizeof(sq), 0);
> + }
> +
> + if (ret < 0) {
> + dev_err(qmi_tmd_cli->dev, "QMI connect failed for node %u port %u: %d\n",
> + service->node, service->port, ret);
> + return ret;
> + }
> +
> + queue_work(system_highpri_wq, &qmi_tmd_cli->svc_arrive_work);
> +
> + return 0;
> +}
> +
> +static const struct qmi_ops qmi_tmd_ops = {
> + .new_server = qmi_tmd_new_server,
> + .del_server = qmi_tmd_del_server,
> +};
> +
> +static int qmi_tmd_get_instance_id(const char *remoteproc_name)
> +{
> + if (!strcmp(remoteproc_name, "modem"))
> + return QMI_TMD_INSTANCE_MODEM;
> +
> + if (!strcmp(remoteproc_name, "cdsp"))
> + return QMI_TMD_INSTANCE_CDSP;
> +
> + if (!strcmp(remoteproc_name, "cdsp1"))
> + return QMI_TMD_INSTANCE_CDSP1;
> +
> + return -ENODEV;
Okay, this definitely should be coming from the PAS driver, being a part
of the platform data.
> +}
> +
> +/**
> + * qmi_tmd_init() - Initialize QMI TMD instance
> + * @dev: Device pointer
> + * @remoteproc_name: Remoteproc name (for example modem, cdsp)
> + * @tmd_names: Array of TMD names
> + * @num_tmds: Number of TMD names
> + *
> + * Return: Pointer to qmi_tmd_client on success, ERR_PTR on failure
> + */
> +struct qmi_tmd_client *qmi_tmd_init(struct device *dev,
> + const char *remoteproc_name,
> + const char * const *tmd_names,
> + int num_tmds)
> +{
> + struct qmi_tmd_client *qmi_tmd_cli;
> + int ret, i, instance_id;
> +
> + if (!dev || !remoteproc_name || !tmd_names || num_tmds <= 0)
> + return ERR_PTR(-EINVAL);
> +
> + instance_id = qmi_tmd_get_instance_id(remoteproc_name);
> + if (instance_id < 0) {
> + dev_err(dev, "Unsupported remoteproc name '%s' for TMD lookup\n",
> + remoteproc_name);
> + return ERR_PTR(instance_id);
> + }
> +
> + qmi_tmd_cli = devm_kzalloc(dev, struct_size(qmi_tmd_cli, tmds, num_tmds), GFP_KERNEL);
> + if (!qmi_tmd_cli)
> + return ERR_PTR(-ENOMEM);
> +
> + qmi_tmd_cli->dev = dev;
> + qmi_tmd_cli->num_tmds = num_tmds;
> + mutex_init(&qmi_tmd_cli->mutex);
> + INIT_WORK(&qmi_tmd_cli->svc_arrive_work, qmi_tmd_svc_arrive);
> +
> + /* Initialize TMD structures */
Is it a useful comment?
> + for (i = 0; i < num_tmds; i++) {
> + qmi_tmd_cli->tmds[i].name = tmd_names[i];
> + qmi_tmd_cli->tmds[i].qmi_tmd_cli = qmi_tmd_cli;
> + }
> +
> + ret = qmi_handle_init(&qmi_tmd_cli->handle,
> + TMD_GET_DEV_LIST_RESP_MAX_LEN,
> + &qmi_tmd_ops, NULL);
> + if (ret < 0) {
> + dev_err(dev, "QMI handle init failed: %d\n", ret);
> + return ERR_PTR(ret);
> + }
> +
> + ret = qmi_add_lookup(&qmi_tmd_cli->handle, QMI_SERVICE_ID_TMD,
> + QMI_TMD_SERVICE_VERS_V01, instance_id);
> + if (ret < 0) {
> + dev_err(dev, "QMI add lookup failed: %d\n", ret);
> + goto err_release_handle;
> + }
> +
> + return qmi_tmd_cli;
> +
> +err_release_handle:
> + qmi_handle_release(&qmi_tmd_cli->handle);
> +
> + return ERR_PTR(ret);
> +}
> +EXPORT_SYMBOL_GPL(qmi_tmd_init);
> +
> +/**
> + * qmi_tmd_exit() - Deinitialize QMI TMD instance
> + * @qmi_tmd_cli: QMI TMD client to deinitialize
> + */
> +void qmi_tmd_exit(struct qmi_tmd_client *qmi_tmd_cli)
> +{
> + if (!qmi_tmd_cli)
> + return;
> +
> + cancel_work_sync(&qmi_tmd_cli->svc_arrive_work);
> + qmi_handle_release(&qmi_tmd_cli->handle);
> + qmi_tmd_unregister(qmi_tmd_cli);
> +
> + scoped_guard(mutex, &qmi_tmd_cli->mutex)
> + qmi_tmd_cli->connection_active = false;
> +}
> +EXPORT_SYMBOL_GPL(qmi_tmd_exit);
--
With best wishes
Dmitry
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH v3 3/8] remoteproc: qcom: pas: register TMD thermal cooling devices
2026-06-09 10:22 ` [PATCH v3 3/8] remoteproc: qcom: pas: register TMD thermal " Gaurav Kohli
2026-06-09 10:40 ` sashiko-bot
2026-06-09 11:05 ` Dmitry Baryshkov
@ 2026-06-09 12:03 ` Konrad Dybcio
2 siblings, 0 replies; 18+ messages in thread
From: Konrad Dybcio @ 2026-06-09 12:03 UTC (permalink / raw)
To: Gaurav Kohli, Bjorn Andersson, Mathieu Poirier, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Daniel Lezcano, Amit Kucheria,
Manivannan Sadhasivam, Konrad Dybcio, Kees Cook,
Gustavo A. R. Silva, cros-qcom-dts-watchers
Cc: linux-arm-msm, linux-remoteproc, devicetree, linux-kernel,
linux-pm, linux-hardening, Manaf Meethalavalappu Pallikunhi
On 6/9/26 12:22 PM, Gaurav Kohli wrote:
> Add support for Thermal Mitigation Devices (TMDs) to enable
> thermal throttling of remote processors through QMI.
>
> This enables the thermal framework to request mitigation when remote
> subsystems (modem, CDSP) contribute to thermal issues.
>
> Signed-off-by: Gaurav Kohli <gaurav.kohli@oss.qualcomm.com>
> Signed-off-by: Daniel Lezcano <daniel.lezcano@oss.qualcomm.com>
There's no other signs of Daniel in this patch, please fix the
tags chain
[...]
> +static int qcom_pas_setup_tmd(struct qcom_pas *pas)
> +{
> + struct device *dev = pas->dev;
> + struct device_node *np = dev->of_node;
> + const char **tmd_names;
> + int num_tmds, ret, i;
> +
> + if (!of_find_property(np, "tmd-names", NULL))
Let's use device_property_present() instead
> + return 0;
> +
> + /* Get the TMD names array */
> + num_tmds = of_property_count_strings(np, "tmd-names");
Is this something we can stuff into platform_data for a given rproc on a
given SoC (for which we already store *some* data in the PAS driver)?
Konrad
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH v3 2/8] soc: qcom: Add support for QMI TMD cooling devices
2026-06-09 11:30 ` Dmitry Baryshkov
@ 2026-06-09 12:08 ` Daniel Lezcano
0 siblings, 0 replies; 18+ messages in thread
From: Daniel Lezcano @ 2026-06-09 12:08 UTC (permalink / raw)
To: Dmitry Baryshkov, Gaurav Kohli
Cc: Bjorn Andersson, Mathieu Poirier, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Amit Kucheria,
Manivannan Sadhasivam, Konrad Dybcio, Kees Cook,
Gustavo A. R. Silva, cros-qcom-dts-watchers, linux-arm-msm,
linux-remoteproc, devicetree, linux-kernel, linux-pm,
linux-hardening, Manaf Meethalavalappu Pallikunhi, Casey Connolly
On 6/9/26 13:30, Dmitry Baryshkov wrote:
> On Tue, Jun 09, 2026 at 03:52:57PM +0530, Gaurav Kohli wrote:
>> From: Casey Connolly <casey.connolly@linaro.org>
>>
>> Add a Qualcomm QMI Thermal Mitigation Device (TMD) to support thermal
>> cooling devices backed by remote subsystems.
>>
>> On several Qualcomm platforms, remote processors (for example modem and
>> CDSP) expose thermal mitigation controls through the TMD QMI service.
>> Client drivers need a way to discover that service, map DT thermal
>> mitigation endpoints to cooling devices, and forward cooling state
>> updates to the remote subsystem.
>>
>> Co-developed-by: Gaurav Kohli <gaurav.kohli@oss.qualcomm.com>
>> Signed-off-by: Gaurav Kohli <gaurav.kohli@oss.qualcomm.com>
>> Signed-off-by: Casey Connolly <casey.connolly@linaro.org>
>> Signed-off-by: Daniel Lezcano <daniel.lezcano@oss.qualcomm.com>
>
> Wrong SoB chain.
I think Gaurav wanted to reflect the changes did a back and forth
between us, so I ended up in the delivery path somehow. I guess adding
Co-developped-by should fix the SoB but won't reflect Gaurav and Casey
did actually most of the work. So I'm fine if we remove my SoB to fix
the chain
^ permalink raw reply [flat|nested] 18+ messages in thread
end of thread, other threads:[~2026-06-09 12:09 UTC | newest]
Thread overview: 18+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-06-09 10:22 [PATCH v3 0/8] Add support for Qualcomm remoteproc subsystem cooling Gaurav Kohli
2026-06-09 10:22 ` [PATCH v3 1/8] dt-bindings: remoteproc: qcom,pas: add thermal mitigation properties Gaurav Kohli
2026-06-09 10:36 ` sashiko-bot
2026-06-09 10:47 ` Dmitry Baryshkov
2026-06-09 10:22 ` [PATCH v3 2/8] soc: qcom: Add support for QMI TMD cooling devices Gaurav Kohli
2026-06-09 10:37 ` sashiko-bot
2026-06-09 11:30 ` Dmitry Baryshkov
2026-06-09 12:08 ` Daniel Lezcano
2026-06-09 10:22 ` [PATCH v3 3/8] remoteproc: qcom: pas: register TMD thermal " Gaurav Kohli
2026-06-09 10:40 ` sashiko-bot
2026-06-09 11:05 ` Dmitry Baryshkov
2026-06-09 12:03 ` Konrad Dybcio
2026-06-09 10:22 ` [PATCH v3 4/8] arm64: dts: qcom: kodiak: Enable CDSP & Modem cooling Gaurav Kohli
2026-06-09 10:57 ` Dmitry Baryshkov
2026-06-09 10:23 ` [PATCH v3 5/8] arm64: dts: qcom: lemans: Enable CDSP cooling Gaurav Kohli
2026-06-09 10:23 ` [PATCH v3 6/8] arm64: dts: qcom: talos: " Gaurav Kohli
2026-06-09 10:23 ` [PATCH v3 7/8] arm64: dts: qcom: monaco: " Gaurav Kohli
2026-06-09 10:23 ` [PATCH v3 8/8] arm64: dts: qcom: hamoa: " Gaurav Kohli
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.