Fix about TBI mode. This fix doesn't influence MII mode.
- Fix panic in mediachange. - Fix SWDPIN(1)'s polarity on some chips. - Fix flow control stuff (includes PR#32009). - Stop RXCFG storm. It ocours easily. - And more fix about autonego. Tested on PRO/1000F, PRO/1000XF and PRO/1000 MF.
This commit is contained in:
parent
0873e7f203
commit
0855c70d27
@ -1,4 +1,4 @@
|
|||||||
/* $NetBSD: if_wm.c,v 1.172 2009/03/31 06:58:55 darran Exp $ */
|
/* $NetBSD: if_wm.c,v 1.173 2009/04/07 18:23:37 msaitoh Exp $ */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2001, 2002, 2003, 2004 Wasabi Systems, Inc.
|
* Copyright (c) 2001, 2002, 2003, 2004 Wasabi Systems, Inc.
|
||||||
@ -79,7 +79,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <sys/cdefs.h>
|
#include <sys/cdefs.h>
|
||||||
__KERNEL_RCSID(0, "$NetBSD: if_wm.c,v 1.172 2009/03/31 06:58:55 darran Exp $");
|
__KERNEL_RCSID(0, "$NetBSD: if_wm.c,v 1.173 2009/04/07 18:23:37 msaitoh Exp $");
|
||||||
|
|
||||||
#include "bpfilter.h"
|
#include "bpfilter.h"
|
||||||
#include "rnd.h"
|
#include "rnd.h"
|
||||||
@ -257,6 +257,8 @@ typedef enum {
|
|||||||
WM_T_ICH10, /* ICH10 LAN */
|
WM_T_ICH10, /* ICH10 LAN */
|
||||||
} wm_chip_type;
|
} wm_chip_type;
|
||||||
|
|
||||||
|
#define WM_LINKUP_TIMEOUT 50
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Software state per device.
|
* Software state per device.
|
||||||
*/
|
*/
|
||||||
@ -377,7 +379,10 @@ struct wm_softc {
|
|||||||
uint32_t sc_pba; /* prototype PBA register */
|
uint32_t sc_pba; /* prototype PBA register */
|
||||||
|
|
||||||
int sc_tbi_linkup; /* TBI link status */
|
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 */
|
int sc_mchash_type; /* multicast filter offset */
|
||||||
|
|
||||||
@ -594,6 +599,7 @@ static int wm_check_mng_mode_82574(struct wm_softc *);
|
|||||||
#endif
|
#endif
|
||||||
static int wm_check_mng_mode_generic(struct wm_softc *);
|
static int wm_check_mng_mode_generic(struct wm_softc *);
|
||||||
static void wm_get_hw_control(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),
|
CFATTACH_DECL_NEW(wm, sizeof(struct wm_softc),
|
||||||
wm_match, wm_attach, NULL, NULL);
|
wm_match, wm_attach, NULL, NULL);
|
||||||
@ -2780,6 +2786,8 @@ wm_linkintr(struct wm_softc *sc, uint32_t icr)
|
|||||||
{
|
{
|
||||||
uint32_t status;
|
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
|
* If we get a link status interrupt on a 1000BASE-T
|
||||||
* device, just fall into the normal MII tick path.
|
* device, just fall into the normal MII tick path.
|
||||||
@ -2836,22 +2844,18 @@ wm_linkintr(struct wm_softc *sc, uint32_t icr)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
status = CSR_READ(sc, WMREG_STATUS);
|
||||||
* 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (icr & ICR_LSC) {
|
if (icr & ICR_LSC) {
|
||||||
status = CSR_READ(sc, WMREG_STATUS);
|
|
||||||
if (status & STATUS_LU) {
|
if (status & STATUS_LU) {
|
||||||
DPRINTF(WM_DEBUG_LINK, ("%s: LINK: LSC -> up %s\n",
|
DPRINTF(WM_DEBUG_LINK, ("%s: LINK: LSC -> up %s\n",
|
||||||
device_xname(sc->sc_dev),
|
device_xname(sc->sc_dev),
|
||||||
(status & STATUS_FD) ? "FDX" : "HDX"));
|
(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_tctl &= ~TCTL_COLD(0x3ff);
|
||||||
sc->sc_fcrtl &= ~FCRTL_XONE;
|
sc->sc_fcrtl &= ~FCRTL_XONE;
|
||||||
if (status & STATUS_FD)
|
if (status & STATUS_FD)
|
||||||
@ -2860,7 +2864,7 @@ wm_linkintr(struct wm_softc *sc, uint32_t icr)
|
|||||||
else
|
else
|
||||||
sc->sc_tctl |=
|
sc->sc_tctl |=
|
||||||
TCTL_COLD(TX_COLLISION_DISTANCE_HDX);
|
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;
|
sc->sc_fcrtl |= FCRTL_XONE;
|
||||||
CSR_WRITE(sc, WMREG_TCTL, sc->sc_tctl);
|
CSR_WRITE(sc, WMREG_TCTL, sc->sc_tctl);
|
||||||
CSR_WRITE(sc, (sc->sc_type < WM_T_82543) ?
|
CSR_WRITE(sc, (sc->sc_type < WM_T_82543) ?
|
||||||
@ -2872,8 +2876,12 @@ wm_linkintr(struct wm_softc *sc, uint32_t icr)
|
|||||||
device_xname(sc->sc_dev)));
|
device_xname(sc->sc_dev)));
|
||||||
sc->sc_tbi_linkup = 0;
|
sc->sc_tbi_linkup = 0;
|
||||||
}
|
}
|
||||||
sc->sc_tbi_anstate = 2;
|
|
||||||
wm_tbi_set_linkled(sc);
|
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) {
|
} else if (icr & ICR_RXSEQ) {
|
||||||
DPRINTF(WM_DEBUG_LINK,
|
DPRINTF(WM_DEBUG_LINK,
|
||||||
("%s: LINK: Receive sequence error\n",
|
("%s: LINK: Receive sequence error\n",
|
||||||
@ -3305,6 +3313,9 @@ wm_init(struct ifnet *ifp)
|
|||||||
reg |= RXCSUM_IPV6OFL | RXCSUM_TUOFL;
|
reg |= RXCSUM_IPV6OFL | RXCSUM_TUOFL;
|
||||||
CSR_WRITE(sc, WMREG_RXCSUM, reg);
|
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.
|
* Set up the interrupt registers.
|
||||||
*/
|
*/
|
||||||
@ -3461,6 +3472,11 @@ wm_stop(struct ifnet *ifp, int disable)
|
|||||||
if (sc->sc_flags & WM_F_HAS_MII) {
|
if (sc->sc_flags & WM_F_HAS_MII) {
|
||||||
/* Down the MII. */
|
/* Down the MII. */
|
||||||
mii_down(&sc->sc_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. */
|
/* Stop the transmit and receive processes. */
|
||||||
@ -4095,6 +4111,7 @@ wm_set_filter(struct wm_softc *sc)
|
|||||||
static void
|
static void
|
||||||
wm_tbi_mediainit(struct wm_softc *sc)
|
wm_tbi_mediainit(struct wm_softc *sc)
|
||||||
{
|
{
|
||||||
|
struct ifnet *ifp = &sc->sc_ethercom.ec_if;
|
||||||
const char *sep = "";
|
const char *sep = "";
|
||||||
|
|
||||||
if (sc->sc_type < WM_T_82543)
|
if (sc->sc_type < WM_T_82543)
|
||||||
@ -4102,6 +4119,12 @@ wm_tbi_mediainit(struct wm_softc *sc)
|
|||||||
else
|
else
|
||||||
sc->sc_tipg = TIPG_LG_DFLT;
|
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,
|
ifmedia_init(&sc->sc_mii.mii_media, IFM_IMASK, wm_tbi_mediachange,
|
||||||
wm_tbi_mediastatus);
|
wm_tbi_mediastatus);
|
||||||
|
|
||||||
@ -4143,12 +4166,13 @@ static void
|
|||||||
wm_tbi_mediastatus(struct ifnet *ifp, struct ifmediareq *ifmr)
|
wm_tbi_mediastatus(struct ifnet *ifp, struct ifmediareq *ifmr)
|
||||||
{
|
{
|
||||||
struct wm_softc *sc = ifp->if_softc;
|
struct wm_softc *sc = ifp->if_softc;
|
||||||
uint32_t ctrl;
|
uint32_t ctrl, status;
|
||||||
|
|
||||||
ifmr->ifm_status = IFM_AVALID;
|
ifmr->ifm_status = IFM_AVALID;
|
||||||
ifmr->ifm_active = IFM_ETHER;
|
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;
|
ifmr->ifm_active |= IFM_NONE;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -4177,18 +4201,20 @@ wm_tbi_mediachange(struct ifnet *ifp)
|
|||||||
uint32_t status;
|
uint32_t status;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
sc->sc_txcw = ife->ifm_data;
|
sc->sc_txcw = 0;
|
||||||
DPRINTF(WM_DEBUG_LINK,("%s: sc_txcw = 0x%x on entry\n",
|
|
||||||
device_xname(sc->sc_dev),sc->sc_txcw));
|
|
||||||
if (IFM_SUBTYPE(ife->ifm_media) == IFM_AUTO ||
|
if (IFM_SUBTYPE(ife->ifm_media) == IFM_AUTO ||
|
||||||
(sc->sc_mii.mii_media.ifm_media & IFM_FLOW) != 0)
|
(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) {
|
if (IFM_SUBTYPE(ife->ifm_media) == IFM_AUTO) {
|
||||||
sc->sc_txcw |= TXCW_ANE;
|
sc->sc_txcw |= TXCW_ANE;
|
||||||
} else {
|
} 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_txcw &= ~TXCW_ANE;
|
||||||
sc->sc_ctrl |= CTRL_SLU | CTRL_FD;
|
sc->sc_ctrl |= CTRL_SLU | CTRL_FD;
|
||||||
|
sc->sc_ctrl &= ~(CTRL_TFCE | CTRL_RFCE);
|
||||||
CSR_WRITE(sc, WMREG_CTRL, sc->sc_ctrl);
|
CSR_WRITE(sc, WMREG_CTRL, sc->sc_ctrl);
|
||||||
delay(1000);
|
delay(1000);
|
||||||
}
|
}
|
||||||
@ -4198,10 +4224,6 @@ wm_tbi_mediachange(struct ifnet *ifp)
|
|||||||
CSR_WRITE(sc, WMREG_TXCW, sc->sc_txcw);
|
CSR_WRITE(sc, WMREG_TXCW, sc->sc_txcw);
|
||||||
delay(10000);
|
delay(10000);
|
||||||
|
|
||||||
/* NOTE: CTRL will update TFCE and RFCE automatically. */
|
|
||||||
|
|
||||||
sc->sc_tbi_anstate = 0;
|
|
||||||
|
|
||||||
i = CSR_READ(sc, WMREG_CTRL) & CTRL_SWDPIN(1);
|
i = CSR_READ(sc, WMREG_CTRL) & CTRL_SWDPIN(1);
|
||||||
DPRINTF(WM_DEBUG_LINK,("%s: i = 0x%x\n", device_xname(sc->sc_dev),i));
|
DPRINTF(WM_DEBUG_LINK,("%s: i = 0x%x\n", device_xname(sc->sc_dev),i));
|
||||||
|
|
||||||
@ -4209,7 +4231,7 @@ wm_tbi_mediachange(struct ifnet *ifp)
|
|||||||
* On 82544 chips and later, the CTRL_SWDPIN(1) bit will be set if the
|
* On 82544 chips and later, the CTRL_SWDPIN(1) bit will be set if the
|
||||||
* optics detect a signal, 0 if they don't.
|
* 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. */
|
/* Have signal; wait for the link to come up. */
|
||||||
|
|
||||||
if (IFM_SUBTYPE(ife->ifm_media) == IFM_AUTO) {
|
if (IFM_SUBTYPE(ife->ifm_media) == IFM_AUTO) {
|
||||||
@ -4224,7 +4246,7 @@ wm_tbi_mediachange(struct ifnet *ifp)
|
|||||||
delay(1000);
|
delay(1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < 50; i++) {
|
for (i = 0; i < WM_LINKUP_TIMEOUT; i++) {
|
||||||
delay(10000);
|
delay(10000);
|
||||||
if (CSR_READ(sc, WMREG_STATUS) & STATUS_LU)
|
if (CSR_READ(sc, WMREG_STATUS) & STATUS_LU)
|
||||||
break;
|
break;
|
||||||
@ -4243,6 +4265,12 @@ wm_tbi_mediachange(struct ifnet *ifp)
|
|||||||
("%s: LINK: set media -> link up %s\n",
|
("%s: LINK: set media -> link up %s\n",
|
||||||
device_xname(sc->sc_dev),
|
device_xname(sc->sc_dev),
|
||||||
(status & STATUS_FD) ? "FDX" : "HDX"));
|
(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_tctl &= ~TCTL_COLD(0x3ff);
|
||||||
sc->sc_fcrtl &= ~FCRTL_XONE;
|
sc->sc_fcrtl &= ~FCRTL_XONE;
|
||||||
if (status & STATUS_FD)
|
if (status & STATUS_FD)
|
||||||
@ -4259,6 +4287,8 @@ wm_tbi_mediachange(struct ifnet *ifp)
|
|||||||
sc->sc_fcrtl);
|
sc->sc_fcrtl);
|
||||||
sc->sc_tbi_linkup = 1;
|
sc->sc_tbi_linkup = 1;
|
||||||
} else {
|
} else {
|
||||||
|
if (i == WM_LINKUP_TIMEOUT)
|
||||||
|
wm_check_for_link(sc);
|
||||||
/* Link is down. */
|
/* Link is down. */
|
||||||
DPRINTF(WM_DEBUG_LINK,
|
DPRINTF(WM_DEBUG_LINK,
|
||||||
("%s: LINK: set media -> link down\n",
|
("%s: LINK: set media -> link down\n",
|
||||||
@ -4290,6 +4320,9 @@ wm_tbi_set_linkled(struct wm_softc *sc)
|
|||||||
else
|
else
|
||||||
sc->sc_ctrl &= ~CTRL_SWDPIN(0);
|
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);
|
CSR_WRITE(sc, WMREG_CTRL, sc->sc_ctrl);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -4301,49 +4334,58 @@ wm_tbi_set_linkled(struct wm_softc *sc)
|
|||||||
static void
|
static void
|
||||||
wm_tbi_check_link(struct wm_softc *sc)
|
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;
|
uint32_t rxcw, ctrl, status;
|
||||||
|
|
||||||
if (sc->sc_tbi_anstate == 0)
|
status = CSR_READ(sc, WMREG_STATUS);
|
||||||
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;
|
|
||||||
|
|
||||||
rxcw = CSR_READ(sc, WMREG_RXCW);
|
rxcw = CSR_READ(sc, WMREG_RXCW);
|
||||||
ctrl = CSR_READ(sc, WMREG_CTRL);
|
ctrl = CSR_READ(sc, WMREG_CTRL);
|
||||||
status = CSR_READ(sc, WMREG_STATUS);
|
|
||||||
|
|
||||||
|
/* set link status */
|
||||||
if ((status & STATUS_LU) == 0) {
|
if ((status & STATUS_LU) == 0) {
|
||||||
DPRINTF(WM_DEBUG_LINK,
|
DPRINTF(WM_DEBUG_LINK,
|
||||||
("%s: LINK: checklink -> down\n", device_xname(sc->sc_dev)));
|
("%s: LINK: checklink -> down\n", device_xname(sc->sc_dev)));
|
||||||
sc->sc_tbi_linkup = 0;
|
sc->sc_tbi_linkup = 0;
|
||||||
} else {
|
} else if (sc->sc_tbi_linkup == 0) {
|
||||||
DPRINTF(WM_DEBUG_LINK,
|
DPRINTF(WM_DEBUG_LINK,
|
||||||
("%s: LINK: checklink -> up %s\n", device_xname(sc->sc_dev),
|
("%s: LINK: checklink -> up %s\n", device_xname(sc->sc_dev),
|
||||||
(status & STATUS_FD) ? "FDX" : "HDX"));
|
(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;
|
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);
|
wm_tbi_set_linkled(sc);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -5511,3 +5553,74 @@ wm_get_hw_control(struct wm_softc *sc)
|
|||||||
break;
|
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;
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user