--- /dev/null
+From: Suresh Siddha <suresh.b.siddha@intel.com>
+Subject: x64, x2apic/intr-remap: code re-structuring, to be used by both DMA and Interrupt remapping
+References: fate #303948 and fate #303984
+Patch-Mainline: queued for .28
+Commit-ID: 1886e8a90a580f3ad343f2065c84c1b9e1dac9ef
+
+Signed-off-by: Thomas Renninger <trenn@suse.de>
+
+Allocate the iommu during the parse of DMA remapping hardware
+definition structures. And also, introduce routines for device
+scope initialization which will be explicitly called during
+dma-remapping initialization.
+
+These will be used for enabling interrupt remapping separately from the
+existing DMA-remapping enabling sequence.
+
+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>
+
+---
+ drivers/pci/dmar.c | 89 +++++++++++++++++++++++++++++++++++++---------
+ drivers/pci/intel-iommu.c | 10 ++---
+ drivers/pci/intel-iommu.h | 2 -
+ include/linux/dmar.h | 10 ++++-
+ 4 files changed, 88 insertions(+), 23 deletions(-)
+
+--- a/drivers/pci/dmar.c
++++ b/drivers/pci/dmar.c
+@@ -174,19 +174,37 @@ dmar_parse_one_drhd(struct acpi_dmar_hea
+ struct acpi_dmar_hardware_unit *drhd;
+ struct dmar_drhd_unit *dmaru;
+ int ret = 0;
+- static int include_all;
+
+ dmaru = kzalloc(sizeof(*dmaru), GFP_KERNEL);
+ if (!dmaru)
+ return -ENOMEM;
+
++ dmaru->hdr = header;
+ drhd = (struct acpi_dmar_hardware_unit *)header;
+ dmaru->reg_base_addr = drhd->address;
+ dmaru->include_all = drhd->flags & 0x1; /* BIT0: INCLUDE_ALL */
+
++ ret = alloc_iommu(dmaru);
++ if (ret) {
++ kfree(dmaru);
++ return ret;
++ }
++ dmar_register_drhd_unit(dmaru);
++ return 0;
++}
++
++static int __init
++dmar_parse_dev(struct dmar_drhd_unit *dmaru)
++{
++ struct acpi_dmar_hardware_unit *drhd;
++ static int include_all;
++ int ret;
++
++ drhd = (struct acpi_dmar_hardware_unit *) dmaru->hdr;
++
+ if (!dmaru->include_all)
+ ret = dmar_parse_dev_scope((void *)(drhd + 1),
+- ((void *)drhd) + header->length,
++ ((void *)drhd) + drhd->header.length,
+ &dmaru->devices_cnt, &dmaru->devices,
+ drhd->segment);
+ else {
+@@ -199,10 +217,10 @@ dmar_parse_one_drhd(struct acpi_dmar_hea
+ include_all = 1;
+ }
+
+- if (ret || (dmaru->devices_cnt == 0 && !dmaru->include_all))
++ if (ret || (dmaru->devices_cnt == 0 && !dmaru->include_all)) {
++ list_del(&dmaru->list);
+ kfree(dmaru);
+- else
+- dmar_register_drhd_unit(dmaru);
++ }
+ return ret;
+ }
+
+@@ -211,23 +229,35 @@ dmar_parse_one_rmrr(struct acpi_dmar_hea
+ {
+ struct acpi_dmar_reserved_memory *rmrr;
+ struct dmar_rmrr_unit *rmrru;
+- int ret = 0;
+
+ 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) + header->length,
++ ((void *)rmrr) + rmrr->header.length,
+ &rmrru->devices_cnt, &rmrru->devices, rmrr->segment);
+
+- if (ret || (rmrru->devices_cnt == 0))
++ if (ret || (rmrru->devices_cnt == 0)) {
++ list_del(&rmrru->list);
+ kfree(rmrru);
+- else
+- dmar_register_rmrr_unit(rmrru);
++ }
+ return ret;
+ }
+
+@@ -333,15 +363,42 @@ dmar_find_matched_drhd_unit(struct pci_d
+ return NULL;
+ }
+
++int __init dmar_dev_scope_init(void)
++{
++ struct dmar_drhd_unit *drhd;
++ struct dmar_rmrr_unit *rmrr;
++ int ret = -ENODEV;
++
++ for_each_drhd_unit(drhd) {
++ ret = dmar_parse_dev(drhd);
++ if (ret)
++ return ret;
++ }
++
++ for_each_rmrr_units(rmrr) {
++ ret = rmrr_parse_dev(rmrr);
++ if (ret)
++ return ret;
++ }
++
++ return ret;
++}
++
+
+ int __init dmar_table_init(void)
+ {
+-
++ static int dmar_table_initialized;
+ int ret;
+
++ if (dmar_table_initialized)
++ return 0;
++
++ dmar_table_initialized = 1;
++
+ ret = parse_dmar_table();
+ if (ret) {
+- printk(KERN_INFO PREFIX "parse DMAR table failure.\n");
++ if (ret != -ENODEV)
++ printk(KERN_INFO PREFIX "parse DMAR table failure.\n");
+ return ret;
+ }
+
+@@ -375,7 +432,7 @@ int __init early_dmar_detect(void)
+ return (ACPI_SUCCESS(status) ? 1 : 0);
+ }
+
+-struct intel_iommu *alloc_iommu(struct dmar_drhd_unit *drhd)
++int alloc_iommu(struct dmar_drhd_unit *drhd)
+ {
+ struct intel_iommu *iommu;
+ int map_size;
+@@ -384,7 +441,7 @@ struct intel_iommu *alloc_iommu(struct d
+
+ iommu = kzalloc(sizeof(*iommu), GFP_KERNEL);
+ if (!iommu)
+- return NULL;
++ return -ENOMEM;
+
+ iommu->seq_id = iommu_allocated++;
+
+@@ -417,10 +474,10 @@ struct intel_iommu *alloc_iommu(struct d
+ spin_lock_init(&iommu->register_lock);
+
+ drhd->iommu = iommu;
+- return iommu;
++ return 0;
+ error:
+ kfree(iommu);
+- return NULL;
++ return -1;
+ }
+
+ void free_iommu(struct intel_iommu *iommu)
+--- a/drivers/pci/intel-iommu.c
++++ b/drivers/pci/intel-iommu.c
+@@ -1667,11 +1667,8 @@ int __init init_dmars(void)
+ for_each_drhd_unit(drhd) {
+ if (drhd->ignored)
+ continue;
+- iommu = alloc_iommu(drhd);
+- if (!iommu) {
+- ret = -ENOMEM;
+- goto error;
+- }
++
++ iommu = drhd->iommu;
+
+ ret = iommu_init_domains(iommu);
+ if (ret)
+@@ -2349,6 +2346,9 @@ int __init intel_iommu_init(void)
+ if (dmar_table_init())
+ return -ENODEV;
+
++ if (dmar_dev_scope_init())
++ return -ENODEV;
++
+ iommu_init_mempool();
+ dmar_init_reserved_ranges();
+
+--- a/drivers/pci/intel-iommu.h
++++ b/drivers/pci/intel-iommu.h
+@@ -199,7 +199,7 @@ struct intel_iommu {
+
+ extern struct dmar_drhd_unit * dmar_find_matched_drhd_unit(struct pci_dev *dev);
+
+-extern struct intel_iommu *alloc_iommu(struct dmar_drhd_unit *drhd);
++extern int alloc_iommu(struct dmar_drhd_unit *drhd);
+ extern void free_iommu(struct intel_iommu *iommu);
+
+ #endif
+--- a/include/linux/dmar.h
++++ b/include/linux/dmar.h
+@@ -46,12 +46,14 @@ 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 struct list_head dmar_drhd_units;
+ extern struct list_head dmar_rmrr_units;
+
+ struct dmar_drhd_unit {
+ struct list_head list; /* list of drhd units */
++ struct acpi_dmar_header *hdr; /* ACPI header */
+ u64 reg_base_addr; /* register base address*/
+ struct pci_dev **devices; /* target device array */
+ int devices_cnt; /* target device count */
+@@ -62,6 +64,7 @@ struct dmar_drhd_unit {
+
+ struct dmar_rmrr_unit {
+ struct list_head list; /* list of rmrr units */
++ struct acpi_dmar_header *hdr; /* ACPI header */
+ u64 base_address; /* reserved base address*/
+ u64 end_address; /* reserved end address */
+ struct pci_dev **devices; /* target devices */
+@@ -72,6 +75,8 @@ struct dmar_rmrr_unit {
+ list_for_each_entry(drhd, &dmar_drhd_units, list)
+ #define for_each_rmrr_units(rmrr) \
+ list_for_each_entry(rmrr, &dmar_rmrr_units, list)
++
++extern int alloc_iommu(struct dmar_drhd_unit *);
+ #else
+ static inline void detect_intel_iommu(void)
+ {
+@@ -81,6 +86,9 @@ static inline int intel_iommu_init(void)
+ {
+ return -ENODEV;
+ }
+-
++static inline int dmar_table_init(void)
++{
++ return -ENODEV;
++}
+ #endif /* !CONFIG_DMAR */
+ #endif /* __DMAR_H__ */