diff options
author | Theo de Raadt <deraadt@cvs.openbsd.org> | 2012-04-03 23:39:10 +0000 |
---|---|---|
committer | Theo de Raadt <deraadt@cvs.openbsd.org> | 2012-04-03 23:39:10 +0000 |
commit | 6380067e84f8ff0d74edc5890a5c22ee00c4314a (patch) | |
tree | 1173c7b2bf0d2df983f70b17093252dc04173a01 | |
parent | cb46184035e1c5a70fafe31bb4b0f9c4fee1dfb6 (diff) |
After suspend/resume, reload the firmware. Skip firmware on
FXP_REV_82550_C with server extensions.
-rw-r--r-- | sys/dev/ic/fxp.c | 70 | ||||
-rw-r--r-- | sys/dev/ic/fxpreg.h | 15 | ||||
-rw-r--r-- | sys/dev/ic/fxpvar.h | 10 |
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. */ |