]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blobdiff - drivers/iommu/iommu.c
Merge branches 'arm/exynos', 'arm/omap', 'arm/rockchip', 'arm/mediatek', 'arm/smmu...
[mirror_ubuntu-artful-kernel.git] / drivers / iommu / iommu.c
index 3b67144dead2e3811918af8fa44ec6e67a19c955..cf7ca7e70777d6498f751fac98bc29fef9ba8ce6 100644 (file)
@@ -36,6 +36,7 @@
 
 static struct kset *iommu_group_kset;
 static DEFINE_IDA(iommu_group_ida);
+static unsigned int iommu_def_domain_type = IOMMU_DOMAIN_DMA;
 
 struct iommu_callback_data {
        const struct iommu_ops *ops;
@@ -112,6 +113,18 @@ static int __iommu_attach_group(struct iommu_domain *domain,
 static void __iommu_detach_group(struct iommu_domain *domain,
                                 struct iommu_group *group);
 
+static int __init iommu_set_def_domain_type(char *str)
+{
+       bool pt;
+
+       if (!str || strtobool(str, &pt))
+               return -EINVAL;
+
+       iommu_def_domain_type = pt ? IOMMU_DOMAIN_IDENTITY : IOMMU_DOMAIN_DMA;
+       return 0;
+}
+early_param("iommu.passthrough", iommu_set_def_domain_type);
+
 static ssize_t iommu_group_attr_show(struct kobject *kobj,
                                     struct attribute *__attr, char *buf)
 {
@@ -1015,10 +1028,19 @@ struct iommu_group *iommu_group_get_for_dev(struct device *dev)
         * IOMMU driver.
         */
        if (!group->default_domain) {
-               group->default_domain = __iommu_domain_alloc(dev->bus,
-                                                            IOMMU_DOMAIN_DMA);
+               struct iommu_domain *dom;
+
+               dom = __iommu_domain_alloc(dev->bus, iommu_def_domain_type);
+               if (!dom && iommu_def_domain_type != IOMMU_DOMAIN_DMA) {
+                       dev_warn(dev,
+                                "failed to allocate default IOMMU domain of type %u; falling back to IOMMU_DOMAIN_DMA",
+                                iommu_def_domain_type);
+                       dom = __iommu_domain_alloc(dev->bus, IOMMU_DOMAIN_DMA);
+               }
+
+               group->default_domain = dom;
                if (!group->domain)
-                       group->domain = group->default_domain;
+                       group->domain = dom;
        }
 
        ret = iommu_group_add_device(group, dev);
@@ -1083,8 +1105,12 @@ static int iommu_bus_notifier(struct notifier_block *nb,
         * result in ADD/DEL notifiers to group->notifier
         */
        if (action == BUS_NOTIFY_ADD_DEVICE) {
-               if (ops->add_device)
-                       return ops->add_device(dev);
+               if (ops->add_device) {
+                       int ret;
+
+                       ret = ops->add_device(dev);
+                       return (ret) ? NOTIFY_DONE : NOTIFY_OK;
+               }
        } else if (action == BUS_NOTIFY_REMOVED_DEVICE) {
                if (ops->remove_device && dev->iommu_group) {
                        ops->remove_device(dev);
@@ -1652,6 +1678,48 @@ void iommu_domain_window_disable(struct iommu_domain *domain, u32 wnd_nr)
 }
 EXPORT_SYMBOL_GPL(iommu_domain_window_disable);
 
+/**
+ * report_iommu_fault() - report about an IOMMU fault to the IOMMU framework
+ * @domain: the iommu domain where the fault has happened
+ * @dev: the device where the fault has happened
+ * @iova: the faulting address
+ * @flags: mmu fault flags (e.g. IOMMU_FAULT_READ/IOMMU_FAULT_WRITE/...)
+ *
+ * This function should be called by the low-level IOMMU implementations
+ * whenever IOMMU faults happen, to allow high-level users, that are
+ * interested in such events, to know about them.
+ *
+ * This event may be useful for several possible use cases:
+ * - mere logging of the event
+ * - dynamic TLB/PTE loading
+ * - if restarting of the faulting device is required
+ *
+ * Returns 0 on success and an appropriate error code otherwise (if dynamic
+ * PTE/TLB loading will one day be supported, implementations will be able
+ * to tell whether it succeeded or not according to this return value).
+ *
+ * Specifically, -ENOSYS is returned if a fault handler isn't installed
+ * (though fault handlers can also return -ENOSYS, in case they want to
+ * elicit the default behavior of the IOMMU drivers).
+ */
+int report_iommu_fault(struct iommu_domain *domain, struct device *dev,
+                      unsigned long iova, int flags)
+{
+       int ret = -ENOSYS;
+
+       /*
+        * if upper layers showed interest and installed a fault handler,
+        * invoke it.
+        */
+       if (domain->handler)
+               ret = domain->handler(domain, dev, iova, flags,
+                                               domain->handler_token);
+
+       trace_io_page_fault(dev, iova, flags);
+       return ret;
+}
+EXPORT_SYMBOL_GPL(report_iommu_fault);
+
 static int __init iommu_init(void)
 {
        iommu_group_kset = kset_create_and_add("iommu_groups",