mirror of
https://github.com/torvalds/linux.git
synced 2024-11-26 22:21:42 +00:00
IOMMU Fixes for Linux v5.11-rc5
Including: - AMD IOMMU Fix to make sure features are detected before they are queried. - Intel IOMMU address alignment check fix for an IOLTB flushing command. - Performance fix for Intel IOMMU to make sure the code does not do full IOTLB flushes all the time. Those flushes are very expensive on emulated IOMMUs. -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEr9jSbILcajRFYWYyK/BELZcBGuMFAmAUOaQACgkQK/BELZcB GuO2hQ/9HOWNK4R06JufpOy+G29M4nY74RkfB2DuFjamouKkgSEODyv9bzz6Rhn6 WvTPzIxhaFuaw5MCiOp1a80CnzP9rPLn8zMAG9jSh4dHMnIvCZsXrJJkIT1NIBOH Sryz1tqu3MNWvOauoQnopRSbmhlEMTfgOY62Tn4bcz92Y49LH5/gb0Wcz/YZbFZd q3f3UKI2xOTB2nGckxGEOMtpWSkaeNZs4GhPl9HwFXUwkNgPleVJZcnx/KL6fPRk WTmPOgf7EVoVr/2aAtLvEWwZIJ6OE0D1AgYgPn6y18UsBYQiAz1/5k+M2r1lJo5L UKnjSsRuybAO6aQwRdl7kQXk9bTzU0D7tVqMvWLsiJP02U/+0LiRH1WIY+eWnkRt syHBWTYQFqLryHmXyy7rNEEslqgidP+SBSH6NDdzKJR5OwjzAqNgrnMxIlciL/n0 1hlwR3B5OjliHilMZo8/Bc9XzAMlK7nl5EpMcCvhYocX5pJV1FQrOhrIgRASWVZ4 Ce+F4RxgbpyYihDNg3PpE2DMh/5OjxXCIsTGh5BA4AQgINrRe6ETwh6Vw3NBJI5k T7L/MVqo59nBPPZ5RmVdyl6XjTTHFMt8C9zpnNg4LbOuNUP0Udm0vLaiJKldzg5B oth+P7ftg9H9KJtOQtkfSP8A/WCaHRqHJOuMwZ53eb7EL+JEq0E= =djR4 -----END PGP SIGNATURE----- Merge tag 'iommu-fixes-v5.11-rc5' of git://git.kernel.org/pub/scm/linux/kernel/git/joro/iommu Pull iommu fixes from Joerg Roedel: - AMD IOMMU fix to make sure features are detected before they are queried. - Intel IOMMU address alignment check fix for an IOLTB flushing command. - Performance fix for Intel IOMMU to make sure the code does not do full IOTLB flushes all the time. Those flushes are very expensive on emulated IOMMUs. * tag 'iommu-fixes-v5.11-rc5' of git://git.kernel.org/pub/scm/linux/kernel/git/joro/iommu: iommu/vt-d: Do not use flush-queue when caching-mode is on iommu/vt-d: Correctly check addr alignment in qi_flush_dev_iotlb_pasid() iommu/amd: Use IVHD EFR for early initialization of IOMMU features
This commit is contained in:
commit
8ef24c2011
@ -84,12 +84,9 @@ static inline bool is_rd890_iommu(struct pci_dev *pdev)
|
||||
(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 false;
|
||||
|
||||
return !!(iommu->features & f);
|
||||
return !!(iommu->features & mask);
|
||||
}
|
||||
|
||||
static inline u64 iommu_virt_to_phys(void *vaddr)
|
||||
|
@ -387,6 +387,10 @@
|
||||
#define IOMMU_CAP_NPCACHE 26
|
||||
#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 */
|
||||
#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 u32 amd_iommu_ivinfo __initdata;
|
||||
|
||||
bool translation_pre_enabled(struct amd_iommu *iommu)
|
||||
{
|
||||
return (iommu->flags & AMD_IOMMU_FLAG_TRANS_PRE_ENABLED);
|
||||
@ -296,6 +298,18 @@ int amd_iommu_get_num_iommus(void)
|
||||
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 */
|
||||
|
||||
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))
|
||||
amd_iommu_xt_mode = IRQ_REMAP_X2APIC_MODE;
|
||||
|
||||
early_iommu_features_init(iommu, h);
|
||||
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
@ -1770,6 +1787,35 @@ static const struct attribute_group *amd_iommu_groups[] = {
|
||||
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)
|
||||
{
|
||||
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)))
|
||||
amd_iommu_iotlb_sup = false;
|
||||
|
||||
/* read extended feature bits */
|
||||
iommu->features = readq(iommu->mmio_base + MMIO_EXT_FEATURES);
|
||||
late_iommu_features_init(iommu);
|
||||
|
||||
if (iommu_feature(iommu, FEATURE_GT)) {
|
||||
int glxval;
|
||||
@ -2607,6 +2652,11 @@ static void __init free_dma_resources(void)
|
||||
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 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)
|
||||
goto out;
|
||||
|
||||
ivinfo_init(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);
|
||||
|
||||
|
@ -1496,7 +1496,7 @@ void qi_flush_dev_iotlb_pasid(struct intel_iommu *iommu, u16 sid, u16 pfsid,
|
||||
* Max Invs Pending (MIP) is set to 0 for now until we have DIT in
|
||||
* ECAP.
|
||||
*/
|
||||
if (addr & GENMASK_ULL(size_order + VTD_PAGE_SHIFT, 0))
|
||||
if (!IS_ALIGNED(addr, VTD_PAGE_SIZE << size_order))
|
||||
pr_warn_ratelimited("Invalidate non-aligned address %llx, order %d\n",
|
||||
addr, size_order);
|
||||
|
||||
|
@ -5440,6 +5440,36 @@ intel_iommu_domain_set_attr(struct iommu_domain *domain,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static bool domain_use_flush_queue(void)
|
||||
{
|
||||
struct dmar_drhd_unit *drhd;
|
||||
struct intel_iommu *iommu;
|
||||
bool r = true;
|
||||
|
||||
if (intel_iommu_strict)
|
||||
return false;
|
||||
|
||||
/*
|
||||
* The flush queue implementation does not perform page-selective
|
||||
* invalidations that are required for efficient TLB flushes in virtual
|
||||
* environments. The benefit of batching is likely to be much lower than
|
||||
* the overhead of synchronizing the virtual and physical IOMMU
|
||||
* page-tables.
|
||||
*/
|
||||
rcu_read_lock();
|
||||
for_each_active_iommu(iommu, drhd) {
|
||||
if (!cap_caching_mode(iommu->cap))
|
||||
continue;
|
||||
|
||||
pr_warn_once("IOMMU batching is disabled due to virtualization");
|
||||
r = false;
|
||||
break;
|
||||
}
|
||||
rcu_read_unlock();
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static int
|
||||
intel_iommu_domain_get_attr(struct iommu_domain *domain,
|
||||
enum iommu_attr attr, void *data)
|
||||
@ -5450,7 +5480,7 @@ intel_iommu_domain_get_attr(struct iommu_domain *domain,
|
||||
case IOMMU_DOMAIN_DMA:
|
||||
switch (attr) {
|
||||
case DOMAIN_ATTR_DMA_USE_FLUSH_QUEUE:
|
||||
*(int *)data = !intel_iommu_strict;
|
||||
*(int *)data = domain_use_flush_queue();
|
||||
return 0;
|
||||
default:
|
||||
return -ENODEV;
|
||||
|
Loading…
Reference in New Issue
Block a user