aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSuresh Siddha <suresh.b.siddha@intel.com>2008-07-10 11:16:40 -0700
committerIngo Molnar <mingo@elte.hu>2008-07-12 08:44:50 +0200
commitad3ad3f6a2caebf56869b83b69e23eb9fa5e0ab6 (patch)
tree7bc99dde6a6313eb43783086a33f6eebc1da1907
parent2d6b5f85bb4ca919d8ab0f30311309b53fb93bc3 (diff)
downloadkernel_samsung_smdk4412-ad3ad3f6a2caebf56869b83b69e23eb9fa5e0ab6.zip
kernel_samsung_smdk4412-ad3ad3f6a2caebf56869b83b69e23eb9fa5e0ab6.tar.gz
kernel_samsung_smdk4412-ad3ad3f6a2caebf56869b83b69e23eb9fa5e0ab6.tar.bz2
x64, x2apic/intr-remap: parse ioapic scope under vt-d structures
Parse the vt-d device scope structures to find the mapping between IO-APICs and the interrupt remapping hardware units. This will be used later for enabling Interrupt-remapping for IOAPIC devices. Signed-off-by: Suresh Siddha <suresh.b.siddha@intel.com> Cc: akpm@linux-foundation.org Cc: arjan@linux.intel.com Cc: andi@firstfloor.org Cc: ebiederm@xmission.com Cc: jbarnes@virtuousgeek.org Cc: steiner@sgi.com Signed-off-by: Ingo Molnar <mingo@elte.hu>
-rw-r--r--drivers/pci/Makefile2
-rw-r--r--drivers/pci/dmar.c3
-rw-r--r--drivers/pci/intel-iommu.h2
-rw-r--r--drivers/pci/intr_remapping.c70
-rw-r--r--drivers/pci/intr_remapping.h6
-rw-r--r--include/linux/dmar.h1
6 files changed, 84 insertions, 0 deletions
diff --git a/drivers/pci/Makefile b/drivers/pci/Makefile
index 4d1ce2e..1c409c7 100644
--- a/drivers/pci/Makefile
+++ b/drivers/pci/Makefile
@@ -26,6 +26,8 @@ obj-$(CONFIG_HT_IRQ) += htirq.o
# Build Intel IOMMU support
obj-$(CONFIG_DMAR) += dmar.o iova.o intel-iommu.o
+obj-$(CONFIG_INTR_REMAP) += dmar.o intr_remapping.o
+
#
# Some architectures use the generic PCI setup functions
#
diff --git a/drivers/pci/dmar.c b/drivers/pci/dmar.c
index 903f170..127764c 100644
--- a/drivers/pci/dmar.c
+++ b/drivers/pci/dmar.c
@@ -423,6 +423,9 @@ int __init dmar_table_init(void)
printk(KERN_INFO PREFIX "No RMRR found\n");
#endif
+#ifdef CONFIG_INTR_REMAP
+ parse_ioapics_under_ir();
+#endif
return 0;
}
diff --git a/drivers/pci/intel-iommu.h b/drivers/pci/intel-iommu.h
index 371e3b9..eb167e3 100644
--- a/drivers/pci/intel-iommu.h
+++ b/drivers/pci/intel-iommu.h
@@ -114,6 +114,8 @@ static inline void dmar_writeq(void __iomem *addr, u64 val)
#define ecap_max_iotlb_offset(e) \
(ecap_iotlb_offset(e) + ecap_niotlb_iunits(e) * 16)
#define ecap_coherent(e) ((e) & 0x1)
+#define ecap_eim_support(e) ((e >> 4) & 0x1)
+#define ecap_ir_support(e) ((e >> 3) & 0x1)
/* IOTLB_REG */
diff --git a/drivers/pci/intr_remapping.c b/drivers/pci/intr_remapping.c
new file mode 100644
index 0000000..a80b879
--- /dev/null
+++ b/drivers/pci/intr_remapping.c
@@ -0,0 +1,70 @@
+#include <linux/dmar.h>
+#include <asm/io_apic.h>
+#include "intel-iommu.h"
+#include "intr_remapping.h"
+
+static struct ioapic_scope ir_ioapic[MAX_IO_APICS];
+static int ir_ioapic_num;
+
+static int ir_parse_ioapic_scope(struct acpi_dmar_header *header,
+ struct intel_iommu *iommu)
+{
+ struct acpi_dmar_hardware_unit *drhd;
+ struct acpi_dmar_device_scope *scope;
+ void *start, *end;
+
+ drhd = (struct acpi_dmar_hardware_unit *)header;
+
+ start = (void *)(drhd + 1);
+ end = ((void *)drhd) + header->length;
+
+ while (start < end) {
+ scope = start;
+ if (scope->entry_type == ACPI_DMAR_SCOPE_TYPE_IOAPIC) {
+ if (ir_ioapic_num == MAX_IO_APICS) {
+ printk(KERN_WARNING "Exceeded Max IO APICS\n");
+ return -1;
+ }
+
+ printk(KERN_INFO "IOAPIC id %d under DRHD base"
+ " 0x%Lx\n", scope->enumeration_id,
+ drhd->address);
+
+ ir_ioapic[ir_ioapic_num].iommu = iommu;
+ ir_ioapic[ir_ioapic_num].id = scope->enumeration_id;
+ ir_ioapic_num++;
+ }
+ start += scope->length;
+ }
+
+ return 0;
+}
+
+/*
+ * Finds the assocaition between IOAPIC's and its Interrupt-remapping
+ * hardware unit.
+ */
+int __init parse_ioapics_under_ir(void)
+{
+ struct dmar_drhd_unit *drhd;
+ int ir_supported = 0;
+
+ for_each_drhd_unit(drhd) {
+ struct intel_iommu *iommu = drhd->iommu;
+
+ if (ecap_ir_support(iommu->ecap)) {
+ if (ir_parse_ioapic_scope(drhd->hdr, iommu))
+ return -1;
+
+ ir_supported = 1;
+ }
+ }
+
+ if (ir_supported && ir_ioapic_num != nr_ioapics) {
+ printk(KERN_WARNING
+ "Not all IO-APIC's listed under remapping hardware\n");
+ return -1;
+ }
+
+ return ir_supported;
+}
diff --git a/drivers/pci/intr_remapping.h b/drivers/pci/intr_remapping.h
new file mode 100644
index 0000000..c4a40b2
--- /dev/null
+++ b/drivers/pci/intr_remapping.h
@@ -0,0 +1,6 @@
+#include "intel-iommu.h"
+
+struct ioapic_scope {
+ struct intel_iommu *iommu;
+ unsigned int id;
+};
diff --git a/include/linux/dmar.h b/include/linux/dmar.h
index 3ab07e4..c4e96eb 100644
--- a/include/linux/dmar.h
+++ b/include/linux/dmar.h
@@ -47,6 +47,7 @@ extern int intel_iommu_init(void);
extern int dmar_table_init(void);
extern int early_dmar_detect(void);
extern int dmar_dev_scope_init(void);
+extern int parse_ioapics_under_ir(void);
extern struct list_head dmar_drhd_units;
extern struct list_head dmar_rmrr_units;