Merge tag 'microblaze-3.15-rc1' of git://git.monstr.eu/linux-2.6-microblaze
[cascardo/linux.git] / drivers / iommu / omap-iommu.c
index eb73ef2..7fcbfc4 100644 (file)
@@ -520,7 +520,8 @@ static void flush_iopte_range(u32 *first, u32 *last)
 static void iopte_free(u32 *iopte)
 {
        /* Note: freed iopte's must be clean ready for re-use */
-       kmem_cache_free(iopte_cachep, iopte);
+       if (iopte)
+               kmem_cache_free(iopte_cachep, iopte);
 }
 
 static u32 *iopte_alloc(struct omap_iommu *obj, u32 *iopgd, u32 da)
@@ -961,6 +962,8 @@ static int omap_iommu_probe(struct platform_device *pdev)
                 */
                obj->da_start = 0;
                obj->da_end = 0xfffff000;
+               if (of_find_property(of, "ti,iommu-bus-err-back", NULL))
+                       obj->has_bus_err_back = MMU_GP_REG_BUS_ERR_BACK_EN;
        } else {
                obj->nr_tlb_entries = pdata->nr_tlb_entries;
                obj->name = pdata->name;
@@ -1251,6 +1254,49 @@ static int omap_iommu_domain_has_cap(struct iommu_domain *domain,
        return 0;
 }
 
+static int omap_iommu_add_device(struct device *dev)
+{
+       struct omap_iommu_arch_data *arch_data;
+       struct device_node *np;
+
+       /*
+        * Allocate the archdata iommu structure for DT-based devices.
+        *
+        * TODO: Simplify this when removing non-DT support completely from the
+        * IOMMU users.
+        */
+       if (!dev->of_node)
+               return 0;
+
+       np = of_parse_phandle(dev->of_node, "iommus", 0);
+       if (!np)
+               return 0;
+
+       arch_data = kzalloc(sizeof(*arch_data), GFP_KERNEL);
+       if (!arch_data) {
+               of_node_put(np);
+               return -ENOMEM;
+       }
+
+       arch_data->name = kstrdup(dev_name(dev), GFP_KERNEL);
+       dev->archdata.iommu = arch_data;
+
+       of_node_put(np);
+
+       return 0;
+}
+
+static void omap_iommu_remove_device(struct device *dev)
+{
+       struct omap_iommu_arch_data *arch_data = dev->archdata.iommu;
+
+       if (!dev->of_node || !arch_data)
+               return;
+
+       kfree(arch_data->name);
+       kfree(arch_data);
+}
+
 static struct iommu_ops omap_iommu_ops = {
        .domain_init    = omap_iommu_domain_init,
        .domain_destroy = omap_iommu_domain_destroy,
@@ -1260,6 +1306,8 @@ static struct iommu_ops omap_iommu_ops = {
        .unmap          = omap_iommu_unmap,
        .iova_to_phys   = omap_iommu_iova_to_phys,
        .domain_has_cap = omap_iommu_domain_has_cap,
+       .add_device     = omap_iommu_add_device,
+       .remove_device  = omap_iommu_remove_device,
        .pgsize_bitmap  = OMAP_IOMMU_PGSIZES,
 };