Message ID | 20250528-ddr_stats_-v4-2-b4b7dae072dc@oss.qualcomm.com |
---|---|
State | New |
Headers | show |
Series | soc: qcom: qcom_stats: Add DDR stats | expand |
On Thu, May 29, 2025 at 09:07:49PM +0200, Konrad Dybcio wrote: > On 5/28/25 1:02 PM, Dmitry Baryshkov wrote: > > On Wed, May 28, 2025 at 02:51:32PM +0530, Maulik Shah wrote: > >> 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> > >> --- > >> drivers/soc/qcom/qcom_stats.c | 34 +++++++++++++++++++++++++++++++++- > >> 1 file changed, 33 insertions(+), 1 deletion(-) > >> > >> diff --git a/drivers/soc/qcom/qcom_stats.c b/drivers/soc/qcom/qcom_stats.c > >> index 33fd2a1574464768bd07289e743fbb79ba415e84..0545c8cbefb8f18758d4eb51638e4ecb94e05422 100644 > >> --- a/drivers/soc/qcom/qcom_stats.c > >> +++ b/drivers/soc/qcom/qcom_stats.c > >> @@ -13,6 +13,7 @@ > >> #include <linux/platform_device.h> > >> #include <linux/seq_file.h> > >> > >> +#include <linux/soc/qcom/qcom_aoss.h> > >> #include <linux/soc/qcom/smem.h> > >> #include <clocksource/arm_arch_timer.h> > >> > >> @@ -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,19 @@ 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)) { > >> + if (PTR_ERR(qcom_stats_qmp) == -EPROBE_DEFER) > >> + return -EPROBE_DEFER; > >> + > >> + /* We assume any other error means it's not defined/needed */ > >> + qcom_stats_qmp = NULL; > > > > I still think that we shouldn't be ignoring actual errors here. I'd say, > > check for of_property_present(dev->of_node, "qcom,qmp") before. > > /** > * qmp_get() - get a qmp handle from a device > * @dev: client device pointer > * > * Return: handle to qmp device on success, ERR_PTR() on failure > */ > struct qmp *qmp_get(struct device *dev) > { > struct platform_device *pdev; > struct device_node *np; > struct qmp *qmp; > > if (!dev || !dev->of_node) > return ERR_PTR(-EINVAL); > > np = of_parse_phandle(dev->of_node, "qcom,qmp", 0); > if (!np) > return ERR_PTR(-ENODEV); So, I'd say, we need to identify whether it is this caluse or another error. It should be enough to ignore ENODEV and return an error in all other cases. > > pdev = of_find_device_by_node(np); > of_node_put(np); > if (!pdev) > return ERR_PTR(-EINVAL); > > qmp = platform_get_drvdata(pdev); > > if (!qmp) { > put_device(&pdev->dev); > return ERR_PTR(-EPROBE_DEFER); > } > return qmp; > } > EXPORT_SYMBOL_GPL(qmp_get); > > > Konrad
diff --git a/drivers/soc/qcom/qcom_stats.c b/drivers/soc/qcom/qcom_stats.c index 33fd2a1574464768bd07289e743fbb79ba415e84..0545c8cbefb8f18758d4eb51638e4ecb94e05422 100644 --- a/drivers/soc/qcom/qcom_stats.c +++ b/drivers/soc/qcom/qcom_stats.c @@ -13,6 +13,7 @@ #include <linux/platform_device.h> #include <linux/seq_file.h> +#include <linux/soc/qcom/qcom_aoss.h> #include <linux/soc/qcom/smem.h> #include <clocksource/arm_arch_timer.h> @@ -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,19 @@ 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)) { + if (PTR_ERR(qcom_stats_qmp) == -EPROBE_DEFER) + return -EPROBE_DEFER; + + /* We assume any other error means it's not defined/needed */ + qcom_stats_qmp = NULL; + } root = debugfs_create_dir("qcom_stats", NULL);
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> --- drivers/soc/qcom/qcom_stats.c | 34 +++++++++++++++++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-)