From mboxrd@z Thu Jan 1 00:00:00 1970 From: Julien Grall Subject: [PATCH v3 07/24] xen/arm: Introduce xen, passthrough property Date: Tue, 13 Jan 2015 14:25:16 +0000 Message-ID: <1421159133-31526-8-git-send-email-julien.grall@linaro.org> References: <1421159133-31526-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.bemta14.messagelabs.com ([193.109.254.103]) by lists.xen.org with esmtp (Exim 4.72) (envelope-from ) id 1YB2QW-000196-8K for xen-devel@lists.xenproject.org; Tue, 13 Jan 2015 14:26:36 +0000 Received: by mail-we0-f177.google.com with SMTP id q59so3192353wes.8 for ; Tue, 13 Jan 2015 06:26:33 -0800 (PST) In-Reply-To: <1421159133-31526-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: stefano.stabellini@citrix.com, Julien Grall , tim@xen.org, ian.campbell@citrix.com List-Id: xen-devel@lists.xenproject.org When a device is marked for passthrough (via the new property "xen,passthrough"), dom0 must not access to the device (i.e not loading a driver), but should be able to manage the MMIO/interrupt of the passthrough device. The latter part will allow the toolstack to map MMIO/IRQ when a device is pass through to a guest. The property "xen,passthrough" will be translated as 'status="disabled"' in the device tree to avoid DOM0 using the device. We assume that DOM0 is able to cope with this property (already the case for Linux). Rework the function map_device (renamed into handle_device) to: * For a given device node: - Give permission to manage IRQ/MMIO for this device - Retrieve the IRQ configuration (i.e edge/level) from the device tree * When the device is not marked for guest passthrough: - Assign the device to the guest if it's protected by an IOMMU - Map the IRQs and MMIOs regions to the guest Signed-off-by: Julien Grall --- Changes in v3: - This patch was formely "xen/arm: Follow-up to allow DOM0 manage IRQ and MMIO". It has been split in 2 parts [1]. - Update commit title and improve message - Remove spurious change [1] https://patches.linaro.org/34669/ --- docs/misc/arm/device-tree/passthrough.txt | 7 ++ xen/arch/arm/device.c | 2 +- xen/arch/arm/domain_build.c | 102 ++++++++++++++++++++++-------- xen/common/device_tree.c | 6 ++ xen/include/xen/device_tree.h | 11 ++++ 5 files changed, 100 insertions(+), 28 deletions(-) create mode 100644 docs/misc/arm/device-tree/passthrough.txt diff --git a/docs/misc/arm/device-tree/passthrough.txt b/docs/misc/arm/device-tree/passthrough.txt new file mode 100644 index 0000000..04645b3 --- /dev/null +++ b/docs/misc/arm/device-tree/passthrough.txt @@ -0,0 +1,7 @@ +Device passthrough +=================== + +Any device that will be passthrough to a guest should have a property +"xen,passthrough" in their device tree node. + +The device won't be exposed to DOM0 and therefore no driver will be loaded. diff --git a/xen/arch/arm/device.c b/xen/arch/arm/device.c index 1993929..1a01793 100644 --- a/xen/arch/arm/device.c +++ b/xen/arch/arm/device.c @@ -30,7 +30,7 @@ int __init device_init(struct dt_device_node *dev, enum device_match type, ASSERT(dev != NULL); - if ( !dt_device_is_available(dev) ) + if ( !dt_device_is_available(dev) || dt_device_for_passthrough(dev) ) return -ENODEV; for ( desc = _sdevice; desc != _edevice; desc++ ) diff --git a/xen/arch/arm/domain_build.c b/xen/arch/arm/domain_build.c index f68755f..b48b5d0 100644 --- a/xen/arch/arm/domain_build.c +++ b/xen/arch/arm/domain_build.c @@ -402,7 +402,7 @@ static int write_properties(struct domain *d, struct kernel_info *kinfo, const struct dt_device_node *node) { const char *bootargs = NULL; - const struct dt_property *prop; + const struct dt_property *prop, *status = NULL; int res = 0; int had_dom0_bootargs = 0; @@ -457,6 +457,17 @@ static int write_properties(struct domain *d, struct kernel_info *kinfo, } } + /* Don't expose the property "xen,passthrough" to the guest */ + if ( dt_property_name_is_equal(prop, "xen,passthrough") ) + continue; + + /* Remember and skip the status property as Xen may modify it later */ + if ( dt_property_name_is_equal(prop, "status") ) + { + status = prop; + continue; + } + res = fdt_property(kinfo->fdt, prop->name, prop_data, prop_len); xfree(new_data); @@ -465,6 +476,19 @@ static int write_properties(struct domain *d, struct kernel_info *kinfo, return res; } + /* + * Override the property "status" to disable the device when it's + * marked for passthrough. + */ + if ( dt_device_for_passthrough(node) ) + res = fdt_property_string(kinfo->fdt, "status", "disabled"); + else if ( status ) + res = fdt_property(kinfo->fdt, "status", status->value, + status->length); + + if ( res ) + return res; + if ( dt_node_path_is_equal(node, "/chosen") ) { const struct bootmodule *mod = kinfo->initrd_bootmodule; @@ -919,8 +943,14 @@ static int make_timer_node(const struct domain *d, void *fdt, return res; } -/* Map the device in the domain */ -static int map_device(struct domain *d, struct dt_device_node *dev) +/* For a given device node: + * - 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: + * - Assign the device to the guest if it's protected by an IOMMU + * - Map the IRQs and iomem regions to DOM0 + */ +static int handle_device(struct domain *d, struct dt_device_node *dev) { unsigned int nirq; unsigned int naddr; @@ -929,13 +959,15 @@ static int map_device(struct domain *d, struct dt_device_node *dev) unsigned int irq; struct dt_raw_irq rirq; u64 addr, size; + bool_t need_mapping = !dt_device_for_passthrough(dev); nirq = dt_number_of_irq(dev); naddr = dt_number_of_address(dev); - DPRINT("%s nirq = %d naddr = %u\n", dt_node_full_name(dev), nirq, naddr); + DPRINT("%s passthrough = %d nirq = %d naddr = %u\n", dt_node_full_name(dev), + need_mapping, nirq, naddr); - if ( dt_device_is_protected(dev) ) + if ( dt_device_is_protected(dev) && need_mapping ) { DPRINT("%s setup iommu\n", dt_node_full_name(dev)); res = iommu_assign_dt_device(d, dev); @@ -947,7 +979,7 @@ static int map_device(struct domain *d, struct dt_device_node *dev) } } - /* Map IRQs */ + /* Give permission and map IRQs */ for ( i = 0; i < nirq; i++ ) { res = dt_device_get_raw_irq(dev, i, &rirq); @@ -980,22 +1012,34 @@ static int map_device(struct domain *d, struct dt_device_node *dev) irq = res; DPRINT("irq %u = %u\n", i, irq); - /* - * Checking the return of vgic_reserve_virq is not - * necessary. It should not fail except when we try to map - * twice the IRQ. This can happen if the IRQ is shared - */ - vgic_reserve_virq(d, irq); - res = route_irq_to_guest(d, irq, dt_node_name(dev)); + + res = irq_permit_access(d, irq); if ( res ) { - printk(XENLOG_ERR "Unable to route IRQ %u to domain %u\n", - irq, d->domain_id); + printk(XENLOG_ERR "Unable to permit to dom%u access to IRQ %u\n", + d->domain_id, irq); return res; } + + if ( need_mapping ) + { + /* + * Checking the return of vgic_reserve_virq is not + * necessary. It should not fail except when we try to map + * twice the IRQ. This can happen if the IRQ is shared + */ + vgic_reserve_virq(d, irq); + res = route_irq_to_guest(d, irq, dt_node_name(dev)); + if ( res ) + { + printk(XENLOG_ERR "Unable to route IRQ %u to domain %u\n", + irq, d->domain_id); + return res; + } + } } - /* Map the address ranges */ + /* Give permission and map MMIOs */ for ( i = 0; i < naddr; i++ ) { res = dt_device_get_address(dev, i, &addr, &size); @@ -1019,17 +1063,21 @@ static int map_device(struct domain *d, struct dt_device_node *dev) addr & PAGE_MASK, PAGE_ALIGN(addr + size) - 1); return res; } - res = map_mmio_regions(d, - paddr_to_pfn(addr & PAGE_MASK), - DIV_ROUND_UP(size, PAGE_SIZE), - paddr_to_pfn(addr & PAGE_MASK)); - if ( res ) + + if ( need_mapping ) { - printk(XENLOG_ERR "Unable to map 0x%"PRIx64 - " - 0x%"PRIx64" in domain %d\n", - addr & PAGE_MASK, PAGE_ALIGN(addr + size) - 1, - d->domain_id); - return res; + res = map_mmio_regions(d, + paddr_to_pfn(addr & PAGE_MASK), + DIV_ROUND_UP(size, PAGE_SIZE), + paddr_to_pfn(addr & PAGE_MASK)); + if ( res ) + { + printk(XENLOG_ERR "Unable to map 0x%"PRIx64 + " - 0x%"PRIx64" in domain %d\n", + addr & PAGE_MASK, PAGE_ALIGN(addr + size) - 1, + d->domain_id); + return res; + } } } @@ -1104,7 +1152,7 @@ static int handle_node(struct domain *d, struct kernel_info *kinfo, return 0; } - res = map_device(d, node); + res = handle_device(d, node); if ( res) return res; diff --git a/xen/common/device_tree.c b/xen/common/device_tree.c index bb9d7ce..ce10574 100644 --- a/xen/common/device_tree.c +++ b/xen/common/device_tree.c @@ -1103,6 +1103,12 @@ bool_t dt_device_is_available(const struct dt_device_node *device) return 0; } +bool_t dt_device_for_passthrough(const struct dt_device_node *device) +{ + return (dt_find_property(device, "xen,passthrough", NULL) != NULL); + +} + static int __dt_parse_phandle_with_args(const struct dt_device_node *np, const char *list_name, const char *cells_name, diff --git a/xen/include/xen/device_tree.h b/xen/include/xen/device_tree.h index 890d356..caaf65f 100644 --- a/xen/include/xen/device_tree.h +++ b/xen/include/xen/device_tree.h @@ -555,6 +555,17 @@ int dt_n_addr_cells(const struct dt_device_node *np); bool_t dt_device_is_available(const struct dt_device_node *device); /** + * dt_device_for_passthrough - Check if a device will be used for + * passthrough later + * + * @device: Node to check + * + * Return true if the property "xen,passthrough" is present in the node, + * false otherwise. + */ +bool_t dt_device_for_passthrough(const struct dt_device_node *device); + +/** * dt_match_node - Tell if a device_node has a matching of dt_device_match * @matches: array of dt_device_match structures to search in * @node: the dt_device_node structure to match against -- 2.1.4