iommu/arm-smmu: fix architecture version detection
[firefly-linux-kernel-4.4.55.git] / drivers / iommu / arm-smmu.c
index 482cc9e3138a5312692ca8b2ff3130f4930871d3..c00f483e106f03617014c4aeca76ade93f1beea1 100644 (file)
@@ -24,7 +24,7 @@
  *     - v7/v8 long-descriptor format
  *     - Non-secure access to the SMMU
  *     - 4k and 64k pages, with contiguous pte hints.
- *     - Up to 42-bit addressing (dependent on VA_BITS)
+ *     - Up to 48-bit addressing (dependent on VA_BITS)
  *     - Context fault reporting
  */
 
@@ -331,6 +331,11 @@ module_param_named(force_stage, force_stage, int, S_IRUGO | S_IWUSR);
 MODULE_PARM_DESC(force_stage,
        "Force SMMU mappings to be installed at a particular stage of translation. A value of '1' or '2' forces the corresponding stage. All other values are ignored (i.e. no stage is forced). Note that selecting a specific stage will disable support for nested translation.");
 
+enum arm_smmu_arch_version {
+       ARM_SMMU_V1 = 1,
+       ARM_SMMU_V2,
+};
+
 struct arm_smmu_smr {
        u8                              idx;
        u16                             mask;
@@ -365,7 +370,7 @@ struct arm_smmu_device {
 
 #define ARM_SMMU_OPT_SECURE_CFG_ACCESS (1 << 0)
        u32                             options;
-       int                             version;
+       enum arm_smmu_arch_version      version;
 
        u32                             num_context_banks;
        u32                             num_s2_context_banks;
@@ -375,8 +380,9 @@ struct arm_smmu_device {
        u32                             num_mapping_groups;
        DECLARE_BITMAP(smr_map, ARM_SMMU_MAX_SMRS);
 
-       unsigned long                   input_size;
+       unsigned long                   s1_input_size;
        unsigned long                   s1_output_size;
+       unsigned long                   s2_input_size;
        unsigned long                   s2_output_size;
 
        u32                             num_global_irqs;
@@ -736,7 +742,7 @@ static void arm_smmu_init_context_bank(struct arm_smmu_domain *smmu_domain)
 
        /* CBAR */
        reg = cfg->cbar;
-       if (smmu->version == 1)
+       if (smmu->version == ARM_SMMU_V1)
                reg |= cfg->irptndx << CBAR_IRPTNDX_SHIFT;
 
        /*
@@ -751,7 +757,7 @@ static void arm_smmu_init_context_bank(struct arm_smmu_domain *smmu_domain)
        }
        writel_relaxed(reg, gr1_base + ARM_SMMU_GR1_CBAR(cfg->cbndx));
 
-       if (smmu->version > 1) {
+       if (smmu->version > ARM_SMMU_V1) {
                /* CBA2R */
 #ifdef CONFIG_64BIT
                reg = CBA2R_RW64_64BIT;
@@ -762,7 +768,7 @@ static void arm_smmu_init_context_bank(struct arm_smmu_domain *smmu_domain)
                               gr1_base + ARM_SMMU_GR1_CBA2R(cfg->cbndx));
 
                /* TTBCR2 */
-               switch (smmu->input_size) {
+               switch (smmu->s1_input_size) {
                case 32:
                        reg = (TTBCR2_ADDR_32 << TTBCR2_SEP_SHIFT);
                        break;
@@ -824,14 +830,14 @@ static void arm_smmu_init_context_bank(struct arm_smmu_domain *smmu_domain)
         * TTBCR
         * We use long descriptor, with inner-shareable WBWA tables in TTBR0.
         */
-       if (smmu->version > 1) {
+       if (smmu->version > ARM_SMMU_V1) {
                if (PAGE_SIZE == SZ_4K)
                        reg = TTBCR_TG0_4K;
                else
                        reg = TTBCR_TG0_64K;
 
                if (!stage1) {
-                       reg |= (64 - smmu->s1_output_size) << TTBCR_T0SZ_SHIFT;
+                       reg |= (64 - smmu->s2_input_size) << TTBCR_T0SZ_SHIFT;
 
                        switch (smmu->s2_output_size) {
                        case 32:
@@ -854,7 +860,7 @@ static void arm_smmu_init_context_bank(struct arm_smmu_domain *smmu_domain)
                                break;
                        }
                } else {
-                       reg |= (64 - smmu->input_size) << TTBCR_T0SZ_SHIFT;
+                       reg |= (64 - smmu->s1_input_size) << TTBCR_T0SZ_SHIFT;
                }
        } else {
                reg = 0;
@@ -921,7 +927,7 @@ static int arm_smmu_init_domain_context(struct iommu_domain *domain,
                goto out_unlock;
 
        cfg->cbndx = ret;
-       if (smmu->version == 1) {
+       if (smmu->version == ARM_SMMU_V1) {
                cfg->irptndx = atomic_inc_return(&smmu->irptndx);
                cfg->irptndx %= smmu->num_context_irqs;
        } else {
@@ -1454,9 +1460,11 @@ static int arm_smmu_handle_mapping(struct arm_smmu_domain *smmu_domain,
 
        if (cfg->cbar == CBAR_TYPE_S2_TRANS) {
                stage = 2;
+               input_mask = (1ULL << smmu->s2_input_size) - 1;
                output_mask = (1ULL << smmu->s2_output_size) - 1;
        } else {
                stage = 1;
+               input_mask = (1ULL << smmu->s1_input_size) - 1;
                output_mask = (1ULL << smmu->s1_output_size) - 1;
        }
 
@@ -1466,7 +1474,6 @@ static int arm_smmu_handle_mapping(struct arm_smmu_domain *smmu_domain,
        if (size & ~PAGE_MASK)
                return -EINVAL;
 
-       input_mask = (1ULL << smmu->input_size) - 1;
        if ((phys_addr_t)iova & ~input_mask)
                return -ERANGE;
 
@@ -1731,10 +1738,6 @@ static int arm_smmu_device_cfg_probe(struct arm_smmu_device *smmu)
        u32 id;
 
        dev_notice(smmu->dev, "probing hardware configuration...\n");
-
-       /* Primecell ID */
-       id = readl_relaxed(gr0_base + ARM_SMMU_GR0_PIDR2);
-       smmu->version = ((id >> PIDR2_ARCH_SHIFT) & PIDR2_ARCH_MASK) + 1;
        dev_notice(smmu->dev, "SMMUv%d with:\n", smmu->version);
 
        /* ID0 */
@@ -1838,28 +1841,21 @@ static int arm_smmu_device_cfg_probe(struct arm_smmu_device *smmu)
        /* ID2 */
        id = readl_relaxed(gr0_base + ARM_SMMU_GR0_ID2);
        size = arm_smmu_id_size_to_bits((id >> ID2_IAS_SHIFT) & ID2_IAS_MASK);
+       smmu->s1_output_size = min_t(unsigned long, PHYS_MASK_SHIFT, size);
 
-       /*
-        * Stage-1 output limited by stage-2 input size due to pgd
-        * allocation (PTRS_PER_PGD).
-        */
-       if (smmu->features & ARM_SMMU_FEAT_TRANS_NESTED) {
+       /* Stage-2 input size limited due to pgd allocation (PTRS_PER_PGD) */
 #ifdef CONFIG_64BIT
-               smmu->s1_output_size = min_t(unsigned long, VA_BITS, size);
+       smmu->s2_input_size = min_t(unsigned long, VA_BITS, size);
 #else
-               smmu->s1_output_size = min(32UL, size);
+       smmu->s2_input_size = min(32UL, size);
 #endif
-       } else {
-               smmu->s1_output_size = min_t(unsigned long, PHYS_MASK_SHIFT,
-                                            size);
-       }
 
        /* The stage-2 output mask is also applied for bypass */
        size = arm_smmu_id_size_to_bits((id >> ID2_OAS_SHIFT) & ID2_OAS_MASK);
        smmu->s2_output_size = min_t(unsigned long, PHYS_MASK_SHIFT, size);
 
-       if (smmu->version == 1) {
-               smmu->input_size = 32;
+       if (smmu->version == ARM_SMMU_V1) {
+               smmu->s1_input_size = 32;
        } else {
 #ifdef CONFIG_64BIT
                size = (id >> ID2_UBS_SHIFT) & ID2_UBS_MASK;
@@ -1867,7 +1863,7 @@ static int arm_smmu_device_cfg_probe(struct arm_smmu_device *smmu)
 #else
                size = 32;
 #endif
-               smmu->input_size = size;
+               smmu->s1_input_size = size;
 
                if ((PAGE_SIZE == SZ_4K && !(id & ID2_PTFS_4K)) ||
                    (PAGE_SIZE == SZ_64K && !(id & ID2_PTFS_64K)) ||
@@ -1878,15 +1874,29 @@ static int arm_smmu_device_cfg_probe(struct arm_smmu_device *smmu)
                }
        }
 
-       dev_notice(smmu->dev,
-                  "\t%lu-bit VA, %lu-bit IPA, %lu-bit PA\n",
-                  smmu->input_size, smmu->s1_output_size,
-                  smmu->s2_output_size);
+       if (smmu->features & ARM_SMMU_FEAT_TRANS_S1)
+               dev_notice(smmu->dev, "\tStage-1: %lu-bit VA -> %lu-bit IPA\n",
+                          smmu->s1_input_size, smmu->s1_output_size);
+
+       if (smmu->features & ARM_SMMU_FEAT_TRANS_S2)
+               dev_notice(smmu->dev, "\tStage-2: %lu-bit IPA -> %lu-bit PA\n",
+                          smmu->s2_input_size, smmu->s2_output_size);
+
        return 0;
 }
 
+static struct of_device_id arm_smmu_of_match[] = {
+       { .compatible = "arm,smmu-v1", .data = (void *)ARM_SMMU_V1 },
+       { .compatible = "arm,smmu-v2", .data = (void *)ARM_SMMU_V2 },
+       { .compatible = "arm,mmu-400", .data = (void *)ARM_SMMU_V1 },
+       { .compatible = "arm,mmu-500", .data = (void *)ARM_SMMU_V2 },
+       { },
+};
+MODULE_DEVICE_TABLE(of, arm_smmu_of_match);
+
 static int arm_smmu_device_dt_probe(struct platform_device *pdev)
 {
+       const struct of_device_id *of_id;
        struct resource *res;
        struct arm_smmu_device *smmu;
        struct device *dev = &pdev->dev;
@@ -1901,6 +1911,9 @@ static int arm_smmu_device_dt_probe(struct platform_device *pdev)
        }
        smmu->dev = dev;
 
+       of_id = of_match_node(arm_smmu_of_match, dev->of_node);
+       smmu->version = (enum arm_smmu_arch_version)of_id->data;
+
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        smmu->base = devm_ioremap_resource(dev, res);
        if (IS_ERR(smmu->base))
@@ -1965,7 +1978,7 @@ static int arm_smmu_device_dt_probe(struct platform_device *pdev)
 
        parse_driver_options(smmu);
 
-       if (smmu->version > 1 &&
+       if (smmu->version > ARM_SMMU_V1 &&
            smmu->num_context_banks != smmu->num_context_irqs) {
                dev_err(dev,
                        "found only %d context interrupt(s) but %d required\n",
@@ -2046,17 +2059,6 @@ static int arm_smmu_device_remove(struct platform_device *pdev)
        return 0;
 }
 
-#ifdef CONFIG_OF
-static struct of_device_id arm_smmu_of_match[] = {
-       { .compatible = "arm,smmu-v1", },
-       { .compatible = "arm,smmu-v2", },
-       { .compatible = "arm,mmu-400", },
-       { .compatible = "arm,mmu-500", },
-       { },
-};
-MODULE_DEVICE_TABLE(of, arm_smmu_of_match);
-#endif
-
 static struct platform_driver arm_smmu_driver = {
        .driver = {
                .owner          = THIS_MODULE,