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

Re: [Xen-devel] [PATCH 6/7] xen/arm: SMMU: Support generic IOMMU bindings



On Fri, 30 Jun 2017, Wei Chen wrote:
> The SMMU MasterIDs are placed at the master devices' DT node while
> using the generic bindings. In this case, it's very hard for us to
> register SMMU masters while probing SMMU as we had done for legacy
> bindings. Because we have to go through whole device tree for all
> SMMU devices to find their master devices.
> 
> It's better to register SMMU master for generic bindings in add_device
> callback. This callback will only be called while constructing Dom0.
> 
> Signed-off-by: Wei Chen <Wei.Chen@xxxxxxx>
> ---
>  xen/drivers/passthrough/arm/smmu.c | 144 
> ++++++++++++++++++++++++++++++++++++-
>  1 file changed, 143 insertions(+), 1 deletion(-)
> 
> diff --git a/xen/drivers/passthrough/arm/smmu.c 
> b/xen/drivers/passthrough/arm/smmu.c
> index 895024c..25f2207 100644
> --- a/xen/drivers/passthrough/arm/smmu.c
> +++ b/xen/drivers/passthrough/arm/smmu.c
> @@ -2621,8 +2621,150 @@ static void arm_smmu_destroy_iommu_domain(struct 
> iommu_domain *domain)
>       xfree(domain);
>  }
>  
> +static int arm_smmu_add_generic_master_id(struct arm_smmu_device *smmu,
> +                             struct device *master_dev, u16 fwid)
> +{
> +     struct arm_smmu_master *master;
> +     struct device_node *master_np = master_dev->of_node;
> +
> +     master = find_smmu_master(smmu, master_np);
> +     if (!master) {
> +             dev_notice(smmu->dev,
> +                     "This smmu master [%s] hasn't been registered, creating 
> now!\n",
> +                     master_np->full_name);
> +             master = devm_kzalloc(smmu->dev, sizeof(*master), GFP_KERNEL);
> +             if (!master)
> +                     return -ENOMEM;
> +
> +             master->of_node = master_np;
> +             master->cfg.num_streamids = 0;
> +
> +             /*
> +              * Xen: Let Xen know that the device is protected by a SMMU.
> +              * Only do while registering the master.
> +              */
> +             dt_device_set_protected(master_np);
> +     }
> +
> +     /*
> +      * If the smmu is using the stream index mode, check whether
> +      * the streamid exceeds the max allowed id,
> +      */
> +     if (!(smmu->features & ARM_SMMU_FEAT_STREAM_MATCH) &&
> +             (fwid >= smmu->num_mapping_groups)) {
> +             dev_err(smmu->dev,
> +                     "Stream ID for master device %s greater than maximum 
> allowed (%d)\n",
> +                     master_np->name, smmu->num_mapping_groups);
> +             return -ERANGE;
> +     }
> +
> +     if (master->cfg.num_streamids >= MAX_MASTER_STREAMIDS) {
> +             dev_err(smmu->dev,
> +                     "Reached maximum number (%d) of stream IDs for master 
> device %s\n",
> +                     MAX_MASTER_STREAMIDS, master_np->name);
> +             return -ENOSPC;
> +     }
> +
> +     /*
> +      * If this is the first time we add id to this master,
> +      * we have to register this master to rb tree.
> +      */
> +     if (!master->cfg.num_streamids) {
> +             int ret;
> +             ret = insert_smmu_master(smmu, master);
> +             if ( ret && ret != -EEXIST ) {
> +                     dev_err(smmu->dev,
> +                             "Insert %s to smmu's master rb tree failed\n", 
> master_np->name);
> +                     return ret;
> +             }
> +     }
> +
> +     master->cfg.streamids[master->cfg.num_streamids] = fwid;
> +     master->cfg.num_streamids++;
> +     dev_dbg(smmu->dev,
> +             "Add new streamid [%d] to smmu [%s] for master [%s]!\n",
> +             fwid, smmu->dev->of_node->name, master_np->name);
> +
> +     return 0;
> +}
> +
> +static struct arm_smmu_device *find_smmu(const struct device *dev);
> +
> +static int arm_smmu_of_xlate(struct device *dev, struct of_phandle_args 
> *args)
> +{
> +     struct arm_smmu_device *smmu;
> +     u32 mask = 0, fwid = 0;
> +
> +     smmu = find_smmu(dt_to_dev(args->np));
> +     if (!smmu) {
> +             dev_err(dev, "Could not find smmu device!\n");
> +             return -ENODEV;
> +     }
> +
> +     if (args->args_count > 0)
> +             fwid |= (u16)args->args[0];
> +
> +     if (args->args_count > 1)
> +             fwid |= (u16)args->args[1] << SMR_MASK_SHIFT;
> +     else if (!of_property_read_u32(args->np, "stream-match-mask", &mask))
> +             fwid |= (u16)mask << SMR_MASK_SHIFT;
> +     dev_dbg(dev, "%s fwid:%08x mask:%08x args_count:%d\n",
> +                        args->np->full_name, fwid,
> +                        mask, args->args_count);

I don't understand why fwid is declared as u32 but used as a u16 below.
Shouldn't it be declared as u16 in the first place?


> +     return arm_smmu_add_generic_master_id(smmu, dev, (u16)fwid);
> +}
> +
> +/*
> + * Parse "iommus" information from generic bindings of platfomr master
> + * device, and then xlate to master IDs and register to SMMU device.
> + */
> +static int arm_smmu_platform_iommu_init(struct device *dev)
> +{
> +     struct of_phandle_args iommu_spec;
> +     int idx = 0, ret;
> +
> +     /*
> +      * We don't currently walk up the tree looking for a parent IOMMU.
> +      * See the `Notes:' section of
> +      * Documentation/devicetree/bindings/iommu/iommu.txt
> +      */
> +     while (!of_parse_phandle_with_args(dev->of_node, "iommus",
> +                             "#iommu-cells",
> +                             idx, &iommu_spec)) {
> +             ret = arm_smmu_of_xlate(dev, &iommu_spec);
> +             if (ret) {
> +                     dev_err(dev,
> +                             "Do of_xlate for platform device failed, 
> err=%d\n", ret);
                 ^ remove Do

> +                     return ret;
> +             }
> +
> +             idx++;
> +     }
> +
> +     /*
> +      * Return 0 if the device is not protected to follow the behavior
> +      * of PCI add device.
> +      */
> +     return 0;
> +}
> +
>  static int arm_smmu_xen_add_device(u8 devfn, struct device*dev)
>  {
> +     int ret;
> +
> +     /*
> +      * iommu_add_dt_device() is only called for the hardware domain.
> +      * If the SMMU is using generic bindings, we should parse and
> +      * register Master IDs while this function had been invoked.
> +      */
> +     if (using_generic_binding) {
> +             ret = arm_smmu_platform_iommu_init(dev);
> +             if (ret)
> +                     return ret;
> +     }
> +
>       if (dt_device_is_protected(dev->of_node)) {
>               if (!dev->archdata.iommu) {
>                       dev->archdata.iommu = xzalloc(struct 
> arm_smmu_xen_device);
> @@ -2832,7 +2974,7 @@ static const struct iommu_ops arm_smmu_iommu_ops = {
>      .unmap_page = arm_smmu_unmap_page,
>  };
>  
> -static __init const struct arm_smmu_device *find_smmu(const struct device 
> *dev)
> +static struct arm_smmu_device *find_smmu(const struct device *dev)
>  {
>       struct arm_smmu_device *smmu;
>       bool found = false;

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

 


Rackspace

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