diff options
author | Hari Kanigeri <h-kanigeri2@ti.com> | 2010-10-04 11:06:59 -0500 |
---|---|---|
committer | Ricardo Perez Olivares <x0081762@ti.com> | 2010-10-06 12:39:54 -0500 |
commit | 9152c0999526b6df55df3b7d6a11583dd24c3281 (patch) | |
tree | f6178caca3f3477e26282db346b8372ec962ebc9 /arch | |
parent | f6317a75f3841ece523c9a5a300314f6f5a111ee (diff) |
omap:iommu-event notification shouldn't be blocking call
iommu_notify_event function is called from interrupt context, and this
function is using internally blocking_notifier_call_chain call that could
sleep.
The fix is changing blocking_notifier to raw_notifier and let the callers
of the iommu_notify_event handle the protection.
iommu_notify_event is used for 2 purposes. One is for MMU FAULT notification
to the device handler where the devh sets the error state to Fault and prevents
the broadcasting of any iommu close notifications. This shouldn't be blocking.
Second, it is used to broadcast the notifications of the Process ID that closed
the iommu handle to remote processor. This could be blocking.
Reported by Hari Nagalla
Signed-off-by: Hari Kanigeri <h-kanigeri2@ti.com>
Signed-off-by: Hari Nagalla <hnagalla@ti.com>
Diffstat (limited to 'arch')
-rw-r--r-- | arch/arm/plat-omap/dmm_user.c | 10 | ||||
-rw-r--r-- | arch/arm/plat-omap/include/plat/iommu.h | 2 | ||||
-rw-r--r-- | arch/arm/plat-omap/iommu.c | 11 |
3 files changed, 16 insertions, 7 deletions
diff --git a/arch/arm/plat-omap/dmm_user.c b/arch/arm/plat-omap/dmm_user.c index 30f8bedee140..3afa28db3d2d 100644 --- a/arch/arm/plat-omap/dmm_user.c +++ b/arch/arm/plat-omap/dmm_user.c @@ -244,7 +244,15 @@ static int omap_dmm_release(struct inode *inode, struct file *filp) } obj = filp->private_data; flush_signals(current); - iommu_notify_event(obj->iovmm->iommu, IOMMU_CLOSE, NULL); + + status = mutex_lock_interruptible(&obj->iovmm->dmm_map_lock); + if (status == 0) { + iommu_notify_event(obj->iovmm->iommu, IOMMU_CLOSE, NULL); + mutex_unlock(&obj->iovmm->dmm_map_lock); + } else { + pr_err("%s mutex_lock_interruptible returned 0x%x\n", + __func__, status); + } user_remove_resources(obj); iommu_put(obj->iovmm->iommu); kfree(obj); diff --git a/arch/arm/plat-omap/include/plat/iommu.h b/arch/arm/plat-omap/include/plat/iommu.h index 2d949d4947d1..80311a1684fd 100644 --- a/arch/arm/plat-omap/include/plat/iommu.h +++ b/arch/arm/plat-omap/include/plat/iommu.h @@ -46,7 +46,7 @@ struct iommu { struct list_head mmap; struct mutex mmap_lock; /* protect mmap */ - struct blocking_notifier_head notifier; + struct raw_notifier_head notifier; struct iotlb_entry *tlbs_e;/* iommu tlbs context: saved area */ diff --git a/arch/arm/plat-omap/iommu.c b/arch/arm/plat-omap/iommu.c index d5deb3e60007..d728af8aec6b 100644 --- a/arch/arm/plat-omap/iommu.c +++ b/arch/arm/plat-omap/iommu.c @@ -827,15 +827,16 @@ void eventfd_notification(struct iommu *obj) eventfd_signal(fd_reg->evt_ctx, 1); } -int iommu_notify_event(struct iommu *obj, int event, void *data) { - return blocking_notifier_call_chain(&obj->notifier, event, data); +int iommu_notify_event(struct iommu *obj, int event, void *data) +{ + return raw_notifier_call_chain(&obj->notifier, event, data); } int iommu_register_notifier(struct iommu *obj, struct notifier_block *nb) { if (!nb) return -EINVAL; - return blocking_notifier_chain_register(&obj->notifier, nb); + return raw_notifier_chain_register(&obj->notifier, nb); } EXPORT_SYMBOL_GPL(iommu_register_notifier); @@ -843,7 +844,7 @@ int iommu_unregister_notifier(struct iommu *obj, struct notifier_block *nb) { if (!nb) return -EINVAL; - return blocking_notifier_chain_unregister(&obj->notifier, nb); + return raw_notifier_chain_unregister(&obj->notifier, nb); } EXPORT_SYMBOL_GPL(iommu_unregister_notifier); @@ -995,7 +996,7 @@ static int __devinit omap_iommu_probe(struct platform_device *pdev) INIT_LIST_HEAD(&obj->event_list); obj->regbase = pdata->io_base; - BLOCKING_INIT_NOTIFIER_HEAD(&obj->notifier); + RAW_INIT_NOTIFIER_HEAD(&obj->notifier); err = request_irq(pdata->irq, iommu_fault_handler, IRQF_SHARED, dev_name(&pdev->dev), obj); |