diff mbox series

iommu/amd-vi: adjust _amd_iommu_flush_pages() to handle pseudo-domids

Message ID 20230614083236.64574-1-roger.pau@citrix.com (mailing list archive)
State New, archived
Headers show
Series iommu/amd-vi: adjust _amd_iommu_flush_pages() to handle pseudo-domids | expand

Commit Message

Roger Pau Monné June 14, 2023, 8:32 a.m. UTC
When the passed domain is DomIO iterate over the list of DomIO
assigned devices and flush each pseudo-domid found.

invalidate_all_domain_pages() does call amd_iommu_flush_all_pages()
with DomIO as a parameter, and hence the underlying
_amd_iommu_flush_pages() implementation must be capable of flushing
all pseudo-domids used by the quarantine domain logic.

While there fix invalidate_all_domain_pages() to only attempt to flush
the domains that have IOMMU enabled, otherwise the flush is pointless.

Fixes: 14dd241aad8a ('IOMMU/x86: use per-device page tables for quarantining')
Signed-off-by: Roger Pau Monné <roger.pau@citrix.com>
---
Only build tested, as I don't have an AMD system that I can do
suspend/resume on.
---
 xen/drivers/passthrough/amd/iommu_cmd.c  | 29 ++++++++++++++++++++----
 xen/drivers/passthrough/amd/iommu_init.c |  4 +++-
 2 files changed, 28 insertions(+), 5 deletions(-)

Comments

Jan Beulich June 14, 2023, 12:58 p.m. UTC | #1
On 14.06.2023 10:32, Roger Pau Monne wrote:
> When the passed domain is DomIO iterate over the list of DomIO
> assigned devices and flush each pseudo-domid found.
> 
> invalidate_all_domain_pages() does call amd_iommu_flush_all_pages()
> with DomIO as a parameter,

Does it? Since the full function is visible in the patch (because of
the "While there ..." change), it seems pretty clear that it doesn't:
for_each_domain() iterates over ordinary domains only.

> and hence the underlying
> _amd_iommu_flush_pages() implementation must be capable of flushing
> all pseudo-domids used by the quarantine domain logic.

While it didn't occur to me right away when we discussed this, it
may well be that I left alone all flushing when introducing the pseudo
domain IDs simply because no flushing would ever happen for the
quarantine domain.

> While there fix invalidate_all_domain_pages() to only attempt to flush
> the domains that have IOMMU enabled, otherwise the flush is pointless.

For the moment at least it looks to me as if this change alone wants
to go in.

Jan
Roger Pau Monné June 14, 2023, 1:23 p.m. UTC | #2
On Wed, Jun 14, 2023 at 02:58:14PM +0200, Jan Beulich wrote:
> On 14.06.2023 10:32, Roger Pau Monne wrote:
> > When the passed domain is DomIO iterate over the list of DomIO
> > assigned devices and flush each pseudo-domid found.
> > 
> > invalidate_all_domain_pages() does call amd_iommu_flush_all_pages()
> > with DomIO as a parameter,
> 
> Does it? Since the full function is visible in the patch (because of
> the "While there ..." change), it seems pretty clear that it doesn't:
> for_each_domain() iterates over ordinary domains only.

Oh, I got confused by domain_create() returning early for system
domains.

> > and hence the underlying
> > _amd_iommu_flush_pages() implementation must be capable of flushing
> > all pseudo-domids used by the quarantine domain logic.
> 
> While it didn't occur to me right away when we discussed this, it
> may well be that I left alone all flushing when introducing the pseudo
> domain IDs simply because no flushing would ever happen for the
> quarantine domain.

But the purpose of the calls to invalidate_all_devices() and
invalidate_all_domain_pages() in amd_iommu_resume() is to cover up for
the lack of Invalidate All support in the IOMMU, so flushing
pseudo-domids is also required in order to flush all possible IOMMU
state.

Note that as part of invalidate_all_devices() we do invalidate DTEs
for devices assigned to pseudo-domids, hence it seems natural that we
also flush such pseudo-domids.

> > While there fix invalidate_all_domain_pages() to only attempt to flush
> > the domains that have IOMMU enabled, otherwise the flush is pointless.
> 
> For the moment at least it looks to me as if this change alone wants
> to go in.

I would rather get the current patch with an added call to flush
dom_io in invalidate_all_domain_pages().

Thanks, Roger.
Jan Beulich June 14, 2023, 1:51 p.m. UTC | #3
On 14.06.2023 15:23, Roger Pau Monné wrote:
> On Wed, Jun 14, 2023 at 02:58:14PM +0200, Jan Beulich wrote:
>> On 14.06.2023 10:32, Roger Pau Monne wrote:
>>> When the passed domain is DomIO iterate over the list of DomIO
>>> assigned devices and flush each pseudo-domid found.
>>>
>>> invalidate_all_domain_pages() does call amd_iommu_flush_all_pages()
>>> with DomIO as a parameter,
>>
>> Does it? Since the full function is visible in the patch (because of
>> the "While there ..." change), it seems pretty clear that it doesn't:
>> for_each_domain() iterates over ordinary domains only.
> 
> Oh, I got confused by domain_create() returning early for system
> domains.
> 
>>> and hence the underlying
>>> _amd_iommu_flush_pages() implementation must be capable of flushing
>>> all pseudo-domids used by the quarantine domain logic.
>>
>> While it didn't occur to me right away when we discussed this, it
>> may well be that I left alone all flushing when introducing the pseudo
>> domain IDs simply because no flushing would ever happen for the
>> quarantine domain.
> 
> But the purpose of the calls to invalidate_all_devices() and
> invalidate_all_domain_pages() in amd_iommu_resume() is to cover up for
> the lack of Invalidate All support in the IOMMU, so flushing
> pseudo-domids is also required in order to flush all possible IOMMU
> state.
> 
> Note that as part of invalidate_all_devices() we do invalidate DTEs
> for devices assigned to pseudo-domids, hence it seems natural that we
> also flush such pseudo-domids.
> 
>>> While there fix invalidate_all_domain_pages() to only attempt to flush
>>> the domains that have IOMMU enabled, otherwise the flush is pointless.
>>
>> For the moment at least it looks to me as if this change alone wants
>> to go in.
> 
> I would rather get the current patch with an added call to flush
> dom_io in invalidate_all_domain_pages().

The question is: Is there anything that needs flushing for the
quarantine domain. Right now I'm thinking that there isn't.

Jan
diff mbox series

Patch

diff --git a/xen/drivers/passthrough/amd/iommu_cmd.c b/xen/drivers/passthrough/amd/iommu_cmd.c
index 40ddf366bb4d..ff55e3b88ae6 100644
--- a/xen/drivers/passthrough/amd/iommu_cmd.c
+++ b/xen/drivers/passthrough/amd/iommu_cmd.c
@@ -330,13 +330,34 @@  static void _amd_iommu_flush_pages(struct domain *d,
                                    daddr_t daddr, unsigned int order)
 {
     struct amd_iommu *iommu;
-    unsigned int dom_id = d->domain_id;
 
     /* send INVALIDATE_IOMMU_PAGES command */
-    for_each_amd_iommu ( iommu )
+    if ( d != dom_io )
     {
-        invalidate_iommu_pages(iommu, daddr, dom_id, order);
-        flush_command_buffer(iommu, 0);
+        for_each_amd_iommu ( iommu )
+        {
+            invalidate_iommu_pages(iommu, daddr, d->domain_id, order);
+            flush_command_buffer(iommu, 0);
+        }
+    }
+    else
+    {
+        const struct pci_dev *pdev;
+
+        for_each_pdev(dom_io, pdev)
+            if ( pdev->arch.pseudo_domid != DOMID_INVALID )
+            {
+                iommu = find_iommu_for_device(pdev->sbdf.seg, pdev->sbdf.bdf);
+                if ( !iommu )
+                {
+                    ASSERT_UNREACHABLE();
+                    continue;
+                }
+
+                invalidate_iommu_pages(iommu, daddr, pdev->arch.pseudo_domid,
+                                       order);
+                flush_command_buffer(iommu, 0);
+            }
     }
 
     if ( ats_enabled )
diff --git a/xen/drivers/passthrough/amd/iommu_init.c b/xen/drivers/passthrough/amd/iommu_init.c
index 7dbd7e7d094a..af6713d2fc02 100644
--- a/xen/drivers/passthrough/amd/iommu_init.c
+++ b/xen/drivers/passthrough/amd/iommu_init.c
@@ -1532,8 +1532,10 @@  int __init amd_iommu_init_late(void)
 static void invalidate_all_domain_pages(void)
 {
     struct domain *d;
+
     for_each_domain( d )
-        amd_iommu_flush_all_pages(d);
+        if ( is_iommu_enabled(d) )
+            amd_iommu_flush_all_pages(d);
 }
 
 static int cf_check _invalidate_all_devices(