lkml.org 
[lkml]   [2022]   [Sep]   [13]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 5.15 117/121] iommu/vt-d: Correctly calculate sagaw value of IOMMU
    Date
    From: Lu Baolu <baolu.lu@linux.intel.com>

    commit 53fc7ad6edf210b497230ce74b61b322a202470c upstream.

    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: b802d070a52a1 ("iommu/vt-d: Use iova over first level")
    Cc: stable@vger.kernel.org
    Signed-off-by: Lu Baolu <baolu.lu@linux.intel.com>
    Link: https://lore.kernel.org/r/20220817023558.3253263-1-baolu.lu@linux.intel.com
    Signed-off-by: Joerg Roedel <jroedel@suse.de>
    Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
    ---
    drivers/iommu/intel/iommu.c | 28 +++++++++++++++++++++++++---
    1 file changed, 25 insertions(+), 3 deletions(-)

    --- a/drivers/iommu/intel/iommu.c
    +++ b/drivers/iommu/intel/iommu.c
    @@ -542,14 +542,36 @@ static inline int domain_pfn_supported(s
    return !(addr_width < BITS_PER_LONG && pfn >> addr_width);
    }

    +/*
    + * Calculate the Supported Adjusted Guest Address Widths of an IOMMU.
    + * Refer to 11.4.2 of the VT-d spec for the encoding of each bit of
    + * the returned SAGAW.
    + */
    +static unsigned long __iommu_calculate_sagaw(struct intel_iommu *iommu)
    +{
    + unsigned long fl_sagaw, sl_sagaw;
    +
    + fl_sagaw = BIT(2) | (cap_fl1gp_support(iommu->cap) ? BIT(3) : 0);
    + sl_sagaw = cap_sagaw(iommu->cap);
    +
    + /* Second level only. */
    + if (!sm_supported(iommu) || !ecap_flts(iommu->ecap))
    + return sl_sagaw;
    +
    + /* First level only. */
    + if (!ecap_slts(iommu->ecap))
    + return fl_sagaw;
    +
    + return fl_sagaw & sl_sagaw;
    +}
    +
    static int __iommu_calculate_agaw(struct intel_iommu *iommu, int max_gaw)
    {
    unsigned long sagaw;
    int agaw;

    - sagaw = cap_sagaw(iommu->cap);
    - for (agaw = width_to_agaw(max_gaw);
    - agaw >= 0; agaw--) {
    + sagaw = __iommu_calculate_sagaw(iommu);
    + for (agaw = width_to_agaw(max_gaw); agaw >= 0; agaw--) {
    if (test_bit(agaw, &sagaw))
    break;
    }

    \
     
     \ /
      Last update: 2022-09-13 19:52    [W:2.227 / U:0.132 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site