diff options
-rw-r--r-- | arch/x86/kernel/amd_iommu_init.c | 87 |
1 files changed, 87 insertions, 0 deletions
diff --git a/arch/x86/kernel/amd_iommu_init.c b/arch/x86/kernel/amd_iommu_init.c index 3f4f7b890441..555fcc9830c8 100644 --- a/arch/x86/kernel/amd_iommu_init.c +++ b/arch/x86/kernel/amd_iommu_init.c | |||
@@ -556,3 +556,90 @@ static int __init init_iommu_all(struct acpi_table_header *table) | |||
556 | return 0; | 556 | return 0; |
557 | } | 557 | } |
558 | 558 | ||
559 | static void __init free_unity_maps(void) | ||
560 | { | ||
561 | struct unity_map_entry *entry, *next; | ||
562 | |||
563 | list_for_each_entry_safe(entry, next, &amd_iommu_unity_map, list) { | ||
564 | list_del(&entry->list); | ||
565 | kfree(entry); | ||
566 | } | ||
567 | } | ||
568 | |||
569 | static int __init init_exclusion_range(struct ivmd_header *m) | ||
570 | { | ||
571 | int i; | ||
572 | |||
573 | switch (m->type) { | ||
574 | case ACPI_IVMD_TYPE: | ||
575 | set_device_exclusion_range(m->devid, m); | ||
576 | break; | ||
577 | case ACPI_IVMD_TYPE_ALL: | ||
578 | for (i = 0; i < amd_iommu_last_bdf; ++i) | ||
579 | set_device_exclusion_range(i, m); | ||
580 | break; | ||
581 | case ACPI_IVMD_TYPE_RANGE: | ||
582 | for (i = m->devid; i <= m->aux; ++i) | ||
583 | set_device_exclusion_range(i, m); | ||
584 | break; | ||
585 | default: | ||
586 | break; | ||
587 | } | ||
588 | |||
589 | return 0; | ||
590 | } | ||
591 | |||
592 | static int __init init_unity_map_range(struct ivmd_header *m) | ||
593 | { | ||
594 | struct unity_map_entry *e = 0; | ||
595 | |||
596 | e = kzalloc(sizeof(*e), GFP_KERNEL); | ||
597 | if (e == NULL) | ||
598 | return -ENOMEM; | ||
599 | |||
600 | switch (m->type) { | ||
601 | default: | ||
602 | case ACPI_IVMD_TYPE: | ||
603 | e->devid_start = e->devid_end = m->devid; | ||
604 | break; | ||
605 | case ACPI_IVMD_TYPE_ALL: | ||
606 | e->devid_start = 0; | ||
607 | e->devid_end = amd_iommu_last_bdf; | ||
608 | break; | ||
609 | case ACPI_IVMD_TYPE_RANGE: | ||
610 | e->devid_start = m->devid; | ||
611 | e->devid_end = m->aux; | ||
612 | break; | ||
613 | } | ||
614 | e->address_start = PAGE_ALIGN(m->range_start); | ||
615 | e->address_end = e->address_start + PAGE_ALIGN(m->range_length); | ||
616 | e->prot = m->flags >> 1; | ||
617 | |||
618 | list_add_tail(&e->list, &amd_iommu_unity_map); | ||
619 | |||
620 | return 0; | ||
621 | } | ||
622 | |||
623 | static int __init init_memory_definitions(struct acpi_table_header *table) | ||
624 | { | ||
625 | u8 *p = (u8 *)table, *end = (u8 *)table; | ||
626 | struct ivmd_header *m; | ||
627 | |||
628 | INIT_LIST_HEAD(&amd_iommu_unity_map); | ||
629 | |||
630 | end += table->length; | ||
631 | p += IVRS_HEADER_LENGTH; | ||
632 | |||
633 | while (p < end) { | ||
634 | m = (struct ivmd_header *)p; | ||
635 | if (m->flags & IVMD_FLAG_EXCL_RANGE) | ||
636 | init_exclusion_range(m); | ||
637 | else if (m->flags & IVMD_FLAG_UNITY_MAP) | ||
638 | init_unity_map_range(m); | ||
639 | |||
640 | p += m->length; | ||
641 | } | ||
642 | |||
643 | return 0; | ||
644 | } | ||
645 | |||