Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 2 Aug 2002 20:39:28 -0700 (PDT)
From:      Doug Ambrisko <ambrisko@ambrisko.com>
To:        Kal Torak <kaltorak@quake.com.au>
Cc:        FreeBSD ISP <freebsd-isp@FreeBSD.ORG>, FreeBSD Stable <freebsd-stable@FreeBSD.ORG>
Subject:   Re: Problems with D-Link DEF-580TX??
Message-ID:  <200208030339.g733dSD06635@ambrisko.com>
In-Reply-To: <3D461766.6090901@quake.com.au>

next in thread | previous in thread | raw e-mail | index | archive | help
Kal Torak writes:
| Just wondering if anyone has been able to use the new DEF-580TX
| quad port card without any problems??

No ... doesn't seem possible but you can make it happier with these patches.
I need to test under current and then I will commit them.

Seems like the chip has a fundamental problem to block any I/O but it's
own under have RX load.  Happens under Linux, Windows, FreeBSD etc.

The Znyx (http://www.znyx.com/) cards seem to work fine under -stable.
I have the 32 and 64 bit versions of the dc(4) versions.

Doug A.

Index: sys/pci/if_ste.c
===================================================================
RCS file: /cvs/src/sys/pci/if_ste.c,v
retrieving revision 1.14.2.5
diff -u -r1.14.2.5 if_ste.c
--- sys/pci/if_ste.c	16 Dec 2001 15:46:08 -0000	1.14.2.5
+++ sys/pci/if_ste.c	3 Aug 2002 03:36:06 -0000
@@ -45,6 +45,7 @@
 #include <net/ethernet.h>
 #include <net/if_dl.h>
 #include <net/if_media.h>
+#include <net/if_vlan_var.h>
 
 #include <net/bpf.h>
 
@@ -415,6 +416,7 @@
 {
 	struct ste_softc	*sc;
 	struct mii_data		*mii;
+	int			i;
 
 	sc = device_get_softc(dev);
 	mii = device_get_softc(sc->ste_miibus);
@@ -425,6 +427,15 @@
 		STE_CLRBIT2(sc, STE_MACCTL0, STE_MACCTL0_FULLDUPLEX);
 	}
 
+	STE_SETBIT4(sc, STE_ASICCTL,STE_ASICCTL_RX_RESET |
+		    STE_ASICCTL_TX_RESET);
+	for (i = 0; i < STE_TIMEOUT; i++) {
+		if (!(CSR_READ_4(sc, STE_ASICCTL) & STE_ASICCTL_RESET_BUSY))
+			break;
+	}
+	if (i == STE_TIMEOUT)
+		printf("ste%d: rx reset never completed\n", sc->ste_unit);
+
 	return;
 }
  
@@ -643,6 +654,9 @@
 			ste_stats_update(sc);
 		}
 
+		if (status & STE_ISR_LINKEVENT)
+			mii_pollstat(device_get_softc(sc->ste_miibus));
+
 		if (status & STE_ISR_HOSTERR) {
 			ste_reset(sc);
 			ste_init(sc);
@@ -669,17 +683,20 @@
         struct mbuf		*m;
         struct ifnet		*ifp;
 	struct ste_chain_onefrag	*cur_rx;
-	int			total_len = 0;
+	int			total_len = 0, count=0;
 	u_int32_t		rxstat;
 
 	ifp = &sc->arpcom.ac_if;
 
-again:
+	while((rxstat = sc->ste_cdata.ste_rx_head->ste_ptr->ste_status)
+	      & STE_RXSTAT_DMADONE) {
+		if ((STE_RX_LIST_CNT - count) < 3) {
+			break;
+		}
 
-	while((rxstat = sc->ste_cdata.ste_rx_head->ste_ptr->ste_status)) {
 		cur_rx = sc->ste_cdata.ste_rx_head;
 		sc->ste_cdata.ste_rx_head = cur_rx->ste_next;
-
+ 
 		/*
 		 * If an error occurs, update stats, clear the
 		 * status word and leave the mbuf cluster in place:
@@ -730,29 +747,9 @@
 		/* Remove header from mbuf and pass it on. */
 		m_adj(m, sizeof(struct ether_header));
 		ether_input(ifp, eh, m);
-	}
-
-	/*
-	 * Handle the 'end of channel' condition. When the upload
-	 * engine hits the end of the RX ring, it will stall. This
-	 * is our cue to flush the RX ring, reload the uplist pointer
-	 * register and unstall the engine.
-	 * XXX This is actually a little goofy. With the ThunderLAN
-	 * chip, you get an interrupt when the receiver hits the end
-	 * of the receive ring, which tells you exactly when you
-	 * you need to reload the ring pointer. Here we have to
-	 * fake it. I'm mad at myself for not being clever enough
-	 * to avoid the use of a goto here.
-	 */
-	if (CSR_READ_4(sc, STE_RX_DMALIST_PTR) == 0 ||
-		CSR_READ_4(sc, STE_DMACTL) & STE_DMACTL_RXDMA_STOPPED) {
-		STE_SETBIT4(sc, STE_DMACTL, STE_DMACTL_RXDMA_STALL);
-		ste_wait(sc);
-		CSR_WRITE_4(sc, STE_RX_DMALIST_PTR,
-			vtophys(&sc->ste_ldata->ste_rx_list[0]));
-		sc->ste_cdata.ste_rx_head = &sc->ste_cdata.ste_rx_chain[0];
-		STE_SETBIT4(sc, STE_DMACTL, STE_DMACTL_RXDMA_UNSTALL);
-		goto again;
+		
+		cur_rx->ste_ptr->ste_status = 0;
+		count++;
 	}
 
 	return;
@@ -836,11 +833,9 @@
 	void			*xsc;
 {
 	struct ste_softc	*sc;
-	struct ste_stats	stats;
 	struct ifnet		*ifp;
 	struct mii_data		*mii;
-	int			i, s;
-	u_int8_t		*p;
+	int			s;
 
 	s = splimp();
 
@@ -848,24 +843,23 @@
 	ifp = &sc->arpcom.ac_if;
 	mii = device_get_softc(sc->ste_miibus);
 
-	p = (u_int8_t *)&stats;
-
-	for (i = 0; i < sizeof(stats); i++) {
-		*p = CSR_READ_1(sc, STE_STATS + i);
-		p++;
-	}
-
-	ifp->if_collisions += stats.ste_single_colls +
-	    stats.ste_multi_colls + stats.ste_late_colls;
+        ifp->if_collisions += CSR_READ_1(sc, STE_LATE_COLLS)
+            + CSR_READ_1(sc, STE_MULTI_COLLS)
+            + CSR_READ_1(sc, STE_SINGLE_COLLS);
 
-	mii_tick(mii);
 	if (!sc->ste_link) {
 		mii_pollstat(mii);
 		if (mii->mii_media_status & IFM_ACTIVE &&
-		    IFM_SUBTYPE(mii->mii_media_active) != IFM_NONE)
+		    IFM_SUBTYPE(mii->mii_media_active) != IFM_NONE) {
 			sc->ste_link++;
+			/* 
+			 * we don't get a call-back on re-init so do it 
+			 * otherwise we get stuck in the wrong link state
+			 */
+			ste_miibus_statchg(sc->ste_dev);
 			if (ifp->if_snd.ifq_head != NULL)
 				ste_start(ifp);
+		}
 	}
 
 	sc->ste_stat_ch = timeout(ste_stats_update, sc, hz);
@@ -916,6 +910,7 @@
 	sc = device_get_softc(dev);
 	unit = device_get_unit(dev);
 	bzero(sc, sizeof(struct ste_softc));
+	sc->ste_dev = dev;
 
 	/*
 	 * Handle power management nonsense.
@@ -1069,11 +1064,18 @@
 	ifp->if_baudrate = 10000000;
 	ifp->if_snd.ifq_maxlen = STE_TX_LIST_CNT - 1;
 
+	sc->ste_tx_thresh = STE_TXSTART_THRESH;
+
 	/*
 	 * Call MI attach routine.
 	 */
 	ether_ifattach(ifp, ETHER_BPF_SUPPORTED);
 
+        /*
+         * Tell the upper layer(s) we support long frames.
+         */
+        ifp->if_data.ifi_hdrlen = sizeof(struct ether_vlan_header);
+ 
 fail:
 	splx(s);
 	return(error);
@@ -1136,7 +1138,7 @@
 	c->ste_mbuf = m_new;
 	c->ste_ptr->ste_status = 0;
 	c->ste_ptr->ste_frag.ste_addr = vtophys(mtod(m_new, caddr_t));
-	c->ste_ptr->ste_frag.ste_len = 1536 | STE_FRAG_LAST;
+	c->ste_ptr->ste_frag.ste_len = (1536 + EVL_ENCAPLEN) | STE_FRAG_LAST;
 
 	return(0);
 }
@@ -1166,7 +1168,7 @@
 			ld->ste_rx_list[i].ste_next =
 			    vtophys(&ld->ste_rx_list[i + 1]);
 		}
-
+		ld->ste_rx_list[i].ste_status = 0;
 	}
 
 	cd->ste_rx_head = &cd->ste_rx_chain[0];
@@ -1185,6 +1187,8 @@
 	ld = sc->ste_ldata;
 	for (i = 0; i < STE_TX_LIST_CNT; i++) {
 		cd->ste_tx_chain[i].ste_ptr = &ld->ste_tx_list[i];
+		cd->ste_tx_chain[i].ste_ptr->ste_next = 0;
+		cd->ste_tx_chain[i].ste_ptr->ste_ctl  = 0;
 		cd->ste_tx_chain[i].ste_phys = vtophys(&ld->ste_tx_list[i]);
 		if (i == (STE_TX_LIST_CNT - 1))
 			cd->ste_tx_chain[i].ste_next =
@@ -1200,10 +1204,6 @@
 			     &cd->ste_tx_chain[i - 1];
 	}
 
-
-	bzero((char *)ld->ste_tx_list,
-	    sizeof(struct ste_desc) * STE_TX_LIST_CNT);
-
 	cd->ste_tx_prod = 0;
 	cd->ste_tx_cons = 0;
 	cd->ste_tx_cnt = 0;
@@ -1241,6 +1241,9 @@
 		return;
 	}
 
+	/* Set RX polling interval */
+	CSR_WRITE_1(sc, STE_RX_DMAPOLL_PERIOD, 1);
+
 	/* Init TX descriptors */
 	ste_init_tx_list(sc);
 
@@ -1280,20 +1283,21 @@
 	STE_SETBIT4(sc, STE_DMACTL, STE_DMACTL_RXDMA_UNSTALL);
 	STE_SETBIT4(sc, STE_DMACTL, STE_DMACTL_RXDMA_UNSTALL);
 
-	/* Set TX polling interval */
-	CSR_WRITE_1(sc, STE_TX_DMAPOLL_PERIOD, 64);
+	/* Set TX polling interval (defer until we TX first packet */
+	CSR_WRITE_1(sc, STE_TX_DMAPOLL_PERIOD, 0);
 
 	/* Load address of the TX list */
 	STE_SETBIT4(sc, STE_DMACTL, STE_DMACTL_TXDMA_STALL);
 	ste_wait(sc);
-	CSR_WRITE_4(sc, STE_TX_DMALIST_PTR,
-	    vtophys(&sc->ste_ldata->ste_tx_list[0]));
+	CSR_WRITE_4(sc, STE_TX_DMALIST_PTR, 0);
 	STE_SETBIT4(sc, STE_DMACTL, STE_DMACTL_TXDMA_UNSTALL);
 	STE_SETBIT4(sc, STE_DMACTL, STE_DMACTL_TXDMA_UNSTALL);
 	ste_wait(sc);
+	sc->ste_tx_prev_idx=-1;
 
 	/* Enable receiver and transmitter */
 	CSR_WRITE_2(sc, STE_MACCTL0, 0);
+	CSR_WRITE_2(sc, STE_MACCTL1, 0);
 	STE_SETBIT2(sc, STE_MACCTL1, STE_MACCTL1_TX_ENABLE);
 	STE_SETBIT2(sc, STE_MACCTL1, STE_MACCTL1_RX_ENABLE);
 
@@ -1304,6 +1308,9 @@
 	CSR_WRITE_2(sc, STE_ISR, 0xFFFF);
 	CSR_WRITE_2(sc, STE_IMR, STE_INTRS);
 
+	/* Accept VLAN length packets */
+	CSR_WRITE_2(sc, STE_MAX_FRAMELEN, ETHER_MAX_LEN + EVL_ENCAPLEN);
+
 	ste_ifmedia_upd(ifp);
 
 	ifp->if_flags |= IFF_RUNNING;
@@ -1333,6 +1340,11 @@
 	STE_SETBIT2(sc, STE_DMACTL, STE_DMACTL_TXDMA_STALL);
 	STE_SETBIT2(sc, STE_DMACTL, STE_DMACTL_RXDMA_STALL);
 	ste_wait(sc);
+	/* 
+	 * Try really hard to stop the RX engine or under heavy RX 
+	 * data chip will write into de-allocated memory.
+	 */
+	ste_reset(sc);
 
 	sc->ste_link = 0;
 
@@ -1350,6 +1362,8 @@
 		}
 	}
 
+	bzero(sc->ste_ldata, sizeof(struct ste_list_data));
+
 	ifp->if_flags &= ~(IFF_RUNNING|IFF_OACTIVE);
 
 	return;
@@ -1413,8 +1427,10 @@
 			    sc->ste_if_flags & IFF_PROMISC) {
 				STE_CLRBIT1(sc, STE_RX_MODE,
 				    STE_RXMODE_PROMISC);
-			} else if (!(ifp->if_flags & IFF_RUNNING)) {
-				sc->ste_tx_thresh = STE_MIN_FRAMELEN;
+			} 
+			if (!(ifp->if_flags & IFF_RUNNING)) {
+				sc->ste_tx_thresh = STE_MIN_FRAMELEN * 2;
+				sc->ste_tx_thresh = STE_TXSTART_THRESH;
 				ste_init(sc);
 			}
 		} else {
@@ -1457,14 +1473,13 @@
 
 	d = c->ste_ptr;
 	d->ste_ctl = 0;
-	d->ste_next = 0;
 
 	for (m = m_head, frag = 0; m != NULL; m = m->m_next) {
 		if (m->m_len != 0) {
 			if (frag == STE_MAXFRAGS)
 				break;
 			total_len += m->m_len;
-			f = &c->ste_ptr->ste_frags[frag];
+			f = &d->ste_frags[frag];
 			f->ste_addr = vtophys(mtod(m, vm_offset_t));
 			f->ste_len = m->m_len;
 			frag++;
@@ -1472,8 +1487,8 @@
 	}
 
 	c->ste_mbuf = m_head;
-	c->ste_ptr->ste_frags[frag - 1].ste_len |= STE_FRAG_LAST;
-	c->ste_ptr->ste_ctl = total_len;
+	d->ste_frags[frag - 1].ste_len |= STE_FRAG_LAST;
+	d->ste_ctl = 1;
 
 	return(0);
 }
@@ -1483,7 +1498,7 @@
 {
 	struct ste_softc	*sc;
 	struct mbuf		*m_head = NULL;
-	struct ste_chain	*prev = NULL, *cur_tx = NULL, *start_tx;
+	struct ste_chain	*cur_tx = NULL;
 	int			idx;
 
 	sc = ifp->if_softc;
@@ -1495,7 +1510,6 @@
 		return;
 
 	idx = sc->ste_cdata.ste_tx_prod;
-	start_tx = &sc->ste_cdata.ste_tx_chain[idx];
 
 	while(sc->ste_cdata.ste_tx_chain[idx].ste_mbuf == NULL) {
 
@@ -1512,9 +1526,32 @@
 
 		ste_encap(sc, cur_tx, m_head);
 
-		if (prev != NULL)
-			prev->ste_ptr->ste_next = cur_tx->ste_phys;
-		prev = cur_tx;
+		cur_tx->ste_ptr->ste_next = 0;
+
+		if(sc->ste_tx_prev_idx < 0){
+			cur_tx->ste_ptr->ste_ctl = STE_TXCTL_DMAINTR | 1;
+			/* Load address of the TX list */
+			STE_SETBIT4(sc, STE_DMACTL, STE_DMACTL_TXDMA_STALL);
+			ste_wait(sc);
+
+			CSR_WRITE_4(sc, STE_TX_DMALIST_PTR,
+			    vtophys(&sc->ste_ldata->ste_tx_list[0]));
+
+			/* Set TX polling interval to start TX engine */
+			CSR_WRITE_1(sc, STE_TX_DMAPOLL_PERIOD, 64);
+		  
+			STE_SETBIT4(sc, STE_DMACTL, STE_DMACTL_TXDMA_UNSTALL);
+			STE_SETBIT4(sc, STE_DMACTL, STE_DMACTL_TXDMA_UNSTALL);
+			ste_wait(sc);
+
+		}else{
+			cur_tx->ste_ptr->ste_ctl = STE_TXCTL_DMAINTR | 1;
+			sc->ste_cdata.ste_tx_chain[
+			    sc->ste_tx_prev_idx].ste_ptr->ste_next
+				= cur_tx->ste_phys;
+		}
+
+		sc->ste_tx_prev_idx=idx;
 
 		/*
 		 * If there's a BPF listener, bounce a copy of this frame
@@ -1525,18 +1562,9 @@
 
 		STE_INC(idx, STE_TX_LIST_CNT);
 		sc->ste_cdata.ste_tx_cnt++;
+		ifp->if_timer = 5;
+		sc->ste_cdata.ste_tx_prod = idx;
 	}
-
-	if (cur_tx == NULL)
-		return;
-
-	cur_tx->ste_ptr->ste_ctl |= STE_TXCTL_DMAINTR;
-
-	/* Start transmission */
-	sc->ste_cdata.ste_tx_prod = idx;
-	start_tx->ste_prev->ste_ptr->ste_next = start_tx->ste_phys;
-
-	ifp->if_timer = 5;
 
 	return;
 }
Index: sys/pci/if_stereg.h
===================================================================
RCS file: /cvs/src/sys/pci/if_stereg.h,v
retrieving revision 1.5.2.1
diff -u -r1.5.2.1 if_stereg.h
--- sys/pci/if_stereg.h	23 Aug 2001 20:04:06 -0000	1.5.2.1
+++ sys/pci/if_stereg.h	3 Aug 2002 03:36:06 -0000
@@ -93,6 +93,10 @@
 #define STE_MAR3		0x66
 #define STE_STATS		0x68
 
+#define STE_LATE_COLLS  0x75
+#define STE_MULTI_COLLS	0x76
+#define STE_SINGLE_COLLS 0x77	
+
 #define STE_DMACTL_RXDMA_STOPPED	0x00000001
 #define STE_DMACTL_TXDMA_CMPREQ		0x00000002
 #define STE_DMACTL_TXDMA_STOPPED	0x00000004
@@ -224,13 +228,13 @@
  * The number of bytes that must in present in the TX FIFO before
  * transmission begins. Value should be in increments of 4 bytes.
  */
-#define STE_TXSTART_THRESH		0x1FFF
+#define STE_TXSTART_THRESH		0x1FFC
 
 /*
  * Number of bytes that must be present in the RX FIFO before
  * an RX EARLY interrupt is generated.
  */
-#define STE_RXEARLY_THRESH		0x1FFF
+#define STE_RXEARLY_THRESH		0x1FFC
 
 #define STE_WAKEEVENT_WAKEPKT_ENB	0x01
 #define STE_WAKEEVENT_MAGICPKT_ENB	0x02
@@ -272,8 +276,9 @@
 #define STE_IMR_RX_DMADONE		0x0400
 
 #define STE_INTRS					\
-	(STE_IMR_RX_DMADONE|STE_IMR_TX_DMADONE|STE_IMR_STATS_OFLOW|	\
-	STE_IMR_TX_DONE|STE_IMR_HOSTERR|STE_IMR_RX_EARLY)
+	(STE_IMR_RX_DMADONE|STE_IMR_TX_DMADONE|	\
+	STE_IMR_TX_DONE|STE_IMR_HOSTERR| \
+        STE_IMR_LINKEVENT)
 
 #define STE_ISR_INTLATCH		0x0001
 #define STE_ISR_HOSTERR			0x0002
@@ -406,7 +411,7 @@
 #define STE_FRAG_LAST		0x80000000
 #define STE_FRAG_LEN		0x00001FFF
 
-#define STE_MAXFRAGS	63
+#define STE_MAXFRAGS	8
 
 struct ste_desc {
 	u_int32_t		ste_next;
@@ -460,9 +465,10 @@
 #define STE_MIN_FRAMELEN	60
 #define STE_PACKET_SIZE		1536
 #define ETHER_ALIGN		2
-#define STE_RX_LIST_CNT		128
-#define STE_TX_LIST_CNT		256
+#define STE_RX_LIST_CNT		64
+#define STE_TX_LIST_CNT		64
 #define STE_INC(x, y)		(x) = (x + 1) % y
+#define STE_NEXT(x, y)		(x + 1) % y
 
 struct ste_type {
 	u_int16_t		ste_vid;
@@ -509,10 +515,12 @@
 	void			*ste_intrhand;
 	struct ste_type		*ste_info;
 	device_t		ste_miibus;
+	device_t		ste_dev;
 	int			ste_unit;
 	int			ste_tx_thresh;
 	u_int8_t		ste_link;
 	int			ste_if_flags;
+	int			ste_tx_prev_idx;
 	struct ste_list_data	*ste_ldata;
 	struct ste_chain_data	ste_cdata;
 	struct callout_handle	ste_stat_ch;

To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-isp" in the body of the message




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