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

Next file: linux/arch/ia64/mm/fault.c
Previous file: linux/arch/ia64/lib/strnlen_user.S
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.4.14/linux/arch/ia64/lib/swiotlb.c linux/arch/ia64/lib/swiotlb.c
@@ -27,6 +27,10 @@
 #define ALIGN(val, align) ((unsigned long)	\
 	(((unsigned long) (val) + ((align) - 1)) & ~((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))
+
 /*
  * log of the size of each IO TLB slab.  The number of slabs is command line controllable.
  */
@@ -392,15 +396,20 @@
 int
 swiotlb_map_sg (struct pci_dev *hwdev, struct scatterlist *sg, int nelems, int direction)
 {
+	void *addr;
 	int i;
 
 	if (direction == PCI_DMA_NONE)
 		BUG();
 
 	for (i = 0; i < nelems; i++, sg++) {
-		sg->orig_address = sg->address;
-		if ((virt_to_phys(sg->address) & ~hwdev->dma_mask) != 0) {
-			sg->address = map_single(hwdev, sg->address, sg->length, direction);
+		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);
+			if (sg->address)
+				sg->address = addr;
+			else
+				sg->page = virt_to_page(addr);
 		}
 	}
 	return nelems;
@@ -419,9 +428,12 @@
 		BUG();
 
 	for (i = 0; i < nelems; i++, sg++)
-		if (sg->orig_address != sg->address) {
-			unmap_single(hwdev, sg->address, sg->length, direction);
-			sg->address = sg->orig_address;
+		if (sg->orig_address != SG_ENT_VIRT_ADDRESS(sg)) {
+			unmap_single(hwdev, SG_ENT_VIRT_ADDRESS(sg), sg->length, direction);
+			if (sg->address)
+				sg->address = sg->orig_address;
+			else
+				sg->page = virt_to_page(sg->orig_address);
 		} else if (direction == PCI_DMA_FROMDEVICE)
 			mark_clean(sg->address, sg->length);
 }
@@ -442,14 +454,14 @@
 		BUG();
 
 	for (i = 0; i < nelems; i++, sg++)
-		if (sg->orig_address != sg->address)
-			sync_single(hwdev, sg->address, sg->length, direction);
+		if (sg->orig_address != SG_ENT_VIRT_ADDRESS(sg))
+			sync_single(hwdev, SG_ENT_VIRT_ADDRESS(sg), sg->length, direction);
 }
 
 unsigned long
 swiotlb_dma_address (struct scatterlist *sg)
 {
-	return virt_to_phys(sg->address);
+	return SG_ENT_PHYS_ADDRESS(sg);
 }
 
 EXPORT_SYMBOL(swiotlb_init);

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