Skip to content

Commit 5b81415

Browse files
committed
Merge tag 'qcom-drivers-for-6.17' of https://git.kernel.org/pub/scm/linux/kernel/git/qcom/linux into soc/drivers
Qualcomm driver updates for v6.17 Perform input validation in the MDT loader, as this was not properly done in the non-remoteproc cases. Fix endian issues in the QMI encoder/decoder. Support reading DDR statistic using the Qualcomm stats driver. Add support for reading TME firmware details to the socinfo driver. Document the Kryo 470 CPU, and add SM7150 to the DCC to DeviceTree bindings. * tag 'qcom-drivers-for-6.17' of https://git.kernel.org/pub/scm/linux/kernel/git/qcom/linux: soc: qcom: mdt_loader: Fix error return values in mdt_header_valid() dt-bindings: sram: qcom,imem: Add a number of missing compatibles dt-bindings: arm: cpus: Add Kryo 470 CPUs dt-bindings: sram: qcom,imem: Add the SM7150 compatible dt-bindings: soc: qcom: aoss-qmp: Add the SM7150 compatible dt-bindings: soc: qcom,dcc: Add the SM7150 compatible soc: qcom: socinfo: Add support to retrieve TME build details soc: qcom: fix endianness for QMI header soc: qcom: QMI encoding/decoding for big endian dt-bindings: soc: qcom: add qcom,qcs615-imem compatible soc: qcom: qcom_stats: Add QMP support for syncing ddr stats soc: qcom: qcom_stats: Add support to read DDR statistic soc: qcom: mdt_loader: Actually use the e_phoff soc: qcom: mdt_loader: Rename mdt_phdr_valid() soc: qcom: mdt_loader: Ensure we don't read past the ELF header Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Arnd Bergmann <[email protected]>
2 parents 9841d92 + 9f35ab0 commit 5b81415

File tree

10 files changed

+253
-27
lines changed

10 files changed

+253
-27
lines changed

Documentation/devicetree/bindings/arm/cpus.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -200,6 +200,7 @@ properties:
200200
- qcom,kryo385
201201
- qcom,kryo465
202202
- qcom,kryo468
203+
- qcom,kryo470
203204
- qcom,kryo485
204205
- qcom,kryo560
205206
- qcom,kryo570

Documentation/devicetree/bindings/soc/qcom/qcom,aoss-qmp.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ properties:
3838
- qcom,sdx75-aoss-qmp
3939
- qcom,sdm845-aoss-qmp
4040
- qcom,sm6350-aoss-qmp
41+
- qcom,sm7150-aoss-qmp
4142
- qcom,sm8150-aoss-qmp
4243
- qcom,sm8250-aoss-qmp
4344
- qcom,sm8350-aoss-qmp

Documentation/devicetree/bindings/soc/qcom/qcom,dcc.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ properties:
1818
compatible:
1919
items:
2020
- enum:
21+
- qcom,sm7150-dcc
2122
- qcom,sm8150-dcc
2223
- qcom,sc7280-dcc
2324
- qcom,sc7180-dcc

Documentation/devicetree/bindings/sram/qcom,imem.yaml

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,17 +22,32 @@ properties:
2222
- qcom,msm8974-imem
2323
- qcom,msm8976-imem
2424
- qcom,qcs404-imem
25+
- qcom,qcs615-imem
2526
- qcom,qcs8300-imem
2627
- qcom,qdu1000-imem
2728
- qcom,sa8775p-imem
29+
- qcom,sar2130p-imem
2830
- qcom,sc7180-imem
2931
- qcom,sc7280-imem
32+
- qcom,sc8280xp-imem
3033
- qcom,sdm630-imem
3134
- qcom,sdm845-imem
3235
- qcom,sdx55-imem
3336
- qcom,sdx65-imem
37+
- qcom,sdx75-imem
38+
- qcom,sm6115-imem
39+
- qcom,sm6125-imem
40+
- qcom,sm6350-imem
3441
- qcom,sm6375-imem
42+
- qcom,sm7150-imem
43+
- qcom,sm8150-imem
44+
- qcom,sm8250-imem
45+
- qcom,sm8350-imem
3546
- qcom,sm8450-imem
47+
- qcom,sm8550-imem
48+
- qcom,sm8650-imem
49+
- qcom,sm8750-imem
50+
- qcom,x1e80100-imem
3651
- const: syscon
3752
- const: simple-mfd
3853

drivers/soc/qcom/mdt_loader.c

Lines changed: 53 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,38 @@
1818
#include <linux/slab.h>
1919
#include <linux/soc/qcom/mdt_loader.h>
2020

21-
static bool mdt_phdr_valid(const struct elf32_phdr *phdr)
21+
static bool mdt_header_valid(const struct firmware *fw)
22+
{
23+
const struct elf32_hdr *ehdr;
24+
size_t phend;
25+
size_t shend;
26+
27+
if (fw->size < sizeof(*ehdr))
28+
return false;
29+
30+
ehdr = (struct elf32_hdr *)fw->data;
31+
32+
if (memcmp(ehdr->e_ident, ELFMAG, SELFMAG))
33+
return false;
34+
35+
if (ehdr->e_phentsize != sizeof(struct elf32_phdr))
36+
return false;
37+
38+
phend = size_add(size_mul(sizeof(struct elf32_phdr), ehdr->e_phnum), ehdr->e_phoff);
39+
if (phend > fw->size)
40+
return false;
41+
42+
if (ehdr->e_shentsize != sizeof(struct elf32_shdr))
43+
return false;
44+
45+
shend = size_add(size_mul(sizeof(struct elf32_shdr), ehdr->e_shnum), ehdr->e_shoff);
46+
if (shend > fw->size)
47+
return false;
48+
49+
return true;
50+
}
51+
52+
static bool mdt_phdr_loadable(const struct elf32_phdr *phdr)
2253
{
2354
if (phdr->p_type != PT_LOAD)
2455
return false;
@@ -82,13 +113,16 @@ ssize_t qcom_mdt_get_size(const struct firmware *fw)
82113
phys_addr_t max_addr = 0;
83114
int i;
84115

116+
if (!mdt_header_valid(fw))
117+
return -EINVAL;
118+
85119
ehdr = (struct elf32_hdr *)fw->data;
86-
phdrs = (struct elf32_phdr *)(ehdr + 1);
120+
phdrs = (struct elf32_phdr *)(fw->data + ehdr->e_phoff);
87121

88122
for (i = 0; i < ehdr->e_phnum; i++) {
89123
phdr = &phdrs[i];
90124

91-
if (!mdt_phdr_valid(phdr))
125+
if (!mdt_phdr_loadable(phdr))
92126
continue;
93127

94128
if (phdr->p_paddr < min_addr)
@@ -134,8 +168,11 @@ void *qcom_mdt_read_metadata(const struct firmware *fw, size_t *data_len,
134168
ssize_t ret;
135169
void *data;
136170

171+
if (!mdt_header_valid(fw))
172+
return ERR_PTR(-EINVAL);
173+
137174
ehdr = (struct elf32_hdr *)fw->data;
138-
phdrs = (struct elf32_phdr *)(ehdr + 1);
175+
phdrs = (struct elf32_phdr *)(fw->data + ehdr->e_phoff);
139176

140177
if (ehdr->e_phnum < 2)
141178
return ERR_PTR(-EINVAL);
@@ -214,13 +251,16 @@ int qcom_mdt_pas_init(struct device *dev, const struct firmware *fw,
214251
int ret;
215252
int i;
216253

254+
if (!mdt_header_valid(fw))
255+
return -EINVAL;
256+
217257
ehdr = (struct elf32_hdr *)fw->data;
218-
phdrs = (struct elf32_phdr *)(ehdr + 1);
258+
phdrs = (struct elf32_phdr *)(fw->data + ehdr->e_phoff);
219259

220260
for (i = 0; i < ehdr->e_phnum; i++) {
221261
phdr = &phdrs[i];
222262

223-
if (!mdt_phdr_valid(phdr))
263+
if (!mdt_phdr_loadable(phdr))
224264
continue;
225265

226266
if (phdr->p_flags & QCOM_MDT_RELOCATABLE)
@@ -270,7 +310,7 @@ static bool qcom_mdt_bins_are_split(const struct firmware *fw, const char *fw_na
270310
int i;
271311

272312
ehdr = (struct elf32_hdr *)fw->data;
273-
phdrs = (struct elf32_phdr *)(ehdr + 1);
313+
phdrs = (struct elf32_phdr *)(fw->data + ehdr->e_phoff);
274314

275315
for (i = 0; i < ehdr->e_phnum; i++) {
276316
/*
@@ -310,14 +350,17 @@ static int __qcom_mdt_load(struct device *dev, const struct firmware *fw,
310350
if (!fw || !mem_region || !mem_phys || !mem_size)
311351
return -EINVAL;
312352

353+
if (!mdt_header_valid(fw))
354+
return -EINVAL;
355+
313356
is_split = qcom_mdt_bins_are_split(fw, fw_name);
314357
ehdr = (struct elf32_hdr *)fw->data;
315-
phdrs = (struct elf32_phdr *)(ehdr + 1);
358+
phdrs = (struct elf32_phdr *)(fw->data + ehdr->e_phoff);
316359

317360
for (i = 0; i < ehdr->e_phnum; i++) {
318361
phdr = &phdrs[i];
319362

320-
if (!mdt_phdr_valid(phdr))
363+
if (!mdt_phdr_loadable(phdr))
321364
continue;
322365

323366
if (phdr->p_flags & QCOM_MDT_RELOCATABLE)
@@ -344,7 +387,7 @@ static int __qcom_mdt_load(struct device *dev, const struct firmware *fw,
344387
for (i = 0; i < ehdr->e_phnum; i++) {
345388
phdr = &phdrs[i];
346389

347-
if (!mdt_phdr_valid(phdr))
390+
if (!mdt_phdr_loadable(phdr))
348391
continue;
349392

350393
offset = phdr->p_paddr - mem_reloc;

drivers/soc/qcom/qcom_stats.c

Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
// SPDX-License-Identifier: GPL-2.0-only
22
/*
33
* Copyright (c) 2011-2021, The Linux Foundation. All rights reserved.
4+
* Copyright (c) 2022-2025, Qualcomm Innovation Center, Inc. All rights reserved.
45
*/
56

7+
#include <linux/bitfield.h>
68
#include <linux/debugfs.h>
79
#include <linux/device.h>
810
#include <linux/io.h>
@@ -11,6 +13,7 @@
1113
#include <linux/platform_device.h>
1214
#include <linux/seq_file.h>
1315

16+
#include <linux/soc/qcom/qcom_aoss.h>
1417
#include <linux/soc/qcom/smem.h>
1518
#include <clocksource/arm_arch_timer.h>
1619

@@ -24,6 +27,19 @@
2427
#define ACCUMULATED_OFFSET 0x18
2528
#define CLIENT_VOTES_OFFSET 0x20
2629

30+
#define DDR_STATS_MAGIC_KEY 0xA1157A75
31+
#define DDR_STATS_MAX_NUM_MODES 20
32+
#define DDR_STATS_MAGIC_KEY_ADDR 0x0
33+
#define DDR_STATS_NUM_MODES_ADDR 0x4
34+
#define DDR_STATS_ENTRY_START_ADDR 0x8
35+
36+
#define DDR_STATS_CP_IDX(data) FIELD_GET(GENMASK(4, 0), data)
37+
#define DDR_STATS_LPM_NAME(data) FIELD_GET(GENMASK(7, 0), data)
38+
#define DDR_STATS_TYPE(data) FIELD_GET(GENMASK(15, 8), data)
39+
#define DDR_STATS_FREQ(data) FIELD_GET(GENMASK(31, 16), data)
40+
41+
static struct qmp *qcom_stats_qmp;
42+
2743
struct subsystem_data {
2844
const char *name;
2945
u32 smem_item;
@@ -48,12 +64,19 @@ static const struct subsystem_data subsystems[] = {
4864

4965
struct stats_config {
5066
size_t stats_offset;
67+
size_t ddr_stats_offset;
5168
size_t num_records;
5269
bool appended_stats_avail;
5370
bool dynamic_offset;
5471
bool subsystem_stats_in_smem;
5572
};
5673

74+
struct ddr_stats_entry {
75+
u32 name;
76+
u32 count;
77+
u64 duration;
78+
};
79+
5780
struct stats_data {
5881
bool appended_stats_avail;
5982
void __iomem *base;
@@ -122,8 +145,101 @@ static int qcom_soc_sleep_stats_show(struct seq_file *s, void *unused)
122145
return 0;
123146
}
124147

148+
static void qcom_ddr_stats_print(struct seq_file *s, struct ddr_stats_entry *data)
149+
{
150+
u32 cp_idx;
151+
152+
/*
153+
* DDR statistic have two different types of details encoded.
154+
* (1) DDR LPM Stats
155+
* (2) DDR Frequency Stats
156+
*
157+
* The name field have details like which type of DDR stat (bits 8:15)
158+
* along with other details as explained below
159+
*
160+
* In case of DDR LPM stat, name field will be encoded as,
161+
* Bits - Meaning
162+
* 0:7 - DDR LPM name, can be of 0xd4, 0xd3, 0x11 and 0xd0.
163+
* 8:15 - 0x0 (indicates its a LPM stat)
164+
* 16:31 - Unused
165+
*
166+
* In case of DDR FREQ stats, name field will be encoded as,
167+
* Bits - Meaning
168+
* 0:4 - DDR Clock plan index (CP IDX)
169+
* 5:7 - Unused
170+
* 8:15 - 0x1 (indicates its Freq stat)
171+
* 16:31 - Frequency value in Mhz
172+
*/
173+
switch (DDR_STATS_TYPE(data->name)) {
174+
case 0:
175+
seq_printf(s, "DDR LPM Stat Name:0x%lx\tcount:%u\tDuration (ticks):%llu\n",
176+
DDR_STATS_LPM_NAME(data->name), data->count, data->duration);
177+
break;
178+
case 1:
179+
if (!data->count || !DDR_STATS_FREQ(data->name))
180+
return;
181+
182+
cp_idx = DDR_STATS_CP_IDX(data->name);
183+
seq_printf(s, "DDR Freq %luMhz:\tCP IDX:%u\tcount:%u\tDuration (ticks):%llu\n",
184+
DDR_STATS_FREQ(data->name), cp_idx, data->count, data->duration);
185+
break;
186+
}
187+
}
188+
189+
static int qcom_ddr_stats_show(struct seq_file *s, void *d)
190+
{
191+
struct ddr_stats_entry data[DDR_STATS_MAX_NUM_MODES];
192+
void __iomem *reg = (void __iomem *)s->private;
193+
u32 entry_count;
194+
int i, ret;
195+
196+
entry_count = readl_relaxed(reg + DDR_STATS_NUM_MODES_ADDR);
197+
if (entry_count > DDR_STATS_MAX_NUM_MODES)
198+
return -EINVAL;
199+
200+
if (qcom_stats_qmp) {
201+
/*
202+
* Recent SoCs (SM8450 onwards) do not have duration field
203+
* populated from boot up onwards for both DDR LPM Stats
204+
* and DDR Frequency Stats.
205+
*
206+
* Send QMP message to Always on processor which will
207+
* populate duration field into MSG RAM area.
208+
*
209+
* Sent every time to read latest data.
210+
*/
211+
ret = qmp_send(qcom_stats_qmp, "{class: ddr, action: freqsync}");
212+
if (ret)
213+
return ret;
214+
}
215+
216+
reg += DDR_STATS_ENTRY_START_ADDR;
217+
memcpy_fromio(data, reg, sizeof(struct ddr_stats_entry) * entry_count);
218+
219+
for (i = 0; i < entry_count; i++)
220+
qcom_ddr_stats_print(s, &data[i]);
221+
222+
return 0;
223+
}
224+
125225
DEFINE_SHOW_ATTRIBUTE(qcom_soc_sleep_stats);
126226
DEFINE_SHOW_ATTRIBUTE(qcom_subsystem_sleep_stats);
227+
DEFINE_SHOW_ATTRIBUTE(qcom_ddr_stats);
228+
229+
static void qcom_create_ddr_stat_files(struct dentry *root, void __iomem *reg,
230+
const struct stats_config *config)
231+
{
232+
u32 key;
233+
234+
if (!config->ddr_stats_offset)
235+
return;
236+
237+
key = readl_relaxed(reg + config->ddr_stats_offset + DDR_STATS_MAGIC_KEY_ADDR);
238+
if (key == DDR_STATS_MAGIC_KEY)
239+
debugfs_create_file("ddr_stats", 0400, root,
240+
(__force void *)reg + config->ddr_stats_offset,
241+
&qcom_ddr_stats_fops);
242+
}
127243

128244
static void qcom_create_soc_sleep_stat_files(struct dentry *root, void __iomem *reg,
129245
struct stats_data *d,
@@ -207,11 +323,27 @@ static int qcom_stats_probe(struct platform_device *pdev)
207323

208324
for (i = 0; i < config->num_records; i++)
209325
d[i].appended_stats_avail = config->appended_stats_avail;
326+
/*
327+
* QMP is used for DDR stats syncing to MSG RAM for recent SoCs (SM8450 onwards).
328+
* The prior SoCs do not need QMP handle as the required stats are already present
329+
* in MSG RAM, provided the DDR_STATS_MAGIC_KEY matches.
330+
*/
331+
qcom_stats_qmp = qmp_get(&pdev->dev);
332+
if (IS_ERR(qcom_stats_qmp)) {
333+
/* We ignore error if QMP is not defined/needed */
334+
if (!of_property_present(pdev->dev.of_node, "qcom,qmp"))
335+
qcom_stats_qmp = NULL;
336+
else if (PTR_ERR(qcom_stats_qmp) == -EPROBE_DEFER)
337+
return -EPROBE_DEFER;
338+
else
339+
return PTR_ERR(qcom_stats_qmp);
340+
}
210341

211342
root = debugfs_create_dir("qcom_stats", NULL);
212343

213344
qcom_create_subsystem_stat_files(root, config);
214345
qcom_create_soc_sleep_stat_files(root, reg, d, config);
346+
qcom_create_ddr_stat_files(root, reg, config);
215347

216348
platform_set_drvdata(pdev, root);
217349

@@ -254,6 +386,7 @@ static const struct stats_config rpmh_data_sdm845 = {
254386

255387
static const struct stats_config rpmh_data = {
256388
.stats_offset = 0x48,
389+
.ddr_stats_offset = 0xb8,
257390
.num_records = 3,
258391
.appended_stats_avail = false,
259392
.dynamic_offset = false,

0 commit comments

Comments
 (0)