* [PATCH v2 0/2] iommu/amd-vi: remove zeroing of MMIO region
@ 2026-05-06 13:55 Roger Pau Monne
2026-05-06 13:55 ` [PATCH v2 1/2] iommu/amd-vi: allow disable_iommu() against non-initialized IOMMUs Roger Pau Monne
` (2 more replies)
0 siblings, 3 replies; 8+ messages in thread
From: Roger Pau Monne @ 2026-05-06 13:55 UTC (permalink / raw)
To: xen-devel
Cc: Roger Pau Monne, Jan Beulich, Andrew Cooper, Jason Andryuk,
Teddy Astie
Hello,
Unconditionally zeroing the whole IOMMU MMIO region is dangerous, at
least on an upcoming platform this does put the IOMMU in a broken state
that's not recoverable by the init procedure in Xen.
Get rid of the zeroing, and instead attempt to disable the IOMMU ahead
of enabling it.
Thanks, Roger.
Roger Pau Monne (2):
iommu/amd-vi: allow disable_iommu() against non-initialized IOMMUs
iommu/amd-vi: do not zero IOMMU MMIO region
xen/drivers/passthrough/amd/iommu_init.c | 41 +++++++++++++-----------
1 file changed, 22 insertions(+), 19 deletions(-)
--
2.53.0
^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH v2 1/2] iommu/amd-vi: allow disable_iommu() against non-initialized IOMMUs
2026-05-06 13:55 [PATCH v2 0/2] iommu/amd-vi: remove zeroing of MMIO region Roger Pau Monne
@ 2026-05-06 13:55 ` Roger Pau Monne
2026-05-06 13:55 ` [PATCH v2 2/2] iommu/amd-vi: do not zero IOMMU MMIO region Roger Pau Monne
2026-05-06 16:49 ` [PATCH v2 0/2] iommu/amd-vi: remove zeroing of " Marek Marczykowski-Górecki
2 siblings, 0 replies; 8+ messages in thread
From: Roger Pau Monne @ 2026-05-06 13:55 UTC (permalink / raw)
To: xen-devel
Cc: Roger Pau Monne, Jan Beulich, Andrew Cooper, Jason Andryuk,
Teddy Astie
Introduce a force option to disable_iommu() that allows it to disable the
IOMMU, even when ->enabled is not set. While there remove the unlikely(),
this is not a hot path anyway.
No functional change, as there are no current callers that pass force ==
true.
Signed-off-by: Roger Pau Monné <roger.pau@citrix.com>
Acked-by: Jan Beulich <jbeulich@suse.com>
---
xen/drivers/passthrough/amd/iommu_init.c | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/xen/drivers/passthrough/amd/iommu_init.c b/xen/drivers/passthrough/amd/iommu_init.c
index d77dd8511288..76ae78e5ea53 100644
--- a/xen/drivers/passthrough/amd/iommu_init.c
+++ b/xen/drivers/passthrough/amd/iommu_init.c
@@ -929,13 +929,13 @@ static void enable_iommu(struct amd_iommu *iommu)
amd_iommu_flush_all_caches(iommu);
}
-static void disable_iommu(struct amd_iommu *iommu)
+static void disable_iommu(struct amd_iommu *iommu, bool force)
{
unsigned long flags;
spin_lock_irqsave(&iommu->lock, flags);
- if ( unlikely(!iommu->enabled) )
+ if ( !iommu->enabled && !force )
goto out;
if ( !iommu->ctrl.int_cap_xt_en )
@@ -1139,7 +1139,7 @@ static void __init amd_iommu_init_cleanup(void)
iommu->ctrl.int_cap_xt_en = 0;
if ( iommu->enabled )
- disable_iommu(iommu);
+ disable_iommu(iommu, false);
else if ( iommu->mmio_base )
writeq(iommu->ctrl.raw,
iommu->mmio_base + IOMMU_CONTROL_MMIO_OFFSET);
@@ -1584,7 +1584,7 @@ void cf_check amd_iommu_crash_shutdown(void)
struct amd_iommu *iommu;
for_each_amd_iommu ( iommu )
- disable_iommu(iommu);
+ disable_iommu(iommu, false);
}
void cf_check amd_iommu_resume(void)
@@ -1598,7 +1598,7 @@ void cf_check amd_iommu_resume(void)
* To make sure that iommus have not been touched
* before re-enablement
*/
- disable_iommu(iommu);
+ disable_iommu(iommu, false);
enable_iommu(iommu);
if ( !iommu->features.flds.ia_sup )
invalidate_all = false;
--
2.53.0
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH v2 2/2] iommu/amd-vi: do not zero IOMMU MMIO region
2026-05-06 13:55 [PATCH v2 0/2] iommu/amd-vi: remove zeroing of MMIO region Roger Pau Monne
2026-05-06 13:55 ` [PATCH v2 1/2] iommu/amd-vi: allow disable_iommu() against non-initialized IOMMUs Roger Pau Monne
@ 2026-05-06 13:55 ` Roger Pau Monne
2026-05-06 16:18 ` Andrew Cooper
2026-05-06 16:49 ` [PATCH v2 0/2] iommu/amd-vi: remove zeroing of " Marek Marczykowski-Górecki
2 siblings, 1 reply; 8+ messages in thread
From: Roger Pau Monne @ 2026-05-06 13:55 UTC (permalink / raw)
To: xen-devel
Cc: Roger Pau Monne, Jan Beulich, Andrew Cooper, Jason Andryuk,
Teddy Astie
Attempting to memset the whole IOMMU MMIO region to zero is dangerous to
say the least. We don't know what registers might be there, nor which
values might be safe for those registers. On a forthcoming platform doing
the zeroing of the MMIO region does put the IOMMU in a broken state, which
is not recoverable by the IOMMU initialization procedure in Xen.
Instead attempt to forcefully disable the IOMMU ahead of enabling it. Fold
map_iommu_mmio_region() into it's only caller, as the function body is just
an ioremap() call after the removal of the memset().
Fixes: 0700c962ac2d ("Add AMD IOMMU support into hypervisor")
Signed-off-by: Roger Pau Monné <roger.pau@citrix.com>
---
Changes since v1:
- Zero the control register after calling disable_iommu().
- Print a warning message if the IOMMU is handed enabled to Xen from
firmware.
- Fix commit log grammar issues.
---
xen/drivers/passthrough/amd/iommu_init.c | 31 +++++++++++++-----------
1 file changed, 17 insertions(+), 14 deletions(-)
diff --git a/xen/drivers/passthrough/amd/iommu_init.c b/xen/drivers/passthrough/amd/iommu_init.c
index 76ae78e5ea53..ffc041211fb5 100644
--- a/xen/drivers/passthrough/amd/iommu_init.c
+++ b/xen/drivers/passthrough/amd/iommu_init.c
@@ -42,18 +42,6 @@ static bool iommu_has_ht_flag(struct amd_iommu *iommu, u8 mask)
return iommu->ht_flags & mask;
}
-static int __init map_iommu_mmio_region(struct amd_iommu *iommu)
-{
- iommu->mmio_base = ioremap(iommu->mmio_base_phys,
- IOMMU_MMIO_REGION_LENGTH);
- if ( !iommu->mmio_base )
- return -ENOMEM;
-
- memset(iommu->mmio_base, 0, IOMMU_MMIO_REGION_LENGTH);
-
- return 0;
-}
-
static void __init unmap_iommu_mmio_region(struct amd_iommu *iommu)
{
if ( iommu->mmio_base )
@@ -1367,11 +1355,14 @@ static int __init amd_iommu_prepare_one(struct amd_iommu *iommu)
{
int rc = alloc_ivrs_mappings(iommu->sbdf.seg);
- if ( !rc )
- rc = map_iommu_mmio_region(iommu);
if ( rc )
return rc;
+ iommu->mmio_base = ioremap(iommu->mmio_base_phys,
+ IOMMU_MMIO_REGION_LENGTH);
+ if ( !iommu->mmio_base )
+ return -ENOMEM;
+
get_iommu_features(iommu);
/*
@@ -1381,6 +1372,18 @@ static int __init amd_iommu_prepare_one(struct amd_iommu *iommu)
if ( amd_iommu_max_paging_mode < amd_iommu_min_paging_mode )
return -ERANGE;
+ /* Read current control register and forcefully disable the IOMMU. */
+ iommu->ctrl.raw = readq(iommu->mmio_base + IOMMU_CONTROL_MMIO_OFFSET);
+ if ( iommu->ctrl.iommu_en )
+ printk(XENLOG_WARNING
+ "AMD-Vi: IOMMU %pp enabled by firmware (%016lx)\n",
+ &iommu->sbdf, iommu->ctrl.raw);
+ disable_iommu(iommu, true);
+
+ /* With the IOMMU disabled zero the control register. */
+ iommu->ctrl.raw = 0;
+ writeq(0, iommu->mmio_base + IOMMU_CONTROL_MMIO_OFFSET);
+
return 0;
}
--
2.53.0
^ permalink raw reply related [flat|nested] 8+ messages in thread
* Re: [PATCH v2 2/2] iommu/amd-vi: do not zero IOMMU MMIO region
2026-05-06 13:55 ` [PATCH v2 2/2] iommu/amd-vi: do not zero IOMMU MMIO region Roger Pau Monne
@ 2026-05-06 16:18 ` Andrew Cooper
2026-05-06 16:31 ` Roger Pau Monné
2026-05-07 7:57 ` Jan Beulich
0 siblings, 2 replies; 8+ messages in thread
From: Andrew Cooper @ 2026-05-06 16:18 UTC (permalink / raw)
To: Roger Pau Monne, xen-devel
Cc: Andrew Cooper, Jan Beulich, Jason Andryuk, Teddy Astie
On 06/05/2026 2:55 pm, Roger Pau Monne wrote:
> Attempting to memset the whole IOMMU MMIO region to zero is dangerous to
> say the least. We don't know what registers might be there, nor which
Sorry, one more. "We don't know which registers might".
> values might be safe for those registers. On a forthcoming platform doing
> the zeroing of the MMIO region does put the IOMMU in a broken state, which
> is not recoverable by the IOMMU initialization procedure in Xen.
>
> Instead attempt to forcefully disable the IOMMU ahead of enabling it. Fold
> map_iommu_mmio_region() into it's only caller, as the function body is just
> an ioremap() call after the removal of the memset().
>
> Fixes: 0700c962ac2d ("Add AMD IOMMU support into hypervisor")
> Signed-off-by: Roger Pau Monné <roger.pau@citrix.com>
> ---
> Changes since v1:
> - Zero the control register after calling disable_iommu().
> - Print a warning message if the IOMMU is handed enabled to Xen from
> firmware.
> - Fix commit log grammar issues.
> ---
> xen/drivers/passthrough/amd/iommu_init.c | 31 +++++++++++++-----------
> 1 file changed, 17 insertions(+), 14 deletions(-)
>
> diff --git a/xen/drivers/passthrough/amd/iommu_init.c b/xen/drivers/passthrough/amd/iommu_init.c
> index 76ae78e5ea53..ffc041211fb5 100644
> --- a/xen/drivers/passthrough/amd/iommu_init.c
> +++ b/xen/drivers/passthrough/amd/iommu_init.c
> @@ -42,18 +42,6 @@ static bool iommu_has_ht_flag(struct amd_iommu *iommu, u8 mask)
> return iommu->ht_flags & mask;
> }
>
> -static int __init map_iommu_mmio_region(struct amd_iommu *iommu)
> -{
> - iommu->mmio_base = ioremap(iommu->mmio_base_phys,
> - IOMMU_MMIO_REGION_LENGTH);
> - if ( !iommu->mmio_base )
> - return -ENOMEM;
> -
> - memset(iommu->mmio_base, 0, IOMMU_MMIO_REGION_LENGTH);
> -
> - return 0;
> -}
> -
> static void __init unmap_iommu_mmio_region(struct amd_iommu *iommu)
> {
> if ( iommu->mmio_base )
> @@ -1367,11 +1355,14 @@ static int __init amd_iommu_prepare_one(struct amd_iommu *iommu)
> {
> int rc = alloc_ivrs_mappings(iommu->sbdf.seg);
>
> - if ( !rc )
> - rc = map_iommu_mmio_region(iommu);
> if ( rc )
> return rc;
>
> + iommu->mmio_base = ioremap(iommu->mmio_base_phys,
> + IOMMU_MMIO_REGION_LENGTH);
> + if ( !iommu->mmio_base )
> + return -ENOMEM;
> +
> get_iommu_features(iommu);
>
> /*
> @@ -1381,6 +1372,18 @@ static int __init amd_iommu_prepare_one(struct amd_iommu *iommu)
> if ( amd_iommu_max_paging_mode < amd_iommu_min_paging_mode )
> return -ERANGE;
>
> + /* Read current control register and forcefully disable the IOMMU. */
> + iommu->ctrl.raw = readq(iommu->mmio_base + IOMMU_CONTROL_MMIO_OFFSET);
> + if ( iommu->ctrl.iommu_en )
> + printk(XENLOG_WARNING
> + "AMD-Vi: IOMMU %pp enabled by firmware (%016lx)\n",
> + &iommu->sbdf, iommu->ctrl.raw);
> + disable_iommu(iommu, true);
> +
> + /* With the IOMMU disabled zero the control register. */
> + iommu->ctrl.raw = 0;
> + writeq(0, iommu->mmio_base + IOMMU_CONTROL_MMIO_OFFSET);
> +
> return 0;
> }
>
I don't think calling disable_iommu() is a good thing here.
It's just a cascade of clearing one/few bits in ctrl at a time, but is
is added unconditionally so that's 5 UC stores writing 0's to the same
register in the common case.
I think this logic wants to be:
@@ -1381,6 +1372,18 @@ static int __init amd_iommu_prepare_one(struct amd_iommu *iommu)
if ( amd_iommu_max_paging_mode < amd_iommu_min_paging_mode )
return -ERANGE;
+ /* Check if the IOMMU is active, and disable. */
+ iommu->ctrl.raw = readq(iommu->mmio_base + IOMMU_CONTROL_MMIO_OFFSET);
+ if ( iommu->ctrl.iommu_en )
+ {
+ printk(XENLOG_WARNING
+ "AMD-Vi: IOMMU %pp enabled by firmware (ctrl %016lx)\n",
+ &iommu->sbdf, iommu->ctrl.raw);
+
+ iommu->ctrl.raw = 0;
+ writeq(0, iommu->mmio_base + IOMMU_CONTROL_MMIO_OFFSET);
+ }
+
return 0;
}
which has the advantage that it's closer to the current behaviour, and
therefore arguably a safer backport.
The only thing that disable_iommu() does which isn't editing the control
register is playing with the PCI MSI enable bit, but that really doesn't
matter when we clear ctrl.int_cap_xt_en. (And in fact, that path is
buggy because it clears MSI enable without inhibiting interrupt
generation, which architecturally will turn into legacy line interrupt
to deal with.)
We're just about to re-set everything up, so everything's going to get
re-enabled.
In the commit message, I think it's worth highlighting that zeroing the
control register is the current behaviour, and this will need revisiting
in order to support Preboot DMA Protection.
Or alternatively, would you like me to submit a patch? (Happy either way.)
~Andrew
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH v2 2/2] iommu/amd-vi: do not zero IOMMU MMIO region
2026-05-06 16:18 ` Andrew Cooper
@ 2026-05-06 16:31 ` Roger Pau Monné
2026-05-07 7:57 ` Jan Beulich
1 sibling, 0 replies; 8+ messages in thread
From: Roger Pau Monné @ 2026-05-06 16:31 UTC (permalink / raw)
To: Andrew Cooper; +Cc: xen-devel, Jan Beulich, Jason Andryuk, Teddy Astie
On Wed, May 06, 2026 at 05:18:40PM +0100, Andrew Cooper wrote:
> On 06/05/2026 2:55 pm, Roger Pau Monne wrote:
> > Attempting to memset the whole IOMMU MMIO region to zero is dangerous to
> > say the least. We don't know what registers might be there, nor which
>
> Sorry, one more. "We don't know which registers might".
>
> > values might be safe for those registers. On a forthcoming platform doing
> > the zeroing of the MMIO region does put the IOMMU in a broken state, which
> > is not recoverable by the IOMMU initialization procedure in Xen.
> >
> > Instead attempt to forcefully disable the IOMMU ahead of enabling it. Fold
> > map_iommu_mmio_region() into it's only caller, as the function body is just
> > an ioremap() call after the removal of the memset().
> >
> > Fixes: 0700c962ac2d ("Add AMD IOMMU support into hypervisor")
> > Signed-off-by: Roger Pau Monné <roger.pau@citrix.com>
> > ---
> > Changes since v1:
> > - Zero the control register after calling disable_iommu().
> > - Print a warning message if the IOMMU is handed enabled to Xen from
> > firmware.
> > - Fix commit log grammar issues.
> > ---
> > xen/drivers/passthrough/amd/iommu_init.c | 31 +++++++++++++-----------
> > 1 file changed, 17 insertions(+), 14 deletions(-)
> >
> > diff --git a/xen/drivers/passthrough/amd/iommu_init.c b/xen/drivers/passthrough/amd/iommu_init.c
> > index 76ae78e5ea53..ffc041211fb5 100644
> > --- a/xen/drivers/passthrough/amd/iommu_init.c
> > +++ b/xen/drivers/passthrough/amd/iommu_init.c
> > @@ -42,18 +42,6 @@ static bool iommu_has_ht_flag(struct amd_iommu *iommu, u8 mask)
> > return iommu->ht_flags & mask;
> > }
> >
> > -static int __init map_iommu_mmio_region(struct amd_iommu *iommu)
> > -{
> > - iommu->mmio_base = ioremap(iommu->mmio_base_phys,
> > - IOMMU_MMIO_REGION_LENGTH);
> > - if ( !iommu->mmio_base )
> > - return -ENOMEM;
> > -
> > - memset(iommu->mmio_base, 0, IOMMU_MMIO_REGION_LENGTH);
> > -
> > - return 0;
> > -}
> > -
> > static void __init unmap_iommu_mmio_region(struct amd_iommu *iommu)
> > {
> > if ( iommu->mmio_base )
> > @@ -1367,11 +1355,14 @@ static int __init amd_iommu_prepare_one(struct amd_iommu *iommu)
> > {
> > int rc = alloc_ivrs_mappings(iommu->sbdf.seg);
> >
> > - if ( !rc )
> > - rc = map_iommu_mmio_region(iommu);
> > if ( rc )
> > return rc;
> >
> > + iommu->mmio_base = ioremap(iommu->mmio_base_phys,
> > + IOMMU_MMIO_REGION_LENGTH);
> > + if ( !iommu->mmio_base )
> > + return -ENOMEM;
> > +
> > get_iommu_features(iommu);
> >
> > /*
> > @@ -1381,6 +1372,18 @@ static int __init amd_iommu_prepare_one(struct amd_iommu *iommu)
> > if ( amd_iommu_max_paging_mode < amd_iommu_min_paging_mode )
> > return -ERANGE;
> >
> > + /* Read current control register and forcefully disable the IOMMU. */
> > + iommu->ctrl.raw = readq(iommu->mmio_base + IOMMU_CONTROL_MMIO_OFFSET);
> > + if ( iommu->ctrl.iommu_en )
> > + printk(XENLOG_WARNING
> > + "AMD-Vi: IOMMU %pp enabled by firmware (%016lx)\n",
> > + &iommu->sbdf, iommu->ctrl.raw);
> > + disable_iommu(iommu, true);
> > +
> > + /* With the IOMMU disabled zero the control register. */
> > + iommu->ctrl.raw = 0;
> > + writeq(0, iommu->mmio_base + IOMMU_CONTROL_MMIO_OFFSET);
> > +
> > return 0;
> > }
> >
>
> I don't think calling disable_iommu() is a good thing here.
>
> It's just a cascade of clearing one/few bits in ctrl at a time, but is
> is added unconditionally so that's 5 UC stores writing 0's to the same
> register in the common case.
The approach to use disable_iommu() is because that's closer to what
Linux does in iommu_disable(), which seems to explicitly disable one
feature at a time instead of writing zero to the command register in
one go. I've been cautious in taking the same approach on Xen.
I don't mind doing a plain write of 0, let me test to ensure this is
OK.
> I think this logic wants to be:
>
> @@ -1381,6 +1372,18 @@ static int __init amd_iommu_prepare_one(struct amd_iommu *iommu)
> if ( amd_iommu_max_paging_mode < amd_iommu_min_paging_mode )
> return -ERANGE;
>
> + /* Check if the IOMMU is active, and disable. */
> + iommu->ctrl.raw = readq(iommu->mmio_base + IOMMU_CONTROL_MMIO_OFFSET);
> + if ( iommu->ctrl.iommu_en )
> + {
> + printk(XENLOG_WARNING
> + "AMD-Vi: IOMMU %pp enabled by firmware (ctrl %016lx)\n",
> + &iommu->sbdf, iommu->ctrl.raw);
> +
> + iommu->ctrl.raw = 0;
> + writeq(0, iommu->mmio_base + IOMMU_CONTROL_MMIO_OFFSET);
> + }
In your snippet above, I think we want to unconditionally set
iommu->ctrl.raw = 0, and also propagate that 0 to the register,
otherwise we will inherit set bits from whatever is currently in the
control register:
> + /* Check if the IOMMU is active, and disable. */
> + iommu->ctrl.raw = readq(iommu->mmio_base + IOMMU_CONTROL_MMIO_OFFSET);
> + if ( iommu->ctrl.iommu_en )
> + printk(XENLOG_WARNING
> + "AMD-Vi: IOMMU %pp enabled by firmware (ctrl %016lx)\n",
> + &iommu->sbdf, iommu->ctrl.raw);
> +
> + iommu->ctrl.raw = 0;
> + writeq(0, iommu->mmio_base + IOMMU_CONTROL_MMIO_OFFSET);
Thanks, Roger.
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH v2 0/2] iommu/amd-vi: remove zeroing of MMIO region
2026-05-06 13:55 [PATCH v2 0/2] iommu/amd-vi: remove zeroing of MMIO region Roger Pau Monne
2026-05-06 13:55 ` [PATCH v2 1/2] iommu/amd-vi: allow disable_iommu() against non-initialized IOMMUs Roger Pau Monne
2026-05-06 13:55 ` [PATCH v2 2/2] iommu/amd-vi: do not zero IOMMU MMIO region Roger Pau Monne
@ 2026-05-06 16:49 ` Marek Marczykowski-Górecki
2026-05-06 16:55 ` Roger Pau Monné
2 siblings, 1 reply; 8+ messages in thread
From: Marek Marczykowski-Górecki @ 2026-05-06 16:49 UTC (permalink / raw)
To: Roger Pau Monne
Cc: xen-devel, Jan Beulich, Andrew Cooper, Jason Andryuk, Teddy Astie
[-- Attachment #1: Type: text/plain, Size: 735 bytes --]
On Wed, May 06, 2026 at 03:55:12PM +0200, Roger Pau Monne wrote:
> Hello,
>
> Unconditionally zeroing the whole IOMMU MMIO region is dangerous, at
> least on an upcoming platform this does put the IOMMU in a broken state
> that's not recoverable by the init procedure in Xen.
>
> Get rid of the zeroing, and instead attempt to disable the IOMMU ahead
> of enabling it.
Just to mention it here, while this looks like a step in the right
direction, even better would be to not disable IOMMU at boot, but
reconfigure it - to preserve uninterrupted protection when boot time DMA
protection is enabled in firmware. But that's definitely more work...
--
Best Regards,
Marek Marczykowski-Górecki
Invisible Things Lab
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH v2 0/2] iommu/amd-vi: remove zeroing of MMIO region
2026-05-06 16:49 ` [PATCH v2 0/2] iommu/amd-vi: remove zeroing of " Marek Marczykowski-Górecki
@ 2026-05-06 16:55 ` Roger Pau Monné
0 siblings, 0 replies; 8+ messages in thread
From: Roger Pau Monné @ 2026-05-06 16:55 UTC (permalink / raw)
To: Marek Marczykowski-Górecki
Cc: xen-devel, Jan Beulich, Andrew Cooper, Jason Andryuk, Teddy Astie
On Wed, May 06, 2026 at 06:49:47PM +0200, Marek Marczykowski-Górecki wrote:
> On Wed, May 06, 2026 at 03:55:12PM +0200, Roger Pau Monne wrote:
> > Hello,
> >
> > Unconditionally zeroing the whole IOMMU MMIO region is dangerous, at
> > least on an upcoming platform this does put the IOMMU in a broken state
> > that's not recoverable by the init procedure in Xen.
> >
> > Get rid of the zeroing, and instead attempt to disable the IOMMU ahead
> > of enabling it.
>
> Just to mention it here, while this looks like a step in the right
> direction, even better would be to not disable IOMMU at boot, but
> reconfigure it - to preserve uninterrupted protection when boot time DMA
> protection is enabled in firmware. But that's definitely more work...
Yes, we are aware of this. But IMO booting with the IOMMU enabled
will be a new feature, this is strictly a fix that we can "safely"
backport to stable branches to deal with broken hardware.
Thanks, Roger.
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH v2 2/2] iommu/amd-vi: do not zero IOMMU MMIO region
2026-05-06 16:18 ` Andrew Cooper
2026-05-06 16:31 ` Roger Pau Monné
@ 2026-05-07 7:57 ` Jan Beulich
1 sibling, 0 replies; 8+ messages in thread
From: Jan Beulich @ 2026-05-07 7:57 UTC (permalink / raw)
To: Andrew Cooper; +Cc: Jason Andryuk, Teddy Astie, Roger Pau Monne, xen-devel
On 06.05.2026 18:18, Andrew Cooper wrote:
> On 06/05/2026 2:55 pm, Roger Pau Monne wrote:
>> Attempting to memset the whole IOMMU MMIO region to zero is dangerous to
>> say the least. We don't know what registers might be there, nor which
>
> Sorry, one more. "We don't know which registers might".
>
>> values might be safe for those registers. On a forthcoming platform doing
>> the zeroing of the MMIO region does put the IOMMU in a broken state, which
>> is not recoverable by the IOMMU initialization procedure in Xen.
>>
>> Instead attempt to forcefully disable the IOMMU ahead of enabling it. Fold
>> map_iommu_mmio_region() into it's only caller, as the function body is just
>> an ioremap() call after the removal of the memset().
>>
>> Fixes: 0700c962ac2d ("Add AMD IOMMU support into hypervisor")
>> Signed-off-by: Roger Pau Monné <roger.pau@citrix.com>
>> ---
>> Changes since v1:
>> - Zero the control register after calling disable_iommu().
>> - Print a warning message if the IOMMU is handed enabled to Xen from
>> firmware.
>> - Fix commit log grammar issues.
>> ---
>> xen/drivers/passthrough/amd/iommu_init.c | 31 +++++++++++++-----------
>> 1 file changed, 17 insertions(+), 14 deletions(-)
>>
>> diff --git a/xen/drivers/passthrough/amd/iommu_init.c b/xen/drivers/passthrough/amd/iommu_init.c
>> index 76ae78e5ea53..ffc041211fb5 100644
>> --- a/xen/drivers/passthrough/amd/iommu_init.c
>> +++ b/xen/drivers/passthrough/amd/iommu_init.c
>> @@ -42,18 +42,6 @@ static bool iommu_has_ht_flag(struct amd_iommu *iommu, u8 mask)
>> return iommu->ht_flags & mask;
>> }
>>
>> -static int __init map_iommu_mmio_region(struct amd_iommu *iommu)
>> -{
>> - iommu->mmio_base = ioremap(iommu->mmio_base_phys,
>> - IOMMU_MMIO_REGION_LENGTH);
>> - if ( !iommu->mmio_base )
>> - return -ENOMEM;
>> -
>> - memset(iommu->mmio_base, 0, IOMMU_MMIO_REGION_LENGTH);
>> -
>> - return 0;
>> -}
>> -
>> static void __init unmap_iommu_mmio_region(struct amd_iommu *iommu)
>> {
>> if ( iommu->mmio_base )
>> @@ -1367,11 +1355,14 @@ static int __init amd_iommu_prepare_one(struct amd_iommu *iommu)
>> {
>> int rc = alloc_ivrs_mappings(iommu->sbdf.seg);
>>
>> - if ( !rc )
>> - rc = map_iommu_mmio_region(iommu);
>> if ( rc )
>> return rc;
>>
>> + iommu->mmio_base = ioremap(iommu->mmio_base_phys,
>> + IOMMU_MMIO_REGION_LENGTH);
>> + if ( !iommu->mmio_base )
>> + return -ENOMEM;
>> +
>> get_iommu_features(iommu);
>>
>> /*
>> @@ -1381,6 +1372,18 @@ static int __init amd_iommu_prepare_one(struct amd_iommu *iommu)
>> if ( amd_iommu_max_paging_mode < amd_iommu_min_paging_mode )
>> return -ERANGE;
>>
>> + /* Read current control register and forcefully disable the IOMMU. */
>> + iommu->ctrl.raw = readq(iommu->mmio_base + IOMMU_CONTROL_MMIO_OFFSET);
>> + if ( iommu->ctrl.iommu_en )
>> + printk(XENLOG_WARNING
>> + "AMD-Vi: IOMMU %pp enabled by firmware (%016lx)\n",
>> + &iommu->sbdf, iommu->ctrl.raw);
>> + disable_iommu(iommu, true);
>> +
>> + /* With the IOMMU disabled zero the control register. */
>> + iommu->ctrl.raw = 0;
>> + writeq(0, iommu->mmio_base + IOMMU_CONTROL_MMIO_OFFSET);
>> +
>> return 0;
>> }
>>
>
> I don't think calling disable_iommu() is a good thing here.
>
> It's just a cascade of clearing one/few bits in ctrl at a time, but is
> is added unconditionally so that's 5 UC stores writing 0's to the same
> register in the common case.
>
> I think this logic wants to be:
>
> @@ -1381,6 +1372,18 @@ static int __init amd_iommu_prepare_one(struct amd_iommu *iommu)
> if ( amd_iommu_max_paging_mode < amd_iommu_min_paging_mode )
> return -ERANGE;
>
> + /* Check if the IOMMU is active, and disable. */
> + iommu->ctrl.raw = readq(iommu->mmio_base + IOMMU_CONTROL_MMIO_OFFSET);
> + if ( iommu->ctrl.iommu_en )
> + {
> + printk(XENLOG_WARNING
> + "AMD-Vi: IOMMU %pp enabled by firmware (ctrl %016lx)\n",
> + &iommu->sbdf, iommu->ctrl.raw);
> +
> + iommu->ctrl.raw = 0;
> + writeq(0, iommu->mmio_base + IOMMU_CONTROL_MMIO_OFFSET);
> + }
> +
> return 0;
> }
>
>
>
> which has the advantage that it's closer to the current behaviour, and
> therefore arguably a safer backport.
>
> The only thing that disable_iommu() does which isn't editing the control
> register is playing with the PCI MSI enable bit, but that really doesn't
> matter when we clear ctrl.int_cap_xt_en. (And in fact, that path is
> buggy because it clears MSI enable without inhibiting interrupt
> generation, which architecturally will turn into legacy line interrupt
> to deal with.)
Except there's no line interrupt associated with this?
Jan
^ permalink raw reply [flat|nested] 8+ messages in thread
end of thread, other threads:[~2026-05-07 7:57 UTC | newest]
Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-05-06 13:55 [PATCH v2 0/2] iommu/amd-vi: remove zeroing of MMIO region Roger Pau Monne
2026-05-06 13:55 ` [PATCH v2 1/2] iommu/amd-vi: allow disable_iommu() against non-initialized IOMMUs Roger Pau Monne
2026-05-06 13:55 ` [PATCH v2 2/2] iommu/amd-vi: do not zero IOMMU MMIO region Roger Pau Monne
2026-05-06 16:18 ` Andrew Cooper
2026-05-06 16:31 ` Roger Pau Monné
2026-05-07 7:57 ` Jan Beulich
2026-05-06 16:49 ` [PATCH v2 0/2] iommu/amd-vi: remove zeroing of " Marek Marczykowski-Górecki
2026-05-06 16:55 ` Roger Pau Monné
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.