Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 12 Jan 2006 16:01:02 GMT
From:      Olivier Houchard <cognet@FreeBSD.org>
To:        Perforce Change Reviews <perforce@freebsd.org>
Subject:   PERFORCE change 89554 for review
Message-ID:  <200601121601.k0CG12lc014178@repoman.freebsd.org>

next in thread | raw e-mail | index | archive | help
http://perforce.freebsd.org/chv.cgi?CH=89554

Change 89554 by cognet@cognet on 2006/01/12 16:00:13

	- Setup the RX descriptors.
	- Start an interrupt handler.

Affected files ...

.. //depot/projects/arm/src/sys/arm/at91/if_ate.c#20 edit

Differences ...

==== //depot/projects/arm/src/sys/arm/at91/if_ate.c#20 (text+ko) ====

@@ -62,6 +62,12 @@
 #include "miibus_if.h"
 
 #define ATE_MAX_TX_BUFFERS 2		/* We have ping-pong tx buffers */
+#define ATE_MAX_RX_BUFFERS 8
+
+typedef struct {
+    	bus_addr_t addr;
+	int status;
+} rx_desc_t;
 
 struct ate_softc
 {
@@ -75,7 +81,15 @@
 	struct callout tick_ch;		/* Tick callout */
 	bus_dma_tag_t mtag;		/* bus dma tag for mbufs */
 	bus_dmamap_t tx_map[ATE_MAX_TX_BUFFERS];
+	bus_dma_tag_t rxtag;
+	bus_dmamap_t rx_map[ATE_MAX_RX_BUFFERS];
+	bus_dma_tag_t rx_desc_tag;
+	bus_dmamap_t rx_desc_map;
 	int txcur;			/* current tx map pointer */
+	struct mbuf *sent_mbuf[ATE_MAX_TX_BUFFERS]; /* Sent mbufs */
+	struct mbuf *rx_mbuf[ATE_MAX_RX_BUFFERS]; /* RX mbufs */
+	bus_addr_t rx_desc_phys;
+	rx_desc_t *rx_descs;
 
 	// XXX bogus
 	int intr;
@@ -212,6 +226,17 @@
 	return EBUSY;	/* XXX */
 }
 
+static void
+ate_getaddr(void *arg, bus_dma_segment_t *segs, int nsegs, int error)
+{
+	struct ate_softc *sc;
+
+	if (error != 0)
+		return;
+	sc = (struct ate_softc *)arg;
+	sc->rx_desc_phys = segs[0].ds_addr;
+}
+
 static int
 ate_activate(device_t dev)
 {
@@ -243,14 +268,65 @@
 		if (err != 0)
 			goto errout;
 	}
-
+	 /*
+	  * Allocate our Rx buffers.  This chip has a rx structure that's filled
+	  * in
+	  */
+	
 	/*
-	 * Allocate our Rx buffers.  This chip has a rx structure that's filled
-	 * in -- later XXX
+	 * Allocate DMA tags and maps for RX.
 	 */
+	err = bus_dma_tag_create(NULL, 1, 0, BUS_SPACE_MAXADDR_32BIT,
+	    BUS_SPACE_MAXADDR, NULL, NULL, MCLBYTES, 1, MCLBYTES, 0,
+	    busdma_lock_mutex, &sc->sc_mtx, &sc->rxtag);
+	if (err != 0)
+		goto errout;
+	for (i = 0; i < ATE_MAX_RX_BUFFERS; i++) {
+		err = bus_dmamap_create(sc->rxtag, 0, &sc->rx_map[i]);
+		if (err != 0)
+			goto errout;
+	}
 
+	/* Dma TAG and MAP for the rx descriptors. */
+	err = bus_dma_tag_create(NULL, sizeof(rx_desc_t), 0, 
+	    BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL,
+	    ATE_MAX_RX_BUFFERS * sizeof(rx_desc_t), 1,
+	    ATE_MAX_RX_BUFFERS * sizeof(rx_desc_t), 0, busdma_lock_mutex,
+	    &sc->sc_mtx, &sc->rx_desc_tag);
+	if (err != 0)
+		goto errout;
+	if (bus_dmamem_alloc(sc->rx_desc_tag, (void **)&sc->rx_descs, M_WAITOK,
+	    &sc->rx_desc_map) != 0)
+		goto errout;
+	if (bus_dmamap_load(sc->rx_desc_tag, sc->rx_desc_map, 
+	    sc->rx_descs, ATE_MAX_RX_BUFFERS * sizeof(rx_desc_t), ate_getaddr,
+	    sc, 0) != 0)
+		goto errout;
+	for (i = 0; i < ATE_MAX_RX_BUFFERS; i++) {
+		bus_dma_segment_t seg;
+		int nsegs;
+		
+		sc->rx_mbuf[i] = m_getcl(M_WAITOK, MT_DATA, M_PKTHDR);
+		sc->rx_mbuf[i]->m_len = sc->rx_mbuf[i]->m_pkthdr.len =
+		    MCLBYTES;
+		if (bus_dmamap_load_mbuf_sg(sc->rxtag, sc->rx_map[i],
+		    sc->rx_mbuf[i], &seg, &nsegs, 0) != 0)
+			goto errout;
+		/*
+		 * For the last buffer, set the wrap bit so the controller
+		 * restarts from the first descriptor.
+		 */
+		if (i == ATE_MAX_RX_BUFFERS - 1)
+			seg.ds_addr |= 1 << 1;
+		sc->rx_descs[i].addr = seg.ds_addr;
+		sc->rx_descs[i].status = 0;
+		bus_dmamap_sync(sc->rxtag, sc->rx_map[i], BUS_DMASYNC_PREWRITE);
+	}
+	bus_dmamap_sync(sc->rx_desc_tag, sc->rx_desc_map, BUS_DMASYNC_PREWRITE);
+	/* Write the descriptor queue address. */
+	WR4(sc, ETH_RBQP, sc->rx_desc_phys);
 	return (0);
-errout:;
+errout:
 	ate_deactivate(dev);
 	return (ENOMEM);
 }
@@ -442,8 +518,86 @@
 ate_intr(void *xsc)
 {
 	struct ate_softc *sc = xsc;
+	int status;
+	int i;
+		
+	sc->intr++;
+	status = RD4(sc, ETH_ISR);
+	if (status == 0)
+		return;
+	if (status & ETH_ISR_RCOM) {
+		bus_dmamap_sync(sc->rx_desc_tag, sc->rx_desc_map,
+		    BUS_DMASYNC_POSTREAD);
+		for (i = 0; i < ATE_MAX_RX_BUFFERS; i++) {
+			if (sc->rx_descs[i].addr & 1) {
+				struct mbuf *mb = sc->rx_mbuf[i];
+				bus_dma_segment_t seg;
+				int rx_stat = sc->rx_descs[i].status;
+				int nsegs;
+
+				bus_dmamap_sync(sc->rxtag,
+				    sc->rx_map[i], BUS_DMASYNC_POSTREAD);
+				bus_dmamap_unload(sc->rxtag,
+				    sc->rx_map[i]);
+				/*
+				 * Clear the corresponding bits in RSR.
+				 */
+				WR4(sc, ETH_RSR, RD4(sc, ETH_RSR));
+				sc->rx_mbuf[i] = m_getcl(M_DONTWAIT, MT_DATA,
+				    M_PKTHDR);
+				if (!sc->rx_mbuf[i]) {
+					sc->rx_mbuf[i] = mb;
+					sc->rx_descs[i].addr &= ~1;
+					bus_dmamap_sync(sc->rx_desc_tag,
+					    sc->rx_desc_map, 
+					    BUS_DMASYNC_PREWRITE);
+					break;
+				}
+				if (bus_dmamap_load_mbuf_sg(sc->rxtag,
+				    sc->rx_map[i],
+				    sc->rx_mbuf[i], &seg, &nsegs, 0) != 0) {
+					sc->rx_mbuf[i] = mb;
+					sc->rx_descs[i].addr &= ~1;
+					bus_dmamap_sync(sc->rx_desc_tag,
+					    sc->rx_desc_map,
+					    BUS_DMASYNC_PREWRITE);
+					break;
+				}
+				/*
+				 * For the last buffer, set the wrap bit so the controller
+				 * restarts from the first descriptor.
+				 */
+				if (i == ATE_MAX_RX_BUFFERS - 1)
+					seg.ds_addr |= 1 << 1;
+				sc->rx_descs[i].addr = seg.ds_addr;
+				sc->rx_descs[i].status = 0;
+				/* Bits 0-10 of the status file == length. */
+				mb->m_len = rx_stat & 0x7ff;
+				(*sc->ifp->if_input)(sc->ifp, mb);
+				break;
 
-	sc->intr++;
+
+			}
+		}
+	}
+	if (status & ETH_ISR_TCOM) {
+		if (sc->sent_mbuf[0])
+			m_freem(sc->sent_mbuf[0]);
+		if (sc->sent_mbuf[1]) {
+			if (RD4(sc, ETH_TSR) & ETH_TSR_IDLE) {
+				m_freem(sc->sent_mbuf[1]);
+				sc->txcur = 0;
+				sc->sent_mbuf[0] = sc->sent_mbuf[1] = NULL;
+			} else {
+				sc->sent_mbuf[0] = sc->sent_mbuf[1];
+				sc->sent_mbuf[1] = NULL;
+				sc->txcur = 1;
+			}
+		} else {
+			sc->sent_mbuf[0] = NULL;
+			sc->txcur = 0;
+		}
+	}
 }
 
 /*
@@ -477,7 +631,7 @@
 	WR4(sc, ETH_CFG, RD4(sc, ETH_CFG) & ~ETH_CFG_RMII);
 #endif
 
-	WR4(sc, ETH_CTL, RD4(sc, ETH_CTL) | ETH_CTL_TE);
+	WR4(sc, ETH_CTL, RD4(sc, ETH_CTL) | ETH_CTL_TE | ETH_CTL_RE);
 
 	/*
 	 * Boot loader fills in MAC address.  If that's not the case, then
@@ -516,7 +670,7 @@
 	if (ifp->if_drv_flags & IFF_DRV_OACTIVE)
 		return;
 
-outloop:;
+outloop:
 	/* XXX ed checks to see if there are buffered packets and an idle
 	 * transmitter and kicks something if so.  This shouldn't happen
 	 * for this device, and I note it here only in passing
@@ -545,6 +699,7 @@
 		goto outloop;
 	}
 	bus_dmamap_sync(sc->mtag, sc->tx_map[sc->txcur], BUS_DMASYNC_PREWRITE);
+	sc->sent_mbuf[sc->txcur] = m;
 	sc->txcur++;
 	if (sc->txcur >= ATE_MAX_TX_BUFFERS)
 		sc->txcur = 0;



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200601121601.k0CG12lc014178>