aboutsummaryrefslogtreecommitdiff
path: root/sys/dev/fxp
diff options
context:
space:
mode:
authorJonathan Lemon <jlemon@FreeBSD.org>2001-08-27 16:07:12 +0000
committerJonathan Lemon <jlemon@FreeBSD.org>2001-08-27 16:07:12 +0000
commit00c4116b3e9099f2e80351e3334441427354bb7e (patch)
tree00f2f2972cb22abdddd4f4920317f845fc446721 /sys/dev/fxp
parent3b243b7292b985b80603e837d57e21810e0cb277 (diff)
Notes
Diffstat (limited to 'sys/dev/fxp')
-rw-r--r--sys/dev/fxp/if_fxp.c155
-rw-r--r--sys/dev/fxp/if_fxpreg.h1
2 files changed, 132 insertions, 24 deletions
diff --git a/sys/dev/fxp/if_fxp.c b/sys/dev/fxp/if_fxp.c
index b4dce3792b00..d4001885b834 100644
--- a/sys/dev/fxp/if_fxp.c
+++ b/sys/dev/fxp/if_fxp.c
@@ -185,9 +185,13 @@ static int fxp_add_rfabuf(struct fxp_softc *sc, struct mbuf *oldm);
static void fxp_mc_setup(struct fxp_softc *sc);
static u_int16_t fxp_eeprom_getword(struct fxp_softc *sc, int offset,
int autosize);
+static void fxp_eeprom_putword(struct fxp_softc *sc, int offset,
+ u_int16_t data);
static void fxp_autosize_eeprom(struct fxp_softc *sc);
static void fxp_read_eeprom(struct fxp_softc *sc, u_short *data,
int offset, int words);
+static void fxp_write_eeprom(struct fxp_softc *sc, u_short *data,
+ int offset, int words);
static int fxp_ifmedia_upd(struct ifnet *ifp);
static void fxp_ifmedia_sts(struct ifnet *ifp,
struct ifmediareq *ifmr);
@@ -261,7 +265,7 @@ fxp_scb_wait(struct fxp_softc *sc)
while (CSR_READ_1(sc, FXP_CSR_SCB_COMMAND) && --i)
DELAY(2);
if (i == 0)
- device_printf(sc->dev, "SCB timeout: 0x%x, 0x%x, 0x%x 0x%x\n",
+ device_printf(sc->dev, "SCB timeout: 0x%x 0x%x 0x%x 0x%x\n",
CSR_READ_1(sc, FXP_CSR_SCB_COMMAND),
CSR_READ_1(sc, FXP_CSR_SCB_STATACK),
CSR_READ_1(sc, FXP_CSR_SCB_RUSCUS),
@@ -479,10 +483,57 @@ fxp_attach(device_t dev)
/*
* Enable workarounds for certain chip revision deficiencies.
+ *
+ * Systems based on the ICH2/ICH2-M chip from Intel have a defect
+ * where the chip can cause a PCI protocol violation if it receives
+ * a CU_RESUME command when it is entering the IDLE state. The
+ * workaround is to disable Dynamic Standby Mode, so the chip never
+ * deasserts CLKRUN#, and always remains in an active state.
+ *
+ * See Intel 82801BA/82801BAM Specification Update, Errata #30.
*/
i = pci_get_device(dev);
- if (i == 0x2449 || (i > 0x1030 && i < 0x1039))
- sc->flags |= FXP_FLAG_CU_RESUME_BUG;
+ if (i == 0x2449 || (i > 0x1030 && i < 0x1039)) {
+ fxp_read_eeprom(sc, &data, 10, 1);
+ if (data & 0x02) { /* STB enable */
+ u_int16_t cksum;
+ int i;
+
+ device_printf(dev,
+ "*** DISABLING DYNAMIC STANDBY MODE IN EEPROM ***\n");
+ data &= ~0x02;
+ fxp_write_eeprom(sc, &data, 10, 1);
+ device_printf(dev, "New EEPROM ID: 0x%x\n", data);
+ cksum = 0;
+ for (i = 0; i < (1 << sc->eeprom_size) - 1; i++) {
+ fxp_read_eeprom(sc, &data, i, 1);
+ cksum += data;
+ }
+ i = (1 << sc->eeprom_size) - 1;
+ cksum = 0xBABA - cksum;
+ fxp_read_eeprom(sc, &data, i, 1);
+ fxp_write_eeprom(sc, &cksum, i, 1);
+ device_printf(dev,
+ "EEPROM checksum @ 0x%x: 0x%x -> 0x%x\n",
+ i, data, cksum);
+ /*
+ * We need to do a full PCI reset here. A software
+ * reset to the port doesn't cut it, but let's try
+ * anyway.
+ */
+ CSR_WRITE_4(sc, FXP_CSR_PORT, FXP_PORT_SOFTWARE_RESET);
+ DELAY(50);
+ device_printf(dev,
+ "*** PLEASE REBOOT THE SYSTEM NOW FOR CORRECT OPERATION ***\n");
+#if 1
+ /*
+ * If the user elects to continue, try the software
+ * workaround, as it is better than nothing.
+ */
+ sc->flags |= FXP_FLAG_CU_RESUME_BUG;
+#endif
+ }
+ }
/*
* If we are not a 82557 chip, we can enable extended features.
@@ -739,6 +790,29 @@ fxp_resume(device_t dev)
return (0);
}
+static void
+fxp_eeprom_shiftin(struct fxp_softc *sc, int data, int length)
+{
+ u_int16_t reg;
+ int x;
+
+ /*
+ * Shift in data.
+ */
+ for (x = 1 << (length - 1); x; x >>= 1) {
+ if (data & x)
+ reg = FXP_EEPROM_EECS | FXP_EEPROM_EEDI;
+ else
+ reg = FXP_EEPROM_EECS;
+ CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, reg);
+ DELAY(1);
+ CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, reg | FXP_EEPROM_EESK);
+ DELAY(1);
+ CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, reg);
+ DELAY(1);
+ }
+}
+
/*
* Read from the serial EEPROM. Basically, you manually shift in
* the read opcode (one bit at a time) and then shift in the address,
@@ -756,18 +830,7 @@ fxp_eeprom_getword(struct fxp_softc *sc, int offset, int autosize)
/*
* Shift in read opcode.
*/
- for (x = 1 << 2; x; x >>= 1) {
- if (FXP_EEPROM_OPC_READ & x)
- reg = FXP_EEPROM_EECS | FXP_EEPROM_EEDI;
- else
- reg = FXP_EEPROM_EECS;
- CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, reg);
- DELAY(1);
- CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, reg | FXP_EEPROM_EESK);
- DELAY(1);
- CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, reg);
- DELAY(1);
- }
+ fxp_eeprom_shiftin(sc, FXP_EEPROM_OPC_READ, 3);
/*
* Shift in address.
*/
@@ -809,6 +872,50 @@ fxp_eeprom_getword(struct fxp_softc *sc, int offset, int autosize)
return (data);
}
+static void
+fxp_eeprom_putword(struct fxp_softc *sc, int offset, u_int16_t data)
+{
+ int i;
+
+ /*
+ * Erase/write enable.
+ */
+ CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, FXP_EEPROM_EECS);
+ fxp_eeprom_shiftin(sc, 0x4, 3);
+ fxp_eeprom_shiftin(sc, 0x03 << (sc->eeprom_size - 2), sc->eeprom_size);
+ CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, 0);
+ DELAY(1);
+ /*
+ * Shift in write opcode, address, data.
+ */
+ CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, FXP_EEPROM_EECS);
+ fxp_eeprom_shiftin(sc, FXP_EEPROM_OPC_WRITE, 3);
+ fxp_eeprom_shiftin(sc, offset, sc->eeprom_size);
+ fxp_eeprom_shiftin(sc, data, 16);
+ CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, 0);
+ DELAY(1);
+ /*
+ * Wait for EEPROM to finish up.
+ */
+ CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, FXP_EEPROM_EECS);
+ DELAY(1);
+ for (i = 0; i < 1000; i++) {
+ if (CSR_READ_2(sc, FXP_CSR_EEPROMCONTROL) & FXP_EEPROM_EEDO)
+ break;
+ DELAY(50);
+ }
+ CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, 0);
+ DELAY(1);
+ /*
+ * Erase/write disable.
+ */
+ CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, FXP_EEPROM_EECS);
+ fxp_eeprom_shiftin(sc, 0x4, 3);
+ fxp_eeprom_shiftin(sc, 0, sc->eeprom_size);
+ CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, 0);
+ DELAY(1);
+}
+
/*
* From NetBSD:
*
@@ -828,14 +935,6 @@ fxp_eeprom_getword(struct fxp_softc *sc, int offset, int autosize)
* 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.
*/
static void
fxp_autosize_eeprom(struct fxp_softc *sc)
@@ -857,6 +956,15 @@ fxp_read_eeprom(struct fxp_softc *sc, u_short *data, int offset, int words)
data[i] = fxp_eeprom_getword(sc, offset + i, 0);
}
+static void
+fxp_write_eeprom(struct fxp_softc *sc, u_short *data, int offset, int words)
+{
+ int i;
+
+ for (i = 0; i < words; i++)
+ fxp_eeprom_putword(sc, offset + i, data[i]);
+}
+
/*
* Start packet transmission on the interface.
*/
@@ -1266,7 +1374,6 @@ fxp_stop(struct fxp_softc *sc)
struct fxp_cb_tx *txp;
int i;
-
ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
ifp->if_timer = 0;
diff --git a/sys/dev/fxp/if_fxpreg.h b/sys/dev/fxp/if_fxpreg.h
index a1c76b7cf8c6..f165019bab5a 100644
--- a/sys/dev/fxp/if_fxpreg.h
+++ b/sys/dev/fxp/if_fxpreg.h
@@ -46,6 +46,7 @@
#define FXP_CSR_EEPROMCONTROL 14 /* eeprom control (2 bytes) */
#define FXP_CSR_MDICONTROL 16 /* mdi control (4 bytes) */
#define FXP_CSR_FLOWCONTROL 0x19 /* flow control (2 bytes) */
+#define FXP_CSR_GENCONTROL 0x1C /* general control (1 byte) */
/*
* FOR REFERENCE ONLY, the old definition of FXP_CSR_SCB_RUSCUS: