patch-2.4.25 linux-2.4.25/arch/ppc64/kernel/pci_dma.c

Next file: linux-2.4.25/arch/ppc64/kernel/perfmon.c
Previous file: linux-2.4.25/arch/ppc64/kernel/pSeries_pci.c
Back to the patch index
Back to the overall index

diff -urN linux-2.4.24/arch/ppc64/kernel/pci_dma.c linux-2.4.25/arch/ppc64/kernel/pci_dma.c
@@ -97,11 +97,8 @@
 			   unsigned order );
 
 /* allocates a range of tces and sets them to the pages  */
-static inline dma_addr_t get_tces( struct TceTable *, 
-				   unsigned order, 
-				   void *page, 
-				   unsigned numPages,
-				   int direction );
+dma_addr_t get_tces(struct TceTable *, unsigned order, void *page,
+		    unsigned numPages, int direction);
 
 static long test_tce_range( struct TceTable *, 
 			    long tcenum, 
@@ -219,7 +216,7 @@
  * Build a TceTable structure.  This contains a multi-level bit map which
  * is used to manage allocation of the tce space.
  */
-static struct TceTable *build_tce_table( struct TceTable * tbl )
+struct TceTable *build_tce_table(struct TceTable * tbl)
 {
 	unsigned long bits, bytes, totalBytes;
 	unsigned long numBits[NUM_TCE_LEVELS], numBytes[NUM_TCE_LEVELS];
@@ -527,7 +524,8 @@
 	return retval;
 }
 
-static inline dma_addr_t get_tces( struct TceTable *tbl, unsigned order, void *page, unsigned numPages, int direction )
+inline dma_addr_t get_tces(struct TceTable *tbl, unsigned order,
+			   void *page, unsigned numPages, int direction)
 {
 	long tcenum;
 	unsigned long uaddr;
@@ -537,8 +535,8 @@
 	uaddr = (unsigned long)page & PAGE_MASK;
 	
 	/* Allocate a range of tces */
-	tcenum = alloc_tce_range( tbl, order );
-	if ( tcenum != -1 ) {
+	tcenum = alloc_tce_range(tbl, order);
+	if (tcenum != -1) {
 		/* We got the tces we wanted */
 		tcenum += tbl->startOffset;	/* Offset into real TCE table */
 		retTce = tcenum << PAGE_SHIFT;	/* Set the return dma address */
@@ -553,9 +551,9 @@
 		   the TCE table with the MMIO that will send
 		   the bus address to the IOA */
 		__asm__ __volatile__ ("sync" : : : "memory");
-	}
-	else {
-		panic("PCI_DMA: Tce Allocation failure in get_tces. 0x%p\n",tbl);
+	} else {
+		panic("get_tces: TCE allocation failed. 0x%p 0x%x\n",
+		      tbl, order);
 	}
 
 	return retTce; 
@@ -586,8 +584,8 @@
 
 }
 
-static void tce_free(struct TceTable *tbl, dma_addr_t dma_addr, 
-			     unsigned order, unsigned num_pages)
+void tce_free(struct TceTable *tbl, dma_addr_t dma_addr,
+	      unsigned order, unsigned num_pages)
 {
 	long tcenum, total_tces, free_tce;
 	unsigned i;
@@ -1009,34 +1007,34 @@
 
  	/* Client asked for way to much space.  This is checked later anyway */
 	/* It is easier to debug here for the drivers than in the tce tables.*/
- 	if(order >= NUM_TCE_LEVELS) {
- 		printk("PCI_DMA: pci_alloc_consistent size to large: 0x%lx \n",size);
- 		return (void *)NO_TCE;
+ 	if (order >= NUM_TCE_LEVELS) {
+ 		printk("PCI_DMA: pci_alloc_consistent size too large: 0x%lx\n",
+		       size);
+ 		return (void *)NULL;
  	}
 
 	tbl = get_tce_table(hwdev); 
 
-	if ( tbl ) {
+	if (tbl) {
 		/* Alloc enough pages (and possibly more) */
 		ret = (void *)__get_free_pages( GFP_ATOMIC, order );
-		if ( ret ) {
+		if (ret) {
 			/* Page allocation succeeded */
 			memset(ret, 0, nPages << PAGE_SHIFT);
 			/* Set up tces to cover the allocated range */
 			tce = get_tces( tbl, order, ret, nPages, PCI_DMA_BIDIRECTIONAL );
-			if ( tce == NO_TCE ) {
-				PPCDBG(PPCDBG_TCE, "pci_alloc_consistent: get_tces failed\n" );
+			if (tce == NO_TCE) {
 				free_pages( (unsigned long)ret, order );
 				ret = NULL;
-			}
-			else
-			{
+			} else {
 				*dma_handle = tce;
 			}
+		} else {
+			printk("pci_alloc_consistent: __get_free_pages failed for order = %d\n", order);
 		}
-		else PPCDBG(PPCDBG_TCE, "pci_alloc_consistent: __get_free_pages failed for order = %d\n", order);
+	} else {
+		panic("pci_alloc_consistent: unable to find TCE table\n");
 	}
-	else PPCDBG(PPCDBG_TCE, "pci_alloc_consistent: get_tce_table failed for 0x%016lx\n", hwdev);
 
 	PPCDBG(PPCDBG_TCE, "\tpci_alloc_consistent: dma_handle = 0x%16.16lx\n", *dma_handle);	
 	PPCDBG(PPCDBG_TCE, "\tpci_alloc_consistent: return     = 0x%16.16lx\n", ret);	
@@ -1059,7 +1057,7 @@
  	/* Client asked for way to much space.  This is checked later anyway */
 	/* It is easier to debug here for the drivers than in the tce tables.*/
  	if(order >= NUM_TCE_LEVELS) {
- 		printk("PCI_DMA: pci_free_consistent size to large: 0x%lx \n",size);
+ 		printk("PCI_DMA: pci_free_consistent size too large: 0x%lx \n",size);
  		return;
  	}
 	
@@ -1087,7 +1085,7 @@
 
 	PPCDBG(PPCDBG_TCE, "pci_map_single:\n");
 	PPCDBG(PPCDBG_TCE, "\thwdev = 0x%16.16lx, size = 0x%16.16lx, direction = 0x%16.16lx, vaddr = 0x%16.16lx\n", hwdev, size, direction, vaddr);	
-	if ( direction == PCI_DMA_NONE )
+	if (direction == PCI_DMA_NONE)
 		BUG();
 	
 	uaddr = (unsigned long)vaddr;
@@ -1098,15 +1096,18 @@
  	/* Client asked for way to much space.  This is checked later anyway */
 	/* It is easier to debug here for the drivers than in the tce tables.*/
  	if(order >= NUM_TCE_LEVELS) {
- 		printk("PCI_DMA: pci_map_single size to large: 0x%lx \n",size);
- 		return NO_TCE;
+		panic("PCI_DMA: pci_map_single size too large: 0x%lx \n", size);
+		return dma_handle;
  	}
 
 	tbl = get_tce_table(hwdev); 
 
-	if ( tbl ) {
+	if (tbl) {
+		/* get_tces panics if there are no entries available */
 		dma_handle = get_tces( tbl, order, vaddr, nPages, direction );
 		dma_handle |= ( uaddr & ~PAGE_MASK );
+	} else {
+		panic("PCI_DMA: Unable to find TCE table.\n");
 	}
 
 	return dma_handle;
@@ -1129,7 +1130,7 @@
  	/* Client asked for way to much space.  This is checked later anyway */
 	/* It is easier to debug here for the drivers than in the tce tables.*/
  	if(order >= NUM_TCE_LEVELS) {
- 		printk("PCI_DMA: pci_unmap_single size to large: 0x%lx \n",size);
+ 		printk("PCI_DMA: pci_unmap_single size too large: 0x%lx \n",size);
  		return;
  	}
 	
@@ -1151,6 +1152,7 @@
 {
 	unsigned long nTces, numPages, startPage, endPage, prevEndPage;
 	unsigned i;
+	void *address;
 
 	prevEndPage = 0;
 	nTces = 0;
@@ -1159,8 +1161,10 @@
 		/* Compute the starting page number and
 		 * the ending page number for this entry
 		 */
-		startPage = (unsigned long)sg->address >> PAGE_SHIFT;
-		endPage = ((unsigned long)sg->address + sg->length - 1) >> PAGE_SHIFT;
+		address = sg->address ? sg->address :
+			(page_address(sg->page) + sg->offset);
+		startPage = (unsigned long)address >> PAGE_SHIFT;
+		endPage = ((unsigned long)address + sg->length - 1) >> PAGE_SHIFT;
 		numPages = endPage - startPage + 1;
 		/* Simple optimization: if the previous entry ended
 		 * in the same page in which this entry starts
@@ -1187,17 +1191,20 @@
 	u32 cur_start_dma;
 	unsigned long cur_len_dma, cur_end_virt, uaddr;
 	unsigned num_dma_ents;
+	void *address;
 
 	dma_sg = sg;
 	num_dma_ents = 1;
 
 	/* Process the first sg entry */
-	cur_start_dma = dma_addr + ((unsigned long)sg->address & (~PAGE_MASK));
+	address = sg->address ? sg->address :
+		(page_address(sg->page) + sg->offset);
+	cur_start_dma = dma_addr + ((unsigned long)address & (~PAGE_MASK));
 	cur_len_dma = sg->length;
 	/* cur_end_virt holds the address of the byte immediately after the
 	 * end of the current buffer.
 	 */
-	cur_end_virt = (unsigned long)sg->address + cur_len_dma;
+	cur_end_virt = (unsigned long)address + cur_len_dma;
 	/* Later code assumes that unused sg->dma_address and sg->dma_length
 	 * fields will be zero.  Other archs seem to assume that the user
 	 * (device driver) guarantees that...I don't want to depend on that
@@ -1222,7 +1229,9 @@
 		 * or if the previous entry ends at a page boundary
 		 * and the current entry starts at a page boundary.
 		 */
-		uaddr = (unsigned long)sg->address;
+		address = sg->address ? sg->address :
+			(page_address(sg->page) + sg->offset);
+		uaddr = (unsigned long)address;
 		if ( ( uaddr != cur_end_virt ) &&
 		     ( ( ( uaddr | cur_end_virt ) & (~PAGE_MASK) ) ||
 		       ( ( uaddr & PAGE_MASK ) == ( ( cur_end_virt-1 ) & PAGE_MASK ) ) ) ) {
@@ -1273,13 +1282,14 @@
 /* Call the hypervisor to create the TCE entries.
  * return the number of TCEs created
  */
-static dma_addr_t create_tces_sg( struct TceTable *tbl, struct scatterlist *sg, 
-		   int nents, unsigned numTces, int direction )
+static dma_addr_t create_tces_sg(struct TceTable *tbl, struct scatterlist *sg, 
+				 int nents, unsigned numTces, int direction)
 {
 	unsigned order, i, j;
 	unsigned long startPage, endPage, prevEndPage, numPages, uaddr;
 	long tcenum, starttcenum;
 	dma_addr_t dmaAddr;
+	void *address;
 
 	dmaAddr = NO_TCE;
 
@@ -1287,23 +1297,26 @@
  	/* Client asked for way to much space.  This is checked later anyway */
 	/* It is easier to debug here for the drivers than in the tce tables.*/
  	if(order >= NUM_TCE_LEVELS) {
-		printk("PCI_DMA: create_tces_sg size to large: 0x%x \n",(numTces << PAGE_SHIFT));
+		printk("PCI_DMA: create_tces_sg size too large: 0x%llx \n",(numTces << PAGE_SHIFT));
+		panic("numTces is off");
  		return NO_TCE;
  	}
 
 	/* allocate a block of tces */
-	tcenum = alloc_tce_range( tbl, order );
-	if ( tcenum != -1 ) {
+	tcenum = alloc_tce_range(tbl, order);
+	if (tcenum != -1) {
 		tcenum += tbl->startOffset;
 		starttcenum = tcenum;
 		dmaAddr = tcenum << PAGE_SHIFT;
 		prevEndPage = 0;
 		for (j=0; j<nents; ++j) {
-			startPage = (unsigned long)sg->address >> PAGE_SHIFT;
-			endPage = ((unsigned long)sg->address + sg->length - 1) >> PAGE_SHIFT;
+			address = sg->address ? sg->address :
+				(page_address(sg->page) + sg->offset);
+			startPage = (unsigned long)address >> PAGE_SHIFT;
+			endPage = ((unsigned long)address + sg->length - 1) >> PAGE_SHIFT;
 			numPages = endPage - startPage + 1;
 			
-			uaddr = (unsigned long)sg->address;
+			uaddr = (unsigned long)address;
 
 			/* If the previous entry ended in the same page that
 			 * the current page starts then they share that
@@ -1335,6 +1348,9 @@
 	    		PPCDBG(PPCDBG_TCE, "create_tces_sg: numTces %d, tces used %d\n",
 		   		numTces, (unsigned)(tcenum - starttcenum));
 
+	} else {
+		panic("PCI_DMA: TCE allocation failure in create_tces_sg. 0x%p 0x%x\n",
+		      tbl, order);
 	}
 
 	return dmaAddr;
@@ -1346,25 +1362,26 @@
 	unsigned numTces;
 	int num_dma = 0;
 	dma_addr_t dma_handle;
+	void *address;
 
-	PPCDBG(PPCDBG_TCE, "pci_map_sg:\n");
-	PPCDBG(PPCDBG_TCE, "\thwdev = 0x%16.16lx, sg = 0x%16.16lx, direction = 0x%16.16lx, nents = 0x%16.16lx\n", hwdev, sg, direction, nents);	
 	/* Fast path for a single entry scatterlist */
 	if ( nents == 1 ) {
-		sg->dma_address = pci_map_single( hwdev, sg->address, 
-					sg->length, direction );
+ 		address = sg->address ? sg->address :
+ 			(page_address(sg->page) + sg->offset);
+ 		sg->dma_address = pci_map_single( hwdev, address,
+ 						  sg->length, direction );
 		sg->dma_length = sg->length;
 		return 1;
 	}
 	
-	if ( direction == PCI_DMA_NONE )
+	if (direction == PCI_DMA_NONE)
 		BUG();
 	
 	tbl = get_tce_table(hwdev); 
 
-	if ( tbl ) {
+	if (tbl) {
 		/* Compute the number of tces required */
-		numTces = num_tces_sg( sg, nents );
+		numTces = num_tces_sg(sg, nents);
 		/* Create the tces and get the dma address */ 
 		dma_handle = create_tces_sg( tbl, sg, nents, numTces, direction );
 
@@ -1372,6 +1389,8 @@
 
 		/* Fill in the dma scatterlist */
 		num_dma = fill_scatterlist_sg( sg, nents, dma_handle, numTces );
+	} else {
+		panic("pci_map_sg: unable to find TCE table\n");
 	}
 
 	return num_dma;
@@ -1407,7 +1426,7 @@
 	/* It is easier to debug here for the drivers than in the tce tables.*/
  	if(order >= NUM_TCE_LEVELS) {
 		printk("PCI_DMA: dma_start_page:0x%lx  dma_end_page:0x%lx\n",dma_start_page,dma_end_page);
-		printk("PCI_DMA: pci_unmap_sg size to large: 0x%x \n",(numTces << PAGE_SHIFT));
+		printk("PCI_DMA: pci_unmap_sg size too large: 0x%x \n",(numTces << PAGE_SHIFT));
  		return;
  	}
 	

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