Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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 <maulik.shah@oss.qualcomm.com>
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
Link: https://lore.kernel.org/r/20250611-ddr_stats_-v5-2-24b16dd67c9c@oss.qualcomm.com
Signed-off-by: Bjorn Andersson <andersson@kernel.org>

authored by

Maulik Shah and committed by
Bjorn Andersson
e265de1f 33301e5b

+35 -1
+35 -1
drivers/soc/qcom/qcom_stats.c
··· 13 13 #include <linux/platform_device.h> 14 14 #include <linux/seq_file.h> 15 15 16 + #include <linux/soc/qcom/qcom_aoss.h> 16 17 #include <linux/soc/qcom/smem.h> 17 18 #include <clocksource/arm_arch_timer.h> 18 19 ··· 37 36 #define DDR_STATS_LPM_NAME(data) FIELD_GET(GENMASK(7, 0), data) 38 37 #define DDR_STATS_TYPE(data) FIELD_GET(GENMASK(15, 8), data) 39 38 #define DDR_STATS_FREQ(data) FIELD_GET(GENMASK(31, 16), data) 39 + 40 + static struct qmp *qcom_stats_qmp; 40 41 41 42 struct subsystem_data { 42 43 const char *name; ··· 191 188 struct ddr_stats_entry data[DDR_STATS_MAX_NUM_MODES]; 192 189 void __iomem *reg = (void __iomem *)s->private; 193 190 u32 entry_count; 194 - int i; 191 + int i, ret; 195 192 196 193 entry_count = readl_relaxed(reg + DDR_STATS_NUM_MODES_ADDR); 197 194 if (entry_count > DDR_STATS_MAX_NUM_MODES) 198 195 return -EINVAL; 196 + 197 + if (qcom_stats_qmp) { 198 + /* 199 + * Recent SoCs (SM8450 onwards) do not have duration field 200 + * populated from boot up onwards for both DDR LPM Stats 201 + * and DDR Frequency Stats. 202 + * 203 + * Send QMP message to Always on processor which will 204 + * populate duration field into MSG RAM area. 205 + * 206 + * Sent every time to read latest data. 207 + */ 208 + ret = qmp_send(qcom_stats_qmp, "{class: ddr, action: freqsync}"); 209 + if (ret) 210 + return ret; 211 + } 199 212 200 213 reg += DDR_STATS_ENTRY_START_ADDR; 201 214 memcpy_fromio(data, reg, sizeof(struct ddr_stats_entry) * entry_count); ··· 323 304 324 305 for (i = 0; i < config->num_records; i++) 325 306 d[i].appended_stats_avail = config->appended_stats_avail; 307 + /* 308 + * QMP is used for DDR stats syncing to MSG RAM for recent SoCs (SM8450 onwards). 309 + * The prior SoCs do not need QMP handle as the required stats are already present 310 + * in MSG RAM, provided the DDR_STATS_MAGIC_KEY matches. 311 + */ 312 + qcom_stats_qmp = qmp_get(&pdev->dev); 313 + if (IS_ERR(qcom_stats_qmp)) { 314 + /* We ignore error if QMP is not defined/needed */ 315 + if (!of_property_present(pdev->dev.of_node, "qcom,qmp")) 316 + qcom_stats_qmp = NULL; 317 + else if (PTR_ERR(qcom_stats_qmp) == -EPROBE_DEFER) 318 + return -EPROBE_DEFER; 319 + else 320 + return PTR_ERR(qcom_stats_qmp); 321 + } 326 322 327 323 root = debugfs_create_dir("qcom_stats", NULL); 328 324