[COMMON] iommu/exynos: add dma-window property parsing
authorJanghyuck Kim <janghyuck.kim@samsung.com>
Wed, 11 May 2016 02:25:18 +0000 (11:25 +0900)
committerSangwook Ju <sw.ju@samsung.com>
Mon, 14 May 2018 10:45:19 +0000 (19:45 +0900)
Each domain may need different dma ranges for client device's
requirement. 'dma-window' property specifies dma ranges
for each domain.

This property is optional, so if it doesn't exist,
default dma ranges from 0x10000000 to 0xD0000000 are used.

If this property is used, address and size cells should be described.
Below is an example.

iommu-domain_something {
compatible = "samsung,exynos-iommu-bus";

#dma-address-cells = <1>;
#dma-size-cells = <1>;
/* start address, size */
dma-window = <0x10000000 0xC0000000>;

domain-clients = <&something>;
};

Change-Id: I2765f8a4a6b142475c5de80aa73234bef0bd3248
Signed-off-by: Janghyuck Kim <janghyuck.kim@samsung.com>
drivers/iommu/exynos-iommu.c
drivers/iommu/exynos-iommu.h
drivers/iommu/exynos-iovmm.c

index 9c55c160fa5ae32a244af51e43e73717b2735a7f..509a444771799eeea0fc6574573e417247973d72 100644 (file)
 
 #include "exynos-iommu.h"
 
+/* Default IOVA region: [0x1000000, 0xD0000000) */
+#define IOVA_START     0x10000000
+#define IOVA_END       0xD0000000
+#define IOVA_OVFL(x)   ((x) > 0xFFFFFFFF)
+
 static struct kmem_cache *lv2table_kmem_cache;
 
 static struct sysmmu_drvdata *sysmmu_drvdata_list;
@@ -1253,11 +1258,30 @@ static int __init exynos_iommu_create_domain(void)
                struct device_node *np;
                struct exynos_iovmm *vmm = NULL;
                struct exynos_iommu_domain *domain;
+               unsigned int start = IOVA_START, end = IOVA_END;
+               dma_addr_t d_addr;
+               size_t d_size;
                int i = 0;
 
+               ret = of_get_dma_window(domain_np, NULL, 0, NULL, &d_addr, &d_size);
+               if (!ret) {
+                       if (d_addr == 0 || IOVA_OVFL(d_addr + d_size)) {
+                               pr_err("Failed to get valid dma ranges,\n");
+                               pr_err("Domain %s, range %pad++%#zx]\n",
+                                       domain_np->name, &d_addr, d_size);
+                               of_node_put(domain_np);
+                               return -EINVAL;
+                       }
+                       start = d_addr;
+                       end = d_addr + d_size;
+               }
+               pr_info("DMA ranges for domain %s. [%#x..%#x]\n",
+                                       domain_np->name, start, end);
+
                while ((np = of_parse_phandle(domain_np, "domain-clients", i++))) {
                        if (!vmm) {
-                               vmm = exynos_create_single_iovmm(np->name);
+                               vmm = exynos_create_single_iovmm(np->name,
+                                                               start, end);
                                if (IS_ERR(vmm)) {
                                        pr_err("%s: Failed to create IOVM space\
                                                        of %s\n",
index 3eb267ac85ddd57373d4d3018e7868ce7a156ead..955e66c7cfe995f78a85134ee3d8cfab859f402a 100644 (file)
@@ -363,7 +363,8 @@ static inline struct exynos_iovmm *exynos_get_iovmm(struct device *dev)
 struct exynos_vm_region *find_iovm_region(struct exynos_iovmm *vmm,
                                                dma_addr_t iova);
 
-struct exynos_iovmm *exynos_create_single_iovmm(const char *name);
+struct exynos_iovmm *exynos_create_single_iovmm(const char *name,
+                                       unsigned int start, unsigned int end);
 #else
 static inline struct exynos_iovmm *exynos_get_iovmm(struct device *dev)
 {
@@ -376,7 +377,8 @@ struct exynos_vm_region *find_iovm_region(struct exynos_iovmm *vmm,
        return NULL;
 }
 
-static inline struct exynos_iovmm *exynos_create_single_iovmm(const char *name)
+static inline struct exynos_iovmm *exynos_create_single_iovmm(const char *name,
+                                       unsigned int start, unsigned int end);
 {
        return NULL;
 }
index 3f8643937b97b4ef2531adc73f2b1b6d08d1627b..b61ad53f9a6b089fd16c4917b4b2fed0330a0ab4 100644 (file)
@@ -24,9 +24,6 @@
 
 #include "exynos-iommu.h"
 
-/* IOVM region: [0x1000000, 0xD0000000) */
-#define IOVA_START     0x10000000
-#define IOVM_SIZE      (0xD0000000  - IOVA_START)
 #define sg_physically_continuous(sg) (sg_next(sg) == NULL)
 
 /* alloc_iovm_region - Allocate IO virtual memory region
@@ -678,7 +675,8 @@ static void iovmm_register_debugfs(struct exynos_iovmm *vmm)
                        exynos_iovmm_debugfs_root, vmm, &iovmm_debug_fops);
 }
 
-struct exynos_iovmm *exynos_create_single_iovmm(const char *name)
+struct exynos_iovmm *exynos_create_single_iovmm(const char *name,
+                                       unsigned int start, unsigned int end)
 {
        struct exynos_iovmm *vmm;
        int ret = 0;
@@ -689,9 +687,9 @@ struct exynos_iovmm *exynos_create_single_iovmm(const char *name)
                goto err_alloc_vmm;
        }
 
-       vmm->iovm_size = IOVM_SIZE;
-       vmm->iova_start = IOVA_START;
-       vmm->vm_map = kzalloc(IOVM_BITMAP_SIZE(IOVM_SIZE), GFP_KERNEL);
+       vmm->iovm_size = (size_t)(end - start);
+       vmm->iova_start = start;
+       vmm->vm_map = kzalloc(IOVM_BITMAP_SIZE(vmm->iovm_size), GFP_KERNEL);
        if (!vmm->vm_map) {
                ret = -ENOMEM;
                goto err_setup_domain;
@@ -712,8 +710,8 @@ struct exynos_iovmm *exynos_create_single_iovmm(const char *name)
 
        iovmm_register_debugfs(vmm);
 
-       pr_debug("%s IOVMM: Created %#x B IOVMM from %#x.\n",
-                       name, IOVM_SIZE, IOVA_START);
+       pr_debug("%s IOVMM: Created %#zx B IOVMM from %#x.\n",
+                       name, vmm->iovm_size, vmm->iova_start);
        return vmm;
 
 err_setup_domain: