diff mbox

[Xen-devel,v3,08/13] xen/passthrough: iommu: Basic support of device tree assignment

Message ID 1394552999-14171-9-git-send-email-julien.grall@linaro.org
State Superseded, archived
Headers show

Commit Message

Julien Grall March 11, 2014, 3:49 p.m. UTC
Add IOMMU helpers to support device tree assignment/deassignment. This patch
introduces 2 new fields in the dt_device_node:
    - is_protected: Does the device is protected by an IOMMU
    - next_assigned: Pointer to the next device assigned to the same
    domain

Signed-off-by: Julien Grall <julien.grall@linaro.org>
Cc: Xiantao Zhang <xiantao.zhang@intel.com>
Cc: Jan Beulich <jbeulich@suse.com>

---
    Changes in v3:
        - Remove iommu_dt_domain_{init,destroy} call in common code. Let
        architecture code to call them
        - Fix indentation in xen/include/xen/hvm/iommu.h
    Changes in v2:
        - Patch added
---
 xen/common/device_tree.c              |    4 ++
 xen/drivers/passthrough/Makefile      |    1 +
 xen/drivers/passthrough/device_tree.c |  106 +++++++++++++++++++++++++++++++++
 xen/include/xen/device_tree.h         |   14 +++++
 xen/include/xen/hvm/iommu.h           |    6 ++
 xen/include/xen/iommu.h               |   16 +++++
 6 files changed, 147 insertions(+)
 create mode 100644 xen/drivers/passthrough/device_tree.c

Comments

Jan Beulich March 11, 2014, 4:55 p.m. UTC | #1
>>> On 11.03.14 at 16:49, Julien Grall <julien.grall@linaro.org> wrote:
> Add IOMMU helpers to support device tree assignment/deassignment. This patch
> introduces 2 new fields in the dt_device_node:
>     - is_protected: Does the device is protected by an IOMMU
>     - next_assigned: Pointer to the next device assigned to the same
>     domain
> 
> Signed-off-by: Julien Grall <julien.grall@linaro.org>
> Cc: Xiantao Zhang <xiantao.zhang@intel.com>

For the modifications to existing files:
Acked-by: Jan Beulich <jbeulich@suse.com>

> 
> ---
>     Changes in v3:
>         - Remove iommu_dt_domain_{init,destroy} call in common code. Let
>         architecture code to call them
>         - Fix indentation in xen/include/xen/hvm/iommu.h
>     Changes in v2:
>         - Patch added
> ---
>  xen/common/device_tree.c              |    4 ++
>  xen/drivers/passthrough/Makefile      |    1 +
>  xen/drivers/passthrough/device_tree.c |  106 
> +++++++++++++++++++++++++++++++++
>  xen/include/xen/device_tree.h         |   14 +++++
>  xen/include/xen/hvm/iommu.h           |    6 ++
>  xen/include/xen/iommu.h               |   16 +++++
>  6 files changed, 147 insertions(+)
>  create mode 100644 xen/drivers/passthrough/device_tree.c
> 
> diff --git a/xen/common/device_tree.c b/xen/common/device_tree.c
> index 564f2bb..7c6b683 100644
> --- a/xen/common/device_tree.c
> +++ b/xen/common/device_tree.c
> @@ -1695,6 +1695,10 @@ static unsigned long __init unflatten_dt_node(const 
> void *fdt,
>          np->full_name = ((char *)np) + sizeof(struct dt_device_node);
>          /* By default dom0 owns the device */
>          np->used_by = 0;
> +        /* By default the device is not protected */
> +        np->is_protected = false;
> +        INIT_LIST_HEAD(&np->next_assigned);
> +
>          if ( new_format )
>          {
>              char *fn = np->full_name;
> diff --git a/xen/drivers/passthrough/Makefile 
> b/xen/drivers/passthrough/Makefile
> index 6e08f89..5a0a35e 100644
> --- a/xen/drivers/passthrough/Makefile
> +++ b/xen/drivers/passthrough/Makefile
> @@ -5,3 +5,4 @@ subdir-$(x86_64) += x86
>  obj-y += iommu.o
>  obj-$(x86) += io.o
>  obj-$(HAS_PCI) += pci.o
> +obj-$(HAS_DEVICE_TREE) += device_tree.o
> diff --git a/xen/drivers/passthrough/device_tree.c 
> b/xen/drivers/passthrough/device_tree.c
> new file mode 100644
> index 0000000..7384e73
> --- /dev/null
> +++ b/xen/drivers/passthrough/device_tree.c
> @@ -0,0 +1,106 @@
> +/*
> + * xen/drivers/passthrough/arm/device_tree.c
> + *
> + * Code to passthrough device tree node to a guest
> + *
> + * Julien Grall <julien.grall@linaro.org>
> + * Copyright (c) 2014 Linaro Limited.
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + */
> +
> +#include <xen/lib.h>
> +#include <xen/sched.h>
> +#include <xen/iommu.h>
> +#include <xen/device_tree.h>
> +
> +static spinlock_t dtdevs_lock = SPIN_LOCK_UNLOCKED;
> +
> +int iommu_assign_dt_device(struct domain *d, struct dt_device_node *dev)
> +{
> +    int rc = -EBUSY;
> +    struct hvm_iommu *hd = domain_hvm_iommu(d);
> +
> +    if ( !iommu_enabled || !hd->platform_ops )
> +        return -EINVAL;
> +
> +    if ( !dt_device_is_protected(dev) )
> +        return -EINVAL;
> +
> +    spin_lock(&dtdevs_lock);
> +
> +    if ( !list_empty(&dev->next_assigned) )
> +        goto fail;
> +
> +    rc = hd->platform_ops->assign_dt_device(d, dev);
> +
> +    if ( rc )
> +        goto fail;
> +
> +    list_add(&dev->next_assigned, &hd->dt_devices);
> +    dt_device_set_used_by(dev, d->domain_id);
> +
> +fail:
> +    spin_unlock(&dtdevs_lock);
> +
> +    return rc;
> +}
> +
> +int iommu_deassign_dt_device(struct domain *d, struct dt_device_node *dev)
> +{
> +    struct hvm_iommu *hd = domain_hvm_iommu(d);
> +    int rc;
> +
> +    if ( !iommu_enabled || !hd->platform_ops )
> +        return -EINVAL;
> +
> +    if ( !dt_device_is_protected(dev) )
> +        return -EINVAL;
> +
> +    spin_lock(&dtdevs_lock);
> +
> +    rc = hd->platform_ops->reassign_dt_device(d, dom0, dev);
> +    if ( rc )
> +        goto fail;
> +
> +    dt_device_set_used_by(dev, dom0->domain_id);
> +
> +    list_del(&dev->next_assigned);
> +
> +fail:
> +    spin_unlock(&dtdevs_lock);
> +
> +    return rc;
> +}
> +
> +int iommu_dt_domain_init(struct domain *d)
> +{
> +    struct hvm_iommu *hd = domain_hvm_iommu(d);
> +
> +    INIT_LIST_HEAD(&hd->dt_devices);
> +
> +    return 0;
> +}
> +
> +void iommu_dt_domain_destroy(struct domain *d)
> +{
> +    struct hvm_iommu *hd = domain_hvm_iommu(d);
> +    struct dt_device_node *dev, *_dev;
> +    int rc;
> +
> +    list_for_each_entry_safe(dev, _dev, &hd->dt_devices, next_assigned)
> +    {
> +        rc = iommu_deassign_dt_device(d, dev);
> +        if ( rc )
> +            dprintk(XENLOG_ERR, "Failed to deassign %s in domain %u\n",
> +                    dt_node_full_name(dev), d->domain_id);
> +    }
> +}
> diff --git a/xen/include/xen/device_tree.h b/xen/include/xen/device_tree.h
> index d429e60..2aae047 100644
> --- a/xen/include/xen/device_tree.h
> +++ b/xen/include/xen/device_tree.h
> @@ -16,6 +16,7 @@
>  #include <xen/string.h>
>  #include <xen/types.h>
>  #include <xen/stdbool.h>
> +#include <xen/list.h>
>  
>  #define DEVICE_TREE_MAX_DEPTH 16
>  
> @@ -110,6 +111,9 @@ struct dt_device_node {
>      struct dt_device_node *next; /* TODO: Remove it. Only use to know the 
> last children */
>      struct dt_device_node *allnext;
>  
> +    /* IOMMU specific fields */
> +    bool is_protected; /* Tell if the device is protected by an IOMMU */
> +    struct list_head next_assigned;
>  };
>  
>  #define MAX_PHANDLE_ARGS 16
> @@ -325,6 +329,16 @@ static inline domid_t dt_device_used_by(const struct 
> dt_device_node *device)
>      return device->used_by;
>  }
>  
> +static inline void dt_device_set_protected(struct dt_device_node *device)
> +{
> +    device->is_protected = true;
> +}
> +
> +static inline bool dt_device_is_protected(const struct dt_device_node 
> *device)
> +{
> +    return device->is_protected;
> +}
> +
>  static inline bool_t dt_property_name_is_equal(const struct dt_property 
> *pp,
>                                                 const char *name)
>  {
> diff --git a/xen/include/xen/hvm/iommu.h b/xen/include/xen/hvm/iommu.h
> index f8f8a93..1259e16 100644
> --- a/xen/include/xen/hvm/iommu.h
> +++ b/xen/include/xen/hvm/iommu.h
> @@ -21,6 +21,7 @@
>  #define __XEN_HVM_IOMMU_H__
>  
>  #include <xen/iommu.h>
> +#include <xen/list.h>
>  #include <asm/hvm/iommu.h>
>  
>  struct hvm_iommu {
> @@ -28,6 +29,11 @@ struct hvm_iommu {
>  
>      /* iommu_ops */
>      const struct iommu_ops *platform_ops;
> +
> +#ifdef HAS_DEVICE_TREE
> +    /* List of DT devices assigned to this domain */
> +    struct list_head dt_devices;
> +#endif
>  };
>  
>  #endif /* __XEN_HVM_IOMMU_H__ */
> diff --git a/xen/include/xen/iommu.h b/xen/include/xen/iommu.h
> index f556a7e..56f6c5c 100644
> --- a/xen/include/xen/iommu.h
> +++ b/xen/include/xen/iommu.h
> @@ -82,6 +82,16 @@ bool_t pt_irq_need_timer(uint32_t flags);
>  #define PT_IRQ_TIME_OUT MILLISECS(8)
>  #endif /* HAS_PCI */
>  
> +#ifdef HAS_DEVICE_TREE
> +#include <xen/device_tree.h>
> +
> +int iommu_assign_dt_device(struct domain *d, struct dt_device_node *dev);
> +int iommu_deassign_dt_device(struct domain *d, struct dt_device_node *dev);
> +int iommu_dt_domain_init(struct domain *d);
> +void iommu_dt_domain_destroy(struct domain *d);
> +
> +#endif /* HAS_DEVICE_TREE */
> +
>  #ifdef HAS_PCI
>  struct msi_desc;
>  struct msi_msg;
> @@ -103,6 +113,12 @@ struct iommu_ops {
>      int (*update_ire_from_msi)(struct msi_desc *msi_desc, struct msi_msg 
> *msg);
>      void (*read_msi_from_ire)(struct msi_desc *msi_desc, struct msi_msg 
> *msg);
>  #endif /* HAS_PCI */
> +#ifdef HAS_DEVICE_TREE
> +    int (*assign_dt_device)(struct domain *d, const struct dt_device_node 
> *dev);
> +    int (*reassign_dt_device)(struct domain *s, struct domain *t,
> +                              const struct dt_device_node *dev);
> +#endif
> +
>      void (*teardown)(struct domain *d);
>      int (*map_page)(struct domain *d, unsigned long gfn, unsigned long mfn,
>                      unsigned int flags);
> -- 
> 1.7.10.4
Ian Campbell March 18, 2014, 4:33 p.m. UTC | #2
On Tue, 2014-03-11 at 15:49 +0000, Julien Grall wrote:
> Add IOMMU helpers to support device tree assignment/deassignment. This patch
> introduces 2 new fields in the dt_device_node:
>     - is_protected: Does the device is protected by an IOMMU
>     - next_assigned: Pointer to the next device assigned to the same
>     domain

Am I correct that this list is not maintained for dom0? The behaviour of
dt_assign_device and dt_deassign_device seems to rely on it?

> Signed-off-by: Julien Grall <julien.grall@linaro.org>
> Cc: Xiantao Zhang <xiantao.zhang@intel.com>
> Cc: Jan Beulich <jbeulich@suse.com>

Ian.
Julien Grall March 18, 2014, 7:46 p.m. UTC | #3
Hi Ian,

On 03/18/2014 04:33 PM, Ian Campbell wrote:
> On Tue, 2014-03-11 at 15:49 +0000, Julien Grall wrote:
>> Add IOMMU helpers to support device tree assignment/deassignment. This patch
>> introduces 2 new fields in the dt_device_node:
>>     - is_protected: Does the device is protected by an IOMMU
>>     - next_assigned: Pointer to the next device assigned to the same
>>     domain
> 
> Am I correct that this list is not maintained for dom0? The behaviour of
> dt_assign_device and dt_deassign_device seems to rely on it?

DOM0 will call dt_assign_device for every device protected by the IOMMU
(see patch #9). So it will itself have a list maintained.

Regards,
Ian Campbell March 19, 2014, 10:12 a.m. UTC | #4
On Tue, 2014-03-18 at 19:46 +0000, Julien Grall wrote:
> Hi Ian,
> 
> On 03/18/2014 04:33 PM, Ian Campbell wrote:
> > On Tue, 2014-03-11 at 15:49 +0000, Julien Grall wrote:
> >> Add IOMMU helpers to support device tree assignment/deassignment. This patch
> >> introduces 2 new fields in the dt_device_node:
> >>     - is_protected: Does the device is protected by an IOMMU
> >>     - next_assigned: Pointer to the next device assigned to the same
> >>     domain
> > 
> > Am I correct that this list is not maintained for dom0? The behaviour of
> > dt_assign_device and dt_deassign_device seems to rely on it?
> 
> DOM0 will call dt_assign_device for every device protected by the IOMMU
> (see patch #9). So it will itself have a list maintained.

Does this not mean that iommu_assign_dt_device will refuse to assign the
device to another domain (next_assigned list is not empty).

BTW, next_assigned is not a very good name for this list, since the
"nextness" is abstracted away. Consider just device_list.

Ian.
Julien Grall March 19, 2014, 10:42 a.m. UTC | #5
Hi Ian,

On 19/03/14 10:12, Ian Campbell wrote:
>> On 03/18/2014 04:33 PM, Ian Campbell wrote:
>>> On Tue, 2014-03-11 at 15:49 +0000, Julien Grall wrote:
>>>> Add IOMMU helpers to support device tree assignment/deassignment. This patch
>>>> introduces 2 new fields in the dt_device_node:
>>>>      - is_protected: Does the device is protected by an IOMMU
>>>>      - next_assigned: Pointer to the next device assigned to the same
>>>>      domain
>>>
>>> Am I correct that this list is not maintained for dom0? The behaviour of
>>> dt_assign_device and dt_deassign_device seems to rely on it?
>>
>> DOM0 will call dt_assign_device for every device protected by the IOMMU
>> (see patch #9). So it will itself have a list maintained.
>
> Does this not mean that iommu_assign_dt_device will refuse to assign the
> device to another domain (next_assigned list is not empty).

Yes. After thinking, I'm not sure we want maintain a list for dom0.
At least the iommu_deassign_dt_device function is wrong because the 
device is not reassigned to dom0 (from the list point of view).


> BTW, next_assigned is not a very good name for this list, since the
> "nextness" is abstracted away. Consider just device_list.

I found device_list too generic. We don't know if it's the list of all 
the devices or just the ones of a specific domain.

What about domain_device_list?

Regards,
Ian Campbell March 19, 2014, 10:54 a.m. UTC | #6
On Wed, 2014-03-19 at 10:42 +0000, Julien Grall wrote:
> > BTW, next_assigned is not a very good name for this list, since the
> > "nextness" is abstracted away. Consider just device_list.
> 
> I found device_list too generic. We don't know if it's the list of all 
> the devices or just the ones of a specific domain.
> 
> What about domain_device_list?

Just domain_list would do I think, device is before the -> in the uses.

Ian.
diff mbox

Patch

diff --git a/xen/common/device_tree.c b/xen/common/device_tree.c
index 564f2bb..7c6b683 100644
--- a/xen/common/device_tree.c
+++ b/xen/common/device_tree.c
@@ -1695,6 +1695,10 @@  static unsigned long __init unflatten_dt_node(const void *fdt,
         np->full_name = ((char *)np) + sizeof(struct dt_device_node);
         /* By default dom0 owns the device */
         np->used_by = 0;
+        /* By default the device is not protected */
+        np->is_protected = false;
+        INIT_LIST_HEAD(&np->next_assigned);
+
         if ( new_format )
         {
             char *fn = np->full_name;
diff --git a/xen/drivers/passthrough/Makefile b/xen/drivers/passthrough/Makefile
index 6e08f89..5a0a35e 100644
--- a/xen/drivers/passthrough/Makefile
+++ b/xen/drivers/passthrough/Makefile
@@ -5,3 +5,4 @@  subdir-$(x86_64) += x86
 obj-y += iommu.o
 obj-$(x86) += io.o
 obj-$(HAS_PCI) += pci.o
+obj-$(HAS_DEVICE_TREE) += device_tree.o
diff --git a/xen/drivers/passthrough/device_tree.c b/xen/drivers/passthrough/device_tree.c
new file mode 100644
index 0000000..7384e73
--- /dev/null
+++ b/xen/drivers/passthrough/device_tree.c
@@ -0,0 +1,106 @@ 
+/*
+ * xen/drivers/passthrough/arm/device_tree.c
+ *
+ * Code to passthrough device tree node to a guest
+ *
+ * Julien Grall <julien.grall@linaro.org>
+ * Copyright (c) 2014 Linaro Limited.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <xen/lib.h>
+#include <xen/sched.h>
+#include <xen/iommu.h>
+#include <xen/device_tree.h>
+
+static spinlock_t dtdevs_lock = SPIN_LOCK_UNLOCKED;
+
+int iommu_assign_dt_device(struct domain *d, struct dt_device_node *dev)
+{
+    int rc = -EBUSY;
+    struct hvm_iommu *hd = domain_hvm_iommu(d);
+
+    if ( !iommu_enabled || !hd->platform_ops )
+        return -EINVAL;
+
+    if ( !dt_device_is_protected(dev) )
+        return -EINVAL;
+
+    spin_lock(&dtdevs_lock);
+
+    if ( !list_empty(&dev->next_assigned) )
+        goto fail;
+
+    rc = hd->platform_ops->assign_dt_device(d, dev);
+
+    if ( rc )
+        goto fail;
+
+    list_add(&dev->next_assigned, &hd->dt_devices);
+    dt_device_set_used_by(dev, d->domain_id);
+
+fail:
+    spin_unlock(&dtdevs_lock);
+
+    return rc;
+}
+
+int iommu_deassign_dt_device(struct domain *d, struct dt_device_node *dev)
+{
+    struct hvm_iommu *hd = domain_hvm_iommu(d);
+    int rc;
+
+    if ( !iommu_enabled || !hd->platform_ops )
+        return -EINVAL;
+
+    if ( !dt_device_is_protected(dev) )
+        return -EINVAL;
+
+    spin_lock(&dtdevs_lock);
+
+    rc = hd->platform_ops->reassign_dt_device(d, dom0, dev);
+    if ( rc )
+        goto fail;
+
+    dt_device_set_used_by(dev, dom0->domain_id);
+
+    list_del(&dev->next_assigned);
+
+fail:
+    spin_unlock(&dtdevs_lock);
+
+    return rc;
+}
+
+int iommu_dt_domain_init(struct domain *d)
+{
+    struct hvm_iommu *hd = domain_hvm_iommu(d);
+
+    INIT_LIST_HEAD(&hd->dt_devices);
+
+    return 0;
+}
+
+void iommu_dt_domain_destroy(struct domain *d)
+{
+    struct hvm_iommu *hd = domain_hvm_iommu(d);
+    struct dt_device_node *dev, *_dev;
+    int rc;
+
+    list_for_each_entry_safe(dev, _dev, &hd->dt_devices, next_assigned)
+    {
+        rc = iommu_deassign_dt_device(d, dev);
+        if ( rc )
+            dprintk(XENLOG_ERR, "Failed to deassign %s in domain %u\n",
+                    dt_node_full_name(dev), d->domain_id);
+    }
+}
diff --git a/xen/include/xen/device_tree.h b/xen/include/xen/device_tree.h
index d429e60..2aae047 100644
--- a/xen/include/xen/device_tree.h
+++ b/xen/include/xen/device_tree.h
@@ -16,6 +16,7 @@ 
 #include <xen/string.h>
 #include <xen/types.h>
 #include <xen/stdbool.h>
+#include <xen/list.h>
 
 #define DEVICE_TREE_MAX_DEPTH 16
 
@@ -110,6 +111,9 @@  struct dt_device_node {
     struct dt_device_node *next; /* TODO: Remove it. Only use to know the last children */
     struct dt_device_node *allnext;
 
+    /* IOMMU specific fields */
+    bool is_protected; /* Tell if the device is protected by an IOMMU */
+    struct list_head next_assigned;
 };
 
 #define MAX_PHANDLE_ARGS 16
@@ -325,6 +329,16 @@  static inline domid_t dt_device_used_by(const struct dt_device_node *device)
     return device->used_by;
 }
 
+static inline void dt_device_set_protected(struct dt_device_node *device)
+{
+    device->is_protected = true;
+}
+
+static inline bool dt_device_is_protected(const struct dt_device_node *device)
+{
+    return device->is_protected;
+}
+
 static inline bool_t dt_property_name_is_equal(const struct dt_property *pp,
                                                const char *name)
 {
diff --git a/xen/include/xen/hvm/iommu.h b/xen/include/xen/hvm/iommu.h
index f8f8a93..1259e16 100644
--- a/xen/include/xen/hvm/iommu.h
+++ b/xen/include/xen/hvm/iommu.h
@@ -21,6 +21,7 @@ 
 #define __XEN_HVM_IOMMU_H__
 
 #include <xen/iommu.h>
+#include <xen/list.h>
 #include <asm/hvm/iommu.h>
 
 struct hvm_iommu {
@@ -28,6 +29,11 @@  struct hvm_iommu {
 
     /* iommu_ops */
     const struct iommu_ops *platform_ops;
+
+#ifdef HAS_DEVICE_TREE
+    /* List of DT devices assigned to this domain */
+    struct list_head dt_devices;
+#endif
 };
 
 #endif /* __XEN_HVM_IOMMU_H__ */
diff --git a/xen/include/xen/iommu.h b/xen/include/xen/iommu.h
index f556a7e..56f6c5c 100644
--- a/xen/include/xen/iommu.h
+++ b/xen/include/xen/iommu.h
@@ -82,6 +82,16 @@  bool_t pt_irq_need_timer(uint32_t flags);
 #define PT_IRQ_TIME_OUT MILLISECS(8)
 #endif /* HAS_PCI */
 
+#ifdef HAS_DEVICE_TREE
+#include <xen/device_tree.h>
+
+int iommu_assign_dt_device(struct domain *d, struct dt_device_node *dev);
+int iommu_deassign_dt_device(struct domain *d, struct dt_device_node *dev);
+int iommu_dt_domain_init(struct domain *d);
+void iommu_dt_domain_destroy(struct domain *d);
+
+#endif /* HAS_DEVICE_TREE */
+
 #ifdef HAS_PCI
 struct msi_desc;
 struct msi_msg;
@@ -103,6 +113,12 @@  struct iommu_ops {
     int (*update_ire_from_msi)(struct msi_desc *msi_desc, struct msi_msg *msg);
     void (*read_msi_from_ire)(struct msi_desc *msi_desc, struct msi_msg *msg);
 #endif /* HAS_PCI */
+#ifdef HAS_DEVICE_TREE
+    int (*assign_dt_device)(struct domain *d, const struct dt_device_node *dev);
+    int (*reassign_dt_device)(struct domain *s, struct domain *t,
+                              const struct dt_device_node *dev);
+#endif
+
     void (*teardown)(struct domain *d);
     int (*map_page)(struct domain *d, unsigned long gfn, unsigned long mfn,
                     unsigned int flags);