PERFORCE change 194491 for review

Jakub Wojciech Klama jceel at FreeBSD.org
Thu Jun 9 08:54:38 UTC 2011


http://p4web.freebsd.org/@@194491?ac=10

Change 194491 by jceel at jceel_cyclone on 2011/06/09 08:54:06

	Ethernet driver update: working correctly in trivial scenarios.

Affected files ...

.. //depot/projects/soc2011/jceel_lpc/sys/arm/lpc/if_lpe.c#2 edit
.. //depot/projects/soc2011/jceel_lpc/sys/arm/lpc/if_lpereg.h#2 edit

Differences ...

==== //depot/projects/soc2011/jceel_lpc/sys/arm/lpc/if_lpe.c#2 (text+ko) ====

@@ -94,6 +94,7 @@
 	struct lpe_txdesc	lpe_tx_desc[LPE_TXDESC_NUM];
 	int			lpe_tx_prod;
 	int			lpe_tx_cons;
+	int			lpe_tx_used;
 	int			lpe_rx_cons;
 };
 
@@ -120,8 +121,8 @@
 	bus_space_tag_t		lpe_bst;
 	bus_space_handle_t	lpe_bsh;
 	uint32_t		lpe_flags;
+	struct callout		lpe_tick;
 
-
 	struct lpe_chain_data	lpe_cdata;
 	struct lpe_ring_data	lpe_rdata;
 };
@@ -144,11 +145,13 @@
 static void lpe_intr(void *);
 static void lpe_rxintr(struct lpe_softc *);
 static void lpe_txintr(struct lpe_softc *);
-//static void lpe_tick(void *);
+static void lpe_tick(void *);
 static int lpe_encap(struct lpe_softc *, struct mbuf **);
 static int lpe_dma_alloc(struct lpe_softc *);
 static int lpe_dma_alloc_rx(struct lpe_softc *);
 static int lpe_dma_alloc_tx(struct lpe_softc *);
+static int lpe_init_rx(struct lpe_softc *);
+static int lpe_init_rxbuf(struct lpe_softc *, int);
 static void lpe_dmamap_cb(void *, bus_dma_segment_t *, int, int);
 static int lpe_ifmedia_upd(struct ifnet *);
 static void lpe_ifmedia_sts(struct ifnet *, struct ifmediareq *);
@@ -194,6 +197,8 @@
 	mtx_init(&sc->lpe_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK,
 	    MTX_DEF);
 
+	callout_init_mtx(&sc->lpe_tick, &sc->lpe_mtx, 0);
+
 	rid = 0;
 	sc->lpe_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
 	    RF_ACTIVE);
@@ -287,8 +292,6 @@
 	struct lpe_softc *sc = device_get_softc(dev);
 	uint32_t val;
 
-	device_printf(dev, "mii read: phy=%d reg=%d\n", phy, reg);
-
 	lpe_write_4(sc, LPE_MCMD, LPE_MCMD_READ);
 	lpe_write_4(sc, LPE_MADR, 
 	    (reg & LPE_MADR_REGMASK) << LPE_MADR_REGSHIFT |
@@ -305,7 +308,11 @@
 	if (val & LPE_MIND_INVALID)
 		return (0);
 
-	return (lpe_read_4(sc, LPE_MRDD) & LPE_MRDD_DATAMASK);
+	lpe_write_4(sc, LPE_MCMD, 0);
+
+	int x = (lpe_read_4(sc, LPE_MRDD) & LPE_MRDD_DATAMASK);
+//	printf("mii read: phy=%d reg=%d result=0x%04x\n", phy, reg, x);
+	return (x);
 }
 
 static int
@@ -314,6 +321,8 @@
 	struct lpe_softc *sc = device_get_softc(dev);
 	uint32_t val;
 
+//	printf("mii write: phy=%d reg=%d data=0x%04x\n", phy, reg, data);
+
 	lpe_write_4(sc, LPE_MCMD, LPE_MCMD_WRITE);
 	lpe_write_4(sc, LPE_MADR, 
 	    (reg & LPE_MADR_REGMASK) << LPE_MADR_REGSHIFT |
@@ -393,11 +402,20 @@
 
 	/* Enable Tx and Rx */
 	cmd = lpe_read_4(sc, LPE_COMMAND);
-	lpe_write_4(sc, LPE_COMMAND, cmd | LPE_COMMAND_RXENABLE | LPE_COMMAND_TXENABLE);
+	lpe_write_4(sc, LPE_COMMAND, cmd | LPE_COMMAND_RXENABLE |
+	    LPE_COMMAND_TXENABLE | LPE_COMMAND_PASSRUNTFRAME | 
+	    LPE_COMMAND_PASSRXFILTER);
 
 	/* Enable receive */
 	mac1 = lpe_read_4(sc, LPE_MAC1);
-	lpe_write_4(sc, LPE_MAC1, mac1 | LPE_MAC1_RXENABLE);
+	lpe_write_4(sc, LPE_MAC1, /*mac1 |*/ LPE_MAC1_RXENABLE | LPE_MAC1_PASSALL);
+
+	/* XXX */
+	lpe_write_4(sc, LPE_MAC2, LPE_MAC2_CRCENABLE | LPE_MAC2_PADCRCENABLE |
+	    LPE_MAC2_FULLDUPLEX);
+
+	/* XXX */
+	lpe_write_4(sc, LPE_MCFG, (((7) & 0x7) << 2));
 
 	/* Set up Rx filter */
 	lpe_write_4(sc, LPE_RXFILTER_CTRL, 0xffffffff);
@@ -407,20 +425,36 @@
 	    LPE_INT_RXFINISH | LPE_INT_RXDONE | LPE_INT_TXUNDERRUN | 
 	    LPE_INT_TXERROR | LPE_INT_TXFINISH | LPE_INT_TXDONE);
 
+	sc->lpe_cdata.lpe_tx_prod = 0;
+	sc->lpe_cdata.lpe_tx_cons = 0;
+	sc->lpe_cdata.lpe_tx_used = 0;
+	sc->lpe_cdata.lpe_rx_cons = 0;
+
+	lpe_init_rx(sc);
+
 	/* Initialize Rx packet and status descriptor heads */
 	lpe_write_4(sc, LPE_RXDESC, sc->lpe_rdata.lpe_rx_ring_phys);
 	lpe_write_4(sc, LPE_RXSTATUS, sc->lpe_rdata.lpe_rx_status_phys);
-	lpe_write_4(sc, LPE_RXDESC_NUMBER, LPE_RXDESC_NUM);
+	lpe_write_4(sc, LPE_RXDESC_NUMBER, LPE_RXDESC_NUM - 1);
 	lpe_write_4(sc, LPE_RXDESC_CONS, 0);
 
+
+	device_printf(sc->lpe_dev, "rx ring: %p, rx status: %p\n",
+	    sc->lpe_rdata.lpe_rx_ring, sc->lpe_rdata.lpe_rx_status);
+
 	/* Initialize Tx packet and status descriptor heads */
 	lpe_write_4(sc, LPE_TXDESC, sc->lpe_rdata.lpe_tx_ring_phys);
 	lpe_write_4(sc, LPE_TXSTATUS, sc->lpe_rdata.lpe_tx_status_phys);
-	lpe_write_4(sc, LPE_TXDESC_NUMBER, LPE_TXDESC_NUM);
+	lpe_write_4(sc, LPE_TXDESC_NUMBER, LPE_TXDESC_NUM - 1);
 	lpe_write_4(sc, LPE_TXDESC_PROD, 0);
-	
+
+	device_printf(sc->lpe_dev, "tx ring: %p, tx status: %p\n",
+	    sc->lpe_rdata.lpe_tx_ring, sc->lpe_rdata.lpe_tx_status);
+
 	ifp->if_drv_flags |= IFF_DRV_RUNNING;
 	ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
+
+	callout_reset(&sc->lpe_tick, hz, lpe_tick, sc);
 }
 
 static void
@@ -442,7 +476,7 @@
 
 	lpe_lock_assert(sc);
 
-	device_printf(sc->lpe_dev, "lpe_start_locked()\n");
+//	device_printf(sc->lpe_dev, "lpe_start_locked()\n");
 
 	while (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) {
 		/* Dequeue first packet */
@@ -451,11 +485,13 @@
 			break;
 
 		lpe_encap(sc, &m_head);
+
+		encap++;
 	}
 
 	/* Submit new descriptor list */
 	if (encap) {
-
+		lpe_write_4(sc, LPE_TXDESC_PROD, sc->lpe_cdata.lpe_tx_prod);
 	}
 	
 }
@@ -465,13 +501,21 @@
 {
 	struct lpe_txdesc *txd;
 	struct lpe_hwdesc *hwd;
-	struct lpe_hwstatus *hws;
+	//struct lpe_hwstatus *hws;
 	bus_dma_segment_t segs[LPE_MAXFRAGS];
-	int i, err, nsegs;
+	int i, err, nsegs, prod;
 
 	lpe_lock_assert(sc);
 	M_ASSERTPKTHDR((*m_head));
 
+	prod = sc->lpe_cdata.lpe_tx_prod;
+	txd = &sc->lpe_cdata.lpe_tx_desc[prod];
+
+//	device_printf(sc->lpe_dev, "lpe_encap: starting with prod=%d\n", prod);
+
+//	device_printf(sc->lpe_dev, "lpe_encap: packet data: %16D\n",
+//	    mtod(*m_head, const char *), " ");
+
 	err = bus_dmamap_load_mbuf_sg(sc->lpe_cdata.lpe_tx_buf_tag,
 	    txd->lpe_txdesc_dmamap, *m_head, segs, &nsegs, BUS_DMA_NOWAIT);
 
@@ -484,12 +528,34 @@
 		return (EIO);
 	}
 
+        bus_dmamap_sync(sc->lpe_cdata.lpe_tx_buf_tag, txd->lpe_txdesc_dmamap,
+          BUS_DMASYNC_PREREAD);
+        bus_dmamap_sync(sc->lpe_cdata.lpe_tx_ring_tag, sc->lpe_cdata.lpe_tx_ring_map,
+            BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
+
 	for (i = 0; i < nsegs; i++) {
-		hwd = &sc->lpe_rdata.lpe_tx_desc[prod];
-	
+		hwd = &sc->lpe_rdata.lpe_tx_ring[prod];
+		hwd->lhr_data = segs[i].ds_addr;
+		hwd->lhr_control = segs[i].ds_len - 1;// & LPE_HWDESC_SIZE_MASK;
+
+		if (i == nsegs - 1) {
+			hwd->lhr_control |= LPE_HWDESC_LASTFLAG;
+			hwd->lhr_control |= LPE_HWDESC_INTERRUPT;
+			hwd->lhr_control |= (1 << 28) | (1 << 29);
+		}
+
 		LPE_INC(prod, LPE_TXDESC_NUM);
+
+//		device_printf(sc->lpe_dev, "lpe_encap: 1 segment done @ %p, size: %ld\n",
+//			hwd, segs[i].ds_len);
 	}
 
+	bus_dmamap_sync(sc->lpe_cdata.lpe_tx_ring_tag, sc->lpe_cdata.lpe_tx_ring_map,
+	    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
+
+	sc->lpe_cdata.lpe_tx_used += nsegs;
+	sc->lpe_cdata.lpe_tx_prod = prod;
+
 	return (0);
 }
 
@@ -510,9 +576,16 @@
 static int
 lpe_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
 {
+	struct lpe_softc *sc = ifp->if_softc;
+	struct mii_data *mii = device_get_softc(sc->lpe_miibus);
+	struct ifreq *ifr = (struct ifreq *)data;
 	int err;
 
 	switch (cmd) {
+	case SIOCGIFMEDIA:
+	case SIOCSIFMEDIA:
+		err = ifmedia_ioctl(ifp, ifr, &mii->mii_media, cmd);
+		break;
 	default:
 		err = ether_ioctl(ifp, cmd, data);
 		break;
@@ -527,14 +600,16 @@
 	struct lpe_softc *sc = (struct lpe_softc *)arg;
 	uint32_t intstatus;
 
-	device_printf(sc->lpe_dev, "intr(): 0x%08x\n", lpe_read_4(sc, LPE_INTSTATUS));
+//	device_printf(sc->lpe_dev, "intr(): 0x%08x\n", lpe_read_4(sc, LPE_INTSTATUS));
 
 	while ((intstatus = lpe_read_4(sc, LPE_INTSTATUS))) {
-		if (intstatus & LPE_INT_RXFINISH)
+		if (intstatus & LPE_INT_RXDONE)
 			lpe_rxintr(sc);
 
-		if (intstatus & LPE_INT_TXFINISH)
+		if (intstatus & LPE_INT_TXDONE)
 			lpe_txintr(sc);
+	
+		lpe_write_4(sc, LPE_INTCLEAR, 0xffff);
 	}
 
 
@@ -543,22 +618,62 @@
 static void
 lpe_rxintr(struct lpe_softc *sc)
 {
+	struct ifnet *ifp = sc->lpe_ifp;
+	struct lpe_hwdesc *hwd;
+	struct lpe_hwstatus *hws;
+	struct lpe_rxdesc *rxd;
+	struct mbuf *m;
+	int prod, cons;
 
+//	device_printf(sc->lpe_dev, "receive interrupt\n");
+
+	for (;;) {
+		prod = lpe_read_4(sc, LPE_RXDESC_PROD);
+		cons = lpe_read_4(sc, LPE_RXDESC_CONS);
+		if (prod == cons)
+			break;
+
+		rxd = &sc->lpe_cdata.lpe_rx_desc[cons];
+		hwd = &sc->lpe_rdata.lpe_rx_ring[cons];
+		hws = &sc->lpe_rdata.lpe_rx_status[cons];
+
+//		device_printf(sc->lpe_dev, "incoming packet: idx=%d len=%d data=%16D\n",
+//		    cons, hws->lhs_info & 0x7ff,
+//		    mtod(rxd->lpe_rxdesc_mbuf, const char *), " ");
+
+
+		m = rxd->lpe_rxdesc_mbuf;
+		m->m_pkthdr.rcvif = ifp;
+		m->m_data += 2;
+
+		(*ifp->if_input)(ifp, m);	
+
+		lpe_init_rxbuf(sc, cons);
+
+		LPE_INC(cons, LPE_RXDESC_NUM);
+		lpe_write_4(sc, LPE_RXDESC_CONS, cons);
+	}
+
+//	device_printf(sc->lpe_dev, "rx: prod=%d cons=%d\n", prod, cons);
 }
 
 static void
 lpe_txintr(struct lpe_softc *sc)
 {
-
+///	device_printf(sc->lpe_dev, "transmit interrupt\n");
 }
 
-#if 0
 static void
 lpe_tick(void *arg)
 {
+	struct lpe_softc *sc = (struct lpe_softc *)arg;
+	//struct mii_data *mii = device_get_softc(sc->lpe_miibus);
+
+	lpe_lock_assert(sc);
+	//mii_tick(mii);
 
+	callout_reset(&sc->lpe_tick, hz, lpe_tick, sc);
 }
-#endif
 
 static int
 lpe_dma_alloc(struct lpe_softc *sc)
@@ -797,6 +912,84 @@
 	return (err);
 }
 
+static int
+lpe_init_rx(struct lpe_softc *sc)
+{
+	int i, err;
+
+	for (i = 0; i < LPE_RXDESC_NUM; i++) {
+		err = lpe_init_rxbuf(sc, i);
+		if (err)
+			return (err);
+	}
+
+	return (0);
+}
+
+static int
+lpe_init_rxbuf(struct lpe_softc *sc, int n)
+{
+	struct lpe_rxdesc *rxd;
+	struct lpe_hwdesc *hwd;
+	struct lpe_hwstatus *hws;
+	struct mbuf *m;
+	bus_dma_segment_t segs[1];
+	int nsegs;
+
+	rxd = &sc->lpe_cdata.lpe_rx_desc[n];
+	hwd = &sc->lpe_rdata.lpe_rx_ring[n];
+	hws = &sc->lpe_rdata.lpe_rx_status[n];
+	m = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR);
+
+	if (!m) {
+		device_printf(sc->lpe_dev, "WARNING: mbufs exhausted!\n");
+		return (ENOBUFS);
+	}
+
+	m->m_len = m->m_pkthdr.len = MCLBYTES;
+
+	bus_dmamap_unload(sc->lpe_cdata.lpe_rx_buf_tag, rxd->lpe_rxdesc_dmamap);
+
+//	printf("i=%d sc=%p lpe_rx_buf_tag=%p lpe_rxdesc_dmamap=%p m=%p\n",
+//		n, sc, sc->lpe_cdata.lpe_rx_buf_tag, rxd->lpe_rxdesc_dmamap, m);
+
+	if (bus_dmamap_load_mbuf_sg(sc->lpe_cdata.lpe_rx_buf_tag, 
+	    rxd->lpe_rxdesc_dmamap, m, segs, &nsegs, 0)) {
+		m_freem(m);
+		return (ENOBUFS);
+	}
+
+	bus_dmamap_sync(sc->lpe_cdata.lpe_rx_buf_tag, rxd->lpe_rxdesc_dmamap, 
+	    BUS_DMASYNC_PREREAD);
+
+	rxd->lpe_rxdesc_mbuf = m;
+	hwd->lhr_data = segs[0].ds_addr + 2;
+	hwd->lhr_control = (segs[0].ds_len - 1) | LPE_HWDESC_INTERRUPT;
+
+	return (0);
+}
+
+#if 0
+static void
+lpe_discard_rxbuf(struct lpe_softc *sc, int n)
+{
+	struct lpe_rxdesc *rxd;
+	struct lpe_hwdesc *hwd;
+
+	rxd = &sc->lpe_cdata.lpe_rx_desc[n];
+	hwd = &sc->lpe_rdata.lpe_rx_ring[n];
+
+	bus_dmamap_unload(rxch->dve_rx_buf_tag, rxd->dve_rxdesc_dmamap);
+
+	hwd->hw_flagslen = 0;
+
+	if (rxd->dve_rxdesc_mbuf) {
+		m_freem(rxd->dve_rxdesc_mbuf); 
+		rxd->dve_rxdesc_mbuf = NULL;
+	}
+}
+#endif
+
 static void
 lpe_dmamap_cb(void *arg, bus_dma_segment_t *segs, int nseg, int error)
 {
@@ -854,6 +1047,6 @@
 
 DRIVER_MODULE(lpe, simplebus, lpe_driver, lpe_devclass, 0, 0);
 DRIVER_MODULE(miibus, lpe, miibus_driver, miibus_devclass, 0, 0);
-MODULE_DEPEND(dve, obio, 1, 1, 1);
-MODULE_DEPEND(dve, miibus, 1, 1, 1);
-MODULE_DEPEND(dve, ether, 1, 1, 1);
+MODULE_DEPEND(lpe, obio, 1, 1, 1);
+MODULE_DEPEND(lpe, miibus, 1, 1, 1);
+MODULE_DEPEND(lpe, ether, 1, 1, 1);

==== //depot/projects/soc2011/jceel_lpc/sys/arm/lpc/if_lpereg.h#2 (text+ko) ====

@@ -151,6 +151,8 @@
 	uint32_t	lhs_crc;
 };
 
+#define	LPE_INC(x, y)		(x) = ((x) == ((y)-1)) ? 0 : (x)+1
+
 /* These are valid for both Rx and Tx descriptors */
 #define	LPE_HWDESC_SIZE_MASK	(1 << 10)
 


More information about the p4-projects mailing list