OSDN Git Service

Merge branches 'apple/dart', 'arm/mediatek', 'arm/renesas', 'arm/smmu', 'arm/tegra...
[uclinux-h8/linux.git] / drivers / iommu / apple-dart.c
index 559db92..96d4a1f 100644 (file)
@@ -15,7 +15,6 @@
 #include <linux/bitfield.h>
 #include <linux/clk.h>
 #include <linux/dev_printk.h>
-#include <linux/dma-iommu.h>
 #include <linux/dma-mapping.h>
 #include <linux/err.h>
 #include <linux/interrupt.h>
@@ -70,6 +69,8 @@
 #define DART_ERROR_ADDR_HI 0x54
 #define DART_ERROR_ADDR_LO 0x50
 
+#define DART_STREAMS_ENABLE 0xfc
+
 #define DART_TCR(sid) (0x100 + 4 * (sid))
 #define DART_TCR_TRANSLATE_ENABLE BIT(7)
 #define DART_TCR_BYPASS0_ENABLE BIT(8)
@@ -183,7 +184,6 @@ struct apple_dart_master_cfg {
 
 static struct platform_driver apple_dart_driver;
 static const struct iommu_ops apple_dart_iommu_ops;
-static const struct iommu_flush_ops apple_dart_tlb_ops;
 
 static struct apple_dart_domain *to_dart_domain(struct iommu_domain *dom)
 {
@@ -302,6 +302,9 @@ static int apple_dart_hw_reset(struct apple_dart *dart)
        apple_dart_hw_disable_dma(&stream_map);
        apple_dart_hw_clear_all_ttbrs(&stream_map);
 
+       /* enable all streams globally since TCR is used to control isolation */
+       writel(DART_STREAM_ALL, dart->regs + DART_STREAMS_ENABLE);
+
        /* clear any pending errors before the interrupt is unmasked */
        writel(readl(dart->regs + DART_ERROR), dart->regs + DART_ERROR);
 
@@ -338,22 +341,6 @@ static void apple_dart_iotlb_sync_map(struct iommu_domain *domain,
        apple_dart_domain_flush_tlb(to_dart_domain(domain));
 }
 
-static void apple_dart_tlb_flush_all(void *cookie)
-{
-       apple_dart_domain_flush_tlb(cookie);
-}
-
-static void apple_dart_tlb_flush_walk(unsigned long iova, size_t size,
-                                     size_t granule, void *cookie)
-{
-       apple_dart_domain_flush_tlb(cookie);
-}
-
-static const struct iommu_flush_ops apple_dart_tlb_ops = {
-       .tlb_flush_all = apple_dart_tlb_flush_all,
-       .tlb_flush_walk = apple_dart_tlb_flush_walk,
-};
-
 static phys_addr_t apple_dart_iova_to_phys(struct iommu_domain *domain,
                                           dma_addr_t iova)
 {
@@ -435,7 +422,6 @@ static int apple_dart_finalize_domain(struct iommu_domain *domain,
                .ias = 32,
                .oas = 36,
                .coherent_walk = 1,
-               .tlb = &apple_dart_tlb_ops,
                .iommu_dev = dart->dev,
        };
 
@@ -596,7 +582,6 @@ static struct iommu_domain *apple_dart_domain_alloc(unsigned int type)
        if (!dart_domain)
                return NULL;
 
-       iommu_get_dma_cookie(&dart_domain->domain);
        mutex_init(&dart_domain->init_lock);
 
        /* no need to allocate pgtbl_ops or do any other finalization steps */
@@ -661,16 +646,34 @@ static int apple_dart_of_xlate(struct device *dev, struct of_phandle_args *args)
        return -EINVAL;
 }
 
+static DEFINE_MUTEX(apple_dart_groups_lock);
+
+static void apple_dart_release_group(void *iommu_data)
+{
+       int i, sid;
+       struct apple_dart_stream_map *stream_map;
+       struct apple_dart_master_cfg *group_master_cfg = iommu_data;
+
+       mutex_lock(&apple_dart_groups_lock);
+
+       for_each_stream_map(i, group_master_cfg, stream_map)
+               for_each_set_bit(sid, &stream_map->sidmap, DART_MAX_STREAMS)
+                       stream_map->dart->sid2group[sid] = NULL;
+
+       kfree(iommu_data);
+       mutex_unlock(&apple_dart_groups_lock);
+}
+
 static struct iommu_group *apple_dart_device_group(struct device *dev)
 {
-       static DEFINE_MUTEX(lock);
        int i, sid;
        struct apple_dart_master_cfg *cfg = dev_iommu_priv_get(dev);
        struct apple_dart_stream_map *stream_map;
+       struct apple_dart_master_cfg *group_master_cfg;
        struct iommu_group *group = NULL;
        struct iommu_group *res = ERR_PTR(-EINVAL);
 
-       mutex_lock(&lock);
+       mutex_lock(&apple_dart_groups_lock);
 
        for_each_stream_map(i, cfg, stream_map) {
                for_each_set_bit(sid, &stream_map->sidmap, DART_MAX_STREAMS) {
@@ -698,6 +701,19 @@ static struct iommu_group *apple_dart_device_group(struct device *dev)
 #endif
                group = generic_device_group(dev);
 
+       res = ERR_PTR(-ENOMEM);
+       if (!group)
+               goto out;
+
+       group_master_cfg = kmemdup(cfg, sizeof(*group_master_cfg), GFP_KERNEL);
+       if (!group_master_cfg) {
+               iommu_group_put(group);
+               goto out;
+       }
+
+       iommu_group_set_iommudata(group, group_master_cfg,
+               apple_dart_release_group);
+
        for_each_stream_map(i, cfg, stream_map)
                for_each_set_bit(sid, &stream_map->sidmap, DART_MAX_STREAMS)
                        stream_map->dart->sid2group[sid] = group;
@@ -705,7 +721,7 @@ static struct iommu_group *apple_dart_device_group(struct device *dev)
        res = group;
 
 out:
-       mutex_unlock(&lock);
+       mutex_unlock(&apple_dart_groups_lock);
        return res;
 }