]> pilppa.com Git - linux-2.6-omap-h63xx.git/commitdiff
x86, AMD IOMMU: add functions to parse IOMMU memory mapping requirements for devices
authorJoerg Roedel <joerg.roedel@amd.com>
Thu, 26 Jun 2008 19:27:49 +0000 (21:27 +0200)
committerIngo Molnar <mingo@elte.hu>
Fri, 27 Jun 2008 08:12:12 +0000 (10:12 +0200)
This patch adds the functions to parse the information about IOMMU exclusion
ranges and required unity mappings for the devices handled by the IOMMU.

Signed-off-by: Joerg Roedel <joerg.roedel@amd.com>
Cc: iommu@lists.linux-foundation.org
Cc: bhavna.sarathy@amd.com
Cc: Sebastian.Biemueller@amd.com
Cc: robert.richter@amd.com
Cc: joro@8bytes.org
Signed-off-by: Ingo Molnar <mingo@elte.hu>
arch/x86/kernel/amd_iommu_init.c

index 3f4f7b8904417f3d018ca4257e95a371776d31f2..555fcc9830c8fbf31369117ae5b711a3cd01a68b 100644 (file)
@@ -556,3 +556,90 @@ static int __init init_iommu_all(struct acpi_table_header *table)
        return 0;
 }
 
+static void __init free_unity_maps(void)
+{
+       struct unity_map_entry *entry, *next;
+
+       list_for_each_entry_safe(entry, next, &amd_iommu_unity_map, list) {
+               list_del(&entry->list);
+               kfree(entry);
+       }
+}
+
+static int __init init_exclusion_range(struct ivmd_header *m)
+{
+       int i;
+
+       switch (m->type) {
+       case ACPI_IVMD_TYPE:
+               set_device_exclusion_range(m->devid, m);
+               break;
+       case ACPI_IVMD_TYPE_ALL:
+               for (i = 0; i < amd_iommu_last_bdf; ++i)
+                       set_device_exclusion_range(i, m);
+               break;
+       case ACPI_IVMD_TYPE_RANGE:
+               for (i = m->devid; i <= m->aux; ++i)
+                       set_device_exclusion_range(i, m);
+               break;
+       default:
+               break;
+       }
+
+       return 0;
+}
+
+static int __init init_unity_map_range(struct ivmd_header *m)
+{
+       struct unity_map_entry *e = 0;
+
+       e = kzalloc(sizeof(*e), GFP_KERNEL);
+       if (e == NULL)
+               return -ENOMEM;
+
+       switch (m->type) {
+       default:
+       case ACPI_IVMD_TYPE:
+               e->devid_start = e->devid_end = m->devid;
+               break;
+       case ACPI_IVMD_TYPE_ALL:
+               e->devid_start = 0;
+               e->devid_end = amd_iommu_last_bdf;
+               break;
+       case ACPI_IVMD_TYPE_RANGE:
+               e->devid_start = m->devid;
+               e->devid_end = m->aux;
+               break;
+       }
+       e->address_start = PAGE_ALIGN(m->range_start);
+       e->address_end = e->address_start + PAGE_ALIGN(m->range_length);
+       e->prot = m->flags >> 1;
+
+       list_add_tail(&e->list, &amd_iommu_unity_map);
+
+       return 0;
+}
+
+static int __init init_memory_definitions(struct acpi_table_header *table)
+{
+       u8 *p = (u8 *)table, *end = (u8 *)table;
+       struct ivmd_header *m;
+
+       INIT_LIST_HEAD(&amd_iommu_unity_map);
+
+       end += table->length;
+       p += IVRS_HEADER_LENGTH;
+
+       while (p < end) {
+               m = (struct ivmd_header *)p;
+               if (m->flags & IVMD_FLAG_EXCL_RANGE)
+                       init_exclusion_range(m);
+               else if (m->flags & IVMD_FLAG_UNITY_MAP)
+                       init_unity_map_range(m);
+
+               p += m->length;
+       }
+
+       return 0;
+}
+