patch-2.4.19 linux-2.4.19/arch/ia64/lib/swiotlb.c

Next file: linux-2.4.19/arch/ia64/mm/extable.c
Previous file: linux-2.4.19/arch/ia64/kernel/unwind_i.h
Back to the patch index
Back to the overall index

diff -urN linux-2.4.18/arch/ia64/lib/swiotlb.c linux-2.4.19/arch/ia64/lib/swiotlb.c
@@ -27,11 +27,21 @@
 #define ALIGN(val, align) ((unsigned long)	\
 	(((unsigned long) (val) + ((align) - 1)) & ~((align) - 1)))
 
+#define OFFSET(val,align) ((unsigned long)	\
+	                   ( (val) & ( (align) - 1)))
+
 #define SG_ENT_VIRT_ADDRESS(sg)	((sg)->address ? (sg)->address			\
 				 : page_address((sg)->page) + (sg)->offset)
 #define SG_ENT_PHYS_ADDRESS(SG)	virt_to_phys(SG_ENT_VIRT_ADDRESS(SG))
 
 /*
+ * Maximum allowable number of contiguous slabs to map,
+ * must be a power of 2.  What is the appropriate value ?
+ * The complexity of {map,unmap}_single is linearly dependent on this value.
+ */
+#define IO_TLB_SEGSIZE	128
+
+/*
  * log of the size of each IO TLB slab.  The number of slabs is command line controllable.
  */
 #define IO_TLB_SHIFT 11
@@ -69,10 +79,15 @@
 setup_io_tlb_npages (char *str)
 {
 	io_tlb_nslabs = simple_strtoul(str, NULL, 0) << (PAGE_SHIFT - IO_TLB_SHIFT);
+
+	/* avoid tail segment of size < IO_TLB_SEGSIZE */
+	io_tlb_nslabs = ALIGN(io_tlb_nslabs, IO_TLB_SEGSIZE);
+
 	return 1;
 }
 __setup("swiotlb=", setup_io_tlb_npages);
 
+
 /*
  * Statically reserve bounce buffer space and initialize bounce buffer data structures for
  * the software IO TLB used to implement the PCI DMA API.
@@ -92,12 +107,12 @@
 
 	/*
 	 * Allocate and initialize the free list array.  This array is used
-	 * to find contiguous free memory regions of size 2^IO_TLB_SHIFT between
-	 * io_tlb_start and io_tlb_end.
+	 * to find contiguous free memory regions of size up to IO_TLB_SEGSIZE
+	 * between io_tlb_start and io_tlb_end.
 	 */
 	io_tlb_list = alloc_bootmem(io_tlb_nslabs * sizeof(int));
 	for (i = 0; i < io_tlb_nslabs; i++)
-		io_tlb_list[i] = io_tlb_nslabs - i;
+ 		io_tlb_list[i] = IO_TLB_SEGSIZE - OFFSET(i, IO_TLB_SEGSIZE);
 	io_tlb_index = 0;
 	io_tlb_orig_addr = alloc_bootmem(io_tlb_nslabs * sizeof(char *));
 
@@ -124,7 +139,7 @@
 	if (size > (1 << PAGE_SHIFT))
 		stride = (1 << (PAGE_SHIFT - IO_TLB_SHIFT));
 	else
-		stride = nslots;
+		stride = 1;
 
 	if (!nslots)
 		BUG();
@@ -151,7 +166,8 @@
 
 				for (i = index; i < index + nslots; i++)
 					io_tlb_list[i] = 0;
-				for (i = index - 1; (i >= 0) && io_tlb_list[i]; i--)
+				for (i = index - 1; (OFFSET(i, IO_TLB_SEGSIZE) != IO_TLB_SEGSIZE -1)
+				       && io_tlb_list[i]; i--)
 					io_tlb_list[i] = ++count;
 				dma_addr = io_tlb_start + (index << IO_TLB_SHIFT);
 
@@ -217,7 +233,8 @@
 	 */
 	spin_lock_irqsave(&io_tlb_lock, flags);
 	{
-		int count = ((index + nslots) < io_tlb_nslabs ? io_tlb_list[index + nslots] : 0);
+		int count = ((index + nslots) < ALIGN(index + 1, IO_TLB_SEGSIZE) ?
+			     io_tlb_list[index + nslots] : 0);
 		/*
 		 * Step 1: return the slots to the free list, merging the slots with
 		 * superceeding slots
@@ -228,7 +245,8 @@
 		 * Step 2: merge the returned slots with the preceeding slots, if
 		 * available (non zero)
 		 */
-		for (i = index - 1; (i >= 0) && io_tlb_list[i]; i--)
+		for (i = index - 1;  (OFFSET(i, IO_TLB_SEGSIZE) != IO_TLB_SEGSIZE -1) &&
+		       io_tlb_list[i]; i--)
 			io_tlb_list[i] = ++count;
 	}
 	spin_unlock_irqrestore(&io_tlb_lock, flags);
@@ -405,11 +423,13 @@
 	for (i = 0; i < nelems; i++, sg++) {
 		sg->orig_address = SG_ENT_VIRT_ADDRESS(sg);
 		if ((SG_ENT_PHYS_ADDRESS(sg) & ~hwdev->dma_mask) != 0) {
-			addr = map_single(hwdev, sg->address, sg->length, direction);
+			addr = map_single(hwdev, sg->orig_address, sg->length, direction);
 			if (sg->address)
 				sg->address = addr;
-			else
+			else {
 				sg->page = virt_to_page(addr);
+				sg->offset = (u64) addr & ~PAGE_MASK;
+			}
 		}
 	}
 	return nelems;
@@ -432,10 +452,12 @@
 			unmap_single(hwdev, SG_ENT_VIRT_ADDRESS(sg), sg->length, direction);
 			if (sg->address)
 				sg->address = sg->orig_address;
-			else
+			else {
 				sg->page = virt_to_page(sg->orig_address);
+				sg->offset = (u64) sg->orig_address & ~PAGE_MASK;
+			}
 		} else if (direction == PCI_DMA_FROMDEVICE)
-			mark_clean(sg->address, sg->length);
+			mark_clean(SG_ENT_VIRT_ADDRESS(sg), sg->length);
 }
 
 /*

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)