aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/iommu/arm-smmu.c
diff options
context:
space:
mode:
authorTirumalesh Chalamarla <tchalamarla@caviumnetworks.com>2016-03-04 16:56:09 -0500
committerWill Deacon <will.deacon@arm.com>2016-05-03 13:23:01 -0400
commit1bd37a6835bef0ecd2138cb42f9088fd890f9939 (patch)
treec2b9cb2eb6d21b7d12d7a846e177d67fd7638d32 /drivers/iommu/arm-smmu.c
parent4e3e9b6997b24383264031198bf8905b3746221e (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.c39
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
339struct arm_smmu_cfg { 341struct 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
349enum arm_smmu_domain_stage { 351enum 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
377static atomic_t cavium_smmu_context_count = ATOMIC_INIT(0);
378
375static struct arm_smmu_option_prop arm_smmu_options[] = { 379static 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};
1742MODULE_DEVICE_TABLE(of, arm_smmu_of_match); 1747MODULE_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);