summaryrefslogtreecommitdiff
path: root/drivers/iommu
diff options
context:
space:
mode:
authorHiroshi Doyu <hdoyu@nvidia.com>2012-11-27 20:46:25 +0200
committerHarshada Kale <hkale@nvidia.com>2013-06-10 03:45:11 -0700
commitf2994961986a91040798291187f9a2e727919fbc (patch)
treea13ed71cdd6cddd742707d2af75b43586526eadd /drivers/iommu
parentb76c1c2be45810290f45f57cb974eaabc8883e43 (diff)
ARM: tegra: bus_notifier registers platform IOMMU devices
Most of platform devices are IOMMU'able in Tegra30 SoC. Registering all IOMMU'able devices manually isn't nice. This patch allows platform bus_notifier to register IOMMU devices. Map info can be passed from DT. Info format is: dma-window = <0 0x40000000>; This is a fix for the following commit: commit 5688fbe0b3de2576e1f3f39e7477ebf9e5a9e49b platform: IOMMU'able platform_device w/ PLATFORM_ENABLE_IOMMU bug 1286500 Change-Id: I80f2be03ff5c8a5b0a73254c0648084cfbcaf314 (cherry picked from commit 805b2bd223214015c1211998576bda8484d36b85) Signed-off-by: Hiroshi Doyu <hdoyu@nvidia.com> Reviewed-on: http://git-master/r/234110 Reviewed-by: Automatic_Commit_Validation_User Reviewed-by: Krishna Reddy <vdumpa@nvidia.com>
Diffstat (limited to 'drivers/iommu')
-rw-r--r--drivers/iommu/tegra-smmu.c61
1 files changed, 60 insertions, 1 deletions
diff --git a/drivers/iommu/tegra-smmu.c b/drivers/iommu/tegra-smmu.c
index f0053e4de00f..ee0d123dc045 100644
--- a/drivers/iommu/tegra-smmu.c
+++ b/drivers/iommu/tegra-smmu.c
@@ -32,9 +32,11 @@
#include <linux/io.h>
#include <linux/debugfs.h>
#include <linux/seq_file.h>
+#include <linux/of_iommu.h>
#include <asm/page.h>
#include <asm/cacheflush.h>
+#include <asm/dma-iommu.h>
#include <mach/iomap.h>
#include <mach/hardware.h>
@@ -1362,13 +1364,70 @@ static struct platform_driver tegra_smmu_driver = {
},
};
+static int tegra_smmu_device_notifier(struct notifier_block *nb,
+ unsigned long event, void *_dev)
+{
+ struct dma_iommu_mapping *map = tegra_smmu_get_map();
+ struct device *dev = _dev;
+ dma_addr_t base;
+ size_t size;
+ int err;
+
+ switch (event) {
+ case BUS_NOTIFY_ADD_DEVICE:
+ err = of_get_dma_window(dev->of_node, NULL, 0, NULL, &base,
+ &size);
+ if (!err)
+ map = arm_iommu_create_mapping(&platform_bus_type,
+ base, size, 0);
+ if (IS_ERR_OR_NULL(map))
+ break;
+ if (arm_iommu_attach_device(dev, map)) {
+ arm_iommu_release_mapping(map);
+ dev_err(dev, "Failed to attach %s\n", dev_name(dev));
+ break;
+ }
+ dev_dbg(dev, "Attached %s to map %p\n", dev_name(dev), map);
+ break;
+ default:
+ break;
+ }
+ return NOTIFY_DONE;
+}
+
+static struct notifier_block tegra_smmu_device_nb = {
+ .notifier_call = tegra_smmu_device_notifier,
+};
+
static int __devinit tegra_smmu_init(void)
{
- return platform_driver_register(&tegra_smmu_driver);
+ int err;
+
+ err = platform_driver_register(&tegra_smmu_driver);
+ if (err)
+ return err;
+ if (IS_ENABLED(CONFIG_ARM_DMA_USE_IOMMU))
+ bus_register_notifier(&platform_bus_type,
+ &tegra_smmu_device_nb);
+ return 0;
+}
+
+static int tegra_smmu_remove_map(struct device *dev, void *data)
+{
+ struct dma_iommu_mapping *map = to_dma_iommu_mapping(dev);
+ if (map)
+ arm_iommu_release_mapping(map);
+ return 0;
}
static void __exit tegra_smmu_exit(void)
{
+ if (IS_ENABLED(CONFIG_ARM_DMA_USE_IOMMU)) {
+ bus_for_each_dev(&platform_bus_type, NULL, NULL,
+ tegra_smmu_remove_map);
+ bus_unregister_notifier(&platform_bus_type,
+ &tegra_smmu_device_nb);
+ }
platform_driver_unregister(&tegra_smmu_driver);
}