diff options
Diffstat (limited to 'drivers/iommu/amd_iommu_init.c')
-rw-r--r-- | drivers/iommu/amd_iommu_init.c | 68 |
1 files changed, 66 insertions, 2 deletions
diff --git a/drivers/iommu/amd_iommu_init.c b/drivers/iommu/amd_iommu_init.c index 18a89b760aaa..617985961195 100644 --- a/drivers/iommu/amd_iommu_init.c +++ b/drivers/iommu/amd_iommu_init.c | |||
@@ -55,6 +55,10 @@ | |||
55 | #define IVHD_DEV_ALIAS_RANGE 0x43 | 55 | #define IVHD_DEV_ALIAS_RANGE 0x43 |
56 | #define IVHD_DEV_EXT_SELECT 0x46 | 56 | #define IVHD_DEV_EXT_SELECT 0x46 |
57 | #define IVHD_DEV_EXT_SELECT_RANGE 0x47 | 57 | #define IVHD_DEV_EXT_SELECT_RANGE 0x47 |
58 | #define IVHD_DEV_SPECIAL 0x48 | ||
59 | |||
60 | #define IVHD_SPECIAL_IOAPIC 1 | ||
61 | #define IVHD_SPECIAL_HPET 2 | ||
58 | 62 | ||
59 | #define IVHD_FLAG_HT_TUN_EN_MASK 0x01 | 63 | #define IVHD_FLAG_HT_TUN_EN_MASK 0x01 |
60 | #define IVHD_FLAG_PASSPW_EN_MASK 0x02 | 64 | #define IVHD_FLAG_PASSPW_EN_MASK 0x02 |
@@ -690,6 +694,31 @@ static void __init set_dev_entry_from_acpi(struct amd_iommu *iommu, | |||
690 | set_iommu_for_device(iommu, devid); | 694 | set_iommu_for_device(iommu, devid); |
691 | } | 695 | } |
692 | 696 | ||
697 | static int add_special_device(u8 type, u8 id, u16 devid) | ||
698 | { | ||
699 | struct devid_map *entry; | ||
700 | struct list_head *list; | ||
701 | |||
702 | if (type != IVHD_SPECIAL_IOAPIC && type != IVHD_SPECIAL_HPET) | ||
703 | return -EINVAL; | ||
704 | |||
705 | entry = kzalloc(sizeof(*entry), GFP_KERNEL); | ||
706 | if (!entry) | ||
707 | return -ENOMEM; | ||
708 | |||
709 | entry->id = id; | ||
710 | entry->devid = devid; | ||
711 | |||
712 | if (type == IVHD_SPECIAL_IOAPIC) | ||
713 | list = &ioapic_map; | ||
714 | else | ||
715 | list = &hpet_map; | ||
716 | |||
717 | list_add_tail(&entry->list, list); | ||
718 | |||
719 | return 0; | ||
720 | } | ||
721 | |||
693 | /* | 722 | /* |
694 | * Reads the device exclusion range from ACPI and initialize IOMMU with | 723 | * Reads the device exclusion range from ACPI and initialize IOMMU with |
695 | * it | 724 | * it |
@@ -717,7 +746,7 @@ static void __init set_device_exclusion_range(u16 devid, struct ivmd_header *m) | |||
717 | * Takes a pointer to an AMD IOMMU entry in the ACPI table and | 746 | * Takes a pointer to an AMD IOMMU entry in the ACPI table and |
718 | * initializes the hardware and our data structures with it. | 747 | * initializes the hardware and our data structures with it. |
719 | */ | 748 | */ |
720 | static void __init init_iommu_from_acpi(struct amd_iommu *iommu, | 749 | static int __init init_iommu_from_acpi(struct amd_iommu *iommu, |
721 | struct ivhd_header *h) | 750 | struct ivhd_header *h) |
722 | { | 751 | { |
723 | u8 *p = (u8 *)h; | 752 | u8 *p = (u8 *)h; |
@@ -867,12 +896,43 @@ static void __init init_iommu_from_acpi(struct amd_iommu *iommu, | |||
867 | flags, ext_flags); | 896 | flags, ext_flags); |
868 | } | 897 | } |
869 | break; | 898 | break; |
899 | case IVHD_DEV_SPECIAL: { | ||
900 | u8 handle, type; | ||
901 | const char *var; | ||
902 | u16 devid; | ||
903 | int ret; | ||
904 | |||
905 | handle = e->ext & 0xff; | ||
906 | devid = (e->ext >> 8) & 0xffff; | ||
907 | type = (e->ext >> 24) & 0xff; | ||
908 | |||
909 | if (type == IVHD_SPECIAL_IOAPIC) | ||
910 | var = "IOAPIC"; | ||
911 | else if (type == IVHD_SPECIAL_HPET) | ||
912 | var = "HPET"; | ||
913 | else | ||
914 | var = "UNKNOWN"; | ||
915 | |||
916 | DUMP_printk(" DEV_SPECIAL(%s[%d])\t\tdevid: %02x:%02x.%x\n", | ||
917 | var, (int)handle, | ||
918 | PCI_BUS(devid), | ||
919 | PCI_SLOT(devid), | ||
920 | PCI_FUNC(devid)); | ||
921 | |||
922 | set_dev_entry_from_acpi(iommu, devid, e->flags, 0); | ||
923 | ret = add_special_device(type, handle, devid); | ||
924 | if (ret) | ||
925 | return ret; | ||
926 | break; | ||
927 | } | ||
870 | default: | 928 | default: |
871 | break; | 929 | break; |
872 | } | 930 | } |
873 | 931 | ||
874 | p += ivhd_entry_length(p); | 932 | p += ivhd_entry_length(p); |
875 | } | 933 | } |
934 | |||
935 | return 0; | ||
876 | } | 936 | } |
877 | 937 | ||
878 | /* Initializes the device->iommu mapping for the driver */ | 938 | /* Initializes the device->iommu mapping for the driver */ |
@@ -912,6 +972,8 @@ static void __init free_iommu_all(void) | |||
912 | */ | 972 | */ |
913 | static int __init init_iommu_one(struct amd_iommu *iommu, struct ivhd_header *h) | 973 | static int __init init_iommu_one(struct amd_iommu *iommu, struct ivhd_header *h) |
914 | { | 974 | { |
975 | int ret; | ||
976 | |||
915 | spin_lock_init(&iommu->lock); | 977 | spin_lock_init(&iommu->lock); |
916 | 978 | ||
917 | /* Add IOMMU to internal data structures */ | 979 | /* Add IOMMU to internal data structures */ |
@@ -947,7 +1009,9 @@ static int __init init_iommu_one(struct amd_iommu *iommu, struct ivhd_header *h) | |||
947 | 1009 | ||
948 | iommu->int_enabled = false; | 1010 | iommu->int_enabled = false; |
949 | 1011 | ||
950 | init_iommu_from_acpi(iommu, h); | 1012 | ret = init_iommu_from_acpi(iommu, h); |
1013 | if (ret) | ||
1014 | return ret; | ||
951 | init_iommu_devices(iommu); | 1015 | init_iommu_devices(iommu); |
952 | 1016 | ||
953 | return 0; | 1017 | return 0; |