Message ID | 1569339027-19484-8-git-send-email-olekstysh@gmail.com (mailing list archive) |
---|---|
State | Superseded |
Headers | show |
Series | iommu/arm: Add Renesas IPMMU-VMSA support + Linux's iommu_fwspec | expand |
Hi, On 9/24/19 4:30 PM, Oleksandr Tyshchenko wrote: > @@ -1263,15 +1264,22 @@ static int __init handle_device(struct domain *d, struct dt_device_node *dev, > 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 ) > - { > - printk(XENLOG_ERR "Failed to setup the IOMMU for %s\n", > + dt_dprintk("Check if %s is behind the IOMMU and add it\n", > dt_node_full_name(dev)); > - return res; > + > + iommu_add_dt_device(dev); Return value should always be checked or explain why this is not done. [...] > int iommu_do_dt_domctl(struct xen_domctl *domctl, struct domain *d, > XEN_GUEST_HANDLE_PARAM(xen_domctl_t) u_domctl) > { > @@ -177,6 +241,13 @@ int iommu_do_dt_domctl(struct xen_domctl *domctl, struct domain *d, > break; > } > > + iommu_add_dt_device(dev); Same here. > + if ( !dt_device_is_protected(dev) ) > + { > + ret = -EINVAL; > + break; > + } This is already checked in iommu_assign_dt_device(). Cheers,
On 24.09.19 18:57, Julien Grall wrote: > Hi, Hi Julien > > On 9/24/19 4:30 PM, Oleksandr Tyshchenko wrote: >> @@ -1263,15 +1264,22 @@ static int __init handle_device(struct domain >> *d, struct dt_device_node *dev, >> 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 ) >> - { >> - printk(XENLOG_ERR "Failed to setup the IOMMU for %s\n", >> + dt_dprintk("Check if %s is behind the IOMMU and add it\n", >> dt_node_full_name(dev)); >> - return res; >> + >> + iommu_add_dt_device(dev); > > Return value should always be checked or explain why this is not done. Yes, I will add a check. The positive result for us is non-negative (either "device is protected" or "device doesn't need to be protected"). > > > [...] > >> int iommu_do_dt_domctl(struct xen_domctl *domctl, struct domain *d, >> XEN_GUEST_HANDLE_PARAM(xen_domctl_t) u_domctl) >> { >> @@ -177,6 +241,13 @@ int iommu_do_dt_domctl(struct xen_domctl >> *domctl, struct domain *d, >> break; >> } >> + iommu_add_dt_device(dev); > > Same here. Yes, I think, we don't need to check for return value, because the only one positive result "here" is the fact that "device is protected" (which is checked below). What is more, if we add a check for the return value to be strictly 0, we will get an error after guest's reboot (since iommu_add_dt_device() will return -EEXIST). So, I will add a comment explaining why we don't check. What do you think? > >> + if ( !dt_device_is_protected(dev) ) >> + { >> + ret = -EINVAL; >> + break; >> + } > > This is already checked in iommu_assign_dt_device(). Will drop here.
Hi Oleksandr, On 9/24/19 5:22 PM, Oleksandr wrote: > > On 24.09.19 18:57, Julien Grall wrote: >> Hi, > > Hi Julien > > >> >> On 9/24/19 4:30 PM, Oleksandr Tyshchenko wrote: >>> @@ -1263,15 +1264,22 @@ static int __init handle_device(struct domain >>> *d, struct dt_device_node *dev, >>> 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 ) >>> - { >>> - printk(XENLOG_ERR "Failed to setup the IOMMU for %s\n", >>> + dt_dprintk("Check if %s is behind the IOMMU and add it\n", >>> dt_node_full_name(dev)); >>> - return res; >>> + >>> + iommu_add_dt_device(dev); >> >> Return value should always be checked or explain why this is not done. > > Yes, I will add a check. The positive result for us is non-negative > (either "device is protected" or "device doesn't need to be protected"). > > >> >> >> [...] >> >>> int iommu_do_dt_domctl(struct xen_domctl *domctl, struct domain *d, >>> XEN_GUEST_HANDLE_PARAM(xen_domctl_t) u_domctl) >>> { >>> @@ -177,6 +241,13 @@ int iommu_do_dt_domctl(struct xen_domctl >>> *domctl, struct domain *d, >>> break; >>> } >>> + iommu_add_dt_device(dev); >> >> Same here. > > Yes, I think, we don't need to check for return value, because the only > one positive result "here" is the fact that "device is protected" (which > is checked below). > > What is more, if we add a check for the return value to be strictly 0, > we will get an error after guest's reboot (since iommu_add_dt_device() > will return -EEXIST). > > So, I will add a comment explaining why we don't check. What do you think? Why don't you do the following code? if ( ret < 0 && ret != -EEXIST ) This would allow the code to return the corrrect error to the upper layer. A suitable comment on top explaing the check would also be useful. Cheers,
On 24.09.19 20:21, Julien Grall wrote: > Hi Oleksandr, Hi Julien. > >>> >>> >>> [...] >>> >>>> int iommu_do_dt_domctl(struct xen_domctl *domctl, struct domain *d, >>>> XEN_GUEST_HANDLE_PARAM(xen_domctl_t) u_domctl) >>>> { >>>> @@ -177,6 +241,13 @@ int iommu_do_dt_domctl(struct xen_domctl >>>> *domctl, struct domain *d, >>>> break; >>>> } >>>> + iommu_add_dt_device(dev); >>> >>> Same here. >> >> Yes, I think, we don't need to check for return value, because the >> only one positive result "here" is the fact that "device is >> protected" (which is checked below). >> >> What is more, if we add a check for the return value to be strictly >> 0, we will get an error after guest's reboot (since >> iommu_add_dt_device() will return -EEXIST). >> >> So, I will add a comment explaining why we don't check. What do you >> think? > > Why don't you do the following code? > > if ( ret < 0 && ret != -EEXIST ) > > This would allow the code to return the corrrect error to the upper > layer. A suitable comment on top explaing the check would also be useful. Being honest, I was thinking about the similar, but rejected this. I thought, all what we wanted to know "here" was whether the particular device protected or not. But, I agree now, the upper layer should be informed about the exact error reason.
diff --git a/xen/arch/arm/domain_build.c b/xen/arch/arm/domain_build.c index a0fee1e..8048789 100644 --- a/xen/arch/arm/domain_build.c +++ b/xen/arch/arm/domain_build.c @@ -1243,6 +1243,7 @@ static int __init map_device_children(struct domain *d, * - 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 */ @@ -1263,15 +1264,22 @@ static int __init handle_device(struct domain *d, struct dt_device_node *dev, 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 ) - { - printk(XENLOG_ERR "Failed to setup the IOMMU for %s\n", + dt_dprintk("Check if %s is behind the IOMMU and add it\n", dt_node_full_name(dev)); - return res; + + iommu_add_dt_device(dev); + 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; + } } } diff --git a/xen/drivers/passthrough/device_tree.c b/xen/drivers/passthrough/device_tree.c index 3f328f4..0fd2488 100644 --- a/xen/drivers/passthrough/device_tree.c +++ b/xen/drivers/passthrough/device_tree.c @@ -22,6 +22,8 @@ #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) @@ -136,6 +138,68 @@ int iommu_release_dt_devices(struct domain *d) 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) { @@ -177,6 +241,13 @@ int iommu_do_dt_domctl(struct xen_domctl *domctl, struct domain *d, break; } + iommu_add_dt_device(dev); + if ( !dt_device_is_protected(dev) ) + { + ret = -EINVAL; + break; + } + ret = iommu_assign_dt_device(d, dev); if ( ret ) diff --git a/xen/include/xen/iommu.h b/xen/include/xen/iommu.h index c5ed7ef..2d1cc6e 100644 --- a/xen/include/xen/iommu.h +++ b/xen/include/xen/iommu.h @@ -186,6 +186,17 @@ int iommu_deassign_dt_device(struct domain *d, struct dt_device_node *dev); 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)); @@ -254,6 +265,16 @@ struct iommu_ops { 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>