[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Xen-devel] [PATCH v3 07/24] xen/arm: Introduce xen, passthrough property



On Tue, 13 Jan 2015, Julien Grall wrote:
> 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 <julien.grall@xxxxxxxxxx>
> 
> ---
>     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);

Why is the "else" needed? Wouldn't the status property for
non-passtrough devices already be covered by the
dt_for_each_property_node loop above?


> +    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
> 

_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxx
http://lists.xen.org/xen-devel


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.