Merge tag 'iommu-updates-v4.19' of git://git.kernel.org/pub/scm/linux/kernel/git...
[linux-2.6-microblaze.git] / drivers / iommu / ipmmu-vmsa.c
index f026aa1..22b94f8 100644 (file)
@@ -47,6 +47,7 @@ struct ipmmu_features {
        unsigned int number_of_contexts;
        bool setup_imbuscr;
        bool twobit_imttbcr_sl0;
+       bool reserved_context;
 };
 
 struct ipmmu_vmsa_device {
@@ -73,7 +74,7 @@ struct ipmmu_vmsa_domain {
        struct io_pgtable_ops *iop;
 
        unsigned int context_id;
-       spinlock_t lock;                        /* Protects mappings */
+       struct mutex mutex;                     /* Protects mappings */
 };
 
 static struct ipmmu_vmsa_domain *to_vmsa_domain(struct iommu_domain *dom)
@@ -194,7 +195,9 @@ static struct ipmmu_vmsa_device *to_ipmmu(struct device *dev)
 #define IMPMBA(n)                      (0x0280 + ((n) * 4))
 #define IMPMBD(n)                      (0x02c0 + ((n) * 4))
 
-#define IMUCTR(n)                      (0x0300 + ((n) * 16))
+#define IMUCTR(n)                      ((n) < 32 ? IMUCTR0(n) : IMUCTR32(n))
+#define IMUCTR0(n)                     (0x0300 + ((n) * 16))
+#define IMUCTR32(n)                    (0x0600 + (((n) - 32) * 16))
 #define IMUCTR_FIXADDEN                        (1 << 31)
 #define IMUCTR_FIXADD_MASK             (0xff << 16)
 #define IMUCTR_FIXADD_SHIFT            16
@@ -204,7 +207,9 @@ static struct ipmmu_vmsa_device *to_ipmmu(struct device *dev)
 #define IMUCTR_FLUSH                   (1 << 1)
 #define IMUCTR_MMUEN                   (1 << 0)
 
-#define IMUASID(n)                     (0x0308 + ((n) * 16))
+#define IMUASID(n)                     ((n) < 32 ? IMUASID0(n) : IMUASID32(n))
+#define IMUASID0(n)                    (0x0308 + ((n) * 16))
+#define IMUASID32(n)                   (0x0608 + (((n) - 32) * 16))
 #define IMUASID_ASID8_MASK             (0xff << 8)
 #define IMUASID_ASID8_SHIFT            8
 #define IMUASID_ASID0_MASK             (0xff << 0)
@@ -595,7 +600,7 @@ static struct iommu_domain *__ipmmu_domain_alloc(unsigned type)
        if (!domain)
                return NULL;
 
-       spin_lock_init(&domain->lock);
+       mutex_init(&domain->mutex);
 
        return &domain->io_domain;
 }
@@ -641,7 +646,6 @@ static int ipmmu_attach_device(struct iommu_domain *io_domain,
        struct iommu_fwspec *fwspec = dev->iommu_fwspec;
        struct ipmmu_vmsa_device *mmu = to_ipmmu(dev);
        struct ipmmu_vmsa_domain *domain = to_vmsa_domain(io_domain);
-       unsigned long flags;
        unsigned int i;
        int ret = 0;
 
@@ -650,7 +654,7 @@ static int ipmmu_attach_device(struct iommu_domain *io_domain,
                return -ENXIO;
        }
 
-       spin_lock_irqsave(&domain->lock, flags);
+       mutex_lock(&domain->mutex);
 
        if (!domain->mmu) {
                /* The domain hasn't been used yet, initialize it. */
@@ -674,7 +678,7 @@ static int ipmmu_attach_device(struct iommu_domain *io_domain,
        } else
                dev_info(dev, "Reusing IPMMU context %u\n", domain->context_id);
 
-       spin_unlock_irqrestore(&domain->lock, flags);
+       mutex_unlock(&domain->mutex);
 
        if (ret < 0)
                return ret;
@@ -756,8 +760,12 @@ static bool ipmmu_slave_whitelist(struct device *dev)
        return false;
 }
 
-static const struct soc_device_attribute soc_r8a7795[] = {
+static const struct soc_device_attribute soc_rcar_gen3[] = {
        { .soc_id = "r8a7795", },
+       { .soc_id = "r8a7796", },
+       { .soc_id = "r8a77965", },
+       { .soc_id = "r8a77970", },
+       { .soc_id = "r8a77995", },
        { /* sentinel */ }
 };
 
@@ -765,7 +773,7 @@ static int ipmmu_of_xlate(struct device *dev,
                          struct of_phandle_args *spec)
 {
        /* For R-Car Gen3 use a white list to opt-in slave devices */
-       if (soc_device_match(soc_r8a7795) && !ipmmu_slave_whitelist(dev))
+       if (soc_device_match(soc_rcar_gen3) && !ipmmu_slave_whitelist(dev))
                return -ENODEV;
 
        iommu_fwspec_add_ids(dev, spec->args, 1);
@@ -889,7 +897,6 @@ static const struct iommu_ops ipmmu_ops = {
        .unmap = ipmmu_unmap,
        .flush_iotlb_all = ipmmu_iotlb_sync,
        .iotlb_sync = ipmmu_iotlb_sync,
-       .map_sg = default_iommu_map_sg,
        .iova_to_phys = ipmmu_iova_to_phys,
        .add_device = ipmmu_add_device,
        .remove_device = ipmmu_remove_device,
@@ -917,14 +924,16 @@ static const struct ipmmu_features ipmmu_features_default = {
        .number_of_contexts = 1, /* software only tested with one context */
        .setup_imbuscr = true,
        .twobit_imttbcr_sl0 = false,
+       .reserved_context = false,
 };
 
-static const struct ipmmu_features ipmmu_features_r8a7795 = {
+static const struct ipmmu_features ipmmu_features_rcar_gen3 = {
        .use_ns_alias_offset = false,
        .has_cache_leaf_nodes = true,
        .number_of_contexts = 8,
        .setup_imbuscr = false,
        .twobit_imttbcr_sl0 = true,
+       .reserved_context = true,
 };
 
 static const struct of_device_id ipmmu_of_ids[] = {
@@ -933,7 +942,19 @@ static const struct of_device_id ipmmu_of_ids[] = {
                .data = &ipmmu_features_default,
        }, {
                .compatible = "renesas,ipmmu-r8a7795",
-               .data = &ipmmu_features_r8a7795,
+               .data = &ipmmu_features_rcar_gen3,
+       }, {
+               .compatible = "renesas,ipmmu-r8a7796",
+               .data = &ipmmu_features_rcar_gen3,
+       }, {
+               .compatible = "renesas,ipmmu-r8a77965",
+               .data = &ipmmu_features_rcar_gen3,
+       }, {
+               .compatible = "renesas,ipmmu-r8a77970",
+               .data = &ipmmu_features_rcar_gen3,
+       }, {
+               .compatible = "renesas,ipmmu-r8a77995",
+               .data = &ipmmu_features_rcar_gen3,
        }, {
                /* Terminator */
        },
@@ -955,7 +976,7 @@ static int ipmmu_probe(struct platform_device *pdev)
        }
 
        mmu->dev = &pdev->dev;
-       mmu->num_utlbs = 32;
+       mmu->num_utlbs = 48;
        spin_lock_init(&mmu->lock);
        bitmap_zero(mmu->ctx, IPMMU_CTX_MAX);
        mmu->features = of_device_get_match_data(&pdev->dev);
@@ -1018,6 +1039,11 @@ static int ipmmu_probe(struct platform_device *pdev)
                }
 
                ipmmu_device_reset(mmu);
+
+               if (mmu->features->reserved_context) {
+                       dev_info(&pdev->dev, "IPMMU context 0 is reserved\n");
+                       set_bit(0, mmu->ctx);
+               }
        }
 
        /*
@@ -1081,12 +1107,19 @@ static struct platform_driver ipmmu_driver = {
 
 static int __init ipmmu_init(void)
 {
+       struct device_node *np;
        static bool setup_done;
        int ret;
 
        if (setup_done)
                return 0;
 
+       np = of_find_matching_node(NULL, ipmmu_of_ids);
+       if (!np)
+               return 0;
+
+       of_node_put(np);
+
        ret = platform_driver_register(&ipmmu_driver);
        if (ret < 0)
                return ret;