Message ID | 20191209180514.272727-9-jean-philippe@linaro.org (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | iommu: Add PASID support to Arm SMMUv3 | expand |
Hi Jean, On 12/9/19 7:05 PM, Jean-Philippe Brucker wrote: s/Propate/Propagate in the commit title. > Now that we support substream IDs, initialize s1cdmax with the number of > SSID bits supported by a master and the SMMU. > > Context descriptor tables are allocated once for the first master > attached to a domain. Therefore attaching multiple devices with > different SSID sizes is tricky, and we currently don't support it. > > As a future improvement it would be nice to at least support attaching a > SSID-capable device to a domain that isn't using SSID, by reallocating > the SSID table. Isn't that use case relevant (I mean using both devices in a non SSID use case). For platform devices you can work this around with FW but for PCI devices? This would allow supporting a SSID-capable device that > is in the same IOMMU group as a bridge, for example. Varying SSID size > is less of a concern, since the PCIe specification "highly recommends" > that devices supporting PASID implement all 20 bits of it. > > Signed-off-by: Jean-Philippe Brucker <jean-philippe@linaro.org> Besides, Reviewed-by: Eric Auger <eric.auger@redhat.com> Thanks Eric > --- > drivers/iommu/arm-smmu-v3.c | 19 ++++++++++++++++--- > 1 file changed, 16 insertions(+), 3 deletions(-) > > diff --git a/drivers/iommu/arm-smmu-v3.c b/drivers/iommu/arm-smmu-v3.c > index a01071123c34..f260abadde6d 100644 > --- a/drivers/iommu/arm-smmu-v3.c > +++ b/drivers/iommu/arm-smmu-v3.c > @@ -2279,6 +2279,7 @@ static void arm_smmu_domain_free(struct iommu_domain *domain) > } > > static int arm_smmu_domain_finalise_s1(struct arm_smmu_domain *smmu_domain, > + struct arm_smmu_master *master, > struct io_pgtable_cfg *pgtbl_cfg) > { > int ret; > @@ -2290,6 +2291,8 @@ static int arm_smmu_domain_finalise_s1(struct arm_smmu_domain *smmu_domain, > if (asid < 0) > return asid; > > + cfg->s1cdmax = master->ssid_bits; > + > ret = arm_smmu_alloc_cd_tables(smmu_domain); > if (ret) > goto out_free_asid; > @@ -2306,6 +2309,7 @@ static int arm_smmu_domain_finalise_s1(struct arm_smmu_domain *smmu_domain, > } > > static int arm_smmu_domain_finalise_s2(struct arm_smmu_domain *smmu_domain, > + struct arm_smmu_master *master, > struct io_pgtable_cfg *pgtbl_cfg) > { > int vmid; > @@ -2322,7 +2326,8 @@ static int arm_smmu_domain_finalise_s2(struct arm_smmu_domain *smmu_domain, > return 0; > } > > -static int arm_smmu_domain_finalise(struct iommu_domain *domain) > +static int arm_smmu_domain_finalise(struct iommu_domain *domain, > + struct arm_smmu_master *master) > { > int ret; > unsigned long ias, oas; > @@ -2330,6 +2335,7 @@ static int arm_smmu_domain_finalise(struct iommu_domain *domain) > struct io_pgtable_cfg pgtbl_cfg; > struct io_pgtable_ops *pgtbl_ops; > int (*finalise_stage_fn)(struct arm_smmu_domain *, > + struct arm_smmu_master *, > struct io_pgtable_cfg *); > struct arm_smmu_domain *smmu_domain = to_smmu_domain(domain); > struct arm_smmu_device *smmu = smmu_domain->smmu; > @@ -2384,7 +2390,7 @@ static int arm_smmu_domain_finalise(struct iommu_domain *domain) > domain->geometry.aperture_end = (1UL << pgtbl_cfg.ias) - 1; > domain->geometry.force_aperture = true; > > - ret = finalise_stage_fn(smmu_domain, &pgtbl_cfg); > + ret = finalise_stage_fn(smmu_domain, master, &pgtbl_cfg); > if (ret < 0) { > free_io_pgtable_ops(pgtbl_ops); > return ret; > @@ -2537,7 +2543,7 @@ static int arm_smmu_attach_dev(struct iommu_domain *domain, struct device *dev) > > if (!smmu_domain->smmu) { > smmu_domain->smmu = smmu; > - ret = arm_smmu_domain_finalise(domain); > + ret = arm_smmu_domain_finalise(domain, master); > if (ret) { > smmu_domain->smmu = NULL; > goto out_unlock; > @@ -2549,6 +2555,13 @@ static int arm_smmu_attach_dev(struct iommu_domain *domain, struct device *dev) > dev_name(smmu->dev)); > ret = -ENXIO; > goto out_unlock; > + } else if (smmu_domain->stage == ARM_SMMU_DOMAIN_S1 && > + master->ssid_bits != smmu_domain->s1_cfg.s1cdmax) { > + dev_err(dev, > + "cannot attach to incompatible domain (%u SSID bits != %u)\n", > + smmu_domain->s1_cfg.s1cdmax, master->ssid_bits); > + ret = -EINVAL; > + goto out_unlock; > } > > master->domain = smmu_domain; >
On Tue, Dec 17, 2019 at 06:07:26PM +0100, Auger Eric wrote: > Hi Jean, > > On 12/9/19 7:05 PM, Jean-Philippe Brucker wrote: > > s/Propate/Propagate in the commit title. > > Now that we support substream IDs, initialize s1cdmax with the number of > > SSID bits supported by a master and the SMMU. > > > > Context descriptor tables are allocated once for the first master > > attached to a domain. Therefore attaching multiple devices with > > different SSID sizes is tricky, and we currently don't support it. > > > > As a future improvement it would be nice to at least support attaching a > > SSID-capable device to a domain that isn't using SSID, by reallocating > > the SSID table. > Isn't that use case relevant (I mean using both devices in a non SSID > use case). For platform devices you can work this around with FW but for > PCI devices? Normally each device gets its own domain. Especially since PASID is a PCI Express capability, I expect them to be properly isolated with ACS, each with its own IOMMU group. So I don't think this is too relevant for the moment, it would be a quirk for a broken system. Thanks, Jean
Hi Jean, On 12/18/19 5:08 PM, Jean-Philippe Brucker wrote: > On Tue, Dec 17, 2019 at 06:07:26PM +0100, Auger Eric wrote: >> Hi Jean, >> >> On 12/9/19 7:05 PM, Jean-Philippe Brucker wrote: >> >> s/Propate/Propagate in the commit title. >>> Now that we support substream IDs, initialize s1cdmax with the number of >>> SSID bits supported by a master and the SMMU. >>> >>> Context descriptor tables are allocated once for the first master >>> attached to a domain. Therefore attaching multiple devices with >>> different SSID sizes is tricky, and we currently don't support it. >>> >>> As a future improvement it would be nice to at least support attaching a >>> SSID-capable device to a domain that isn't using SSID, by reallocating >>> the SSID table. >> Isn't that use case relevant (I mean using both devices in a non SSID >> use case). For platform devices you can work this around with FW but for >> PCI devices? > > Normally each device gets its own domain. Especially since PASID is a PCI > Express capability, I expect them to be properly isolated with ACS, each > with its own IOMMU group. So I don't think this is too relevant for the > moment, it would be a quirk for a broken system. OK Eric > > Thanks, > Jean >
diff --git a/drivers/iommu/arm-smmu-v3.c b/drivers/iommu/arm-smmu-v3.c index a01071123c34..f260abadde6d 100644 --- a/drivers/iommu/arm-smmu-v3.c +++ b/drivers/iommu/arm-smmu-v3.c @@ -2279,6 +2279,7 @@ static void arm_smmu_domain_free(struct iommu_domain *domain) } static int arm_smmu_domain_finalise_s1(struct arm_smmu_domain *smmu_domain, + struct arm_smmu_master *master, struct io_pgtable_cfg *pgtbl_cfg) { int ret; @@ -2290,6 +2291,8 @@ static int arm_smmu_domain_finalise_s1(struct arm_smmu_domain *smmu_domain, if (asid < 0) return asid; + cfg->s1cdmax = master->ssid_bits; + ret = arm_smmu_alloc_cd_tables(smmu_domain); if (ret) goto out_free_asid; @@ -2306,6 +2309,7 @@ static int arm_smmu_domain_finalise_s1(struct arm_smmu_domain *smmu_domain, } static int arm_smmu_domain_finalise_s2(struct arm_smmu_domain *smmu_domain, + struct arm_smmu_master *master, struct io_pgtable_cfg *pgtbl_cfg) { int vmid; @@ -2322,7 +2326,8 @@ static int arm_smmu_domain_finalise_s2(struct arm_smmu_domain *smmu_domain, return 0; } -static int arm_smmu_domain_finalise(struct iommu_domain *domain) +static int arm_smmu_domain_finalise(struct iommu_domain *domain, + struct arm_smmu_master *master) { int ret; unsigned long ias, oas; @@ -2330,6 +2335,7 @@ static int arm_smmu_domain_finalise(struct iommu_domain *domain) struct io_pgtable_cfg pgtbl_cfg; struct io_pgtable_ops *pgtbl_ops; int (*finalise_stage_fn)(struct arm_smmu_domain *, + struct arm_smmu_master *, struct io_pgtable_cfg *); struct arm_smmu_domain *smmu_domain = to_smmu_domain(domain); struct arm_smmu_device *smmu = smmu_domain->smmu; @@ -2384,7 +2390,7 @@ static int arm_smmu_domain_finalise(struct iommu_domain *domain) domain->geometry.aperture_end = (1UL << pgtbl_cfg.ias) - 1; domain->geometry.force_aperture = true; - ret = finalise_stage_fn(smmu_domain, &pgtbl_cfg); + ret = finalise_stage_fn(smmu_domain, master, &pgtbl_cfg); if (ret < 0) { free_io_pgtable_ops(pgtbl_ops); return ret; @@ -2537,7 +2543,7 @@ static int arm_smmu_attach_dev(struct iommu_domain *domain, struct device *dev) if (!smmu_domain->smmu) { smmu_domain->smmu = smmu; - ret = arm_smmu_domain_finalise(domain); + ret = arm_smmu_domain_finalise(domain, master); if (ret) { smmu_domain->smmu = NULL; goto out_unlock; @@ -2549,6 +2555,13 @@ static int arm_smmu_attach_dev(struct iommu_domain *domain, struct device *dev) dev_name(smmu->dev)); ret = -ENXIO; goto out_unlock; + } else if (smmu_domain->stage == ARM_SMMU_DOMAIN_S1 && + master->ssid_bits != smmu_domain->s1_cfg.s1cdmax) { + dev_err(dev, + "cannot attach to incompatible domain (%u SSID bits != %u)\n", + smmu_domain->s1_cfg.s1cdmax, master->ssid_bits); + ret = -EINVAL; + goto out_unlock; } master->domain = smmu_domain;
Now that we support substream IDs, initialize s1cdmax with the number of SSID bits supported by a master and the SMMU. Context descriptor tables are allocated once for the first master attached to a domain. Therefore attaching multiple devices with different SSID sizes is tricky, and we currently don't support it. As a future improvement it would be nice to at least support attaching a SSID-capable device to a domain that isn't using SSID, by reallocating the SSID table. This would allow supporting a SSID-capable device that is in the same IOMMU group as a bridge, for example. Varying SSID size is less of a concern, since the PCIe specification "highly recommends" that devices supporting PASID implement all 20 bits of it. Signed-off-by: Jean-Philippe Brucker <jean-philippe@linaro.org> --- drivers/iommu/arm-smmu-v3.c | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-)