aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/iommu
diff options
context:
space:
mode:
authorJoerg Roedel <joerg.roedel@amd.com>2012-06-14 09:52:58 -0400
committerJoerg Roedel <joerg.roedel@amd.com>2012-09-28 11:29:34 -0400
commit6efed63bec36e260204a50cfe6878cd36b710ade (patch)
treeb558d08bfcb70faaf896fdc903c32ddbd0940d76 /drivers/iommu
parent979570e02981d4a8fc20b3cc8fd651856c98ee9d (diff)
iommu/amd: Keep track of HPET and IOAPIC device ids
The IVRS ACPI table provides information about the IOAPICs and the HPETs available in the system and which PCI device ID they use in transactions. Save that information for later usage in interrupt remapping. Signed-off-by: Joerg Roedel <joerg.roedel@amd.com> Reviewed-by: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
Diffstat (limited to 'drivers/iommu')
-rw-r--r--drivers/iommu/amd_iommu.c3
-rw-r--r--drivers/iommu/amd_iommu_init.c68
-rw-r--r--drivers/iommu/amd_iommu_types.h34
3 files changed, 103 insertions, 2 deletions
diff --git a/drivers/iommu/amd_iommu.c b/drivers/iommu/amd_iommu.c
index b64502dfa9f4..6f514831af1f 100644
--- a/drivers/iommu/amd_iommu.c
+++ b/drivers/iommu/amd_iommu.c
@@ -72,6 +72,9 @@ static DEFINE_SPINLOCK(iommu_pd_list_lock);
72static LIST_HEAD(dev_data_list); 72static LIST_HEAD(dev_data_list);
73static DEFINE_SPINLOCK(dev_data_list_lock); 73static DEFINE_SPINLOCK(dev_data_list_lock);
74 74
75LIST_HEAD(ioapic_map);
76LIST_HEAD(hpet_map);
77
75/* 78/*
76 * Domain for untranslated devices - only allocated 79 * Domain for untranslated devices - only allocated
77 * if iommu=pt passed on kernel cmd line. 80 * if iommu=pt passed on kernel cmd line.
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;
diff --git a/drivers/iommu/amd_iommu_types.h b/drivers/iommu/amd_iommu_types.h
index d0dab865a8b8..4495b78b1296 100644
--- a/drivers/iommu/amd_iommu_types.h
+++ b/drivers/iommu/amd_iommu_types.h
@@ -565,6 +565,16 @@ struct amd_iommu {
565 u32 stored_l2[0x83]; 565 u32 stored_l2[0x83];
566}; 566};
567 567
568struct devid_map {
569 struct list_head list;
570 u8 id;
571 u16 devid;
572};
573
574/* Map HPET and IOAPIC ids to the devid used by the IOMMU */
575extern struct list_head ioapic_map;
576extern struct list_head hpet_map;
577
568/* 578/*
569 * List with all IOMMUs in the system. This list is not locked because it is 579 * List with all IOMMUs in the system. This list is not locked because it is
570 * only written and read at driver initialization or suspend time 580 * only written and read at driver initialization or suspend time
@@ -678,6 +688,30 @@ static inline u16 calc_devid(u8 bus, u8 devfn)
678 return (((u16)bus) << 8) | devfn; 688 return (((u16)bus) << 8) | devfn;
679} 689}
680 690
691static inline int get_ioapic_devid(int id)
692{
693 struct devid_map *entry;
694
695 list_for_each_entry(entry, &ioapic_map, list) {
696 if (entry->id == id)
697 return entry->devid;
698 }
699
700 return -EINVAL;
701}
702
703static inline int get_hpet_devid(int id)
704{
705 struct devid_map *entry;
706
707 list_for_each_entry(entry, &hpet_map, list) {
708 if (entry->id == id)
709 return entry->devid;
710 }
711
712 return -EINVAL;
713}
714
681#ifdef CONFIG_AMD_IOMMU_STATS 715#ifdef CONFIG_AMD_IOMMU_STATS
682 716
683struct __iommu_counter { 717struct __iommu_counter {