diff options
Diffstat (limited to 'arch/x86/kernel/amd_iommu_init.c')
-rw-r--r-- | arch/x86/kernel/amd_iommu_init.c | 119 |
1 files changed, 62 insertions, 57 deletions
diff --git a/arch/x86/kernel/amd_iommu_init.c b/arch/x86/kernel/amd_iommu_init.c index c20001e4f556..9dc91b431470 100644 --- a/arch/x86/kernel/amd_iommu_init.c +++ b/arch/x86/kernel/amd_iommu_init.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2007-2008 Advanced Micro Devices, Inc. | 2 | * Copyright (C) 2007-2009 Advanced Micro Devices, Inc. |
3 | * Author: Joerg Roedel <joerg.roedel@amd.com> | 3 | * Author: Joerg Roedel <joerg.roedel@amd.com> |
4 | * Leo Duran <leo.duran@amd.com> | 4 | * Leo Duran <leo.duran@amd.com> |
5 | * | 5 | * |
@@ -25,10 +25,12 @@ | |||
25 | #include <linux/interrupt.h> | 25 | #include <linux/interrupt.h> |
26 | #include <linux/msi.h> | 26 | #include <linux/msi.h> |
27 | #include <asm/pci-direct.h> | 27 | #include <asm/pci-direct.h> |
28 | #include <asm/amd_iommu_proto.h> | ||
28 | #include <asm/amd_iommu_types.h> | 29 | #include <asm/amd_iommu_types.h> |
29 | #include <asm/amd_iommu.h> | 30 | #include <asm/amd_iommu.h> |
30 | #include <asm/iommu.h> | 31 | #include <asm/iommu.h> |
31 | #include <asm/gart.h> | 32 | #include <asm/gart.h> |
33 | #include <asm/x86_init.h> | ||
32 | 34 | ||
33 | /* | 35 | /* |
34 | * definitions for the ACPI scanning code | 36 | * definitions for the ACPI scanning code |
@@ -123,18 +125,29 @@ u16 amd_iommu_last_bdf; /* largest PCI device id we have | |||
123 | to handle */ | 125 | to handle */ |
124 | LIST_HEAD(amd_iommu_unity_map); /* a list of required unity mappings | 126 | LIST_HEAD(amd_iommu_unity_map); /* a list of required unity mappings |
125 | we find in ACPI */ | 127 | we find in ACPI */ |
126 | #ifdef CONFIG_IOMMU_STRESS | ||
127 | bool amd_iommu_isolate = false; | ||
128 | #else | ||
129 | bool amd_iommu_isolate = true; /* if true, device isolation is | ||
130 | enabled */ | ||
131 | #endif | ||
132 | |||
133 | bool amd_iommu_unmap_flush; /* if true, flush on every unmap */ | 128 | bool amd_iommu_unmap_flush; /* if true, flush on every unmap */ |
134 | 129 | ||
135 | LIST_HEAD(amd_iommu_list); /* list of all AMD IOMMUs in the | 130 | LIST_HEAD(amd_iommu_list); /* list of all AMD IOMMUs in the |
136 | system */ | 131 | system */ |
137 | 132 | ||
133 | /* Array to assign indices to IOMMUs*/ | ||
134 | struct amd_iommu *amd_iommus[MAX_IOMMUS]; | ||
135 | int amd_iommus_present; | ||
136 | |||
137 | /* IOMMUs have a non-present cache? */ | ||
138 | bool amd_iommu_np_cache __read_mostly; | ||
139 | |||
140 | /* | ||
141 | * Set to true if ACPI table parsing and hardware intialization went properly | ||
142 | */ | ||
143 | static bool amd_iommu_initialized; | ||
144 | |||
145 | /* | ||
146 | * List of protection domains - used during resume | ||
147 | */ | ||
148 | LIST_HEAD(amd_iommu_pd_list); | ||
149 | spinlock_t amd_iommu_pd_lock; | ||
150 | |||
138 | /* | 151 | /* |
139 | * Pointer to the device table which is shared by all AMD IOMMUs | 152 | * Pointer to the device table which is shared by all AMD IOMMUs |
140 | * it is indexed by the PCI device id or the HT unit id and contains | 153 | * it is indexed by the PCI device id or the HT unit id and contains |
@@ -157,12 +170,6 @@ u16 *amd_iommu_alias_table; | |||
157 | struct amd_iommu **amd_iommu_rlookup_table; | 170 | struct amd_iommu **amd_iommu_rlookup_table; |
158 | 171 | ||
159 | /* | 172 | /* |
160 | * The pd table (protection domain table) is used to find the protection domain | ||
161 | * data structure a device belongs to. Indexed with the PCI device id too. | ||
162 | */ | ||
163 | struct protection_domain **amd_iommu_pd_table; | ||
164 | |||
165 | /* | ||
166 | * AMD IOMMU allows up to 2^16 differend protection domains. This is a bitmap | 173 | * AMD IOMMU allows up to 2^16 differend protection domains. This is a bitmap |
167 | * to know which ones are already in use. | 174 | * to know which ones are already in use. |
168 | */ | 175 | */ |
@@ -838,7 +845,18 @@ static void __init free_iommu_all(void) | |||
838 | static int __init init_iommu_one(struct amd_iommu *iommu, struct ivhd_header *h) | 845 | static int __init init_iommu_one(struct amd_iommu *iommu, struct ivhd_header *h) |
839 | { | 846 | { |
840 | spin_lock_init(&iommu->lock); | 847 | spin_lock_init(&iommu->lock); |
848 | |||
849 | /* Add IOMMU to internal data structures */ | ||
841 | list_add_tail(&iommu->list, &amd_iommu_list); | 850 | list_add_tail(&iommu->list, &amd_iommu_list); |
851 | iommu->index = amd_iommus_present++; | ||
852 | |||
853 | if (unlikely(iommu->index >= MAX_IOMMUS)) { | ||
854 | WARN(1, "AMD-Vi: System has more IOMMUs than supported by this driver\n"); | ||
855 | return -ENOSYS; | ||
856 | } | ||
857 | |||
858 | /* Index is fine - add IOMMU to the array */ | ||
859 | amd_iommus[iommu->index] = iommu; | ||
842 | 860 | ||
843 | /* | 861 | /* |
844 | * Copy data from ACPI table entry to the iommu struct | 862 | * Copy data from ACPI table entry to the iommu struct |
@@ -868,6 +886,9 @@ static int __init init_iommu_one(struct amd_iommu *iommu, struct ivhd_header *h) | |||
868 | init_iommu_from_acpi(iommu, h); | 886 | init_iommu_from_acpi(iommu, h); |
869 | init_iommu_devices(iommu); | 887 | init_iommu_devices(iommu); |
870 | 888 | ||
889 | if (iommu->cap & (1UL << IOMMU_CAP_NPCACHE)) | ||
890 | amd_iommu_np_cache = true; | ||
891 | |||
871 | return pci_enable_device(iommu->dev); | 892 | return pci_enable_device(iommu->dev); |
872 | } | 893 | } |
873 | 894 | ||
@@ -913,6 +934,8 @@ static int __init init_iommu_all(struct acpi_table_header *table) | |||
913 | } | 934 | } |
914 | WARN_ON(p != end); | 935 | WARN_ON(p != end); |
915 | 936 | ||
937 | amd_iommu_initialized = true; | ||
938 | |||
916 | return 0; | 939 | return 0; |
917 | } | 940 | } |
918 | 941 | ||
@@ -925,7 +948,7 @@ static int __init init_iommu_all(struct acpi_table_header *table) | |||
925 | * | 948 | * |
926 | ****************************************************************************/ | 949 | ****************************************************************************/ |
927 | 950 | ||
928 | static int __init iommu_setup_msi(struct amd_iommu *iommu) | 951 | static int iommu_setup_msi(struct amd_iommu *iommu) |
929 | { | 952 | { |
930 | int r; | 953 | int r; |
931 | 954 | ||
@@ -1176,19 +1199,10 @@ static struct sys_device device_amd_iommu = { | |||
1176 | * functions. Finally it prints some information about AMD IOMMUs and | 1199 | * functions. Finally it prints some information about AMD IOMMUs and |
1177 | * the driver state and enables the hardware. | 1200 | * the driver state and enables the hardware. |
1178 | */ | 1201 | */ |
1179 | int __init amd_iommu_init(void) | 1202 | static int __init amd_iommu_init(void) |
1180 | { | 1203 | { |
1181 | int i, ret = 0; | 1204 | int i, ret = 0; |
1182 | 1205 | ||
1183 | |||
1184 | if (no_iommu) { | ||
1185 | printk(KERN_INFO "AMD-Vi disabled by kernel command line\n"); | ||
1186 | return 0; | ||
1187 | } | ||
1188 | |||
1189 | if (!amd_iommu_detected) | ||
1190 | return -ENODEV; | ||
1191 | |||
1192 | /* | 1206 | /* |
1193 | * First parse ACPI tables to find the largest Bus/Dev/Func | 1207 | * First parse ACPI tables to find the largest Bus/Dev/Func |
1194 | * we need to handle. Upon this information the shared data | 1208 | * we need to handle. Upon this information the shared data |
@@ -1225,15 +1239,6 @@ int __init amd_iommu_init(void) | |||
1225 | if (amd_iommu_rlookup_table == NULL) | 1239 | if (amd_iommu_rlookup_table == NULL) |
1226 | goto free; | 1240 | goto free; |
1227 | 1241 | ||
1228 | /* | ||
1229 | * Protection Domain table - maps devices to protection domains | ||
1230 | * This table has the same size as the rlookup_table | ||
1231 | */ | ||
1232 | amd_iommu_pd_table = (void *)__get_free_pages(GFP_KERNEL | __GFP_ZERO, | ||
1233 | get_order(rlookup_table_size)); | ||
1234 | if (amd_iommu_pd_table == NULL) | ||
1235 | goto free; | ||
1236 | |||
1237 | amd_iommu_pd_alloc_bitmap = (void *)__get_free_pages( | 1242 | amd_iommu_pd_alloc_bitmap = (void *)__get_free_pages( |
1238 | GFP_KERNEL | __GFP_ZERO, | 1243 | GFP_KERNEL | __GFP_ZERO, |
1239 | get_order(MAX_DOMAIN_ID/8)); | 1244 | get_order(MAX_DOMAIN_ID/8)); |
@@ -1255,6 +1260,8 @@ int __init amd_iommu_init(void) | |||
1255 | */ | 1260 | */ |
1256 | amd_iommu_pd_alloc_bitmap[0] = 1; | 1261 | amd_iommu_pd_alloc_bitmap[0] = 1; |
1257 | 1262 | ||
1263 | spin_lock_init(&amd_iommu_pd_lock); | ||
1264 | |||
1258 | /* | 1265 | /* |
1259 | * now the data structures are allocated and basically initialized | 1266 | * now the data structures are allocated and basically initialized |
1260 | * start the real acpi table scan | 1267 | * start the real acpi table scan |
@@ -1263,6 +1270,9 @@ int __init amd_iommu_init(void) | |||
1263 | if (acpi_table_parse("IVRS", init_iommu_all) != 0) | 1270 | if (acpi_table_parse("IVRS", init_iommu_all) != 0) |
1264 | goto free; | 1271 | goto free; |
1265 | 1272 | ||
1273 | if (!amd_iommu_initialized) | ||
1274 | goto free; | ||
1275 | |||
1266 | if (acpi_table_parse("IVRS", init_memory_definitions) != 0) | 1276 | if (acpi_table_parse("IVRS", init_memory_definitions) != 0) |
1267 | goto free; | 1277 | goto free; |
1268 | 1278 | ||
@@ -1274,39 +1284,43 @@ int __init amd_iommu_init(void) | |||
1274 | if (ret) | 1284 | if (ret) |
1275 | goto free; | 1285 | goto free; |
1276 | 1286 | ||
1287 | ret = amd_iommu_init_devices(); | ||
1288 | if (ret) | ||
1289 | goto free; | ||
1290 | |||
1277 | if (iommu_pass_through) | 1291 | if (iommu_pass_through) |
1278 | ret = amd_iommu_init_passthrough(); | 1292 | ret = amd_iommu_init_passthrough(); |
1279 | else | 1293 | else |
1280 | ret = amd_iommu_init_dma_ops(); | 1294 | ret = amd_iommu_init_dma_ops(); |
1295 | |||
1281 | if (ret) | 1296 | if (ret) |
1282 | goto free; | 1297 | goto free; |
1283 | 1298 | ||
1299 | amd_iommu_init_api(); | ||
1300 | |||
1301 | amd_iommu_init_notifier(); | ||
1302 | |||
1284 | enable_iommus(); | 1303 | enable_iommus(); |
1285 | 1304 | ||
1286 | if (iommu_pass_through) | 1305 | if (iommu_pass_through) |
1287 | goto out; | 1306 | goto out; |
1288 | 1307 | ||
1289 | printk(KERN_INFO "AMD-Vi: device isolation "); | ||
1290 | if (amd_iommu_isolate) | ||
1291 | printk("enabled\n"); | ||
1292 | else | ||
1293 | printk("disabled\n"); | ||
1294 | |||
1295 | if (amd_iommu_unmap_flush) | 1308 | if (amd_iommu_unmap_flush) |
1296 | printk(KERN_INFO "AMD-Vi: IO/TLB flush on unmap enabled\n"); | 1309 | printk(KERN_INFO "AMD-Vi: IO/TLB flush on unmap enabled\n"); |
1297 | else | 1310 | else |
1298 | printk(KERN_INFO "AMD-Vi: Lazy IO/TLB flushing enabled\n"); | 1311 | printk(KERN_INFO "AMD-Vi: Lazy IO/TLB flushing enabled\n"); |
1299 | 1312 | ||
1313 | x86_platform.iommu_shutdown = disable_iommus; | ||
1300 | out: | 1314 | out: |
1301 | return ret; | 1315 | return ret; |
1302 | 1316 | ||
1303 | free: | 1317 | free: |
1318 | |||
1319 | amd_iommu_uninit_devices(); | ||
1320 | |||
1304 | free_pages((unsigned long)amd_iommu_pd_alloc_bitmap, | 1321 | free_pages((unsigned long)amd_iommu_pd_alloc_bitmap, |
1305 | get_order(MAX_DOMAIN_ID/8)); | 1322 | get_order(MAX_DOMAIN_ID/8)); |
1306 | 1323 | ||
1307 | free_pages((unsigned long)amd_iommu_pd_table, | ||
1308 | get_order(rlookup_table_size)); | ||
1309 | |||
1310 | free_pages((unsigned long)amd_iommu_rlookup_table, | 1324 | free_pages((unsigned long)amd_iommu_rlookup_table, |
1311 | get_order(rlookup_table_size)); | 1325 | get_order(rlookup_table_size)); |
1312 | 1326 | ||
@@ -1323,11 +1337,6 @@ free: | |||
1323 | goto out; | 1337 | goto out; |
1324 | } | 1338 | } |
1325 | 1339 | ||
1326 | void amd_iommu_shutdown(void) | ||
1327 | { | ||
1328 | disable_iommus(); | ||
1329 | } | ||
1330 | |||
1331 | /**************************************************************************** | 1340 | /**************************************************************************** |
1332 | * | 1341 | * |
1333 | * Early detect code. This code runs at IOMMU detection time in the DMA | 1342 | * Early detect code. This code runs at IOMMU detection time in the DMA |
@@ -1342,16 +1351,16 @@ static int __init early_amd_iommu_detect(struct acpi_table_header *table) | |||
1342 | 1351 | ||
1343 | void __init amd_iommu_detect(void) | 1352 | void __init amd_iommu_detect(void) |
1344 | { | 1353 | { |
1345 | if (swiotlb || no_iommu || (iommu_detected && !gart_iommu_aperture)) | 1354 | if (no_iommu || (iommu_detected && !gart_iommu_aperture)) |
1346 | return; | 1355 | return; |
1347 | 1356 | ||
1348 | if (acpi_table_parse("IVRS", early_amd_iommu_detect) == 0) { | 1357 | if (acpi_table_parse("IVRS", early_amd_iommu_detect) == 0) { |
1349 | iommu_detected = 1; | 1358 | iommu_detected = 1; |
1350 | amd_iommu_detected = 1; | 1359 | amd_iommu_detected = 1; |
1351 | #ifdef CONFIG_GART_IOMMU | 1360 | x86_init.iommu.iommu_init = amd_iommu_init; |
1352 | gart_iommu_aperture_disabled = 1; | 1361 | |
1353 | gart_iommu_aperture = 0; | 1362 | /* Make sure ACS will be enabled */ |
1354 | #endif | 1363 | pci_request_acs(); |
1355 | } | 1364 | } |
1356 | } | 1365 | } |
1357 | 1366 | ||
@@ -1372,10 +1381,6 @@ static int __init parse_amd_iommu_dump(char *str) | |||
1372 | static int __init parse_amd_iommu_options(char *str) | 1381 | static int __init parse_amd_iommu_options(char *str) |
1373 | { | 1382 | { |
1374 | for (; *str; ++str) { | 1383 | for (; *str; ++str) { |
1375 | if (strncmp(str, "isolate", 7) == 0) | ||
1376 | amd_iommu_isolate = true; | ||
1377 | if (strncmp(str, "share", 5) == 0) | ||
1378 | amd_iommu_isolate = false; | ||
1379 | if (strncmp(str, "fullflush", 9) == 0) | 1384 | if (strncmp(str, "fullflush", 9) == 0) |
1380 | amd_iommu_unmap_flush = true; | 1385 | amd_iommu_unmap_flush = true; |
1381 | } | 1386 | } |