Subject: kern/9675: tlp0: sorry, unable to handle your board
To: None <gnats-bugs@gnats.netbsd.org>
From: Manuel Bouyer <bouyer@antioche.lip6.fr>
List: netbsd-bugs
Date: 03/26/2000 08:21:42
>Number: 9675
>Category: kern
>Synopsis: tlp0: sorry, unable to handle your board
>Confidential: no
>Severity: serious
>Priority: medium
>Responsible: kern-bug-people (Kernel Bug People)
>State: open
>Class: sw-bug
>Submitter-Id: net
>Arrival-Date: Sun Mar 26 08:15:00 2000
>Last-Modified:
>Originator:
>Organization:
LIP6
>Release: -current as of yesterday
>Environment:
System: NetBSD armandeche 1.4W NetBSD 1.4W (ARMANDECHE) #2: Sun Mar 26 17:39:32 MEST 2000 bouyer@armandeche:/home/cvs.netbsd.org/src/sys/arch/i386/compile/ARMANDECHE i386
>Description:
I have a 21140A-based SMC board which used to work fine with the
TLP driver:
tlp0 at pci0 dev 9 function 0: DECchip 21140A Ethernet, pass 2.0
tlp0: interrupting at irq 5
tlp0: Ethernet address 00:00:c0:f1:ee:e9
nsphy0 at tlp0 phy 3: DP83840 10/100 media interface, rev. 0
nsphy0: 10baseT, 10baseT-FDX, 100baseTX, 100baseTX-FDX, auto
tlp0: supplying EUI64: 00:00:c0:ff:fe:f1:ee:e9
I haven't upgraded this box for a while (previous kernel
was from early march) but I had to compile a new kernel from fresh
sources. With the new kernel I get:
tlp0 at pci0 dev 9 function 0: DECchip 21140A Ethernet, pass 2.0
tlp0: sorry, unable to handle your board
and of course the board is unusable
>How-To-Repeat:
boot -current in a box with a 21140A-based SMC board; I think other
boards based on the 21140A may have the same problem.
>Fix:
I narrowed the problem down to tlp_isv_srom_enaddr() failing.
dev/ic/tulip.c 1.46->1.47
dev/pci/if_tlp_pci.c 1.32->1.33
sys/dev/ic/tulipvar.h 1.28->1.29
(single change, commit message was:
Determine the size of the SROM by probing the chip using the standard Microwire
protocol. Eliminates the need for srom_quirks and some other trash.)
and my board is working again.
I provide the diff as a workaroud for peoples who have the same
problem, but obviously this is not the rigth solution :)
Index: ic/tulip.c
===================================================================
RCS file: /cvsroot/syssrc/sys/dev/ic/tulip.c,v
retrieving revision 1.56
diff -u -r1.56 tulip.c
--- tulip.c 2000/03/23 07:01:33 1.56
+++ tulip.c 2000/03/26 16:02:57
@@ -1,4 +1,4 @@
-/* $NetBSD: tulip.c,v 1.56 2000/03/23 07:01:33 thorpej Exp $ */
+/* $NetBSD: tulip.c,v 1.46 2000/03/06 21:02:01 thorpej Exp $ */
/*-
* Copyright (c) 1998, 1999, 2000 The NetBSD Foundation, Inc.
@@ -153,7 +153,6 @@
int tlp_add_rxbuf __P((struct tulip_softc *, int));
void tlp_idle __P((struct tulip_softc *, u_int32_t));
void tlp_srom_idle __P((struct tulip_softc *));
-int tlp_srom_size __P((struct tulip_softc *));
int tlp_enable __P((struct tulip_softc *));
void tlp_disable __P((struct tulip_softc *));
@@ -630,9 +629,6 @@
shutdownhook_disestablish(sc->sc_sdhook);
powerhook_disestablish(sc->sc_powerhook);
- if (sc->sc_srom)
- free(sc->sc_srom, M_DEVBUF);
-
return (0);
}
@@ -2011,7 +2007,7 @@
#define SROM_EMIT(sc, x) \
do { \
TULIP_WRITE((sc), CSR_MIIROM, (x)); \
- delay(2); \
+ delay(1); \
} while (0)
/*
@@ -2037,8 +2033,8 @@
SROM_EMIT(sc, miirom|MIIROM_SROMSK);
- /* Strobe the clock 32 times. */
- for (i = 0; i < 32; i++) {
+ /* Strobe the clock 25 times. */
+ for (i = 0; i < 25; i++) {
SROM_EMIT(sc, miirom);
SROM_EMIT(sc, miirom|MIIROM_SROMSK);
}
@@ -2052,90 +2048,22 @@
}
/*
- * tlp_srom_size:
- *
- * Determine the number of address bits in the SROM.
- */
-int
-tlp_srom_size(sc)
- struct tulip_softc *sc;
-{
- u_int32_t miirom;
- int x;
-
- /* Select the SROM. */
- miirom = MIIROM_SR;
- SROM_EMIT(sc, miirom);
-
- miirom |= MIIROM_RD;
- SROM_EMIT(sc, miirom);
-
- /* Send CHIP SELECT for one clock tick. */
- miirom |= MIIROM_SROMCS;
- SROM_EMIT(sc, miirom);
-
- /* Shift in the READ opcode. */
- for (x = 3; x > 0; x--) {
- if (TULIP_SROM_OPC_READ & (1 << (x - 1)))
- miirom |= MIIROM_SROMDI;
- else
- miirom &= ~MIIROM_SROMDI;
- SROM_EMIT(sc, miirom);
- SROM_EMIT(sc, miirom|MIIROM_SROMSK);
- SROM_EMIT(sc, miirom);
- }
-
- /* Shift in address and look for dummy 0 bit. */
- for (x = 1; x <= 12; x++) {
- miirom &= ~MIIROM_SROMDI;
- SROM_EMIT(sc, miirom);
- SROM_EMIT(sc, miirom|MIIROM_SROMSK);
- if (!TULIP_ISSET(sc, CSR_MIIROM, MIIROM_SROMDO))
- break;
- SROM_EMIT(sc, miirom);
- }
-
- /* Clear CHIP SELECT. */
- miirom &= ~MIIROM_SROMCS;
- SROM_EMIT(sc, miirom);
-
- /* Deselect the SROM. */
- SROM_EMIT(sc, 0);
-
- if (x > 12) {
- printf("%s: failed to find SROM size\n", sc->sc_dev.dv_xname);
- return (0);
- } else {
-#ifdef TLP_DEBUG
- printf("%s: SROM size is 2^%d*16 bits (%d bytes)\n",
- sc->sc_dev.dv_xname, x, (1 << (x + 4)) >> 3);
-#endif
- return (x);
- }
-}
-
-/*
* tlp_read_srom:
*
* Read the Tulip SROM.
*/
-int
-tlp_read_srom(sc)
+void
+tlp_read_srom(sc, word, wordcnt, data)
struct tulip_softc *sc;
+ int word, wordcnt;
+ u_int8_t *data;
{
- int size;
u_int32_t miirom;
u_int16_t datain;
int i, x;
tlp_srom_idle(sc);
- sc->sc_srom_addrbits = tlp_srom_size(sc);
- if (sc->sc_srom_addrbits == 0)
- return (0);
- size = TULIP_ROM_SIZE(sc->sc_srom_addrbits);
- sc->sc_srom = malloc(size, M_DEVBUF, M_NOWAIT);
-
/* Select the SROM. */
miirom = MIIROM_SR;
SROM_EMIT(sc, miirom);
@@ -2143,7 +2071,7 @@
miirom |= MIIROM_RD;
SROM_EMIT(sc, miirom);
- for (i = 0; i < size; i += 2) {
+ for (i = 0; i < wordcnt; i++) {
/* Send CHIP SELECT for one clock tick. */
miirom |= MIIROM_SROMCS;
SROM_EMIT(sc, miirom);
@@ -2161,7 +2089,7 @@
/* Shift in address. */
for (x = sc->sc_srom_addrbits; x > 0; x--) {
- if (i & (1 << x))
+ if ((word + i) & (1 << (x - 1)))
miirom |= MIIROM_SROMDI;
else
miirom &= ~MIIROM_SROMDI;
@@ -2179,8 +2107,8 @@
datain |= (1 << (x - 1));
SROM_EMIT(sc, miirom);
}
- sc->sc_srom[i] = datain & 0xff;
- sc->sc_srom[i + 1] = datain >> 8;
+ data[2 * i] = datain & 0xff;
+ data[(2 * i) + 1] = datain >> 8;
/* Clear CHIP SELECT. */
miirom &= ~MIIROM_SROMCS;
@@ -2192,18 +2120,6 @@
/* ...and idle it. */
tlp_srom_idle(sc);
-
-#if 0
- printf("SROM CONTENTS:");
- for (i = 0; i < size; i++) {
- if ((i % 8) == 0)
- printf("\n\t");
- printf("0x%02x ", sc->sc_srom[i]);
- }
- printf("\n");
-#endif
-
- return (1);
}
#undef SROM_EMIT
Index: ic/tulipvar.h
===================================================================
RCS file: /cvsroot/syssrc/sys/dev/ic/tulipvar.h,v
retrieving revision 1.32
diff -u -r1.32 tulipvar.h
--- tulipvar.h 2000/03/23 07:01:33 1.32
+++ tulipvar.h 2000/03/26 16:02:57
@@ -1,4 +1,4 @@
-/* $NetBSD: tulipvar.h,v 1.32 2000/03/23 07:01:33 thorpej Exp $ */
+/* $NetBSD: tulipvar.h,v 1.28 2000/02/01 22:54:48 thorpej Exp $ */
/*-
* Copyright (c) 1998, 1999, 2000 The NetBSD Foundation, Inc.
@@ -278,7 +278,7 @@
/*
* Contents of the SROM.
*/
- u_int8_t *sc_srom;
+ u_int8_t sc_srom[TULIP_MAX_ROM_SIZE];
int sc_srom_addrbits;
/*
@@ -515,7 +515,7 @@
int tlp_activate __P((struct device *, enum devact));
int tlp_detach __P((struct tulip_softc *));
int tlp_intr __P((void *));
-int tlp_read_srom __P((struct tulip_softc *));
+void tlp_read_srom __P((struct tulip_softc *, int, int, u_int8_t *));
int tlp_srom_crcok __P((const u_int8_t *));
int tlp_isv_srom __P((const u_int8_t *));
int tlp_isv_srom_enaddr __P((struct tulip_softc *, u_int8_t *));
Index: pci/if_tlp_pci.c
===================================================================
RCS file: /cvsroot/syssrc/sys/dev/pci/if_tlp_pci.c,v
retrieving revision 1.35
diff -u -r1.35 if_tlp_pci.c
--- if_tlp_pci.c 2000/03/23 22:23:03 1.35
+++ if_tlp_pci.c 2000/03/26 16:02:57
@@ -1,4 +1,4 @@
-/* $NetBSD: if_tlp_pci.c,v 1.35 2000/03/23 22:23:03 mycroft Exp $ */
+/* $NetBSD: if_tlp_pci.c,v 1.32 2000/01/26 16:51:11 thorpej Exp $ */
/*-
* Copyright (c) 1998, 1999 The NetBSD Foundation, Inc.
@@ -245,6 +245,26 @@
{ NULL, { 0, 0, 0 } }
};
+/*
+ * Even more disgusting... some 21143 implementations (namely Cobalt's)
+ * which should have a 8-address-bit SROM actually only have a
+ * 6-address-bit SROM (even though it's rev 4.1!). Broken! This
+ * quirk detects that.
+ */
+#define TPSQ_NOMATCH 0
+#define TPSQ_CONTINUE 1
+#define TPSQ_READ_AGAIN_AND_CONTINUE 2
+
+typedef int (*tlp_pci_srom_quirk_t) __P((struct tulip_pci_softc *));
+
+int tlp_pci_cobalt_21143_srom_quirks __P((struct tulip_pci_softc *));
+int tlp_pci_21143_srom_quirks __P((struct tulip_pci_softc *));
+
+tlp_pci_srom_quirk_t tlp_pci_21143_srom_quirks_list[] = {
+ tlp_pci_cobalt_21143_srom_quirks,
+ tlp_pci_21143_srom_quirks, /* MUST BE AT THE END */
+};
+
int tlp_pci_shared_intr __P((void *));
const struct tulip_pci_product *tlp_pci_lookup
@@ -380,6 +400,13 @@
sc->sc_flags |= TULIPF_ENABLED;
/*
+ * Some chips have a 128 byte SROM (6 address bits), and some
+ * have a 512 byte SROM (8 address bits). Default to 6; we'll
+ * adjust below.
+ */
+ sc->sc_srom_addrbits = 6;
+
+ /*
* Get revision info, and set some chip-specific variables.
*/
sc->sc_rev = PCI_REVISION(pa->pa_class);
@@ -542,12 +569,12 @@
/*
* Read the contents of the Ethernet Address ROM/SROM.
*/
+ read_srom_again:
+ memset(sc->sc_srom, 0, sizeof(sc->sc_srom));
switch (sc->sc_chip) {
case TULIP_CHIP_21040:
- sc->sc_srom_addrbits = 6;
- sc->sc_srom = malloc(TULIP_ROM_SIZE(6), M_DEVBUF, M_NOWAIT);
TULIP_WRITE(sc, CSR_MIIROM, MIIROM_SROMCS);
- for (i = 0; i < TULIP_ROM_SIZE(6); i++) {
+ for (i = 0; i < TULIP_ROM_SIZE(sc->sc_srom_addrbits); i++) {
for (j = 0; j < 10000; j++) {
val = TULIP_READ(sc, CSR_MIIROM);
if ((val & MIIROM_DN) == 0)
@@ -560,17 +587,16 @@
case TULIP_CHIP_82C168:
case TULIP_CHIP_82C169:
{
- sc->sc_srom_addrbits = 2;
- sc->sc_srom = malloc(TULIP_ROM_SIZE(2), M_DEVBUF, M_NOWAIT);
+ u_int16_t *rombuf = (u_int16_t *)sc->sc_srom;
/*
* The Lite-On PNIC stores the Ethernet address in
* the first 3 words of the EEPROM. EEPROM access
* is not like the other Tulip chips.
*/
- for (i = 0; i < 6; i += 2) {
+ for (i = 0; i < 3; i++) {
TULIP_WRITE(sc, CSR_PNIC_SROMCTL,
- PNIC_SROMCTL_READ | (i >> 1));
+ PNIC_SROMCTL_READ | i);
for (j = 0; j < 500; j++) {
delay(2);
val = TULIP_READ(sc, CSR_MIIROM);
@@ -582,17 +608,23 @@
sc->sc_dev.dv_xname);
return;
}
- val &= PNIC_MIIROM_DATA;
- sc->sc_srom[i] = val >> 8;
- sc->sc_srom[i + 1] = val & 0xff;
+ rombuf[i] = bswap16(val & PNIC_MIIROM_DATA);
}
break;
}
default:
- if (tlp_read_srom(sc) == 0)
- goto cant_cope;
- break;
+ tlp_read_srom(sc, 0, TULIP_ROM_SIZE(sc->sc_srom_addrbits) >> 1,
+ sc->sc_srom);
+#if 0
+ printf("SROM CONTENTS:");
+ for (i = 0; i < TULIP_ROM_SIZE(sc->sc_srom_addrbits); i++) {
+ if ((i % 8) == 0)
+ printf("\n\t");
+ printf("0x%02x ", sc->sc_srom[i]);
+ }
+ printf("\n");
+#endif
}
/*
@@ -612,8 +644,11 @@
/*
* Parse the Ethernet Address ROM.
*/
- if (tlp_parse_old_srom(sc, enaddr) == 0)
- goto cant_cope;
+ if (tlp_parse_old_srom(sc, enaddr) == 0) {
+ printf("%s: unable to decode Ethernet Address ROM\n",
+ sc->sc_dev.dv_xname);
+ return;
+ }
/*
* If we have a slaved ROM, adjust the Ethernet address.
@@ -648,8 +683,11 @@
* Not an ISV SROM; try the old DEC Ethernet Address
* ROM format.
*/
- if (tlp_parse_old_srom(sc, enaddr) == 0)
- goto cant_cope;
+ if (tlp_parse_old_srom(sc, enaddr) == 0) {
+ printf("%s: unable to decode Ethernet "
+ "Address ROM\n", sc->sc_dev.dv_xname);
+ return;
+ }
}
/*
@@ -672,8 +710,10 @@
* Not an ISV SROM; try the old DEC Ethernet Address
* ROM format.
*/
- if (tlp_parse_old_srom(sc, enaddr) == 0)
+ if (tlp_parse_old_srom(sc, enaddr) == 0) {
+ printf("Bad eth addr\n");
goto cant_cope;
+ }
} else {
/*
* We start out with the 2114x ISV media switch.
@@ -699,12 +739,37 @@
case TULIP_CHIP_21143:
/* Check for new format SROM. */
if (tlp_isv_srom_enaddr(sc, enaddr) == 0) {
+ if (sc->sc_chip == TULIP_CHIP_21143) {
+ tlp_pci_srom_quirk_t q;
+
+ /*
+ * Check for SROM quirkiness.
+ */
+ for (i = 0; sc->sc_srom_addrbits != 8; i++) {
+ q = tlp_pci_21143_srom_quirks_list[i];
+ switch ((*q)(psc)) {
+ case TPSQ_NOMATCH:
+ continue;
+
+ case TPSQ_CONTINUE:
+ break;
+
+ case TPSQ_READ_AGAIN_AND_CONTINUE:
+ goto read_srom_again;
+ }
+ break; /* for TPSQ_CONTINUE */
+ }
+ }
+
/*
* Not an ISV SROM; try the old DEC Ethernet Address
* ROM format.
*/
- if (tlp_parse_old_srom(sc, enaddr) == 0)
+ if (tlp_parse_old_srom(sc, enaddr) == 0) {
+ printf("%s: unable to decode Ethernet "
+ "Address ROM\n", sc->sc_dev.dv_xname);
goto cant_cope;
+ }
} else {
/*
* We start out with the 2114x ISV media switch.
@@ -1092,4 +1157,43 @@
* Cobalt Networks interfaces are just MII-on-SIO.
*/
sc->sc_mediasw = &tlp_sio_mii_mediasw;
+}
+
+int
+tlp_pci_cobalt_21143_srom_quirks(psc)
+ struct tulip_pci_softc *psc;
+{
+ struct tulip_softc *sc = &psc->sc_tulip;
+
+ /*
+ * Check for broken Cobalt interface; pass 4.1 Tulip with
+ * only 6-bit SROM and Ethernet address in first 6 bytes.
+ */
+ if (sc->sc_srom[0] == 0x00 &&
+ sc->sc_srom[1] == 0x10 &&
+ sc->sc_srom[2] == 0xe0)
+ return (TPSQ_CONTINUE);
+
+ return (TPSQ_NOMATCH);
+}
+
+int
+tlp_pci_21143_srom_quirks(psc)
+ struct tulip_pci_softc *psc;
+{
+ struct tulip_softc *sc = &psc->sc_tulip;
+
+ /*
+ * Pass 4.1 21143s are supposed to have an 8-address-bit SROM.
+ * We need to read them again.
+ */
+ if (sc->sc_rev >= 0x41) {
+ sc->sc_srom_addrbits = 8;
+ return (TPSQ_READ_AGAIN_AND_CONTINUE);
+ }
+
+ /*
+ * ...otherwise, what we read is just fine.
+ */
+ return (TPSQ_CONTINUE);
}
>Audit-Trail:
>Unformatted: