Thread (31 messages) flat view 31 messages, 7 authors, 2011-02-24
STALE5639d

[PATCH v3 2/2] OMAP: IOMMU: add support to callback during fault handling

From: David Cohen <hidden>
Date: 2011-02-21 09:07:01
Also in: linux-omap

On Mon, Feb 21, 2011 at 10:18 AM, Hiroshi DOYU [off-list ref] wrote:
From: David Cohen <redacted>
Subject: [PATCH v3 2/2] OMAP: IOMMU: add support to callback during fault handling
Date: Wed, 16 Feb 2011 21:35:51 +0200
quoted
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 <redacted>
---
?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
quoted
? ? ? 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
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help