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

Re: [PATCH v2 2/2] iommu/amd-vi: do not zero IOMMU MMIO region


  • To: Andrew Cooper <andrew.cooper3@xxxxxxxxxx>
  • From: Roger Pau Monné <roger.pau@xxxxxxxxxx>
  • Date: Wed, 6 May 2026 18:31:15 +0200
  • Arc-authentication-results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=citrix.com; dmarc=pass action=none header.from=citrix.com; dkim=pass header.d=citrix.com; arc=none
  • Arc-message-signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector10001; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1; bh=7rEEFKS9AptWT2FR6SFz8tovo4ncn9GkcQjPrfqsQT0=; b=joUiViUaKBUHB74pBXUNt78ccDgRLP8uZHhDiy4Iy1Xu9nji8cca+MQsV8nPLrsK1V6xD4U0Ijlyp5Ohg4o/1QvQ9gpRWZ742N6dc6npTM5ZA6EVVw1kVUU02SxbsH5UKLJuI0O6h5ZpU+i4TZbDBwU11Nnh+IctjF5Fc5TZtlHuTPRjS3t4GVUrLFMhHJs0QE5UDT+8w9F9yLs79D6yQbO/LY3v6foUrYQ5muBgmiJ/zdHRKpc2PzJFDJe0UypHYun4eqhzdDqVinoW7Hwn9OjdfPILec1KM/Z2WCThU/z2BPY2Vjb2UGRtuwlcKL42BMnpwTb9uRC6KgvrCQ/qLA==
  • Arc-seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=t4Rz3jmlXd+CfDz87nh5cGM2z4efY1k6FMQ8D1/Yv/+OelYB9cUO/WDaZmxfQLiPsgeX6Eo59IRHfeSOFBibeWXzuWSDb2hDXcOm6Js5juUaSSiFl4v/WhK8RjqAIcjFNbjKkiaxESyJvo4t7ORfSp2R+cZa+LYN5nQygu8Q+ND65gwGJlxPjE5XU1w31jJksTymny/Ihy7wn1omSFDOKk8OUEQHhKG49cmTxWbrY80N+ceWgs7SNhnLZm03dzjOYlOEEiSIe4eduNt0wAMp3S1Ic29aWeYe41iXiwttXfRycdAKyO49pKH08f+bW2gtEqe5GUNyqDubHetXye4P5g==
  • Authentication-results: eu.smtp.expurgate.cloud; dkim=pass header.s=selector1 header.d=citrix.com header.i="@citrix.com" header.h="From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck"
  • Authentication-results: dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=citrix.com;
  • Cc: xen-devel@xxxxxxxxxxxxxxxxxxxx, Jan Beulich <jbeulich@xxxxxxxx>, Jason Andryuk <jason.andryuk@xxxxxxx>, Teddy Astie <teddy.astie@xxxxxxxxxx>
  • Delivery-date: Wed, 06 May 2026 16:31:30 +0000
  • List-id: Xen developer discussion <xen-devel.lists.xenproject.org>

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@xxxxxxxxxx>
> > ---
> > 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.



 


Rackspace

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