diff options
-rw-r--r-- | arch/ia64/include/asm/iommu_table.h | 6 | ||||
-rw-r--r-- | arch/x86/include/asm/amd_iommu.h | 4 | ||||
-rw-r--r-- | arch/x86/include/asm/calgary.h | 4 | ||||
-rw-r--r-- | arch/x86/include/asm/gart.h | 5 | ||||
-rw-r--r-- | arch/x86/include/asm/iommu_table.h | 100 | ||||
-rw-r--r-- | arch/x86/include/asm/swiotlb.h | 13 | ||||
-rw-r--r-- | arch/x86/kernel/Makefile | 1 | ||||
-rw-r--r-- | arch/x86/kernel/amd_iommu_init.c | 15 | ||||
-rw-r--r-- | arch/x86/kernel/aperture_64.c | 11 | ||||
-rw-r--r-- | arch/x86/kernel/pci-calgary_64.c | 18 | ||||
-rw-r--r-- | arch/x86/kernel/pci-dma.c | 44 | ||||
-rw-r--r-- | arch/x86/kernel/pci-gart_64.c | 2 | ||||
-rw-r--r-- | arch/x86/kernel/pci-iommu_table.c | 89 | ||||
-rw-r--r-- | arch/x86/kernel/pci-swiotlb.c | 44 | ||||
-rw-r--r-- | arch/x86/kernel/vmlinux.lds.S | 28 | ||||
-rw-r--r-- | arch/x86/xen/pci-swiotlb-xen.c | 5 | ||||
-rw-r--r-- | drivers/pci/dmar.c | 6 | ||||
-rw-r--r-- | include/linux/dmar.h | 6 |
18 files changed, 344 insertions, 57 deletions
diff --git a/arch/ia64/include/asm/iommu_table.h b/arch/ia64/include/asm/iommu_table.h new file mode 100644 index 000000000000..92c8d36ae5ae --- /dev/null +++ b/arch/ia64/include/asm/iommu_table.h | |||
@@ -0,0 +1,6 @@ | |||
1 | #ifndef _ASM_IA64_IOMMU_TABLE_H | ||
2 | #define _ASM_IA64_IOMMU_TABLE_H | ||
3 | |||
4 | #define IOMMU_INIT_POST(_detect) | ||
5 | |||
6 | #endif /* _ASM_IA64_IOMMU_TABLE_H */ | ||
diff --git a/arch/x86/include/asm/amd_iommu.h b/arch/x86/include/asm/amd_iommu.h index f16a2caca1e0..a6863a2dec1f 100644 --- a/arch/x86/include/asm/amd_iommu.h +++ b/arch/x86/include/asm/amd_iommu.h | |||
@@ -24,11 +24,11 @@ | |||
24 | 24 | ||
25 | #ifdef CONFIG_AMD_IOMMU | 25 | #ifdef CONFIG_AMD_IOMMU |
26 | 26 | ||
27 | extern void amd_iommu_detect(void); | 27 | extern int amd_iommu_detect(void); |
28 | 28 | ||
29 | #else | 29 | #else |
30 | 30 | ||
31 | static inline void amd_iommu_detect(void) { } | 31 | static inline int amd_iommu_detect(void) { return -ENODEV; } |
32 | 32 | ||
33 | #endif | 33 | #endif |
34 | 34 | ||
diff --git a/arch/x86/include/asm/calgary.h b/arch/x86/include/asm/calgary.h index 0918654305af..0d467b338835 100644 --- a/arch/x86/include/asm/calgary.h +++ b/arch/x86/include/asm/calgary.h | |||
@@ -62,9 +62,9 @@ struct cal_chipset_ops { | |||
62 | extern int use_calgary; | 62 | extern int use_calgary; |
63 | 63 | ||
64 | #ifdef CONFIG_CALGARY_IOMMU | 64 | #ifdef CONFIG_CALGARY_IOMMU |
65 | extern void detect_calgary(void); | 65 | extern int detect_calgary(void); |
66 | #else | 66 | #else |
67 | static inline void detect_calgary(void) { return; } | 67 | static inline int detect_calgary(void) { return -ENODEV; } |
68 | #endif | 68 | #endif |
69 | 69 | ||
70 | #endif /* _ASM_X86_CALGARY_H */ | 70 | #endif /* _ASM_X86_CALGARY_H */ |
diff --git a/arch/x86/include/asm/gart.h b/arch/x86/include/asm/gart.h index bf357f9b25f0..43085bfc99c3 100644 --- a/arch/x86/include/asm/gart.h +++ b/arch/x86/include/asm/gart.h | |||
@@ -37,7 +37,7 @@ extern int gart_iommu_aperture_disabled; | |||
37 | extern void early_gart_iommu_check(void); | 37 | extern void early_gart_iommu_check(void); |
38 | extern int gart_iommu_init(void); | 38 | extern int gart_iommu_init(void); |
39 | extern void __init gart_parse_options(char *); | 39 | extern void __init gart_parse_options(char *); |
40 | extern void gart_iommu_hole_init(void); | 40 | extern int gart_iommu_hole_init(void); |
41 | 41 | ||
42 | #else | 42 | #else |
43 | #define gart_iommu_aperture 0 | 43 | #define gart_iommu_aperture 0 |
@@ -50,8 +50,9 @@ static inline void early_gart_iommu_check(void) | |||
50 | static inline void gart_parse_options(char *options) | 50 | static inline void gart_parse_options(char *options) |
51 | { | 51 | { |
52 | } | 52 | } |
53 | static inline void gart_iommu_hole_init(void) | 53 | static inline int gart_iommu_hole_init(void) |
54 | { | 54 | { |
55 | return -ENODEV; | ||
55 | } | 56 | } |
56 | #endif | 57 | #endif |
57 | 58 | ||
diff --git a/arch/x86/include/asm/iommu_table.h b/arch/x86/include/asm/iommu_table.h new file mode 100644 index 000000000000..f229b13a5f30 --- /dev/null +++ b/arch/x86/include/asm/iommu_table.h | |||
@@ -0,0 +1,100 @@ | |||
1 | #ifndef _ASM_X86_IOMMU_TABLE_H | ||
2 | #define _ASM_X86_IOMMU_TABLE_H | ||
3 | |||
4 | #include <asm/swiotlb.h> | ||
5 | |||
6 | /* | ||
7 | * History lesson: | ||
8 | * The execution chain of IOMMUs in 2.6.36 looks as so: | ||
9 | * | ||
10 | * [xen-swiotlb] | ||
11 | * | | ||
12 | * +----[swiotlb *]--+ | ||
13 | * / | \ | ||
14 | * / | \ | ||
15 | * [GART] [Calgary] [Intel VT-d] | ||
16 | * / | ||
17 | * / | ||
18 | * [AMD-Vi] | ||
19 | * | ||
20 | * *: if SWIOTLB detected 'iommu=soft'/'swiotlb=force' it would skip | ||
21 | * over the rest of IOMMUs and unconditionally initialize the SWIOTLB. | ||
22 | * Also it would surreptitiously initialize set the swiotlb=1 if there were | ||
23 | * more than 4GB and if the user did not pass in 'iommu=off'. The swiotlb | ||
24 | * flag would be turned off by all IOMMUs except the Calgary one. | ||
25 | * | ||
26 | * The IOMMU_INIT* macros allow a similar tree (or more complex if desired) | ||
27 | * to be built by defining who we depend on. | ||
28 | * | ||
29 | * And all that needs to be done is to use one of the macros in the IOMMU | ||
30 | * and the pci-dma.c will take care of the rest. | ||
31 | */ | ||
32 | |||
33 | struct iommu_table_entry { | ||
34 | initcall_t detect; | ||
35 | initcall_t depend; | ||
36 | void (*early_init)(void); /* No memory allocate available. */ | ||
37 | void (*late_init)(void); /* Yes, can allocate memory. */ | ||
38 | #define IOMMU_FINISH_IF_DETECTED (1<<0) | ||
39 | #define IOMMU_DETECTED (1<<1) | ||
40 | int flags; | ||
41 | }; | ||
42 | /* | ||
43 | * Macro fills out an entry in the .iommu_table that is equivalent | ||
44 | * to the fields that 'struct iommu_table_entry' has. The entries | ||
45 | * that are put in the .iommu_table section are not put in any order | ||
46 | * hence during boot-time we will have to resort them based on | ||
47 | * dependency. */ | ||
48 | |||
49 | |||
50 | #define __IOMMU_INIT(_detect, _depend, _early_init, _late_init, _finish)\ | ||
51 | static const struct iommu_table_entry const \ | ||
52 | __iommu_entry_##_detect __used \ | ||
53 | __attribute__ ((unused, __section__(".iommu_table"), \ | ||
54 | aligned((sizeof(void *))))) \ | ||
55 | = {_detect, _depend, _early_init, _late_init, \ | ||
56 | _finish ? IOMMU_FINISH_IF_DETECTED : 0} | ||
57 | /* | ||
58 | * The simplest IOMMU definition. Provide the detection routine | ||
59 | * and it will be run after the SWIOTLB and the other IOMMUs | ||
60 | * that utilize this macro. If the IOMMU is detected (ie, the | ||
61 | * detect routine returns a positive value), the other IOMMUs | ||
62 | * are also checked. You can use IOMMU_INIT_POST_FINISH if you prefer | ||
63 | * to stop detecting the other IOMMUs after yours has been detected. | ||
64 | */ | ||
65 | #define IOMMU_INIT_POST(_detect) \ | ||
66 | __IOMMU_INIT(_detect, pci_swiotlb_detect_4gb, 0, 0, 0) | ||
67 | |||
68 | #define IOMMU_INIT_POST_FINISH(detect) \ | ||
69 | __IOMMU_INIT(_detect, pci_swiotlb_detect_4gb, 0, 0, 1) | ||
70 | |||
71 | /* | ||
72 | * A more sophisticated version of IOMMU_INIT. This variant requires: | ||
73 | * a). A detection routine function. | ||
74 | * b). The name of the detection routine we depend on to get called | ||
75 | * before us. | ||
76 | * c). The init routine which gets called if the detection routine | ||
77 | * returns a positive value from the pci_iommu_alloc. This means | ||
78 | * no presence of a memory allocator. | ||
79 | * d). Similar to the 'init', except that this gets called from pci_iommu_init | ||
80 | * where we do have a memory allocator. | ||
81 | * | ||
82 | * The standard vs the _FINISH differs in that the _FINISH variant will | ||
83 | * continue detecting other IOMMUs in the call list after the | ||
84 | * the detection routine returns a positive number. The _FINISH will | ||
85 | * stop the execution chain. Both will still call the 'init' and | ||
86 | * 'late_init' functions if they are set. | ||
87 | */ | ||
88 | #define IOMMU_INIT_FINISH(_detect, _depend, _init, _late_init) \ | ||
89 | __IOMMU_INIT(_detect, _depend, _init, _late_init, 1) | ||
90 | |||
91 | #define IOMMU_INIT(_detect, _depend, _init, _late_init) \ | ||
92 | __IOMMU_INIT(_detect, _depend, _init, _late_init, 0) | ||
93 | |||
94 | void sort_iommu_table(struct iommu_table_entry *start, | ||
95 | struct iommu_table_entry *finish); | ||
96 | |||
97 | void check_iommu_entries(struct iommu_table_entry *start, | ||
98 | struct iommu_table_entry *finish); | ||
99 | |||
100 | #endif /* _ASM_X86_IOMMU_TABLE_H */ | ||
diff --git a/arch/x86/include/asm/swiotlb.h b/arch/x86/include/asm/swiotlb.h index 8085277e1b8b..977f1761a25d 100644 --- a/arch/x86/include/asm/swiotlb.h +++ b/arch/x86/include/asm/swiotlb.h | |||
@@ -5,17 +5,26 @@ | |||
5 | 5 | ||
6 | #ifdef CONFIG_SWIOTLB | 6 | #ifdef CONFIG_SWIOTLB |
7 | extern int swiotlb; | 7 | extern int swiotlb; |
8 | extern int __init pci_swiotlb_detect(void); | 8 | extern int __init pci_swiotlb_detect_override(void); |
9 | extern int __init pci_swiotlb_detect_4gb(void); | ||
9 | extern void __init pci_swiotlb_init(void); | 10 | extern void __init pci_swiotlb_init(void); |
11 | extern void __init pci_swiotlb_late_init(void); | ||
10 | #else | 12 | #else |
11 | #define swiotlb 0 | 13 | #define swiotlb 0 |
12 | static inline int pci_swiotlb_detect(void) | 14 | static inline int pci_swiotlb_detect_override(void) |
15 | { | ||
16 | return 0; | ||
17 | } | ||
18 | static inline int pci_swiotlb_detect_4gb(void) | ||
13 | { | 19 | { |
14 | return 0; | 20 | return 0; |
15 | } | 21 | } |
16 | static inline void pci_swiotlb_init(void) | 22 | static inline void pci_swiotlb_init(void) |
17 | { | 23 | { |
18 | } | 24 | } |
25 | static inline void pci_swiotlb_late_init(void) | ||
26 | { | ||
27 | } | ||
19 | #endif | 28 | #endif |
20 | 29 | ||
21 | static inline void dma_mark_clean(void *addr, size_t size) {} | 30 | static inline void dma_mark_clean(void *addr, size_t size) {} |
diff --git a/arch/x86/kernel/Makefile b/arch/x86/kernel/Makefile index 80a93dc99076..2c833d8c4141 100644 --- a/arch/x86/kernel/Makefile +++ b/arch/x86/kernel/Makefile | |||
@@ -45,6 +45,7 @@ obj-y += bootflag.o e820.o | |||
45 | obj-y += pci-dma.o quirks.o i8237.o topology.o kdebugfs.o | 45 | obj-y += pci-dma.o quirks.o i8237.o topology.o kdebugfs.o |
46 | obj-y += alternative.o i8253.o pci-nommu.o hw_breakpoint.o | 46 | obj-y += alternative.o i8253.o pci-nommu.o hw_breakpoint.o |
47 | obj-y += tsc.o io_delay.o rtc.o | 47 | obj-y += tsc.o io_delay.o rtc.o |
48 | obj-y += pci-iommu_table.o | ||
48 | 49 | ||
49 | obj-$(CONFIG_X86_TRAMPOLINE) += trampoline.o | 50 | obj-$(CONFIG_X86_TRAMPOLINE) += trampoline.o |
50 | obj-y += process.o | 51 | obj-y += process.o |
diff --git a/arch/x86/kernel/amd_iommu_init.c b/arch/x86/kernel/amd_iommu_init.c index 3cb482e123de..6e11c8134158 100644 --- a/arch/x86/kernel/amd_iommu_init.c +++ b/arch/x86/kernel/amd_iommu_init.c | |||
@@ -31,7 +31,7 @@ | |||
31 | #include <asm/iommu.h> | 31 | #include <asm/iommu.h> |
32 | #include <asm/gart.h> | 32 | #include <asm/gart.h> |
33 | #include <asm/x86_init.h> | 33 | #include <asm/x86_init.h> |
34 | 34 | #include <asm/iommu_table.h> | |
35 | /* | 35 | /* |
36 | * definitions for the ACPI scanning code | 36 | * definitions for the ACPI scanning code |
37 | */ | 37 | */ |
@@ -1499,13 +1499,13 @@ static int __init early_amd_iommu_detect(struct acpi_table_header *table) | |||
1499 | return 0; | 1499 | return 0; |
1500 | } | 1500 | } |
1501 | 1501 | ||
1502 | void __init amd_iommu_detect(void) | 1502 | int __init amd_iommu_detect(void) |
1503 | { | 1503 | { |
1504 | if (no_iommu || (iommu_detected && !gart_iommu_aperture)) | 1504 | if (no_iommu || (iommu_detected && !gart_iommu_aperture)) |
1505 | return; | 1505 | return -ENODEV; |
1506 | 1506 | ||
1507 | if (amd_iommu_disabled) | 1507 | if (amd_iommu_disabled) |
1508 | return; | 1508 | return -ENODEV; |
1509 | 1509 | ||
1510 | if (acpi_table_parse("IVRS", early_amd_iommu_detect) == 0) { | 1510 | if (acpi_table_parse("IVRS", early_amd_iommu_detect) == 0) { |
1511 | iommu_detected = 1; | 1511 | iommu_detected = 1; |
@@ -1514,7 +1514,9 @@ void __init amd_iommu_detect(void) | |||
1514 | 1514 | ||
1515 | /* Make sure ACS will be enabled */ | 1515 | /* Make sure ACS will be enabled */ |
1516 | pci_request_acs(); | 1516 | pci_request_acs(); |
1517 | return 1; | ||
1517 | } | 1518 | } |
1519 | return -ENODEV; | ||
1518 | } | 1520 | } |
1519 | 1521 | ||
1520 | /**************************************************************************** | 1522 | /**************************************************************************** |
@@ -1545,3 +1547,8 @@ static int __init parse_amd_iommu_options(char *str) | |||
1545 | 1547 | ||
1546 | __setup("amd_iommu_dump", parse_amd_iommu_dump); | 1548 | __setup("amd_iommu_dump", parse_amd_iommu_dump); |
1547 | __setup("amd_iommu=", parse_amd_iommu_options); | 1549 | __setup("amd_iommu=", parse_amd_iommu_options); |
1550 | |||
1551 | IOMMU_INIT_FINISH(amd_iommu_detect, | ||
1552 | gart_iommu_hole_init, | ||
1553 | 0, | ||
1554 | 0); | ||
diff --git a/arch/x86/kernel/aperture_64.c b/arch/x86/kernel/aperture_64.c index 377f5db3b8b4..b3a16e8f0703 100644 --- a/arch/x86/kernel/aperture_64.c +++ b/arch/x86/kernel/aperture_64.c | |||
@@ -371,7 +371,7 @@ void __init early_gart_iommu_check(void) | |||
371 | 371 | ||
372 | static int __initdata printed_gart_size_msg; | 372 | static int __initdata printed_gart_size_msg; |
373 | 373 | ||
374 | void __init gart_iommu_hole_init(void) | 374 | int __init gart_iommu_hole_init(void) |
375 | { | 375 | { |
376 | u32 agp_aper_base = 0, agp_aper_order = 0; | 376 | u32 agp_aper_base = 0, agp_aper_order = 0; |
377 | u32 aper_size, aper_alloc = 0, aper_order = 0, last_aper_order = 0; | 377 | u32 aper_size, aper_alloc = 0, aper_order = 0, last_aper_order = 0; |
@@ -381,7 +381,7 @@ void __init gart_iommu_hole_init(void) | |||
381 | 381 | ||
382 | if (gart_iommu_aperture_disabled || !fix_aperture || | 382 | if (gart_iommu_aperture_disabled || !fix_aperture || |
383 | !early_pci_allowed()) | 383 | !early_pci_allowed()) |
384 | return; | 384 | return -ENODEV; |
385 | 385 | ||
386 | printk(KERN_INFO "Checking aperture...\n"); | 386 | printk(KERN_INFO "Checking aperture...\n"); |
387 | 387 | ||
@@ -463,8 +463,9 @@ out: | |||
463 | unsigned long n = (32 * 1024 * 1024) << last_aper_order; | 463 | unsigned long n = (32 * 1024 * 1024) << last_aper_order; |
464 | 464 | ||
465 | insert_aperture_resource((u32)last_aper_base, n); | 465 | insert_aperture_resource((u32)last_aper_base, n); |
466 | return 1; | ||
466 | } | 467 | } |
467 | return; | 468 | return 0; |
468 | } | 469 | } |
469 | 470 | ||
470 | if (!fallback_aper_force) { | 471 | if (!fallback_aper_force) { |
@@ -500,7 +501,7 @@ out: | |||
500 | panic("Not enough memory for aperture"); | 501 | panic("Not enough memory for aperture"); |
501 | } | 502 | } |
502 | } else { | 503 | } else { |
503 | return; | 504 | return 0; |
504 | } | 505 | } |
505 | 506 | ||
506 | /* Fix up the north bridges */ | 507 | /* Fix up the north bridges */ |
@@ -526,4 +527,6 @@ out: | |||
526 | } | 527 | } |
527 | 528 | ||
528 | set_up_gart_resume(aper_order, aper_alloc); | 529 | set_up_gart_resume(aper_order, aper_alloc); |
530 | |||
531 | return 1; | ||
529 | } | 532 | } |
diff --git a/arch/x86/kernel/pci-calgary_64.c b/arch/x86/kernel/pci-calgary_64.c index 078d4ec1a9d9..f56a117cef68 100644 --- a/arch/x86/kernel/pci-calgary_64.c +++ b/arch/x86/kernel/pci-calgary_64.c | |||
@@ -47,6 +47,7 @@ | |||
47 | #include <asm/rio.h> | 47 | #include <asm/rio.h> |
48 | #include <asm/bios_ebda.h> | 48 | #include <asm/bios_ebda.h> |
49 | #include <asm/x86_init.h> | 49 | #include <asm/x86_init.h> |
50 | #include <asm/iommu_table.h> | ||
50 | 51 | ||
51 | #ifdef CONFIG_CALGARY_IOMMU_ENABLED_BY_DEFAULT | 52 | #ifdef CONFIG_CALGARY_IOMMU_ENABLED_BY_DEFAULT |
52 | int use_calgary __read_mostly = 1; | 53 | int use_calgary __read_mostly = 1; |
@@ -1364,7 +1365,7 @@ static int __init calgary_iommu_init(void) | |||
1364 | return 0; | 1365 | return 0; |
1365 | } | 1366 | } |
1366 | 1367 | ||
1367 | void __init detect_calgary(void) | 1368 | int __init detect_calgary(void) |
1368 | { | 1369 | { |
1369 | int bus; | 1370 | int bus; |
1370 | void *tbl; | 1371 | void *tbl; |
@@ -1378,13 +1379,13 @@ void __init detect_calgary(void) | |||
1378 | * another HW IOMMU already, bail out. | 1379 | * another HW IOMMU already, bail out. |
1379 | */ | 1380 | */ |
1380 | if (no_iommu || iommu_detected) | 1381 | if (no_iommu || iommu_detected) |
1381 | return; | 1382 | return -ENODEV; |
1382 | 1383 | ||
1383 | if (!use_calgary) | 1384 | if (!use_calgary) |
1384 | return; | 1385 | return -ENODEV; |
1385 | 1386 | ||
1386 | if (!early_pci_allowed()) | 1387 | if (!early_pci_allowed()) |
1387 | return; | 1388 | return -ENODEV; |
1388 | 1389 | ||
1389 | printk(KERN_DEBUG "Calgary: detecting Calgary via BIOS EBDA area\n"); | 1390 | printk(KERN_DEBUG "Calgary: detecting Calgary via BIOS EBDA area\n"); |
1390 | 1391 | ||
@@ -1410,13 +1411,13 @@ void __init detect_calgary(void) | |||
1410 | if (!rio_table_hdr) { | 1411 | if (!rio_table_hdr) { |
1411 | printk(KERN_DEBUG "Calgary: Unable to locate Rio Grande table " | 1412 | printk(KERN_DEBUG "Calgary: Unable to locate Rio Grande table " |
1412 | "in EBDA - bailing!\n"); | 1413 | "in EBDA - bailing!\n"); |
1413 | return; | 1414 | return -ENODEV; |
1414 | } | 1415 | } |
1415 | 1416 | ||
1416 | ret = build_detail_arrays(); | 1417 | ret = build_detail_arrays(); |
1417 | if (ret) { | 1418 | if (ret) { |
1418 | printk(KERN_DEBUG "Calgary: build_detail_arrays ret %d\n", ret); | 1419 | printk(KERN_DEBUG "Calgary: build_detail_arrays ret %d\n", ret); |
1419 | return; | 1420 | return -ENOMEM; |
1420 | } | 1421 | } |
1421 | 1422 | ||
1422 | specified_table_size = determine_tce_table_size((is_kdump_kernel() ? | 1423 | specified_table_size = determine_tce_table_size((is_kdump_kernel() ? |
@@ -1464,7 +1465,7 @@ void __init detect_calgary(void) | |||
1464 | 1465 | ||
1465 | x86_init.iommu.iommu_init = calgary_iommu_init; | 1466 | x86_init.iommu.iommu_init = calgary_iommu_init; |
1466 | } | 1467 | } |
1467 | return; | 1468 | return calgary_found; |
1468 | 1469 | ||
1469 | cleanup: | 1470 | cleanup: |
1470 | for (--bus; bus >= 0; --bus) { | 1471 | for (--bus; bus >= 0; --bus) { |
@@ -1473,6 +1474,7 @@ cleanup: | |||
1473 | if (info->tce_space) | 1474 | if (info->tce_space) |
1474 | free_tce_table(info->tce_space); | 1475 | free_tce_table(info->tce_space); |
1475 | } | 1476 | } |
1477 | return -ENOMEM; | ||
1476 | } | 1478 | } |
1477 | 1479 | ||
1478 | static int __init calgary_parse_options(char *p) | 1480 | static int __init calgary_parse_options(char *p) |
@@ -1594,3 +1596,5 @@ static int __init calgary_fixup_tce_spaces(void) | |||
1594 | * and before device_initcall. | 1596 | * and before device_initcall. |
1595 | */ | 1597 | */ |
1596 | rootfs_initcall(calgary_fixup_tce_spaces); | 1598 | rootfs_initcall(calgary_fixup_tce_spaces); |
1599 | |||
1600 | IOMMU_INIT_POST(detect_calgary); | ||
diff --git a/arch/x86/kernel/pci-dma.c b/arch/x86/kernel/pci-dma.c index 9f07cfcbd3a5..9ea999a4dcc1 100644 --- a/arch/x86/kernel/pci-dma.c +++ b/arch/x86/kernel/pci-dma.c | |||
@@ -11,9 +11,8 @@ | |||
11 | #include <asm/iommu.h> | 11 | #include <asm/iommu.h> |
12 | #include <asm/gart.h> | 12 | #include <asm/gart.h> |
13 | #include <asm/calgary.h> | 13 | #include <asm/calgary.h> |
14 | #include <asm/amd_iommu.h> | ||
15 | #include <asm/x86_init.h> | 14 | #include <asm/x86_init.h> |
16 | #include <asm/xen/swiotlb-xen.h> | 15 | #include <asm/iommu_table.h> |
17 | 16 | ||
18 | static int forbid_dac __read_mostly; | 17 | static int forbid_dac __read_mostly; |
19 | 18 | ||
@@ -45,6 +44,8 @@ int iommu_detected __read_mostly = 0; | |||
45 | */ | 44 | */ |
46 | int iommu_pass_through __read_mostly; | 45 | int iommu_pass_through __read_mostly; |
47 | 46 | ||
47 | extern struct iommu_table_entry __iommu_table[], __iommu_table_end[]; | ||
48 | |||
48 | /* Dummy device used for NULL arguments (normally ISA). */ | 49 | /* Dummy device used for NULL arguments (normally ISA). */ |
49 | struct device x86_dma_fallback_dev = { | 50 | struct device x86_dma_fallback_dev = { |
50 | .init_name = "fallback device", | 51 | .init_name = "fallback device", |
@@ -130,26 +131,24 @@ static void __init dma32_free_bootmem(void) | |||
130 | 131 | ||
131 | void __init pci_iommu_alloc(void) | 132 | void __init pci_iommu_alloc(void) |
132 | { | 133 | { |
134 | struct iommu_table_entry *p; | ||
135 | |||
133 | /* free the range so iommu could get some range less than 4G */ | 136 | /* free the range so iommu could get some range less than 4G */ |
134 | dma32_free_bootmem(); | 137 | dma32_free_bootmem(); |
135 | 138 | ||
136 | if (pci_xen_swiotlb_detect() || pci_swiotlb_detect()) | 139 | sort_iommu_table(__iommu_table, __iommu_table_end); |
137 | goto out; | 140 | check_iommu_entries(__iommu_table, __iommu_table_end); |
138 | |||
139 | gart_iommu_hole_init(); | ||
140 | |||
141 | detect_calgary(); | ||
142 | |||
143 | detect_intel_iommu(); | ||
144 | 141 | ||
145 | /* needs to be called after gart_iommu_hole_init */ | 142 | for (p = __iommu_table; p < __iommu_table_end; p++) { |
146 | amd_iommu_detect(); | 143 | if (p && p->detect && p->detect() > 0) { |
147 | out: | 144 | p->flags |= IOMMU_DETECTED; |
148 | pci_xen_swiotlb_init(); | 145 | if (p->early_init) |
149 | 146 | p->early_init(); | |
150 | pci_swiotlb_init(); | 147 | if (p->flags & IOMMU_FINISH_IF_DETECTED) |
148 | break; | ||
149 | } | ||
150 | } | ||
151 | } | 151 | } |
152 | |||
153 | void *dma_generic_alloc_coherent(struct device *dev, size_t size, | 152 | void *dma_generic_alloc_coherent(struct device *dev, size_t size, |
154 | dma_addr_t *dma_addr, gfp_t flag) | 153 | dma_addr_t *dma_addr, gfp_t flag) |
155 | { | 154 | { |
@@ -292,6 +291,7 @@ EXPORT_SYMBOL(dma_supported); | |||
292 | 291 | ||
293 | static int __init pci_iommu_init(void) | 292 | static int __init pci_iommu_init(void) |
294 | { | 293 | { |
294 | struct iommu_table_entry *p; | ||
295 | dma_debug_init(PREALLOC_DMA_DEBUG_ENTRIES); | 295 | dma_debug_init(PREALLOC_DMA_DEBUG_ENTRIES); |
296 | 296 | ||
297 | #ifdef CONFIG_PCI | 297 | #ifdef CONFIG_PCI |
@@ -299,12 +299,10 @@ static int __init pci_iommu_init(void) | |||
299 | #endif | 299 | #endif |
300 | x86_init.iommu.iommu_init(); | 300 | x86_init.iommu.iommu_init(); |
301 | 301 | ||
302 | if (swiotlb || xen_swiotlb) { | 302 | for (p = __iommu_table; p < __iommu_table_end; p++) { |
303 | printk(KERN_INFO "PCI-DMA: " | 303 | if (p && (p->flags & IOMMU_DETECTED) && p->late_init) |
304 | "Using software bounce buffering for IO (SWIOTLB)\n"); | 304 | p->late_init(); |
305 | swiotlb_print_info(); | 305 | } |
306 | } else | ||
307 | swiotlb_free(); | ||
308 | 306 | ||
309 | return 0; | 307 | return 0; |
310 | } | 308 | } |
diff --git a/arch/x86/kernel/pci-gart_64.c b/arch/x86/kernel/pci-gart_64.c index c562207b1b3d..ba0f0ca9f280 100644 --- a/arch/x86/kernel/pci-gart_64.c +++ b/arch/x86/kernel/pci-gart_64.c | |||
@@ -41,6 +41,7 @@ | |||
41 | #include <asm/dma.h> | 41 | #include <asm/dma.h> |
42 | #include <asm/amd_nb.h> | 42 | #include <asm/amd_nb.h> |
43 | #include <asm/x86_init.h> | 43 | #include <asm/x86_init.h> |
44 | #include <asm/iommu_table.h> | ||
44 | 45 | ||
45 | static unsigned long iommu_bus_base; /* GART remapping area (physical) */ | 46 | static unsigned long iommu_bus_base; /* GART remapping area (physical) */ |
46 | static unsigned long iommu_size; /* size of remapping area bytes */ | 47 | static unsigned long iommu_size; /* size of remapping area bytes */ |
@@ -905,3 +906,4 @@ void __init gart_parse_options(char *p) | |||
905 | } | 906 | } |
906 | } | 907 | } |
907 | } | 908 | } |
909 | IOMMU_INIT_POST(gart_iommu_hole_init); | ||
diff --git a/arch/x86/kernel/pci-iommu_table.c b/arch/x86/kernel/pci-iommu_table.c new file mode 100644 index 000000000000..55d745ec1181 --- /dev/null +++ b/arch/x86/kernel/pci-iommu_table.c | |||
@@ -0,0 +1,89 @@ | |||
1 | #include <linux/dma-mapping.h> | ||
2 | #include <asm/iommu_table.h> | ||
3 | #include <linux/string.h> | ||
4 | #include <linux/kallsyms.h> | ||
5 | |||
6 | |||
7 | #define DEBUG 1 | ||
8 | |||
9 | static struct iommu_table_entry * __init | ||
10 | find_dependents_of(struct iommu_table_entry *start, | ||
11 | struct iommu_table_entry *finish, | ||
12 | struct iommu_table_entry *q) | ||
13 | { | ||
14 | struct iommu_table_entry *p; | ||
15 | |||
16 | if (!q) | ||
17 | return NULL; | ||
18 | |||
19 | for (p = start; p < finish; p++) | ||
20 | if (p->detect == q->depend) | ||
21 | return p; | ||
22 | |||
23 | return NULL; | ||
24 | } | ||
25 | |||
26 | |||
27 | void __init sort_iommu_table(struct iommu_table_entry *start, | ||
28 | struct iommu_table_entry *finish) { | ||
29 | |||
30 | struct iommu_table_entry *p, *q, tmp; | ||
31 | |||
32 | for (p = start; p < finish; p++) { | ||
33 | again: | ||
34 | q = find_dependents_of(start, finish, p); | ||
35 | /* We are bit sneaky here. We use the memory address to figure | ||
36 | * out if the node we depend on is past our point, if so, swap. | ||
37 | */ | ||
38 | if (q > p) { | ||
39 | tmp = *p; | ||
40 | memmove(p, q, sizeof(*p)); | ||
41 | *q = tmp; | ||
42 | goto again; | ||
43 | } | ||
44 | } | ||
45 | |||
46 | } | ||
47 | |||
48 | #ifdef DEBUG | ||
49 | void __init check_iommu_entries(struct iommu_table_entry *start, | ||
50 | struct iommu_table_entry *finish) | ||
51 | { | ||
52 | struct iommu_table_entry *p, *q, *x; | ||
53 | char sym_p[KSYM_SYMBOL_LEN]; | ||
54 | char sym_q[KSYM_SYMBOL_LEN]; | ||
55 | |||
56 | /* Simple cyclic dependency checker. */ | ||
57 | for (p = start; p < finish; p++) { | ||
58 | q = find_dependents_of(start, finish, p); | ||
59 | x = find_dependents_of(start, finish, q); | ||
60 | if (p == x) { | ||
61 | sprint_symbol(sym_p, (unsigned long)p->detect); | ||
62 | sprint_symbol(sym_q, (unsigned long)q->detect); | ||
63 | |||
64 | printk(KERN_ERR "CYCLIC DEPENDENCY FOUND! %s depends" \ | ||
65 | " on %s and vice-versa. BREAKING IT.\n", | ||
66 | sym_p, sym_q); | ||
67 | /* Heavy handed way..*/ | ||
68 | x->depend = 0; | ||
69 | } | ||
70 | } | ||
71 | |||
72 | for (p = start; p < finish; p++) { | ||
73 | q = find_dependents_of(p, finish, p); | ||
74 | if (q && q > p) { | ||
75 | sprint_symbol(sym_p, (unsigned long)p->detect); | ||
76 | sprint_symbol(sym_q, (unsigned long)q->detect); | ||
77 | |||
78 | printk(KERN_ERR "EXECUTION ORDER INVALID! %s "\ | ||
79 | "should be called before %s!\n", | ||
80 | sym_p, sym_q); | ||
81 | } | ||
82 | } | ||
83 | } | ||
84 | #else | ||
85 | inline void check_iommu_entries(struct iommu_table_entry *start, | ||
86 | struct iommu_table_entry *finish) | ||
87 | { | ||
88 | } | ||
89 | #endif | ||
diff --git a/arch/x86/kernel/pci-swiotlb.c b/arch/x86/kernel/pci-swiotlb.c index a5bc528d4328..8f972cbddef0 100644 --- a/arch/x86/kernel/pci-swiotlb.c +++ b/arch/x86/kernel/pci-swiotlb.c | |||
@@ -10,7 +10,8 @@ | |||
10 | #include <asm/iommu.h> | 10 | #include <asm/iommu.h> |
11 | #include <asm/swiotlb.h> | 11 | #include <asm/swiotlb.h> |
12 | #include <asm/dma.h> | 12 | #include <asm/dma.h> |
13 | 13 | #include <asm/xen/swiotlb-xen.h> | |
14 | #include <asm/iommu_table.h> | ||
14 | int swiotlb __read_mostly; | 15 | int swiotlb __read_mostly; |
15 | 16 | ||
16 | static void *x86_swiotlb_alloc_coherent(struct device *hwdev, size_t size, | 17 | static void *x86_swiotlb_alloc_coherent(struct device *hwdev, size_t size, |
@@ -41,25 +42,42 @@ static struct dma_map_ops swiotlb_dma_ops = { | |||
41 | }; | 42 | }; |
42 | 43 | ||
43 | /* | 44 | /* |
44 | * pci_swiotlb_detect - set swiotlb to 1 if necessary | 45 | * pci_swiotlb_detect_override - set swiotlb to 1 if necessary |
45 | * | 46 | * |
46 | * This returns non-zero if we are forced to use swiotlb (by the boot | 47 | * This returns non-zero if we are forced to use swiotlb (by the boot |
47 | * option). | 48 | * option). |
48 | */ | 49 | */ |
49 | int __init pci_swiotlb_detect(void) | 50 | int __init pci_swiotlb_detect_override(void) |
50 | { | 51 | { |
51 | int use_swiotlb = swiotlb | swiotlb_force; | 52 | int use_swiotlb = swiotlb | swiotlb_force; |
52 | 53 | ||
54 | if (swiotlb_force) | ||
55 | swiotlb = 1; | ||
56 | |||
57 | return use_swiotlb; | ||
58 | } | ||
59 | IOMMU_INIT_FINISH(pci_swiotlb_detect_override, | ||
60 | pci_xen_swiotlb_detect, | ||
61 | pci_swiotlb_init, | ||
62 | pci_swiotlb_late_init); | ||
63 | |||
64 | /* | ||
65 | * if 4GB or more detected (and iommu=off not set) return 1 | ||
66 | * and set swiotlb to 1. | ||
67 | */ | ||
68 | int __init pci_swiotlb_detect_4gb(void) | ||
69 | { | ||
53 | /* don't initialize swiotlb if iommu=off (no_iommu=1) */ | 70 | /* don't initialize swiotlb if iommu=off (no_iommu=1) */ |
54 | #ifdef CONFIG_X86_64 | 71 | #ifdef CONFIG_X86_64 |
55 | if (!no_iommu && max_pfn > MAX_DMA32_PFN) | 72 | if (!no_iommu && max_pfn > MAX_DMA32_PFN) |
56 | swiotlb = 1; | 73 | swiotlb = 1; |
57 | #endif | 74 | #endif |
58 | if (swiotlb_force) | 75 | return swiotlb; |
59 | swiotlb = 1; | ||
60 | |||
61 | return use_swiotlb; | ||
62 | } | 76 | } |
77 | IOMMU_INIT(pci_swiotlb_detect_4gb, | ||
78 | pci_swiotlb_detect_override, | ||
79 | pci_swiotlb_init, | ||
80 | pci_swiotlb_late_init); | ||
63 | 81 | ||
64 | void __init pci_swiotlb_init(void) | 82 | void __init pci_swiotlb_init(void) |
65 | { | 83 | { |
@@ -68,3 +86,15 @@ void __init pci_swiotlb_init(void) | |||
68 | dma_ops = &swiotlb_dma_ops; | 86 | dma_ops = &swiotlb_dma_ops; |
69 | } | 87 | } |
70 | } | 88 | } |
89 | |||
90 | void __init pci_swiotlb_late_init(void) | ||
91 | { | ||
92 | /* An IOMMU turned us off. */ | ||
93 | if (!swiotlb) | ||
94 | swiotlb_free(); | ||
95 | else { | ||
96 | printk(KERN_INFO "PCI-DMA: " | ||
97 | "Using software bounce buffering for IO (SWIOTLB)\n"); | ||
98 | swiotlb_print_info(); | ||
99 | } | ||
100 | } | ||
diff --git a/arch/x86/kernel/vmlinux.lds.S b/arch/x86/kernel/vmlinux.lds.S index d0bb52296fa3..38e2b67807e1 100644 --- a/arch/x86/kernel/vmlinux.lds.S +++ b/arch/x86/kernel/vmlinux.lds.S | |||
@@ -242,6 +242,12 @@ SECTIONS | |||
242 | __x86_cpu_dev_end = .; | 242 | __x86_cpu_dev_end = .; |
243 | } | 243 | } |
244 | 244 | ||
245 | /* | ||
246 | * start address and size of operations which during runtime | ||
247 | * can be patched with virtualization friendly instructions or | ||
248 | * baremetal native ones. Think page table operations. | ||
249 | * Details in paravirt_types.h | ||
250 | */ | ||
245 | . = ALIGN(8); | 251 | . = ALIGN(8); |
246 | .parainstructions : AT(ADDR(.parainstructions) - LOAD_OFFSET) { | 252 | .parainstructions : AT(ADDR(.parainstructions) - LOAD_OFFSET) { |
247 | __parainstructions = .; | 253 | __parainstructions = .; |
@@ -249,6 +255,11 @@ SECTIONS | |||
249 | __parainstructions_end = .; | 255 | __parainstructions_end = .; |
250 | } | 256 | } |
251 | 257 | ||
258 | /* | ||
259 | * struct alt_inst entries. From the header (alternative.h): | ||
260 | * "Alternative instructions for different CPU types or capabilities" | ||
261 | * Think locking instructions on spinlocks. | ||
262 | */ | ||
252 | . = ALIGN(8); | 263 | . = ALIGN(8); |
253 | .altinstructions : AT(ADDR(.altinstructions) - LOAD_OFFSET) { | 264 | .altinstructions : AT(ADDR(.altinstructions) - LOAD_OFFSET) { |
254 | __alt_instructions = .; | 265 | __alt_instructions = .; |
@@ -256,11 +267,28 @@ SECTIONS | |||
256 | __alt_instructions_end = .; | 267 | __alt_instructions_end = .; |
257 | } | 268 | } |
258 | 269 | ||
270 | /* | ||
271 | * And here are the replacement instructions. The linker sticks | ||
272 | * them as binary blobs. The .altinstructions has enough data to | ||
273 | * get the address and the length of them to patch the kernel safely. | ||
274 | */ | ||
259 | .altinstr_replacement : AT(ADDR(.altinstr_replacement) - LOAD_OFFSET) { | 275 | .altinstr_replacement : AT(ADDR(.altinstr_replacement) - LOAD_OFFSET) { |
260 | *(.altinstr_replacement) | 276 | *(.altinstr_replacement) |
261 | } | 277 | } |
262 | 278 | ||
263 | /* | 279 | /* |
280 | * struct iommu_table_entry entries are injected in this section. | ||
281 | * It is an array of IOMMUs which during run time gets sorted depending | ||
282 | * on its dependency order. After rootfs_initcall is complete | ||
283 | * this section can be safely removed. | ||
284 | */ | ||
285 | .iommu_table : AT(ADDR(.iommu_table) - LOAD_OFFSET) { | ||
286 | __iommu_table = .; | ||
287 | *(.iommu_table) | ||
288 | __iommu_table_end = .; | ||
289 | } | ||
290 | . = ALIGN(8); | ||
291 | /* | ||
264 | * .exit.text is discard at runtime, not link time, to deal with | 292 | * .exit.text is discard at runtime, not link time, to deal with |
265 | * references from .altinstructions and .eh_frame | 293 | * references from .altinstructions and .eh_frame |
266 | */ | 294 | */ |
diff --git a/arch/x86/xen/pci-swiotlb-xen.c b/arch/x86/xen/pci-swiotlb-xen.c index a013ec9d0c54..22471001b74c 100644 --- a/arch/x86/xen/pci-swiotlb-xen.c +++ b/arch/x86/xen/pci-swiotlb-xen.c | |||
@@ -5,6 +5,7 @@ | |||
5 | 5 | ||
6 | #include <asm/xen/hypervisor.h> | 6 | #include <asm/xen/hypervisor.h> |
7 | #include <xen/xen.h> | 7 | #include <xen/xen.h> |
8 | #include <asm/iommu_table.h> | ||
8 | 9 | ||
9 | int xen_swiotlb __read_mostly; | 10 | int xen_swiotlb __read_mostly; |
10 | 11 | ||
@@ -56,3 +57,7 @@ void __init pci_xen_swiotlb_init(void) | |||
56 | dma_ops = &xen_swiotlb_dma_ops; | 57 | dma_ops = &xen_swiotlb_dma_ops; |
57 | } | 58 | } |
58 | } | 59 | } |
60 | IOMMU_INIT_FINISH(pci_xen_swiotlb_detect, | ||
61 | 0, | ||
62 | pci_xen_swiotlb_init, | ||
63 | 0); | ||
diff --git a/drivers/pci/dmar.c b/drivers/pci/dmar.c index 3de3a436a432..0157708d474d 100644 --- a/drivers/pci/dmar.c +++ b/drivers/pci/dmar.c | |||
@@ -36,6 +36,7 @@ | |||
36 | #include <linux/tboot.h> | 36 | #include <linux/tboot.h> |
37 | #include <linux/dmi.h> | 37 | #include <linux/dmi.h> |
38 | #include <linux/slab.h> | 38 | #include <linux/slab.h> |
39 | #include <asm/iommu_table.h> | ||
39 | 40 | ||
40 | #define PREFIX "DMAR: " | 41 | #define PREFIX "DMAR: " |
41 | 42 | ||
@@ -687,7 +688,7 @@ failed: | |||
687 | return 0; | 688 | return 0; |
688 | } | 689 | } |
689 | 690 | ||
690 | void __init detect_intel_iommu(void) | 691 | int __init detect_intel_iommu(void) |
691 | { | 692 | { |
692 | int ret; | 693 | int ret; |
693 | 694 | ||
@@ -723,6 +724,8 @@ void __init detect_intel_iommu(void) | |||
723 | } | 724 | } |
724 | early_acpi_os_unmap_memory(dmar_tbl, dmar_tbl_size); | 725 | early_acpi_os_unmap_memory(dmar_tbl, dmar_tbl_size); |
725 | dmar_tbl = NULL; | 726 | dmar_tbl = NULL; |
727 | |||
728 | return ret ? 1 : -ENODEV; | ||
726 | } | 729 | } |
727 | 730 | ||
728 | 731 | ||
@@ -1455,3 +1458,4 @@ int __init dmar_ir_support(void) | |||
1455 | return 0; | 1458 | return 0; |
1456 | return dmar->flags & 0x1; | 1459 | return dmar->flags & 0x1; |
1457 | } | 1460 | } |
1461 | IOMMU_INIT_POST(detect_intel_iommu); | ||
diff --git a/include/linux/dmar.h b/include/linux/dmar.h index 51651b76d40f..a7d9dc21391d 100644 --- a/include/linux/dmar.h +++ b/include/linux/dmar.h | |||
@@ -57,15 +57,15 @@ extern int dmar_table_init(void); | |||
57 | extern int dmar_dev_scope_init(void); | 57 | extern int dmar_dev_scope_init(void); |
58 | 58 | ||
59 | /* Intel IOMMU detection */ | 59 | /* Intel IOMMU detection */ |
60 | extern void detect_intel_iommu(void); | 60 | extern int detect_intel_iommu(void); |
61 | extern int enable_drhd_fault_handling(void); | 61 | extern int enable_drhd_fault_handling(void); |
62 | 62 | ||
63 | extern int parse_ioapics_under_ir(void); | 63 | extern int parse_ioapics_under_ir(void); |
64 | extern int alloc_iommu(struct dmar_drhd_unit *); | 64 | extern int alloc_iommu(struct dmar_drhd_unit *); |
65 | #else | 65 | #else |
66 | static inline void detect_intel_iommu(void) | 66 | static inline int detect_intel_iommu(void) |
67 | { | 67 | { |
68 | return; | 68 | return -ENODEV; |
69 | } | 69 | } |
70 | 70 | ||
71 | static inline int dmar_table_init(void) | 71 | static inline int dmar_table_init(void) |