Subject: Re: noncontingous DMA segments with mc0 at obio
To: Martin Husemann <martin@duskware.de>
From: None <khym@azeotrope.org>
List: port-mac68k
Date: 12/10/2006 13:25:40
On Sat, Dec 09, 2006 at 10:59:46PM +0100, Martin Husemann wrote:
> Hi folks,
> 
> after some hardware troubles I got my "brand new" Quadra 660AV booting
> NetBSD for the first time.
> 
> The 4.0 install kernel fails to attach mc0 at obio, due to physically non
> contingous memory returned by malloc. See the comment in obio/if_mc_obio.c
> around line 140.
> 
> I can rebuild my own install kernel, as suggest with only two rx DMA buffers.
> I could even try to convert this driver to bus_dma ;-)
> 
> But I primarily wonder if this is a common effect, and wether the install
> kernels should be build with options MC_RXDMABUFS=2 to work around it.

I think some changes made to the m68k pmap code a while back caused
malloc to return physically non-contiguous memory... I never saw that
message before, but I always get it in post-3.x kernels.

Using bus_dma would be great :) I took a stab at it a while back, but
I'm not sure if the best way of doing things:

Index: sys/arch/mac68k/dev/if_mc.c
===================================================================
RCS file: /cvsroot/src/sys/arch/mac68k/dev/if_mc.c,v
retrieving revision 1.27
diff -u -r1.27 if_mc.c
--- sys/arch/mac68k/dev/if_mc.c	7 Sep 2006 02:40:31 -0000	1.27
+++ sys/arch/mac68k/dev/if_mc.c	10 Dec 2006 19:24:33 -0000
@@ -411,7 +411,7 @@
 	u_int len, totlen = 0;
 	u_char *buff;
 
-	buff = sc->sc_txbuf;
+	buff = sc->sc_txbuf + (sc->sc_txset == 0 ? 0 : 0x800);
 
 	for (; m; m = n) {
 		u_char *data = mtod(m, u_char *);
Index: sys/arch/mac68k/dev/if_mcvar.h
===================================================================
RCS file: /cvsroot/src/sys/arch/mac68k/dev/if_mcvar.h,v
retrieving revision 1.11
diff -u -r1.11 if_mcvar.h
--- sys/arch/mac68k/dev/if_mcvar.h	24 Dec 2005 20:07:15 -0000	1.11
+++ sys/arch/mac68k/dev/if_mcvar.h	10 Dec 2006 19:24:33 -0000
@@ -78,9 +78,12 @@
 
 	bus_space_tag_t		sc_regt;
 	bus_space_handle_t	sc_regh;
+	bus_dma_tag_t	sc_dmat;
+	bus_dmamap_t	sc_dmam_tx, sc_dmam_rx;
+	bus_dma_segment_t	sc_dmasegs_tx, sc_dmasegs_rx;
 
-	u_char		*sc_txbuf, *sc_rxbuf;
-	int		sc_txbuf_phys, sc_rxbuf_phys;
+	caddr_t		sc_txbuf, sc_rxbuf;
+	bus_addr_t	sc_txbuf_phys, sc_rxbuf_phys;
 	int		sc_tail;
 	int		sc_rxset;
 	int		sc_txset, sc_txseti;
Index: sys/arch/mac68k/obio/if_mc_obio.c
===================================================================
RCS file: /cvsroot/src/sys/arch/mac68k/obio/if_mc_obio.c,v
retrieving revision 1.15
diff -u -r1.15 if_mc_obio.c
--- sys/arch/mac68k/obio/if_mc_obio.c	11 Dec 2005 12:18:03 -0000	1.15
+++ sys/arch/mac68k/obio/if_mc_obio.c	10 Dec 2006 19:24:34 -0000
@@ -111,7 +111,7 @@
 	struct obio_attach_args *oa = (struct obio_attach_args *)aux;
 	struct mc_softc *sc = (void *)self;
 	u_int8_t myaddr[ETHER_ADDR_LEN];
-	int i, noncontig = 0;
+	int rsegs;
 
 	sc->sc_regt = oa->oa_tag;
 	sc->sc_biucc = XMTSP_64;
@@ -130,38 +130,59 @@
 		return;
 	}
 
-	/* allocate memory for transmit buffer and mark it non-cacheable */
-	sc->sc_txbuf = malloc(PAGE_SIZE, M_DEVBUF, M_WAITOK);
-	sc->sc_txbuf_phys = kvtop(sc->sc_txbuf);
-	physaccess (sc->sc_txbuf, (caddr_t)sc->sc_txbuf_phys, PAGE_SIZE,
-	    PG_V | PG_RW | PG_CI);
+	/* allocate memory for transmit and receive DMA buffers */
+	sc->sc_dmat = oa->oa_dmat;
+	if (bus_dmamem_alloc(sc->sc_dmat, 2 * 0x800, 0, 0, &sc->sc_dmasegs_tx,
+		1, &rsegs, BUS_DMA_NOWAIT) != 0) {
+		printf(": failed to allocate TX DMA buffers.\n");
+		return;
+	}
 
-	/*
-	 * allocate memory for receive buffer and mark it non-cacheable
-	 * XXX This should use the bus_dma interface, since the buffer
-	 * needs to be physically contiguous. However, it seems that
-	 * at least on my system, malloc() does allocate contiguous
-	 * memory. If it's not, suggest reducing the number of buffers
-	 * to 2, which will fit in one 4K page.
-	 */
-	sc->sc_rxbuf = malloc(MC_NPAGES * PAGE_SIZE, M_DEVBUF, M_WAITOK);
-	sc->sc_rxbuf_phys = kvtop(sc->sc_rxbuf);
-	for (i = 0; i < MC_NPAGES; i++) {
-		int pa;
-
-		pa = kvtop(sc->sc_rxbuf + PAGE_SIZE*i);
-		physaccess (sc->sc_rxbuf + PAGE_SIZE*i, (caddr_t)pa, PAGE_SIZE,
-		    PG_V | PG_RW | PG_CI);
-		if (pa != sc->sc_rxbuf_phys + PAGE_SIZE*i)
-			noncontig = 1;
+	if (bus_dmamem_map(sc->sc_dmat, &sc->sc_dmasegs_tx, rsegs, 2 * 0x800,
+		&sc->sc_txbuf, BUS_DMA_NOWAIT | BUS_DMA_COHERENT) != 0) {
+		printf(": failed to map TX DMA buffers.\n");
+		return;
 	}
 
-	if (noncontig) {
-		printf("%s: receive DMA buffer not contiguous! "
-		    "Try compiling with \"options MC_RXDMABUFS=2\"\n",
-		    sc->sc_dev.dv_xname);
+	if (bus_dmamem_alloc(sc->sc_dmat, MC_RXDMABUFS * 0x800, 0, 0,
+		&sc->sc_dmasegs_rx, 1, &rsegs, BUS_DMA_NOWAIT) != 0) {
+		printf(": failed to allocate RX DMA buffers.\n");
+		return;
+	}
+
+	if (bus_dmamem_map(sc->sc_dmat, &sc->sc_dmasegs_rx, rsegs,
+		MC_RXDMABUFS * 0x800, &sc->sc_rxbuf,
+		BUS_DMA_NOWAIT | BUS_DMA_COHERENT) != 0) {
+		printf(": failed to map RX DMA buffers.\n");
+		return;
+	}
+
+	if (bus_dmamap_create(sc->sc_dmat, 2 * 0x800, 1, 2 * 0x800, 0,
+	    BUS_DMA_NOWAIT, &sc->sc_dmam_tx) != 0) {
+		printf(": failed to allocate TX DMA map.\n");
 		return;
 	}
+	
+	if (bus_dmamap_load(sc->sc_dmat, sc->sc_dmam_tx, sc->sc_txbuf,
+		2 * 0x800, NULL, BUS_DMA_NOWAIT) != 0) {
+		printf(": failed to map TX DMA mapping.\n");
+		return;
+	}
+
+	if (bus_dmamap_create(sc->sc_dmat, MC_RXDMABUFS * 0x800, 1,
+		MC_RXDMABUFS * 0x800, 0, BUS_DMA_NOWAIT, &sc->sc_dmam_rx) != 0) {
+		printf(": failed to allocate RX DMA map.\n");
+		return;
+	}
+	
+	if (bus_dmamap_load(sc->sc_dmat, sc->sc_dmam_rx, sc->sc_rxbuf,
+		MC_RXDMABUFS * 0x800, NULL, BUS_DMA_NOWAIT) != 0) {
+		printf(": failed to map RX DMA mapping.\n");
+		return;
+	}
+
+	sc->sc_txbuf_phys = sc->sc_dmasegs_tx.ds_addr;
+	sc->sc_rxbuf_phys = sc->sc_dmasegs_rx.ds_addr;
 
 	sc->sc_bus_init = mc_obio_init;
 	sc->sc_putpacket = mc_obio_put;
@@ -219,9 +240,15 @@
 hide void
 mc_obio_put(struct mc_softc *sc, u_int len)
 {
-	psc_reg4(PSC_ENETWR_ADDR + sc->sc_txset) = sc->sc_txbuf_phys;
+	int offset = sc->sc_txset == 0 ? 0 : 0x800;
+
+	bus_dmamap_sync(sc->sc_dmat, sc->sc_dmam_tx, offset, 0x800,
+	    BUS_DMASYNC_PREWRITE);
+	psc_reg4(PSC_ENETWR_ADDR + sc->sc_txset) = sc->sc_txbuf_phys + offset;
 	psc_reg4(PSC_ENETWR_LEN + sc->sc_txset) = len;
 	psc_reg2(PSC_ENETWR_CMD + sc->sc_txset) = 0x9800;
+	bus_dmamap_sync(sc->sc_dmat, sc->sc_dmam_tx, offset, 0x800,
+	    BUS_DMASYNC_POSTWRITE);
 
 	sc->sc_txset ^= 0x10;
 }
@@ -279,6 +306,11 @@
 		/* Loop through, processing each of the packets */
 		for (; sc->sc_tail < head; sc->sc_tail++) {
 			offset = sc->sc_tail * 0x800;
+
+			bus_dmamap_sync(sc->sc_dmat, sc->sc_dmam_rx,
+					PAGE_SIZE + offset, 0x800,
+					BUS_DMASYNC_PREREAD);
+
 			sc->sc_rxframe.rx_rcvcnt = sc->sc_rxbuf[offset];
 			sc->sc_rxframe.rx_rcvsts = sc->sc_rxbuf[offset+2];
 			sc->sc_rxframe.rx_rntpc = sc->sc_rxbuf[offset+4];
@@ -286,6 +318,10 @@
 			sc->sc_rxframe.rx_frame = sc->sc_rxbuf + offset + 16;
 
 			mc_rint(sc);
+
+			bus_dmamap_sync(sc->sc_dmat, sc->sc_dmam_rx,
+					PAGE_SIZE + offset, 0x800,
+					BUS_DMASYNC_POSTREAD);
 		}
 
 		/*
-- 
Name: Dave Huang         |  Mammal, mammal / their names are called /
INet: khym@azeotrope.org |  they raise a paw / the bat, the cat /
FurryMUCK: Dahan         |  dolphin and dog / koala bear and hog -- TMBG
Dahan: Hani G Y+C 31 Y++ L+++ W- C++ T++ A+ E+ S++ V++ F- Q+++ P+ B+ PA+ PL++