diff options
author | Zhen Lei <thunder.leizhen@huawei.com> | 2015-07-06 23:30:18 -0400 |
---|---|---|
committer | Will Deacon <will.deacon@arm.com> | 2015-07-08 12:24:39 -0400 |
commit | 5e92946c39ca6abc65e34775a93cc1d1a819c0e3 (patch) | |
tree | e55bc9345eaef4358aa963e510a4dbe3500d8023 | |
parent | e2f4c2330f08ba73d9a3c919a3d6ca33dce7d2c2 (diff) |
iommu/arm-smmu: Skip the execution of CMD_PREFETCH_CONFIG
Hisilicon SMMUv3 devices treat CMD_PREFETCH_CONFIG as a illegal command,
execute it will trigger GERROR interrupt. Although the gerror code manage
to turn the prefetch into a SYNC, and the system can continue to run
normally, but it's ugly to print error information.
Signed-off-by: Zhen Lei <thunder.leizhen@huawei.com>
[will: extended binding documentation]
Signed-off-by: Will Deacon <will.deacon@arm.com>
-rw-r--r-- | Documentation/devicetree/bindings/iommu/arm,smmu-v3.txt | 3 | ||||
-rw-r--r-- | drivers/iommu/arm-smmu-v3.c | 32 |
2 files changed, 34 insertions, 1 deletions
diff --git a/Documentation/devicetree/bindings/iommu/arm,smmu-v3.txt b/Documentation/devicetree/bindings/iommu/arm,smmu-v3.txt index c03eec116872..3443e0f838df 100644 --- a/Documentation/devicetree/bindings/iommu/arm,smmu-v3.txt +++ b/Documentation/devicetree/bindings/iommu/arm,smmu-v3.txt | |||
@@ -35,3 +35,6 @@ the PCIe specification. | |||
35 | 35 | ||
36 | NOTE: this only applies to the SMMU itself, not | 36 | NOTE: this only applies to the SMMU itself, not |
37 | masters connected upstream of the SMMU. | 37 | masters connected upstream of the SMMU. |
38 | |||
39 | - hisilicon,broken-prefetch-cmd | ||
40 | : Avoid sending CMD_PREFETCH_* commands to the SMMU. | ||
diff --git a/drivers/iommu/arm-smmu-v3.c b/drivers/iommu/arm-smmu-v3.c index 29cba3280af7..da902baaa794 100644 --- a/drivers/iommu/arm-smmu-v3.c +++ b/drivers/iommu/arm-smmu-v3.c | |||
@@ -543,6 +543,9 @@ struct arm_smmu_device { | |||
543 | #define ARM_SMMU_FEAT_HYP (1 << 12) | 543 | #define ARM_SMMU_FEAT_HYP (1 << 12) |
544 | u32 features; | 544 | u32 features; |
545 | 545 | ||
546 | #define ARM_SMMU_OPT_SKIP_PREFETCH (1 << 0) | ||
547 | u32 options; | ||
548 | |||
546 | struct arm_smmu_cmdq cmdq; | 549 | struct arm_smmu_cmdq cmdq; |
547 | struct arm_smmu_evtq evtq; | 550 | struct arm_smmu_evtq evtq; |
548 | struct arm_smmu_priq priq; | 551 | struct arm_smmu_priq priq; |
@@ -603,11 +606,35 @@ struct arm_smmu_domain { | |||
603 | static DEFINE_SPINLOCK(arm_smmu_devices_lock); | 606 | static DEFINE_SPINLOCK(arm_smmu_devices_lock); |
604 | static LIST_HEAD(arm_smmu_devices); | 607 | static LIST_HEAD(arm_smmu_devices); |
605 | 608 | ||
609 | struct arm_smmu_option_prop { | ||
610 | u32 opt; | ||
611 | const char *prop; | ||
612 | }; | ||
613 | |||
614 | static struct arm_smmu_option_prop arm_smmu_options[] = { | ||
615 | { ARM_SMMU_OPT_SKIP_PREFETCH, "hisilicon,broken-prefetch-cmd" }, | ||
616 | { 0, NULL}, | ||
617 | }; | ||
618 | |||
606 | static struct arm_smmu_domain *to_smmu_domain(struct iommu_domain *dom) | 619 | static struct arm_smmu_domain *to_smmu_domain(struct iommu_domain *dom) |
607 | { | 620 | { |
608 | return container_of(dom, struct arm_smmu_domain, domain); | 621 | return container_of(dom, struct arm_smmu_domain, domain); |
609 | } | 622 | } |
610 | 623 | ||
624 | static void parse_driver_options(struct arm_smmu_device *smmu) | ||
625 | { | ||
626 | int i = 0; | ||
627 | |||
628 | do { | ||
629 | if (of_property_read_bool(smmu->dev->of_node, | ||
630 | arm_smmu_options[i].prop)) { | ||
631 | smmu->options |= arm_smmu_options[i].opt; | ||
632 | dev_notice(smmu->dev, "option %s\n", | ||
633 | arm_smmu_options[i].prop); | ||
634 | } | ||
635 | } while (arm_smmu_options[++i].opt); | ||
636 | } | ||
637 | |||
611 | /* Low-level queue manipulation functions */ | 638 | /* Low-level queue manipulation functions */ |
612 | static bool queue_full(struct arm_smmu_queue *q) | 639 | static bool queue_full(struct arm_smmu_queue *q) |
613 | { | 640 | { |
@@ -1037,7 +1064,8 @@ static void arm_smmu_write_strtab_ent(struct arm_smmu_device *smmu, u32 sid, | |||
1037 | arm_smmu_sync_ste_for_sid(smmu, sid); | 1064 | arm_smmu_sync_ste_for_sid(smmu, sid); |
1038 | 1065 | ||
1039 | /* It's likely that we'll want to use the new STE soon */ | 1066 | /* It's likely that we'll want to use the new STE soon */ |
1040 | arm_smmu_cmdq_issue_cmd(smmu, &prefetch_cmd); | 1067 | if (!(smmu->options & ARM_SMMU_OPT_SKIP_PREFETCH)) |
1068 | arm_smmu_cmdq_issue_cmd(smmu, &prefetch_cmd); | ||
1041 | } | 1069 | } |
1042 | 1070 | ||
1043 | static void arm_smmu_init_bypass_stes(u64 *strtab, unsigned int nent) | 1071 | static void arm_smmu_init_bypass_stes(u64 *strtab, unsigned int nent) |
@@ -2575,6 +2603,8 @@ static int arm_smmu_device_dt_probe(struct platform_device *pdev) | |||
2575 | if (irq > 0) | 2603 | if (irq > 0) |
2576 | smmu->gerr_irq = irq; | 2604 | smmu->gerr_irq = irq; |
2577 | 2605 | ||
2606 | parse_driver_options(smmu); | ||
2607 | |||
2578 | /* Probe the h/w */ | 2608 | /* Probe the h/w */ |
2579 | ret = arm_smmu_device_probe(smmu); | 2609 | ret = arm_smmu_device_probe(smmu); |
2580 | if (ret) | 2610 | if (ret) |