diff options
author | 2004-05-18 22:37:25 +0000 | |
---|---|---|
committer | 2004-05-18 22:37:25 +0000 | |
commit | b82aedbc8a9d43f949c85d098f3ef90d2b8bfd31 (patch) | |
tree | 84163e054e5df0014e1cfefae03710da4320cbf4 | |
parent | Check for and handle interface CRC errors. (diff) | |
download | wireguard-openbsd-b82aedbc8a9d43f949c85d098f3ef90d2b8bfd31.tar.xz wireguard-openbsd-b82aedbc8a9d43f949c85d098f3ef90d2b8bfd31.zip |
fix from netbsd to twiddle the fxp eeprom to disable dynamic standby mode
on cards that have issues with this creating pci errors in 10 mbps mode
tested by many, including me, nick, and pval.
ok jason@, markus@
-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 | |