spin_unlock(&iommu_device_lock);
 }
 
+static struct iommu_param *iommu_get_dev_param(struct device *dev)
+{
+       struct iommu_param *param = dev->iommu_param;
+
+       if (param)
+               return param;
+
+       param = kzalloc(sizeof(*param), GFP_KERNEL);
+       if (!param)
+               return NULL;
+
+       mutex_init(¶m->lock);
+       dev->iommu_param = param;
+       return param;
+}
+
+static void iommu_free_dev_param(struct device *dev)
+{
+       kfree(dev->iommu_param);
+       dev->iommu_param = NULL;
+}
+
 int iommu_probe_device(struct device *dev)
 {
        const struct iommu_ops *ops = dev->bus->iommu_ops;
-       int ret = -EINVAL;
+       int ret;
 
        WARN_ON(dev->iommu_group);
+       if (!ops)
+               return -EINVAL;
 
-       if (ops)
-               ret = ops->add_device(dev);
+       if (!iommu_get_dev_param(dev))
+               return -ENOMEM;
+
+       ret = ops->add_device(dev);
+       if (ret)
+               iommu_free_dev_param(dev);
 
        return ret;
 }
 
        if (dev->iommu_group)
                ops->remove_device(dev);
+
+       iommu_free_dev_param(dev);
 }
 
 static struct iommu_domain *__iommu_domain_alloc(struct bus_type *bus,
 }
 EXPORT_SYMBOL_GPL(iommu_group_unregister_notifier);
 
+/**
+ * iommu_register_device_fault_handler() - Register a device fault handler
+ * @dev: the device
+ * @handler: the fault handler
+ * @data: private data passed as argument to the handler
+ *
+ * When an IOMMU fault event is received, this handler gets called with the
+ * fault event and data as argument. The handler should return 0 on success.
+ *
+ * Return 0 if the fault handler was installed successfully, or an error.
+ */
+int iommu_register_device_fault_handler(struct device *dev,
+                                       iommu_dev_fault_handler_t handler,
+                                       void *data)
+{
+       struct iommu_param *param = dev->iommu_param;
+       int ret = 0;
+
+       if (!param)
+               return -EINVAL;
+
+       mutex_lock(¶m->lock);
+       /* Only allow one fault handler registered for each device */
+       if (param->fault_param) {
+               ret = -EBUSY;
+               goto done_unlock;
+       }
+
+       get_device(dev);
+       param->fault_param = kzalloc(sizeof(*param->fault_param), GFP_KERNEL);
+       if (!param->fault_param) {
+               put_device(dev);
+               ret = -ENOMEM;
+               goto done_unlock;
+       }
+       param->fault_param->handler = handler;
+       param->fault_param->data = data;
+
+done_unlock:
+       mutex_unlock(¶m->lock);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(iommu_register_device_fault_handler);
+
+/**
+ * iommu_unregister_device_fault_handler() - Unregister the device fault handler
+ * @dev: the device
+ *
+ * Remove the device fault handler installed with
+ * iommu_register_device_fault_handler().
+ *
+ * Return 0 on success, or an error.
+ */
+int iommu_unregister_device_fault_handler(struct device *dev)
+{
+       struct iommu_param *param = dev->iommu_param;
+       int ret = 0;
+
+       if (!param)
+               return -EINVAL;
+
+       mutex_lock(¶m->lock);
+
+       if (!param->fault_param)
+               goto unlock;
+
+       kfree(param->fault_param);
+       param->fault_param = NULL;
+       put_device(dev);
+unlock:
+       mutex_unlock(¶m->lock);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(iommu_unregister_device_fault_handler);
+
+/**
+ * iommu_report_device_fault() - Report fault event to device driver
+ * @dev: the device
+ * @evt: fault event data
+ *
+ * Called by IOMMU drivers when a fault is detected, typically in a threaded IRQ
+ * handler.
+ *
+ * Return 0 on success, or an error.
+ */
+int iommu_report_device_fault(struct device *dev, struct iommu_fault_event *evt)
+{
+       struct iommu_param *param = dev->iommu_param;
+       struct iommu_fault_param *fparam;
+       int ret = 0;
+
+       if (!param || !evt)
+               return -EINVAL;
+
+       /* we only report device fault if there is a handler registered */
+       mutex_lock(¶m->lock);
+       fparam = param->fault_param;
+       if (!fparam || !fparam->handler) {
+               ret = -EINVAL;
+               goto done_unlock;
+       }
+       ret = fparam->handler(&evt->fault, fparam->data);
+done_unlock:
+       mutex_unlock(¶m->lock);
+       return ret;
+}
+EXPORT_SYMBOL_GPL(iommu_report_device_fault);
+
 /**
  * iommu_group_id - Return ID for a group
  * @group: the group to ID
 
  *     struct iommu_fwspec     *iommu_fwspec;
  */
 struct iommu_param {
+       struct mutex lock;
        struct iommu_fault_param *fault_param;
 };
 
                                         struct notifier_block *nb);
 extern int iommu_group_unregister_notifier(struct iommu_group *group,
                                           struct notifier_block *nb);
+extern int iommu_register_device_fault_handler(struct device *dev,
+                                       iommu_dev_fault_handler_t handler,
+                                       void *data);
+
+extern int iommu_unregister_device_fault_handler(struct device *dev);
+
+extern int iommu_report_device_fault(struct device *dev,
+                                    struct iommu_fault_event *evt);
+
 extern int iommu_group_id(struct iommu_group *group);
 extern struct iommu_group *iommu_group_get_for_dev(struct device *dev);
 extern struct iommu_domain *iommu_group_default_domain(struct iommu_group *);
        return 0;
 }
 
+static inline
+int iommu_register_device_fault_handler(struct device *dev,
+                                       iommu_dev_fault_handler_t handler,
+                                       void *data)
+{
+       return -ENODEV;
+}
+
+static inline int iommu_unregister_device_fault_handler(struct device *dev)
+{
+       return 0;
+}
+
+static inline
+int iommu_report_device_fault(struct device *dev, struct iommu_fault_event *evt)
+{
+       return -ENODEV;
+}
+
 static inline int iommu_group_id(struct iommu_group *group)
 {
        return -ENODEV;