diff options
author | Hiroshi Doyu <hdoyu@nvidia.com> | 2012-11-27 20:46:25 +0200 |
---|---|---|
committer | Harshada Kale <hkale@nvidia.com> | 2013-06-10 03:45:11 -0700 |
commit | f2994961986a91040798291187f9a2e727919fbc (patch) | |
tree | a13ed71cdd6cddd742707d2af75b43586526eadd /drivers/iommu | |
parent | b76c1c2be45810290f45f57cb974eaabc8883e43 (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.c | 61 |
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); } |