I noticed on a FreeBSD list that there is one model which cannot
use the firmware patching we do.

While at it, I noticed a few other issues with the firmware handling.

- After a suspend/resume cycle, firmware re-installation was not
  being done
- If the firmware file is missing on the first initialization, there
  is no way to attempt a firmware installation with files, unless you
  reboot.

And... Mark Kettenis made me document the eeprom layout.

Index: dev/ic/fxp.c
===================================================================
RCS file: /cvs/src/sys/dev/ic/fxp.c,v
retrieving revision 1.109
diff -u -p -u -r1.109 fxp.c
--- dev/ic/fxp.c        19 Dec 2011 22:01:23 -0000      1.109
+++ dev/ic/fxp.c        30 Mar 2012 19:30:24 -0000
@@ -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 c
        /*
         * 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 c
        /*
         * 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 c
            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 c
        }
 
        /* 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 */
Index: dev/ic/fxpreg.h
===================================================================
RCS file: /cvs/src/sys/dev/ic/fxpreg.h,v
retrieving revision 1.13
diff -u -p -u -r1.13 fxpreg.h
--- dev/ic/fxpreg.h     21 Feb 2008 03:58:07 -0000      1.13
+++ dev/ic/fxpreg.h     28 Mar 2012 21:55:31 -0000
@@ -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
Index: dev/ic/fxpvar.h
===================================================================
RCS file: /cvs/src/sys/dev/ic/fxpvar.h,v
retrieving revision 1.34
diff -u -p -u -r1.34 fxpvar.h
--- dev/ic/fxpvar.h     7 Sep 2010 16:21:42 -0000       1.34
+++ dev/ic/fxpvar.h     30 Mar 2012 20:31:06 -0000
@@ -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. */

Reply via email to