Commit 2ccdd9f8 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'iommu-fixes-v5.9-rc3' of git://git.kernel.org/pub/scm/linux/kernel/git/joro/iommu

Pull iommu fixes from Joerg Roedel:

 - three Intel VT-d fixes to fix address handling on 32bit, fix a NULL
   pointer dereference bug and serialize a hardware register access as
   required by the VT-d spec.

 - two patches for AMD IOMMU to force AMD GPUs into translation mode
   when memory encryption is active and disallow using IOMMUv2
   functionality.  This makes the AMDGPU driver work when memory
   encryption is active.

 - two more fixes for AMD IOMMU to fix updating the Interrupt Remapping
   Table Entries.

 - MAINTAINERS file update for the Qualcom IOMMU driver.

* tag 'iommu-fixes-v5.9-rc3' of git://git.kernel.org/pub/scm/linux/kernel/git/joro/iommu:
  iommu/vt-d: Handle 36bit addressing for x86-32
  iommu/amd: Do not use IOMMUv2 functionality when SME is active
  iommu/amd: Do not force direct mapping when SME is active
  iommu/amd: Use cmpxchg_double() when updating 128-bit IRTE
  iommu/amd: Restore IRTE.RemapEn bit after programming IRTE
  iommu/vt-d: Fix NULL pointer dereference in dev_iommu_priv_set()
  iommu/vt-d: Serialize IOMMU GCMD register modifications
  MAINTAINERS: Update QUALCOMM IOMMU after Arm SMMU drivers move
parents 015b3155 29aaebbc
...@@ -14388,7 +14388,7 @@ M: Rob Clark <robdclark@gmail.com> ...@@ -14388,7 +14388,7 @@ M: Rob Clark <robdclark@gmail.com>
L: iommu@lists.linux-foundation.org L: iommu@lists.linux-foundation.org
L: linux-arm-msm@vger.kernel.org L: linux-arm-msm@vger.kernel.org
S: Maintained S: Maintained
F: drivers/iommu/qcom_iommu.c F: drivers/iommu/arm/arm-smmu/qcom_iommu.c
QUALCOMM IPCC MAILBOX DRIVER QUALCOMM IPCC MAILBOX DRIVER
M: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org> M: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
......
...@@ -10,7 +10,7 @@ config AMD_IOMMU ...@@ -10,7 +10,7 @@ config AMD_IOMMU
select IOMMU_API select IOMMU_API
select IOMMU_IOVA select IOMMU_IOVA
select IOMMU_DMA select IOMMU_DMA
depends on X86_64 && PCI && ACPI depends on X86_64 && PCI && ACPI && HAVE_CMPXCHG_DOUBLE
help help
With this option you can enable support for AMD IOMMU hardware in With this option you can enable support for AMD IOMMU hardware in
your system. An IOMMU is a hardware component which provides your system. An IOMMU is a hardware component which provides
......
...@@ -1511,7 +1511,14 @@ static int __init init_iommu_one(struct amd_iommu *iommu, struct ivhd_header *h) ...@@ -1511,7 +1511,14 @@ static int __init init_iommu_one(struct amd_iommu *iommu, struct ivhd_header *h)
iommu->mmio_phys_end = MMIO_REG_END_OFFSET; iommu->mmio_phys_end = MMIO_REG_END_OFFSET;
else else
iommu->mmio_phys_end = MMIO_CNTR_CONF_OFFSET; iommu->mmio_phys_end = MMIO_CNTR_CONF_OFFSET;
if (((h->efr_attr & (0x1 << IOMMU_FEAT_GASUP_SHIFT)) == 0))
/*
* Note: GA (128-bit IRTE) mode requires cmpxchg16b supports.
* GAM also requires GA mode. Therefore, we need to
* check cmpxchg16b support before enabling it.
*/
if (!boot_cpu_has(X86_FEATURE_CX16) ||
((h->efr_attr & (0x1 << IOMMU_FEAT_GASUP_SHIFT)) == 0))
amd_iommu_guest_ir = AMD_IOMMU_GUEST_IR_LEGACY; amd_iommu_guest_ir = AMD_IOMMU_GUEST_IR_LEGACY;
break; break;
case 0x11: case 0x11:
...@@ -1520,8 +1527,18 @@ static int __init init_iommu_one(struct amd_iommu *iommu, struct ivhd_header *h) ...@@ -1520,8 +1527,18 @@ static int __init init_iommu_one(struct amd_iommu *iommu, struct ivhd_header *h)
iommu->mmio_phys_end = MMIO_REG_END_OFFSET; iommu->mmio_phys_end = MMIO_REG_END_OFFSET;
else else
iommu->mmio_phys_end = MMIO_CNTR_CONF_OFFSET; iommu->mmio_phys_end = MMIO_CNTR_CONF_OFFSET;
if (((h->efr_reg & (0x1 << IOMMU_EFR_GASUP_SHIFT)) == 0))
/*
* Note: GA (128-bit IRTE) mode requires cmpxchg16b supports.
* XT, GAM also requires GA mode. Therefore, we need to
* check cmpxchg16b support before enabling them.
*/
if (!boot_cpu_has(X86_FEATURE_CX16) ||
((h->efr_reg & (0x1 << IOMMU_EFR_GASUP_SHIFT)) == 0)) {
amd_iommu_guest_ir = AMD_IOMMU_GUEST_IR_LEGACY; amd_iommu_guest_ir = AMD_IOMMU_GUEST_IR_LEGACY;
break;
}
/* /*
* Note: Since iommu_update_intcapxt() leverages * Note: Since iommu_update_intcapxt() leverages
* the IOMMU MMIO access to MSI capability block registers * the IOMMU MMIO access to MSI capability block registers
......
...@@ -2659,7 +2659,12 @@ static int amd_iommu_def_domain_type(struct device *dev) ...@@ -2659,7 +2659,12 @@ static int amd_iommu_def_domain_type(struct device *dev)
if (!dev_data) if (!dev_data)
return 0; return 0;
if (dev_data->iommu_v2) /*
* Do not identity map IOMMUv2 capable devices when memory encryption is
* active, because some of those devices (AMD GPUs) don't have the
* encryption bit in their DMA-mask and require remapping.
*/
if (!mem_encrypt_active() && dev_data->iommu_v2)
return IOMMU_DOMAIN_IDENTITY; return IOMMU_DOMAIN_IDENTITY;
return 0; return 0;
...@@ -3292,6 +3297,7 @@ static int alloc_irq_index(u16 devid, int count, bool align, ...@@ -3292,6 +3297,7 @@ static int alloc_irq_index(u16 devid, int count, bool align,
static int modify_irte_ga(u16 devid, int index, struct irte_ga *irte, static int modify_irte_ga(u16 devid, int index, struct irte_ga *irte,
struct amd_ir_data *data) struct amd_ir_data *data)
{ {
bool ret;
struct irq_remap_table *table; struct irq_remap_table *table;
struct amd_iommu *iommu; struct amd_iommu *iommu;
unsigned long flags; unsigned long flags;
...@@ -3309,10 +3315,18 @@ static int modify_irte_ga(u16 devid, int index, struct irte_ga *irte, ...@@ -3309,10 +3315,18 @@ static int modify_irte_ga(u16 devid, int index, struct irte_ga *irte,
entry = (struct irte_ga *)table->table; entry = (struct irte_ga *)table->table;
entry = &entry[index]; entry = &entry[index];
entry->lo.fields_remap.valid = 0;
entry->hi.val = irte->hi.val; ret = cmpxchg_double(&entry->lo.val, &entry->hi.val,
entry->lo.val = irte->lo.val; entry->lo.val, entry->hi.val,
entry->lo.fields_remap.valid = 1; irte->lo.val, irte->hi.val);
/*
* We use cmpxchg16 to atomically update the 128-bit IRTE,
* and it cannot be updated by the hardware or other processors
* behind us, so the return value of cmpxchg16 should be the
* same as the old value.
*/
WARN_ON(!ret);
if (data) if (data)
data->ref = entry; data->ref = entry;
...@@ -3850,6 +3864,7 @@ int amd_iommu_deactivate_guest_mode(void *data) ...@@ -3850,6 +3864,7 @@ int amd_iommu_deactivate_guest_mode(void *data)
struct amd_ir_data *ir_data = (struct amd_ir_data *)data; struct amd_ir_data *ir_data = (struct amd_ir_data *)data;
struct irte_ga *entry = (struct irte_ga *) ir_data->entry; struct irte_ga *entry = (struct irte_ga *) ir_data->entry;
struct irq_cfg *cfg = ir_data->cfg; struct irq_cfg *cfg = ir_data->cfg;
u64 valid = entry->lo.fields_remap.valid;
if (!AMD_IOMMU_GUEST_IR_VAPIC(amd_iommu_guest_ir) || if (!AMD_IOMMU_GUEST_IR_VAPIC(amd_iommu_guest_ir) ||
!entry || !entry->lo.fields_vapic.guest_mode) !entry || !entry->lo.fields_vapic.guest_mode)
...@@ -3858,6 +3873,7 @@ int amd_iommu_deactivate_guest_mode(void *data) ...@@ -3858,6 +3873,7 @@ int amd_iommu_deactivate_guest_mode(void *data)
entry->lo.val = 0; entry->lo.val = 0;
entry->hi.val = 0; entry->hi.val = 0;
entry->lo.fields_remap.valid = valid;
entry->lo.fields_remap.dm = apic->irq_dest_mode; entry->lo.fields_remap.dm = apic->irq_dest_mode;
entry->lo.fields_remap.int_type = apic->irq_delivery_mode; entry->lo.fields_remap.int_type = apic->irq_delivery_mode;
entry->hi.fields.vector = cfg->vector; entry->hi.fields.vector = cfg->vector;
......
...@@ -737,6 +737,13 @@ int amd_iommu_init_device(struct pci_dev *pdev, int pasids) ...@@ -737,6 +737,13 @@ int amd_iommu_init_device(struct pci_dev *pdev, int pasids)
might_sleep(); might_sleep();
/*
* When memory encryption is active the device is likely not in a
* direct-mapped domain. Forbid using IOMMUv2 functionality for now.
*/
if (mem_encrypt_active())
return -ENODEV;
if (!amd_iommu_v2_supported()) if (!amd_iommu_v2_supported())
return -ENODEV; return -ENODEV;
......
...@@ -123,29 +123,29 @@ static inline unsigned int level_to_offset_bits(int level) ...@@ -123,29 +123,29 @@ static inline unsigned int level_to_offset_bits(int level)
return (level - 1) * LEVEL_STRIDE; return (level - 1) * LEVEL_STRIDE;
} }
static inline int pfn_level_offset(unsigned long pfn, int level) static inline int pfn_level_offset(u64 pfn, int level)
{ {
return (pfn >> level_to_offset_bits(level)) & LEVEL_MASK; return (pfn >> level_to_offset_bits(level)) & LEVEL_MASK;
} }
static inline unsigned long level_mask(int level) static inline u64 level_mask(int level)
{ {
return -1UL << level_to_offset_bits(level); return -1ULL << level_to_offset_bits(level);
} }
static inline unsigned long level_size(int level) static inline u64 level_size(int level)
{ {
return 1UL << level_to_offset_bits(level); return 1ULL << level_to_offset_bits(level);
} }
static inline unsigned long align_to_level(unsigned long pfn, int level) static inline u64 align_to_level(u64 pfn, int level)
{ {
return (pfn + level_size(level) - 1) & level_mask(level); return (pfn + level_size(level) - 1) & level_mask(level);
} }
static inline unsigned long lvl_to_nr_pages(unsigned int lvl) static inline unsigned long lvl_to_nr_pages(unsigned int lvl)
{ {
return 1 << min_t(int, (lvl - 1) * LEVEL_STRIDE, MAX_AGAW_PFN_WIDTH); return 1UL << min_t(int, (lvl - 1) * LEVEL_STRIDE, MAX_AGAW_PFN_WIDTH);
} }
/* VT-d pages must always be _smaller_ than MM pages. Otherwise things /* VT-d pages must always be _smaller_ than MM pages. Otherwise things
...@@ -364,7 +364,6 @@ static int iommu_skip_te_disable; ...@@ -364,7 +364,6 @@ static int iommu_skip_te_disable;
int intel_iommu_gfx_mapped; int intel_iommu_gfx_mapped;
EXPORT_SYMBOL_GPL(intel_iommu_gfx_mapped); EXPORT_SYMBOL_GPL(intel_iommu_gfx_mapped);
#define DUMMY_DEVICE_DOMAIN_INFO ((struct device_domain_info *)(-1))
#define DEFER_DEVICE_DOMAIN_INFO ((struct device_domain_info *)(-2)) #define DEFER_DEVICE_DOMAIN_INFO ((struct device_domain_info *)(-2))
struct device_domain_info *get_domain_info(struct device *dev) struct device_domain_info *get_domain_info(struct device *dev)
{ {
...@@ -374,8 +373,7 @@ struct device_domain_info *get_domain_info(struct device *dev) ...@@ -374,8 +373,7 @@ struct device_domain_info *get_domain_info(struct device *dev)
return NULL; return NULL;
info = dev_iommu_priv_get(dev); info = dev_iommu_priv_get(dev);
if (unlikely(info == DUMMY_DEVICE_DOMAIN_INFO || if (unlikely(info == DEFER_DEVICE_DOMAIN_INFO))
info == DEFER_DEVICE_DOMAIN_INFO))
return NULL; return NULL;
return info; return info;
...@@ -742,11 +740,6 @@ struct context_entry *iommu_context_addr(struct intel_iommu *iommu, u8 bus, ...@@ -742,11 +740,6 @@ struct context_entry *iommu_context_addr(struct intel_iommu *iommu, u8 bus,
return &context[devfn]; return &context[devfn];
} }
static int iommu_dummy(struct device *dev)
{
return dev_iommu_priv_get(dev) == DUMMY_DEVICE_DOMAIN_INFO;
}
static bool attach_deferred(struct device *dev) static bool attach_deferred(struct device *dev)
{ {
return dev_iommu_priv_get(dev) == DEFER_DEVICE_DOMAIN_INFO; return dev_iommu_priv_get(dev) == DEFER_DEVICE_DOMAIN_INFO;
...@@ -779,6 +772,53 @@ is_downstream_to_pci_bridge(struct device *dev, struct device *bridge) ...@@ -779,6 +772,53 @@ is_downstream_to_pci_bridge(struct device *dev, struct device *bridge)
return false; return false;
} }
static bool quirk_ioat_snb_local_iommu(struct pci_dev *pdev)
{
struct dmar_drhd_unit *drhd;
u32 vtbar;
int rc;
/* We know that this device on this chipset has its own IOMMU.
* If we find it under a different IOMMU, then the BIOS is lying
* to us. Hope that the IOMMU for this device is actually
* disabled, and it needs no translation...
*/
rc = pci_bus_read_config_dword(pdev->bus, PCI_DEVFN(0, 0), 0xb0, &vtbar);
if (rc) {
/* "can't" happen */
dev_info(&pdev->dev, "failed to run vt-d quirk\n");
return false;
}
vtbar &= 0xffff0000;
/* we know that the this iommu should be at offset 0xa000 from vtbar */
drhd = dmar_find_matched_drhd_unit(pdev);
if (!drhd || drhd->reg_base_addr - vtbar != 0xa000) {
pr_warn_once(FW_BUG "BIOS assigned incorrect VT-d unit for Intel(R) QuickData Technology device\n");
add_taint(TAINT_FIRMWARE_WORKAROUND, LOCKDEP_STILL_OK);
return true;
}
return false;
}
static bool iommu_is_dummy(struct intel_iommu *iommu, struct device *dev)
{
if (!iommu || iommu->drhd->ignored)
return true;
if (dev_is_pci(dev)) {
struct pci_dev *pdev = to_pci_dev(dev);
if (pdev->vendor == PCI_VENDOR_ID_INTEL &&
pdev->device == PCI_DEVICE_ID_INTEL_IOAT_SNB &&
quirk_ioat_snb_local_iommu(pdev))
return true;
}
return false;
}
struct intel_iommu *device_to_iommu(struct device *dev, u8 *bus, u8 *devfn) struct intel_iommu *device_to_iommu(struct device *dev, u8 *bus, u8 *devfn)
{ {
struct dmar_drhd_unit *drhd = NULL; struct dmar_drhd_unit *drhd = NULL;
...@@ -788,7 +828,7 @@ struct intel_iommu *device_to_iommu(struct device *dev, u8 *bus, u8 *devfn) ...@@ -788,7 +828,7 @@ struct intel_iommu *device_to_iommu(struct device *dev, u8 *bus, u8 *devfn)
u16 segment = 0; u16 segment = 0;
int i; int i;
if (!dev || iommu_dummy(dev)) if (!dev)
return NULL; return NULL;
if (dev_is_pci(dev)) { if (dev_is_pci(dev)) {
...@@ -805,7 +845,7 @@ struct intel_iommu *device_to_iommu(struct device *dev, u8 *bus, u8 *devfn) ...@@ -805,7 +845,7 @@ struct intel_iommu *device_to_iommu(struct device *dev, u8 *bus, u8 *devfn)
dev = &ACPI_COMPANION(dev)->dev; dev = &ACPI_COMPANION(dev)->dev;
rcu_read_lock(); rcu_read_lock();
for_each_active_iommu(iommu, drhd) { for_each_iommu(iommu, drhd) {
if (pdev && segment != drhd->segment) if (pdev && segment != drhd->segment)
continue; continue;
...@@ -841,6 +881,9 @@ struct intel_iommu *device_to_iommu(struct device *dev, u8 *bus, u8 *devfn) ...@@ -841,6 +881,9 @@ struct intel_iommu *device_to_iommu(struct device *dev, u8 *bus, u8 *devfn)
} }
iommu = NULL; iommu = NULL;
out: out:
if (iommu_is_dummy(iommu, dev))
iommu = NULL;
rcu_read_unlock(); rcu_read_unlock();
return iommu; return iommu;
...@@ -2447,7 +2490,7 @@ struct dmar_domain *find_domain(struct device *dev) ...@@ -2447,7 +2490,7 @@ struct dmar_domain *find_domain(struct device *dev)
{ {
struct device_domain_info *info; struct device_domain_info *info;
if (unlikely(attach_deferred(dev) || iommu_dummy(dev))) if (unlikely(attach_deferred(dev)))
return NULL; return NULL;
/* No lock here, assumes no domain exit in normal case */ /* No lock here, assumes no domain exit in normal case */
...@@ -3989,35 +4032,6 @@ static void __init iommu_exit_mempool(void) ...@@ -3989,35 +4032,6 @@ static void __init iommu_exit_mempool(void)
iova_cache_put(); iova_cache_put();
} }
static void quirk_ioat_snb_local_iommu(struct pci_dev *pdev)
{
struct dmar_drhd_unit *drhd;
u32 vtbar;
int rc;
/* We know that this device on this chipset has its own IOMMU.
* If we find it under a different IOMMU, then the BIOS is lying
* to us. Hope that the IOMMU for this device is actually
* disabled, and it needs no translation...
*/
rc = pci_bus_read_config_dword(pdev->bus, PCI_DEVFN(0, 0), 0xb0, &vtbar);
if (rc) {
/* "can't" happen */
dev_info(&pdev->dev, "failed to run vt-d quirk\n");
return;
}
vtbar &= 0xffff0000;
/* we know that the this iommu should be at offset 0xa000 from vtbar */
drhd = dmar_find_matched_drhd_unit(pdev);
if (!drhd || drhd->reg_base_addr - vtbar != 0xa000) {
pr_warn_once(FW_BUG "BIOS assigned incorrect VT-d unit for Intel(R) QuickData Technology device\n");
add_taint(TAINT_FIRMWARE_WORKAROUND, LOCKDEP_STILL_OK);
dev_iommu_priv_set(&pdev->dev, DUMMY_DEVICE_DOMAIN_INFO);
}
}
DECLARE_PCI_FIXUP_ENABLE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_IOAT_SNB, quirk_ioat_snb_local_iommu);
static void __init init_no_remapping_devices(void) static void __init init_no_remapping_devices(void)
{ {
struct dmar_drhd_unit *drhd; struct dmar_drhd_unit *drhd;
...@@ -4049,12 +4063,8 @@ static void __init init_no_remapping_devices(void) ...@@ -4049,12 +4063,8 @@ static void __init init_no_remapping_devices(void)
/* This IOMMU has *only* gfx devices. Either bypass it or /* This IOMMU has *only* gfx devices. Either bypass it or
set the gfx_mapped flag, as appropriate */ set the gfx_mapped flag, as appropriate */
drhd->gfx_dedicated = 1; drhd->gfx_dedicated = 1;
if (!dmar_map_gfx) { if (!dmar_map_gfx)
drhd->ignored = 1; drhd->ignored = 1;
for_each_active_dev_scope(drhd->devices,
drhd->devices_cnt, i, dev)
dev_iommu_priv_set(dev, DUMMY_DEVICE_DOMAIN_INFO);
}
} }
} }
......
...@@ -508,12 +508,18 @@ static void iommu_enable_irq_remapping(struct intel_iommu *iommu) ...@@ -508,12 +508,18 @@ static void iommu_enable_irq_remapping(struct intel_iommu *iommu)
/* Enable interrupt-remapping */ /* Enable interrupt-remapping */
iommu->gcmd |= DMA_GCMD_IRE; iommu->gcmd |= DMA_GCMD_IRE;
iommu->gcmd &= ~DMA_GCMD_CFI; /* Block compatibility-format MSIs */
writel(iommu->gcmd, iommu->reg + DMAR_GCMD_REG); writel(iommu->gcmd, iommu->reg + DMAR_GCMD_REG);
IOMMU_WAIT_OP(iommu, DMAR_GSTS_REG, IOMMU_WAIT_OP(iommu, DMAR_GSTS_REG,
readl, (sts & DMA_GSTS_IRES), sts); readl, (sts & DMA_GSTS_IRES), sts);
/* Block compatibility-format MSIs */
if (sts & DMA_GSTS_CFIS) {
iommu->gcmd &= ~DMA_GCMD_CFI;
writel(iommu->gcmd, iommu->reg + DMAR_GCMD_REG);
IOMMU_WAIT_OP(iommu, DMAR_GSTS_REG,
readl, !(sts & DMA_GSTS_CFIS), sts);
}
/* /*
* With CFI clear in the Global Command register, we should be * With CFI clear in the Global Command register, we should be
* protected from dangerous (i.e. compatibility) interrupts * protected from dangerous (i.e. compatibility) interrupts
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment