aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorFUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp>2009-12-15 06:47:56 -0500
committerIngo Molnar <mingo@elte.hu>2009-12-15 07:01:57 -0500
commit186a25026c44d1bfa97671110ff14dcd0c99678e (patch)
tree363fa110d9f4a785abf26cd9979dd60c0ed92a99 /arch
parent873b5271f878a11729fb4602c6ce967d0ff81119 (diff)
x86: Split swiotlb initialization into two stages
The commit f4780ca005404166cc40af77ef0e86132ab98a81 moves swiotlb initialization before dma32_free_bootmem(). It's supposed to fix a bug that the commit 75f1cdf1dda92cae037ec848ae63690d91913eac introduced, we initialize SWIOTLB right after dma32_free_bootmem so we wrongly steal memory area allocated for GART with broken BIOS earlier. However, the above commit introduced another problem, which likely breaks machines with huge amount of memory. Such a box use the majority of DMA32_ZONE so there is no memory for swiotlb. With this patch, the x86 IOMMU initialization sequence are: 1. We set swiotlb to 1 in the case of (max_pfn > MAX_DMA32_PFN && !no_iommu). If swiotlb usage is forced by the boot option, we go to the step 3 and finish (we don't try to detect IOMMUs). 2. We call the detection functions of all the IOMMUs. The detection function sets x86_init.iommu.iommu_init to the IOMMU initialization function (so we can avoid calling the initialization functions of all the IOMMUs needlessly). 3. We initialize swiotlb (and set dma_ops to swiotlb_dma_ops) if swiotlb is set to 1. 4. If the IOMMU initialization function doesn't need swiotlb (e.g. the initialization is sucessful) then sets swiotlb to zero. 5. If we find that swiotlb is set to zero, we free swiotlb resource. Reported-by: Yinghai Lu <yinghai@kernel.org> Reported-by: Roland Dreier <rdreier@cisco.com> Signed-off-by: FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp> LKML-Reference: <20091215204729A.fujita.tomonori@lab.ntt.co.jp> Tested-by: Yinghai Lu <yinghai@kernel.org> Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'arch')
-rw-r--r--arch/x86/include/asm/swiotlb.h8
-rw-r--r--arch/x86/kernel/pci-dma.c9
-rw-r--r--arch/x86/kernel/pci-swiotlb.c11
3 files changed, 17 insertions, 11 deletions
diff --git a/arch/x86/include/asm/swiotlb.h b/arch/x86/include/asm/swiotlb.h
index 87ffcb12a1b8..8085277e1b8b 100644
--- a/arch/x86/include/asm/swiotlb.h
+++ b/arch/x86/include/asm/swiotlb.h
@@ -5,13 +5,17 @@
5 5
6#ifdef CONFIG_SWIOTLB 6#ifdef CONFIG_SWIOTLB
7extern int swiotlb; 7extern int swiotlb;
8extern int pci_swiotlb_init(void); 8extern int __init pci_swiotlb_detect(void);
9extern void __init pci_swiotlb_init(void);
9#else 10#else
10#define swiotlb 0 11#define swiotlb 0
11static inline int pci_swiotlb_init(void) 12static inline int pci_swiotlb_detect(void)
12{ 13{
13 return 0; 14 return 0;
14} 15}
16static inline void pci_swiotlb_init(void)
17{
18}
15#endif 19#endif
16 20
17static inline void dma_mark_clean(void *addr, size_t size) {} 21static inline void dma_mark_clean(void *addr, size_t size) {}
diff --git a/arch/x86/kernel/pci-dma.c b/arch/x86/kernel/pci-dma.c
index fcc2f2bfa39c..75e14e21f61a 100644
--- a/arch/x86/kernel/pci-dma.c
+++ b/arch/x86/kernel/pci-dma.c
@@ -120,15 +120,12 @@ static void __init dma32_free_bootmem(void)
120 120
121void __init pci_iommu_alloc(void) 121void __init pci_iommu_alloc(void)
122{ 122{
123 int use_swiotlb;
124
125 use_swiotlb = pci_swiotlb_init();
126#ifdef CONFIG_X86_64 123#ifdef CONFIG_X86_64
127 /* free the range so iommu could get some range less than 4G */ 124 /* free the range so iommu could get some range less than 4G */
128 dma32_free_bootmem(); 125 dma32_free_bootmem();
129#endif 126#endif
130 if (use_swiotlb) 127 if (pci_swiotlb_detect())
131 return; 128 goto out;
132 129
133 gart_iommu_hole_init(); 130 gart_iommu_hole_init();
134 131
@@ -138,6 +135,8 @@ void __init pci_iommu_alloc(void)
138 135
139 /* needs to be called after gart_iommu_hole_init */ 136 /* needs to be called after gart_iommu_hole_init */
140 amd_iommu_detect(); 137 amd_iommu_detect();
138out:
139 pci_swiotlb_init();
141} 140}
142 141
143void *dma_generic_alloc_coherent(struct device *dev, size_t size, 142void *dma_generic_alloc_coherent(struct device *dev, size_t size,
diff --git a/arch/x86/kernel/pci-swiotlb.c b/arch/x86/kernel/pci-swiotlb.c
index e3c0a66b9e77..7d2829dde20e 100644
--- a/arch/x86/kernel/pci-swiotlb.c
+++ b/arch/x86/kernel/pci-swiotlb.c
@@ -43,12 +43,12 @@ static struct dma_map_ops swiotlb_dma_ops = {
43}; 43};
44 44
45/* 45/*
46 * pci_swiotlb_init - initialize swiotlb if necessary 46 * pci_swiotlb_detect - set swiotlb to 1 if necessary
47 * 47 *
48 * This returns non-zero if we are forced to use swiotlb (by the boot 48 * This returns non-zero if we are forced to use swiotlb (by the boot
49 * option). 49 * option).
50 */ 50 */
51int __init pci_swiotlb_init(void) 51int __init pci_swiotlb_detect(void)
52{ 52{
53 int use_swiotlb = swiotlb | swiotlb_force; 53 int use_swiotlb = swiotlb | swiotlb_force;
54 54
@@ -60,10 +60,13 @@ int __init pci_swiotlb_init(void)
60 if (swiotlb_force) 60 if (swiotlb_force)
61 swiotlb = 1; 61 swiotlb = 1;
62 62
63 return use_swiotlb;
64}
65
66void __init pci_swiotlb_init(void)
67{
63 if (swiotlb) { 68 if (swiotlb) {
64 swiotlb_init(0); 69 swiotlb_init(0);
65 dma_ops = &swiotlb_dma_ops; 70 dma_ops = &swiotlb_dma_ops;
66 } 71 }
67
68 return use_swiotlb;
69} 72}