aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/kernel/pci-calgary_64.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-calgary_64.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-calgary_64.c')
-rw-r--r--arch/x86/kernel/pci-calgary_64.c10
1 files changed, 1 insertions, 9 deletions
diff --git a/arch/x86/kernel/pci-calgary_64.c b/arch/x86/kernel/pci-calgary_64.c
index 47bd419ea4d2..833f491440b9 100644
--- a/arch/x86/kernel/pci-calgary_64.c
+++ b/arch/x86/kernel/pci-calgary_64.c
@@ -1360,7 +1360,7 @@ void __init detect_calgary(void)
1360 * if the user specified iommu=off or iommu=soft or we found 1360 * if the user specified iommu=off or iommu=soft or we found
1361 * another HW IOMMU already, bail out. 1361 * another HW IOMMU already, bail out.
1362 */ 1362 */
1363 if (swiotlb || no_iommu || iommu_detected) 1363 if (no_iommu || iommu_detected)
1364 return; 1364 return;
1365 1365
1366 if (!use_calgary) 1366 if (!use_calgary)
@@ -1445,10 +1445,6 @@ void __init detect_calgary(void)
1445 printk(KERN_INFO "PCI-DMA: Calgary TCE table spec is %d\n", 1445 printk(KERN_INFO "PCI-DMA: Calgary TCE table spec is %d\n",
1446 specified_table_size); 1446 specified_table_size);
1447 1447
1448 /* swiotlb for devices that aren't behind the Calgary. */
1449 if (max_pfn > MAX_DMA32_PFN)
1450 swiotlb = 1;
1451
1452 x86_init.iommu.iommu_init = calgary_iommu_init; 1448 x86_init.iommu.iommu_init = calgary_iommu_init;
1453 } 1449 }
1454 return; 1450 return;
@@ -1476,11 +1472,7 @@ int __init calgary_iommu_init(void)
1476 return ret; 1472 return ret;
1477 } 1473 }
1478 1474
1479 force_iommu = 1;
1480 bad_dma_address = 0x0; 1475 bad_dma_address = 0x0;
1481 /* dma_ops is set to swiotlb or nommu */
1482 if (!dma_ops)
1483 dma_ops = &nommu_dma_ops;
1484 1476
1485 return 0; 1477 return 0;
1486} 1478}