diff options
author | Joerg Roedel <jroedel@suse.de> | 2014-05-20 17:18:23 -0400 |
---|---|---|
committer | Joerg Roedel <jroedel@suse.de> | 2014-05-26 05:28:12 -0400 |
commit | 741669c765c45cace9bd630f7c8c8047c8b33567 (patch) | |
tree | 9d8d9304cf6e58a9b43729e1a852250d526ca2d9 /drivers/iommu | |
parent | b87d2d7c0b3507b6b17590d741b5be01e8a21b84 (diff) |
iommu/amd: Convert IOMMUv2 state_table into state_list
The state_table consumes 512kb of memory and is only sparsly
populated. Convert it into a list to save memory. There
should be no measurable performance impact.
Signed-off-by: Joerg Roedel <jroedel@suse.de>
Tested-by: Jay Cornwall <Jay.Cornwall@amd.com>
Diffstat (limited to 'drivers/iommu')
-rw-r--r-- | drivers/iommu/amd_iommu_v2.c | 39 |
1 files changed, 18 insertions, 21 deletions
diff --git a/drivers/iommu/amd_iommu_v2.c b/drivers/iommu/amd_iommu_v2.c index 5db3675cad76..569b6a0b6f56 100644 --- a/drivers/iommu/amd_iommu_v2.c +++ b/drivers/iommu/amd_iommu_v2.c | |||
@@ -56,6 +56,8 @@ struct pasid_state { | |||
56 | }; | 56 | }; |
57 | 57 | ||
58 | struct device_state { | 58 | struct device_state { |
59 | struct list_head list; | ||
60 | u16 devid; | ||
59 | atomic_t count; | 61 | atomic_t count; |
60 | struct pci_dev *pdev; | 62 | struct pci_dev *pdev; |
61 | struct pasid_state **states; | 63 | struct pasid_state **states; |
@@ -81,7 +83,7 @@ struct fault { | |||
81 | u16 flags; | 83 | u16 flags; |
82 | }; | 84 | }; |
83 | 85 | ||
84 | static struct device_state **state_table; | 86 | static LIST_HEAD(state_list); |
85 | static spinlock_t state_lock; | 87 | static spinlock_t state_lock; |
86 | 88 | ||
87 | /* List and lock for all pasid_states */ | 89 | /* List and lock for all pasid_states */ |
@@ -113,7 +115,14 @@ static u16 device_id(struct pci_dev *pdev) | |||
113 | 115 | ||
114 | static struct device_state *__get_device_state(u16 devid) | 116 | static struct device_state *__get_device_state(u16 devid) |
115 | { | 117 | { |
116 | return state_table[devid]; | 118 | struct device_state *dev_state; |
119 | |||
120 | list_for_each_entry(dev_state, &state_list, list) { | ||
121 | if (dev_state->devid == devid) | ||
122 | return dev_state; | ||
123 | } | ||
124 | |||
125 | return NULL; | ||
117 | } | 126 | } |
118 | 127 | ||
119 | static struct device_state *get_device_state(u16 devid) | 128 | static struct device_state *get_device_state(u16 devid) |
@@ -778,7 +787,8 @@ int amd_iommu_init_device(struct pci_dev *pdev, int pasids) | |||
778 | 787 | ||
779 | spin_lock_init(&dev_state->lock); | 788 | spin_lock_init(&dev_state->lock); |
780 | init_waitqueue_head(&dev_state->wq); | 789 | init_waitqueue_head(&dev_state->wq); |
781 | dev_state->pdev = pdev; | 790 | dev_state->pdev = pdev; |
791 | dev_state->devid = devid; | ||
782 | 792 | ||
783 | tmp = pasids; | 793 | tmp = pasids; |
784 | for (dev_state->pasid_levels = 0; (tmp - 1) & ~0x1ff; tmp >>= 9) | 794 | for (dev_state->pasid_levels = 0; (tmp - 1) & ~0x1ff; tmp >>= 9) |
@@ -808,13 +818,13 @@ int amd_iommu_init_device(struct pci_dev *pdev, int pasids) | |||
808 | 818 | ||
809 | spin_lock_irqsave(&state_lock, flags); | 819 | spin_lock_irqsave(&state_lock, flags); |
810 | 820 | ||
811 | if (state_table[devid] != NULL) { | 821 | if (__get_device_state(devid) != NULL) { |
812 | spin_unlock_irqrestore(&state_lock, flags); | 822 | spin_unlock_irqrestore(&state_lock, flags); |
813 | ret = -EBUSY; | 823 | ret = -EBUSY; |
814 | goto out_free_domain; | 824 | goto out_free_domain; |
815 | } | 825 | } |
816 | 826 | ||
817 | state_table[devid] = dev_state; | 827 | list_add_tail(&dev_state->list, &state_list); |
818 | 828 | ||
819 | spin_unlock_irqrestore(&state_lock, flags); | 829 | spin_unlock_irqrestore(&state_lock, flags); |
820 | 830 | ||
@@ -852,7 +862,7 @@ void amd_iommu_free_device(struct pci_dev *pdev) | |||
852 | return; | 862 | return; |
853 | } | 863 | } |
854 | 864 | ||
855 | state_table[devid] = NULL; | 865 | list_del(&dev_state->list); |
856 | 866 | ||
857 | spin_unlock_irqrestore(&state_lock, flags); | 867 | spin_unlock_irqrestore(&state_lock, flags); |
858 | 868 | ||
@@ -927,7 +937,6 @@ EXPORT_SYMBOL(amd_iommu_set_invalidate_ctx_cb); | |||
927 | 937 | ||
928 | static int __init amd_iommu_v2_init(void) | 938 | static int __init amd_iommu_v2_init(void) |
929 | { | 939 | { |
930 | size_t state_table_size; | ||
931 | int ret; | 940 | int ret; |
932 | 941 | ||
933 | pr_info("AMD IOMMUv2 driver by Joerg Roedel <joerg.roedel@amd.com>\n"); | 942 | pr_info("AMD IOMMUv2 driver by Joerg Roedel <joerg.roedel@amd.com>\n"); |
@@ -943,16 +952,10 @@ static int __init amd_iommu_v2_init(void) | |||
943 | 952 | ||
944 | spin_lock_init(&state_lock); | 953 | spin_lock_init(&state_lock); |
945 | 954 | ||
946 | state_table_size = MAX_DEVICES * sizeof(struct device_state *); | ||
947 | state_table = (void *)__get_free_pages(GFP_KERNEL | __GFP_ZERO, | ||
948 | get_order(state_table_size)); | ||
949 | if (state_table == NULL) | ||
950 | return -ENOMEM; | ||
951 | |||
952 | ret = -ENOMEM; | 955 | ret = -ENOMEM; |
953 | iommu_wq = create_workqueue("amd_iommu_v2"); | 956 | iommu_wq = create_workqueue("amd_iommu_v2"); |
954 | if (iommu_wq == NULL) | 957 | if (iommu_wq == NULL) |
955 | goto out_free; | 958 | goto out; |
956 | 959 | ||
957 | ret = -ENOMEM; | 960 | ret = -ENOMEM; |
958 | empty_page_table = (u64 *)get_zeroed_page(GFP_KERNEL); | 961 | empty_page_table = (u64 *)get_zeroed_page(GFP_KERNEL); |
@@ -967,16 +970,13 @@ static int __init amd_iommu_v2_init(void) | |||
967 | out_destroy_wq: | 970 | out_destroy_wq: |
968 | destroy_workqueue(iommu_wq); | 971 | destroy_workqueue(iommu_wq); |
969 | 972 | ||
970 | out_free: | 973 | out: |
971 | free_pages((unsigned long)state_table, get_order(state_table_size)); | ||
972 | |||
973 | return ret; | 974 | return ret; |
974 | } | 975 | } |
975 | 976 | ||
976 | static void __exit amd_iommu_v2_exit(void) | 977 | static void __exit amd_iommu_v2_exit(void) |
977 | { | 978 | { |
978 | struct device_state *dev_state; | 979 | struct device_state *dev_state; |
979 | size_t state_table_size; | ||
980 | int i; | 980 | int i; |
981 | 981 | ||
982 | if (!amd_iommu_v2_supported()) | 982 | if (!amd_iommu_v2_supported()) |
@@ -1005,9 +1005,6 @@ static void __exit amd_iommu_v2_exit(void) | |||
1005 | 1005 | ||
1006 | destroy_workqueue(iommu_wq); | 1006 | destroy_workqueue(iommu_wq); |
1007 | 1007 | ||
1008 | state_table_size = MAX_DEVICES * sizeof(struct device_state *); | ||
1009 | free_pages((unsigned long)state_table, get_order(state_table_size)); | ||
1010 | |||
1011 | free_page((unsigned long)empty_page_table); | 1008 | free_page((unsigned long)empty_page_table); |
1012 | } | 1009 | } |
1013 | 1010 | ||