Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 7 Feb 2003 23:48:04 +0100
From:      Martin Blapp <mb@imp.ch>
To:        freebsd-stable@freebsd.org
Cc:        hackers@freebsd.org
Subject:   HEADS UP: Broken if_dc NICs with MACs like 08:08[...] or 00:00[...]
Message-ID:  <Pine.SGI.4.44.0302072336080.4468343-100000@nbs.imp.ch>

next in thread | raw e-mail | index | archive | help

Hi all,

Many if_dc cards are still broken in RELENG_4. Can you please
try this diff if you own such a broken card ?

If you have a Conexant LANfinity MiniPCI 10/100BaseTX card, I'd like
to have feedback if full duplex mode works now too.

Thank you very much for your tests. I'd like to see all these
DEC/Intel 21143 clone cards fixed for 4.8R.

Martin

-----------------------------------------------------------------

http://people.freebsd.org/~mbr/patches/if_dc.c-MFC.diff

MFC Rev. 1.80, 1.81

Dynamically configure the width of the srom.  This code comes from
OpenBSD who got the code (or the idea) from the NetBSD tlp driver.

MFC Rev. 1.67

Fix Conexant chips which always reports carrier lost
on full duplex mode.

Index: if_dc.c
===================================================================
RCS file: /home/ncvs/src/sys/pci/if_dc.c,v
retrieving revision 1.9.2.38
diff -u -r1.9.2.38 if_dc.c
--- if_dc.c	5 Feb 2003 22:10:04 -0000	1.9.2.38
+++ if_dc.c	7 Feb 2003 19:01:18 -0000
@@ -223,6 +223,7 @@
 static void dc_eeprom_getword	__P((struct dc_softc *, int, u_int16_t *));
 static void dc_eeprom_getword_pnic
 				__P((struct dc_softc *, int, u_int16_t *));
+static void dc_eeprom_width	__P((struct dc_softc *));
 static void dc_read_eeprom	__P((struct dc_softc *, caddr_t, int,
 							int, int));

@@ -250,6 +251,7 @@
 static int dc_list_rx_init	__P((struct dc_softc *));
 static int dc_list_tx_init	__P((struct dc_softc *));

+static void dc_read_srom	__P((struct dc_softc *, int));
 static void dc_parse_21143_srom	__P((struct dc_softc *));
 static void dc_decode_leaf_sia	__P((struct dc_softc *,
 				    struct dc_eblock_sia *));
@@ -324,6 +326,70 @@
 		CSR_READ_4(sc, DC_BUSCTL);
 }

+static void dc_eeprom_width(sc)
+	struct dc_softc		*sc;
+{
+	int i;
+
+	/* Force EEPROM to idle state. */
+	dc_eeprom_idle(sc);
+
+	/* Enter EEPROM access mode. */
+	CSR_WRITE_4(sc, DC_SIO, DC_SIO_EESEL);
+	dc_delay(sc);
+	DC_SETBIT(sc, DC_SIO, DC_SIO_ROMCTL_READ);
+	dc_delay(sc);
+	DC_CLRBIT(sc, DC_SIO, DC_SIO_EE_CLK);
+	dc_delay(sc);
+	DC_SETBIT(sc, DC_SIO, DC_SIO_EE_CS);
+	dc_delay(sc);
+
+	for (i = 3; i--;) {
+		if (6 & (1 << i))
+			DC_SETBIT(sc, DC_SIO, DC_SIO_EE_DATAIN);
+		else
+			DC_CLRBIT(sc, DC_SIO, DC_SIO_EE_DATAIN);
+		dc_delay(sc);
+		DC_SETBIT(sc, DC_SIO, DC_SIO_EE_CLK);
+		dc_delay(sc);
+		DC_CLRBIT(sc, DC_SIO, DC_SIO_EE_CLK);
+		dc_delay(sc);
+	}
+
+	for (i = 1; i <= 12; i++) {
+		DC_SETBIT(sc, DC_SIO, DC_SIO_EE_CLK);
+		dc_delay(sc);
+		if (!(CSR_READ_4(sc, DC_SIO) & DC_SIO_EE_DATAOUT)) {
+			DC_CLRBIT(sc, DC_SIO, DC_SIO_EE_CLK);
+			dc_delay(sc);
+			break;
+		}
+		DC_CLRBIT(sc, DC_SIO, DC_SIO_EE_CLK);
+		dc_delay(sc);
+	}
+
+	/* Turn off EEPROM access mode. */
+	dc_eeprom_idle(sc);
+
+	if (i < 4 || i > 12)
+		sc->dc_romwidth = 6;
+	else
+		sc->dc_romwidth = i;
+
+	/* Enter EEPROM access mode. */
+	CSR_WRITE_4(sc, DC_SIO, DC_SIO_EESEL);
+	dc_delay(sc);
+	DC_SETBIT(sc, DC_SIO, DC_SIO_ROMCTL_READ);
+	dc_delay(sc);
+	DC_CLRBIT(sc, DC_SIO, DC_SIO_EE_CLK);
+	dc_delay(sc);
+	DC_SETBIT(sc, DC_SIO, DC_SIO_EE_CS);
+	dc_delay(sc);
+
+	/* Turn off EEPROM access mode. */
+	dc_eeprom_idle(sc);
+}
+
 static void dc_eeprom_idle(sc)
 	struct dc_softc		*sc;
 {
@@ -363,21 +429,24 @@
 {
 	register int		d, i;

-	/*
-	 * The AN985 has a 93C66 EEPROM on it instead of
-	 * a 93C46. It uses a different bit sequence for
-	 * specifying the "read" opcode.
-	 */
-	if (DC_IS_CENTAUR(sc) || DC_IS_CONEXANT(sc))
-		d = addr | (DC_EECMD_READ << 2);
-	else
-		d = addr | DC_EECMD_READ;
+	d = DC_EECMD_READ >> 6;
+	for (i = 3; i--; ) {
+		if (d & (1 << i))
+			DC_SETBIT(sc, DC_SIO, DC_SIO_EE_DATAIN);
+		else
+			DC_CLRBIT(sc, DC_SIO, DC_SIO_EE_DATAIN);
+		dc_delay(sc);
+		DC_SETBIT(sc, DC_SIO, DC_SIO_EE_CLK);
+		dc_delay(sc);
+		DC_CLRBIT(sc, DC_SIO, DC_SIO_EE_CLK);
+		dc_delay(sc);
+	}

 	/*
 	 * Feed in each bit and strobe the clock.
 	 */
-	for (i = 0x400; i; i >>= 1) {
-		if (d & i) {
+	for (i = sc->dc_romwidth; i--;) {
+		if (addr & (1 << i)) {
 			SIO_SET(DC_SIO_EE_DATAIN);
 		} else {
 			SIO_CLR(DC_SIO_EE_DATAIN);
@@ -1572,6 +1641,7 @@

 	m->dc_next = sc->dc_mi;
 	sc->dc_mi = m;
+	free(sc->dc_srom, M_DEVBUF);

 	sc->dc_pmode = DC_PMODE_SIA;

@@ -1630,6 +1700,17 @@
 	return;
 }

+static void dc_read_srom(sc, bits)
+	struct dc_softc		*sc;
+	int			bits;
+{
+	int size;
+
+	size = 2 << bits;
+	sc->dc_srom = malloc(size, M_DEVBUF, M_NOWAIT);
+	dc_read_eeprom(sc, (caddr_t)sc->dc_srom, 0, (size / 2), 0);
+}
+
 static void dc_parse_21143_srom(sc)
 	struct dc_softc		*sc;
 {
@@ -1753,13 +1834,17 @@
 	sc->dc_info = dc_devtype(dev);
 	revision = pci_read_config(dev, DC_PCI_CFRV, 4) & 0x000000FF;

+	/* Get the eeprom width, but PNIC has no eeprom */
+	if (sc->dc_info->dc_did != DC_DEVICEID_82C168)
+		dc_eeprom_width(sc);
+
 	switch(sc->dc_info->dc_did) {
 	case DC_DEVICEID_21143:
 		sc->dc_type = DC_TYPE_21143;
 		sc->dc_flags |= DC_TX_POLL|DC_TX_USE_TX_INTR;
 		sc->dc_flags |= DC_REDUCED_MII_POLL;
 		/* Save EEPROM contents so we can parse them later. */
-		dc_read_eeprom(sc, (caddr_t)&sc->dc_srom, 0, 512, 0);
+		dc_read_srom(sc, sc->dc_romwidth);
 		break;
 	case DC_DEVICEID_DM9009:
 	case DC_DEVICEID_DM9100:
@@ -1779,6 +1864,7 @@
 		sc->dc_flags |= DC_TX_USE_TX_INTR;
 		sc->dc_flags |= DC_TX_ADMTEK_WAR;
 		sc->dc_pmode = DC_PMODE_MII;
+		dc_read_srom(sc, sc->dc_romwidth);
 		break;
 	case DC_DEVICEID_AN985:
 	case DC_DEVICEID_EN2242:
@@ -1786,6 +1872,7 @@
 		sc->dc_flags |= DC_TX_USE_TX_INTR;
 		sc->dc_flags |= DC_TX_ADMTEK_WAR;
 		sc->dc_pmode = DC_PMODE_MII;
+		dc_read_srom(sc, sc->dc_romwidth);
 		break;
 	case DC_DEVICEID_98713:
 	case DC_DEVICEID_98713_CP:
@@ -1844,7 +1931,7 @@
 		sc->dc_flags |= DC_TX_INTR_ALWAYS;
 		sc->dc_flags |= DC_REDUCED_MII_POLL;
 		sc->dc_pmode = DC_PMODE_MII;
-		dc_read_eeprom(sc, (caddr_t)&sc->dc_srom, 0, 256, 0);
+		dc_read_srom(sc, sc->dc_romwidth);
 		break;
 	default:
 		printf("dc%d: unknown device: %x\n", sc->dc_unit,
@@ -1908,6 +1995,8 @@
 		break;
 	case DC_TYPE_AL981:
 	case DC_TYPE_AN985:
+		bcopy(&sc->dc_srom[DC_AL_EE_NODEADDR], (caddr_t)&eaddr,
+		    ETHER_ADDR_LEN);
 		dc_read_eeprom(sc, (caddr_t)&eaddr, DC_AL_EE_NODEADDR, 3, 0);
 		break;
 	case DC_TYPE_CONEXANT:
@@ -2468,13 +2557,13 @@
  * the list buffers.
  */

-static void dc_txeof(sc)
+static void
+dc_txeof(sc)
 	struct dc_softc		*sc;
 {
 	struct dc_desc		*cur_tx = NULL;
 	struct ifnet		*ifp;
 	int			idx;
-	u_int32_t		errmask;

 	ifp = &sc->arpcom.ac_if;

@@ -2494,7 +2583,6 @@

 		if (!(cur_tx->dc_ctl & DC_TXCTL_LASTFRAG) ||
 		    cur_tx->dc_ctl & DC_TXCTL_SETUP) {
-			sc->dc_cdata.dc_tx_cnt--;
 			if (cur_tx->dc_ctl & DC_TXCTL_SETUP) {
 				/*
 				 * Yes, the PNIC is so brain damaged
@@ -2511,21 +2599,29 @@
 				}
 				sc->dc_cdata.dc_tx_chain[idx] = NULL;
 			}
+			sc->dc_cdata.dc_tx_cnt--;
 			DC_INC(idx, DC_TX_LIST_CNT);
 			continue;
 		}

-		if (sc->dc_pmode == DC_PMODE_MII) {
-			errmask = DC_TXSTAT_ERRSUM|
-			    DC_TXSTAT_NOCARRIER|DC_TXSTAT_CARRLOST;
+		if (DC_IS_CONEXANT(sc)) {
 			/*
-			 * The Conexant chip always reports carrier lost
-			 * in full duplex modes.
+			 * For some reason Conexant chips like
+			 * setting the CARRLOST flag even when
+			 * the carrier is there. In CURRENT we
+			 * have the same problem for Xircom
+			 * cards !
 			 */
-			if (DC_IS_CONEXANT(sc) && (sc->dc_if_media & IFM_FDX)) {
-				errmask &= ~DC_TXSTAT_CARRLOST;
-			}
-			if ((txstat & 0xFFFF) & ~errmask)
+			if (/*sc->dc_type == DC_TYPE_21143 &&*/
+			    sc->dc_pmode == DC_PMODE_MII &&
+			    ((txstat & 0xFFFF) & ~(DC_TXSTAT_ERRSUM|
+			    DC_TXSTAT_NOCARRIER)))
+				txstat &= ~DC_TXSTAT_ERRSUM;
+		} else {
+			if (/*sc->dc_type == DC_TYPE_21143 &&*/
+			    sc->dc_pmode == DC_PMODE_MII &&
+			    ((txstat & 0xFFFF) & ~(DC_TXSTAT_ERRSUM|
+			    DC_TXSTAT_NOCARRIER|DC_TXSTAT_CARRLOST)))
 				txstat &= ~DC_TXSTAT_ERRSUM;
 		}

@@ -2553,11 +2649,13 @@
 		DC_INC(idx, DC_TX_LIST_CNT);
 	}

-        if (idx != sc->dc_cdata.dc_tx_cons) {
+	if (idx != sc->dc_cdata.dc_tx_cons) {
+	    	/* some buffers have been freed */
 		sc->dc_cdata.dc_tx_cons = idx;
-                ifp->if_flags &= ~IFF_OACTIVE;
-        }
-        ifp->if_timer = (sc->dc_cdata.dc_tx_cnt == 0) ? 0 : 5;
+		ifp->if_flags &= ~IFF_OACTIVE;
+	}
+	ifp->if_timer = (sc->dc_cdata.dc_tx_cnt == 0) ? 0 : 5;
+
 	return;
 }

Index: if_dcreg.h
===================================================================
RCS file: /home/ncvs/src/sys/pci/if_dcreg.h,v
retrieving revision 1.4.2.20
diff -u -r1.4.2.20 if_dcreg.h
--- if_dcreg.h	5 Feb 2003 22:10:04 -0000	1.4.2.20
+++ if_dcreg.h	7 Feb 2003 19:01:18 -0000
@@ -688,13 +688,14 @@
 	u_int8_t		dc_pmode;
 	u_int8_t		dc_link;
 	u_int8_t		dc_cachesize;
+	int			dc_romwidth;
 	int			dc_pnic_rx_bug_save;
 	unsigned char		*dc_pnic_rx_buf;
 	int			dc_if_flags;
 	int			dc_if_media;
 	u_int32_t		dc_flags;
 	u_int32_t		dc_txthresh;
-	u_int8_t		dc_srom[1024];
+	u_int8_t		*dc_srom;
 	struct dc_mediainfo	*dc_mi;
 	struct dc_list_data	*dc_ldata;
 	struct dc_chain_data	dc_cdata;

Martin Blapp, <mb@imp.ch> <mbr@FreeBSD.org>
------------------------------------------------------------------
ImproWare AG, UNIXSP & ISP, Zurlindenstrasse 29, 4133 Pratteln, CH
Phone: +41 61 826 93 00 Fax: +41 61 826 93 01
PGP: <finger -l mbr@freebsd.org>
PGP Fingerprint: B434 53FC C87C FE7B 0A18 B84C 8686 EF22 D300 551E
------------------------------------------------------------------



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




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?Pine.SGI.4.44.0302072336080.4468343-100000>