mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: Shuai Xue <xueshuai@linux.alibaba.com>
To: joro@8bytes.org, iommu@lists.linux.dev, linux-kernel@vger.kernel.org
Cc: suravee.suthikulpanit@amd.com, vasant.hegde@amd.com,
	will@kernel.org, robin.murphy@arm.com, nicolinc@nvidia.com,
	joerg.roedel@amd.com, stable@vger.kernel.org,
	oliver.yang@linux.alibaba.com, zhuo.song@linux.alibaba.com,
	xueshuai@linux.alibaba.com
Subject: [PATCH] iommu/amd: Flush stale TLB entries when freeing a nested domain ID
Date: Wed,  9 Sep 2026 16:13:58 +0800	[thread overview]
Message-ID: <20260909081358.83235-1-xueshuai@linux.alibaba.com> (raw)

A nested domain uses its hdom_id as the domain ID tag for the stage-2
translations programmed into the DTE.  When the last user of a
gdom_id -> hdom_id mapping goes away, nested_domain_free() returns
the hdom_id to the global pool without invalidating the TLB entries
that were cached under that ID while devices were attached.

Once the hdom_id is handed out to a different domain, those stale
entries become reachable through the new owner of the ID, breaking
DMA isolation between the two domains.

Flush all TLB entries tagged with the hdom_id on the IOMMU of the
viommu before returning the ID to the pool, the same way
set_dte_entry() flushes the old domain ID it replaces right after
calling amd_iommu_update_dte().  This is safe at this point: the
IOMMU core guarantees that a domain is detached from all devices
before it is freed, and the mapping's refcount counts nested domain
objects sharing the mapping rather than devices, so once it drops to
zero no device translates through the hdom_id anymore.

Fixes: 103f4e7c8544 ("iommu/amd: Add support for nested domain attach/detach")
Cc: stable@vger.kernel.org
Assisted-by: Qoder:Qwen-3.8-MAX-Preview
Signed-off-by: Shuai Xue <xueshuai@linux.alibaba.com>
---
 drivers/iommu/amd/amd_iommu.h | 1 +
 drivers/iommu/amd/iommu.c     | 2 +-
 drivers/iommu/amd/nested.c    | 9 +++++++++
 3 files changed, 11 insertions(+), 1 deletion(-)

diff --git a/drivers/iommu/amd/amd_iommu.h b/drivers/iommu/amd/amd_iommu.h
index a2fe804b038b..97883db687ec 100644
--- a/drivers/iommu/amd/amd_iommu.h
+++ b/drivers/iommu/amd/amd_iommu.h
@@ -89,6 +89,7 @@ int amd_iommu_complete_ppr(struct device *dev, u32 pasid, int status, int tag);
  * This function flushes all internal caches of
  * the IOMMU used by this driver.
  */
+void amd_iommu_flush_tlb_domid(struct amd_iommu *iommu, u32 dom_id);
 void amd_iommu_flush_all_caches(struct amd_iommu *iommu);
 void amd_iommu_domain_flush_pages(struct protection_domain *domain,
 				  u64 address, u64 last, u32 flags);
diff --git a/drivers/iommu/amd/iommu.c b/drivers/iommu/amd/iommu.c
index 4dc306a4b5c6..15bc9ddd93f4 100644
--- a/drivers/iommu/amd/iommu.c
+++ b/drivers/iommu/amd/iommu.c
@@ -1576,7 +1576,7 @@ static void amd_iommu_flush_tlb_all(struct amd_iommu *iommu)
 	iommu_completion_wait(iommu);
 }
 
-static void amd_iommu_flush_tlb_domid(struct amd_iommu *iommu, u32 dom_id)
+void amd_iommu_flush_tlb_domid(struct amd_iommu *iommu, u32 dom_id)
 {
 	struct iommu_cmd cmd;
 
diff --git a/drivers/iommu/amd/nested.c b/drivers/iommu/amd/nested.c
index 63b53b29e029..d92ee06edb4c 100644
--- a/drivers/iommu/amd/nested.c
+++ b/drivers/iommu/amd/nested.c
@@ -265,6 +265,8 @@ static void nested_domain_free(struct iommu_domain *dom)
 	struct guest_domain_mapping_info *curr;
 	struct nested_domain *ndom __free(kfree) = to_ndomain(dom);
 	struct amd_iommu_viommu *aviommu = ndom->viommu;
+	struct amd_iommu *iommu = container_of(aviommu->core.iommu_dev,
+					       struct amd_iommu, iommu);
 
 	xa_lock_irqsave(&aviommu->gdomid_array, irqflags);
 
@@ -288,6 +290,13 @@ static void nested_domain_free(struct iommu_domain *dom)
 	pr_debug("%s: Free gdom_id=%#x, hdom_id=%#x\n",
 		__func__, ndom->gdom_id, curr->hdom_id);
 
+	/*
+	 * Flush any TLB entries still tagged with this hdom_id before
+	 * returning it to the global pool, so that a future owner of the
+	 * ID can not hit stale stage-2 translations.
+	 */
+	amd_iommu_flush_tlb_domid(iommu, curr->hdom_id);
+
 	amd_iommu_pdom_id_free(ndom->gdom_info->hdom_id);
 	kfree(curr);
 }
-- 
2.39.3


                 reply	other threads:[~2026-09-09  8:19 UTC|newest]

Thread overview: [no followups] expand[flat|nested]  mbox.gz  Atom feed

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260909081358.83235-1-xueshuai@linux.alibaba.com \
    --to=xueshuai@linux.alibaba.com \
    --cc=iommu@lists.linux.dev \
    --cc=joerg.roedel@amd.com \
    --cc=joro@8bytes.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=nicolinc@nvidia.com \
    --cc=oliver.yang@linux.alibaba.com \
    --cc=robin.murphy@arm.com \
    --cc=stable@vger.kernel.org \
    --cc=suravee.suthikulpanit@amd.com \
    --cc=vasant.hegde@amd.com \
    --cc=will@kernel.org \
    --cc=zhuo.song@linux.alibaba.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®