Subject: [2.5 PATCH] pci.h cleanup and fixes

From: Vivien Chappelier <[email-masked]>
Date: Mon, 12 Aug 2002 02:17:51 +0200 (CEST)

Hi,

	This patch fixes the following things for pci.h:
	- flush cache only on non-coherent archs
	- fix usage of bus_to_baddr
	- fix DECLARE_PCI_UNMAP_ADDR, ... for non-coherent arch where
pci_unmap_* functions are not a empty.
	- change __pa, '+ PAGE_OFFSET' to virt_to_phys() and
phys_to_virt()
	- adds sg->offset to page_address(sg->page) when mapping a
scatter-gather buffer

	This is a patch against CVS HEAD (2.5.5)/mips64. It should apply
directly to 2.5.5/mips as well. As for 2.5.4 care should be taken with the
old 'sg->address' interface for scatter-gather buffers, but these fixes
should probably be applied as well.

Please comment and/or apply,
Vivien.

--- linux/include/asm-mips64/addrspace.h	Thu Aug  1 20:22:00 2002
+++ linux.patch/include/asm-mips64/addrspace.h	Thu Aug  1 20:21:54 2002
@@ -58,7 +58,7 @@
 
 #ifndef __ASSEMBLY__
 #define PHYSADDR(a) ({						\
-	const _ATYPE64_ _a = (a);				\
+	const _ATYPE64_ _a = _ACAST64_ (a);				\
 	_a == _ACAST32_ _a ? CPHYSADDR(_a) : XPHYSADDR(_a); })
 #endif
 
--- linux/include/asm-mips64/pci.h	Mon Aug 12 00:25:23 2002
+++ linux.patch/include/asm-mips64/pci.h	Mon Aug 12 00:19:27 2002
@@ -120,14 +120,20 @@
 static inline dma_addr_t pci_map_single(struct pci_dev *hwdev, void *ptr,
 					size_t size, int direction)
 {
+#ifdef CONFIG_NONCOHERENT_IO
 	unsigned long addr = (unsigned long) ptr;
+#endif
 
 	if (direction == PCI_DMA_NONE)
 		BUG();
 
+#ifdef CONFIG_NONCOHERENT_IO
+	/* even if DMAing from device, make sure there is no dirty entry */
+	/* in the cache that could be evicted during the DMA transfer    */
+	/* thus overwritting the device data */
 	dma_cache_wback_inv(addr, size);
-
-	return bus_to_baddr(hwdev->bus->number, __pa(ptr));
+#endif
+	return bus_to_baddr(hwdev, virt_to_phys(ptr));
 }
 
 /*
@@ -141,17 +147,37 @@
 static inline void pci_unmap_single(struct pci_dev *hwdev, dma_addr_t dma_addr,
 				    size_t size, int direction)
 {
+#ifdef CONFIG_NONCOHERENT_IO
+	unsigned long addr;
+#endif
+
 	if (direction == PCI_DMA_NONE)
 		BUG();
 
-	if (direction != PCI_DMA_TODEVICE) {
-		unsigned long addr;
+	if (direction == PCI_DMA_TODEVICE)
+		return; /* nothing to do */
 
-		addr = baddr_to_bus(hwdev, dma_addr) + PAGE_OFFSET;
-		dma_cache_wback_inv(addr, size);
-	}
+#ifdef CONFIG_NONCOHERENT_IO
+	addr = (unsigned long) phys_to_virt(baddr_to_bus(hwdev, dma_addr));
+	dma_cache_wback_inv(addr, size);
+#endif
 }
 
+#ifdef CONFIG_NONCOHERENT_IO
+/* pci_unmap_{single,page} is not a nop, thus... */
+#define DECLARE_PCI_UNMAP_ADDR(ADDR_NAME)	\
+	dma_addr_t ADDR_NAME;
+#define DECLARE_PCI_UNMAP_LEN(LEN_NAME)		\
+	__u32 LEN_NAME;
+#define pci_unmap_addr(PTR, ADDR_NAME)			\
+	((PTR)->ADDR_NAME)
+#define pci_unmap_addr_set(PTR, ADDR_NAME, VAL)		\
+	(((PTR)->ADDR_NAME) = (VAL))
+#define pci_unmap_len(PTR, LEN_NAME)			\
+	((PTR)->LEN_NAME)
+#define pci_unmap_len_set(PTR, LEN_NAME, VAL)		\
+	(((PTR)->LEN_NAME) = (VAL))
+#else
 /* pci_unmap_{page,single} is a nop so... */
 #define DECLARE_PCI_UNMAP_ADDR(ADDR_NAME)
 #define DECLARE_PCI_UNMAP_LEN(LEN_NAME)
@@ -159,6 +185,7 @@
 #define pci_unmap_addr_set(PTR, ADDR_NAME, VAL)	do { } while (0)
 #define pci_unmap_len(PTR, LEN_NAME)		(0)
 #define pci_unmap_len_set(PTR, LEN_NAME, VAL)	do { } while (0)
+#endif
 
 /*
  * pci_{map,unmap}_single_page maps a kernel page to a dma_addr_t. identical
@@ -168,13 +195,17 @@
 				      unsigned long offset, size_t size,
                                       int direction)
 {
+#ifdef CONFIG_NONCOHERENT_IO
 	unsigned long addr;
+#endif
 
 	if (direction == PCI_DMA_NONE)
 		BUG();
 
+#ifdef CONFIG_NONCOHERENT_IO
 	addr = (unsigned long) page_address(page) + offset;
 	dma_cache_wback_inv(addr, size);
+#endif
 
 	return bus_to_baddr(hwdev, page_to_phys(page) + offset);
 }
@@ -182,15 +213,20 @@
 static inline void pci_unmap_page(struct pci_dev *hwdev, dma_addr_t dma_address,
 				  size_t size, int direction)
 {
+#ifdef CONFIG_NONCOHERENT_IO
+	unsigned long addr;
+#endif
+
 	if (direction == PCI_DMA_NONE)
 		BUG();
 
-	if (direction != PCI_DMA_TODEVICE) {
-		unsigned long addr;
+	if (direction == PCI_DMA_TODEVICE)
+		return; /* nothing to do */
 
-		addr = baddr_to_bus(hwdev, dma_address) + PAGE_OFFSET;
-		dma_cache_wback_inv(addr, size);
-	}
+#ifdef CONFIG_NONCOHERENT_IO
+	addr = (unsigned long) phys_to_virt(baddr_to_bus(hwdev, dma_address));
+	dma_cache_wback_inv(addr, size);
+#endif
 }
 
 /*
@@ -212,21 +248,23 @@
 static inline int pci_map_sg(struct pci_dev *hwdev, struct scatterlist *sg,
 			     int nents, int direction)
 {
+#ifdef CONFIG_NONCOHERENT_IO
 	int i;
+#endif
 
 	if (direction == PCI_DMA_NONE)
 		BUG();
 
+#ifdef CONFIG_NONCOHERENT_IO
 	for (i = 0; i < nents; i++, sg++) {
 		unsigned long addr;
 
-		addr = (unsigned long) page_address(sg->page);
-		if (addr)
-			dma_cache_wback_inv(addr, sg->length);
+		addr = (unsigned long) page_address(sg->page) + sg->offset;
+		dma_cache_wback_inv(addr, sg->length);
 		sg->dma_address = (dma_addr_t) bus_to_baddr(hwdev,
 			page_to_phys(sg->page) + sg->offset);
 	}
-
+#endif
 	return nents;
 }
 
@@ -238,24 +276,27 @@
 static inline void pci_unmap_sg(struct pci_dev *hwdev, struct scatterlist *sg,
 				int nents, int direction)
 {
+#ifdef CONFIG_NONCOHERENT_IO
 	int i;
+#endif
 
 	if (direction == PCI_DMA_NONE)
 		BUG();
 
 	if (direction == PCI_DMA_TODEVICE)
-		return;
+		return; /* nothing to do */
 
+#ifdef CONFIG_NONCOHERENT_IO
 	for (i = 0; i < nents; i++, sg++) {
 		unsigned long addr;
 
 		if (!sg->page)
 			BUG();
 
-		addr = (unsigned long) page_address(sg->page);
-		if (addr)
-			dma_cache_wback_inv(addr + sg->offset, sg->length);
+		addr = (unsigned long) page_address(sg->page) + sg->offset;
+		dma_cache_wback_inv(addr, sg->length);
 	}
+#endif
 }
 
 /*
@@ -272,13 +313,17 @@
 				       dma_addr_t dma_handle,
 				       size_t size, int direction)
 {
+#ifdef CONFIG_NONCOHERENT_IO
 	unsigned long addr;
+#endif
 
 	if (direction == PCI_DMA_NONE)
 		BUG();
 
-	addr = baddr_to_bus(hwdev, dma_handle) + PAGE_OFFSET;
+#ifdef CONFIG_NONCOHERENT_IO
+	addr = (unsigned long) phys_to_virt(baddr_to_bus(hwdev, dma_handle));
 	dma_cache_wback_inv(addr, size);
+#endif
 }
 
 /*
@@ -301,9 +346,12 @@
 
 	/* Make sure that gcc doesn't leave the empty loop body.  */
 #ifdef CONFIG_NONCOHERENT_IO
-	for (i = 0; i < nelems; i++, sg++)
-		dma_cache_wback_inv((unsigned long)page_address(sg->page),
-		                    sg->length);
+	for (i = 0; i < nelems; i++, sg++) {
+		unsigned long addr;
+
+		addr = (unsigned long) page_address(sg->page) + sg->offset;
+		dma_cache_wback_inv(addr, sg->length);
+	}
 #endif
 }
 #endif /* CONFIG_MAPPED_PCI_IO  */
@@ -337,7 +385,7 @@
 {
 	dma64_addr_t addr = page_to_phys(page) + offset;
 
-	return (dma64_addr_t) bus_to_baddr(hwdev->bus->number, addr);
+	return (dma64_addr_t) bus_to_baddr(hwdev, addr);
 }
 
 static inline struct page *pci_dac_dma_to_page(struct pci_dev *pdev,
@@ -362,8 +410,10 @@
 	if (direction == PCI_DMA_NONE)
 		BUG();
 
-	addr = baddr_to_bus(hwdev->bus->number, dma_addr) + PAGE_OFFSET;
+	addr = (unsigned long) phys_to_virt(baddr_to_bus(hwdev, dma_addr));
+#ifdef CONFIG_NONCOHERENT_IO
 	dma_cache_wback_inv(addr, len);
+#endif
 }
 
 /*