aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/iommu/amd_iommu_init.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/iommu/amd_iommu_init.c')
-rw-r--r--drivers/iommu/amd_iommu_init.c68
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
697static 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 */
720static void __init init_iommu_from_acpi(struct amd_iommu *iommu, 749static 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 */
913static int __init init_iommu_one(struct amd_iommu *iommu, struct ivhd_header *h) 973static 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;