Skip to content

Commit 53fc7ad

Browse files
LuBaolujoergroedel
authored andcommitted
iommu/vt-d: Correctly calculate sagaw value of IOMMU
The Intel IOMMU driver possibly selects between the first-level and the second-level translation tables for DMA address translation. However, the levels of page-table walks for the 4KB base page size are calculated from the SAGAW field of the capability register, which is only valid for the second-level page table. This causes the IOMMU driver to stop working if the hardware (or the emulated IOMMU) advertises only first-level translation capability and reports the SAGAW field as 0. This solves the above problem by considering both the first level and the second level when calculating the supported page table levels. Fixes: b802d07 ("iommu/vt-d: Use iova over first level") Cc: [email protected] Signed-off-by: Lu Baolu <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Joerg Roedel <[email protected]>
1 parent 0c5f6c0 commit 53fc7ad

File tree

1 file changed

+25
-3
lines changed

1 file changed

+25
-3
lines changed

drivers/iommu/intel/iommu.c

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -390,14 +390,36 @@ static inline int domain_pfn_supported(struct dmar_domain *domain,
390390
return !(addr_width < BITS_PER_LONG && pfn >> addr_width);
391391
}
392392

393+
/*
394+
* Calculate the Supported Adjusted Guest Address Widths of an IOMMU.
395+
* Refer to 11.4.2 of the VT-d spec for the encoding of each bit of
396+
* the returned SAGAW.
397+
*/
398+
static unsigned long __iommu_calculate_sagaw(struct intel_iommu *iommu)
399+
{
400+
unsigned long fl_sagaw, sl_sagaw;
401+
402+
fl_sagaw = BIT(2) | (cap_fl1gp_support(iommu->cap) ? BIT(3) : 0);
403+
sl_sagaw = cap_sagaw(iommu->cap);
404+
405+
/* Second level only. */
406+
if (!sm_supported(iommu) || !ecap_flts(iommu->ecap))
407+
return sl_sagaw;
408+
409+
/* First level only. */
410+
if (!ecap_slts(iommu->ecap))
411+
return fl_sagaw;
412+
413+
return fl_sagaw & sl_sagaw;
414+
}
415+
393416
static int __iommu_calculate_agaw(struct intel_iommu *iommu, int max_gaw)
394417
{
395418
unsigned long sagaw;
396419
int agaw;
397420

398-
sagaw = cap_sagaw(iommu->cap);
399-
for (agaw = width_to_agaw(max_gaw);
400-
agaw >= 0; agaw--) {
421+
sagaw = __iommu_calculate_sagaw(iommu);
422+
for (agaw = width_to_agaw(max_gaw); agaw >= 0; agaw--) {
401423
if (test_bit(agaw, &sagaw))
402424
break;
403425
}

0 commit comments

Comments
 (0)