Merge branches 'irq-fixes-for-linus' and 'sched-fixes-for-linus' of git://git.kernel...
[cascardo/linux.git] / arch / arm / plat-omap / iommu.c
index b1107c0..8a51fd5 100644 (file)
@@ -104,6 +104,9 @@ static int iommu_enable(struct iommu *obj)
        if (!obj)
                return -EINVAL;
 
+       if (!arch_iommu)
+               return -ENODEV;
+
        clk_enable(obj->clk);
 
        err = arch_iommu->enable(obj);
@@ -780,25 +783,19 @@ static void iopgtable_clear_entry_all(struct iommu *obj)
  */
 static irqreturn_t iommu_fault_handler(int irq, void *data)
 {
-       u32 stat, da;
+       u32 da, errs;
        u32 *iopgd, *iopte;
-       int err = -EIO;
        struct iommu *obj = data;
 
        if (!obj->refcount)
                return IRQ_NONE;
 
-       /* Dynamic loading TLB or PTE */
-       if (obj->isr)
-               err = obj->isr(obj);
-
-       if (!err)
-               return IRQ_HANDLED;
-
        clk_enable(obj->clk);
-       stat = iommu_report_fault(obj, &da);
+       errs = iommu_report_fault(obj, &da);
        clk_disable(obj->clk);
-       if (!stat)
+
+       /* Fault callback or TLB/PTE Dynamic loading */
+       if (obj->isr && !obj->isr(obj, da, errs, obj->isr_priv))
                return IRQ_HANDLED;
 
        iommu_disable(obj);
@@ -806,15 +803,16 @@ static irqreturn_t iommu_fault_handler(int irq, void *data)
        iopgd = iopgd_offset(obj, da);
 
        if (!iopgd_is_table(*iopgd)) {
-               dev_err(obj->dev, "%s: da:%08x pgd:%p *pgd:%08x\n", __func__,
-                       da, iopgd, *iopgd);
+               dev_err(obj->dev, "%s: errs:0x%08x da:0x%08x pgd:0x%p "
+                       "*pgd:px%08x\n", obj->name, errs, da, iopgd, *iopgd);
                return IRQ_NONE;
        }
 
        iopte = iopte_offset(iopgd, da);
 
-       dev_err(obj->dev, "%s: da:%08x pgd:%p *pgd:%08x pte:%p *pte:%08x\n",
-               __func__, da, iopgd, *iopgd, iopte, *iopte);
+       dev_err(obj->dev, "%s: errs:0x%08x da:0x%08x pgd:0x%p *pgd:0x%08x "
+               "pte:0x%p *pte:0x%08x\n", obj->name, errs, da, iopgd, *iopgd,
+               iopte, *iopte);
 
        return IRQ_NONE;
 }
@@ -917,6 +915,33 @@ void iommu_put(struct iommu *obj)
 }
 EXPORT_SYMBOL_GPL(iommu_put);
 
+int iommu_set_isr(const char *name,
+                 int (*isr)(struct iommu *obj, u32 da, u32 iommu_errs,
+                            void *priv),
+                 void *isr_priv)
+{
+       struct device *dev;
+       struct iommu *obj;
+
+       dev = driver_find_device(&omap_iommu_driver.driver, NULL, (void *)name,
+                                device_match_by_alias);
+       if (!dev)
+               return -ENODEV;
+
+       obj = to_iommu(dev);
+       mutex_lock(&obj->iommu_lock);
+       if (obj->refcount != 0) {
+               mutex_unlock(&obj->iommu_lock);
+               return -EBUSY;
+       }
+       obj->isr = isr;
+       obj->isr_priv = isr_priv;
+       mutex_unlock(&obj->iommu_lock);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(iommu_set_isr);
+
 /*
  *     OMAP Device MMU(IOMMU) detection
  */
@@ -957,11 +982,6 @@ static int __devinit omap_iommu_probe(struct platform_device *pdev)
                err = -ENODEV;
                goto err_mem;
        }
-       obj->regbase = ioremap(res->start, resource_size(res));
-       if (!obj->regbase) {
-               err = -ENOMEM;
-               goto err_mem;
-       }
 
        res = request_mem_region(res->start, resource_size(res),
                                 dev_name(&pdev->dev));
@@ -970,6 +990,12 @@ static int __devinit omap_iommu_probe(struct platform_device *pdev)
                goto err_mem;
        }
 
+       obj->regbase = ioremap(res->start, resource_size(res));
+       if (!obj->regbase) {
+               err = -ENOMEM;
+               goto err_ioremap;
+       }
+
        irq = platform_get_irq(pdev, 0);
        if (irq < 0) {
                err = -ENODEV;
@@ -998,8 +1024,9 @@ static int __devinit omap_iommu_probe(struct platform_device *pdev)
 err_pgd:
        free_irq(irq, obj);
 err_irq:
-       release_mem_region(res->start, resource_size(res));
        iounmap(obj->regbase);
+err_ioremap:
+       release_mem_region(res->start, resource_size(res));
 err_mem:
        clk_put(obj->clk);
 err_clk: