summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sys/dev/ic/fxp.c117
-rw-r--r--sys/dev/ic/fxpvar.h3
-rw-r--r--sys/dev/pci/if_fxp_pci.c19
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 |