* - Give permission to the guest to manage IRQ and MMIO range
* - Retrieve the IRQ configuration (i.e edge/level) from device tree
* When the device is not marked for guest passthrough:
+ * - Try to call iommu_add_dt_device to protect the device by an IOMMU
* - Assign the device to the guest if it's protected by an IOMMU
* - Map the IRQs and iomem regions to DOM0
*/
dt_dprintk("%s passthrough = %d nirq = %d naddr = %u\n",
dt_node_full_name(dev), need_mapping, nirq, naddr);
- if ( dt_device_is_protected(dev) && need_mapping )
+ if ( need_mapping )
{
- dt_dprintk("%s setup iommu\n", dt_node_full_name(dev));
- res = iommu_assign_dt_device(d, dev);
- if ( res )
+ dt_dprintk("Check if %s is behind the IOMMU and add it\n",
+ dt_node_full_name(dev));
+
+ res = iommu_add_dt_device(dev);
+ if ( res < 0 )
{
- printk(XENLOG_ERR "Failed to setup the IOMMU for %s\n",
+ printk(XENLOG_ERR "Failed to add %s to the IOMMU\n",
dt_node_full_name(dev));
return res;
}
+
+ if ( dt_device_is_protected(dev) )
+ {
+ dt_dprintk("%s setup iommu\n", dt_node_full_name(dev));
+ res = iommu_assign_dt_device(d, dev);
+ if ( res )
+ {
+ printk(XENLOG_ERR "Failed to setup the IOMMU for %s\n",
+ dt_node_full_name(dev));
+ return res;
+ }
+ }
}
/* Give permission and map IRQs */
#include <xen/sched.h>
#include <xsm/xsm.h>
+#include <asm/iommu_fwspec.h>
+
static spinlock_t dtdevs_lock = SPIN_LOCK_UNLOCKED;
int iommu_assign_dt_device(struct domain *d, struct dt_device_node *dev)
return 0;
}
+int iommu_add_dt_device(struct dt_device_node *np)
+{
+ const struct iommu_ops *ops = iommu_get_ops();
+ struct dt_phandle_args iommu_spec;
+ struct device *dev = dt_to_dev(np);
+ int rc = 1, index = 0;
+
+ if ( !iommu_enabled )
+ return 1;
+
+ if ( !ops )
+ return -EINVAL;
+
+ if ( dev_iommu_fwspec_get(dev) )
+ return -EEXIST;
+
+ /*
+ * According to the Documentation/devicetree/bindings/iommu/iommu.txt
+ * from Linux.
+ */
+ while ( !dt_parse_phandle_with_args(np, "iommus", "#iommu-cells",
+ index, &iommu_spec) )
+ {
+ /*
+ * The driver which supports generic IOMMU DT bindings must have
+ * these callback implemented.
+ */
+ if ( !ops->add_device || !ops->dt_xlate )
+ return -EINVAL;
+
+ if ( !dt_device_is_available(iommu_spec.np) )
+ break;
+
+ rc = iommu_fwspec_init(dev, &iommu_spec.np->dev);
+ if ( rc )
+ break;
+
+ /*
+ * Provide DT IOMMU specifier which describes the IOMMU master
+ * interfaces of that device (device IDs, etc) to the driver.
+ * The driver is responsible to decide how to interpret them.
+ */
+ rc = ops->dt_xlate(dev, &iommu_spec);
+ if ( rc )
+ break;
+
+ index++;
+ }
+
+ /*
+ * Add master device to the IOMMU if latter is present and available.
+ * The driver is responsible to mark that device as protected.
+ */
+ if ( !rc )
+ rc = ops->add_device(0, dev);
+
+ if ( rc < 0 )
+ iommu_fwspec_free(dev);
+
+ return rc;
+}
+
int iommu_do_dt_domctl(struct xen_domctl *domctl, struct domain *d,
XEN_GUEST_HANDLE_PARAM(xen_domctl_t) u_domctl)
{
break;
}
+ ret = iommu_add_dt_device(dev);
+ /*
+ * Ignore "-EEXIST" error code as it would mean that the device is
+ * already added to the IOMMU (positive result). Such happens after
+ * re-creating guest domain.
+ */
+ if ( ret < 0 && ret != -EEXIST )
+ {
+ printk(XENLOG_G_ERR "Failed to add %s to the IOMMU\n",
+ dt_node_full_name(dev));
+ break;
+ }
+
ret = iommu_assign_dt_device(d, dev);
if ( ret )
int iommu_dt_domain_init(struct domain *d);
int iommu_release_dt_devices(struct domain *d);
+/*
+ * Helper to add master device to the IOMMU using generic IOMMU DT bindings.
+ *
+ * Return values:
+ * 0 : device is protected by an IOMMU
+ * <0 : device is not protected by an IOMMU, but must be (error condition)
+ * >0 : device doesn't need to be protected by an IOMMU
+ * (IOMMU is not enabled/present or device is not connected to it).
+ */
+int iommu_add_dt_device(struct dt_device_node *np);
+
int iommu_do_dt_domctl(struct xen_domctl *, struct domain *,
XEN_GUEST_HANDLE_PARAM(xen_domctl_t));
int __must_check (*iotlb_flush_all)(struct domain *d);
int (*get_reserved_device_memory)(iommu_grdm_t *, void *);
void (*dump_p2m_table)(struct domain *d);
+
+#ifdef CONFIG_HAS_DEVICE_TREE
+ /*
+ * All IOMMU drivers which support generic IOMMU DT bindings should use
+ * this callback. This is a way for the framework to provide the driver
+ * with DT IOMMU specifier which describes the IOMMU master interfaces of
+ * that device (device IDs, etc).
+ */
+ int (*dt_xlate)(device_t *dev, const struct dt_phandle_args *args);
+#endif
};
#include <asm/iommu.h>