Subject: Re: Panic in latest -current with fxp0
To: Patrick Hartling <patrick@137.org>
From: Johan Danielsson <joda@pdc.kth.se>
List: current-users
Date: 11/19/1999 16:29:21
"Patrick Hartling" <patrick@137.org> writes:
> I can boot using this patch.
...
> 000b 000b 000f 000b 000f 0003
Ok, fine. I just commited some code that should hopefully work on all
types of cards. A patch relative to 1.12 is appended, it would be
great if you could verify that this does The Right Thing.
To kernel wizards (Bill and others :-) what's the right thing to do if
the size check fails? This most likely means that we have a 64 word
EEPROM, but is it ok to assume so, or should we panic, or panic iff
DIAGNOSTIC/DEBUG?
/Johan
--- i82557.c 1999/11/12 18:14:18 1.12
+++ i82557.c 1999/11/19 15:19:14 1.13
@@ -1,4 +1,4 @@
-/* $NetBSD: i82557.c,v 1.12 1999/11/12 18:14:18 thorpej Exp $ */
+/* $NetBSD: i82557.c,v 1.13 1999/11/19 15:19:14 joda Exp $ */
/*-
* Copyright (c) 1997, 1998, 1999 The NetBSD Foundation, Inc.
@@ -181,6 +181,7 @@
int fxp_mdi_read __P((struct device *, int, int));
void fxp_statchg __P((struct device *));
void fxp_mdi_write __P((struct device *, int, int, int));
+void fxp_autosize_eeprom __P((struct fxp_softc*));
void fxp_read_eeprom __P((struct fxp_softc *, u_int16_t *, int, int));
void fxp_get_info __P((struct fxp_softc *, u_int8_t *));
void fxp_tick __P((void *));
@@ -484,30 +485,14 @@
CSR_WRITE_4(sc, FXP_CSR_PORT, FXP_PORT_SELECTIVE_RESET);
DELAY(10);
- /*
- * Figure out EEPROM size.
- *
- * Cards can have either 64-word or 256-word EEPROMs, with
- * addresses fed in using a bit-at-a-time protocol, MSB first.
- *
- * XXX this is probably not the best way to do this; the linux
- * driver does a checksum of the eeprom, but there is
- * (AFAIK) no on-line documentation on what this checksum
- * should look like (you could just steal the code from
- * linux, but that's cheating); for now we just use the fact
- * that the upper two bits of word 10 should be 01
- */
- for(sc->sc_eeprom_size = 6;
- sc->sc_eeprom_size <= 8;
- sc->sc_eeprom_size += 2) {
- fxp_read_eeprom(sc, &data, 10, 1);
- if((data & 0xc000) == 0x4000)
- break;
+ sc->sc_eeprom_size = 0;
+ fxp_autosize_eeprom(sc);
+ if(sc->sc_eeprom_size == 0) {
+ printf("%s: failed to detect EEPROM size", sc->sc_dev.dv_xname);
+ sc->sc_eeprom_size = 6; /* XXX panic here? */
}
- if(sc->sc_eeprom_size > 8)
- panic("%s: failed to get EEPROM size", sc->sc_dev.dv_xname);
#ifdef DEBUG
- printf("%s: assuming %d word EEPROM\n",
+ printf("%s: detected %d word EEPROM\n",
sc->sc_dev.dv_xname,
1 << sc->sc_eeprom_size);
#endif
@@ -528,6 +513,83 @@
}
/*
+ * Figure out EEPROM size.
+ *
+ * 559's can have either 64-word or 256-word EEPROMs, the 558
+ * datasheet only talks about 64-word EEPROMs, and the 557 datasheet
+ * talks about the existance of 16 to 256 word EEPROMs.
+ *
+ * The only known sizes are 64 and 256, where the 256 version is used
+ * by CardBus cards to store CIS information.
+ *
+ * The address is shifted in msb-to-lsb, and after the last
+ * address-bit the EEPROM is supposed to output a `dummy zero' bit,
+ * after which follows the actual data. We try to detect this zero, by
+ * probing the data-out bit in the EEPROM control register just after
+ * having shifted in a bit. If the bit is zero, we assume we've
+ * shifted enough address bits. The data-out should be tri-state,
+ * before this, which should translate to a logical one.
+ *
+ * Other ways to do this would be to try to read a register with known
+ * contents with a varying number of address bits, but no such
+ * register seem to be available. The high bits of register 10 are 01
+ * on the 558 and 559, but apparently not on the 557.
+ *
+ * The Linux driver computes a checksum on the EEPROM data, but the
+ * value of this checksum is not very well documented.
+ */
+
+void
+fxp_autosize_eeprom(sc)
+ struct fxp_softc *sc;
+{
+ u_int16_t reg;
+ int x;
+
+ CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, FXP_EEPROM_EECS);
+ /*
+ * Shift in read opcode.
+ */
+ for (x = 3; x > 0; x--) {
+ if (FXP_EEPROM_OPC_READ & (1 << (x - 1))) {
+ reg = FXP_EEPROM_EECS | FXP_EEPROM_EEDI;
+ } else {
+ reg = FXP_EEPROM_EECS;
+ }
+ CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, reg);
+ CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL,
+ reg | FXP_EEPROM_EESK);
+ DELAY(1);
+ CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, reg);
+ DELAY(1);
+ }
+ /*
+ * Shift in address, wait for the dummy zero following a correct
+ * address shift.
+ */
+ for (x = 1; x <= 8; x++) {
+ CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, FXP_EEPROM_EECS);
+ CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL,
+ FXP_EEPROM_EECS | FXP_EEPROM_EESK);
+ DELAY(1);
+ if((CSR_READ_2(sc, FXP_CSR_EEPROMCONTROL) &
+ FXP_EEPROM_EEDO) == 0)
+ break;
+ CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, FXP_EEPROM_EECS);
+ DELAY(1);
+ }
+ CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, 0);
+ DELAY(1);
+ if(x != 6 && x != 8) {
+#ifdef DEBUG
+ printf("%s: strange EEPROM size (%d)\n",
+ sc->sc_dev.dv_xname, 1 << x);
+#endif
+ } else
+ sc->sc_eeprom_size = x;
+}
+
+/*
* Read from the serial EEPROM. Basically, you manually shift in
* the read opcode (one bit at a time) and then shift in the address,
* and then you shift out the data (all of this one bit at a time).