From patchwork Sat Feb 12 10:42:53 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: David Cohen X-Patchwork-Id: 551641 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 p1CAgwqX017488 for ; Sat, 12 Feb 2011 10:43:57 GMT Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753222Ab1BLKnS (ORCPT ); Sat, 12 Feb 2011 05:43:18 -0500 Received: from mail-ey0-f174.google.com ([209.85.215.174]:57093 "EHLO mail-ey0-f174.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1753835Ab1BLKnI (ORCPT ); Sat, 12 Feb 2011 05:43:08 -0500 Received: by eye27 with SMTP id 27so1724890eye.19 for ; Sat, 12 Feb 2011 02:43:06 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=gamma; h=domainkey-signature:from:to:cc:subject:date:message-id:x-mailer :in-reply-to:references; bh=O92XlsPic6Ki2faZQXZvfPygPXTKS77+lh+zGb2EyRk=; b=jceEG+pYF0EkKEfWcv//pChgnKndMwv0c7im6dO7Xh2OKvhUyM1yPMOOOo7Qg8bKtP ERrJ/188+8iUag/BCZaeaoow6I6UQ7Yq1jeuDqjjdZEVE9bdfzrziAWA1GG4Gl+uZ0kk fLaOUBZPinFo1MbtTULqor8c+6fT++BslNxBE= DomainKey-Signature: a=rsa-sha1; c=nofws; d=gmail.com; s=gamma; h=from:to:cc:subject:date:message-id:x-mailer:in-reply-to:references; b=ZuyxqzGMjqEaXMCDiXazbkWFljcjtBTvDIWXO1P4iFsgQypjgmkYdMvyTQuv7YMIza 1t9RWd96DYiMLPhSvhpi+VOWSVP6Yee2WIocKbsj2rLVB4QH/kHppB2iNR1uN1EuGVvm lQGdsAxCjivLbwmOmKFf1xOU1Z2FbrXMhMAkw= Received: by 10.14.17.225 with SMTP id j73mr602926eej.26.1297507386743; Sat, 12 Feb 2011 02:43:06 -0800 (PST) Received: from localhost.localdomain (a91-152-85-108.elisa-laajakaista.fi [91.152.85.108]) by mx.google.com with ESMTPS id u1sm305065eeh.10.2011.02.12.02.43.04 (version=TLSv1/SSLv3 cipher=OTHER); Sat, 12 Feb 2011 02:43:05 -0800 (PST) From: David Cohen To: Hiroshi.DOYU@nokia.com Cc: linux-omap@vger.kernel.org, David Cohen Subject: [RFC/PATCH 3/3] OMAP: IOMMU: add support to callback during fault handling Date: Sat, 12 Feb 2011 12:42:53 +0200 Message-Id: <1297507373-1520-4-git-send-email-dacohen@gmail.com> X-Mailer: git-send-email 1.7.1 In-Reply-To: <1297507373-1520-1-git-send-email-dacohen@gmail.com> References: <1297507373-1520-1-git-send-email-dacohen@gmail.com> 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]); Sat, 12 Feb 2011 10:43:57 +0000 (UTC) diff --git a/arch/arm/mach-omap2/iommu2.c b/arch/arm/mach-omap2/iommu2.c index 641f54a..d3f7871 100644 --- a/arch/arm/mach-omap2/iommu2.c +++ b/arch/arm/mach-omap2/iommu2.c @@ -143,10 +143,10 @@ static void omap2_iommu_set_twl(struct iommu *obj, bool on) __iommu_set_twl(obj, false); } -static u32 omap2_iommu_fault_isr(struct iommu *obj, u32 *ra) +static u32 omap2_iommu_fault_isr(struct iommu *obj, u32 *ra, u32 *iommu_errs) { int i; - u32 stat, da; + u32 stat, da, errs; const char *err_msg[] = { "tlb miss", "translation fault", @@ -157,8 +157,10 @@ static u32 omap2_iommu_fault_isr(struct iommu *obj, u32 *ra) stat = iommu_read_reg(obj, MMU_IRQSTATUS); stat &= MMU_IRQ_MASK; - if (!stat) + if (!stat) { + *iommu_errs = 0; return 0; + } da = iommu_read_reg(obj, MMU_FAULT_AD); *ra = da; @@ -171,6 +173,19 @@ static u32 omap2_iommu_fault_isr(struct iommu *obj, u32 *ra) } printk("\n"); + errs = 0; + 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_errs = errs; + iommu_write_reg(obj, stat, MMU_IRQSTATUS); return stat; diff --git a/arch/arm/plat-omap/include/plat/iommu.h b/arch/arm/plat-omap/include/plat/iommu.h index 71f369d..9e8c104 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 *fault_cb_priv; unsigned int refcount; struct mutex iommu_lock; /* global for this whole object */ @@ -48,6 +49,7 @@ struct iommu { struct mutex mmap_lock; /* protect mmap */ int (*isr)(struct iommu *obj); + void (*fault_cb)(struct iommu *obj, u32 da, u32 iommu_errs, void *priv); void *ctx; /* iommu context: registres saved area */ u32 da_start; @@ -83,7 +85,7 @@ struct iommu_functions { int (*enable)(struct iommu *obj); void (*disable)(struct iommu *obj); void (*set_twl)(struct iommu *obj, bool on); - u32 (*fault_isr)(struct iommu *obj, u32 *ra); + u32 (*fault_isr)(struct iommu *obj, u32 *ra, u32 *iommu_errs); void (*tlb_read_cr)(struct iommu *obj, struct cr_regs *cr); void (*tlb_load_cr)(struct iommu *obj, struct cr_regs *cr); @@ -166,6 +168,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_fault_callback(const char *name, + void (*fault_cb)(struct iommu *obj, u32 da, + u32 errs, void *priv), + void *fault_cb_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..7761eab 100644 --- a/arch/arm/plat-omap/iommu.c +++ b/arch/arm/plat-omap/iommu.c @@ -163,9 +163,9 @@ static u32 get_iopte_attr(struct iotlb_entry *e) return arch_iommu->get_pte_attr(e); } -static u32 iommu_report_fault(struct iommu *obj, u32 *da) +static u32 iommu_report_fault(struct iommu *obj, u32 *da, u32 *iommu_errs) { - return arch_iommu->fault_isr(obj, da); + return arch_iommu->fault_isr(obj, da, iommu_errs); } static void iotlb_lock_get(struct iommu *obj, struct iotlb_lock *l) @@ -780,7 +780,7 @@ static void iopgtable_clear_entry_all(struct iommu *obj) */ static irqreturn_t iommu_fault_handler(int irq, void *data) { - u32 stat, da; + u32 stat, da, errs; u32 *iopgd, *iopte; int err = -EIO; struct iommu *obj = data; @@ -796,11 +796,17 @@ static irqreturn_t iommu_fault_handler(int irq, void *data) return IRQ_HANDLED; clk_enable(obj->clk); - stat = iommu_report_fault(obj, &da); + stat = iommu_report_fault(obj, &da, &errs); clk_disable(obj->clk); if (!stat) return IRQ_HANDLED; + if (obj->fault_cb) { + obj->fault_cb(obj, da, errs, obj->fault_cb_priv); + /* No need to print error message as callback is called */ + return IRQ_NONE; + } + iommu_disable(obj); iopgd = iopgd_offset(obj, da); @@ -917,6 +923,33 @@ void iommu_put(struct iommu *obj) } EXPORT_SYMBOL_GPL(iommu_put); +int iommu_set_fault_callback(const char *name, + void (*fault_cb)(struct iommu *obj, u32 da, + u32 iommu_errs, void *priv), + void *fault_cb_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->fault_cb = fault_cb; + obj->fault_cb_priv = fault_cb_priv; + mutex_unlock(&obj->iommu_lock); + + return 0; +} +EXPORT_SYMBOL_GPL(iommu_set_fault_callback); + /* * OMAP Device MMU(IOMMU) detection */