iommu: Add DMA window parser, of_get_dma_window()
Hiroshi Doyu [Mon, 25 Jun 2012 11:23:54 +0000 (14:23 +0300)]
This code was based on:
    "arch/microblaze/kernel/prom_parse.c"
    "arch/powerpc/kernel/prom_parse.c"

Can replace "of_parse_dma_window()" in the above. This supports
different formats flexibly. "prefix" can be configured if any. "busno"
and "index" are optionally specified. Set NULL and 0 if not used.

[Hiroshi DOYU: Backport from the upstream]

Bug 1025468

Change-Id: I45182b312be6c2ef671d852cd2434a0f07206dfa
Signed-off-by: Hiroshi DOYU <hdoyu@nvidia.com>
Acked-by: Stephen Warren <swarren@wwwdotorg.org>
Signed-off-by: Joerg Roedel <joerg.roedel@amd.com>
Reviewed-on: http://git-master/r/166869
Reviewed-by: Automatic_Commit_Validation_User
Reviewed-by: Krishna Reddy <vdumpa@nvidia.com>

drivers/iommu/Kconfig
drivers/iommu/Makefile
drivers/iommu/of_iommu.c [new file with mode: 0644]
include/linux/of_iommu.h [new file with mode: 0644]

index 3e8df39..feec0e6 100644 (file)
@@ -13,6 +13,10 @@ menuconfig IOMMU_SUPPORT
 
 if IOMMU_SUPPORT
 
+config OF_IOMMU
+       def_bool y
+       depends on OF
+
 # MSM IOMMU support
 config MSM_IOMMU
        bool "MSM IOMMU Support"
index 02182be..c205f85 100644 (file)
@@ -1,6 +1,7 @@
 GCOV_PROFILE := y
 
 obj-$(CONFIG_IOMMU_API) += iommu.o
+obj-$(CONFIG_OF_IOMMU) += of_iommu.o
 obj-$(CONFIG_MSM_IOMMU) += msm_iommu.o msm_iommu_dev.o
 obj-$(CONFIG_AMD_IOMMU) += amd_iommu.o amd_iommu_init.o
 obj-$(CONFIG_AMD_IOMMU_V2) += amd_iommu_v2.o
diff --git a/drivers/iommu/of_iommu.c b/drivers/iommu/of_iommu.c
new file mode 100644 (file)
index 0000000..ee249bc
--- /dev/null
@@ -0,0 +1,90 @@
+/*
+ * OF helpers for IOMMU
+ *
+ * Copyright (c) 2012, NVIDIA CORPORATION.  All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <linux/export.h>
+#include <linux/limits.h>
+#include <linux/of.h>
+
+/**
+ * of_get_dma_window - Parse *dma-window property and returns 0 if found.
+ *
+ * @dn: device node
+ * @prefix: prefix for property name if any
+ * @index: index to start to parse
+ * @busno: Returns busno if supported. Otherwise pass NULL
+ * @addr: Returns address that DMA starts
+ * @size: Returns the range that DMA can handle
+ *
+ * This supports different formats flexibly. "prefix" can be
+ * configured if any. "busno" and "index" are optionally
+ * specified. Set 0(or NULL) if not used.
+ */
+int of_get_dma_window(struct device_node *dn, const char *prefix, int index,
+                     unsigned long *busno, dma_addr_t *addr, size_t *size)
+{
+       const __be32 *dma_window, *end;
+       int bytes, cur_index = 0;
+       char propname[NAME_MAX], addrname[NAME_MAX], sizename[NAME_MAX];
+
+       if (!dn || !addr || !size)
+               return -EINVAL;
+
+       if (!prefix)
+               prefix = "";
+
+       snprintf(propname, sizeof(propname), "%sdma-window", prefix);
+       snprintf(addrname, sizeof(addrname), "%s#dma-address-cells", prefix);
+       snprintf(sizename, sizeof(sizename), "%s#dma-size-cells", prefix);
+
+       dma_window = of_get_property(dn, propname, &bytes);
+       if (!dma_window)
+               return -ENODEV;
+       end = dma_window + bytes / sizeof(*dma_window);
+
+       while (dma_window < end) {
+               u32 cells;
+               const void *prop;
+
+               /* busno is one cell if supported */
+               if (busno)
+                       *busno = be32_to_cpup(dma_window++);
+
+               prop = of_get_property(dn, addrname, NULL);
+               if (!prop)
+                       prop = of_get_property(dn, "#address-cells", NULL);
+
+               cells = prop ? be32_to_cpup(prop) : of_n_addr_cells(dn);
+               if (!cells)
+                       return -EINVAL;
+               *addr = of_read_number(dma_window, cells);
+               dma_window += cells;
+
+               prop = of_get_property(dn, sizename, NULL);
+               cells = prop ? be32_to_cpup(prop) : of_n_size_cells(dn);
+               if (!cells)
+                       return -EINVAL;
+               *size = of_read_number(dma_window, cells);
+               dma_window += cells;
+
+               if (cur_index++ == index)
+                       break;
+       }
+       return 0;
+}
+EXPORT_SYMBOL_GPL(of_get_dma_window);
diff --git a/include/linux/of_iommu.h b/include/linux/of_iommu.h
new file mode 100644 (file)
index 0000000..51a560f
--- /dev/null
@@ -0,0 +1,21 @@
+#ifndef __OF_IOMMU_H
+#define __OF_IOMMU_H
+
+#ifdef CONFIG_OF_IOMMU
+
+extern int of_get_dma_window(struct device_node *dn, const char *prefix,
+                            int index, unsigned long *busno, dma_addr_t *addr,
+                            size_t *size);
+
+#else
+
+static inline int of_get_dma_window(struct device_node *dn, const char *prefix,
+                           int index, unsigned long *busno, dma_addr_t *addr,
+                           size_t *size)
+{
+       return -EINVAL;
+}
+
+#endif /* CONFIG_OF_IOMMU */
+
+#endif /* __OF_IOMMU_H */