lkml.org 
[lkml]   [2023]   [Aug]   [17]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
/
Date
SubjectRe: [PATCH v2] iommu/arm-smmu-v3: Allow default substream bypass with a pasid support
From
On 2023-08-17 16:20, Jason Gunthorpe wrote:
> On Wed, Aug 16, 2023 at 09:21:35PM -0700, Nicolin Chen wrote:
>> When an iommu_domain is set to IOMMU_DOMAIN_IDENTITY, the driver sets the
>> arm_smmu_domain->stage to ARM_SMMU_DOMAIN_BYPASS and skips the allocation
>> of a CD table, and then sets STRTAB_STE_0_CFG_BYPASS to the CONFIG field
>> of the STE. This works well for devices that only have one substream, i.e.
>> pasid disabled.
>>
>> With a pasid-capable device, however, there could be a use case where it
>> allows an IDENTITY domain attachment without disabling its pasid feature.
>> This requires the driver to allocate a multi-entry CD table to attach the
>> IDENTITY domain to its default substream and to configure the S1DSS filed
>> of the STE to STRTAB_STE_1_S1DSS_BYPASS. So, there is a missing link here
>> between the STE setup and an IDENTITY domain attachment.
>>
>> Add a new stage ARM_SMMU_DOMAIN_BYPASS_S1DSS to tag this configuration by
>> overriding the ARM_SMMU_DOMAIN_BYPASS if the device has pasid capability.
>> This new tag will allow the driver allocating a CD table yet skipping an
>> CD insertion from the IDENTITY domain, and setting up the STE accordingly.
>>
>> In a use case of ARM_SMMU_DOMAIN_BYPASS_S1DSS, the SHCFG field of the STE
>> should be set to STRTAB_STE_1_SHCFG_INCOMING. In other cases of having a
>> CD table, the shareability comes from a CD, not the SHCFG field: according
>> to "13.5 Summary of attribute/permission configuration fields" in the spec
>> the SHCFG field value is irrelevant. So, always configure the SHCFG field
>> of the STE to STRTAB_STE_1_SHCFG_INCOMING when a CD table is present, for
>> simplification.
>>
>> Signed-off-by: Nicolin Chen <nicolinc@nvidia.com>
>> ---
>>
>> Changelog
>> v2:
>> * Rebased on top of Michael's series reworking CD table ownership:
>> https://lore.kernel.org/all/20230816131925.2521220-1-mshavit@google.com/
>> * Added a new ARM_SMMU_DOMAIN_BYPASS_S1DSS stage to tag the use case
>> v1: https://lore.kernel.org/all/20230627033326.5236-1-nicolinc@nvidia.com/
>
> After rebasing there really shouldn't be a
> ARM_SMMU_DOMAIN_BYPASS_S1DSS. I want to get to a model where the
> identity domain is a global static, so it can't be changing depending
> on how it is attched.
>
> I continue to think that the right way to think about this is to have
> the CD table code generate the STE it wants and when doing so it will
> inspect what SSID0 is. If it is the IDENTITY domain then it fills
> s1dss / etc

Indeed, that's what I was getting at with "generalisation of
ARM_SMMU_DOMAIN_BYPASS based on s1cdmax" - just one type all the way
down to the bowels of arm_smmu_write_strtab_ent(), which then decides
whether it means touching S1DSS or Config in the given STE.

>> diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
>> index b27011b2bec9..860db4fbb995 100644
>> --- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
>> +++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
>> @@ -1271,6 +1271,7 @@ static void arm_smmu_write_strtab_ent(struct arm_smmu_master *master, u32 sid,
>> * 3. Update Config, sync
>> */
>> u64 val = le64_to_cpu(dst[0]);
>> + u8 s1dss = STRTAB_STE_1_S1DSS_SSID0;
>> bool ste_live = false;
>> struct arm_smmu_device *smmu = NULL;
>> struct arm_smmu_ctx_desc_cfg *cd_table = NULL;
>> @@ -1290,6 +1291,9 @@ static void arm_smmu_write_strtab_ent(struct arm_smmu_master *master, u32 sid,
>>
>> if (smmu_domain) {
>> switch (smmu_domain->stage) {
>> + case ARM_SMMU_DOMAIN_BYPASS_S1DSS:
>> + s1dss = STRTAB_STE_1_S1DSS_BYPASS;
>> + fallthrough;
>> case ARM_SMMU_DOMAIN_S1:
>> cd_table = &master->cd_table;
>> break;
>
> Eg, I think the code looks much nicer if the logic here is more like:
>
> if (master->cd_table.cdtab)
> arm_smmu_cd_table_get_ste(master->cd_table, &ste)
> else if (master->domain)
> arm_smmu_domain_get_ste(master->domain, &ste);
> else
> ste = not attached
>
> And you'd check in arm_smmu_cd_table_get_ste() to learn the CD
> parameters and also what SSID=0 is. If SSID=0 is IDENTITY then
> arm_smmu_cd_table_get_ste would return with S1DSS set.
>
> arm_smmu_domain_get_ste() would multiplex based on the domain type.
>
>> @@ -2435,6 +2440,16 @@ static int arm_smmu_attach_dev(struct iommu_domain *domain, struct device *dev)
>> } else if (smmu_domain->smmu != smmu)
>> ret = -EINVAL;
>>
>> + /*
>> + * When attaching an IDENTITY domain to a master with pasid capability,
>> + * the master can still enable SVA feature by allocating a multi-entry
>> + * CD table and attaching the IDENTITY domain to its default substream
>> + * that alone can be byassed using the S1DSS field of the STE.
>> + */
>> + if (smmu_domain->stage == ARM_SMMU_DOMAIN_BYPASS && master->ssid_bits &&
>> + smmu->features & ARM_SMMU_FEAT_TRANS_S1)
>> + smmu_domain->stage = ARM_SMMU_DOMAIN_BYPASS_S1DSS;
>
> Then you don't technically need to do this.
>
> Though if we can't atomically change the STE from IDENTITY to IDENTIY
> with a CD then you still have to do something here,

Strictly I think we are safe to do that - fill in all the S1* fields
while Config[0] is still 0 and they're ignored, sync, then set
Config[0]. Adding a CD table under a translation domain should be
achievable as well, since S1CDMax, S1ContextPtr and S1Fmt can all be
updated together atomically (although it's still the kind of switcheroo
where I'd be scared of a massive boulder suddenly rolling out of the
ceiling...)

> but really what we
> want is to force a CD table for all cases if PASID is enabled, and
> force DMA domains to be S2 domains as well.

Wut? No, DMA domains really want to be stage 1, for many reasons.
Implementing them with stage 2 when stage 1 isn't supported was always a
bit of a bodge, but thankfully I'm not aware of anyone ever building a
stage-2-only SMMUv3 anyway.

The most glaringly obvious one, though, is that I think people like
PASID support and SVA to actually work ;)

Thanks,
Robin.

>> mutex_unlock(&smmu_domain->init_mutex);
>> if (ret)
>> return ret;
>> @@ -2456,7 +2471,8 @@ static int arm_smmu_attach_dev(struct iommu_domain *domain, struct device *dev)
>> list_add(&master->domain_head, &smmu_domain->devices);
>> spin_unlock_irqrestore(&smmu_domain->devices_lock, flags);
>>
>> - if (smmu_domain->stage == ARM_SMMU_DOMAIN_S1) {
>> + if (smmu_domain->stage == ARM_SMMU_DOMAIN_S1 ||
>> + smmu_domain->stage == ARM_SMMU_DOMAIN_BYPASS_S1DSS) {
>> if (!master->cd_table.cdtab) {
>> ret = arm_smmu_alloc_cd_tables(master);
>> if (ret) {
>
> So more like:
>
> if (smmu_domain == IDENTIY && arm_smmu_support_ssid(dev))
> arm_smmu_alloc_cd_tables()
>
> Jason

\
 
 \ /
  Last update: 2023-08-17 18:27    [W:0.036 / U:2.496 seconds]
©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site