forked from Minki/linux
iommu/amd: Use IVHD EFR for early initialization of IOMMU features
IOMMU Extended Feature Register (EFR) is used to communicate the supported features for each IOMMU to the IOMMU driver. This is normally read from the PCI MMIO register offset 0x30, and used by the iommu_feature() helper function. However, there are certain scenarios where the information is needed prior to PCI initialization, and the iommu_feature() function is used prematurely w/o warning. This has caused incorrect initialization of IOMMU. This is the case for the commit6d39bdee23
("iommu/amd: Enforce 4k mapping for certain IOMMU data structures") Since, the EFR is also available in the IVHD header, and is available to the driver prior to PCI initialization. Therefore, default to using the IVHD EFR instead. Fixes:6d39bdee23
("iommu/amd: Enforce 4k mapping for certain IOMMU data structures") Signed-off-by: Suravee Suthikulpanit <suravee.suthikulpanit@amd.com> Tested-by: Brijesh Singh <brijesh.singh@amd.com> Reviewed-by: Robert Richter <rrichter@amd.com> Link: https://lore.kernel.org/r/20210120135002.2682-1-suravee.suthikulpanit@amd.com Signed-off-by: Joerg Roedel <jroedel@suse.de>
This commit is contained in:
parent
6ee1d745b7
commit
a44092e326
@ -84,12 +84,9 @@ static inline bool is_rd890_iommu(struct pci_dev *pdev)
|
|||||||
(pdev->device == PCI_DEVICE_ID_RD890_IOMMU);
|
(pdev->device == PCI_DEVICE_ID_RD890_IOMMU);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bool iommu_feature(struct amd_iommu *iommu, u64 f)
|
static inline bool iommu_feature(struct amd_iommu *iommu, u64 mask)
|
||||||
{
|
{
|
||||||
if (!(iommu->cap & (1 << IOMMU_CAP_EFR)))
|
return !!(iommu->features & mask);
|
||||||
return false;
|
|
||||||
|
|
||||||
return !!(iommu->features & f);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline u64 iommu_virt_to_phys(void *vaddr)
|
static inline u64 iommu_virt_to_phys(void *vaddr)
|
||||||
|
@ -387,6 +387,10 @@
|
|||||||
#define IOMMU_CAP_NPCACHE 26
|
#define IOMMU_CAP_NPCACHE 26
|
||||||
#define IOMMU_CAP_EFR 27
|
#define IOMMU_CAP_EFR 27
|
||||||
|
|
||||||
|
/* IOMMU IVINFO */
|
||||||
|
#define IOMMU_IVINFO_OFFSET 36
|
||||||
|
#define IOMMU_IVINFO_EFRSUP BIT(0)
|
||||||
|
|
||||||
/* IOMMU Feature Reporting Field (for IVHD type 10h */
|
/* IOMMU Feature Reporting Field (for IVHD type 10h */
|
||||||
#define IOMMU_FEAT_GASUP_SHIFT 6
|
#define IOMMU_FEAT_GASUP_SHIFT 6
|
||||||
|
|
||||||
|
@ -257,6 +257,8 @@ static void init_device_table_dma(void);
|
|||||||
|
|
||||||
static bool amd_iommu_pre_enabled = true;
|
static bool amd_iommu_pre_enabled = true;
|
||||||
|
|
||||||
|
static u32 amd_iommu_ivinfo __initdata;
|
||||||
|
|
||||||
bool translation_pre_enabled(struct amd_iommu *iommu)
|
bool translation_pre_enabled(struct amd_iommu *iommu)
|
||||||
{
|
{
|
||||||
return (iommu->flags & AMD_IOMMU_FLAG_TRANS_PRE_ENABLED);
|
return (iommu->flags & AMD_IOMMU_FLAG_TRANS_PRE_ENABLED);
|
||||||
@ -296,6 +298,18 @@ int amd_iommu_get_num_iommus(void)
|
|||||||
return amd_iommus_present;
|
return amd_iommus_present;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* For IVHD type 0x11/0x40, EFR is also available via IVHD.
|
||||||
|
* Default to IVHD EFR since it is available sooner
|
||||||
|
* (i.e. before PCI init).
|
||||||
|
*/
|
||||||
|
static void __init early_iommu_features_init(struct amd_iommu *iommu,
|
||||||
|
struct ivhd_header *h)
|
||||||
|
{
|
||||||
|
if (amd_iommu_ivinfo & IOMMU_IVINFO_EFRSUP)
|
||||||
|
iommu->features = h->efr_reg;
|
||||||
|
}
|
||||||
|
|
||||||
/* Access to l1 and l2 indexed register spaces */
|
/* Access to l1 and l2 indexed register spaces */
|
||||||
|
|
||||||
static u32 iommu_read_l1(struct amd_iommu *iommu, u16 l1, u8 address)
|
static u32 iommu_read_l1(struct amd_iommu *iommu, u16 l1, u8 address)
|
||||||
@ -1577,6 +1591,9 @@ static int __init init_iommu_one(struct amd_iommu *iommu, struct ivhd_header *h)
|
|||||||
|
|
||||||
if (h->efr_reg & BIT(IOMMU_EFR_XTSUP_SHIFT))
|
if (h->efr_reg & BIT(IOMMU_EFR_XTSUP_SHIFT))
|
||||||
amd_iommu_xt_mode = IRQ_REMAP_X2APIC_MODE;
|
amd_iommu_xt_mode = IRQ_REMAP_X2APIC_MODE;
|
||||||
|
|
||||||
|
early_iommu_features_init(iommu, h);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
@ -1770,6 +1787,35 @@ static const struct attribute_group *amd_iommu_groups[] = {
|
|||||||
NULL,
|
NULL,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Note: IVHD 0x11 and 0x40 also contains exact copy
|
||||||
|
* of the IOMMU Extended Feature Register [MMIO Offset 0030h].
|
||||||
|
* Default to EFR in IVHD since it is available sooner (i.e. before PCI init).
|
||||||
|
*/
|
||||||
|
static void __init late_iommu_features_init(struct amd_iommu *iommu)
|
||||||
|
{
|
||||||
|
u64 features;
|
||||||
|
|
||||||
|
if (!(iommu->cap & (1 << IOMMU_CAP_EFR)))
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* read extended feature bits */
|
||||||
|
features = readq(iommu->mmio_base + MMIO_EXT_FEATURES);
|
||||||
|
|
||||||
|
if (!iommu->features) {
|
||||||
|
iommu->features = features;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Sanity check and warn if EFR values from
|
||||||
|
* IVHD and MMIO conflict.
|
||||||
|
*/
|
||||||
|
if (features != iommu->features)
|
||||||
|
pr_warn(FW_WARN "EFR mismatch. Use IVHD EFR (%#llx : %#llx\n).",
|
||||||
|
features, iommu->features);
|
||||||
|
}
|
||||||
|
|
||||||
static int __init iommu_init_pci(struct amd_iommu *iommu)
|
static int __init iommu_init_pci(struct amd_iommu *iommu)
|
||||||
{
|
{
|
||||||
int cap_ptr = iommu->cap_ptr;
|
int cap_ptr = iommu->cap_ptr;
|
||||||
@ -1789,8 +1835,7 @@ static int __init iommu_init_pci(struct amd_iommu *iommu)
|
|||||||
if (!(iommu->cap & (1 << IOMMU_CAP_IOTLB)))
|
if (!(iommu->cap & (1 << IOMMU_CAP_IOTLB)))
|
||||||
amd_iommu_iotlb_sup = false;
|
amd_iommu_iotlb_sup = false;
|
||||||
|
|
||||||
/* read extended feature bits */
|
late_iommu_features_init(iommu);
|
||||||
iommu->features = readq(iommu->mmio_base + MMIO_EXT_FEATURES);
|
|
||||||
|
|
||||||
if (iommu_feature(iommu, FEATURE_GT)) {
|
if (iommu_feature(iommu, FEATURE_GT)) {
|
||||||
int glxval;
|
int glxval;
|
||||||
@ -2607,6 +2652,11 @@ static void __init free_dma_resources(void)
|
|||||||
free_unity_maps();
|
free_unity_maps();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void __init ivinfo_init(void *ivrs)
|
||||||
|
{
|
||||||
|
amd_iommu_ivinfo = *((u32 *)(ivrs + IOMMU_IVINFO_OFFSET));
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This is the hardware init function for AMD IOMMU in the system.
|
* This is the hardware init function for AMD IOMMU in the system.
|
||||||
* This function is called either from amd_iommu_init or from the interrupt
|
* This function is called either from amd_iommu_init or from the interrupt
|
||||||
@ -2661,6 +2711,8 @@ static int __init early_amd_iommu_init(void)
|
|||||||
if (ret)
|
if (ret)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
|
ivinfo_init(ivrs_base);
|
||||||
|
|
||||||
amd_iommu_target_ivhd_type = get_highest_supported_ivhd_type(ivrs_base);
|
amd_iommu_target_ivhd_type = get_highest_supported_ivhd_type(ivrs_base);
|
||||||
DUMP_printk("Using IVHD type %#x\n", amd_iommu_target_ivhd_type);
|
DUMP_printk("Using IVHD type %#x\n", amd_iommu_target_ivhd_type);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user