mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [PATCH] iommu/vt-d: Fix page table level calculation in compute_vasz_lg2_ss()
@ 2026-08-25  8:00 Zhenzhong Duan
  2026-08-25 11:32 ` Jason Gunthorpe
  0 siblings, 1 reply; 2+ messages in thread
From: Zhenzhong Duan @ 2026-08-25  8:00 UTC (permalink / raw)
  To: iommu, linux-kernel
  Cc: dwmw2, baolu.lu, joro, will, robin.murphy, jgg, kevin.tian,
	Zhenzhong Duan, Joerg Roedel

compute_vasz_lg2_ss() finds the optimal Second-Stage page table level by
intersecting the maximum guest address width (mgaw) with the hardware's
SAGAW capability register.

The VT-d spec maps the SAGAW bit field positions as:
  - Bit 1: 39-bit AGAW (3-level page table, top_level = 2)
  - Bit 2: 48-bit AGAW (4-level page table, top_level = 3)
  - Bit 3: 57-bit AGAW (5-level page table, top_level = 4)

The fallback paths use bit shifts that are one position too large,
causing ffs() to select a deeper page table level than the mgaw window
requires:

  - mgaw > 39: "3 + ffs(sagaw >> 3)" evaluates to top_level = 4 (5-level)
    instead of top_level = 3 (4-level) when hardware supports both
    48-bit (Bit 2) and 57-bit (Bit 3) AGAW.
  - mgaw > 30: "2 + ffs(sagaw >> 2)" evaluates to top_level = 3 (4-level)
    instead of top_level = 2 (3-level) when hardware supports both
    39-bit (Bit 1) and 48-bit (Bit 2) AGAW.

In both cases the selected level is still one that the hardware advertises
in its SAGAW capability, so IOVA translation remains functionally correct.
However, an unnecessarily deep page table may be selected, adding an extra
level of page walk overhead and reducing TLB and cache efficiency without
providing any increase in addressable IOVA space beyond what the mgaw
window already caps.

Fix by decreasing the shift offset by one in each fallback case, ensuring
ffs() targets the correct SAGAW bit position and selects the smallest
page table level that fully covers the mgaw range:

  - mgaw > 39: "2 + ffs(sagaw >> 2)" correctly yields top_level = 3
  - mgaw > 30: "1 + ffs(sagaw >> 1)" correctly yields top_level = 2

Fixes: d856f9d27885 ("iommupt/vtd: Allow VT-d to have a larger table top than the vasz requires")
Signed-off-by: Zhenzhong Duan <zhenzhong.duan@intel.com>
---
 drivers/iommu/intel/iommu.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c
index 2e3b3ab216f8..05f351833d0b 100644
--- a/drivers/iommu/intel/iommu.c
+++ b/drivers/iommu/intel/iommu.c
@@ -2911,10 +2911,10 @@ static unsigned int compute_vasz_lg2_ss(struct intel_iommu *iommu,
 		*top_level = 4;
 		return min(57, mgaw);
 	} else if (mgaw > 39 && sagaw >= BIT(2)) {
-		*top_level = 3 + ffs(sagaw >> 3);
+		*top_level = 2 + ffs(sagaw >> 2);
 		return min(48, mgaw);
 	} else if (mgaw > 30 && sagaw >= BIT(1)) {
-		*top_level = 2 + ffs(sagaw >> 2);
+		*top_level = 1 + ffs(sagaw >> 1);
 		return min(39, mgaw);
 	}
 	return 0;
-- 
2.52.0


^ permalink raw reply	[flat|nested] 2+ messages in thread

* Re: [PATCH] iommu/vt-d: Fix page table level calculation in compute_vasz_lg2_ss()
  2026-08-25  8:00 [PATCH] iommu/vt-d: Fix page table level calculation in compute_vasz_lg2_ss() Zhenzhong Duan
@ 2026-08-25 11:32 ` Jason Gunthorpe
  0 siblings, 0 replies; 2+ messages in thread
From: Jason Gunthorpe @ 2026-08-25 11:32 UTC (permalink / raw)
  To: Zhenzhong Duan
  Cc: iommu, linux-kernel, dwmw2, baolu.lu, joro, will, robin.murphy,
	kevin.tian, Joerg Roedel

On Tue, Aug 25, 2026 at 04:00:02PM +0800, Zhenzhong Duan wrote:
> compute_vasz_lg2_ss() finds the optimal Second-Stage page table level by
> intersecting the maximum guest address width (mgaw) with the hardware's
> SAGAW capability register.
> 
> The VT-d spec maps the SAGAW bit field positions as:
>   - Bit 1: 39-bit AGAW (3-level page table, top_level = 2)
>   - Bit 2: 48-bit AGAW (4-level page table, top_level = 3)
>   - Bit 3: 57-bit AGAW (5-level page table, top_level = 4)
> 
> The fallback paths use bit shifts that are one position too large,
> causing ffs() to select a deeper page table level than the mgaw window
> requires:
> 
>   - mgaw > 39: "3 + ffs(sagaw >> 3)" evaluates to top_level = 4 (5-level)
>     instead of top_level = 3 (4-level) when hardware supports both
>     48-bit (Bit 2) and 57-bit (Bit 3) AGAW.
>   - mgaw > 30: "2 + ffs(sagaw >> 2)" evaluates to top_level = 3 (4-level)
>     instead of top_level = 2 (3-level) when hardware supports both
>     39-bit (Bit 1) and 48-bit (Bit 2) AGAW.
> 
> In both cases the selected level is still one that the hardware advertises
> in its SAGAW capability, so IOVA translation remains functionally correct.
> However, an unnecessarily deep page table may be selected, adding an extra
> level of page walk overhead and reducing TLB and cache efficiency without
> providing any increase in addressable IOVA space beyond what the mgaw
> window already caps.
> 
> Fix by decreasing the shift offset by one in each fallback case, ensuring
> ffs() targets the correct SAGAW bit position and selects the smallest
> page table level that fully covers the mgaw range:
> 
>   - mgaw > 39: "2 + ffs(sagaw >> 2)" correctly yields top_level = 3
>   - mgaw > 30: "1 + ffs(sagaw >> 1)" correctly yields top_level = 2
> 
> Fixes: d856f9d27885 ("iommupt/vtd: Allow VT-d to have a larger table top than the vasz requires")
> Signed-off-by: Zhenzhong Duan <zhenzhong.duan@intel.com>
> ---
>  drivers/iommu/intel/iommu.c | 4 ++--
>  1 file changed, 2 insertions(+), 2 deletions(-)

Reviewed-by: Jason Gunthorpe <jgg@nvidia.com>

Jason

^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2026-08-25 11:32 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-08-25  8:00 [PATCH] iommu/vt-d: Fix page table level calculation in compute_vasz_lg2_ss() Zhenzhong Duan
2026-08-25 11:32 ` Jason Gunthorpe

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®