On Mon, Feb 21, 2011 at 10:18 AM, Hiroshi DOYU <Hiroshi.DOYU@xxxxxxxxx> wrote: > From: David Cohen <dacohen@xxxxxxxxx> > Subject: [PATCH v3 2/2] OMAP: IOMMU: add support to callback during fault handling > Date: Wed, 16 Feb 2011 21:35:51 +0200 > >> Add support to register an isr for IOMMU fault situations and adapt it >> to allow such (*isr)() to be used as fault callback. Drivers using IOMMU >> module might want to be informed when errors happen in order to debug it >> or react. >> >> Signed-off-by: David Cohen <dacohen@xxxxxxxxx> >> --- >> Âarch/arm/mach-omap2/iommu2.c      Â|  17 +++++++++- >> Âarch/arm/plat-omap/include/plat/iommu.h |  14 ++++++++- >> Âarch/arm/plat-omap/iommu.c       Â|  52 ++++++++++++++++++++++--------- >> Â3 files changed, 65 insertions(+), 18 deletions(-) >> >> diff --git a/arch/arm/mach-omap2/iommu2.c b/arch/arm/mach-omap2/iommu2.c >> index 49a1e5e..adb083e 100644 >> --- a/arch/arm/mach-omap2/iommu2.c >> +++ b/arch/arm/mach-omap2/iommu2.c >> @@ -146,18 +146,31 @@ static void omap2_iommu_set_twl(struct iommu *obj, bool on) >> Âstatic u32 omap2_iommu_fault_isr(struct iommu *obj, u32 *ra) >> Â{ >>    u32 stat, da; >> +   u32 errs = 0; >> >>    stat = iommu_read_reg(obj, MMU_IRQSTATUS); >>    stat &= MMU_IRQ_MASK; >> -   if (!stat) >> +   if (!stat) { >> +       *ra = 0; >>        return 0; >> +   } >> >>    da = iommu_read_reg(obj, MMU_FAULT_AD); >>    *ra = da; >> >> +   if (stat & MMU_IRQ_TLBMISS) >> +       errs |= OMAP_IOMMU_ERR_TLB_MISS; >> +   if (stat & MMU_IRQ_TRANSLATIONFAULT) >> +       errs |= OMAP_IOMMU_ERR_TRANS_FAULT; >> +   if (stat & MMU_IRQ_EMUMISS) >> +       errs |= OMAP_IOMMU_ERR_EMU_MISS; >> +   if (stat & MMU_IRQ_TABLEWALKFAULT) >> +       errs |= OMAP_IOMMU_ERR_TBLWALK_FAULT; >> +   if (stat & MMU_IRQ_MULTIHITFAULT) >> +       errs |= OMAP_IOMMU_ERR_MULTIHIT_FAULT; >>    iommu_write_reg(obj, stat, MMU_IRQSTATUS); >> >> -   return stat; >> +   return errs; >> Â} >> >> Âstatic void omap2_tlb_read_cr(struct iommu *obj, struct cr_regs *cr) >> diff --git a/arch/arm/plat-omap/include/plat/iommu.h b/arch/arm/plat-omap/include/plat/iommu.h >> index 19cbb5e..174f1b9 100644 >> --- a/arch/arm/plat-omap/include/plat/iommu.h >> +++ b/arch/arm/plat-omap/include/plat/iommu.h >> @@ -31,6 +31,7 @@ struct iommu { >>    struct clk   Â*clk; >>    void __iomem  Â*regbase; >>    struct device  *dev; >> +   void      Â*isr_priv; > > Ideally I'd like to avoid having "isr_priv" in iommu since it's not > used for iommu but client needs the place to pass its info to its > custom handler. Any better idea? (*isr)() relies in the same situation, as it belongs to the client. Without this priv_data, it's necessary to create a global variable to store client's private data on client side. IMO, it is worse. Br, David > > >>    unsigned int  Ârefcount; >>    struct mutex  Âiommu_lock;   /* global for this whole object */ >> @@ -47,7 +48,7 @@ struct iommu { >>    struct list_head    Âmmap; >>    struct mutex      Âmmap_lock; /* protect mmap */ >> >> -   int (*isr)(struct iommu *obj); >> +   int (*isr)(struct iommu *obj, u32 da, u32 iommu_errs, void *priv); >> >>    void *ctx; /* iommu context: registres saved area */ >>    u32 da_start; >> @@ -109,6 +110,13 @@ struct iommu_platform_data { >>    u32 da_end; >> Â}; >> >> +/* IOMMU errors */ >> +#define OMAP_IOMMU_ERR_TLB_MISS       Â(1 << 0) >> +#define OMAP_IOMMU_ERR_TRANS_FAULT  (1 << 1) >> +#define OMAP_IOMMU_ERR_EMU_MISS       Â(1 << 2) >> +#define OMAP_IOMMU_ERR_TBLWALK_FAULT (1 << 3) >> +#define OMAP_IOMMU_ERR_MULTIHIT_FAULT    Â(1 << 4) >> + >> Â#if defined(CONFIG_ARCH_OMAP1) >> Â#error "iommu for this processor not implemented yet" >> Â#else >> @@ -161,6 +169,10 @@ extern size_t iopgtable_clear_entry(struct iommu *obj, u32 iova); >> Âextern int iommu_set_da_range(struct iommu *obj, u32 start, u32 end); >> Âextern struct iommu *iommu_get(const char *name); >> Âextern void iommu_put(struct iommu *obj); >> +extern int iommu_set_isr(const char *name, >> +           Âint (*isr)(struct iommu *obj, u32 da, u32 iommu_errs, >> +                 void *priv), >> +           Âvoid *isr_priv); >> >> Âextern void iommu_save_ctx(struct iommu *obj); >> Âextern void iommu_restore_ctx(struct iommu *obj); >> diff --git a/arch/arm/plat-omap/iommu.c b/arch/arm/plat-omap/iommu.c >> index f55f458..b0e0efc 100644 >> --- a/arch/arm/plat-omap/iommu.c >> +++ b/arch/arm/plat-omap/iommu.c >> @@ -780,25 +780,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 +800,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", obj->name, >> -           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", >> -       obj->name, 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 +912,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 >>  */ >> -- >> 1.7.2.3 >> > -- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html