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

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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


[Index of Archives]     [Linux Arm (vger)]     [ARM Kernel]     [ARM MSM]     [Linux Tegra]     [Linux WPAN Networking]     [Linux Wireless Networking]     [Maemo Users]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite Trails]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux