diff options
| author | Jonathan Lemon <jlemon@FreeBSD.org> | 2001-08-27 16:07:12 +0000 |
|---|---|---|
| committer | Jonathan Lemon <jlemon@FreeBSD.org> | 2001-08-27 16:07:12 +0000 |
| commit | 00c4116b3e9099f2e80351e3334441427354bb7e (patch) | |
| tree | 00f2f2972cb22abdddd4f4920317f845fc446721 /sys/dev/fxp | |
| parent | 3b243b7292b985b80603e837d57e21810e0cb277 (diff) | |
Notes
Diffstat (limited to 'sys/dev/fxp')
| -rw-r--r-- | sys/dev/fxp/if_fxp.c | 155 | ||||
| -rw-r--r-- | sys/dev/fxp/if_fxpreg.h | 1 |
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: |
