summaryrefslogtreecommitdiffstats
path: root/drivers/pci/dmar.c
diff options
context:
space:
mode:
authorSuresh Siddha <suresh.b.siddha@intel.com>2008-07-10 20:16:37 +0200
committerIngo Molnar <mingo@elte.hu>2008-07-12 08:44:48 +0200
commit1886e8a90a580f3ad343f2065c84c1b9e1dac9ef (patch)
tree1f0a6b536a1bb7b24585973e70ad8e1a9a076f09 /drivers/pci/dmar.c
parentx64, x2apic/intr-remap: fix the need for sequential array allocation of iommus (diff)
downloadlinux-1886e8a90a580f3ad343f2065c84c1b9e1dac9ef.tar.xz
linux-1886e8a90a580f3ad343f2065c84c1b9e1dac9ef.zip
x64, x2apic/intr-remap: code re-structuring, to be used by both DMA and Interrupt remapping
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>
Diffstat (limited to 'drivers/pci/dmar.c')
-rw-r--r--drivers/pci/dmar.c89
1 files changed, 73 insertions, 16 deletions
diff --git a/drivers/pci/dmar.c b/drivers/pci/dmar.c
index 1a59423a8eda..158bc5bfcf75 100644
--- a/drivers/pci/dmar.c
+++ b/drivers/pci/dmar.c
@@ -174,19 +174,37 @@ dmar_parse_one_drhd(struct acpi_dmar_header *header)
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_header *header)
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_header *header)
{
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_dev *dev)
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;
}
@@ -377,7 +434,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;
@@ -386,7 +443,7 @@ struct intel_iommu *alloc_iommu(struct dmar_drhd_unit *drhd)
iommu = kzalloc(sizeof(*iommu), GFP_KERNEL);
if (!iommu)
- return NULL;
+ return -ENOMEM;
iommu->seq_id = iommu_allocated++;
@@ -419,10 +476,10 @@ struct intel_iommu *alloc_iommu(struct dmar_drhd_unit *drhd)
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)