From patchwork Wed Feb 16 19:35:51 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: David Cohen X-Patchwork-Id: 568221 X-Patchwork-Delegate: tony@atomide.com Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by demeter1.kernel.org (8.14.4/8.14.3) with ESMTP id p1GJTRmq021161 for ; Wed, 16 Feb 2011 19:31:57 GMT Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751370Ab1BPTbk (ORCPT ); Wed, 16 Feb 2011 14:31:40 -0500 Received: from smtp.nokia.com ([147.243.128.24]:60931 "EHLO mgw-da01.nokia.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751331Ab1BPTbj (ORCPT ); Wed, 16 Feb 2011 14:31:39 -0500 Received: from nokia.com (localhost [127.0.0.1]) by mgw-da01.nokia.com (Switch-3.4.3/Switch-3.4.3) with ESMTP id p1GJVDMM017045; Wed, 16 Feb 2011 21:31:13 +0200 Received: from esdhcp04381.research.nokia.com ([esdhcp040180.research.nokia.com [172.21.40.180]]) by mgw-da01.nokia.com with ESMTP id p1GJUdGs016360 ; Wed, 16 Feb 2011 21:30:46 +0200 From: David Cohen To: hiroshi.doyu@nokia.com Cc: linux-omap@vger.kernel.org, linux-arm-kernel@lists.infradead.org, tony@atomide.com Subject: [PATCH v3 2/2] OMAP: IOMMU: add support to callback during fault handling Date: Wed, 16 Feb 2011 21:35:51 +0200 Message-Id: <1297884951-3019-3-git-send-email-dacohen@gmail.com> X-Mailer: git-send-email 1.7.2.3 In-Reply-To: <1297884951-3019-1-git-send-email-dacohen@gmail.com> References: <1297884951-3019-1-git-send-email-dacohen@gmail.com> X-Nokia-AV: Clean Sender: linux-omap-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-omap@vger.kernel.org X-Greylist: IP, sender and recipient auto-whitelisted, not delayed by milter-greylist-4.2.6 (demeter1.kernel.org [140.211.167.41]); Wed, 16 Feb 2011 19:31:57 +0000 (UTC) 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; 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 */