diff options
-rw-r--r-- | sys/dev/ic/fxp.c | 117 | ||||
-rw-r--r-- | sys/dev/ic/fxpvar.h | 3 | ||||
-rw-r--r-- | sys/dev/pci/if_fxp_pci.c | 19 |
3 files changed, 134 insertions, 5 deletions
diff --git a/sys/dev/ic/fxp.c b/sys/dev/ic/fxp.c index 5f21acb2b59..02221bba25d 100644 --- a/sys/dev/ic/fxp.c +++ b/sys/dev/ic/fxp.c @@ -1,4 +1,4 @@ -/* $OpenBSD: fxp.c,v 1.52 2004/05/18 21:19:35 beck Exp $ */ +/* $OpenBSD: fxp.c,v 1.53 2004/05/18 22:37:25 beck Exp $ */ /* $NetBSD: if_fxp.c,v 1.2 1997/06/05 02:01:55 thorpej Exp $ */ /* @@ -150,6 +150,9 @@ static u_char fxp_cb_config_template[] = { 0x05 /* 21 mc_all */ }; +void fxp_eeprom_shiftin(struct fxp_softc *, int, int); +void fxp_eeprom_putword(struct fxp_softc *, int, u_int16_t); +void fxp_write_eeprom(struct fxp_softc *, u_short *, int, int); int fxp_mediachange(struct ifnet *); void fxp_mediastatus(struct ifnet *, struct ifmediareq *); void fxp_scb_wait(struct fxp_softc *); @@ -205,6 +208,86 @@ fxp_scb_wait(sc) printf("%s: warning: SCB timed out\n", sc->sc_dev.dv_xname); } + +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); + } +} + + +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); +} + +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]); +} + + + /************************************************************* * Operating system-specific autoconfiguration glue *************************************************************/ @@ -363,6 +446,30 @@ fxp_attach_common(sc, enaddr, intrstr) ifp->if_watchdog = fxp_watchdog; IFQ_SET_READY(&ifp->if_snd); + + if (sc->sc_flags & FXPF_DISABLE_STANDBY) { + fxp_read_eeprom(sc, &data, 10, 1); + if (data & 0x02) { /* STB enable */ + u_int16_t cksum; + int i; + printf("Disabling dynamic standby mode in EEPROM\n"); + data &= ~0x02; + fxp_write_eeprom(sc, &data, 10, 1); + printf("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); + printf("EEPROM checksum @ 0x%x: 0x%x -> 0x%x\n", + i, data, cksum); + } + } + #if NVLAN > 0 /* * Only 82558 and newer cards have a bit to ignore oversized frames. @@ -544,6 +651,11 @@ fxp_autosize_eeprom(sc) DELAY(4); 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, @@ -907,9 +1019,8 @@ fxp_stats_update(arg) if (sp->rx_good) { ifp->if_ipackets += letoh32(sp->rx_good); sc->rx_idle_secs = 0; - } else { + } else sc->rx_idle_secs++; - } ifp->if_ierrors += letoh32(sp->rx_crc_errors) + letoh32(sp->rx_alignment_errors) + diff --git a/sys/dev/ic/fxpvar.h b/sys/dev/ic/fxpvar.h index 0a25b5fa759..9b974a7b76d 100644 --- a/sys/dev/ic/fxpvar.h +++ b/sys/dev/ic/fxpvar.h @@ -1,4 +1,4 @@ -/* $OpenBSD: fxpvar.h,v 1.15 2004/04/26 02:35:12 mcbride Exp $ */ +/* $OpenBSD: fxpvar.h,v 1.16 2004/05/18 22:37:25 beck Exp $ */ /* $NetBSD: if_fxpvar.h,v 1.1 1997/06/05 02:01:58 thorpej Exp $ */ /* @@ -87,6 +87,7 @@ struct fxp_softc { #define FXPF_HAS_RESUME_BUG 0x08 /* has the resume bug */ #define FXPF_FIX_RESUME_BUG 0x10 /* currently need to work-around the resume bug */ +#define FXPF_DISABLE_STANDBY 0x20 /* currently need to work-around */ struct timeout stats_update_to; /* Pointer to timeout structure */ int rx_idle_secs; /* # of seconds RX has been idle */ struct fxp_cb_tx *cbl_base; /* base of TxCB list */ diff --git a/sys/dev/pci/if_fxp_pci.c b/sys/dev/pci/if_fxp_pci.c index b02a14144b9..e9832152c82 100644 --- a/sys/dev/pci/if_fxp_pci.c +++ b/sys/dev/pci/if_fxp_pci.c @@ -1,4 +1,4 @@ -/* $OpenBSD: if_fxp_pci.c,v 1.25 2004/02/25 12:25:09 markus Exp $ */ +/* $OpenBSD: if_fxp_pci.c,v 1.26 2004/05/18 22:37:25 beck Exp $ */ /* * Copyright (c) 1995, David Greenman @@ -201,6 +201,23 @@ fxp_pci_attach(parent, self, aux) break; } + /* + * Cards for which we should WRITE TO THE EEPROM + * to turn off dynamic standby mode to avoid + * a problem where the card will fail to resume when + * entering the IDLE state. We use this nasty if statement + * and corresponding pci dev numbers directly so that people + * know not to add new cards to this unless you are really + * certain what you are doing and are not going to end up + * killing people's eeproms. + */ + if ((PCI_VENDOR(pa->pa_id) == PCI_VENDOR_INTEL) && + (PCI_PRODUCT(pa->pa_id) == 0x2449 || + (PCI_PRODUCT(pa->pa_id) > 0x1030 && + PCI_PRODUCT(pa->pa_id) < 0x1039) || + (PCI_PRODUCT(pa->pa_id) == 0x1229 && (rev == 8 || rev == 9)))) + sc->sc_flags |= FXPF_DISABLE_STANDBY; + /* enable bus mastering */ pci_conf_write(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG, PCI_COMMAND_MASTER_ENABLE | |