Current-Users archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

Re: NetBSD 5 STABLE wm0 panic



On Tue, May 19, 2009 at 09:20:21AM -0400, Chris Ross wrote:
> On Tuesday 19 May 2009 01:44:15 SAITOH Masanobu wrote:
> >  Hello.
> >
> >  The bug had been fixed by if_wm.c rev. 1.173 on -current. It's not pulled
> > up yet. I'm now working other bugs and will be pulled up all of them in
> > near future.
> 
>   Great.  Thank you very much for that update.  I'll keep an eye on netbsd-5 
> and watch for it.

I have synched if_wm.c with HEAD in my netbsd-5 tree, see attached
patch. I've been succefully running with this patch on various wm
devices for some time. You may want to give it a try.

-- 
Manuel Bouyer, LIP6, Universite Paris VI.           
Manuel.Bouyer%lip6.fr@localhost
     NetBSD: 26 ans d'experience feront toujours la difference
--
Index: if_wm.c
===================================================================
RCS file: /cvsroot/src/sys/dev/pci/if_wm.c,v
retrieving revision 1.162.4.8
diff -u -p -u -r1.162.4.8 if_wm.c
--- if_wm.c     11 May 2009 20:11:34 -0000      1.162.4.8
+++ if_wm.c     19 May 2009 15:58:57 -0000
@@ -73,9 +73,6 @@
  * TODO (in order of importance):
  *
  *     - Rework how parameters are loaded from the EEPROM.
- *     - Figure out what to do with the i82545GM and i82546GB
- *       SERDES controllers.
- *     - Fix hw VLAN assist.
  */
 
 #include <sys/cdefs.h>
@@ -254,8 +251,11 @@ typedef enum {
        WM_T_80003,                     /* i80003 */
        WM_T_ICH8,                      /* ICH8 LAN */
        WM_T_ICH9,                      /* ICH9 LAN */
+       WM_T_ICH10,                     /* ICH10 LAN */
 } wm_chip_type;
 
+#define WM_LINKUP_TIMEOUT      50
+
 /*
  * Software state per device.
  */
@@ -376,7 +376,10 @@ struct wm_softc {
        uint32_t sc_pba;                /* prototype PBA register */
 
        int sc_tbi_linkup;              /* TBI link status */
-       int sc_tbi_anstate;             /* autonegotiation state */
+       int sc_tbi_anegticks;           /* autonegotiation ticks */
+       int sc_tbi_ticks;               /* tbi ticks */
+       int sc_tbi_nrxcfg;              /* count of ICR_RXCFG */
+       int sc_tbi_lastnrxcfg;          /* count of ICR_RXCFG (on last tick) */
 
        int sc_mchash_type;             /* multicast filter offset */
 
@@ -554,6 +557,9 @@ static void wm_gmii_i82544_writereg(devi
 static int     wm_gmii_i80003_readreg(device_t, int, int);
 static void    wm_gmii_i80003_writereg(device_t, int, int, int);
 
+static int     wm_gmii_bm_readreg(device_t, int, int);
+static void    wm_gmii_bm_writereg(device_t, int, int, int);
+
 static void    wm_gmii_statchg(device_t);
 
 static void    wm_gmii_mediainit(struct wm_softc *);
@@ -580,13 +586,17 @@ static int32_t    wm_ich8_cycle_init(struct
 static int32_t wm_ich8_flash_cycle(struct wm_softc *, uint32_t);
 static int32_t wm_read_ich8_data(struct wm_softc *, uint32_t,
                     uint32_t, uint16_t *);
+static int32_t wm_read_ich8_byte(struct wm_softc *sc, uint32_t, uint8_t *);
 static int32_t wm_read_ich8_word(struct wm_softc *sc, uint32_t, uint16_t *);
 static void    wm_82547_txfifo_stall(void *);
 static int     wm_check_mng_mode(struct wm_softc *);
 static int     wm_check_mng_mode_ich8lan(struct wm_softc *);
+#if 0
 static int     wm_check_mng_mode_82574(struct wm_softc *);
+#endif
 static int     wm_check_mng_mode_generic(struct wm_softc *);
 static void    wm_get_hw_control(struct wm_softc *);
+static int     wm_check_for_link(struct wm_softc *);
 
 CFATTACH_DECL_NEW(wm, sizeof(struct wm_softc),
     wm_match, wm_attach, NULL, NULL);
@@ -867,6 +877,15 @@ static const struct wm_product {
        { PCI_VENDOR_INTEL,     PCI_PRODUCT_INTEL_82801I_IGP_M_AMT,
          "82801I mobile (AMT) LAN Controller",
          WM_T_ICH9,            WMP_F_1000T },
+       { PCI_VENDOR_INTEL,     PCI_PRODUCT_INTEL_82567LM_3,
+         "82567LM-3 LAN Controller",
+         WM_T_ICH10,           WMP_F_1000T },
+       { PCI_VENDOR_INTEL,     PCI_PRODUCT_INTEL_82567LF_3,
+         "82567LF-3 LAN Controller",
+         WM_T_ICH10,           WMP_F_1000T },
+       { PCI_VENDOR_INTEL,     PCI_PRODUCT_INTEL_82801J_D_BM_LF,
+         "i82801J (LF) LAN Controller",
+         WM_T_ICH10,           WMP_F_1000T },
        { 0,                    0,
          NULL,
          0,                    0 },
@@ -1102,7 +1121,8 @@ wm_attach(device_t parent, device_t self
                }
        } else if (sc->sc_type >= WM_T_82571) {
                sc->sc_flags |= WM_F_PCIE;
-               if ((sc->sc_type != WM_T_ICH8) && (sc->sc_type != WM_T_ICH9))
+               if ((sc->sc_type != WM_T_ICH8) && (sc->sc_type != WM_T_ICH9)
+                       && (sc->sc_type != WM_T_ICH10))
                        sc->sc_flags |= WM_F_EEPROM_SEMAPHORE;
                aprint_verbose_dev(sc->sc_dev, "PCI-Express bus\n");
        } else {
@@ -1272,9 +1292,14 @@ wm_attach(device_t parent, device_t self
        wm_reset(sc);
 
        switch (sc->sc_type) {
+       case WM_T_82571:
+       case WM_T_82572:
        case WM_T_82573:
+       case WM_T_82574:
+       case WM_T_80003:
        case WM_T_ICH8:
        case WM_T_ICH9:
+       case WM_T_ICH10:
                if (wm_check_mng_mode(sc) != 0)
                        wm_get_hw_control(sc);
                break;
@@ -1285,7 +1310,8 @@ wm_attach(device_t parent, device_t self
        /*
         * Get some information about the EEPROM.
         */
-       if ((sc->sc_type == WM_T_ICH8) || (sc->sc_type == WM_T_ICH9)) {
+       if ((sc->sc_type == WM_T_ICH8) || (sc->sc_type == WM_T_ICH9)
+           || (sc->sc_type == WM_T_ICH10)) {
                uint32_t flash_size;
                sc->sc_flags |= WM_F_SWFWHW_SYNC | WM_F_EEPROM_FLASH;
                memtype = pci_mapreg_type(pa->pa_pc, pa->pa_tag, WM_ICH8_FLASH);
@@ -1508,7 +1534,8 @@ wm_attach(device_t parent, device_t self
         * media structures accordingly.
         */
        if (sc->sc_type == WM_T_ICH8 || sc->sc_type == WM_T_ICH9
-           || sc->sc_type == WM_T_82573 || sc->sc_type == WM_T_82574) {
+           || sc->sc_type == WM_T_ICH10 || sc->sc_type == WM_T_82573
+           || sc->sc_type == WM_T_82574) {
                /* STATUS_TBIMODE reserved/reused, can't rely on it */
                wm_gmii_mediainit(sc);
        } else if (sc->sc_type < WM_T_82543 ||
@@ -2759,6 +2786,8 @@ wm_linkintr(struct wm_softc *sc, uint32_
 {
        uint32_t status;
 
+       DPRINTF(WM_DEBUG_LINK, ("%s: %s:\n", device_xname(sc->sc_dev),
+               __func__));
        /*
         * If we get a link status interrupt on a 1000BASE-T
         * device, just fall into the normal MII tick path.
@@ -2815,22 +2844,18 @@ wm_linkintr(struct wm_softc *sc, uint32_
                return;
        }
 
-       /*
-        * If we are now receiving /C/, check for link again in
-        * a couple of link clock ticks.
-        */
-       if (icr & ICR_RXCFG) {
-               DPRINTF(WM_DEBUG_LINK, ("%s: LINK: receiving /C/\n",
-                   device_xname(sc->sc_dev)));
-               sc->sc_tbi_anstate = 2;
-       }
-
+       status = CSR_READ(sc, WMREG_STATUS);
        if (icr & ICR_LSC) {
-               status = CSR_READ(sc, WMREG_STATUS);
                if (status & STATUS_LU) {
                        DPRINTF(WM_DEBUG_LINK, ("%s: LINK: LSC -> up %s\n",
                            device_xname(sc->sc_dev),
                            (status & STATUS_FD) ? "FDX" : "HDX"));
+                       /*
+                        * NOTE: CTRL will update TFCE and RFCE automatically,
+                        * so we should update sc->sc_ctrl
+                        */
+                       
+                       sc->sc_ctrl = CSR_READ(sc, WMREG_CTRL);
                        sc->sc_tctl &= ~TCTL_COLD(0x3ff);
                        sc->sc_fcrtl &= ~FCRTL_XONE;
                        if (status & STATUS_FD)
@@ -2839,7 +2864,7 @@ wm_linkintr(struct wm_softc *sc, uint32_
                        else
                                sc->sc_tctl |=
                                    TCTL_COLD(TX_COLLISION_DISTANCE_HDX);
-                       if (CSR_READ(sc, WMREG_CTRL) & CTRL_TFCE)
+                       if (sc->sc_ctrl & CTRL_TFCE)
                                sc->sc_fcrtl |= FCRTL_XONE;
                        CSR_WRITE(sc, WMREG_TCTL, sc->sc_tctl);
                        CSR_WRITE(sc, (sc->sc_type < WM_T_82543) ?
@@ -2851,8 +2876,12 @@ wm_linkintr(struct wm_softc *sc, uint32_
                            device_xname(sc->sc_dev)));
                        sc->sc_tbi_linkup = 0;
                }
-               sc->sc_tbi_anstate = 2;
                wm_tbi_set_linkled(sc);
+       } else if (icr & ICR_RXCFG) {
+               DPRINTF(WM_DEBUG_LINK, ("%s: LINK: receiving /C/\n",
+                   device_xname(sc->sc_dev)));
+               sc->sc_tbi_nrxcfg++;
+               wm_check_for_link(sc);
        } else if (icr & ICR_RXSEQ) {
                DPRINTF(WM_DEBUG_LINK,
                    ("%s: LINK: Receive sequence error\n",
@@ -2937,6 +2966,7 @@ wm_reset(struct wm_softc *sc)
                CSR_WRITE(sc, WMREG_PBS, PBA_16K);
                break;
        case WM_T_ICH9:
+       case WM_T_ICH10:
                sc->sc_pba = PBA_10K;
                break;
        default:
@@ -3005,6 +3035,7 @@ wm_reset(struct wm_softc *sc)
 
        case WM_T_ICH8:
        case WM_T_ICH9:
+       case WM_T_ICH10:
                wm_get_swfwhw_semaphore(sc);
                CSR_WRITE(sc, WMREG_CTRL, CTRL_RST | CTRL_PHY_RESET);
                delay(10000);
@@ -3046,6 +3077,9 @@ wm_reset(struct wm_softc *sc)
                wm_get_auto_rd_done(sc);
        }
 
+       /* reload sc_ctrl */
+       sc->sc_ctrl = CSR_READ(sc, WMREG_CTRL);
+
 #if 0
        for (i = 0; i < 1000; i++) {
                if ((CSR_READ(sc, WMREG_CTRL) & CTRL_RST) == 0) {
@@ -3104,9 +3138,14 @@ wm_init(struct ifnet *ifp)
        wm_reset(sc);
 
        switch (sc->sc_type) {
+       case WM_T_82571:
+       case WM_T_82572:
        case WM_T_82573:
+       case WM_T_82574:
+       case WM_T_80003:
        case WM_T_ICH8:
        case WM_T_ICH9:
+       case WM_T_ICH10:
                if (wm_check_mng_mode(sc) != 0)
                        wm_get_hw_control(sc);
                break;
@@ -3277,6 +3316,9 @@ wm_init(struct ifnet *ifp)
                reg |= RXCSUM_IPV6OFL | RXCSUM_TUOFL;
        CSR_WRITE(sc, WMREG_RXCSUM, reg);
 
+       /* Reset TBI's RXCFG count */
+       sc->sc_tbi_nrxcfg = sc->sc_tbi_lastnrxcfg = 0;
+
        /*
         * Set up the interrupt registers.
         */
@@ -3433,6 +3475,11 @@ wm_stop(struct ifnet *ifp, int disable)
        if (sc->sc_flags & WM_F_HAS_MII) {
                /* Down the MII. */
                mii_down(&sc->sc_mii);
+       } else {
+#if 0
+               /* Should we clear PHY's status properly? */
+               wm_reset(sc);
+#endif
        }
 
        /* Stop the transmit and receive processes. */
@@ -3480,6 +3527,7 @@ wm_get_auto_rd_done(struct wm_softc *sc)
        case WM_T_80003:
        case WM_T_ICH8:
        case WM_T_ICH9:
+       case WM_T_ICH10:
                for (i = 10; i > 0; i--) {
                        if (CSR_READ(sc, WMREG_EECD) & EECD_EE_AUTORD)
                                break;
@@ -3798,7 +3846,8 @@ wm_read_eeprom(struct wm_softc *sc, int 
        if (wm_acquire_eeprom(sc))
                return 1;
 
-       if ((sc->sc_type == WM_T_ICH8) || (sc->sc_type == WM_T_ICH9))
+       if ((sc->sc_type == WM_T_ICH8) || (sc->sc_type == WM_T_ICH9)
+           || (sc->sc_type == WM_T_ICH10))
                rv = wm_read_eeprom_ich8(sc, word, wordcnt, data);
        else if (sc->sc_flags & WM_F_EEPROM_EERDEEWR)
                rv = wm_read_eeprom_eerd(sc, word, wordcnt, data);
@@ -3944,7 +3993,8 @@ wm_mchash(struct wm_softc *sc, const uin
        static const int ich8_hi_shift[4] = { 2, 3, 4, 6 };
        uint32_t hash;
 
-       if ((sc->sc_type == WM_T_ICH8) || (sc->sc_type == WM_T_ICH9)) {
+       if ((sc->sc_type == WM_T_ICH8) || (sc->sc_type == WM_T_ICH9)
+           || (sc->sc_type == WM_T_ICH10)) {
                hash = (enaddr[4] >> ich8_lo_shift[sc->sc_mchash_type]) |
                    (((uint16_t) enaddr[5]) << 
ich8_hi_shift[sc->sc_mchash_type]);
                return (hash & 0x3ff);
@@ -3989,7 +4039,8 @@ wm_set_filter(struct wm_softc *sc)
         * Set the station address in the first RAL slot, and
         * clear the remaining slots.
         */
-       if ((sc->sc_type == WM_T_ICH8) || (sc->sc_type == WM_T_ICH9))
+       if ((sc->sc_type == WM_T_ICH8) || (sc->sc_type == WM_T_ICH9)
+                || (sc->sc_type == WM_T_ICH10))
                size = WM_ICH8_RAL_TABSIZE;
        else
                size = WM_RAL_TABSIZE;
@@ -3997,7 +4048,8 @@ wm_set_filter(struct wm_softc *sc)
        for (i = 1; i < size; i++)
                wm_set_ral(sc, NULL, i);
 
-       if ((sc->sc_type == WM_T_ICH8) || (sc->sc_type == WM_T_ICH9))
+       if ((sc->sc_type == WM_T_ICH8) || (sc->sc_type == WM_T_ICH9)
+           || (sc->sc_type == WM_T_ICH10))
                size = WM_ICH8_MC_TABSIZE;
        else
                size = WM_MC_TABSIZE;
@@ -4022,7 +4074,8 @@ wm_set_filter(struct wm_softc *sc)
                hash = wm_mchash(sc, enm->enm_addrlo);
 
                reg = (hash >> 5);
-               if ((sc->sc_type == WM_T_ICH8) || (sc->sc_type == WM_T_ICH9))
+               if ((sc->sc_type == WM_T_ICH8) || (sc->sc_type == WM_T_ICH9)
+                   || (sc->sc_type == WM_T_ICH10))
                        reg &= 0x1f;
                else
                        reg &= 0x7f;
@@ -4061,6 +4114,7 @@ wm_set_filter(struct wm_softc *sc)
 static void
 wm_tbi_mediainit(struct wm_softc *sc)
 {
+       struct ifnet *ifp = &sc->sc_ethercom.ec_if;
        const char *sep = "";
 
        if (sc->sc_type < WM_T_82543)
@@ -4068,6 +4122,12 @@ wm_tbi_mediainit(struct wm_softc *sc)
        else
                sc->sc_tipg = TIPG_LG_DFLT;
 
+       sc->sc_tbi_anegticks = 5;
+
+       /* Initialize our media structures */
+       sc->sc_mii.mii_ifp = ifp;
+
+       sc->sc_ethercom.ec_mii = &sc->sc_mii;
        ifmedia_init(&sc->sc_mii.mii_media, IFM_IMASK, wm_tbi_mediachange,
            wm_tbi_mediastatus);
 
@@ -4109,12 +4169,13 @@ static void
 wm_tbi_mediastatus(struct ifnet *ifp, struct ifmediareq *ifmr)
 {
        struct wm_softc *sc = ifp->if_softc;
-       uint32_t ctrl;
+       uint32_t ctrl, status;
 
        ifmr->ifm_status = IFM_AVALID;
        ifmr->ifm_active = IFM_ETHER;
 
-       if (sc->sc_tbi_linkup == 0) {
+       status = CSR_READ(sc, WMREG_STATUS);
+       if ((status & STATUS_LU) == 0) {
                ifmr->ifm_active |= IFM_NONE;
                return;
        }
@@ -4143,18 +4204,20 @@ wm_tbi_mediachange(struct ifnet *ifp)
        uint32_t status;
        int i;
 
-       sc->sc_txcw = ife->ifm_data;
-       DPRINTF(WM_DEBUG_LINK,("%s: sc_txcw = 0x%x on entry\n",
-                   device_xname(sc->sc_dev),sc->sc_txcw));
+       sc->sc_txcw = 0;
        if (IFM_SUBTYPE(ife->ifm_media) == IFM_AUTO ||
            (sc->sc_mii.mii_media.ifm_media & IFM_FLOW) != 0)
-               sc->sc_txcw |= ANAR_X_PAUSE_SYM | ANAR_X_PAUSE_ASYM;
+               sc->sc_txcw |= TXCW_SYM_PAUSE | TXCW_ASYM_PAUSE;
        if (IFM_SUBTYPE(ife->ifm_media) == IFM_AUTO) { 
-               sc->sc_txcw |= TXCW_ANE; 
+               sc->sc_txcw |= TXCW_ANE;
        } else {
-               /*If autonegotiation is turned off, force link up and turn on 
full duplex*/
+               /*
+                * If autonegotiation is turned off, force link up and turn on
+                * full duplex
+                */
                sc->sc_txcw &= ~TXCW_ANE;
                sc->sc_ctrl |= CTRL_SLU | CTRL_FD;
+               sc->sc_ctrl &= ~(CTRL_TFCE | CTRL_RFCE);
                CSR_WRITE(sc, WMREG_CTRL, sc->sc_ctrl);
                delay(1000);
        }
@@ -4164,10 +4227,6 @@ wm_tbi_mediachange(struct ifnet *ifp)
        CSR_WRITE(sc, WMREG_TXCW, sc->sc_txcw);
        delay(10000);
 
-       /* NOTE: CTRL will update TFCE and RFCE automatically. */
-
-       sc->sc_tbi_anstate = 0;
-
        i = CSR_READ(sc, WMREG_CTRL) & CTRL_SWDPIN(1);
        DPRINTF(WM_DEBUG_LINK,("%s: i = 0x%x\n", device_xname(sc->sc_dev),i));
 
@@ -4175,7 +4234,7 @@ wm_tbi_mediachange(struct ifnet *ifp)
         * On 82544 chips and later, the CTRL_SWDPIN(1) bit will be set if the
         * optics detect a signal, 0 if they don't.
         */
-       if (((i != 0) && (sc->sc_type >= WM_T_82544)) || (i == 0)) {
+       if (((i != 0) && (sc->sc_type > WM_T_82544)) || (i == 0)) {
                /* Have signal; wait for the link to come up. */
 
                if (IFM_SUBTYPE(ife->ifm_media) == IFM_AUTO) {
@@ -4190,7 +4249,7 @@ wm_tbi_mediachange(struct ifnet *ifp)
                        delay(1000);
                }
 
-               for (i = 0; i < 50; i++) {
+               for (i = 0; i < WM_LINKUP_TIMEOUT; i++) {
                        delay(10000);
                        if (CSR_READ(sc, WMREG_STATUS) & STATUS_LU)
                                break;
@@ -4209,6 +4268,12 @@ wm_tbi_mediachange(struct ifnet *ifp)
                            ("%s: LINK: set media -> link up %s\n",
                            device_xname(sc->sc_dev),
                            (status & STATUS_FD) ? "FDX" : "HDX"));
+
+                       /*
+                        * NOTE: CTRL will update TFCE and RFCE automatically,
+                        * so we should update sc->sc_ctrl
+                        */
+                       sc->sc_ctrl = CSR_READ(sc, WMREG_CTRL);
                        sc->sc_tctl &= ~TCTL_COLD(0x3ff);
                        sc->sc_fcrtl &= ~FCRTL_XONE;
                        if (status & STATUS_FD)
@@ -4225,6 +4290,8 @@ wm_tbi_mediachange(struct ifnet *ifp)
                                      sc->sc_fcrtl);
                        sc->sc_tbi_linkup = 1;
                } else {
+                       if (i == WM_LINKUP_TIMEOUT)
+                               wm_check_for_link(sc);
                        /* Link is down. */
                        DPRINTF(WM_DEBUG_LINK,
                            ("%s: LINK: set media -> link down\n",
@@ -4256,6 +4323,9 @@ wm_tbi_set_linkled(struct wm_softc *sc)
        else
                sc->sc_ctrl &= ~CTRL_SWDPIN(0);
 
+       /* 82540 or newer devices are active low */
+       sc->sc_ctrl ^= (sc->sc_type >= WM_T_82540) ? CTRL_SWDPIN(0) : 0;
+
        CSR_WRITE(sc, WMREG_CTRL, sc->sc_ctrl);
 }
 
@@ -4267,49 +4337,58 @@ wm_tbi_set_linkled(struct wm_softc *sc)
 static void
 wm_tbi_check_link(struct wm_softc *sc)
 {
+       struct ifnet *ifp = &sc->sc_ethercom.ec_if;
+       struct ifmedia_entry *ife = sc->sc_mii.mii_media.ifm_cur;
        uint32_t rxcw, ctrl, status;
 
-       if (sc->sc_tbi_anstate == 0)
-               return;
-       else if (sc->sc_tbi_anstate > 1) {
-               DPRINTF(WM_DEBUG_LINK,
-                   ("%s: LINK: anstate %d\n", device_xname(sc->sc_dev),
-                   sc->sc_tbi_anstate));
-               sc->sc_tbi_anstate--;
-               return;
-       }
-
-       sc->sc_tbi_anstate = 0;
+       status = CSR_READ(sc, WMREG_STATUS);
 
        rxcw = CSR_READ(sc, WMREG_RXCW);
        ctrl = CSR_READ(sc, WMREG_CTRL);
-       status = CSR_READ(sc, WMREG_STATUS);
 
+       /* set link status */
        if ((status & STATUS_LU) == 0) {
                DPRINTF(WM_DEBUG_LINK,
                    ("%s: LINK: checklink -> down\n", 
device_xname(sc->sc_dev)));
                sc->sc_tbi_linkup = 0;
-       } else {
+       } else if (sc->sc_tbi_linkup == 0) {
                DPRINTF(WM_DEBUG_LINK,
                    ("%s: LINK: checklink -> up %s\n", device_xname(sc->sc_dev),
                    (status & STATUS_FD) ? "FDX" : "HDX"));
-               sc->sc_tctl &= ~TCTL_COLD(0x3ff);
-               sc->sc_fcrtl &= ~FCRTL_XONE;
-               if (status & STATUS_FD)
-                       sc->sc_tctl |=
-                           TCTL_COLD(TX_COLLISION_DISTANCE_FDX);
-               else
-                       sc->sc_tctl |=
-                           TCTL_COLD(TX_COLLISION_DISTANCE_HDX);
-               if (ctrl & CTRL_TFCE)
-                       sc->sc_fcrtl |= FCRTL_XONE;
-               CSR_WRITE(sc, WMREG_TCTL, sc->sc_tctl);
-               CSR_WRITE(sc, (sc->sc_type < WM_T_82543) ?
-                             WMREG_OLD_FCRTL : WMREG_FCRTL,
-                             sc->sc_fcrtl);
                sc->sc_tbi_linkup = 1;
        }
 
+       if ((sc->sc_ethercom.ec_if.if_flags & IFF_UP)
+           && ((status & STATUS_LU) == 0)) {
+               sc->sc_tbi_linkup = 0;
+               if (sc->sc_tbi_nrxcfg - sc->sc_tbi_lastnrxcfg > 100) {
+                       /* RXCFG storm! */
+                       DPRINTF(WM_DEBUG_LINK, ("RXCFG storm! (%d)\n",
+                               sc->sc_tbi_nrxcfg - sc->sc_tbi_lastnrxcfg));
+                       wm_init(ifp);
+                       wm_start(ifp);
+               } else if (IFM_SUBTYPE(ife->ifm_media) == IFM_AUTO) {
+                       /* If the timer expired, retry autonegotiation */
+                       if (++sc->sc_tbi_ticks >= sc->sc_tbi_anegticks) {
+                               DPRINTF(WM_DEBUG_LINK, ("EXPIRE\n"));
+                               sc->sc_tbi_ticks = 0;
+                               /*
+                                * Reset the link, and let autonegotiation do
+                                * its thing
+                                */
+                               sc->sc_ctrl |= CTRL_LRST;
+                               CSR_WRITE(sc, WMREG_CTRL, sc->sc_ctrl);
+                               delay(1000);
+                               sc->sc_ctrl &= ~CTRL_LRST;
+                               CSR_WRITE(sc, WMREG_CTRL, sc->sc_ctrl);
+                               delay(1000);
+                               CSR_WRITE(sc, WMREG_TXCW,
+                                   sc->sc_txcw & ~TXCW_ANE);
+                               CSR_WRITE(sc, WMREG_TXCW, sc->sc_txcw);
+                       }
+               }
+       }
+
        wm_tbi_set_linkled(sc);
 }
 
@@ -4324,7 +4403,8 @@ wm_gmii_reset(struct wm_softc *sc)
        uint32_t reg;
        int func = 0; /* XXX gcc */
 
-       if ((sc->sc_type == WM_T_ICH8) || (sc->sc_type == WM_T_ICH9)) {
+       if ((sc->sc_type == WM_T_ICH8) || (sc->sc_type == WM_T_ICH9)
+           || (sc->sc_type == WM_T_ICH10)) {
                if (wm_get_swfwhw_semaphore(sc)) {
                        aprint_error_dev(sc->sc_dev,
                            "%s: failed to get semaphore\n", __func__);
@@ -4374,7 +4454,8 @@ wm_gmii_reset(struct wm_softc *sc)
                sc->sc_ctrl_ext = reg | CTRL_EXT_SWDPIN(4);
 #endif
        }
-       if ((sc->sc_type == WM_T_ICH8) || (sc->sc_type == WM_T_ICH9))
+       if ((sc->sc_type == WM_T_ICH8) || (sc->sc_type == WM_T_ICH9)
+           || (sc->sc_type == WM_T_ICH10))
                wm_put_swfwhw_semaphore(sc);
        if (sc->sc_type == WM_T_80003)
                wm_put_swfw_semaphore(sc, func ? SWFW_PHY1_SM : SWFW_PHY0_SM);
@@ -4410,7 +4491,10 @@ wm_gmii_mediainit(struct wm_softc *sc)
        /* Initialize our media structures and probe the GMII. */
        sc->sc_mii.mii_ifp = ifp;
 
-       if (sc->sc_type >= WM_T_80003) {
+       if (sc->sc_type == WM_T_ICH10) {
+               sc->sc_mii.mii_readreg = wm_gmii_bm_readreg;
+               sc->sc_mii.mii_writereg = wm_gmii_bm_writereg;
+       } else if (sc->sc_type >= WM_T_80003) {
                sc->sc_mii.mii_readreg = wm_gmii_i80003_readreg;
                sc->sc_mii.mii_writereg = wm_gmii_i80003_writereg;
        } else if (sc->sc_type >= WM_T_82544) {
@@ -4706,12 +4790,11 @@ wm_gmii_i80003_readreg(device_t self, in
                wm_gmii_i82544_writereg(self, phy, GG82563_PHY_PAGE_SELECT_ALT,
                    reg >> GG82563_PAGE_SHIFT);
        }
-
        /* Wait more 200us for a bug of the ready bit in the MDIC register */
        delay(200);
-
        rv = wm_gmii_i82544_readreg(self, phy, reg & GG82563_MAX_REG_ADDRESS);
        delay(200);
+
        wm_put_swfw_semaphore(sc, func ? SWFW_PHY1_SM : SWFW_PHY0_SM);
        return (rv);
 }
@@ -4745,12 +4828,79 @@ wm_gmii_i80003_writereg(device_t self, i
                wm_gmii_i82544_writereg(self, phy, GG82563_PHY_PAGE_SELECT_ALT,
                    reg >> GG82563_PAGE_SHIFT);
        }
-
        /* Wait more 200us for a bug of the ready bit in the MDIC register */
        delay(200);
-
        wm_gmii_i82544_writereg(self, phy, reg & GG82563_MAX_REG_ADDRESS, val);
        delay(200);
+
+       wm_put_swfw_semaphore(sc, func ? SWFW_PHY1_SM : SWFW_PHY0_SM);
+}
+
+/*
+ * wm_gmii_bm_readreg: [mii interface function]
+ *
+ *     Read a PHY register on the kumeran
+ * This could be handled by the PHY layer if we didn't have to lock the
+ * ressource ...
+ */
+static int
+wm_gmii_bm_readreg(device_t self, int phy, int reg)
+{
+       struct wm_softc *sc = device_private(self);
+       int func = ((CSR_READ(sc, WMREG_STATUS) >> STATUS_FUNCID_SHIFT) & 1);
+       int rv;
+
+       if (wm_get_swfw_semaphore(sc, func ? SWFW_PHY1_SM : SWFW_PHY0_SM)) {
+               aprint_error_dev(sc->sc_dev, "%s: failed to get semaphore\n",
+                   __func__);
+               return 0;
+       }
+
+       if (reg > GG82563_MAX_REG_ADDRESS) {
+               if (phy == 1)
+                       wm_gmii_i82544_writereg(self, phy, 0x1f,
+                           reg);
+               else
+                       wm_gmii_i82544_writereg(self, phy, 
GG82563_PHY_PAGE_SELECT,
+                           reg >> GG82563_PAGE_SHIFT);
+
+       }
+
+       rv = wm_gmii_i82544_readreg(self, phy, reg & GG82563_MAX_REG_ADDRESS);
+       wm_put_swfw_semaphore(sc, func ? SWFW_PHY1_SM : SWFW_PHY0_SM);
+       return (rv);
+}
+
+/*
+ * wm_gmii_bm_writereg:        [mii interface function]
+ *
+ *     Write a PHY register on the kumeran.
+ * This could be handled by the PHY layer if we didn't have to lock the
+ * ressource ...
+ */
+static void
+wm_gmii_bm_writereg(device_t self, int phy, int reg, int val)
+{
+       struct wm_softc *sc = device_private(self);
+       int func = ((CSR_READ(sc, WMREG_STATUS) >> STATUS_FUNCID_SHIFT) & 1);
+
+       if (wm_get_swfw_semaphore(sc, func ? SWFW_PHY1_SM : SWFW_PHY0_SM)) {
+               aprint_error_dev(sc->sc_dev, "%s: failed to get semaphore\n",
+                   __func__);
+               return;
+       }
+
+       if (reg > GG82563_MAX_REG_ADDRESS) {
+               if (phy == 1)
+                       wm_gmii_i82544_writereg(self, phy, 0x1f,
+                           reg);
+               else
+                       wm_gmii_i82544_writereg(self, phy, 
GG82563_PHY_PAGE_SELECT,
+                           reg >> GG82563_PAGE_SHIFT);
+
+       }
+
+       wm_gmii_i82544_writereg(self, phy, reg & GG82563_MAX_REG_ADDRESS, val);
        wm_put_swfw_semaphore(sc, func ? SWFW_PHY1_SM : SWFW_PHY0_SM);
 }
 
@@ -5006,6 +5156,36 @@ wm_put_swfwhw_semaphore(struct wm_softc 
        CSR_WRITE(sc, WMREG_EXTCNFCTR, ext_ctrl);
 }
 
+static int
+wm_valid_nvm_bank_detect_ich8lan(struct wm_softc *sc, unsigned int *bank)
+{
+       uint32_t act_offset = ICH_NVM_SIG_WORD * 2 + 1;
+       uint8_t bank_high_byte;
+       uint32_t bank1_offset = sc->sc_ich8_flash_bank_size * sizeof(uint16_t);
+
+       if (sc->sc_type != WM_T_ICH10) {
+               /* Value of bit 22 corresponds to the flash bank we're on. */
+               *bank = (CSR_READ(sc, WMREG_EECD) & EECD_SEC1VAL) ? 1 : 0;
+       } else {
+               wm_read_ich8_byte(sc, act_offset, &bank_high_byte);
+               if ((bank_high_byte & 0xc0) == 0x80)
+                       *bank = 0;
+               else {
+                       wm_read_ich8_byte(sc, act_offset + bank1_offset,
+                           &bank_high_byte);
+                       if ((bank_high_byte & 0xc0) == 0x80)
+                               *bank = 1;
+                       else {
+                               aprint_error_dev(sc->sc_dev,
+                                   "EEPROM not present\n");
+                               return -1;
+                       }
+               }
+       }
+
+       return 0;
+}
+
 /******************************************************************************
  * Reads a 16 bit word or words from the EEPROM using the ICH8's flash access
  * register.
@@ -5030,8 +5210,12 @@ wm_read_eeprom_ich8(struct wm_softc *sc,
      * managing flash_bank.  So it cannot be trusted and needs
      * to be updated with each read.
      */
-    /* Value of bit 22 corresponds to the flash bank we're on. */
-    flash_bank = (CSR_READ(sc, WMREG_EECD) & EECD_SEC1VAL) ? 1 : 0;
+    error = wm_valid_nvm_bank_detect_ich8lan(sc, &flash_bank);
+    if (error) {
+           aprint_error_dev(sc->sc_dev, "%s: failed to detect NVM bank\n",
+                   __func__);
+        return error;
+    }
 
     /* Adjust offset appropriately if we're on bank 1 - adjust for word size */
     bank_offset = flash_bank * (sc->sc_ich8_flash_bank_size * 2);
@@ -5229,7 +5413,6 @@ wm_read_ich8_data(struct wm_softc *sc, u
     return error;
 }
 
-#if 0
 /******************************************************************************
  * Reads a single byte from the NVM using the ICH8 flash access registers.
  *
@@ -5250,7 +5433,6 @@ wm_read_ich8_byte(struct wm_softc *sc, u
 
     return status;
 }
-#endif
 
 /******************************************************************************
  * Reads a word from the NVM using the ICH8 flash access registers.
@@ -5276,14 +5458,28 @@ wm_check_mng_mode(struct wm_softc *sc)
        switch (sc->sc_type) {
        case WM_T_ICH8:
        case WM_T_ICH9:
+       case WM_T_ICH10:
                rv = wm_check_mng_mode_ich8lan(sc);
                break;
+#if 0
        case WM_T_82574:
+               /*
+                * The function is provided in em driver, but it's not
+                * used. Why?
+                */
                rv = wm_check_mng_mode_82574(sc);
                break;
-       default:
+#endif
+       case WM_T_82571:
+       case WM_T_82572:
+       case WM_T_82573:
+       case WM_T_80003:
                rv = wm_check_mng_mode_generic(sc);
                break;
+       default:
+               /* noting to do */
+               rv = 0;
+               break;
        }
 
        return rv;
@@ -5302,6 +5498,7 @@ wm_check_mng_mode_ich8lan(struct wm_soft
        return 0;
 }
 
+#if 0
 static int
 wm_check_mng_mode_82574(struct wm_softc *sc)
 {
@@ -5314,6 +5511,7 @@ wm_check_mng_mode_82574(struct wm_softc 
 
        return 0;
 }
+#endif
 
 static int
 wm_check_mng_mode_generic(struct wm_softc *sc)
@@ -5335,6 +5533,13 @@ wm_get_hw_control(struct wm_softc *sc)
 
        switch (sc->sc_type) {
        case WM_T_82573:
+#if 0
+       case WM_T_82574:
+               /*
+                * FreeBSD's em driver has the function for 82574 to checks
+                * the management mode, but it's not used. Why?
+                */
+#endif
                reg = CSR_READ(sc, WMREG_SWSM);
                CSR_WRITE(sc, WMREG_SWSM, reg | SWSM_DRV_LOAD);
                break;
@@ -5343,6 +5548,7 @@ wm_get_hw_control(struct wm_softc *sc)
        case WM_T_80003:
        case WM_T_ICH8:
        case WM_T_ICH9:
+       case WM_T_ICH10:
                reg = CSR_READ(sc, WMREG_CTRL_EXT);
                CSR_WRITE(sc, WMREG_CTRL_EXT, reg | CTRL_EXT_DRV_LOAD);
                break;
@@ -5350,3 +5556,74 @@ wm_get_hw_control(struct wm_softc *sc)
                break;
        }
 }
+
+/* XXX Currently TBI only */
+static int
+wm_check_for_link(struct wm_softc *sc)
+{
+       struct ifmedia_entry *ife = sc->sc_mii.mii_media.ifm_cur;
+       uint32_t rxcw;
+       uint32_t ctrl;
+       uint32_t status;
+       uint32_t sig;
+
+       rxcw = CSR_READ(sc, WMREG_RXCW);
+       ctrl = CSR_READ(sc, WMREG_CTRL);
+       status = CSR_READ(sc, WMREG_STATUS);
+
+       sig = (sc->sc_type > WM_T_82544) ? CTRL_SWDPIN(1) : 0;
+
+       DPRINTF(WM_DEBUG_LINK, ("%s: %s: sig = %d, status_lu = %d, rxcw_c = 
%d\n",
+               device_xname(sc->sc_dev), __func__,
+               ((ctrl & CTRL_SWDPIN(1)) == sig),
+               ((status & STATUS_LU) != 0),
+               ((rxcw & RXCW_C) != 0)
+                   ));
+
+       /*
+        * SWDPIN   LU RXCW
+        *      0    0    0
+        *      0    0    1     (should not happen)
+        *      0    1    0     (should not happen)
+        *      0    1    1     (should not happen)
+        *      1    0    0     Disable autonego and force linkup
+        *      1    0    1     got /C/ but not linkup yet
+        *      1    1    0     (linkup)
+        *      1    1    1     If IFM_AUTO, back to autonego
+        *
+        */
+       if (((ctrl & CTRL_SWDPIN(1)) == sig)
+           && ((status & STATUS_LU) == 0)
+           && ((rxcw & RXCW_C) == 0)) {
+               DPRINTF(WM_DEBUG_LINK, ("%s: force linkup and fullduplex\n",
+                       __func__));
+               sc->sc_tbi_linkup = 0;
+               /* Disable auto-negotiation in the TXCW register */
+               CSR_WRITE(sc, WMREG_TXCW, (sc->sc_txcw & ~TXCW_ANE));
+
+               /*
+                * Force link-up and also force full-duplex.
+                *
+                * NOTE: CTRL was updated TFCE and RFCE automatically,
+                * so we should update sc->sc_ctrl
+                */
+               sc->sc_ctrl = ctrl | CTRL_SLU | CTRL_FD;
+               CSR_WRITE(sc, WMREG_CTRL, sc->sc_ctrl);
+       } else if(((status & STATUS_LU) != 0)
+           && ((rxcw & RXCW_C) != 0)
+           && (IFM_SUBTYPE(ife->ifm_media) == IFM_AUTO)) {
+               sc->sc_tbi_linkup = 1;
+               DPRINTF(WM_DEBUG_LINK, ("%s: go back to autonego\n",
+                       __func__));
+               CSR_WRITE(sc, WMREG_TXCW, sc->sc_txcw);
+               CSR_WRITE(sc, WMREG_CTRL, (ctrl & ~CTRL_SLU));
+       } else if (((ctrl & CTRL_SWDPIN(1)) == sig)
+           && ((rxcw & RXCW_C) != 0)) {
+               DPRINTF(WM_DEBUG_LINK, ("/C/"));
+       } else {
+               DPRINTF(WM_DEBUG_LINK, ("%s: %x,%x,%x\n", __func__, rxcw, ctrl,
+                       status));
+       }
+
+       return 0;
+}
Index: if_wmreg.h
===================================================================
RCS file: /cvsroot/src/sys/dev/pci/if_wmreg.h,v
retrieving revision 1.24.20.1
diff -u -p -u -r1.24.20.1 if_wmreg.h
--- if_wmreg.h  3 May 2009 17:51:02 -0000       1.24.20.1
+++ if_wmreg.h  19 May 2009 15:58:57 -0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: if_wmreg.h,v 1.24.20.1 2009/05/03 17:51:02 snj Exp $   */
+/*     $NetBSD: if_wmreg.h,v 1.27 2009/04/07 18:23:37 msaitoh Exp $    */
 
 /*
  * Copyright (c) 2001 Wasabi Systems, Inc.
@@ -482,6 +482,8 @@ struct livengood_tcpip_ctxdesc {
 
 #define        WMREG_TXCW      0x0178  /* Transmit Configuration Word (TBI 
mode) */
        /* See MII ANAR_X bits. */
+#define        TXCW_SYM_PAUSE  (1U << 7)       /* sym pause request */
+#define        TXCW_ASYM_PAUSE (1U << 8)       /* asym pause request */
 #define        TXCW_TxConfig   (1U << 30)      /* Tx Config */
 #define        TXCW_ANE        (1U << 31)      /* Autonegotiate */
 
@@ -739,5 +741,8 @@ struct livengood_tcpip_ctxdesc {
 #define ICH_GFPREG_BASE_MASK       0x1FFF
 #define ICH_FLASH_LINEAR_ADDR_MASK 0x00FFFFFF
 
+#define ICH_NVM_SIG_WORD       0x13
+#define ICH_NVM_SIG_MASK       0xc000
+
 #define        NVM_INIT_CONTROL2_REG   0x000f
 #define        NVM_INIT_CTRL2_MNGM     0x6000


Home | Main Index | Thread Index | Old Index