Commit 98265300 authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'core-iommu-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip

* 'core-iommu-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
  x86, ioapic: Consolidate the explicit EOI code
  x86, ioapic: Restore the mask bit correctly in eoi_ioapic_irq()
  x86, kdump, ioapic: Reset remote-IRR in clear_IO_APIC
  iommu: Rename the DMAR and INTR_REMAP config options
  x86, ioapic: Define irq_remap_modify_chip_defaults()
  x86, msi, intr-remap: Use the ioapic set affinity routine
  iommu: Cleanup ifdefs in detect_intel_iommu()
  iommu: No need to set dmar_disabled in check_zero_address()
  iommu: Move IOMMU specific code to intel-iommu.c
  intr_remap: Call dmar_dev_scope_init() explicitly
  x86, x2apic: Enable the bios request for x2apic optout
parents 37d96c28 c0205701
......@@ -1020,10 +1020,11 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
has the capability. With this option, super page will
not be supported.
intremap= [X86-64, Intel-IOMMU]
Format: { on (default) | off | nosid }
on enable Interrupt Remapping (default)
off disable Interrupt Remapping
nosid disable Source ID checking
no_x2apic_optout
BIOS x2APIC opt-out request will be ignored
inttest= [IA-64]
......
......@@ -234,4 +234,4 @@ CONFIG_CRYPTO_MD5=y
# CONFIG_CRYPTO_ANSI_CPRNG is not set
CONFIG_CRC_T10DIF=y
CONFIG_MISC_DEVICES=y
CONFIG_DMAR=y
CONFIG_INTEL_IOMMU=y
......@@ -6,7 +6,7 @@
#
obj-y := setup.o
ifeq ($(CONFIG_DMAR), y)
ifeq ($(CONFIG_INTEL_IOMMU), y)
obj-$(CONFIG_IA64_GENERIC) += machvec.o machvec_vtd.o
else
obj-$(CONFIG_IA64_GENERIC) += machvec.o
......
......@@ -10,7 +10,7 @@ struct dev_archdata {
#ifdef CONFIG_ACPI
void *acpi_handle;
#endif
#ifdef CONFIG_DMAR
#ifdef CONFIG_INTEL_IOMMU
void *iommu; /* hook for IOMMU specific extension */
#endif
};
......
......@@ -7,12 +7,14 @@
extern void pci_iommu_shutdown(void);
extern void no_iommu_init(void);
#ifdef CONFIG_INTEL_IOMMU
extern int force_iommu, no_iommu;
extern int iommu_detected;
#ifdef CONFIG_DMAR
extern int iommu_pass_through;
extern int iommu_detected;
#else
#define iommu_pass_through (0)
#define no_iommu (1)
#define iommu_detected (0)
#endif
extern void iommu_dma_init(void);
extern void machvec_init(const char *name);
......
......@@ -139,7 +139,7 @@ static inline int pci_get_legacy_ide_irq(struct pci_dev *dev, int channel)
return channel ? isa_irq_to_vector(15) : isa_irq_to_vector(14);
}
#ifdef CONFIG_DMAR
#ifdef CONFIG_INTEL_IOMMU
extern void pci_iommu_alloc(void);
#endif
#endif /* _ASM_IA64_PCI_H */
......@@ -43,7 +43,7 @@ obj-$(CONFIG_IA64_ESI) += esi.o
ifneq ($(CONFIG_IA64_ESI),)
obj-y += esi_stub.o # must be in kernel proper
endif
obj-$(CONFIG_DMAR) += pci-dma.o
obj-$(CONFIG_INTEL_IOMMU) += pci-dma.o
obj-$(CONFIG_SWIOTLB) += pci-swiotlb.o
obj-$(CONFIG_BINFMT_ELF) += elfcore.o
......
......@@ -88,7 +88,7 @@ acpi_get_sysname(void)
struct acpi_table_rsdp *rsdp;
struct acpi_table_xsdt *xsdt;
struct acpi_table_header *hdr;
#ifdef CONFIG_DMAR
#ifdef CONFIG_INTEL_IOMMU
u64 i, nentries;
#endif
......@@ -125,7 +125,7 @@ acpi_get_sysname(void)
return "xen";
}
#ifdef CONFIG_DMAR
#ifdef CONFIG_INTEL_IOMMU
/* Look for Intel IOMMU */
nentries = (hdr->length - sizeof(*hdr)) /
sizeof(xsdt->table_offset_entry[0]);
......
......@@ -131,7 +131,7 @@ void arch_teardown_msi_irq(unsigned int irq)
return ia64_teardown_msi_irq(irq);
}
#ifdef CONFIG_DMAR
#ifdef CONFIG_INTEL_IOMMU
#ifdef CONFIG_SMP
static int dmar_msi_set_affinity(struct irq_data *data,
const struct cpumask *mask, bool force)
......@@ -210,5 +210,5 @@ int arch_setup_dmar_msi(unsigned int irq)
"edge");
return 0;
}
#endif /* CONFIG_DMAR */
#endif /* CONFIG_INTEL_IOMMU */
......@@ -14,7 +14,7 @@
#include <asm/system.h>
#ifdef CONFIG_DMAR
#ifdef CONFIG_INTEL_IOMMU
#include <linux/kernel.h>
......
......@@ -130,7 +130,7 @@ config SBUS
bool
config NEED_DMA_MAP_STATE
def_bool (X86_64 || DMAR || DMA_API_DEBUG)
def_bool (X86_64 || INTEL_IOMMU || DMA_API_DEBUG)
config NEED_SG_DMA_LENGTH
def_bool y
......@@ -220,7 +220,7 @@ config ARCH_SUPPORTS_DEBUG_PAGEALLOC
config HAVE_INTEL_TXT
def_bool y
depends on EXPERIMENTAL && DMAR && ACPI
depends on EXPERIMENTAL && INTEL_IOMMU && ACPI
config X86_32_SMP
def_bool y
......@@ -287,7 +287,7 @@ config SMP
config X86_X2APIC
bool "Support x2apic"
depends on X86_LOCAL_APIC && X86_64 && INTR_REMAP
depends on X86_LOCAL_APIC && X86_64 && IRQ_REMAP
---help---
This enables x2apic support on CPUs that have this feature.
......
......@@ -67,8 +67,8 @@ CONFIG_CPU_FREQ_GOV_PERFORMANCE=y
CONFIG_CPU_FREQ_GOV_ONDEMAND=y
CONFIG_X86_ACPI_CPUFREQ=y
CONFIG_PCI_MMCONFIG=y
CONFIG_DMAR=y
# CONFIG_DMAR_DEFAULT_ON is not set
CONFIG_INTEL_IOMMU=y
# CONFIG_INTEL_IOMMU_DEFAULT_ON is not set
CONFIG_PCIEPORTBUS=y
CONFIG_PCCARD=y
CONFIG_YENTA=y
......
......@@ -8,7 +8,7 @@ struct dev_archdata {
#ifdef CONFIG_X86_64
struct dma_map_ops *dma_ops;
#endif
#if defined(CONFIG_DMAR) || defined(CONFIG_AMD_IOMMU)
#if defined(CONFIG_INTEL_IOMMU) || defined(CONFIG_AMD_IOMMU)
void *iommu; /* hook for IOMMU specific extension */
#endif
};
......
......@@ -119,7 +119,7 @@ struct irq_cfg {
cpumask_var_t old_domain;
u8 vector;
u8 move_in_progress : 1;
#ifdef CONFIG_INTR_REMAP
#ifdef CONFIG_IRQ_REMAP
struct irq_2_iommu irq_2_iommu;
#endif
};
......
......@@ -3,7 +3,8 @@
#define IRTE_DEST(dest) ((x2apic_mode) ? dest : dest << 8)
#ifdef CONFIG_INTR_REMAP
#ifdef CONFIG_IRQ_REMAP
static void irq_remap_modify_chip_defaults(struct irq_chip *chip);
static inline void prepare_irte(struct irte *irte, int vector,
unsigned int dest)
{
......@@ -36,6 +37,9 @@ static inline bool irq_remapped(struct irq_cfg *cfg)
{
return false;
}
static inline void irq_remap_modify_chip_defaults(struct irq_chip *chip)
{
}
#endif
#endif /* _ASM_X86_IRQ_REMAPPING_H */
......@@ -1437,27 +1437,21 @@ void enable_x2apic(void)
int __init enable_IR(void)
{
#ifdef CONFIG_INTR_REMAP
#ifdef CONFIG_IRQ_REMAP
if (!intr_remapping_supported()) {
pr_debug("intr-remapping not supported\n");
return 0;
return -1;
}
if (!x2apic_preenabled && skip_ioapic_setup) {
pr_info("Skipped enabling intr-remap because of skipping "
"io-apic setup\n");
return 0;
return -1;
}
if (enable_intr_remapping(x2apic_supported()))
return 0;
pr_info("Enabled Interrupt-remapping\n");
return 1;
return enable_intr_remapping();
#endif
return 0;
return -1;
}
void __init enable_IR_x2apic(void)
......@@ -1481,11 +1475,11 @@ void __init enable_IR_x2apic(void)
mask_ioapic_entries();
if (dmar_table_init_ret)
ret = 0;
ret = -1;
else
ret = enable_IR();
if (!ret) {
if (ret < 0) {
/* IR is required if there is APIC ID > 255 even when running
* under KVM
*/
......@@ -1499,6 +1493,9 @@ void __init enable_IR_x2apic(void)
x2apic_force_phys();
}
if (ret == IRQ_REMAP_XAPIC_MODE)
goto nox2apic;
x2apic_enabled = 1;
if (x2apic_supported() && !x2apic_mode) {
......@@ -1508,19 +1505,21 @@ void __init enable_IR_x2apic(void)
}
nox2apic:
if (!ret) /* IR enabling failed */
if (ret < 0) /* IR enabling failed */
restore_ioapic_entries();
legacy_pic->restore_mask();
local_irq_restore(flags);
out:
if (x2apic_enabled)
if (x2apic_enabled || !x2apic_supported())
return;
if (x2apic_preenabled)
panic("x2apic: enabled by BIOS but kernel init failed.");
else if (cpu_has_x2apic)
pr_info("Not enabling x2apic, Intr-remapping init failed.\n");
else if (ret == IRQ_REMAP_XAPIC_MODE)
pr_info("x2apic not enabled, IRQ remapping is in xapic mode\n");
else if (ret < 0)
pr_info("x2apic not enabled, IRQ remapping init failed\n");
}
#ifdef CONFIG_X86_64
......
This diff is collapsed.
......@@ -30,10 +30,10 @@
/*
* If we have Intel graphics, we're not going to have anything other than
* an Intel IOMMU. So make the correct use of the PCI DMA API contingent
* on the Intel IOMMU support (CONFIG_DMAR).
* on the Intel IOMMU support (CONFIG_INTEL_IOMMU).
* Only newer chipsets need to bother with this, of course.
*/
#ifdef CONFIG_DMAR
#ifdef CONFIG_INTEL_IOMMU
#define USE_PCI_DMA_API 1
#else
#define USE_PCI_DMA_API 0
......
......@@ -59,10 +59,14 @@ config AMD_IOMMU_STATS
If unsure, say N.
# Intel IOMMU support
config DMAR
bool "Support for DMA Remapping Devices"
config DMAR_TABLE
bool
config INTEL_IOMMU
bool "Support for Intel IOMMU using DMA Remapping Devices"
depends on PCI_MSI && ACPI && (X86 || IA64_GENERIC)
select IOMMU_API
select DMAR_TABLE
help
DMA remapping (DMAR) devices support enables independent address
translations for Direct Memory Access (DMA) from devices.
......@@ -70,18 +74,18 @@ config DMAR
and include PCI device scope covered by these DMA
remapping devices.
config DMAR_DEFAULT_ON
config INTEL_IOMMU_DEFAULT_ON
def_bool y
prompt "Enable DMA Remapping Devices by default"
depends on DMAR
prompt "Enable Intel DMA Remapping Devices by default"
depends on INTEL_IOMMU
help
Selecting this option will enable a DMAR device at boot time if
one is found. If this option is not selected, DMAR support can
be enabled by passing intel_iommu=on to the kernel.
config DMAR_BROKEN_GFX_WA
config INTEL_IOMMU_BROKEN_GFX_WA
bool "Workaround broken graphics drivers (going away soon)"
depends on DMAR && BROKEN && X86
depends on INTEL_IOMMU && BROKEN && X86
---help---
Current Graphics drivers tend to use physical address
for DMA and avoid using DMA APIs. Setting this config
......@@ -90,18 +94,19 @@ config DMAR_BROKEN_GFX_WA
to use physical addresses for DMA, at least until this
option is removed in the 2.6.32 kernel.
config DMAR_FLOPPY_WA
config INTEL_IOMMU_FLOPPY_WA
def_bool y
depends on DMAR && X86
depends on INTEL_IOMMU && X86
---help---
Floppy disk drivers are known to bypass DMA API calls
thereby failing to work when IOMMU is enabled. This
workaround will setup a 1:1 mapping for the first
16MiB to make floppy (an ISA device) work.
config INTR_REMAP
config IRQ_REMAP
bool "Support for Interrupt Remapping (EXPERIMENTAL)"
depends on X86_64 && X86_IO_APIC && PCI_MSI && ACPI && EXPERIMENTAL
select DMAR_TABLE
---help---
Supports Interrupt remapping for IO-APIC and MSI devices.
To use x2apic mode in the CPU's which support x2APIC enhancements or
......
obj-$(CONFIG_IOMMU_API) += iommu.o
obj-$(CONFIG_MSM_IOMMU) += msm_iommu.o msm_iommu_dev.o
obj-$(CONFIG_AMD_IOMMU) += amd_iommu.o amd_iommu_init.o
obj-$(CONFIG_DMAR) += dmar.o iova.o intel-iommu.o
obj-$(CONFIG_INTR_REMAP) += dmar.o intr_remapping.o
obj-$(CONFIG_DMAR_TABLE) += dmar.o
obj-$(CONFIG_INTEL_IOMMU) += iova.o intel-iommu.o
obj-$(CONFIG_IRQ_REMAP) += intr_remapping.o
......@@ -46,7 +46,7 @@
*/
LIST_HEAD(dmar_drhd_units);
static struct acpi_table_header * __initdata dmar_tbl;
struct acpi_table_header * __initdata dmar_tbl;
static acpi_size dmar_tbl_size;
static void __init dmar_register_drhd_unit(struct dmar_drhd_unit *drhd)
......@@ -118,8 +118,8 @@ static int __init dmar_parse_one_dev_scope(struct acpi_dmar_device_scope *scope,
return 0;
}
static int __init dmar_parse_dev_scope(void *start, void *end, int *cnt,
struct pci_dev ***devices, u16 segment)
int __init dmar_parse_dev_scope(void *start, void *end, int *cnt,
struct pci_dev ***devices, u16 segment)
{
struct acpi_dmar_device_scope *scope;
void * tmp = start;
......@@ -217,133 +217,6 @@ static int __init dmar_parse_dev(struct dmar_drhd_unit *dmaru)
return ret;
}
#ifdef CONFIG_DMAR
LIST_HEAD(dmar_rmrr_units);
static void __init dmar_register_rmrr_unit(struct dmar_rmrr_unit *rmrr)
{
list_add(&rmrr->list, &dmar_rmrr_units);
}
static int __init
dmar_parse_one_rmrr(struct acpi_dmar_header *header)
{
struct acpi_dmar_reserved_memory *rmrr;
struct dmar_rmrr_unit *rmrru;
rmrru = kzalloc(sizeof(*rmrru), GFP_KERNEL);
if (!rmrru)
return -ENOMEM;
rmrru->hdr = header;
rmrr = (struct acpi_dmar_reserved_memory *)header;
rmrru->base_address = rmrr->base_address;
rmrru->end_address = rmrr->end_address;
dmar_register_rmrr_unit(rmrru);
return 0;
}
static int __init
rmrr_parse_dev(struct dmar_rmrr_unit *rmrru)
{
struct acpi_dmar_reserved_memory *rmrr;
int ret;
rmrr = (struct acpi_dmar_reserved_memory *) rmrru->hdr;
ret = dmar_parse_dev_scope((void *)(rmrr + 1),
((void *)rmrr) + rmrr->header.length,
&rmrru->devices_cnt, &rmrru->devices, rmrr->segment);
if (ret || (rmrru->devices_cnt == 0)) {
list_del(&rmrru->list);
kfree(rmrru);
}
return ret;
}
static LIST_HEAD(dmar_atsr_units);
static int __init dmar_parse_one_atsr(struct acpi_dmar_header *hdr)
{
struct acpi_dmar_atsr *atsr;
struct dmar_atsr_unit *atsru;
atsr = container_of(hdr, struct acpi_dmar_atsr, header);
atsru = kzalloc(sizeof(*atsru), GFP_KERNEL);
if (!atsru)
return -ENOMEM;
atsru->hdr = hdr;
atsru->include_all = atsr->flags & 0x1;
list_add(&atsru->list, &dmar_atsr_units);
return 0;
}
static int __init atsr_parse_dev(struct dmar_atsr_unit *atsru)
{
int rc;
struct acpi_dmar_atsr *atsr;
if (atsru->include_all)
return 0;
atsr = container_of(atsru->hdr, struct acpi_dmar_atsr, header);
rc = dmar_parse_dev_scope((void *)(atsr + 1),
(void *)atsr + atsr->header.length,
&atsru->devices_cnt, &atsru->devices,
atsr->segment);
if (rc || !atsru->devices_cnt) {
list_del(&atsru->list);
kfree(atsru);
}
return rc;
}
int dmar_find_matched_atsr_unit(struct pci_dev *dev)
{
int i;
struct pci_bus *bus;
struct acpi_dmar_atsr *atsr;
struct dmar_atsr_unit *atsru;
dev = pci_physfn(dev);
list_for_each_entry(atsru, &dmar_atsr_units, list) {
atsr = container_of(atsru->hdr, struct acpi_dmar_atsr, header);
if (atsr->segment == pci_domain_nr(dev->bus))
goto found;
}
return 0;
found:
for (bus = dev->bus; bus; bus = bus->parent) {
struct pci_dev *bridge = bus->self;
if (!bridge || !pci_is_pcie(bridge) ||
bridge->pcie_type == PCI_EXP_TYPE_PCI_BRIDGE)
return 0;
if (bridge->pcie_type == PCI_EXP_TYPE_ROOT_PORT) {
for (i = 0; i < atsru->devices_cnt; i++)
if (atsru->devices[i] == bridge)
return 1;
break;
}
}
if (atsru->include_all)
return 1;
return 0;
}
#endif
#ifdef CONFIG_ACPI_NUMA
static int __init
dmar_parse_one_rhsa(struct acpi_dmar_header *header)
......@@ -484,14 +357,10 @@ parse_dmar_table(void)
ret = dmar_parse_one_drhd(entry_header);
break;
case ACPI_DMAR_TYPE_RESERVED_MEMORY:
#ifdef CONFIG_DMAR
ret = dmar_parse_one_rmrr(entry_header);
#endif
break;
case ACPI_DMAR_TYPE_ATSR:
#ifdef CONFIG_DMAR
ret = dmar_parse_one_atsr(entry_header);
#endif
break;
case ACPI_DMAR_HARDWARE_AFFINITY:
#ifdef CONFIG_ACPI_NUMA
......@@ -557,34 +426,31 @@ dmar_find_matched_drhd_unit(struct pci_dev *dev)
int __init dmar_dev_scope_init(void)
{
static int dmar_dev_scope_initialized;
struct dmar_drhd_unit *drhd, *drhd_n;
int ret = -ENODEV;
if (dmar_dev_scope_initialized)
return dmar_dev_scope_initialized;
if (list_empty(&dmar_drhd_units))
goto fail;
list_for_each_entry_safe(drhd, drhd_n, &dmar_drhd_units, list) {
ret = dmar_parse_dev(drhd);
if (ret)
return ret;
goto fail;
}
#ifdef CONFIG_DMAR
{
struct dmar_rmrr_unit *rmrr, *rmrr_n;
struct dmar_atsr_unit *atsr, *atsr_n;
list_for_each_entry_safe(rmrr, rmrr_n, &dmar_rmrr_units, list) {
ret = rmrr_parse_dev(rmrr);
if (ret)
return ret;
}
ret = dmar_parse_rmrr_atsr_dev();
if (ret)
goto fail;
list_for_each_entry_safe(atsr, atsr_n, &dmar_atsr_units, list) {
ret = atsr_parse_dev(atsr);
if (ret)
return ret;
}
}
#endif
dmar_dev_scope_initialized = 1;
return 0;
fail:
dmar_dev_scope_initialized = ret;
return ret;
}
......@@ -611,14 +477,6 @@ int __init dmar_table_init(void)
return -ENODEV;
}
#ifdef CONFIG_DMAR
if (list_empty(&dmar_rmrr_units))
printk(KERN_INFO PREFIX "No RMRR found\n");
if (list_empty(&dmar_atsr_units))
printk(KERN_INFO PREFIX "No ATSR found\n");
#endif
return 0;
}
......@@ -682,9 +540,6 @@ int __init check_zero_address(void)
return 1;
failed:
#ifdef CONFIG_DMAR
dmar_disabled = 1;
#endif
return 0;
}
......@@ -696,22 +551,21 @@ int __init detect_intel_iommu(void)
if (ret)
ret = check_zero_address();
{
#ifdef CONFIG_INTR_REMAP
struct acpi_table_dmar *dmar;
dmar = (struct acpi_table_dmar *) dmar_tbl;
if (ret && cpu_has_x2apic && dmar->flags & 0x1)
if (ret && intr_remapping_enabled && cpu_has_x2apic &&
dmar->flags & 0x1)
printk(KERN_INFO
"Queued invalidation will be enabled to support "
"x2apic and Intr-remapping.\n");
#endif
#ifdef CONFIG_DMAR
"Queued invalidation will be enabled to support x2apic and Intr-remapping.\n");
if (ret && !no_iommu && !iommu_detected && !dmar_disabled) {
iommu_detected = 1;
/* Make sure ACS will be enabled */
pci_request_acs();
}
#endif
#ifdef CONFIG_X86
if (ret)
x86_init.iommu.iommu_init = intel_iommu_init;
......@@ -758,7 +612,6 @@ int alloc_iommu(struct dmar_drhd_unit *drhd)
goto err_unmap;
}
#ifdef CONFIG_DMAR
agaw = iommu_calculate_agaw(iommu);
if (agaw < 0) {
printk(KERN_ERR
......@@ -773,7 +626,6 @@ int alloc_iommu(struct dmar_drhd_unit *drhd)
iommu->seq_id);
goto err_unmap;
}
#endif
iommu->agaw = agaw;
iommu->msagaw = msagaw;
......@@ -817,9 +669,7 @@ void free_iommu(struct intel_iommu *iommu)
if (!iommu)
return;
#ifdef CONFIG_DMAR
free_dmar_iommu(iommu);
#endif
if (iommu->reg)
iounmap(iommu->reg);
......
......@@ -398,11 +398,11 @@ static long list_size;
static void domain_remove_dev_info(struct dmar_domain *domain);
#ifdef CONFIG_DMAR_DEFAULT_ON
#ifdef CONFIG_INTEL_IOMMU_DEFAULT_ON
int dmar_disabled = 0;
#else
int dmar_disabled = 1;
#endif /*CONFIG_DMAR_DEFAULT_ON*/
#endif /*CONFIG_INTEL_IOMMU_DEFAULT_ON*/
static int dmar_map_gfx = 1;
static int dmar_forcedac;
......@@ -2157,7 +2157,7 @@ static inline int iommu_prepare_rmrr_dev(struct dmar_rmrr_unit *rmrr,
rmrr->end_address);
}
#ifdef CONFIG_DMAR_FLOPPY_WA
#ifdef CONFIG_INTEL_IOMMU_FLOPPY_WA
static inline void iommu_prepare_isa(void)
{
struct pci_dev *pdev;
......@@ -2180,7 +2180,7 @@ static inline void iommu_prepare_isa(void)
{
return;
}
#endif /* !CONFIG_DMAR_FLPY_WA */
#endif /* !CONFIG_INTEL_IOMMU_FLPY_WA */
static int md_domain_init(struct dmar_domain *domain, int guest_width);
......@@ -2491,7 +2491,7 @@ static int __init init_dmars(void)
if (iommu_pass_through)
iommu_identity_mapping |= IDENTMAP_ALL;
#ifdef CONFIG_DMAR_BROKEN_GFX_WA
#ifdef CONFIG_INTEL_IOMMU_BROKEN_GFX_WA
iommu_identity_mapping |= IDENTMAP_GFX;
#endif
......@@ -3399,6 +3399,151 @@ static void __init init_iommu_pm_ops(void)
static inline void init_iommu_pm_ops(void) {}
#endif /* CONFIG_PM */
LIST_HEAD(dmar_rmrr_units);
static void __init dmar_register_rmrr_unit(struct dmar_rmrr_unit *rmrr)
{
list_add(&rmrr->list, &dmar_rmrr_units);
}
int __init dmar_parse_one_rmrr(struct acpi_dmar_header *header)
{
struct acpi_dmar_reserved_memory *rmrr;
struct dmar_rmrr_unit *rmrru;
rmrru = kzalloc(sizeof(*rmrru), GFP_KERNEL);
if (!rmrru)
return -ENOMEM;
rmrru->hdr = header;
rmrr = (struct acpi_dmar_reserved_memory *)header;
rmrru->base_address = rmrr->base_address;
rmrru->end_address = rmrr->end_address;
dmar_register_rmrr_unit(rmrru);
return 0;
}
static int __init
rmrr_parse_dev(struct dmar_rmrr_unit *rmrru)
{
struct acpi_dmar_reserved_memory *rmrr;
int ret;
rmrr = (struct acpi_dmar_reserved_memory *) rmrru->hdr;
ret = dmar_parse_dev_scope((void *)(rmrr + 1),
((void *)rmrr) + rmrr->header.length,
&rmrru->devices_cnt, &rmrru->devices, rmrr->segment);
if (ret || (rmrru->devices_cnt == 0)) {
list_del(&rmrru->list);
kfree(rmrru);
}
return ret;
}
static LIST_HEAD(dmar_atsr_units);
int __init dmar_parse_one_atsr(struct acpi_dmar_header *hdr)
{
struct acpi_dmar_atsr *atsr;
struct dmar_atsr_unit *atsru;
atsr = container_of(hdr, struct acpi_dmar_atsr, header);
atsru = kzalloc(sizeof(*atsru), GFP_KERNEL);
if (!atsru)
return -ENOMEM;
atsru->hdr = hdr;
atsru->include_all = atsr->flags & 0x1;
list_add(&atsru->list, &dmar_atsr_units);
return 0;
}
static int __init atsr_parse_dev(struct dmar_atsr_unit *atsru)
{
int rc;
struct acpi_dmar_atsr *atsr;
if (atsru->include_all)
return 0;
atsr = container_of(atsru->hdr, struct acpi_dmar_atsr, header);
rc = dmar_parse_dev_scope((void *)(atsr + 1),
(void *)atsr + atsr->header.length,
&atsru->devices_cnt, &atsru->devices,
atsr->segment);
if (rc || !atsru->devices_cnt) {
list_del(&atsru->list);
kfree(atsru);
}
return rc;
}
int dmar_find_matched_atsr_unit(struct pci_dev *dev)
{
int i;
struct pci_bus *bus;
struct acpi_dmar_atsr *atsr;
struct dmar_atsr_unit *atsru;
dev = pci_physfn(dev);
list_for_each_entry(atsru, &dmar_atsr_units, list) {
atsr = container_of(atsru->hdr, struct acpi_dmar_atsr, header);
if (atsr->segment == pci_domain_nr(dev->bus))
goto found;
}
return 0;
found:
for (bus = dev->bus; bus; bus = bus->parent) {
struct pci_dev *bridge = bus->self;
if (!bridge || !pci_is_pcie(bridge) ||
bridge->pcie_type == PCI_EXP_TYPE_PCI_BRIDGE)
return 0;
if (bridge->pcie_type == PCI_EXP_TYPE_ROOT_PORT) {
for (i = 0; i < atsru->devices_cnt; i++)
if (atsru->devices[i] == bridge)
return 1;
break;
}
}
if (atsru->include_all)
return 1;
return 0;
}
int dmar_parse_rmrr_atsr_dev(void)
{
struct dmar_rmrr_unit *rmrr, *rmrr_n;
struct dmar_atsr_unit *atsr, *atsr_n;
int ret = 0;
list_for_each_entry_safe(rmrr, rmrr_n, &dmar_rmrr_units, list) {
ret = rmrr_parse_dev(rmrr);
if (ret)
return ret;
}
list_for_each_entry_safe(atsr, atsr_n, &dmar_atsr_units, list) {
ret = atsr_parse_dev(atsr);
if (ret)
return ret;
}
return ret;
}
/*
* Here we only respond to action of unbound device from driver.
*
......@@ -3448,16 +3593,12 @@ int __init intel_iommu_init(void)
return -ENODEV;
}
if (dmar_dev_scope_init()) {
if (dmar_dev_scope_init() < 0) {
if (force_on)
panic("tboot: Failed to initialize DMAR device scope\n");
return -ENODEV;
}
/*
* Check the need for DMA-remapping initialization now.
* Above initialization will also be used by Interrupt-remapping.
*/
if (no_iommu || dmar_disabled)
return -ENODEV;
......@@ -3467,6 +3608,12 @@ int __init intel_iommu_init(void)
return -ENODEV;
}
if (list_empty(&dmar_rmrr_units))
printk(KERN_INFO "DMAR: No RMRR found\n");
if (list_empty(&dmar_atsr_units))
printk(KERN_INFO "DMAR: No ATSR found\n");
if (dmar_init_reserved_ranges()) {
if (force_on)
panic("tboot: Failed to reserve iommu ranges\n");
......
......@@ -21,6 +21,7 @@ int intr_remapping_enabled;
static int disable_intremap;
static int disable_sourceid_checking;
static int no_x2apic_optout;
static __init int setup_nointremap(char *str)
{
......@@ -34,12 +35,20 @@ static __init int setup_intremap(char *str)
if (!str)
return -EINVAL;
if (!strncmp(str, "on", 2))
disable_intremap = 0;
else if (!strncmp(str, "off", 3))
disable_intremap = 1;
else if (!strncmp(str, "nosid", 5))
disable_sourceid_checking = 1;
while (*str) {
if (!strncmp(str, "on", 2))
disable_intremap = 0;
else if (!strncmp(str, "off", 3))
disable_intremap = 1;
else if (!strncmp(str, "nosid", 5))
disable_sourceid_checking = 1;
else if (!strncmp(str, "no_x2apic_optout", 16))
no_x2apic_optout = 1;
str += strcspn(str, ",");
while (*str == ',')
str++;
}
return 0;
}
......@@ -501,6 +510,15 @@ static void iommu_disable_intr_remapping(struct intel_iommu *iommu)
spin_unlock_irqrestore(&iommu->register_lock, flags);
}
static int __init dmar_x2apic_optout(void)
{
struct acpi_table_dmar *dmar;
dmar = (struct acpi_table_dmar *)dmar_tbl;
if (!dmar || no_x2apic_optout)
return 0;
return dmar->flags & DMAR_X2APIC_OPT_OUT;
}
int __init intr_remapping_supported(void)
{
struct dmar_drhd_unit *drhd;
......@@ -521,16 +539,25 @@ int __init intr_remapping_supported(void)
return 1;
}
int __init enable_intr_remapping(int eim)
int __init enable_intr_remapping(void)
{
struct dmar_drhd_unit *drhd;
int setup = 0;
int eim = 0;
if (parse_ioapics_under_ir() != 1) {
printk(KERN_INFO "Not enable interrupt remapping\n");
return -1;
}
if (x2apic_supported()) {
eim = !dmar_x2apic_optout();
WARN(!eim, KERN_WARNING
"Your BIOS is broken and requested that x2apic be disabled\n"
"This will leave your machine vulnerable to irq-injection attacks\n"
"Use 'intremap=no_x2apic_optout' to override BIOS request\n");
}
for_each_drhd_unit(drhd) {
struct intel_iommu *iommu = drhd->iommu;
......@@ -606,8 +633,9 @@ int __init enable_intr_remapping(int eim)
goto error;
intr_remapping_enabled = 1;
pr_info("Enabled IRQ remapping in %s mode\n", eim ? "x2apic" : "xapic");
return 0;
return eim ? IRQ_REMAP_X2APIC_MODE : IRQ_REMAP_XAPIC_MODE;
error:
/*
......@@ -745,6 +773,15 @@ int __init parse_ioapics_under_ir(void)
return ir_supported;
}
int ir_dev_scope_init(void)
{
if (!intr_remapping_enabled)
return 0;
return dmar_dev_scope_init();
}
rootfs_initcall(ir_dev_scope_init);
void disable_intr_remapping(void)
{
struct dmar_drhd_unit *drhd;
......
......@@ -2788,7 +2788,7 @@ DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_RICOH, PCI_DEVICE_ID_RICOH_R5CE823, ricoh_
DECLARE_PCI_FIXUP_RESUME_EARLY(PCI_VENDOR_ID_RICOH, PCI_DEVICE_ID_RICOH_R5CE823, ricoh_mmc_fixup_r5c832);
#endif /*CONFIG_MMC_RICOH_MMC*/
#if defined(CONFIG_DMAR) || defined(CONFIG_INTR_REMAP)
#ifdef CONFIG_DMAR_TABLE
#define VTUNCERRMSK_REG 0x1ac
#define VTD_MSK_SPEC_ERRORS (1 << 31)
/*
......
......@@ -25,11 +25,12 @@ struct intel_iommu;
struct dmar_domain;
struct root_entry;
extern void free_dmar_iommu(struct intel_iommu *iommu);
#ifdef CONFIG_DMAR
#ifdef CONFIG_INTEL_IOMMU
extern void free_dmar_iommu(struct intel_iommu *iommu);
extern int iommu_calculate_agaw(struct intel_iommu *iommu);
extern int iommu_calculate_max_sagaw(struct intel_iommu *iommu);
extern int dmar_disabled;
#else
static inline int iommu_calculate_agaw(struct intel_iommu *iommu)
{
......@@ -39,8 +40,11 @@ static inline int iommu_calculate_max_sagaw(struct intel_iommu *iommu)
{
return 0;
}
static inline void free_dmar_iommu(struct intel_iommu *iommu)
{
}
#define dmar_disabled (1)
#endif
extern int dmar_disabled;
#endif
......@@ -26,8 +26,13 @@
#include <linux/msi.h>
#include <linux/irqreturn.h>
/* DMAR Flags */
#define DMAR_INTR_REMAP 0x1
#define DMAR_X2APIC_OPT_OUT 0x2
struct intel_iommu;
#if defined(CONFIG_DMAR) || defined(CONFIG_INTR_REMAP)
#ifdef CONFIG_DMAR_TABLE
extern struct acpi_table_header *dmar_tbl;
struct dmar_drhd_unit {
struct list_head list; /* list of drhd units */
struct acpi_dmar_header *hdr; /* ACPI header */
......@@ -76,7 +81,7 @@ static inline int enable_drhd_fault_handling(void)
{
return -1;
}
#endif /* !CONFIG_DMAR && !CONFIG_INTR_REMAP */
#endif /* !CONFIG_DMAR_TABLE */
struct irte {
union {
......@@ -107,10 +112,10 @@ struct irte {
};
};
#ifdef CONFIG_INTR_REMAP
#ifdef CONFIG_IRQ_REMAP
extern int intr_remapping_enabled;
extern int intr_remapping_supported(void);
extern int enable_intr_remapping(int);
extern int enable_intr_remapping(void);
extern void disable_intr_remapping(void);
extern int reenable_intr_remapping(int);
......@@ -177,7 +182,7 @@ static inline int set_msi_sid(struct irte *irte, struct pci_dev *dev)
#define intr_remapping_enabled (0)
static inline int enable_intr_remapping(int eim)
static inline int enable_intr_remapping(void)
{
return -1;
}
......@@ -192,6 +197,11 @@ static inline int reenable_intr_remapping(int eim)
}
#endif
enum {
IRQ_REMAP_XAPIC_MODE,
IRQ_REMAP_X2APIC_MODE,
};
/* Can't use the common MSI interrupt functions
* since DMAR is not a pci device
*/
......@@ -204,7 +214,7 @@ extern int dmar_set_interrupt(struct intel_iommu *iommu);
extern irqreturn_t dmar_fault(int irq, void *dev_id);
extern int arch_setup_dmar_msi(unsigned int irq);
#ifdef CONFIG_DMAR
#ifdef CONFIG_INTEL_IOMMU
extern int iommu_detected, no_iommu;
extern struct list_head dmar_rmrr_units;
struct dmar_rmrr_unit {
......@@ -227,9 +237,26 @@ struct dmar_atsr_unit {
u8 include_all:1; /* include all ports */
};
int dmar_parse_rmrr_atsr_dev(void);
extern int dmar_parse_one_rmrr(struct acpi_dmar_header *header);
extern int dmar_parse_one_atsr(struct acpi_dmar_header *header);
extern int dmar_parse_dev_scope(void *start, void *end, int *cnt,
struct pci_dev ***devices, u16 segment);
extern int intel_iommu_init(void);
#else /* !CONFIG_DMAR: */
#else /* !CONFIG_INTEL_IOMMU: */
static inline int intel_iommu_init(void) { return -ENODEV; }
#endif /* CONFIG_DMAR */
static inline int dmar_parse_one_rmrr(struct acpi_dmar_header *header)
{
return 0;
}
static inline int dmar_parse_one_atsr(struct acpi_dmar_header *header)
{
return 0;
}
static inline int dmar_parse_rmrr_atsr_dev(void)
{
return 0;
}
#endif /* CONFIG_INTEL_IOMMU */
#endif /* __DMAR_H__ */
......@@ -279,7 +279,7 @@ struct q_inval {
int free_cnt;
};
#ifdef CONFIG_INTR_REMAP
#ifdef CONFIG_IRQ_REMAP
/* 1MB - maximum possible interrupt remapping table size */
#define INTR_REMAP_PAGE_ORDER 8
#define INTR_REMAP_TABLE_REG_SIZE 0xf
......@@ -318,7 +318,7 @@ struct intel_iommu {
unsigned int irq;
unsigned char name[13]; /* Device Name */
#ifdef CONFIG_DMAR
#ifdef CONFIG_INTEL_IOMMU
unsigned long *domain_ids; /* bitmap of domains */
struct dmar_domain **domains; /* ptr to domains */
spinlock_t lock; /* protect context, domain ids */
......@@ -329,7 +329,7 @@ struct intel_iommu {
struct q_inval *qi; /* Queued invalidation info */
u32 *iommu_state; /* Store iommu states between suspend and resume.*/
#ifdef CONFIG_INTR_REMAP
#ifdef CONFIG_IRQ_REMAP
struct ir_table *ir_table; /* Interrupt remapping info */
#endif
int node;
......
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