IOMMU Fixes for Linux v5.6-rc5
Including: - Mostly 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 -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEr9jSbILcajRFYWYyK/BELZcBGuMFAl5t8ZcACgkQK/BELZcB GuPHzhAAjVoojKibjI7KMn9mCrfZOOxTcHPTYvpUgo2Wmzawi8CvafRoUM0nK+mH Ha99W7LRNdOSJKjTe83eZwLkCzAaSTKvjNi92/xc9Egr4WnTykUrMNJcsVFETdxX GXxvknKJA30Wr82UZQn6S9t3RbWqj0LdAugAFSb4BlGUEDvIrgAJ5vr6eTeGNjog K4nHBejeVuHzm2gmHQn+StSE1VSAm/QwMPeVCxtfkUrk0waoRvijPUxscBkL6AzA jQrr4jyas3Mp8vndKFjtb1yNZK+fLV3qH51QUAqE7qOlLSQKnzuOCodMPpVtF/S3 gOIh02nJhN2dJBJjnUTvlDbDx1o6SLON/dhNAHWtdnEb2w3gmJ+vDDIzO7fpjMvE sz5VMe/WRjuAeY+U5LHEGRBo1UlAU4XTb0wiSBEKH/7ep853ofwVpv6GR+JIz2s4 88bDAsrMcVRwWpeyYpu6azCGC+7JSOKkf6EJYqg7DIZI5Zv/g5DyAHlQ2LqTYZY+ BWrB82mbIkYiwbludIQ3i4mIkn+IkSU9N1spwCCAQsAdkZCQ6nW9Jds8mB7KiAtL LQVjMCIpWepnbs9rvgQThMXhorDnmhU2KvCK/oA0q6jmgDe1YQ4Erwg+9IBus48U jNJ7MhCyVtn3qFXlERDIKjjJCtF48/VKREz1G7h7ZrxHZC02IKY= =iwpe -----END PGP SIGNATURE----- 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
This commit is contained in:
commit
de28a65cd0
@ -3826,7 +3826,7 @@ int amd_iommu_activate_guest_mode(void *data)
|
|||||||
entry->lo.fields_vapic.ga_tag = ir_data->ga_tag;
|
entry->lo.fields_vapic.ga_tag = ir_data->ga_tag;
|
||||||
|
|
||||||
return modify_irte_ga(ir_data->irq_2_irte.devid,
|
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);
|
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);
|
APICID_TO_IRTE_DEST_HI(cfg->dest_apicid);
|
||||||
|
|
||||||
return modify_irte_ga(ir_data->irq_2_irte.devid,
|
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);
|
EXPORT_SYMBOL(amd_iommu_deactivate_guest_mode);
|
||||||
|
|
||||||
|
@ -177,15 +177,15 @@ static int cookie_init_hw_msi_region(struct iommu_dma_cookie *cookie,
|
|||||||
start -= iova_offset(iovad, start);
|
start -= iova_offset(iovad, start);
|
||||||
num_pages = iova_align(iovad, end - start) >> iova_shift(iovad);
|
num_pages = iova_align(iovad, end - start) >> iova_shift(iovad);
|
||||||
|
|
||||||
msi_page = kcalloc(num_pages, sizeof(*msi_page), GFP_KERNEL);
|
|
||||||
if (!msi_page)
|
|
||||||
return -ENOMEM;
|
|
||||||
|
|
||||||
for (i = 0; i < num_pages; i++) {
|
for (i = 0; i < num_pages; i++) {
|
||||||
msi_page[i].phys = start;
|
msi_page = kmalloc(sizeof(*msi_page), GFP_KERNEL);
|
||||||
msi_page[i].iova = start;
|
if (!msi_page)
|
||||||
INIT_LIST_HEAD(&msi_page[i].list);
|
return -ENOMEM;
|
||||||
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;
|
start += iovad->granule;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -28,6 +28,7 @@
|
|||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
#include <linux/iommu.h>
|
#include <linux/iommu.h>
|
||||||
#include <linux/numa.h>
|
#include <linux/numa.h>
|
||||||
|
#include <linux/limits.h>
|
||||||
#include <asm/irq_remapping.h>
|
#include <asm/irq_remapping.h>
|
||||||
#include <asm/iommu_table.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);
|
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 */
|
/* Only generate path[] for device addition event */
|
||||||
if (event == BUS_NOTIFY_ADD_DEVICE)
|
if (event == BUS_NOTIFY_ADD_DEVICE)
|
||||||
for (tmp = dev; tmp; tmp = tmp->bus->self)
|
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;
|
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 &&
|
if (dmaru->segment == drhd->segment &&
|
||||||
dmaru->reg_base_addr == drhd->address)
|
dmaru->reg_base_addr == drhd->address)
|
||||||
return dmaru;
|
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 */
|
/* Check for NUL termination within the designated length */
|
||||||
if (strnlen(andd->device_name, header->length - 8) == header->length - 8) {
|
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"
|
"Your BIOS is broken; ANDD object name is not NUL-terminated\n"
|
||||||
"BIOS vendor: %s; Ver: %s; Product Version: %s\n",
|
"BIOS vendor: %s; Ver: %s; Product Version: %s\n",
|
||||||
dmi_get_system_info(DMI_BIOS_VENDOR),
|
dmi_get_system_info(DMI_BIOS_VENDOR),
|
||||||
dmi_get_system_info(DMI_BIOS_VERSION),
|
dmi_get_system_info(DMI_BIOS_VERSION),
|
||||||
dmi_get_system_info(DMI_PRODUCT_VERSION));
|
dmi_get_system_info(DMI_PRODUCT_VERSION));
|
||||||
|
add_taint(TAINT_FIRMWARE_WORKAROUND, LOCKDEP_STILL_OK);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
pr_info("ANDD device: %x name: %s\n", andd->device_number,
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
WARN_TAINT(
|
pr_warn(FW_BUG
|
||||||
1, TAINT_FIRMWARE_WORKAROUND,
|
|
||||||
"Your BIOS is broken; RHSA refers to non-existent DMAR unit at %llx\n"
|
"Your BIOS is broken; RHSA refers to non-existent DMAR unit at %llx\n"
|
||||||
"BIOS vendor: %s; Ver: %s; Product Version: %s\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_VENDOR),
|
||||||
dmi_get_system_info(DMI_BIOS_VERSION),
|
dmi_get_system_info(DMI_BIOS_VERSION),
|
||||||
dmi_get_system_info(DMI_PRODUCT_VERSION));
|
dmi_get_system_info(DMI_PRODUCT_VERSION));
|
||||||
|
add_taint(TAINT_FIRMWARE_WORKAROUND, LOCKDEP_STILL_OK);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -827,14 +837,14 @@ int __init dmar_table_init(void)
|
|||||||
|
|
||||||
static void warn_invalid_dmar(u64 addr, const char *message)
|
static void warn_invalid_dmar(u64 addr, const char *message)
|
||||||
{
|
{
|
||||||
WARN_TAINT_ONCE(
|
pr_warn_once(FW_BUG
|
||||||
1, TAINT_FIRMWARE_WORKAROUND,
|
|
||||||
"Your BIOS is broken; DMAR reported at address %llx%s!\n"
|
"Your BIOS is broken; DMAR reported at address %llx%s!\n"
|
||||||
"BIOS vendor: %s; Ver: %s; Product Version: %s\n",
|
"BIOS vendor: %s; Ver: %s; Product Version: %s\n",
|
||||||
addr, message,
|
addr, message,
|
||||||
dmi_get_system_info(DMI_BIOS_VENDOR),
|
dmi_get_system_info(DMI_BIOS_VENDOR),
|
||||||
dmi_get_system_info(DMI_BIOS_VERSION),
|
dmi_get_system_info(DMI_BIOS_VERSION),
|
||||||
dmi_get_system_info(DMI_PRODUCT_VERSION));
|
dmi_get_system_info(DMI_PRODUCT_VERSION));
|
||||||
|
add_taint(TAINT_FIRMWARE_WORKAROUND, LOCKDEP_STILL_OK);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int __ref
|
static int __ref
|
||||||
|
@ -33,38 +33,42 @@ struct iommu_regset {
|
|||||||
|
|
||||||
#define IOMMU_REGSET_ENTRY(_reg_) \
|
#define IOMMU_REGSET_ENTRY(_reg_) \
|
||||||
{ DMAR_##_reg_##_REG, __stringify(_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(VER),
|
||||||
IOMMU_REGSET_ENTRY(CAP),
|
|
||||||
IOMMU_REGSET_ENTRY(ECAP),
|
|
||||||
IOMMU_REGSET_ENTRY(GCMD),
|
IOMMU_REGSET_ENTRY(GCMD),
|
||||||
IOMMU_REGSET_ENTRY(GSTS),
|
IOMMU_REGSET_ENTRY(GSTS),
|
||||||
IOMMU_REGSET_ENTRY(RTADDR),
|
|
||||||
IOMMU_REGSET_ENTRY(CCMD),
|
|
||||||
IOMMU_REGSET_ENTRY(FSTS),
|
IOMMU_REGSET_ENTRY(FSTS),
|
||||||
IOMMU_REGSET_ENTRY(FECTL),
|
IOMMU_REGSET_ENTRY(FECTL),
|
||||||
IOMMU_REGSET_ENTRY(FEDATA),
|
IOMMU_REGSET_ENTRY(FEDATA),
|
||||||
IOMMU_REGSET_ENTRY(FEADDR),
|
IOMMU_REGSET_ENTRY(FEADDR),
|
||||||
IOMMU_REGSET_ENTRY(FEUADDR),
|
IOMMU_REGSET_ENTRY(FEUADDR),
|
||||||
IOMMU_REGSET_ENTRY(AFLOG),
|
|
||||||
IOMMU_REGSET_ENTRY(PMEN),
|
IOMMU_REGSET_ENTRY(PMEN),
|
||||||
IOMMU_REGSET_ENTRY(PLMBASE),
|
IOMMU_REGSET_ENTRY(PLMBASE),
|
||||||
IOMMU_REGSET_ENTRY(PLMLIMIT),
|
IOMMU_REGSET_ENTRY(PLMLIMIT),
|
||||||
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(ICS),
|
||||||
IOMMU_REGSET_ENTRY(IRTA),
|
|
||||||
IOMMU_REGSET_ENTRY(PQH),
|
|
||||||
IOMMU_REGSET_ENTRY(PQT),
|
|
||||||
IOMMU_REGSET_ENTRY(PQA),
|
|
||||||
IOMMU_REGSET_ENTRY(PRS),
|
IOMMU_REGSET_ENTRY(PRS),
|
||||||
IOMMU_REGSET_ENTRY(PECTL),
|
IOMMU_REGSET_ENTRY(PECTL),
|
||||||
IOMMU_REGSET_ENTRY(PEDATA),
|
IOMMU_REGSET_ENTRY(PEDATA),
|
||||||
IOMMU_REGSET_ENTRY(PEADDR),
|
IOMMU_REGSET_ENTRY(PEADDR),
|
||||||
IOMMU_REGSET_ENTRY(PEUADDR),
|
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(IRTA),
|
||||||
|
IOMMU_REGSET_ENTRY(PQH),
|
||||||
|
IOMMU_REGSET_ENTRY(PQT),
|
||||||
|
IOMMU_REGSET_ENTRY(PQA),
|
||||||
IOMMU_REGSET_ENTRY(MTRRCAP),
|
IOMMU_REGSET_ENTRY(MTRRCAP),
|
||||||
IOMMU_REGSET_ENTRY(MTRRDEF),
|
IOMMU_REGSET_ENTRY(MTRRDEF),
|
||||||
IOMMU_REGSET_ENTRY(MTRR_FIX64K_00000),
|
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).
|
* by adding the offset to the pointer (virtual address).
|
||||||
*/
|
*/
|
||||||
raw_spin_lock_irqsave(&iommu->register_lock, flag);
|
raw_spin_lock_irqsave(&iommu->register_lock, flag);
|
||||||
for (i = 0 ; i < ARRAY_SIZE(iommu_regs); i++) {
|
for (i = 0 ; i < ARRAY_SIZE(iommu_regs_32); i++) {
|
||||||
value = dmar_readq(iommu->reg + iommu_regs[i].offset);
|
value = dmar_readl(iommu->reg + iommu_regs_32[i].offset);
|
||||||
seq_printf(m, "%-16s\t0x%02x\t\t0x%016llx\n",
|
seq_printf(m, "%-16s\t0x%02x\t\t0x%016llx\n",
|
||||||
iommu_regs[i].regs, iommu_regs[i].offset,
|
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_64[i].regs, iommu_regs_64[i].offset,
|
||||||
value);
|
value);
|
||||||
}
|
}
|
||||||
raw_spin_unlock_irqrestore(&iommu->register_lock, flag);
|
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 dmar_drhd_unit *drhd;
|
||||||
struct intel_iommu *iommu;
|
struct intel_iommu *iommu;
|
||||||
|
u32 sts;
|
||||||
|
|
||||||
rcu_read_lock();
|
rcu_read_lock();
|
||||||
for_each_active_iommu(iommu, drhd) {
|
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);
|
root_tbl_walk(m, iommu);
|
||||||
seq_putc(m, '\n');
|
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 dmar_drhd_unit *drhd;
|
||||||
struct intel_iommu *iommu;
|
struct intel_iommu *iommu;
|
||||||
u64 irta;
|
u64 irta;
|
||||||
|
u32 sts;
|
||||||
|
|
||||||
rcu_read_lock();
|
rcu_read_lock();
|
||||||
for_each_active_iommu(iommu, drhd) {
|
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",
|
seq_printf(m, "Remapped Interrupt supported on IOMMU: %s\n",
|
||||||
iommu->name);
|
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);
|
irta = virt_to_phys(iommu->ir_table->base);
|
||||||
seq_printf(m, " IR table address:%llx\n", irta);
|
seq_printf(m, " IR table address:%llx\n", irta);
|
||||||
ir_tbl_remap_entry_show(m, iommu);
|
ir_tbl_remap_entry_show(m, iommu);
|
||||||
|
@ -4261,10 +4261,11 @@ static void quirk_ioat_snb_local_iommu(struct pci_dev *pdev)
|
|||||||
|
|
||||||
/* we know that the this iommu should be at offset 0xa000 from vtbar */
|
/* we know that the this iommu should be at offset 0xa000 from vtbar */
|
||||||
drhd = dmar_find_matched_drhd_unit(pdev);
|
drhd = dmar_find_matched_drhd_unit(pdev);
|
||||||
if (WARN_TAINT_ONCE(!drhd || drhd->reg_base_addr - vtbar != 0xa000,
|
if (!drhd || drhd->reg_base_addr - vtbar != 0xa000) {
|
||||||
TAINT_FIRMWARE_WORKAROUND,
|
pr_warn_once(FW_BUG "BIOS assigned incorrect VT-d unit for Intel(R) QuickData Technology device\n");
|
||||||
"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;
|
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);
|
DECLARE_PCI_FIXUP_ENABLE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_IOAT_SNB, quirk_ioat_snb_local_iommu);
|
||||||
|
|
||||||
@ -4460,14 +4461,16 @@ int __init dmar_parse_one_rmrr(struct acpi_dmar_header *header, void *arg)
|
|||||||
struct dmar_rmrr_unit *rmrru;
|
struct dmar_rmrr_unit *rmrru;
|
||||||
|
|
||||||
rmrr = (struct acpi_dmar_reserved_memory *)header;
|
rmrr = (struct acpi_dmar_reserved_memory *)header;
|
||||||
if (rmrr_sanity_check(rmrr))
|
if (rmrr_sanity_check(rmrr)) {
|
||||||
WARN_TAINT(1, TAINT_FIRMWARE_WORKAROUND,
|
pr_warn(FW_BUG
|
||||||
"Your BIOS is broken; bad RMRR [%#018Lx-%#018Lx]\n"
|
"Your BIOS is broken; bad RMRR [%#018Lx-%#018Lx]\n"
|
||||||
"BIOS vendor: %s; Ver: %s; Product Version: %s\n",
|
"BIOS vendor: %s; Ver: %s; Product Version: %s\n",
|
||||||
rmrr->base_address, rmrr->end_address,
|
rmrr->base_address, rmrr->end_address,
|
||||||
dmi_get_system_info(DMI_BIOS_VENDOR),
|
dmi_get_system_info(DMI_BIOS_VENDOR),
|
||||||
dmi_get_system_info(DMI_BIOS_VERSION),
|
dmi_get_system_info(DMI_BIOS_VERSION),
|
||||||
dmi_get_system_info(DMI_PRODUCT_VERSION));
|
dmi_get_system_info(DMI_PRODUCT_VERSION));
|
||||||
|
add_taint(TAINT_FIRMWARE_WORKAROUND, LOCKDEP_STILL_OK);
|
||||||
|
}
|
||||||
|
|
||||||
rmrru = kzalloc(sizeof(*rmrru), GFP_KERNEL);
|
rmrru = kzalloc(sizeof(*rmrru), GFP_KERNEL);
|
||||||
if (!rmrru)
|
if (!rmrru)
|
||||||
@ -5130,6 +5133,9 @@ int __init intel_iommu_init(void)
|
|||||||
|
|
||||||
down_write(&dmar_global_lock);
|
down_write(&dmar_global_lock);
|
||||||
|
|
||||||
|
if (!no_iommu)
|
||||||
|
intel_iommu_debugfs_init();
|
||||||
|
|
||||||
if (no_iommu || dmar_disabled) {
|
if (no_iommu || dmar_disabled) {
|
||||||
/*
|
/*
|
||||||
* We exit the function here to ensure IOMMU's remapping and
|
* 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();
|
init_iommu_pm_ops();
|
||||||
|
|
||||||
|
down_read(&dmar_global_lock);
|
||||||
for_each_active_iommu(iommu, drhd) {
|
for_each_active_iommu(iommu, drhd) {
|
||||||
iommu_device_sysfs_add(&iommu->iommu, NULL,
|
iommu_device_sysfs_add(&iommu->iommu, NULL,
|
||||||
intel_iommu_groups,
|
intel_iommu_groups,
|
||||||
@ -5200,6 +5207,7 @@ int __init intel_iommu_init(void)
|
|||||||
iommu_device_set_ops(&iommu->iommu, &intel_iommu_ops);
|
iommu_device_set_ops(&iommu->iommu, &intel_iommu_ops);
|
||||||
iommu_device_register(&iommu->iommu);
|
iommu_device_register(&iommu->iommu);
|
||||||
}
|
}
|
||||||
|
up_read(&dmar_global_lock);
|
||||||
|
|
||||||
bus_set_iommu(&pci_bus_type, &intel_iommu_ops);
|
bus_set_iommu(&pci_bus_type, &intel_iommu_ops);
|
||||||
if (si_domain && !hw_pass_through)
|
if (si_domain && !hw_pass_through)
|
||||||
@ -5210,7 +5218,6 @@ int __init intel_iommu_init(void)
|
|||||||
down_read(&dmar_global_lock);
|
down_read(&dmar_global_lock);
|
||||||
if (probe_acpi_namespace_devices())
|
if (probe_acpi_namespace_devices())
|
||||||
pr_warn("ACPI name space devices didn't probe correctly\n");
|
pr_warn("ACPI name space devices didn't probe correctly\n");
|
||||||
up_read(&dmar_global_lock);
|
|
||||||
|
|
||||||
/* Finally, we enable the DMA remapping hardware. */
|
/* Finally, we enable the DMA remapping hardware. */
|
||||||
for_each_iommu(iommu, drhd) {
|
for_each_iommu(iommu, drhd) {
|
||||||
@ -5219,10 +5226,11 @@ int __init intel_iommu_init(void)
|
|||||||
|
|
||||||
iommu_disable_protect_mem_regions(iommu);
|
iommu_disable_protect_mem_regions(iommu);
|
||||||
}
|
}
|
||||||
|
up_read(&dmar_global_lock);
|
||||||
|
|
||||||
pr_info("Intel(R) Virtualization Technology for Directed I/O\n");
|
pr_info("Intel(R) Virtualization Technology for Directed I/O\n");
|
||||||
|
|
||||||
intel_iommu_enabled = 1;
|
intel_iommu_enabled = 1;
|
||||||
intel_iommu_debugfs_init();
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
@ -5700,8 +5708,10 @@ static phys_addr_t intel_iommu_iova_to_phys(struct iommu_domain *domain,
|
|||||||
u64 phys = 0;
|
u64 phys = 0;
|
||||||
|
|
||||||
pte = pfn_to_dma_pte(dmar_domain, iova >> VTD_PAGE_SHIFT, &level);
|
pte = pfn_to_dma_pte(dmar_domain, iova >> VTD_PAGE_SHIFT, &level);
|
||||||
if (pte)
|
if (pte && dma_pte_present(pte))
|
||||||
phys = dma_pte_addr(pte);
|
phys = dma_pte_addr(pte) +
|
||||||
|
(iova & (BIT_MASK(level_to_offset_bits(level) +
|
||||||
|
VTD_PAGE_SHIFT) - 1));
|
||||||
|
|
||||||
return phys;
|
return phys;
|
||||||
}
|
}
|
||||||
|
@ -468,7 +468,7 @@ static int arm_lpae_map(struct io_pgtable_ops *ops, unsigned long iova,
|
|||||||
arm_lpae_iopte *ptep = data->pgd;
|
arm_lpae_iopte *ptep = data->pgd;
|
||||||
int ret, lvl = data->start_level;
|
int ret, lvl = data->start_level;
|
||||||
arm_lpae_iopte prot;
|
arm_lpae_iopte prot;
|
||||||
long iaext = (long)iova >> cfg->ias;
|
long iaext = (s64)iova >> cfg->ias;
|
||||||
|
|
||||||
/* If no access, then nothing to do */
|
/* If no access, then nothing to do */
|
||||||
if (!(iommu_prot & (IOMMU_READ | IOMMU_WRITE)))
|
if (!(iommu_prot & (IOMMU_READ | IOMMU_WRITE)))
|
||||||
@ -645,7 +645,7 @@ static size_t arm_lpae_unmap(struct io_pgtable_ops *ops, unsigned long iova,
|
|||||||
struct arm_lpae_io_pgtable *data = io_pgtable_ops_to_data(ops);
|
struct arm_lpae_io_pgtable *data = io_pgtable_ops_to_data(ops);
|
||||||
struct io_pgtable_cfg *cfg = &data->iop.cfg;
|
struct io_pgtable_cfg *cfg = &data->iop.cfg;
|
||||||
arm_lpae_iopte *ptep = data->pgd;
|
arm_lpae_iopte *ptep = data->pgd;
|
||||||
long iaext = (long)iova >> cfg->ias;
|
long iaext = (s64)iova >> cfg->ias;
|
||||||
|
|
||||||
if (WARN_ON(!size || (size & cfg->pgsize_bitmap) != size))
|
if (WARN_ON(!size || (size & cfg->pgsize_bitmap) != size))
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -69,19 +69,23 @@ struct dmar_pci_notify_info {
|
|||||||
extern struct rw_semaphore dmar_global_lock;
|
extern struct rw_semaphore dmar_global_lock;
|
||||||
extern struct list_head dmar_drhd_units;
|
extern struct list_head dmar_drhd_units;
|
||||||
|
|
||||||
#define for_each_drhd_unit(drhd) \
|
#define for_each_drhd_unit(drhd) \
|
||||||
list_for_each_entry_rcu(drhd, &dmar_drhd_units, list)
|
list_for_each_entry_rcu(drhd, &dmar_drhd_units, list, \
|
||||||
|
dmar_rcu_check())
|
||||||
|
|
||||||
#define for_each_active_drhd_unit(drhd) \
|
#define for_each_active_drhd_unit(drhd) \
|
||||||
list_for_each_entry_rcu(drhd, &dmar_drhd_units, list) \
|
list_for_each_entry_rcu(drhd, &dmar_drhd_units, list, \
|
||||||
|
dmar_rcu_check()) \
|
||||||
if (drhd->ignored) {} else
|
if (drhd->ignored) {} else
|
||||||
|
|
||||||
#define for_each_active_iommu(i, drhd) \
|
#define for_each_active_iommu(i, drhd) \
|
||||||
list_for_each_entry_rcu(drhd, &dmar_drhd_units, list) \
|
list_for_each_entry_rcu(drhd, &dmar_drhd_units, list, \
|
||||||
|
dmar_rcu_check()) \
|
||||||
if (i=drhd->iommu, drhd->ignored) {} else
|
if (i=drhd->iommu, drhd->ignored) {} else
|
||||||
|
|
||||||
#define for_each_iommu(i, drhd) \
|
#define for_each_iommu(i, drhd) \
|
||||||
list_for_each_entry_rcu(drhd, &dmar_drhd_units, list) \
|
list_for_each_entry_rcu(drhd, &dmar_drhd_units, list, \
|
||||||
|
dmar_rcu_check()) \
|
||||||
if (i=drhd->iommu, 0) {} else
|
if (i=drhd->iommu, 0) {} else
|
||||||
|
|
||||||
static inline bool dmar_rcu_check(void)
|
static inline bool dmar_rcu_check(void)
|
||||||
|
@ -123,6 +123,8 @@
|
|||||||
|
|
||||||
#define dmar_readq(a) readq(a)
|
#define dmar_readq(a) readq(a)
|
||||||
#define dmar_writeq(a,v) writeq(v,a)
|
#define dmar_writeq(a,v) writeq(v,a)
|
||||||
|
#define dmar_readl(a) readl(a)
|
||||||
|
#define dmar_writel(a, v) writel(v, a)
|
||||||
|
|
||||||
#define DMAR_VER_MAJOR(v) (((v) & 0xf0) >> 4)
|
#define DMAR_VER_MAJOR(v) (((v) & 0xf0) >> 4)
|
||||||
#define DMAR_VER_MINOR(v) ((v) & 0x0f)
|
#define DMAR_VER_MINOR(v) ((v) & 0x0f)
|
||||||
|
Loading…
Reference in New Issue
Block a user