summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTheo de Raadt <deraadt@cvs.openbsd.org>2012-04-03 23:39:10 +0000
committerTheo de Raadt <deraadt@cvs.openbsd.org>2012-04-03 23:39:10 +0000
commit6380067e84f8ff0d74edc5890a5c22ee00c4314a (patch)
tree1173c7b2bf0d2df983f70b17093252dc04173a01
parentcb46184035e1c5a70fafe31bb4b0f9c4fee1dfb6 (diff)
After suspend/resume, reload the firmware. Skip firmware on
FXP_REV_82550_C with server extensions.
-rw-r--r--sys/dev/ic/fxp.c70
-rw-r--r--sys/dev/ic/fxpreg.h15
-rw-r--r--sys/dev/ic/fxpvar.h10
3 files changed, 70 insertions, 25 deletions
diff --git a/sys/dev/ic/fxp.c b/sys/dev/ic/fxp.c
index b2df07a59d2..91d58496d91 100644
--- a/sys/dev/ic/fxp.c
+++ b/sys/dev/ic/fxp.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: fxp.c,v 1.109 2011/12/19 22:01:23 mpf Exp $ */
+/* $OpenBSD: fxp.c,v 1.110 2012/04/03 23:39:09 deraadt Exp $ */
/* $NetBSD: if_fxp.c,v 1.2 1997/06/05 02:01:55 thorpej Exp $ */
/*
@@ -319,6 +319,10 @@ fxp_resume(void *arg1, void *arg2)
struct fxp_softc *sc = arg1;
int s = splnet();
+
+ /* force reload of the microcode */
+ sc->sc_flags &= ~FXPF_UCODELOADED;
+
fxp_init(sc);
splx(s);
}
@@ -411,7 +415,7 @@ fxp_attach(struct fxp_softc *sc, const char *intrstr)
/*
* Get info about the primary PHY
*/
- fxp_read_eeprom(sc, (u_int16_t *)&data, 6, 1);
+ fxp_read_eeprom(sc, (u_int16_t *)&data, FXP_EEPROM_REG_PHY, 1);
sc->phy_primary_addr = data & 0xff;
sc->phy_primary_device = (data >> 8) & 0x3f;
sc->phy_10Mbps_only = data >> 15;
@@ -427,7 +431,7 @@ fxp_attach(struct fxp_softc *sc, const char *intrstr)
/*
* Read MAC address.
*/
- fxp_read_eeprom(sc, (u_int16_t *)enaddr, 0, 3);
+ fxp_read_eeprom(sc, (u_int16_t *)enaddr, FXP_EEPROM_REG_MAC, 3);
ifp = &sc->sc_arpcom.ac_if;
bcopy(enaddr, sc->sc_arpcom.ac_enaddr, ETHER_ADDR_LEN);
@@ -446,14 +450,14 @@ fxp_attach(struct fxp_softc *sc, const char *intrstr)
ether_sprintf(sc->sc_arpcom.ac_enaddr));
if (sc->sc_flags & FXPF_DISABLE_STANDBY) {
- fxp_read_eeprom(sc, &data, 10, 1);
- if (data & 0x02) { /* STB enable */
+ fxp_read_eeprom(sc, &data, FXP_EEPROM_REG_ID, 1);
+ if (data & FXP_EEPROM_REG_ID_STB) {
u_int16_t cksum;
printf("%s: Disabling dynamic standby mode in EEPROM",
sc->sc_dev.dv_xname);
- data &= ~0x02;
- fxp_write_eeprom(sc, &data, 10, 1);
+ data &= ~FXP_EEPROM_REG_ID_STB;
+ fxp_write_eeprom(sc, &data, FXP_EEPROM_REG_ID, 1);
printf(", New ID 0x%x", data);
cksum = 0;
for (i = 0; i < (1 << sc->eeprom_size) - 1; i++) {
@@ -470,8 +474,9 @@ fxp_attach(struct fxp_softc *sc, const char *intrstr)
}
/* Receiver lock-up workaround detection. */
- fxp_read_eeprom(sc, &data, 3, 1);
- if ((data & 0x03) != 0x03)
+ fxp_read_eeprom(sc, &data, FXP_EEPROM_REG_COMPAT, 1);
+ if ((data & (FXP_EEPROM_REG_COMPAT_MC10|FXP_EEPROM_REG_COMPAT_MC100))
+ != (FXP_EEPROM_REG_COMPAT_MC10|FXP_EEPROM_REG_COMPAT_MC100))
sc->sc_flags |= FXPF_RECV_WORKAROUND;
/*
@@ -1054,6 +1059,11 @@ fxp_detach(struct fxp_softc *sc)
ether_ifdetach(ifp);
if_detach(ifp);
+
+#ifndef SMALL_KERNEL
+ if (sc->sc_ucodebuf)
+ free(sc->sc_ucodebuf, M_DEVBUF);
+#endif
}
/*
@@ -1826,31 +1836,52 @@ fxp_load_ucode(struct fxp_softc *sc)
const struct ucode *uc;
struct fxp_cb_ucode *cbp = &sc->sc_ctrl->u.code;
int i, error;
- u_int32_t *ucode_buf;
- size_t ucode_len;
- if (sc->sc_flags & FXPF_UCODE)
+ if (sc->sc_ucodebuf)
+ goto reloadit;
+
+ if (sc->sc_flags & FXPF_NOUCODE)
return;
for (uc = ucode_table; uc->revision != 0; uc++)
if (sc->sc_revision == uc->revision)
break;
- if (uc->revision == 0)
+ if (uc->revision == 0) {
+ sc->sc_flags |= FXPF_NOUCODE;
return; /* no ucode for this chip is found */
+ }
+
+ if (sc->sc_revision == FXP_REV_82550_C) {
+ u_int16_t data;
- error = loadfirmware(uc->uname, (u_char **)&ucode_buf, &ucode_len);
+ /*
+ * 82550C without the server extensions
+ * locks up with the microcode patch.
+ */
+ fxp_read_eeprom(sc, &data, FXP_EEPROM_REG_COMPAT, 1);
+ if ((data & FXP_EEPROM_REG_COMPAT_SRV) == 0) {
+ sc->sc_flags |= FXPF_NOUCODE;
+ return;
+ }
+ }
+
+ error = loadfirmware(uc->uname, (u_char **)&sc->sc_ucodebuf,
+ &sc->sc_ucodelen);
if (error) {
printf("%s: error %d, could not read firmware %s\n",
sc->sc_dev.dv_xname, error, uc->uname);
- sc->sc_flags |= FXPF_UCODE;
return;
}
+reloadit:
+ if (sc->sc_flags & FXPF_UCODELOADED)
+ return;
+
cbp->cb_status = 0;
cbp->cb_command = htole16(FXP_CB_COMMAND_UCODE|FXP_CB_COMMAND_EL);
cbp->link_addr = 0xffffffff; /* (no) next command */
- for (i = 0; i < (ucode_len / sizeof(u_int32_t)); i++)
- cbp->ucode[i] = ucode_buf[i];
+ for (i = 0; i < (sc->sc_ucodelen / sizeof(u_int32_t)); i++)
+ cbp->ucode[i] = sc->sc_ucodebuf[i];
if (uc->int_delay_offset)
*((u_int16_t *)&cbp->ucode[uc->int_delay_offset]) =
@@ -1882,9 +1913,9 @@ fxp_load_ucode(struct fxp_softc *sc)
} while (((cbp->cb_status & htole16(FXP_CB_STATUS_C)) == 0) && --i);
if (i == 0) {
printf("%s: timeout loading microcode\n", sc->sc_dev.dv_xname);
- free(ucode_buf, M_DEVBUF);
return;
}
+ sc->sc_flags |= FXPF_UCODELOADED;
#ifdef DEBUG
printf("%s: microcode loaded, int_delay: %d usec",
@@ -1895,8 +1926,5 @@ fxp_load_ucode(struct fxp_softc *sc)
else
printf("\n");
#endif
-
- free(ucode_buf, M_DEVBUF);
- sc->sc_flags |= FXPF_UCODE;
}
#endif /* SMALL_KERNEL */
diff --git a/sys/dev/ic/fxpreg.h b/sys/dev/ic/fxpreg.h
index d525b99ed91..ccae328a1ee 100644
--- a/sys/dev/ic/fxpreg.h
+++ b/sys/dev/ic/fxpreg.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: fxpreg.h,v 1.13 2008/02/21 03:58:07 brad Exp $ */
+/* $OpenBSD: fxpreg.h,v 1.14 2012/04/03 23:39:09 deraadt Exp $ */
/*
* Copyright (c) 1995, David Greenman
@@ -284,6 +284,19 @@ struct fxp_stats {
#define FXP_EEPROM_OPC_READ 0x6
/*
+ * Serial EEPROM registers. A subset of them from Intel's
+ * "82559 EEPROM Map and Programming Information" document.
+ */
+#define FXP_EEPROM_REG_MAC 0x00
+#define FXP_EEPROM_REG_COMPAT 0x03
+#define FXP_EEPROM_REG_COMPAT_MC10 0x0001
+#define FXP_EEPROM_REG_COMPAT_MC100 0x0002
+#define FXP_EEPROM_REG_COMPAT_SRV 0x0400
+#define FXP_EEPROM_REG_PHY 0x06
+#define FXP_EEPROM_REG_ID 0x0a
+#define FXP_EEPROM_REG_ID_STB 0x0002
+
+/*
* Management Data Interface opcodes
*/
#define FXP_MDI_WRITE 0x1
diff --git a/sys/dev/ic/fxpvar.h b/sys/dev/ic/fxpvar.h
index d71e57febd8..d331585c40e 100644
--- a/sys/dev/ic/fxpvar.h
+++ b/sys/dev/ic/fxpvar.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: fxpvar.h,v 1.34 2010/09/07 16:21:42 deraadt Exp $ */
+/* $OpenBSD: fxpvar.h,v 1.35 2012/04/03 23:39:09 deraadt Exp $ */
/* $NetBSD: if_fxpvar.h,v 1.1 1997/06/05 02:01:58 thorpej Exp $ */
/*
@@ -117,8 +117,9 @@ struct fxp_softc {
int sc_flags; /* misc. flags */
#define FXPF_MWI_ENABLE 0x10 /* enable use of PCI MWI command */
#define FXPF_DISABLE_STANDBY 0x20 /* currently need to work-around */
-#define FXPF_UCODE 0x40 /* ucode load already attempted */
-#define FXPF_RECV_WORKAROUND 0x80 /* receiver lock-up workaround */
+#define FXPF_UCODELOADED 0x40 /* ucode load already attempted */
+#define FXPF_NOUCODE 0x80 /* no ucode for this chip */
+#define FXPF_RECV_WORKAROUND 0x100 /* receiver lock-up workaround */
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 */
@@ -142,6 +143,9 @@ struct fxp_softc {
u_int16_t sc_min_size_mask; /* bit-mask describing the minimum
* size of frame that will be bundled */
struct workq_task sc_resume_wqt;
+
+ u_int32_t *sc_ucodebuf;
+ size_t sc_ucodelen;
};
/* Macros to ease CSR access. */