aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/kernel/pci-dma.c
diff options
context:
space:
mode:
authorFUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp>2009-11-10 05:46:20 -0500
committerIngo Molnar <mingo@elte.hu>2009-11-10 06:32:07 -0500
commit75f1cdf1dda92cae037ec848ae63690d91913eac (patch)
tree9c12705002ebfa2d75333c20a19d0ac15f1db1d9 /arch/x86/kernel/pci-dma.c
parentad32e8cb86e7894aac51c8963eaa9f36bb8a4e14 (diff)
x86: Handle HW IOMMU initialization failure gracefully
If HW IOMMU initialization fails (Intel VT-d often does this, typically due to BIOS bugs), we fall back to nommu. It doesn't work for the majority since nowadays we have more than 4GB memory so we must use swiotlb instead of nommu. The problem is that it's too late to initialize swiotlb when HW IOMMU initialization fails. We need to allocate swiotlb memory earlier from bootmem allocator. Chris explained the issue in detail: http://marc.info/?l=linux-kernel&m=125657444317079&w=2 The current x86 IOMMU initialization sequence is too complicated and handling the above issue makes it more hacky. This patch changes x86 IOMMU initialization sequence to handle the above issue cleanly. The new x86 IOMMU initialization sequence are: 1. we initialize the swiotlb (and setting swiotlb to 1) in the case of (max_pfn > MAX_DMA32_PFN && !no_iommu). dma_ops is set to swiotlb_dma_ops or nommu_dma_ops. if swiotlb usage is forced by the boot option, we finish here. 2. we call the detection functions of all the IOMMUs 3. 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). 4. if the IOMMU initialization function doesn't need to swiotlb then sets swiotlb to zero (e.g. the initialization is sucessful). 5. if we find that swiotlb is set to zero, we free swiotlb resource. Signed-off-by: FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp> Cc: chrisw@sous-sol.org Cc: dwmw2@infradead.org Cc: joerg.roedel@amd.com Cc: muli@il.ibm.com LKML-Reference: <1257849980-22640-10-git-send-email-fujita.tomonori@lab.ntt.co.jp> Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'arch/x86/kernel/pci-dma.c')
-rw-r--r--arch/x86/kernel/pci-dma.c21
1 files changed, 13 insertions, 8 deletions
diff --git a/arch/x86/kernel/pci-dma.c b/arch/x86/kernel/pci-dma.c
index bed05e2e5890..a234e63c2656 100644
--- a/arch/x86/kernel/pci-dma.c
+++ b/arch/x86/kernel/pci-dma.c
@@ -124,24 +124,24 @@ static void __init dma32_free_bootmem(void)
124 124
125void __init pci_iommu_alloc(void) 125void __init pci_iommu_alloc(void)
126{ 126{
127 /* swiotlb is forced by the boot option */
128 int use_swiotlb = swiotlb;
127#ifdef CONFIG_X86_64 129#ifdef CONFIG_X86_64
128 /* free the range so iommu could get some range less than 4G */ 130 /* free the range so iommu could get some range less than 4G */
129 dma32_free_bootmem(); 131 dma32_free_bootmem();
130#endif 132#endif
133 pci_swiotlb_init();
134 if (use_swiotlb)
135 return;
131 136
132 /*
133 * The order of these functions is important for
134 * fall-back/fail-over reasons
135 */
136 gart_iommu_hole_init(); 137 gart_iommu_hole_init();
137 138
138 detect_calgary(); 139 detect_calgary();
139 140
140 detect_intel_iommu(); 141 detect_intel_iommu();
141 142
143 /* needs to be called after gart_iommu_hole_init */
142 amd_iommu_detect(); 144 amd_iommu_detect();
143
144 pci_swiotlb_init();
145} 145}
146 146
147void *dma_generic_alloc_coherent(struct device *dev, size_t size, 147void *dma_generic_alloc_coherent(struct device *dev, size_t size,
@@ -291,10 +291,15 @@ static int __init pci_iommu_init(void)
291#ifdef CONFIG_PCI 291#ifdef CONFIG_PCI
292 dma_debug_add_bus(&pci_bus_type); 292 dma_debug_add_bus(&pci_bus_type);
293#endif 293#endif
294
295 x86_init.iommu.iommu_init(); 294 x86_init.iommu.iommu_init();
296 295
297 no_iommu_init(); 296 if (swiotlb) {
297 printk(KERN_INFO "PCI-DMA: "
298 "Using software bounce buffering for IO (SWIOTLB)\n");
299 swiotlb_print_info();
300 } else
301 swiotlb_free();
302
298 return 0; 303 return 0;
299} 304}
300/* Must execute after PCI subsystem */ 305/* Must execute after PCI subsystem */