Commit de28a65c authored by Linus Torvalds's avatar Linus Torvalds
Browse files

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

Pull IOMMU fixes from Joerg Roedel:

 - Intel VT-d fixes:
    - RCU list handling fixes
    - Replace WARN_TAINT with pr_warn + add_taint for reporting firmware
      issues
    - DebugFS fixes
    - Fix for hugepage handling in iova_to_phys implementation
    - Fix for handling VMD devices, which have a domain number which
      doesn't fit into 16 bits
    - Warning message fix

 - MSI allocation fix for iommu-dma code

 - Sign-extension fix for io page-table code

 - Fix for AMD-Vi to properly update the is-running bit when AVIC is
   used

* tag 'iommu-fixes-v5.6-rc5' of git://git.kernel.org/pub/scm/linux/kernel/git/joro/iommu:
  iommu/vt-d: Populate debugfs if IOMMUs are detected
  iommu/amd: Fix IOMMU AVIC not properly update the is_run bit in IRTE
  iommu/vt-d: Ignore devices with out-of-spec domain number
  iommu/vt-d: Fix the wrong printing in RHSA parsing
  iommu/vt-d: Fix debugfs register reads
  iommu/vt-d: quirk_ioat_snb_local_iommu: replace WARN_TAINT with pr_warn + add_taint
  iommu/vt-d: dmar_parse_one_rmrr: replace WARN_TAINT with pr_warn + add_taint
  iommu/vt-d: dmar: replace WARN_TAINT with pr_warn + add_taint
  iommu/vt-d: Silence RCU-list debugging warnings
  iommu/vt-d: Fix RCU-list bugs in intel_iommu_init()
  iommu/dma: Fix MSI reservation allocation
  iommu/io-pgtable-arm: Fix IOVA validation for 32-bit
  iommu/vt-d: Fix a bug in intel_iommu_iova_to_phys() for huge page
  iommu/vt-d: Fix RCU list debugging warnings
parents d3dca690 1da8347d
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -3826,7 +3826,7 @@ int amd_iommu_activate_guest_mode(void *data)
	entry->lo.fields_vapic.ga_tag      = ir_data->ga_tag;

	return modify_irte_ga(ir_data->irq_2_irte.devid,
			      ir_data->irq_2_irte.index, entry, NULL);
			      ir_data->irq_2_irte.index, entry, ir_data);
}
EXPORT_SYMBOL(amd_iommu_activate_guest_mode);

@@ -3852,7 +3852,7 @@ int amd_iommu_deactivate_guest_mode(void *data)
				APICID_TO_IRTE_DEST_HI(cfg->dest_apicid);

	return modify_irte_ga(ir_data->irq_2_irte.devid,
			      ir_data->irq_2_irte.index, entry, NULL);
			      ir_data->irq_2_irte.index, entry, ir_data);
}
EXPORT_SYMBOL(amd_iommu_deactivate_guest_mode);

+8 −8
Original line number Diff line number Diff line
@@ -177,15 +177,15 @@ static int cookie_init_hw_msi_region(struct iommu_dma_cookie *cookie,
	start -= iova_offset(iovad, start);
	num_pages = iova_align(iovad, end - start) >> iova_shift(iovad);

	msi_page = kcalloc(num_pages, sizeof(*msi_page), GFP_KERNEL);
	for (i = 0; i < num_pages; i++) {
		msi_page = kmalloc(sizeof(*msi_page), GFP_KERNEL);
		if (!msi_page)
			return -ENOMEM;

	for (i = 0; i < num_pages; i++) {
		msi_page[i].phys = start;
		msi_page[i].iova = start;
		INIT_LIST_HEAD(&msi_page[i].list);
		list_add(&msi_page[i].list, &cookie->msi_page_list);
		msi_page->phys = start;
		msi_page->iova = start;
		INIT_LIST_HEAD(&msi_page->list);
		list_add(&msi_page->list, &cookie->msi_page_list);
		start += iovad->granule;
	}

+17 −7
Original line number Diff line number Diff line
@@ -28,6 +28,7 @@
#include <linux/slab.h>
#include <linux/iommu.h>
#include <linux/numa.h>
#include <linux/limits.h>
#include <asm/irq_remapping.h>
#include <asm/iommu_table.h>

@@ -128,6 +129,13 @@ dmar_alloc_pci_notify_info(struct pci_dev *dev, unsigned long event)

	BUG_ON(dev->is_virtfn);

	/*
	 * Ignore devices that have a domain number higher than what can
	 * be looked up in DMAR, e.g. VMD subdevices with domain 0x10000
	 */
	if (pci_domain_nr(dev->bus) > U16_MAX)
		return NULL;

	/* Only generate path[] for device addition event */
	if (event == BUS_NOTIFY_ADD_DEVICE)
		for (tmp = dev; tmp; tmp = tmp->bus->self)
@@ -363,7 +371,8 @@ dmar_find_dmaru(struct acpi_dmar_hardware_unit *drhd)
{
	struct dmar_drhd_unit *dmaru;

	list_for_each_entry_rcu(dmaru, &dmar_drhd_units, list)
	list_for_each_entry_rcu(dmaru, &dmar_drhd_units, list,
				dmar_rcu_check())
		if (dmaru->segment == drhd->segment &&
		    dmaru->reg_base_addr == drhd->address)
			return dmaru;
@@ -440,12 +449,13 @@ static int __init dmar_parse_one_andd(struct acpi_dmar_header *header,

	/* Check for NUL termination within the designated length */
	if (strnlen(andd->device_name, header->length - 8) == header->length - 8) {
		WARN_TAINT(1, TAINT_FIRMWARE_WORKAROUND,
		pr_warn(FW_BUG
			   "Your BIOS is broken; ANDD object name is not NUL-terminated\n"
			   "BIOS vendor: %s; Ver: %s; Product Version: %s\n",
			   dmi_get_system_info(DMI_BIOS_VENDOR),
			   dmi_get_system_info(DMI_BIOS_VERSION),
			   dmi_get_system_info(DMI_PRODUCT_VERSION));
		add_taint(TAINT_FIRMWARE_WORKAROUND, LOCKDEP_STILL_OK);
		return -EINVAL;
	}
	pr_info("ANDD device: %x name: %s\n", andd->device_number,
@@ -471,14 +481,14 @@ static int dmar_parse_one_rhsa(struct acpi_dmar_header *header, void *arg)
			return 0;
		}
	}
	WARN_TAINT(
		1, TAINT_FIRMWARE_WORKAROUND,
	pr_warn(FW_BUG
		"Your BIOS is broken; RHSA refers to non-existent DMAR unit at %llx\n"
		"BIOS vendor: %s; Ver: %s; Product Version: %s\n",
		drhd->reg_base_addr,
		rhsa->base_address,
		dmi_get_system_info(DMI_BIOS_VENDOR),
		dmi_get_system_info(DMI_BIOS_VERSION),
		dmi_get_system_info(DMI_PRODUCT_VERSION));
	add_taint(TAINT_FIRMWARE_WORKAROUND, LOCKDEP_STILL_OK);

	return 0;
}
@@ -827,14 +837,14 @@ int __init dmar_table_init(void)

static void warn_invalid_dmar(u64 addr, const char *message)
{
	WARN_TAINT_ONCE(
		1, TAINT_FIRMWARE_WORKAROUND,
	pr_warn_once(FW_BUG
		"Your BIOS is broken; DMAR reported at address %llx%s!\n"
		"BIOS vendor: %s; Ver: %s; Product Version: %s\n",
		addr, message,
		dmi_get_system_info(DMI_BIOS_VENDOR),
		dmi_get_system_info(DMI_BIOS_VERSION),
		dmi_get_system_info(DMI_PRODUCT_VERSION));
	add_taint(TAINT_FIRMWARE_WORKAROUND, LOCKDEP_STILL_OK);
}

static int __ref
+35 −16
Original line number Diff line number Diff line
@@ -33,38 +33,42 @@ struct iommu_regset {

#define IOMMU_REGSET_ENTRY(_reg_)					\
	{ DMAR_##_reg_##_REG, __stringify(_reg_) }
static const struct iommu_regset iommu_regs[] = {

static const struct iommu_regset iommu_regs_32[] = {
	IOMMU_REGSET_ENTRY(VER),
	IOMMU_REGSET_ENTRY(CAP),
	IOMMU_REGSET_ENTRY(ECAP),
	IOMMU_REGSET_ENTRY(GCMD),
	IOMMU_REGSET_ENTRY(GSTS),
	IOMMU_REGSET_ENTRY(RTADDR),
	IOMMU_REGSET_ENTRY(CCMD),
	IOMMU_REGSET_ENTRY(FSTS),
	IOMMU_REGSET_ENTRY(FECTL),
	IOMMU_REGSET_ENTRY(FEDATA),
	IOMMU_REGSET_ENTRY(FEADDR),
	IOMMU_REGSET_ENTRY(FEUADDR),
	IOMMU_REGSET_ENTRY(AFLOG),
	IOMMU_REGSET_ENTRY(PMEN),
	IOMMU_REGSET_ENTRY(PLMBASE),
	IOMMU_REGSET_ENTRY(PLMLIMIT),
	IOMMU_REGSET_ENTRY(ICS),
	IOMMU_REGSET_ENTRY(PRS),
	IOMMU_REGSET_ENTRY(PECTL),
	IOMMU_REGSET_ENTRY(PEDATA),
	IOMMU_REGSET_ENTRY(PEADDR),
	IOMMU_REGSET_ENTRY(PEUADDR),
};

static const struct iommu_regset iommu_regs_64[] = {
	IOMMU_REGSET_ENTRY(CAP),
	IOMMU_REGSET_ENTRY(ECAP),
	IOMMU_REGSET_ENTRY(RTADDR),
	IOMMU_REGSET_ENTRY(CCMD),
	IOMMU_REGSET_ENTRY(AFLOG),
	IOMMU_REGSET_ENTRY(PHMBASE),
	IOMMU_REGSET_ENTRY(PHMLIMIT),
	IOMMU_REGSET_ENTRY(IQH),
	IOMMU_REGSET_ENTRY(IQT),
	IOMMU_REGSET_ENTRY(IQA),
	IOMMU_REGSET_ENTRY(ICS),
	IOMMU_REGSET_ENTRY(IRTA),
	IOMMU_REGSET_ENTRY(PQH),
	IOMMU_REGSET_ENTRY(PQT),
	IOMMU_REGSET_ENTRY(PQA),
	IOMMU_REGSET_ENTRY(PRS),
	IOMMU_REGSET_ENTRY(PECTL),
	IOMMU_REGSET_ENTRY(PEDATA),
	IOMMU_REGSET_ENTRY(PEADDR),
	IOMMU_REGSET_ENTRY(PEUADDR),
	IOMMU_REGSET_ENTRY(MTRRCAP),
	IOMMU_REGSET_ENTRY(MTRRDEF),
	IOMMU_REGSET_ENTRY(MTRR_FIX64K_00000),
@@ -127,10 +131,16 @@ static int iommu_regset_show(struct seq_file *m, void *unused)
		 * by adding the offset to the pointer (virtual address).
		 */
		raw_spin_lock_irqsave(&iommu->register_lock, flag);
		for (i = 0 ; i < ARRAY_SIZE(iommu_regs); i++) {
			value = dmar_readq(iommu->reg + iommu_regs[i].offset);
		for (i = 0 ; i < ARRAY_SIZE(iommu_regs_32); i++) {
			value = dmar_readl(iommu->reg + iommu_regs_32[i].offset);
			seq_printf(m, "%-16s\t0x%02x\t\t0x%016llx\n",
				   iommu_regs_32[i].regs, iommu_regs_32[i].offset,
				   value);
		}
		for (i = 0 ; i < ARRAY_SIZE(iommu_regs_64); i++) {
			value = dmar_readq(iommu->reg + iommu_regs_64[i].offset);
			seq_printf(m, "%-16s\t0x%02x\t\t0x%016llx\n",
				   iommu_regs[i].regs, iommu_regs[i].offset,
				   iommu_regs_64[i].regs, iommu_regs_64[i].offset,
				   value);
		}
		raw_spin_unlock_irqrestore(&iommu->register_lock, flag);
@@ -272,9 +282,16 @@ static int dmar_translation_struct_show(struct seq_file *m, void *unused)
{
	struct dmar_drhd_unit *drhd;
	struct intel_iommu *iommu;
	u32 sts;

	rcu_read_lock();
	for_each_active_iommu(iommu, drhd) {
		sts = dmar_readl(iommu->reg + DMAR_GSTS_REG);
		if (!(sts & DMA_GSTS_TES)) {
			seq_printf(m, "DMA Remapping is not enabled on %s\n",
				   iommu->name);
			continue;
		}
		root_tbl_walk(m, iommu);
		seq_putc(m, '\n');
	}
@@ -415,6 +432,7 @@ static int ir_translation_struct_show(struct seq_file *m, void *unused)
	struct dmar_drhd_unit *drhd;
	struct intel_iommu *iommu;
	u64 irta;
	u32 sts;

	rcu_read_lock();
	for_each_active_iommu(iommu, drhd) {
@@ -424,7 +442,8 @@ static int ir_translation_struct_show(struct seq_file *m, void *unused)
		seq_printf(m, "Remapped Interrupt supported on IOMMU: %s\n",
			   iommu->name);

		if (iommu->ir_table) {
		sts = dmar_readl(iommu->reg + DMAR_GSTS_REG);
		if (iommu->ir_table && (sts & DMA_GSTS_IRES)) {
			irta = virt_to_phys(iommu->ir_table->base);
			seq_printf(m, " IR table address:%llx\n", irta);
			ir_tbl_remap_entry_show(m, iommu);
+19 −9
Original line number Diff line number Diff line
@@ -4261,11 +4261,12 @@ static void quirk_ioat_snb_local_iommu(struct pci_dev *pdev)

	/* we know that the this iommu should be at offset 0xa000 from vtbar */
	drhd = dmar_find_matched_drhd_unit(pdev);
	if (WARN_TAINT_ONCE(!drhd || drhd->reg_base_addr - vtbar != 0xa000,
			    TAINT_FIRMWARE_WORKAROUND,
			    "BIOS assigned incorrect VT-d unit for Intel(R) QuickData Technology device\n"))
	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);
		pdev->dev.archdata.iommu = 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)
@@ -4460,14 +4461,16 @@ int __init dmar_parse_one_rmrr(struct acpi_dmar_header *header, void *arg)
	struct dmar_rmrr_unit *rmrru;

	rmrr = (struct acpi_dmar_reserved_memory *)header;
	if (rmrr_sanity_check(rmrr))
		WARN_TAINT(1, TAINT_FIRMWARE_WORKAROUND,
	if (rmrr_sanity_check(rmrr)) {
		pr_warn(FW_BUG
			   "Your BIOS is broken; bad RMRR [%#018Lx-%#018Lx]\n"
			   "BIOS vendor: %s; Ver: %s; Product Version: %s\n",
			   rmrr->base_address, rmrr->end_address,
			   dmi_get_system_info(DMI_BIOS_VENDOR),
			   dmi_get_system_info(DMI_BIOS_VERSION),
			   dmi_get_system_info(DMI_PRODUCT_VERSION));
		add_taint(TAINT_FIRMWARE_WORKAROUND, LOCKDEP_STILL_OK);
	}

	rmrru = kzalloc(sizeof(*rmrru), GFP_KERNEL);
	if (!rmrru)
@@ -5130,6 +5133,9 @@ int __init intel_iommu_init(void)

	down_write(&dmar_global_lock);

	if (!no_iommu)
		intel_iommu_debugfs_init();

	if (no_iommu || dmar_disabled) {
		/*
		 * We exit the function here to ensure IOMMU's remapping and
@@ -5193,6 +5199,7 @@ int __init intel_iommu_init(void)

	init_iommu_pm_ops();

	down_read(&dmar_global_lock);
	for_each_active_iommu(iommu, drhd) {
		iommu_device_sysfs_add(&iommu->iommu, NULL,
				       intel_iommu_groups,
@@ -5200,6 +5207,7 @@ int __init intel_iommu_init(void)
		iommu_device_set_ops(&iommu->iommu, &intel_iommu_ops);
		iommu_device_register(&iommu->iommu);
	}
	up_read(&dmar_global_lock);

	bus_set_iommu(&pci_bus_type, &intel_iommu_ops);
	if (si_domain && !hw_pass_through)
@@ -5210,7 +5218,6 @@ int __init intel_iommu_init(void)
	down_read(&dmar_global_lock);
	if (probe_acpi_namespace_devices())
		pr_warn("ACPI name space devices didn't probe correctly\n");
	up_read(&dmar_global_lock);

	/* Finally, we enable the DMA remapping hardware. */
	for_each_iommu(iommu, drhd) {
@@ -5219,10 +5226,11 @@ int __init intel_iommu_init(void)

		iommu_disable_protect_mem_regions(iommu);
	}
	up_read(&dmar_global_lock);

	pr_info("Intel(R) Virtualization Technology for Directed I/O\n");

	intel_iommu_enabled = 1;
	intel_iommu_debugfs_init();

	return 0;

@@ -5700,8 +5708,10 @@ static phys_addr_t intel_iommu_iova_to_phys(struct iommu_domain *domain,
	u64 phys = 0;

	pte = pfn_to_dma_pte(dmar_domain, iova >> VTD_PAGE_SHIFT, &level);
	if (pte)
		phys = dma_pte_addr(pte);
	if (pte && dma_pte_present(pte))
		phys = dma_pte_addr(pte) +
			(iova & (BIT_MASK(level_to_offset_bits(level) +
						VTD_PAGE_SHIFT) - 1));

	return phys;
}
Loading