Skip to content

Commit d4ebd11

Browse files
committed
Merge tag 'arm-smmu-updates' of git://git.kernel.org/pub/scm/linux/kernel/git/will/linux into arm/smmu
Arm SMMU updates for 5.20 - Add even more Qualcomm device-tree compatible strings - Support dumping of IMP DEF Qualcomm registers on TLB sync timeout - Fix reference count leak on device tree node in Qualcomm driver
2 parents a111daf + a91eb68 commit d4ebd11

File tree

9 files changed

+219
-11
lines changed

9 files changed

+219
-11
lines changed

Documentation/devicetree/bindings/iommu/arm,smmu.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ properties:
4242
- qcom,sdx55-smmu-500
4343
- qcom,sdx65-smmu-500
4444
- qcom,sm6350-smmu-500
45+
- qcom,sm6375-smmu-500
4546
- qcom,sm8150-smmu-500
4647
- qcom,sm8250-smmu-500
4748
- qcom,sm8350-smmu-500

drivers/iommu/Kconfig

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -363,6 +363,16 @@ config ARM_SMMU_QCOM
363363
When running on a Qualcomm platform that has the custom variant
364364
of the ARM SMMU, this needs to be built into the SMMU driver.
365365

366+
config ARM_SMMU_QCOM_DEBUG
367+
bool "ARM SMMU QCOM implementation defined debug support"
368+
depends on ARM_SMMU_QCOM
369+
help
370+
Support for implementation specific debug features in ARM SMMU
371+
hardware found in QTI platforms.
372+
373+
Say Y here to enable debug for issues such as TLB sync timeouts
374+
which requires implementation defined register dumps.
375+
366376
config ARM_SMMU_V3
367377
tristate "ARM Ltd. System MMU Version 3 (SMMUv3) Support"
368378
depends on ARM64

drivers/iommu/arm/arm-smmu/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,4 @@ obj-$(CONFIG_QCOM_IOMMU) += qcom_iommu.o
33
obj-$(CONFIG_ARM_SMMU) += arm_smmu.o
44
arm_smmu-objs += arm-smmu.o arm-smmu-impl.o arm-smmu-nvidia.o
55
arm_smmu-$(CONFIG_ARM_SMMU_QCOM) += arm-smmu-qcom.o
6+
arm_smmu-$(CONFIG_ARM_SMMU_QCOM_DEBUG) += arm-smmu-qcom-debug.o
Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
// SPDX-License-Identifier: GPL-2.0-only
2+
/*
3+
* Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
4+
*/
5+
6+
#include <linux/of_device.h>
7+
#include <linux/qcom_scm.h>
8+
#include <linux/ratelimit.h>
9+
10+
#include "arm-smmu.h"
11+
#include "arm-smmu-qcom.h"
12+
13+
enum qcom_smmu_impl_reg_offset {
14+
QCOM_SMMU_TBU_PWR_STATUS,
15+
QCOM_SMMU_STATS_SYNC_INV_TBU_ACK,
16+
QCOM_SMMU_MMU2QSS_AND_SAFE_WAIT_CNTR,
17+
};
18+
19+
struct qcom_smmu_config {
20+
const u32 *reg_offset;
21+
};
22+
23+
void qcom_smmu_tlb_sync_debug(struct arm_smmu_device *smmu)
24+
{
25+
int ret;
26+
u32 tbu_pwr_status, sync_inv_ack, sync_inv_progress;
27+
struct qcom_smmu *qsmmu = container_of(smmu, struct qcom_smmu, smmu);
28+
const struct qcom_smmu_config *cfg;
29+
static DEFINE_RATELIMIT_STATE(rs, DEFAULT_RATELIMIT_INTERVAL,
30+
DEFAULT_RATELIMIT_BURST);
31+
32+
if (__ratelimit(&rs)) {
33+
dev_err(smmu->dev, "TLB sync timed out -- SMMU may be deadlocked\n");
34+
35+
cfg = qsmmu->cfg;
36+
if (!cfg)
37+
return;
38+
39+
ret = qcom_scm_io_readl(smmu->ioaddr + cfg->reg_offset[QCOM_SMMU_TBU_PWR_STATUS],
40+
&tbu_pwr_status);
41+
if (ret)
42+
dev_err(smmu->dev,
43+
"Failed to read TBU power status: %d\n", ret);
44+
45+
ret = qcom_scm_io_readl(smmu->ioaddr + cfg->reg_offset[QCOM_SMMU_STATS_SYNC_INV_TBU_ACK],
46+
&sync_inv_ack);
47+
if (ret)
48+
dev_err(smmu->dev,
49+
"Failed to read TBU sync/inv ack status: %d\n", ret);
50+
51+
ret = qcom_scm_io_readl(smmu->ioaddr + cfg->reg_offset[QCOM_SMMU_MMU2QSS_AND_SAFE_WAIT_CNTR],
52+
&sync_inv_progress);
53+
if (ret)
54+
dev_err(smmu->dev,
55+
"Failed to read TCU syn/inv progress: %d\n", ret);
56+
57+
dev_err(smmu->dev,
58+
"TBU: power_status %#x sync_inv_ack %#x sync_inv_progress %#x\n",
59+
tbu_pwr_status, sync_inv_ack, sync_inv_progress);
60+
}
61+
}
62+
63+
/* Implementation Defined Register Space 0 register offsets */
64+
static const u32 qcom_smmu_impl0_reg_offset[] = {
65+
[QCOM_SMMU_TBU_PWR_STATUS] = 0x2204,
66+
[QCOM_SMMU_STATS_SYNC_INV_TBU_ACK] = 0x25dc,
67+
[QCOM_SMMU_MMU2QSS_AND_SAFE_WAIT_CNTR] = 0x2670,
68+
};
69+
70+
static const struct qcom_smmu_config qcm2290_smmu_cfg = {
71+
.reg_offset = qcom_smmu_impl0_reg_offset,
72+
};
73+
74+
static const struct qcom_smmu_config sc7180_smmu_cfg = {
75+
.reg_offset = qcom_smmu_impl0_reg_offset,
76+
};
77+
78+
static const struct qcom_smmu_config sc7280_smmu_cfg = {
79+
.reg_offset = qcom_smmu_impl0_reg_offset,
80+
};
81+
82+
static const struct qcom_smmu_config sc8180x_smmu_cfg = {
83+
.reg_offset = qcom_smmu_impl0_reg_offset,
84+
};
85+
86+
static const struct qcom_smmu_config sc8280xp_smmu_cfg = {
87+
.reg_offset = qcom_smmu_impl0_reg_offset,
88+
};
89+
90+
static const struct qcom_smmu_config sm6125_smmu_cfg = {
91+
.reg_offset = qcom_smmu_impl0_reg_offset,
92+
};
93+
94+
static const struct qcom_smmu_config sm6350_smmu_cfg = {
95+
.reg_offset = qcom_smmu_impl0_reg_offset,
96+
};
97+
98+
static const struct qcom_smmu_config sm8150_smmu_cfg = {
99+
.reg_offset = qcom_smmu_impl0_reg_offset,
100+
};
101+
102+
static const struct qcom_smmu_config sm8250_smmu_cfg = {
103+
.reg_offset = qcom_smmu_impl0_reg_offset,
104+
};
105+
106+
static const struct qcom_smmu_config sm8350_smmu_cfg = {
107+
.reg_offset = qcom_smmu_impl0_reg_offset,
108+
};
109+
110+
static const struct qcom_smmu_config sm8450_smmu_cfg = {
111+
.reg_offset = qcom_smmu_impl0_reg_offset,
112+
};
113+
114+
static const struct of_device_id __maybe_unused qcom_smmu_impl_debug_match[] = {
115+
{ .compatible = "qcom,msm8998-smmu-v2" },
116+
{ .compatible = "qcom,qcm2290-smmu-500", .data = &qcm2290_smmu_cfg },
117+
{ .compatible = "qcom,sc7180-smmu-500", .data = &sc7180_smmu_cfg },
118+
{ .compatible = "qcom,sc7280-smmu-500", .data = &sc7280_smmu_cfg},
119+
{ .compatible = "qcom,sc8180x-smmu-500", .data = &sc8180x_smmu_cfg },
120+
{ .compatible = "qcom,sc8280xp-smmu-500", .data = &sc8280xp_smmu_cfg },
121+
{ .compatible = "qcom,sdm630-smmu-v2" },
122+
{ .compatible = "qcom,sdm845-smmu-500" },
123+
{ .compatible = "qcom,sm6125-smmu-500", .data = &sm6125_smmu_cfg},
124+
{ .compatible = "qcom,sm6350-smmu-500", .data = &sm6350_smmu_cfg},
125+
{ .compatible = "qcom,sm8150-smmu-500", .data = &sm8150_smmu_cfg },
126+
{ .compatible = "qcom,sm8250-smmu-500", .data = &sm8250_smmu_cfg },
127+
{ .compatible = "qcom,sm8350-smmu-500", .data = &sm8350_smmu_cfg },
128+
{ .compatible = "qcom,sm8450-smmu-500", .data = &sm8450_smmu_cfg },
129+
{ }
130+
};
131+
132+
const void *qcom_smmu_impl_data(struct arm_smmu_device *smmu)
133+
{
134+
const struct of_device_id *match;
135+
const struct device_node *np = smmu->dev->of_node;
136+
137+
match = of_match_node(qcom_smmu_impl_debug_match, np);
138+
if (!match)
139+
return NULL;
140+
141+
return match->data;
142+
}

drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c

Lines changed: 28 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,23 +5,40 @@
55

66
#include <linux/acpi.h>
77
#include <linux/adreno-smmu-priv.h>
8+
#include <linux/delay.h>
89
#include <linux/of_device.h>
910
#include <linux/qcom_scm.h>
1011

1112
#include "arm-smmu.h"
13+
#include "arm-smmu-qcom.h"
1214

13-
struct qcom_smmu {
14-
struct arm_smmu_device smmu;
15-
bool bypass_quirk;
16-
u8 bypass_cbndx;
17-
u32 stall_enabled;
18-
};
15+
#define QCOM_DUMMY_VAL -1
1916

2017
static struct qcom_smmu *to_qcom_smmu(struct arm_smmu_device *smmu)
2118
{
2219
return container_of(smmu, struct qcom_smmu, smmu);
2320
}
2421

22+
static void qcom_smmu_tlb_sync(struct arm_smmu_device *smmu, int page,
23+
int sync, int status)
24+
{
25+
unsigned int spin_cnt, delay;
26+
u32 reg;
27+
28+
arm_smmu_writel(smmu, page, sync, QCOM_DUMMY_VAL);
29+
for (delay = 1; delay < TLB_LOOP_TIMEOUT; delay *= 2) {
30+
for (spin_cnt = TLB_SPIN_COUNT; spin_cnt > 0; spin_cnt--) {
31+
reg = arm_smmu_readl(smmu, page, status);
32+
if (!(reg & ARM_SMMU_sTLBGSTATUS_GSACTIVE))
33+
return;
34+
cpu_relax();
35+
}
36+
udelay(delay);
37+
}
38+
39+
qcom_smmu_tlb_sync_debug(smmu);
40+
}
41+
2542
static void qcom_adreno_smmu_write_sctlr(struct arm_smmu_device *smmu, int idx,
2643
u32 reg)
2744
{
@@ -233,6 +250,7 @@ static const struct of_device_id qcom_smmu_client_of_match[] __maybe_unused = {
233250
{ .compatible = "qcom,sc7280-mdss" },
234251
{ .compatible = "qcom,sc7280-mss-pil" },
235252
{ .compatible = "qcom,sc8180x-mdss" },
253+
{ .compatible = "qcom,sm8250-mdss" },
236254
{ .compatible = "qcom,sdm845-mdss" },
237255
{ .compatible = "qcom,sdm845-mss-pil" },
238256
{ }
@@ -374,6 +392,7 @@ static const struct arm_smmu_impl qcom_smmu_impl = {
374392
.def_domain_type = qcom_smmu_def_domain_type,
375393
.reset = qcom_smmu500_reset,
376394
.write_s2cr = qcom_smmu_write_s2cr,
395+
.tlb_sync = qcom_smmu_tlb_sync,
377396
};
378397

379398
static const struct arm_smmu_impl qcom_adreno_smmu_impl = {
@@ -382,6 +401,7 @@ static const struct arm_smmu_impl qcom_adreno_smmu_impl = {
382401
.reset = qcom_smmu500_reset,
383402
.alloc_context_bank = qcom_adreno_smmu_alloc_context_bank,
384403
.write_sctlr = qcom_adreno_smmu_write_sctlr,
404+
.tlb_sync = qcom_smmu_tlb_sync,
385405
};
386406

387407
static struct arm_smmu_device *qcom_smmu_create(struct arm_smmu_device *smmu,
@@ -398,6 +418,7 @@ static struct arm_smmu_device *qcom_smmu_create(struct arm_smmu_device *smmu,
398418
return ERR_PTR(-ENOMEM);
399419

400420
qsmmu->smmu.impl = impl;
421+
qsmmu->cfg = qcom_smmu_impl_data(smmu);
401422

402423
return &qsmmu->smmu;
403424
}
@@ -413,6 +434,7 @@ static const struct of_device_id __maybe_unused qcom_smmu_impl_of_match[] = {
413434
{ .compatible = "qcom,sdm845-smmu-500" },
414435
{ .compatible = "qcom,sm6125-smmu-500" },
415436
{ .compatible = "qcom,sm6350-smmu-500" },
437+
{ .compatible = "qcom,sm6375-smmu-500" },
416438
{ .compatible = "qcom,sm8150-smmu-500" },
417439
{ .compatible = "qcom,sm8250-smmu-500" },
418440
{ .compatible = "qcom,sm8350-smmu-500" },
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
/* SPDX-License-Identifier: GPL-2.0-only */
2+
/*
3+
* Copyright (c) 2022, Qualcomm Innovation Center, Inc. All rights reserved.
4+
*/
5+
6+
#ifndef _ARM_SMMU_QCOM_H
7+
#define _ARM_SMMU_QCOM_H
8+
9+
struct qcom_smmu {
10+
struct arm_smmu_device smmu;
11+
const struct qcom_smmu_config *cfg;
12+
bool bypass_quirk;
13+
u8 bypass_cbndx;
14+
u32 stall_enabled;
15+
};
16+
17+
#ifdef CONFIG_ARM_SMMU_QCOM_DEBUG
18+
void qcom_smmu_tlb_sync_debug(struct arm_smmu_device *smmu);
19+
const void *qcom_smmu_impl_data(struct arm_smmu_device *smmu);
20+
#else
21+
static inline void qcom_smmu_tlb_sync_debug(struct arm_smmu_device *smmu) { }
22+
static inline const void *qcom_smmu_impl_data(struct arm_smmu_device *smmu)
23+
{
24+
return NULL;
25+
}
26+
#endif
27+
28+
#endif /* _ARM_SMMU_QCOM_H */

drivers/iommu/arm/arm-smmu/arm-smmu.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2074,7 +2074,6 @@ err_reset_platform_ops: __maybe_unused;
20742074
static int arm_smmu_device_probe(struct platform_device *pdev)
20752075
{
20762076
struct resource *res;
2077-
resource_size_t ioaddr;
20782077
struct arm_smmu_device *smmu;
20792078
struct device *dev = &pdev->dev;
20802079
int num_irqs, i, err;
@@ -2098,7 +2097,8 @@ static int arm_smmu_device_probe(struct platform_device *pdev)
20982097
smmu->base = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
20992098
if (IS_ERR(smmu->base))
21002099
return PTR_ERR(smmu->base);
2101-
ioaddr = res->start;
2100+
smmu->ioaddr = res->start;
2101+
21022102
/*
21032103
* The resource size should effectively match the value of SMMU_TOP;
21042104
* stash that temporarily until we know PAGESIZE to validate it with.
@@ -2178,7 +2178,7 @@ static int arm_smmu_device_probe(struct platform_device *pdev)
21782178
}
21792179

21802180
err = iommu_device_sysfs_add(&smmu->iommu, smmu->dev, NULL,
2181-
"smmu.%pa", &ioaddr);
2181+
"smmu.%pa", &smmu->ioaddr);
21822182
if (err) {
21832183
dev_err(dev, "Failed to register iommu in sysfs\n");
21842184
return err;

drivers/iommu/arm/arm-smmu/arm-smmu.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -278,6 +278,7 @@ struct arm_smmu_device {
278278
struct device *dev;
279279

280280
void __iomem *base;
281+
phys_addr_t ioaddr;
281282
unsigned int numpage;
282283
unsigned int pgshift;
283284

drivers/iommu/arm/arm-smmu/qcom_iommu.c

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -750,9 +750,12 @@ static bool qcom_iommu_has_secure_context(struct qcom_iommu_dev *qcom_iommu)
750750
{
751751
struct device_node *child;
752752

753-
for_each_child_of_node(qcom_iommu->dev->of_node, child)
754-
if (of_device_is_compatible(child, "qcom,msm-iommu-v1-sec"))
753+
for_each_child_of_node(qcom_iommu->dev->of_node, child) {
754+
if (of_device_is_compatible(child, "qcom,msm-iommu-v1-sec")) {
755+
of_node_put(child);
755756
return true;
757+
}
758+
}
756759

757760
return false;
758761
}

0 commit comments

Comments
 (0)