From mboxrd@z Thu Jan 1 00:00:00 1970 From: Julien Grall Subject: [PATCH v5 08/14] xen/passthrough: iommu: Basic support of device tree assignment Date: Tue, 13 May 2014 16:50:24 +0100 Message-ID: <1399996230-18201-9-git-send-email-julien.grall@linaro.org> References: <1399996230-18201-1-git-send-email-julien.grall@linaro.org> Mime-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Return-path: Received: from mail6.bemta3.messagelabs.com ([195.245.230.39]) by lists.xen.org with esmtp (Exim 4.72) (envelope-from ) id 1WkEyh-0008R0-Jp for xen-devel@lists.xenproject.org; Tue, 13 May 2014 15:50:51 +0000 Received: by mail-ee0-f47.google.com with SMTP id c13so567619eek.20 for ; Tue, 13 May 2014 08:50:49 -0700 (PDT) In-Reply-To: <1399996230-18201-1-git-send-email-julien.grall@linaro.org> List-Unsubscribe: , List-Post: List-Help: List-Subscribe: , Sender: xen-devel-bounces@lists.xen.org Errors-To: xen-devel-bounces@lists.xen.org To: xen-devel@lists.xenproject.org Cc: ian.campbell@citrix.com, Julien Grall , tim@xen.org, stefano.stabellini@citrix.com, Jan Beulich , Xiantao Zhang List-Id: xen-devel@lists.xenproject.org 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 - domain_list: Pointer to the next device assigned to the same domain This commit contains only support to protected a device with DOM0. Device passthrough to another guest won't work out-of-box. Signed-off-by: Julien Grall Acked-by: Jan Beulich Acked-by: Ian Campbell Cc: Xiantao Zhang --- Changes in v5: - Fix typo in comment headers of drivers/passthrough/device_tree.c - Drop comment of is_protected field Changes in v4: - Use hardware_domain instead of dom0 (recently changes in Xen) - iommu_deassign_dt_device: add back to dom0 list the device - add comments about the current support of DT device passthrough - update commit message - rename next_assigned to domain_list 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 | 108 +++++++++++++++++++++++++++++++++ xen/include/xen/device_tree.h | 14 +++++ xen/include/xen/hvm/iommu.h | 6 ++ xen/include/xen/iommu.h | 16 +++++ 6 files changed, 149 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 6e8e263..f0b17a3 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->domain_list); + 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..3e47df5 --- /dev/null +++ b/xen/drivers/passthrough/device_tree.c @@ -0,0 +1,108 @@ +/* + * Code to passthrough a device tree node to a guest + * + * TODO: This contains only the necessary code to protected device passed to + * dom0. It will need some updates when device passthrough will is added. + * + * Julien Grall + * 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 +#include +#include +#include + +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->domain_list) ) + goto fail; + + rc = hd->platform_ops->assign_dt_device(d, dev); + + if ( rc ) + goto fail; + + list_add(&dev->domain_list, &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, hardware_domain, dev); + if ( rc ) + goto fail; + + list_del(&dev->domain_list); + + dt_device_set_used_by(dev, hardware_domain->domain_id); + list_add(&dev->domain_list, &domain_hvm_iommu(hardware_domain)->dt_devices); + +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, domain_list) + { + 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 e677da9..25db076 100644 --- a/xen/include/xen/device_tree.h +++ b/xen/include/xen/device_tree.h @@ -16,6 +16,7 @@ #include #include #include +#include #define DEVICE_TREE_MAX_DEPTH 16 @@ -111,6 +112,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; + struct list_head domain_list; }; #define MAX_PHANDLE_ARGS 16 @@ -329,6 +333,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 +#include #include 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 ceb66c0..b7481dac 100644 --- a/xen/include/xen/iommu.h +++ b/xen/include/xen/iommu.h @@ -90,6 +90,16 @@ void iommu_read_msi_from_ire(struct msi_desc *msi_desc, struct msi_msg *msg); #define PT_IRQ_TIME_OUT MILLISECS(8) #endif /* HAS_PCI */ +#ifdef HAS_DEVICE_TREE +#include + +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 */ + struct page_info; struct iommu_ops { @@ -106,6 +116,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