Subject: Re: MI SONIC Ethernet driver for mac68k
To: None <port-mac68k@NetBSD.org>
From: Izumi Tsutsui <tsutsui@ceres.dti.ne.jp>
List: port-mac68k
Date: 06/07/2007 01:54:57
I wrote:

> Summary:
> 	TX on sn0	RX on sn0
> MD:	1026KB/s	 846KB/s
> MI:  	 793KB/s	 854KB/s

more results:

MI driver with BUS_DMA_COHERENT support:
	TX on sn0	RX on sn0
	 842KB/s	 888KB/s

MI driver with BUS_DMA_COHERENT support and 16bytes TX DMA threshold:
	TX on sn0	RX on sn0
	 903KB/s	 886KB/s

---
Izumi Tsutsui


Index: arch/m68k/include/bus_dma.h
===================================================================
RCS file: /cvsroot/src/sys/arch/m68k/include/bus_dma.h,v
retrieving revision 1.8
diff -u -r1.8 bus_dma.h
--- arch/m68k/include/bus_dma.h	4 Mar 2007 06:00:04 -0000	1.8
+++ arch/m68k/include/bus_dma.h	6 Jun 2007 16:48:19 -0000
@@ -119,6 +119,7 @@
 struct m68k_bus_dma_segment {
 	bus_addr_t	ds_addr;	/* DMA address */
 	bus_size_t	ds_len;		/* length of transfer */
+	u_int		_ds_flags;	/* MD flags */
 };
 typedef struct m68k_bus_dma_segment	bus_dma_segment_t;
 
@@ -215,7 +216,7 @@
 	int		_dm_segcnt;	/* number of segs this map can map */
 	bus_size_t	_dm_maxmaxsegsz; /* fixed largest possible segment */
 	bus_size_t	_dm_boundary;	/* don't cross this */
-	int		_dm_flags;	/* misc. flags */
+	u_int		_dm_flags;	/* misc. flags */
 
 	/* Machine dependant fields: */
 	bus_size_t  dm_xfer_len;	/* length of successful transfer */
Index: arch/m68k/include/pmap_motorola.h
===================================================================
RCS file: /cvsroot/src/sys/arch/m68k/include/pmap_motorola.h,v
retrieving revision 1.13
diff -u -r1.13 pmap_motorola.h
--- arch/m68k/include/pmap_motorola.h	12 May 2007 17:43:53 -0000	1.13
+++ arch/m68k/include/pmap_motorola.h	6 Jun 2007 16:48:19 -0000
@@ -202,10 +202,8 @@
 #define	PMAP_PREFER(foff, vap, sz, td)	pmap_prefer((foff), (vap))
 #endif
 
-#ifdef mvme68k
 void	_pmap_set_page_cacheable(struct pmap *, vaddr_t);
 void	_pmap_set_page_cacheinhibit(struct pmap *, vaddr_t);
 int	_pmap_page_is_cacheable(struct pmap *, vaddr_t);
-#endif
 
 #endif /* !_M68K_PMAP_MOTOROLA_H_ */
Index: arch/m68k/m68k/bus_dma.c
===================================================================
RCS file: /cvsroot/src/sys/arch/m68k/m68k/bus_dma.c,v
retrieving revision 1.23
diff -u -r1.23 bus_dma.c
--- arch/m68k/m68k/bus_dma.c	2 Jun 2007 11:13:45 -0000	1.23
+++ arch/m68k/m68k/bus_dma.c	6 Jun 2007 16:48:19 -0000
@@ -141,23 +141,30 @@
 	bus_size_t sgsize;
 	bus_addr_t curaddr, lastaddr, baddr, bmask;
 	vaddr_t vaddr = (vaddr_t)buf;
-	int seg;
+	int seg, cacheable, coherent;
+	pmap_t pmap;
 	bool rv;
 
+	coherent = BUS_DMA_COHERENT;
 	lastaddr = *lastaddrp;
 	bmask = ~(map->_dm_boundary - 1);
+	if (!VMSPACE_IS_KERNEL_P(vm))
+		pmap = vm_map_pmap(&vm->vm_map);
+	else
+		pmap = pmap_kernel();
 
 	for (seg = *segp; buflen > 0 ; ) {
 		/*
 		 * Get the physical address for this segment.
 		 */
-		if (!VMSPACE_IS_KERNEL_P(vm))
-			rv = pmap_extract(vm_map_pmap(&vm->vm_map),
-			    vaddr, &curaddr);
-		else
-			rv = pmap_extract(pmap_kernel(), vaddr, &curaddr);
+		rv = pmap_extract(pmap, vaddr, &curaddr);
 		KASSERT(rv);
 
+		cacheable = _pmap_page_is_cacheable(pmap, vaddr);
+
+		if (cacheable)
+			coherent = 0;
+
 		/*
 		 * Compute the segment size, and adjust counts.
 		 */
@@ -181,6 +188,8 @@
 		if (first) {
 			map->dm_segs[seg].ds_addr = curaddr;
 			map->dm_segs[seg].ds_len = sgsize;
+			map->dm_segs[seg]._ds_flags =
+			    cacheable ? 0 : BUS_DMA_COHERENT;
 			first = 0;
 		} else {
 			if (curaddr == lastaddr &&
@@ -195,6 +204,8 @@
 					break;
 				map->dm_segs[seg].ds_addr = curaddr;
 				map->dm_segs[seg].ds_len = sgsize;
+				map->dm_segs[seg]._ds_flags =
+				    cacheable ? 0 : BUS_DMA_COHERENT;
 			}
 		}
 
@@ -205,6 +216,9 @@
 
 	*segp = seg;
 	*lastaddrp = lastaddr;
+	map->_dm_flags &= ~BUS_DMA_COHERENT;
+	/* BUS_DMA_COHERENT is set only if all segments are uncached */
+	map->_dm_flags |= coherent;
 
 	/*
 	 * Did we fit?
@@ -408,6 +422,7 @@
 	map->dm_maxsegsz = map->_dm_maxmaxsegsz;
 	map->dm_mapsize = 0;
 	map->dm_nsegs = 0;
+	map->_dm_flags &= ~BUS_DMA_COHERENT;
 }
 
 /*
@@ -426,6 +441,7 @@
 #if defined(M68040) || defined(M68060)
 	bus_addr_t p, e, ps, pe;
 	bus_size_t seglen;
+	bus_dma_segment_t *seg;
 	int i;
 #endif
 
@@ -438,6 +454,10 @@
 #endif
 
 #if defined(M68040) || defined(M68060)
+	/* If the whole DMA map is uncached, do nothing. */
+	if ((map->_dm_flags & BUS_DMA_COHERENT) != 0)
+		return;
+
 	/* Short-circuit for unsupported `ops' */
 	if ((ops & (BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE)) == 0)
 		return;
@@ -446,9 +466,10 @@
 	 * flush/purge the cache.
 	 */
 	for (i = 0; i < map->dm_nsegs && len != 0; i++) {
-		if (map->dm_segs[i].ds_len <= offset) {
+		seg = &map->dm_segs[i];
+		if (seg->ds_len <= offset) {
 			/* Segment irrelevant - before requested offset */
-			offset -= map->dm_segs[i].ds_len;
+			offset -= seg->ds_len;
 			continue;
 		}
 
@@ -457,11 +478,15 @@
 		 * each segment until we have exhausted the
 		 * length.
 		 */
-		seglen = map->dm_segs[i].ds_len - offset;
+		seglen = seg->ds_len - offset;
 		if (seglen > len)
 			seglen = len;
 
-		ps = map->dm_segs[i].ds_addr + offset;
+		/* Ignore cache-inhibited segments */
+		if ((seg->_ds_flags & BUS_DMA_COHERENT) != 0)
+			continue;
+
+		ps = seg->ds_addr + offset;
 		pe = ps + seglen;
 
 		if (ops & BUS_DMASYNC_PREWRITE) {
@@ -655,10 +680,20 @@
 			pmap_enter(pmap_kernel(), va, addr,
 			    VM_PROT_READ | VM_PROT_WRITE,
 			    VM_PROT_READ | VM_PROT_WRITE | PMAP_WIRED);
+
+			/* Cache-inhibit the page if necessary */
+			if ((flags & BUS_DMA_COHERENT) != 0)
+				_pmap_set_page_cacheinhibit(pmap_kernel(), va);
+
+			segs[curseg]._ds_flags &= ~BUS_DMA_COHERENT;
+			segs[curseg]._ds_flags |= (flags & BUS_DMA_COHERENT);
 		}
 	}
 	pmap_update(pmap_kernel());
 
+	if ((flags & BUS_DMA_COHERENT) != 0)
+		TBIAS();
+
 	return 0;
 }
 
@@ -669,6 +704,8 @@
 void
 _bus_dmamem_unmap(bus_dma_tag_t t, void *kva, size_t size)
 {
+	vaddr_t va;
+	size_t s;
 
 #ifdef DIAGNOSTIC
 	if ((u_long)kva & PGOFSET)
@@ -677,6 +714,15 @@
 
 	size = round_page(size);
 
+	/*
+	 * Re-enable cacheing on the range
+	 * XXXSCW: There should be some way to indicate that the pages
+	 * were mapped DMA_MAP_COHERENT in the first place...
+	 */
+	for (s = 0, va = (vaddr_t)kva; s < size;
+	    s += PAGE_SIZE, va += PAGE_SIZE)
+		_pmap_set_page_cacheable(pmap_kernel(), va);
+
 	pmap_remove(pmap_kernel(), (vaddr_t)kva, (vaddr_t)kva + size);
 	pmap_update(pmap_kernel());
 	uvm_km_free(kernel_map, (vaddr_t)kva, size, UVM_KMF_VAONLY);
@@ -707,6 +753,10 @@
 			continue;
 		}
 
+		/*
+		 * XXXSCW: What about BUS_DMA_COHERENT ??
+		 */
+
 		return m68k_btop((char *)segs[i].ds_addr + off);
 	}
 
Index: arch/m68k/m68k/pmap_motorola.c
===================================================================
RCS file: /cvsroot/src/sys/arch/m68k/m68k/pmap_motorola.c,v
retrieving revision 1.30
diff -u -r1.30 pmap_motorola.c
--- arch/m68k/m68k/pmap_motorola.c	18 May 2007 01:46:40 -0000	1.30
+++ arch/m68k/m68k/pmap_motorola.c	6 Jun 2007 16:48:20 -0000
@@ -2848,8 +2848,6 @@
 	(void)cachectl1(0x80000004, va, len, p);
 }
 
-#ifdef mvme68k
-
 void
 _pmap_set_page_cacheable(pmap_t pmap, vaddr_t va)
 {
@@ -2905,8 +2903,6 @@
 	return (pmap_pte_ci(pmap_pte(pmap, va)) == 0) ? 1 : 0;
 }
 
-#endif /* mvme68k */
-
 #ifdef DEBUG
 /*
  * pmap_pvdump: