From 9f9967fed9d066ed3dae9372b45ffa4f6fccfeef Mon Sep 17 00:00:00 2001 From: Bjorn Andersson Date: Tue, 10 Jun 2025 21:58:28 -0500 Subject: [PATCH 01/15] soc: qcom: mdt_loader: Ensure we don't read past the ELF header When the MDT loader is used in remoteproc, the ELF header is sanitized beforehand, but that's not necessary the case for other clients. Validate the size of the firmware buffer to ensure that we don't read past the end as we iterate over the header. e_phentsize and e_shentsize are validated as well, to ensure that the assumptions about step size in the traversal are valid. Fixes: 2aad40d911ee ("remoteproc: Move qcom_mdt_loader into drivers/soc/qcom") Cc: stable@vger.kernel.org Reported-by: Doug Anderson Signed-off-by: Bjorn Andersson Reviewed-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/20250610-mdt-loader-validation-and-fixes-v2-1-f7073e9ab899@oss.qualcomm.com Signed-off-by: Bjorn Andersson --- drivers/soc/qcom/mdt_loader.c | 43 +++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/drivers/soc/qcom/mdt_loader.c b/drivers/soc/qcom/mdt_loader.c index b2c0fb55d4ae..b2c9731b6f2a 100644 --- a/drivers/soc/qcom/mdt_loader.c +++ b/drivers/soc/qcom/mdt_loader.c @@ -18,6 +18,37 @@ #include #include +static bool mdt_header_valid(const struct firmware *fw) +{ + const struct elf32_hdr *ehdr; + size_t phend; + size_t shend; + + if (fw->size < sizeof(*ehdr)) + return false; + + ehdr = (struct elf32_hdr *)fw->data; + + if (memcmp(ehdr->e_ident, ELFMAG, SELFMAG)) + return false; + + if (ehdr->e_phentsize != sizeof(struct elf32_phdr)) + return -EINVAL; + + phend = size_add(size_mul(sizeof(struct elf32_phdr), ehdr->e_phnum), ehdr->e_phoff); + if (phend > fw->size) + return false; + + if (ehdr->e_shentsize != sizeof(struct elf32_shdr)) + return -EINVAL; + + shend = size_add(size_mul(sizeof(struct elf32_shdr), ehdr->e_shnum), ehdr->e_shoff); + if (shend > fw->size) + return false; + + return true; +} + static bool mdt_phdr_valid(const struct elf32_phdr *phdr) { if (phdr->p_type != PT_LOAD) @@ -82,6 +113,9 @@ ssize_t qcom_mdt_get_size(const struct firmware *fw) phys_addr_t max_addr = 0; int i; + if (!mdt_header_valid(fw)) + return -EINVAL; + ehdr = (struct elf32_hdr *)fw->data; phdrs = (struct elf32_phdr *)(ehdr + 1); @@ -134,6 +168,9 @@ void *qcom_mdt_read_metadata(const struct firmware *fw, size_t *data_len, ssize_t ret; void *data; + if (!mdt_header_valid(fw)) + return ERR_PTR(-EINVAL); + ehdr = (struct elf32_hdr *)fw->data; phdrs = (struct elf32_phdr *)(ehdr + 1); @@ -214,6 +251,9 @@ int qcom_mdt_pas_init(struct device *dev, const struct firmware *fw, int ret; int i; + if (!mdt_header_valid(fw)) + return -EINVAL; + ehdr = (struct elf32_hdr *)fw->data; phdrs = (struct elf32_phdr *)(ehdr + 1); @@ -310,6 +350,9 @@ static int __qcom_mdt_load(struct device *dev, const struct firmware *fw, if (!fw || !mem_region || !mem_phys || !mem_size) return -EINVAL; + if (!mdt_header_valid(fw)) + return -EINVAL; + is_split = qcom_mdt_bins_are_split(fw, fw_name); ehdr = (struct elf32_hdr *)fw->data; phdrs = (struct elf32_phdr *)(ehdr + 1); From cd840362b0a7b3da59740c1380b18ce0ccf8c264 Mon Sep 17 00:00:00 2001 From: Bjorn Andersson Date: Tue, 10 Jun 2025 21:58:29 -0500 Subject: [PATCH 02/15] soc: qcom: mdt_loader: Rename mdt_phdr_valid() The function checks if a program header refers to a PT_LOAD segment, that isn't a hash segment (which should be PT_LOAD in the first place), andwith non-zero size. That's not the definition of "valid", but rather if it's "loadable". Rename the function to reflect what it does. Reviewed-by: Dmitry Baryshkov Signed-off-by: Bjorn Andersson Link: https://lore.kernel.org/r/20250610-mdt-loader-validation-and-fixes-v2-2-f7073e9ab899@oss.qualcomm.com Signed-off-by: Bjorn Andersson --- drivers/soc/qcom/mdt_loader.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/soc/qcom/mdt_loader.c b/drivers/soc/qcom/mdt_loader.c index b2c9731b6f2a..52f0c8bb7c5e 100644 --- a/drivers/soc/qcom/mdt_loader.c +++ b/drivers/soc/qcom/mdt_loader.c @@ -49,7 +49,7 @@ static bool mdt_header_valid(const struct firmware *fw) return true; } -static bool mdt_phdr_valid(const struct elf32_phdr *phdr) +static bool mdt_phdr_loadable(const struct elf32_phdr *phdr) { if (phdr->p_type != PT_LOAD) return false; @@ -122,7 +122,7 @@ ssize_t qcom_mdt_get_size(const struct firmware *fw) for (i = 0; i < ehdr->e_phnum; i++) { phdr = &phdrs[i]; - if (!mdt_phdr_valid(phdr)) + if (!mdt_phdr_loadable(phdr)) continue; if (phdr->p_paddr < min_addr) @@ -260,7 +260,7 @@ int qcom_mdt_pas_init(struct device *dev, const struct firmware *fw, for (i = 0; i < ehdr->e_phnum; i++) { phdr = &phdrs[i]; - if (!mdt_phdr_valid(phdr)) + if (!mdt_phdr_loadable(phdr)) continue; if (phdr->p_flags & QCOM_MDT_RELOCATABLE) @@ -360,7 +360,7 @@ static int __qcom_mdt_load(struct device *dev, const struct firmware *fw, for (i = 0; i < ehdr->e_phnum; i++) { phdr = &phdrs[i]; - if (!mdt_phdr_valid(phdr)) + if (!mdt_phdr_loadable(phdr)) continue; if (phdr->p_flags & QCOM_MDT_RELOCATABLE) @@ -387,7 +387,7 @@ static int __qcom_mdt_load(struct device *dev, const struct firmware *fw, for (i = 0; i < ehdr->e_phnum; i++) { phdr = &phdrs[i]; - if (!mdt_phdr_valid(phdr)) + if (!mdt_phdr_loadable(phdr)) continue; offset = phdr->p_paddr - mem_reloc; From 47e339cac89143709e84a3b71ba8bd9b2fdd2368 Mon Sep 17 00:00:00 2001 From: Bjorn Andersson Date: Tue, 10 Jun 2025 21:58:30 -0500 Subject: [PATCH 03/15] soc: qcom: mdt_loader: Actually use the e_phoff Rather than relying/assuming that the tools generating the firmware places the program headers immediately following the ELF header, use e_phoff as intended to find the program headers. Reviewed-by: Dmitry Baryshkov Signed-off-by: Bjorn Andersson Link: https://lore.kernel.org/r/20250610-mdt-loader-validation-and-fixes-v2-3-f7073e9ab899@oss.qualcomm.com Signed-off-by: Bjorn Andersson --- drivers/soc/qcom/mdt_loader.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/soc/qcom/mdt_loader.c b/drivers/soc/qcom/mdt_loader.c index 52f0c8bb7c5e..1b4ebae458f3 100644 --- a/drivers/soc/qcom/mdt_loader.c +++ b/drivers/soc/qcom/mdt_loader.c @@ -117,7 +117,7 @@ ssize_t qcom_mdt_get_size(const struct firmware *fw) return -EINVAL; ehdr = (struct elf32_hdr *)fw->data; - phdrs = (struct elf32_phdr *)(ehdr + 1); + phdrs = (struct elf32_phdr *)(fw->data + ehdr->e_phoff); for (i = 0; i < ehdr->e_phnum; i++) { phdr = &phdrs[i]; @@ -172,7 +172,7 @@ void *qcom_mdt_read_metadata(const struct firmware *fw, size_t *data_len, return ERR_PTR(-EINVAL); ehdr = (struct elf32_hdr *)fw->data; - phdrs = (struct elf32_phdr *)(ehdr + 1); + phdrs = (struct elf32_phdr *)(fw->data + ehdr->e_phoff); if (ehdr->e_phnum < 2) return ERR_PTR(-EINVAL); @@ -255,7 +255,7 @@ int qcom_mdt_pas_init(struct device *dev, const struct firmware *fw, return -EINVAL; ehdr = (struct elf32_hdr *)fw->data; - phdrs = (struct elf32_phdr *)(ehdr + 1); + phdrs = (struct elf32_phdr *)(fw->data + ehdr->e_phoff); for (i = 0; i < ehdr->e_phnum; i++) { phdr = &phdrs[i]; @@ -310,7 +310,7 @@ static bool qcom_mdt_bins_are_split(const struct firmware *fw, const char *fw_na int i; ehdr = (struct elf32_hdr *)fw->data; - phdrs = (struct elf32_phdr *)(ehdr + 1); + phdrs = (struct elf32_phdr *)(fw->data + ehdr->e_phoff); for (i = 0; i < ehdr->e_phnum; i++) { /* @@ -355,7 +355,7 @@ static int __qcom_mdt_load(struct device *dev, const struct firmware *fw, is_split = qcom_mdt_bins_are_split(fw, fw_name); ehdr = (struct elf32_hdr *)fw->data; - phdrs = (struct elf32_phdr *)(ehdr + 1); + phdrs = (struct elf32_phdr *)(fw->data + ehdr->e_phoff); for (i = 0; i < ehdr->e_phnum; i++) { phdr = &phdrs[i]; From 33301e5b2aeccb1208ddb2d1cc93c9c6c520a0b6 Mon Sep 17 00:00:00 2001 From: Maulik Shah Date: Wed, 11 Jun 2025 11:33:45 +0530 Subject: [PATCH 04/15] soc: qcom: qcom_stats: Add support to read DDR statistic DDR statistic provide different DDR LPM and DDR frequency statistic. Add support to read from MSGRAM and display via debugfs. Reviewed-by: Konrad Dybcio Reviewed-by: Dmitry Baryshkov Signed-off-by: Maulik Shah Link: https://lore.kernel.org/r/20250611-ddr_stats_-v5-1-24b16dd67c9c@oss.qualcomm.com Signed-off-by: Bjorn Andersson --- drivers/soc/qcom/qcom_stats.c | 99 +++++++++++++++++++++++++++++++++++ 1 file changed, 99 insertions(+) diff --git a/drivers/soc/qcom/qcom_stats.c b/drivers/soc/qcom/qcom_stats.c index 5de99cf59b9f..33fd2a157446 100644 --- a/drivers/soc/qcom/qcom_stats.c +++ b/drivers/soc/qcom/qcom_stats.c @@ -1,8 +1,10 @@ // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2011-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2025, Qualcomm Innovation Center, Inc. All rights reserved. */ +#include #include #include #include @@ -24,6 +26,17 @@ #define ACCUMULATED_OFFSET 0x18 #define CLIENT_VOTES_OFFSET 0x20 +#define DDR_STATS_MAGIC_KEY 0xA1157A75 +#define DDR_STATS_MAX_NUM_MODES 20 +#define DDR_STATS_MAGIC_KEY_ADDR 0x0 +#define DDR_STATS_NUM_MODES_ADDR 0x4 +#define DDR_STATS_ENTRY_START_ADDR 0x8 + +#define DDR_STATS_CP_IDX(data) FIELD_GET(GENMASK(4, 0), data) +#define DDR_STATS_LPM_NAME(data) FIELD_GET(GENMASK(7, 0), data) +#define DDR_STATS_TYPE(data) FIELD_GET(GENMASK(15, 8), data) +#define DDR_STATS_FREQ(data) FIELD_GET(GENMASK(31, 16), data) + struct subsystem_data { const char *name; u32 smem_item; @@ -48,12 +61,19 @@ static const struct subsystem_data subsystems[] = { struct stats_config { size_t stats_offset; + size_t ddr_stats_offset; size_t num_records; bool appended_stats_avail; bool dynamic_offset; bool subsystem_stats_in_smem; }; +struct ddr_stats_entry { + u32 name; + u32 count; + u64 duration; +}; + struct stats_data { bool appended_stats_avail; void __iomem *base; @@ -122,8 +142,85 @@ static int qcom_soc_sleep_stats_show(struct seq_file *s, void *unused) return 0; } +static void qcom_ddr_stats_print(struct seq_file *s, struct ddr_stats_entry *data) +{ + u32 cp_idx; + + /* + * DDR statistic have two different types of details encoded. + * (1) DDR LPM Stats + * (2) DDR Frequency Stats + * + * The name field have details like which type of DDR stat (bits 8:15) + * along with other details as explained below + * + * In case of DDR LPM stat, name field will be encoded as, + * Bits - Meaning + * 0:7 - DDR LPM name, can be of 0xd4, 0xd3, 0x11 and 0xd0. + * 8:15 - 0x0 (indicates its a LPM stat) + * 16:31 - Unused + * + * In case of DDR FREQ stats, name field will be encoded as, + * Bits - Meaning + * 0:4 - DDR Clock plan index (CP IDX) + * 5:7 - Unused + * 8:15 - 0x1 (indicates its Freq stat) + * 16:31 - Frequency value in Mhz + */ + switch (DDR_STATS_TYPE(data->name)) { + case 0: + seq_printf(s, "DDR LPM Stat Name:0x%lx\tcount:%u\tDuration (ticks):%llu\n", + DDR_STATS_LPM_NAME(data->name), data->count, data->duration); + break; + case 1: + if (!data->count || !DDR_STATS_FREQ(data->name)) + return; + + cp_idx = DDR_STATS_CP_IDX(data->name); + seq_printf(s, "DDR Freq %luMhz:\tCP IDX:%u\tcount:%u\tDuration (ticks):%llu\n", + DDR_STATS_FREQ(data->name), cp_idx, data->count, data->duration); + break; + } +} + +static int qcom_ddr_stats_show(struct seq_file *s, void *d) +{ + struct ddr_stats_entry data[DDR_STATS_MAX_NUM_MODES]; + void __iomem *reg = (void __iomem *)s->private; + u32 entry_count; + int i; + + entry_count = readl_relaxed(reg + DDR_STATS_NUM_MODES_ADDR); + if (entry_count > DDR_STATS_MAX_NUM_MODES) + return -EINVAL; + + reg += DDR_STATS_ENTRY_START_ADDR; + memcpy_fromio(data, reg, sizeof(struct ddr_stats_entry) * entry_count); + + for (i = 0; i < entry_count; i++) + qcom_ddr_stats_print(s, &data[i]); + + return 0; +} + DEFINE_SHOW_ATTRIBUTE(qcom_soc_sleep_stats); DEFINE_SHOW_ATTRIBUTE(qcom_subsystem_sleep_stats); +DEFINE_SHOW_ATTRIBUTE(qcom_ddr_stats); + +static void qcom_create_ddr_stat_files(struct dentry *root, void __iomem *reg, + const struct stats_config *config) +{ + u32 key; + + if (!config->ddr_stats_offset) + return; + + key = readl_relaxed(reg + config->ddr_stats_offset + DDR_STATS_MAGIC_KEY_ADDR); + if (key == DDR_STATS_MAGIC_KEY) + debugfs_create_file("ddr_stats", 0400, root, + (__force void *)reg + config->ddr_stats_offset, + &qcom_ddr_stats_fops); +} static void qcom_create_soc_sleep_stat_files(struct dentry *root, void __iomem *reg, struct stats_data *d, @@ -212,6 +309,7 @@ static int qcom_stats_probe(struct platform_device *pdev) qcom_create_subsystem_stat_files(root, config); qcom_create_soc_sleep_stat_files(root, reg, d, config); + qcom_create_ddr_stat_files(root, reg, config); platform_set_drvdata(pdev, root); @@ -254,6 +352,7 @@ static const struct stats_config rpmh_data_sdm845 = { static const struct stats_config rpmh_data = { .stats_offset = 0x48, + .ddr_stats_offset = 0xb8, .num_records = 3, .appended_stats_avail = false, .dynamic_offset = false, From e265de1f4815c05803e02fed20a093114e418c46 Mon Sep 17 00:00:00 2001 From: Maulik Shah Date: Wed, 11 Jun 2025 11:33:46 +0530 Subject: [PATCH 05/15] soc: qcom: qcom_stats: Add QMP support for syncing ddr stats Recent SoCs (SM8450 onwards) require QMP command to be sent before reading ddr stats. The duration field of ddr stats will get populated only if QMP command is sent. Add support to send ddr stats freqsync QMP command. Signed-off-by: Maulik Shah Reviewed-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/20250611-ddr_stats_-v5-2-24b16dd67c9c@oss.qualcomm.com Signed-off-by: Bjorn Andersson --- drivers/soc/qcom/qcom_stats.c | 36 ++++++++++++++++++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-) diff --git a/drivers/soc/qcom/qcom_stats.c b/drivers/soc/qcom/qcom_stats.c index 33fd2a157446..2e380faf9080 100644 --- a/drivers/soc/qcom/qcom_stats.c +++ b/drivers/soc/qcom/qcom_stats.c @@ -13,6 +13,7 @@ #include #include +#include #include #include @@ -37,6 +38,8 @@ #define DDR_STATS_TYPE(data) FIELD_GET(GENMASK(15, 8), data) #define DDR_STATS_FREQ(data) FIELD_GET(GENMASK(31, 16), data) +static struct qmp *qcom_stats_qmp; + struct subsystem_data { const char *name; u32 smem_item; @@ -188,12 +191,28 @@ static int qcom_ddr_stats_show(struct seq_file *s, void *d) struct ddr_stats_entry data[DDR_STATS_MAX_NUM_MODES]; void __iomem *reg = (void __iomem *)s->private; u32 entry_count; - int i; + int i, ret; entry_count = readl_relaxed(reg + DDR_STATS_NUM_MODES_ADDR); if (entry_count > DDR_STATS_MAX_NUM_MODES) return -EINVAL; + if (qcom_stats_qmp) { + /* + * Recent SoCs (SM8450 onwards) do not have duration field + * populated from boot up onwards for both DDR LPM Stats + * and DDR Frequency Stats. + * + * Send QMP message to Always on processor which will + * populate duration field into MSG RAM area. + * + * Sent every time to read latest data. + */ + ret = qmp_send(qcom_stats_qmp, "{class: ddr, action: freqsync}"); + if (ret) + return ret; + } + reg += DDR_STATS_ENTRY_START_ADDR; memcpy_fromio(data, reg, sizeof(struct ddr_stats_entry) * entry_count); @@ -304,6 +323,21 @@ static int qcom_stats_probe(struct platform_device *pdev) for (i = 0; i < config->num_records; i++) d[i].appended_stats_avail = config->appended_stats_avail; + /* + * QMP is used for DDR stats syncing to MSG RAM for recent SoCs (SM8450 onwards). + * The prior SoCs do not need QMP handle as the required stats are already present + * in MSG RAM, provided the DDR_STATS_MAGIC_KEY matches. + */ + qcom_stats_qmp = qmp_get(&pdev->dev); + if (IS_ERR(qcom_stats_qmp)) { + /* We ignore error if QMP is not defined/needed */ + if (!of_property_present(pdev->dev.of_node, "qcom,qmp")) + qcom_stats_qmp = NULL; + else if (PTR_ERR(qcom_stats_qmp) == -EPROBE_DEFER) + return -EPROBE_DEFER; + else + return PTR_ERR(qcom_stats_qmp); + } root = debugfs_create_dir("qcom_stats", NULL); From b0123a8aa9dda9c89f0fe7d30a87c03fcddfc505 Mon Sep 17 00:00:00 2001 From: Lijuan Gao Date: Mon, 26 May 2025 13:21:48 +0800 Subject: [PATCH 06/15] dt-bindings: soc: qcom: add qcom,qcs615-imem compatible Document qcom,qcs615-imem compatible. It has a child node for debugging purposes. Acked-by: Krzysztof Kozlowski Signed-off-by: Lijuan Gao Link: https://lore.kernel.org/r/20250526-add_qcs615_remoteproc_support-v4-2-06a7d8bed0b5@quicinc.com Signed-off-by: Bjorn Andersson --- Documentation/devicetree/bindings/sram/qcom,imem.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/sram/qcom,imem.yaml b/Documentation/devicetree/bindings/sram/qcom,imem.yaml index 2711f90d9664..dc3b5a69b925 100644 --- a/Documentation/devicetree/bindings/sram/qcom,imem.yaml +++ b/Documentation/devicetree/bindings/sram/qcom,imem.yaml @@ -22,6 +22,7 @@ properties: - qcom,msm8974-imem - qcom,msm8976-imem - qcom,qcs404-imem + - qcom,qcs615-imem - qcom,qcs8300-imem - qcom,qdu1000-imem - qcom,sa8775p-imem From 3ced38da5f7de4c260f9eaa86fc805827953243a Mon Sep 17 00:00:00 2001 From: Alexander Wilhelm Date: Thu, 22 May 2025 16:35:29 +0200 Subject: [PATCH 07/15] soc: qcom: QMI encoding/decoding for big endian The QMI_DATA_LEN type may have different sizes. Taking the element's address of that type and interpret it as a smaller sized ones works fine for little endian platforms but not for big endian ones. Instead use temporary variables of smaller sized types and cast them correctly to support big endian platforms. Signed-off-by: Alexander Wilhelm Fixes: 9b8a11e82615 ("soc: qcom: Introduce QMI encoder/decoder") Reviewed-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/20250522143530.3623809-2-alexander.wilhelm@westermo.com Signed-off-by: Bjorn Andersson --- drivers/soc/qcom/qmi_encdec.c | 46 +++++++++++++++++++++++++++++------ 1 file changed, 38 insertions(+), 8 deletions(-) diff --git a/drivers/soc/qcom/qmi_encdec.c b/drivers/soc/qcom/qmi_encdec.c index bb09eff85cff..dafe0a4c202e 100644 --- a/drivers/soc/qcom/qmi_encdec.c +++ b/drivers/soc/qcom/qmi_encdec.c @@ -304,6 +304,8 @@ static int qmi_encode(const struct qmi_elem_info *ei_array, void *out_buf, const void *buf_src; int encode_tlv = 0; int rc; + u8 val8; + u16 val16; if (!ei_array) return 0; @@ -338,7 +340,6 @@ static int qmi_encode(const struct qmi_elem_info *ei_array, void *out_buf, break; case QMI_DATA_LEN: - memcpy(&data_len_value, buf_src, temp_ei->elem_size); data_len_sz = temp_ei->elem_size == sizeof(u8) ? sizeof(u8) : sizeof(u16); /* Check to avoid out of range buffer access */ @@ -348,8 +349,17 @@ static int qmi_encode(const struct qmi_elem_info *ei_array, void *out_buf, __func__); return -ETOOSMALL; } - rc = qmi_encode_basic_elem(buf_dst, &data_len_value, - 1, data_len_sz); + if (data_len_sz == sizeof(u8)) { + val8 = *(u8 *)buf_src; + data_len_value = (u32)val8; + rc = qmi_encode_basic_elem(buf_dst, &val8, + 1, data_len_sz); + } else { + val16 = *(u16 *)buf_src; + data_len_value = (u32)le16_to_cpu(val16); + rc = qmi_encode_basic_elem(buf_dst, &val16, + 1, data_len_sz); + } UPDATE_ENCODE_VARIABLES(temp_ei, buf_dst, encoded_bytes, tlv_len, encode_tlv, rc); @@ -523,14 +533,23 @@ static int qmi_decode_string_elem(const struct qmi_elem_info *ei_array, u32 string_len = 0; u32 string_len_sz = 0; const struct qmi_elem_info *temp_ei = ei_array; + u8 val8; + u16 val16; if (dec_level == 1) { string_len = tlv_len; } else { string_len_sz = temp_ei->elem_len <= U8_MAX ? sizeof(u8) : sizeof(u16); - rc = qmi_decode_basic_elem(&string_len, buf_src, - 1, string_len_sz); + if (string_len_sz == sizeof(u8)) { + rc = qmi_decode_basic_elem(&val8, buf_src, + 1, string_len_sz); + string_len = (u32)val8; + } else { + rc = qmi_decode_basic_elem(&val16, buf_src, + 1, string_len_sz); + string_len = (u32)val16; + } decoded_bytes += rc; } @@ -604,6 +623,9 @@ static int qmi_decode(const struct qmi_elem_info *ei_array, void *out_c_struct, u32 decoded_bytes = 0; const void *buf_src = in_buf; int rc; + u8 val8; + u16 val16; + u32 val32; while (decoded_bytes < in_buf_len) { if (dec_level >= 2 && temp_ei->data_type == QMI_EOTI) @@ -642,9 +664,17 @@ static int qmi_decode(const struct qmi_elem_info *ei_array, void *out_c_struct, if (temp_ei->data_type == QMI_DATA_LEN) { data_len_sz = temp_ei->elem_size == sizeof(u8) ? sizeof(u8) : sizeof(u16); - rc = qmi_decode_basic_elem(&data_len_value, buf_src, - 1, data_len_sz); - memcpy(buf_dst, &data_len_value, sizeof(u32)); + if (data_len_sz == sizeof(u8)) { + rc = qmi_decode_basic_elem(&val8, buf_src, + 1, data_len_sz); + data_len_value = (u32)val8; + } else { + rc = qmi_decode_basic_elem(&val16, buf_src, + 1, data_len_sz); + data_len_value = (u32)val16; + } + val32 = cpu_to_le32(data_len_value); + memcpy(buf_dst, &val32, sizeof(u32)); temp_ei = temp_ei + 1; buf_dst = out_c_struct + temp_ei->offset; tlv_len -= data_len_sz; From 07a4688833b237331e5045f90fc546c085b28c86 Mon Sep 17 00:00:00 2001 From: Alexander Wilhelm Date: Thu, 22 May 2025 16:35:30 +0200 Subject: [PATCH 08/15] soc: qcom: fix endianness for QMI header The members of QMI header have to be swapped on big endian platforms. Use __le16 types instead of u16 ones. Signed-off-by: Alexander Wilhelm Fixes: 9b8a11e82615 ("soc: qcom: Introduce QMI encoder/decoder") Fixes: 3830d0771ef6 ("soc: qcom: Introduce QMI helpers") Reviewed-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/20250522143530.3623809-3-alexander.wilhelm@westermo.com Signed-off-by: Bjorn Andersson --- drivers/soc/qcom/qmi_encdec.c | 6 +++--- drivers/soc/qcom/qmi_interface.c | 6 +++--- include/linux/soc/qcom/qmi.h | 6 +++--- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/drivers/soc/qcom/qmi_encdec.c b/drivers/soc/qcom/qmi_encdec.c index dafe0a4c202e..7660a960fb45 100644 --- a/drivers/soc/qcom/qmi_encdec.c +++ b/drivers/soc/qcom/qmi_encdec.c @@ -776,9 +776,9 @@ void *qmi_encode_message(int type, unsigned int msg_id, size_t *len, hdr = msg; hdr->type = type; - hdr->txn_id = txn_id; - hdr->msg_id = msg_id; - hdr->msg_len = msglen; + hdr->txn_id = cpu_to_le16(txn_id); + hdr->msg_id = cpu_to_le16(msg_id); + hdr->msg_len = cpu_to_le16(msglen); *len = sizeof(*hdr) + msglen; diff --git a/drivers/soc/qcom/qmi_interface.c b/drivers/soc/qcom/qmi_interface.c index bc6d6379d8b1..6500f863aae5 100644 --- a/drivers/soc/qcom/qmi_interface.c +++ b/drivers/soc/qcom/qmi_interface.c @@ -400,7 +400,7 @@ static void qmi_invoke_handler(struct qmi_handle *qmi, struct sockaddr_qrtr *sq, for (handler = qmi->handlers; handler->fn; handler++) { if (handler->type == hdr->type && - handler->msg_id == hdr->msg_id) + handler->msg_id == le16_to_cpu(hdr->msg_id)) break; } @@ -488,7 +488,7 @@ static void qmi_handle_message(struct qmi_handle *qmi, /* If this is a response, find the matching transaction handle */ if (hdr->type == QMI_RESPONSE) { mutex_lock(&qmi->txn_lock); - txn = idr_find(&qmi->txns, hdr->txn_id); + txn = idr_find(&qmi->txns, le16_to_cpu(hdr->txn_id)); /* Ignore unexpected responses */ if (!txn) { @@ -514,7 +514,7 @@ static void qmi_handle_message(struct qmi_handle *qmi, } else { /* Create a txn based on the txn_id of the incoming message */ memset(&tmp_txn, 0, sizeof(tmp_txn)); - tmp_txn.id = hdr->txn_id; + tmp_txn.id = le16_to_cpu(hdr->txn_id); qmi_invoke_handler(qmi, sq, &tmp_txn, buf, len); } diff --git a/include/linux/soc/qcom/qmi.h b/include/linux/soc/qcom/qmi.h index 469e02d2aa0d..291cdc7ef49c 100644 --- a/include/linux/soc/qcom/qmi.h +++ b/include/linux/soc/qcom/qmi.h @@ -24,9 +24,9 @@ struct socket; */ struct qmi_header { u8 type; - u16 txn_id; - u16 msg_id; - u16 msg_len; + __le16 txn_id; + __le16 msg_id; + __le16 msg_len; } __packed; #define QMI_REQUEST 0 From 64a026dd896e423a177fe87e11aa69bf5348c27b Mon Sep 17 00:00:00 2001 From: Kathiravan Thirumoorthy Date: Mon, 19 May 2025 19:14:01 +0530 Subject: [PATCH 09/15] soc: qcom: socinfo: Add support to retrieve TME build details Add support to retrieve Trust Management Engine (TME) image details from SMEM, which is present in the IPQ5424 SoC. Signed-off-by: Kathiravan Thirumoorthy Reviewed-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/20250519-tme-crm-version-v1-1-a6dceadc10aa@oss.qualcomm.com Signed-off-by: Bjorn Andersson --- drivers/soc/qcom/socinfo.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/soc/qcom/socinfo.c b/drivers/soc/qcom/socinfo.c index 8c4147737c35..391380820f08 100644 --- a/drivers/soc/qcom/socinfo.c +++ b/drivers/soc/qcom/socinfo.c @@ -48,6 +48,7 @@ #define SMEM_IMAGE_TABLE_CDSP1_INDEX 19 #define SMEM_IMAGE_TABLE_GPDSP_INDEX 20 #define SMEM_IMAGE_TABLE_GPDSP1_INDEX 21 +#define SMEM_IMAGE_TABLE_TME_INDEX 28 #define SMEM_IMAGE_VERSION_TABLE 469 /* @@ -67,6 +68,7 @@ static const char *const socinfo_image_names[] = { [SMEM_IMAGE_TABLE_CDSP1_INDEX] = "cdsp1", [SMEM_IMAGE_TABLE_GPDSP_INDEX] = "gpdsp", [SMEM_IMAGE_TABLE_GPDSP1_INDEX] = "gpdsp1", + [SMEM_IMAGE_TABLE_TME_INDEX] = "tme", }; static const char *const pmic_models[] = { From 71da9389a51c257ed1177bd33bb641e9a21c6a5f Mon Sep 17 00:00:00 2001 From: Danila Tikhonov Date: Tue, 22 Apr 2025 23:17:13 +0300 Subject: [PATCH 10/15] dt-bindings: soc: qcom,dcc: Add the SM7150 compatible Document DDC compatible for SM7150. Signed-off-by: Danila Tikhonov Link: https://lore.kernel.org/r/20250422-sm7150-upstream-v1-12-bf9a9081631d@jiaxyga.com Signed-off-by: Bjorn Andersson --- Documentation/devicetree/bindings/soc/qcom/qcom,dcc.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/soc/qcom/qcom,dcc.yaml b/Documentation/devicetree/bindings/soc/qcom/qcom,dcc.yaml index ce7e20dd22c9..fdc6fc17ed71 100644 --- a/Documentation/devicetree/bindings/soc/qcom/qcom,dcc.yaml +++ b/Documentation/devicetree/bindings/soc/qcom/qcom,dcc.yaml @@ -18,6 +18,7 @@ properties: compatible: items: - enum: + - qcom,sm7150-dcc - qcom,sm8150-dcc - qcom,sc7280-dcc - qcom,sc7180-dcc From 23b0f375b542d6aea4e4d7529abb142a791023e5 Mon Sep 17 00:00:00 2001 From: David Wronek Date: Tue, 22 Apr 2025 23:17:07 +0300 Subject: [PATCH 11/15] dt-bindings: soc: qcom: aoss-qmp: Add the SM7150 compatible Document the AOSS QMP compatible for SM7150. Signed-off-by: David Wronek Signed-off-by: Danila Tikhonov Link: https://lore.kernel.org/r/20250422-sm7150-upstream-v1-6-bf9a9081631d@jiaxyga.com Signed-off-by: Bjorn Andersson --- Documentation/devicetree/bindings/soc/qcom/qcom,aoss-qmp.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/soc/qcom/qcom,aoss-qmp.yaml b/Documentation/devicetree/bindings/soc/qcom/qcom,aoss-qmp.yaml index 41fbbe059d80..b1a786b838d5 100644 --- a/Documentation/devicetree/bindings/soc/qcom/qcom,aoss-qmp.yaml +++ b/Documentation/devicetree/bindings/soc/qcom/qcom,aoss-qmp.yaml @@ -38,6 +38,7 @@ properties: - qcom,sdx75-aoss-qmp - qcom,sdm845-aoss-qmp - qcom,sm6350-aoss-qmp + - qcom,sm7150-aoss-qmp - qcom,sm8150-aoss-qmp - qcom,sm8250-aoss-qmp - qcom,sm8350-aoss-qmp From ee4eba06d617e2be45e54a9fa2be070bb36d9e10 Mon Sep 17 00:00:00 2001 From: Danila Tikhonov Date: Tue, 22 Apr 2025 23:17:06 +0300 Subject: [PATCH 12/15] dt-bindings: sram: qcom,imem: Add the SM7150 compatible Add compatible for SM7150 SoC IMEM. Signed-off-by: Danila Tikhonov Link: https://lore.kernel.org/r/20250422-sm7150-upstream-v1-5-bf9a9081631d@jiaxyga.com Signed-off-by: Bjorn Andersson --- Documentation/devicetree/bindings/sram/qcom,imem.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/sram/qcom,imem.yaml b/Documentation/devicetree/bindings/sram/qcom,imem.yaml index dc3b5a69b925..c49734b53369 100644 --- a/Documentation/devicetree/bindings/sram/qcom,imem.yaml +++ b/Documentation/devicetree/bindings/sram/qcom,imem.yaml @@ -33,6 +33,7 @@ properties: - qcom,sdx55-imem - qcom,sdx65-imem - qcom,sm6375-imem + - qcom,sm7150-imem - qcom,sm8450-imem - const: syscon - const: simple-mfd From 7b768d1235dbd98ef7268596995d86df31afce21 Mon Sep 17 00:00:00 2001 From: Danila Tikhonov Date: Tue, 22 Apr 2025 23:17:02 +0300 Subject: [PATCH 13/15] dt-bindings: arm: cpus: Add Kryo 470 CPUs Document Kryo 470 CPUs found in Qualcomm Snapdragon 730/730G/732G (SM7150). Signed-off-by: Danila Tikhonov Link: https://lore.kernel.org/r/20250422-sm7150-upstream-v1-1-bf9a9081631d@jiaxyga.com Signed-off-by: Bjorn Andersson --- Documentation/devicetree/bindings/arm/cpus.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/arm/cpus.yaml b/Documentation/devicetree/bindings/arm/cpus.yaml index 2e9ab9583005..5bd517befb68 100644 --- a/Documentation/devicetree/bindings/arm/cpus.yaml +++ b/Documentation/devicetree/bindings/arm/cpus.yaml @@ -200,6 +200,7 @@ properties: - qcom,kryo385 - qcom,kryo465 - qcom,kryo468 + - qcom,kryo470 - qcom,kryo485 - qcom,kryo560 - qcom,kryo570 From 9cea10a4f5a39fde32bf7b8addfa5f9175174e0e Mon Sep 17 00:00:00 2001 From: Konrad Dybcio Date: Fri, 23 May 2025 01:18:16 +0200 Subject: [PATCH 14/15] dt-bindings: sram: qcom,imem: Add a number of missing compatibles Currently described or not, IMEM is present on *all* Qualcomm SoCs. Preemptively add a number of compatibles to ease integration. Signed-off-by: Konrad Dybcio Reviewed-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20250523-topic-ipa_mem_dts-v1-1-f7aa94fac1ab@oss.qualcomm.com Signed-off-by: Bjorn Andersson --- .../devicetree/bindings/sram/qcom,imem.yaml | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/Documentation/devicetree/bindings/sram/qcom,imem.yaml b/Documentation/devicetree/bindings/sram/qcom,imem.yaml index c49734b53369..72d35e30c439 100644 --- a/Documentation/devicetree/bindings/sram/qcom,imem.yaml +++ b/Documentation/devicetree/bindings/sram/qcom,imem.yaml @@ -26,15 +26,28 @@ properties: - qcom,qcs8300-imem - qcom,qdu1000-imem - qcom,sa8775p-imem + - qcom,sar2130p-imem - qcom,sc7180-imem - qcom,sc7280-imem + - qcom,sc8280xp-imem - qcom,sdm630-imem - qcom,sdm845-imem - qcom,sdx55-imem - qcom,sdx65-imem + - qcom,sdx75-imem + - qcom,sm6115-imem + - qcom,sm6125-imem + - qcom,sm6350-imem - qcom,sm6375-imem - qcom,sm7150-imem + - qcom,sm8150-imem + - qcom,sm8250-imem + - qcom,sm8350-imem - qcom,sm8450-imem + - qcom,sm8550-imem + - qcom,sm8650-imem + - qcom,sm8750-imem + - qcom,x1e80100-imem - const: syscon - const: simple-mfd From 9f35ab0e53ccbea57bb9cbad8065e0406d516195 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Wed, 25 Jun 2025 10:22:41 -0500 Subject: [PATCH 15/15] soc: qcom: mdt_loader: Fix error return values in mdt_header_valid() This function is supposed to return true for valid headers and false for invalid. In a couple places it returns -EINVAL instead which means the invalid headers are counted as true. Change it to return false. Fixes: 9f9967fed9d0 ("soc: qcom: mdt_loader: Ensure we don't read past the ELF header") Signed-off-by: Dan Carpenter Reviewed-by: Konrad Dybcio Link: https://lore.kernel.org/r/db57c01c-bdcc-4a0f-95db-b0f2784ea91f@sabinyo.mountain Signed-off-by: Bjorn Andersson --- drivers/soc/qcom/mdt_loader.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/soc/qcom/mdt_loader.c b/drivers/soc/qcom/mdt_loader.c index 1b4ebae458f3..0ca268bdf1f8 100644 --- a/drivers/soc/qcom/mdt_loader.c +++ b/drivers/soc/qcom/mdt_loader.c @@ -33,14 +33,14 @@ static bool mdt_header_valid(const struct firmware *fw) return false; if (ehdr->e_phentsize != sizeof(struct elf32_phdr)) - return -EINVAL; + return false; phend = size_add(size_mul(sizeof(struct elf32_phdr), ehdr->e_phnum), ehdr->e_phoff); if (phend > fw->size) return false; if (ehdr->e_shentsize != sizeof(struct elf32_shdr)) - return -EINVAL; + return false; shend = size_add(size_mul(sizeof(struct elf32_shdr), ehdr->e_shnum), ehdr->e_shoff); if (shend > fw->size)