Skip to content

Commit 90654da

Browse files
committed
Merge tag 'arm-smmu-updates' of git://git.kernel.org/pub/scm/linux/kernel/git/will/linux into arm/smmu
Qualc^WArm SMMU updates for 6.6 - Device-tree binding updates: * Add additional compatible strings for Qualcomm SoCs * Allow ASIDs to be configured in the DT to work around Qualcomm's broken hypervisor * Fix clocks for Qualcomm's MSM8998 SoC - SMMUv2: * Support for Qualcomm's legacy firmware implementation featured on at least MSM8956 and MSM8976. * Match compatible strings for Qualcomm SM6350 and SM6375 SoC variants - SMMUv3: * Use 'ida' instead of a bitmap for VMID allocation
2 parents 6eaae19 + afe92fb commit 90654da

File tree

6 files changed

+120
-49
lines changed

6 files changed

+120
-49
lines changed

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

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -270,6 +270,47 @@ allOf:
270270
contains:
271271
enum:
272272
- qcom,msm8998-smmu-v2
273+
then:
274+
anyOf:
275+
- properties:
276+
clock-names:
277+
items:
278+
- const: bus
279+
clocks:
280+
items:
281+
- description: bus clock required for downstream bus access and for
282+
the smmu ptw
283+
- properties:
284+
clock-names:
285+
items:
286+
- const: iface
287+
- const: mem
288+
- const: mem_iface
289+
clocks:
290+
items:
291+
- description: interface clock required to access smmu's registers
292+
through the TCU's programming interface.
293+
- description: bus clock required for memory access
294+
- description: bus clock required for GPU memory access
295+
- properties:
296+
clock-names:
297+
items:
298+
- const: iface-mm
299+
- const: iface-smmu
300+
- const: bus-smmu
301+
clocks:
302+
items:
303+
- description: interface clock required to access mnoc's registers
304+
through the TCU's programming interface.
305+
- description: interface clock required to access smmu's registers
306+
through the TCU's programming interface.
307+
- description: bus clock required for the smmu ptw
308+
309+
- if:
310+
properties:
311+
compatible:
312+
contains:
313+
enum:
273314
- qcom,sdm630-smmu-v2
274315
- qcom,sm6375-smmu-v2
275316
then:

Documentation/devicetree/bindings/iommu/qcom,iommu.yaml

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,16 @@ description: |
1717
1818
properties:
1919
compatible:
20-
items:
21-
- enum:
22-
- qcom,msm8916-iommu
23-
- qcom,msm8953-iommu
24-
- const: qcom,msm-iommu-v1
20+
oneOf:
21+
- items:
22+
- enum:
23+
- qcom,msm8916-iommu
24+
- qcom,msm8953-iommu
25+
- const: qcom,msm-iommu-v1
26+
- items:
27+
- enum:
28+
- qcom,msm8976-iommu
29+
- const: qcom,msm-iommu-v2
2530

2631
clocks:
2732
items:
@@ -64,13 +69,20 @@ patternProperties:
6469
enum:
6570
- qcom,msm-iommu-v1-ns
6671
- qcom,msm-iommu-v1-sec
72+
- qcom,msm-iommu-v2-ns
73+
- qcom,msm-iommu-v2-sec
6774

6875
interrupts:
6976
maxItems: 1
7077

7178
reg:
7279
maxItems: 1
7380

81+
qcom,ctx-asid:
82+
$ref: /schemas/types.yaml#/definitions/uint32
83+
description:
84+
The ASID number associated to the context bank.
85+
7486
required:
7587
- compatible
7688
- interrupts

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

Lines changed: 7 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -2055,24 +2055,6 @@ static struct iommu_domain *arm_smmu_domain_alloc(unsigned type)
20552055
return &smmu_domain->domain;
20562056
}
20572057

2058-
static int arm_smmu_bitmap_alloc(unsigned long *map, int span)
2059-
{
2060-
int idx, size = 1 << span;
2061-
2062-
do {
2063-
idx = find_first_zero_bit(map, size);
2064-
if (idx == size)
2065-
return -ENOSPC;
2066-
} while (test_and_set_bit(idx, map));
2067-
2068-
return idx;
2069-
}
2070-
2071-
static void arm_smmu_bitmap_free(unsigned long *map, int idx)
2072-
{
2073-
clear_bit(idx, map);
2074-
}
2075-
20762058
static void arm_smmu_domain_free(struct iommu_domain *domain)
20772059
{
20782060
struct arm_smmu_domain *smmu_domain = to_smmu_domain(domain);
@@ -2093,7 +2075,7 @@ static void arm_smmu_domain_free(struct iommu_domain *domain)
20932075
} else {
20942076
struct arm_smmu_s2_cfg *cfg = &smmu_domain->s2_cfg;
20952077
if (cfg->vmid)
2096-
arm_smmu_bitmap_free(smmu->vmid_map, cfg->vmid);
2078+
ida_free(&smmu->vmid_map, cfg->vmid);
20972079
}
20982080

20992081
kfree(smmu_domain);
@@ -2167,7 +2149,9 @@ static int arm_smmu_domain_finalise_s2(struct arm_smmu_domain *smmu_domain,
21672149
struct arm_smmu_s2_cfg *cfg = &smmu_domain->s2_cfg;
21682150
typeof(&pgtbl_cfg->arm_lpae_s2_cfg.vtcr) vtcr;
21692151

2170-
vmid = arm_smmu_bitmap_alloc(smmu->vmid_map, smmu->vmid_bits);
2152+
/* Reserve VMID 0 for stage-2 bypass STEs */
2153+
vmid = ida_alloc_range(&smmu->vmid_map, 1, (1 << smmu->vmid_bits) - 1,
2154+
GFP_KERNEL);
21712155
if (vmid < 0)
21722156
return vmid;
21732157

@@ -3098,8 +3082,8 @@ static int arm_smmu_init_strtab(struct arm_smmu_device *smmu)
30983082
reg |= STRTAB_BASE_RA;
30993083
smmu->strtab_cfg.strtab_base = reg;
31003084

3101-
/* Allocate the first VMID for stage-2 bypass STEs */
3102-
set_bit(0, smmu->vmid_map);
3085+
ida_init(&smmu->vmid_map);
3086+
31033087
return 0;
31043088
}
31053089

@@ -3923,6 +3907,7 @@ static void arm_smmu_device_remove(struct platform_device *pdev)
39233907
iommu_device_sysfs_remove(&smmu->iommu);
39243908
arm_smmu_device_disable(smmu);
39253909
iopf_queue_free(smmu->evtq.iopf);
3910+
ida_destroy(&smmu->vmid_map);
39263911
}
39273912

39283913
static void arm_smmu_device_shutdown(struct platform_device *pdev)

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -670,7 +670,7 @@ struct arm_smmu_device {
670670

671671
#define ARM_SMMU_MAX_VMIDS (1 << 16)
672672
unsigned int vmid_bits;
673-
DECLARE_BITMAP(vmid_map, ARM_SMMU_MAX_VMIDS);
673+
struct ida vmid_map;
674674

675675
unsigned int ssid_bits;
676676
unsigned int sid_bits;

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

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -251,10 +251,12 @@ static const struct of_device_id qcom_smmu_client_of_match[] __maybe_unused = {
251251
{ .compatible = "qcom,sc7280-mss-pil" },
252252
{ .compatible = "qcom,sc8180x-mdss" },
253253
{ .compatible = "qcom,sc8280xp-mdss" },
254-
{ .compatible = "qcom,sm8150-mdss" },
255-
{ .compatible = "qcom,sm8250-mdss" },
256254
{ .compatible = "qcom,sdm845-mdss" },
257255
{ .compatible = "qcom,sdm845-mss-pil" },
256+
{ .compatible = "qcom,sm6350-mdss" },
257+
{ .compatible = "qcom,sm6375-mdss" },
258+
{ .compatible = "qcom,sm8150-mdss" },
259+
{ .compatible = "qcom,sm8250-mdss" },
258260
{ }
259261
};
260262

@@ -528,6 +530,7 @@ static const struct of_device_id __maybe_unused qcom_smmu_impl_of_match[] = {
528530
{ .compatible = "qcom,sm6125-smmu-500", .data = &qcom_smmu_500_impl0_data },
529531
{ .compatible = "qcom,sm6350-smmu-v2", .data = &qcom_smmu_v2_data },
530532
{ .compatible = "qcom,sm6350-smmu-500", .data = &qcom_smmu_500_impl0_data },
533+
{ .compatible = "qcom,sm6375-smmu-v2", .data = &qcom_smmu_v2_data },
531534
{ .compatible = "qcom,sm6375-smmu-500", .data = &qcom_smmu_500_impl0_data },
532535
{ .compatible = "qcom,sm8150-smmu-500", .data = &qcom_smmu_500_impl0_data },
533536
{ .compatible = "qcom,sm8250-smmu-500", .data = &qcom_smmu_500_impl0_data },

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

Lines changed: 49 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -51,14 +51,15 @@ struct qcom_iommu_dev {
5151
struct clk_bulk_data clks[CLK_NUM];
5252
void __iomem *local_base;
5353
u32 sec_id;
54-
u8 num_ctxs;
55-
struct qcom_iommu_ctx *ctxs[]; /* indexed by asid-1 */
54+
u8 max_asid;
55+
struct qcom_iommu_ctx *ctxs[]; /* indexed by asid */
5656
};
5757

5858
struct qcom_iommu_ctx {
5959
struct device *dev;
6060
void __iomem *base;
6161
bool secure_init;
62+
bool secured_ctx;
6263
u8 asid; /* asid and ctx bank # are 1:1 */
6364
struct iommu_domain *domain;
6465
};
@@ -94,7 +95,7 @@ static struct qcom_iommu_ctx * to_ctx(struct qcom_iommu_domain *d, unsigned asid
9495
struct qcom_iommu_dev *qcom_iommu = d->iommu;
9596
if (!qcom_iommu)
9697
return NULL;
97-
return qcom_iommu->ctxs[asid - 1];
98+
return qcom_iommu->ctxs[asid];
9899
}
99100

100101
static inline void
@@ -273,6 +274,19 @@ static int qcom_iommu_init_domain(struct iommu_domain *domain,
273274
ctx->secure_init = true;
274275
}
275276

277+
/* Secured QSMMU-500/QSMMU-v2 contexts cannot be programmed */
278+
if (ctx->secured_ctx) {
279+
ctx->domain = domain;
280+
continue;
281+
}
282+
283+
/* Disable context bank before programming */
284+
iommu_writel(ctx, ARM_SMMU_CB_SCTLR, 0);
285+
286+
/* Clear context bank fault address fault status registers */
287+
iommu_writel(ctx, ARM_SMMU_CB_FAR, 0);
288+
iommu_writel(ctx, ARM_SMMU_CB_FSR, ARM_SMMU_FSR_FAULT);
289+
276290
/* TTBRs */
277291
iommu_writeq(ctx, ARM_SMMU_CB_TTBR0,
278292
pgtbl_cfg.arm_lpae_s1_cfg.ttbr |
@@ -527,11 +541,10 @@ static int qcom_iommu_of_xlate(struct device *dev, struct of_phandle_args *args)
527541
qcom_iommu = platform_get_drvdata(iommu_pdev);
528542

529543
/* make sure the asid specified in dt is valid, so we don't have
530-
* to sanity check this elsewhere, since 'asid - 1' is used to
531-
* index into qcom_iommu->ctxs:
544+
* to sanity check this elsewhere:
532545
*/
533-
if (WARN_ON(asid < 1) ||
534-
WARN_ON(asid > qcom_iommu->num_ctxs)) {
546+
if (WARN_ON(asid > qcom_iommu->max_asid) ||
547+
WARN_ON(qcom_iommu->ctxs[asid] == NULL)) {
535548
put_device(&iommu_pdev->dev);
536549
return -EINVAL;
537550
}
@@ -617,23 +630,33 @@ static int qcom_iommu_sec_ptbl_init(struct device *dev)
617630

618631
static int get_asid(const struct device_node *np)
619632
{
620-
u32 reg;
633+
u32 reg, val;
634+
int asid;
621635

622636
/* read the "reg" property directly to get the relative address
623637
* of the context bank, and calculate the asid from that:
624638
*/
625639
if (of_property_read_u32_index(np, "reg", 0, &reg))
626640
return -ENODEV;
627641

628-
return reg / 0x1000; /* context banks are 0x1000 apart */
642+
/*
643+
* Context banks are 0x1000 apart but, in some cases, the ASID
644+
* number doesn't match to this logic and needs to be passed
645+
* from the DT configuration explicitly.
646+
*/
647+
if (!of_property_read_u32(np, "qcom,ctx-asid", &val))
648+
asid = val;
649+
else
650+
asid = reg / 0x1000;
651+
652+
return asid;
629653
}
630654

631655
static int qcom_iommu_ctx_probe(struct platform_device *pdev)
632656
{
633657
struct qcom_iommu_ctx *ctx;
634658
struct device *dev = &pdev->dev;
635659
struct qcom_iommu_dev *qcom_iommu = dev_get_drvdata(dev->parent);
636-
struct resource *res;
637660
int ret, irq;
638661

639662
ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
@@ -643,19 +666,22 @@ static int qcom_iommu_ctx_probe(struct platform_device *pdev)
643666
ctx->dev = dev;
644667
platform_set_drvdata(pdev, ctx);
645668

646-
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
647-
ctx->base = devm_ioremap_resource(dev, res);
669+
ctx->base = devm_platform_ioremap_resource(pdev, 0);
648670
if (IS_ERR(ctx->base))
649671
return PTR_ERR(ctx->base);
650672

651673
irq = platform_get_irq(pdev, 0);
652674
if (irq < 0)
653-
return -ENODEV;
675+
return irq;
676+
677+
if (of_device_is_compatible(dev->of_node, "qcom,msm-iommu-v2-sec"))
678+
ctx->secured_ctx = true;
654679

655680
/* clear IRQs before registering fault handler, just in case the
656681
* boot-loader left us a surprise:
657682
*/
658-
iommu_writel(ctx, ARM_SMMU_CB_FSR, iommu_readl(ctx, ARM_SMMU_CB_FSR));
683+
if (!ctx->secured_ctx)
684+
iommu_writel(ctx, ARM_SMMU_CB_FSR, iommu_readl(ctx, ARM_SMMU_CB_FSR));
659685

660686
ret = devm_request_irq(dev, irq,
661687
qcom_iommu_fault,
@@ -677,7 +703,7 @@ static int qcom_iommu_ctx_probe(struct platform_device *pdev)
677703

678704
dev_dbg(dev, "found asid %u\n", ctx->asid);
679705

680-
qcom_iommu->ctxs[ctx->asid - 1] = ctx;
706+
qcom_iommu->ctxs[ctx->asid] = ctx;
681707

682708
return 0;
683709
}
@@ -689,12 +715,14 @@ static void qcom_iommu_ctx_remove(struct platform_device *pdev)
689715

690716
platform_set_drvdata(pdev, NULL);
691717

692-
qcom_iommu->ctxs[ctx->asid - 1] = NULL;
718+
qcom_iommu->ctxs[ctx->asid] = NULL;
693719
}
694720

695721
static const struct of_device_id ctx_of_match[] = {
696722
{ .compatible = "qcom,msm-iommu-v1-ns" },
697723
{ .compatible = "qcom,msm-iommu-v1-sec" },
724+
{ .compatible = "qcom,msm-iommu-v2-ns" },
725+
{ .compatible = "qcom,msm-iommu-v2-sec" },
698726
{ /* sentinel */ }
699727
};
700728

@@ -712,7 +740,8 @@ static bool qcom_iommu_has_secure_context(struct qcom_iommu_dev *qcom_iommu)
712740
struct device_node *child;
713741

714742
for_each_child_of_node(qcom_iommu->dev->of_node, child) {
715-
if (of_device_is_compatible(child, "qcom,msm-iommu-v1-sec")) {
743+
if (of_device_is_compatible(child, "qcom,msm-iommu-v1-sec") ||
744+
of_device_is_compatible(child, "qcom,msm-iommu-v2-sec")) {
716745
of_node_put(child);
717746
return true;
718747
}
@@ -736,11 +765,11 @@ static int qcom_iommu_device_probe(struct platform_device *pdev)
736765
for_each_child_of_node(dev->of_node, child)
737766
max_asid = max(max_asid, get_asid(child));
738767

739-
qcom_iommu = devm_kzalloc(dev, struct_size(qcom_iommu, ctxs, max_asid),
768+
qcom_iommu = devm_kzalloc(dev, struct_size(qcom_iommu, ctxs, max_asid + 1),
740769
GFP_KERNEL);
741770
if (!qcom_iommu)
742771
return -ENOMEM;
743-
qcom_iommu->num_ctxs = max_asid;
772+
qcom_iommu->max_asid = max_asid;
744773
qcom_iommu->dev = dev;
745774

746775
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -856,6 +885,7 @@ static const struct dev_pm_ops qcom_iommu_pm_ops = {
856885

857886
static const struct of_device_id qcom_iommu_of_match[] = {
858887
{ .compatible = "qcom,msm-iommu-v1" },
888+
{ .compatible = "qcom,msm-iommu-v2" },
859889
{ /* sentinel */ }
860890
};
861891

0 commit comments

Comments
 (0)