[PATCH] x86_64: Try harder to allocate memory in pci_alloc_consistent()

Linux Kernel Mailing List <[email protected]> Tue, 24 May 2005 13:47:16 +0000
Newsgroups gmane.linux.kernel.commits.2-4
Message-ID <[email protected]>
ChangeSet 1.1562, 2005/05/24 10:47:16-03:00, [email protected]

	[PATCH] x86_64: Try harder to allocate memory in pci_alloc_consistent()
	
	Try harder to allocate memory in pci_alloc_consistent()
	
	First try to allocate without GFP_DMA and see if we were lucky
	and the memory fits into the requested physical range. Only
	if that fails fall back to swiotlb. This makes pci_alloc_consistent
	more reliable, especially on systems without hardware IOMMU
	(Intel systems)
	
	Increase the default swiotlb window size to 64MB.
	
	Cc: [email protected]
	Cc: [email protected]
	Signed-off-by: Suresh Siddha <[email protected]>



 ia64/lib/swiotlb.c       |    4 ++--
 x86_64/kernel/pci-gart.c |   28 ++++++++++++++++++++++++++--
 2 files changed, 28 insertions(+), 4 deletions(-)


diff -Nru a/arch/ia64/lib/swiotlb.c b/arch/ia64/lib/swiotlb.c
--- a/arch/ia64/lib/swiotlb.c	2005-05-24 14:07:31 -07:00
+++ b/arch/ia64/lib/swiotlb.c	2005-05-24 14:07:31 -07:00
@@ -50,13 +50,13 @@
  * Used to do a quick range check in swiotlb_unmap_single and swiotlb_sync_single, to see
  * if the memory was in fact allocated by this API.
  */
-static char *io_tlb_start, *io_tlb_end;
+char *io_tlb_start, *io_tlb_end;
 
 /*
  * The number of IO TLB blocks (in groups of 64) betweeen io_tlb_start and io_tlb_end.
  * This is command line adjustable via setup_io_tlb_npages.
  */
-static unsigned long io_tlb_nslabs = 1024;
+static unsigned long io_tlb_nslabs = 32768;
 
 /*
  * This is a free list describing the number of free entries available from each index
diff -Nru a/arch/x86_64/kernel/pci-gart.c b/arch/x86_64/kernel/pci-gart.c
--- a/arch/x86_64/kernel/pci-gart.c	2005-05-24 14:07:31 -07:00
+++ b/arch/x86_64/kernel/pci-gart.c	2005-05-24 14:07:31 -07:00
@@ -155,7 +155,7 @@
 	int i;
 	unsigned long iommu_page;
 
-	if (hwdev == NULL || hwdev->dma_mask < 0xffffffff || no_iommu)
+	if (hwdev == NULL || hwdev->dma_mask < 0xffffffff || (no_iommu && !swiotlb))
 		gfp |= GFP_DMA;
 
 	/* 
@@ -174,6 +174,22 @@
 		if (force_mmu && !(gfp & GFP_DMA)) 
 			mmu = 1;
 		if (no_iommu) { 
+#ifdef CONFIG_SWIOTLB
+			if (swiotlb && high && hwdev) {
+				unsigned long dma_mask = 0;
+				if (hwdev->dma_mask == ~0UL) {
+					hwdev->dma_mask = 0xffffffff;
+					dma_mask = ~0UL;
+				}
+				*dma_handle = swiotlb_map_single(hwdev, memory, size,
+						   		 PCI_DMA_FROMDEVICE);
+				if (dma_mask)
+					hwdev->dma_mask = dma_mask;
+				memset(phys_to_virt(*dma_handle), 0, size); 
+				free_pages((unsigned long)memory, get_order(size));
+				return phys_to_virt(*dma_handle);
+			}
+#endif
 			if (high) goto error;
 			mmu = 0; 
 		} 	
@@ -218,8 +234,16 @@
 			 void *vaddr, dma_addr_t bus)
 {
 	unsigned long iommu_page;
-
+ 	extern  char *io_tlb_start, *io_tlb_end;
+ 
 	size = round_up(size, PAGE_SIZE); 
+#ifdef CONFIG_SWIOTLB
+ 	if (swiotlb && vaddr >= (void *)io_tlb_start &&
+ 	    vaddr < (void *)io_tlb_end) {
+ 		swiotlb_unmap_single (hwdev, bus, size, PCI_DMA_TODEVICE);
+ 		return;
+ 	}
+#endif
 	if (bus >= iommu_bus_base && bus < iommu_bus_base + iommu_size) { 
 		unsigned pages = size >> PAGE_SHIFT;
 		iommu_page = (bus - iommu_bus_base) >> PAGE_SHIFT;