diff options
author | Tirumalesh Chalamarla <tchalamarla@caviumnetworks.com> | 2016-03-04 16:56:09 -0500 |
---|---|---|
committer | Will Deacon <will.deacon@arm.com> | 2016-05-03 13:23:01 -0400 |
commit | 1bd37a6835bef0ecd2138cb42f9088fd890f9939 (patch) | |
tree | c2b9cb2eb6d21b7d12d7a846e177d67fd7638d32 /drivers/iommu/arm-smmu.c | |
parent | 4e3e9b6997b24383264031198bf8905b3746221e (diff) |
iommu/arm-smmu: Workaround for ThunderX erratum #27704
Due to erratum #27704, the CN88xx SMMUv2 implementation supports only
shared ASID and VMID numberspaces.
This patch ensures that ASID and VMIDs are unique across all SMMU
instances on affected Cavium systems.
Signed-off-by: Tirumalesh Chalamarla <tchalamarla@caviumnetworks.com>
Signed-off-by: Akula Geethasowjanya <Geethasowjanya.Akula@caviumnetworks.com>
[will: commit message, comments and formatting]
Signed-off-by: Will Deacon <will.deacon@arm.com>
Diffstat (limited to 'drivers/iommu/arm-smmu.c')
-rw-r--r-- | drivers/iommu/arm-smmu.c | 39 |
1 files changed, 28 insertions, 11 deletions
diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c index 25e884a75f6b..e933679a3266 100644 --- a/drivers/iommu/arm-smmu.c +++ b/drivers/iommu/arm-smmu.c | |||
@@ -334,6 +334,8 @@ struct arm_smmu_device { | |||
334 | 334 | ||
335 | struct list_head list; | 335 | struct list_head list; |
336 | struct rb_root masters; | 336 | struct rb_root masters; |
337 | |||
338 | u32 cavium_id_base; /* Specific to Cavium */ | ||
337 | }; | 339 | }; |
338 | 340 | ||
339 | struct arm_smmu_cfg { | 341 | struct arm_smmu_cfg { |
@@ -343,8 +345,8 @@ struct arm_smmu_cfg { | |||
343 | }; | 345 | }; |
344 | #define INVALID_IRPTNDX 0xff | 346 | #define INVALID_IRPTNDX 0xff |
345 | 347 | ||
346 | #define ARM_SMMU_CB_ASID(cfg) ((cfg)->cbndx) | 348 | #define ARM_SMMU_CB_ASID(smmu, cfg) ((u16)(smmu)->cavium_id_base + (cfg)->cbndx) |
347 | #define ARM_SMMU_CB_VMID(cfg) ((cfg)->cbndx + 1) | 349 | #define ARM_SMMU_CB_VMID(smmu, cfg) ((u16)(smmu)->cavium_id_base + (cfg)->cbndx + 1) |
348 | 350 | ||
349 | enum arm_smmu_domain_stage { | 351 | enum arm_smmu_domain_stage { |
350 | ARM_SMMU_DOMAIN_S1 = 0, | 352 | ARM_SMMU_DOMAIN_S1 = 0, |
@@ -372,6 +374,8 @@ struct arm_smmu_option_prop { | |||
372 | const char *prop; | 374 | const char *prop; |
373 | }; | 375 | }; |
374 | 376 | ||
377 | static atomic_t cavium_smmu_context_count = ATOMIC_INIT(0); | ||
378 | |||
375 | static struct arm_smmu_option_prop arm_smmu_options[] = { | 379 | static struct arm_smmu_option_prop arm_smmu_options[] = { |
376 | { ARM_SMMU_OPT_SECURE_CFG_ACCESS, "calxeda,smmu-secure-config-access" }, | 380 | { ARM_SMMU_OPT_SECURE_CFG_ACCESS, "calxeda,smmu-secure-config-access" }, |
377 | { 0, NULL}, | 381 | { 0, NULL}, |
@@ -583,11 +587,11 @@ static void arm_smmu_tlb_inv_context(void *cookie) | |||
583 | 587 | ||
584 | if (stage1) { | 588 | if (stage1) { |
585 | base = ARM_SMMU_CB_BASE(smmu) + ARM_SMMU_CB(smmu, cfg->cbndx); | 589 | base = ARM_SMMU_CB_BASE(smmu) + ARM_SMMU_CB(smmu, cfg->cbndx); |
586 | writel_relaxed(ARM_SMMU_CB_ASID(cfg), | 590 | writel_relaxed(ARM_SMMU_CB_ASID(smmu, cfg), |
587 | base + ARM_SMMU_CB_S1_TLBIASID); | 591 | base + ARM_SMMU_CB_S1_TLBIASID); |
588 | } else { | 592 | } else { |
589 | base = ARM_SMMU_GR0(smmu); | 593 | base = ARM_SMMU_GR0(smmu); |
590 | writel_relaxed(ARM_SMMU_CB_VMID(cfg), | 594 | writel_relaxed(ARM_SMMU_CB_VMID(smmu, cfg), |
591 | base + ARM_SMMU_GR0_TLBIVMID); | 595 | base + ARM_SMMU_GR0_TLBIVMID); |
592 | } | 596 | } |
593 | 597 | ||
@@ -609,7 +613,7 @@ static void arm_smmu_tlb_inv_range_nosync(unsigned long iova, size_t size, | |||
609 | 613 | ||
610 | if (!IS_ENABLED(CONFIG_64BIT) || smmu->version == ARM_SMMU_V1) { | 614 | if (!IS_ENABLED(CONFIG_64BIT) || smmu->version == ARM_SMMU_V1) { |
611 | iova &= ~12UL; | 615 | iova &= ~12UL; |
612 | iova |= ARM_SMMU_CB_ASID(cfg); | 616 | iova |= ARM_SMMU_CB_ASID(smmu, cfg); |
613 | do { | 617 | do { |
614 | writel_relaxed(iova, reg); | 618 | writel_relaxed(iova, reg); |
615 | iova += granule; | 619 | iova += granule; |
@@ -617,7 +621,7 @@ static void arm_smmu_tlb_inv_range_nosync(unsigned long iova, size_t size, | |||
617 | #ifdef CONFIG_64BIT | 621 | #ifdef CONFIG_64BIT |
618 | } else { | 622 | } else { |
619 | iova >>= 12; | 623 | iova >>= 12; |
620 | iova |= (u64)ARM_SMMU_CB_ASID(cfg) << 48; | 624 | iova |= (u64)ARM_SMMU_CB_ASID(smmu, cfg) << 48; |
621 | do { | 625 | do { |
622 | writeq_relaxed(iova, reg); | 626 | writeq_relaxed(iova, reg); |
623 | iova += granule >> 12; | 627 | iova += granule >> 12; |
@@ -637,7 +641,7 @@ static void arm_smmu_tlb_inv_range_nosync(unsigned long iova, size_t size, | |||
637 | #endif | 641 | #endif |
638 | } else { | 642 | } else { |
639 | reg = ARM_SMMU_GR0(smmu) + ARM_SMMU_GR0_TLBIVMID; | 643 | reg = ARM_SMMU_GR0(smmu) + ARM_SMMU_GR0_TLBIVMID; |
640 | writel_relaxed(ARM_SMMU_CB_VMID(cfg), reg); | 644 | writel_relaxed(ARM_SMMU_CB_VMID(smmu, cfg), reg); |
641 | } | 645 | } |
642 | } | 646 | } |
643 | 647 | ||
@@ -746,7 +750,7 @@ static void arm_smmu_init_context_bank(struct arm_smmu_domain *smmu_domain, | |||
746 | #endif | 750 | #endif |
747 | /* 16-bit VMIDs live in CBA2R */ | 751 | /* 16-bit VMIDs live in CBA2R */ |
748 | if (smmu->features & ARM_SMMU_FEAT_VMID16) | 752 | if (smmu->features & ARM_SMMU_FEAT_VMID16) |
749 | reg |= ARM_SMMU_CB_VMID(cfg) << CBA2R_VMID_SHIFT; | 753 | reg |= ARM_SMMU_CB_VMID(smmu, cfg) << CBA2R_VMID_SHIFT; |
750 | 754 | ||
751 | writel_relaxed(reg, gr1_base + ARM_SMMU_GR1_CBA2R(cfg->cbndx)); | 755 | writel_relaxed(reg, gr1_base + ARM_SMMU_GR1_CBA2R(cfg->cbndx)); |
752 | } | 756 | } |
@@ -765,7 +769,7 @@ static void arm_smmu_init_context_bank(struct arm_smmu_domain *smmu_domain, | |||
765 | (CBAR_S1_MEMATTR_WB << CBAR_S1_MEMATTR_SHIFT); | 769 | (CBAR_S1_MEMATTR_WB << CBAR_S1_MEMATTR_SHIFT); |
766 | } else if (!(smmu->features & ARM_SMMU_FEAT_VMID16)) { | 770 | } else if (!(smmu->features & ARM_SMMU_FEAT_VMID16)) { |
767 | /* 8-bit VMIDs live in CBAR */ | 771 | /* 8-bit VMIDs live in CBAR */ |
768 | reg |= ARM_SMMU_CB_VMID(cfg) << CBAR_VMID_SHIFT; | 772 | reg |= ARM_SMMU_CB_VMID(smmu, cfg) << CBAR_VMID_SHIFT; |
769 | } | 773 | } |
770 | writel_relaxed(reg, gr1_base + ARM_SMMU_GR1_CBAR(cfg->cbndx)); | 774 | writel_relaxed(reg, gr1_base + ARM_SMMU_GR1_CBAR(cfg->cbndx)); |
771 | 775 | ||
@@ -773,11 +777,11 @@ static void arm_smmu_init_context_bank(struct arm_smmu_domain *smmu_domain, | |||
773 | if (stage1) { | 777 | if (stage1) { |
774 | reg64 = pgtbl_cfg->arm_lpae_s1_cfg.ttbr[0]; | 778 | reg64 = pgtbl_cfg->arm_lpae_s1_cfg.ttbr[0]; |
775 | 779 | ||
776 | reg64 |= ((u64)ARM_SMMU_CB_ASID(cfg)) << TTBRn_ASID_SHIFT; | 780 | reg64 |= ((u64)ARM_SMMU_CB_ASID(smmu, cfg)) << TTBRn_ASID_SHIFT; |
777 | smmu_writeq(reg64, cb_base + ARM_SMMU_CB_TTBR0); | 781 | smmu_writeq(reg64, cb_base + ARM_SMMU_CB_TTBR0); |
778 | 782 | ||
779 | reg64 = pgtbl_cfg->arm_lpae_s1_cfg.ttbr[1]; | 783 | reg64 = pgtbl_cfg->arm_lpae_s1_cfg.ttbr[1]; |
780 | reg64 |= ((u64)ARM_SMMU_CB_ASID(cfg)) << TTBRn_ASID_SHIFT; | 784 | reg64 |= ((u64)ARM_SMMU_CB_ASID(smmu, cfg)) << TTBRn_ASID_SHIFT; |
781 | smmu_writeq(reg64, cb_base + ARM_SMMU_CB_TTBR1); | 785 | smmu_writeq(reg64, cb_base + ARM_SMMU_CB_TTBR1); |
782 | } else { | 786 | } else { |
783 | reg64 = pgtbl_cfg->arm_lpae_s2_cfg.vttbr; | 787 | reg64 = pgtbl_cfg->arm_lpae_s2_cfg.vttbr; |
@@ -1737,6 +1741,7 @@ static const struct of_device_id arm_smmu_of_match[] = { | |||
1737 | { .compatible = "arm,mmu-400", .data = (void *)ARM_SMMU_V1 }, | 1741 | { .compatible = "arm,mmu-400", .data = (void *)ARM_SMMU_V1 }, |
1738 | { .compatible = "arm,mmu-401", .data = (void *)ARM_SMMU_V1 }, | 1742 | { .compatible = "arm,mmu-401", .data = (void *)ARM_SMMU_V1 }, |
1739 | { .compatible = "arm,mmu-500", .data = (void *)ARM_SMMU_V2 }, | 1743 | { .compatible = "arm,mmu-500", .data = (void *)ARM_SMMU_V2 }, |
1744 | { .compatible = "cavium,smmu-v2", .data = (void *)ARM_SMMU_V2 }, | ||
1740 | { }, | 1745 | { }, |
1741 | }; | 1746 | }; |
1742 | MODULE_DEVICE_TABLE(of, arm_smmu_of_match); | 1747 | MODULE_DEVICE_TABLE(of, arm_smmu_of_match); |
@@ -1847,6 +1852,18 @@ static int arm_smmu_device_dt_probe(struct platform_device *pdev) | |||
1847 | } | 1852 | } |
1848 | } | 1853 | } |
1849 | 1854 | ||
1855 | /* | ||
1856 | * Cavium CN88xx erratum #27704. | ||
1857 | * Ensure ASID and VMID allocation is unique across all SMMUs in | ||
1858 | * the system. | ||
1859 | */ | ||
1860 | if (of_device_is_compatible(dev->of_node, "cavium,smmu-v2")) { | ||
1861 | smmu->cavium_id_base = | ||
1862 | atomic_add_return(smmu->num_context_banks, | ||
1863 | &cavium_smmu_context_count); | ||
1864 | smmu->cavium_id_base -= smmu->num_context_banks; | ||
1865 | } | ||
1866 | |||
1850 | INIT_LIST_HEAD(&smmu->list); | 1867 | INIT_LIST_HEAD(&smmu->list); |
1851 | spin_lock(&arm_smmu_devices_lock); | 1868 | spin_lock(&arm_smmu_devices_lock); |
1852 | list_add(&smmu->list, &arm_smmu_devices); | 1869 | list_add(&smmu->list, &arm_smmu_devices); |