From: Jason Gunthorpe <jgg@nvidia.com>
If a VM wants to toggle EATS off at the same time as changing the CFG, the
hypervisor will see EATS change to 0 and insert a V=0 breaking update into
the STE even though the VM did not ask for that.
In bare metal, EATS is ignored by CFG=ABORT/BYPASS, which is why this does
not cause a problem until we have nested where CFG is always a variation of
S2 trans that does use EATS.
Relax the rules for EATS sequencing, we don't need it to be exact because
the enclosing code will always disable ATS at the PCI device if we are
changing EATS. This ensures there are no ATS transactions that can race
with an EATS change so we don't need to carefully sequence these bits.
Fixes: 1e8be08d1c91 ("iommu/arm-smmu-v3: Support IOMMU_DOMAIN_NESTED")
Cc: stable@vger.kernel.org
Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
Reviewed-by: Shuai Xue <xueshuai@linux.alibaba.com>
Signed-off-by: Nicolin Chen <nicolinc@nvidia.com>
---
drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c | 18 ++++++++++++++++++
1 file changed, 18 insertions(+)
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 ccd6357fa5a8..58008fe94ab3 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
@@ -1096,6 +1096,24 @@ void arm_smmu_get_ste_update_safe(const __le64 *cur, const __le64 *target,
* fault records even when MEV == 0.
*/
safe_bits[1] |= cpu_to_le64(STRTAB_STE_1_MEV);
+
+ /*
+ * When a STE comes to change EATS the sequencing code in the attach
+ * logic already will have the PCI cap for ATS disabled. Thus at this
+ * moment we can expect that the device will not generate ATS queries
+ * and so we don't care about the sequencing of EATS. The purpose of
+ * EATS is to protect the system from hostile untrusted devices that
+ * issue ATS when the PCI config space is disabled. However, if EATS
+ * is being changed then we already must be trusting the device since
+ * the EATS security block is being disabled.
+ *
+ * Note: Since we moved the EATS update to the first phase, changing
+ * S2S and EATS might transiently set S2S=1 and EATS=1, resulting in
+ * a bad STE. See "5.2 Stream Table Entry". In such a case, we can't
+ * do a hitless update.
+ */
+ if (!((cur[2] | target[2]) & cpu_to_le64(STRTAB_STE_2_S2S)))
+ safe_bits[1] |= cpu_to_le64(STRTAB_STE_1_EATS);
}
EXPORT_SYMBOL_IF_KUNIT(arm_smmu_get_ste_update_safe);
--
2.43.0
On Mon, Jan 12, 2026 at 12:20:16PM -0800, Nicolin Chen wrote:
> From: Jason Gunthorpe <jgg@nvidia.com>
>
> If a VM wants to toggle EATS off at the same time as changing the CFG, the
> hypervisor will see EATS change to 0 and insert a V=0 breaking update into
> the STE even though the VM did not ask for that.
>
> In bare metal, EATS is ignored by CFG=ABORT/BYPASS, which is why this does
> not cause a problem until we have nested where CFG is always a variation of
> S2 trans that does use EATS.
>
> Relax the rules for EATS sequencing, we don't need it to be exact because
> the enclosing code will always disable ATS at the PCI device if we are
> changing EATS. This ensures there are no ATS transactions that can race
> with an EATS change so we don't need to carefully sequence these bits.
>
> Fixes: 1e8be08d1c91 ("iommu/arm-smmu-v3: Support IOMMU_DOMAIN_NESTED")
> Cc: stable@vger.kernel.org
> Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
> Reviewed-by: Shuai Xue <xueshuai@linux.alibaba.com>
> Signed-off-by: Nicolin Chen <nicolinc@nvidia.com>
> ---
> drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c | 18 ++++++++++++++++++
> 1 file changed, 18 insertions(+)
>
> 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 ccd6357fa5a8..58008fe94ab3 100644
> --- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
> +++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
> @@ -1096,6 +1096,24 @@ void arm_smmu_get_ste_update_safe(const __le64 *cur, const __le64 *target,
> * fault records even when MEV == 0.
> */
> safe_bits[1] |= cpu_to_le64(STRTAB_STE_1_MEV);
> +
> + /*
> + * When a STE comes to change EATS the sequencing code in the attach
> + * logic already will have the PCI cap for ATS disabled. Thus at this
> + * moment we can expect that the device will not generate ATS queries
> + * and so we don't care about the sequencing of EATS. The purpose of
> + * EATS is to protect the system from hostile untrusted devices that
> + * issue ATS when the PCI config space is disabled. However, if EATS
> + * is being changed then we already must be trusting the device since
> + * the EATS security block is being disabled.
> + *
> + * Note: Since we moved the EATS update to the first phase, changing
> + * S2S and EATS might transiently set S2S=1 and EATS=1, resulting in
> + * a bad STE. See "5.2 Stream Table Entry". In such a case, we can't
> + * do a hitless update.
> + */
> + if (!((cur[2] | target[2]) & cpu_to_le64(STRTAB_STE_2_S2S)))
> + safe_bits[1] |= cpu_to_le64(STRTAB_STE_1_EATS);
I understand what we're trying to do here but isn't this implicitly
saying it is safe to transition hitlessly to any non-zero EATS value,
including S1CHK or RSVD. S1CHK might have other config dependencies?
> }
> EXPORT_SYMBOL_IF_KUNIT(arm_smmu_get_ste_update_safe);
>
Thanks,
Praan
On Wed, Jan 14, 2026 at 03:58:03PM +0000, Pranjal Shrivastava wrote: > > + > > + /* > > + * When a STE comes to change EATS the sequencing code in the attach > > + * logic already will have the PCI cap for ATS disabled. Thus at this > > + * moment we can expect that the device will not generate ATS queries > > + * and so we don't care about the sequencing of EATS. The purpose of > > + * EATS is to protect the system from hostile untrusted devices that > > + * issue ATS when the PCI config space is disabled. However, if EATS > > + * is being changed then we already must be trusting the device since > > + * the EATS security block is being disabled. > > + * > > + * Note: Since we moved the EATS update to the first phase, changing > > + * S2S and EATS might transiently set S2S=1 and EATS=1, resulting in > > + * a bad STE. See "5.2 Stream Table Entry". In such a case, we can't > > + * do a hitless update. > > + */ > > + if (!((cur[2] | target[2]) & cpu_to_le64(STRTAB_STE_2_S2S))) > > + safe_bits[1] |= cpu_to_le64(STRTAB_STE_1_EATS); > > I understand what we're trying to do here but isn't this implicitly > saying it is safe to transition hitlessly to any non-zero EATS value, > including S1CHK or RSVD. S1CHK might have other config dependencies? Will pointed this issue with S1CHK, Nicolin has a suggestion to fix it here: https://lore.kernel.org/linux-iommu/aWarF90zBqxD0Gef@Asurada-Nvidia/ It would block RSVD too. Thanks, Jason
On Wed, Jan 14, 2026 at 12:15:57PM -0400, Jason Gunthorpe wrote: > On Wed, Jan 14, 2026 at 03:58:03PM +0000, Pranjal Shrivastava wrote: > > > + > > > + /* > > > + * When a STE comes to change EATS the sequencing code in the attach > > > + * logic already will have the PCI cap for ATS disabled. Thus at this > > > + * moment we can expect that the device will not generate ATS queries > > > + * and so we don't care about the sequencing of EATS. The purpose of > > > + * EATS is to protect the system from hostile untrusted devices that > > > + * issue ATS when the PCI config space is disabled. However, if EATS > > > + * is being changed then we already must be trusting the device since > > > + * the EATS security block is being disabled. > > > + * > > > + * Note: Since we moved the EATS update to the first phase, changing > > > + * S2S and EATS might transiently set S2S=1 and EATS=1, resulting in > > > + * a bad STE. See "5.2 Stream Table Entry". In such a case, we can't > > > + * do a hitless update. > > > + */ > > > + if (!((cur[2] | target[2]) & cpu_to_le64(STRTAB_STE_2_S2S))) > > > + safe_bits[1] |= cpu_to_le64(STRTAB_STE_1_EATS); > > > > I understand what we're trying to do here but isn't this implicitly > > saying it is safe to transition hitlessly to any non-zero EATS value, > > including S1CHK or RSVD. S1CHK might have other config dependencies? > > Will pointed this issue with S1CHK, Nicolin has a suggestion to fix it here: > > https://lore.kernel.org/linux-iommu/aWarF90zBqxD0Gef@Asurada-Nvidia/ > > It would block RSVD too. > Ohh okay, sounds good then, my client dropped it somehow. I'll defer this to Will. > Thanks, > Jason Thanks, Praan
© 2016 - 2026 Red Hat, Inc.