summaryrefslogtreecommitdiffstats
path: root/sys/dev/stge
diff options
context:
space:
mode:
authoryongari <yongari@FreeBSD.org>2007-05-01 03:35:48 +0000
committeryongari <yongari@FreeBSD.org>2007-05-01 03:35:48 +0000
commitee96b9879aeecfaf263c527ec77f13f7742a3e07 (patch)
treeb42babbea8ce9a52665275a02472a4b5733b43e0 /sys/dev/stge
parent5f685fc1dc9b6bbebc958f733b9d99cdf82e0111 (diff)
downloadFreeBSD-src-ee96b9879aeecfaf263c527ec77f13f7742a3e07.zip
FreeBSD-src-ee96b9879aeecfaf263c527ec77f13f7742a3e07.tar.gz
Honor link up/down state in stge_start().
While I'm here move MAC control settings to stge_link_task, a task queue which handles link state and duplex/flow controls.
Diffstat (limited to 'sys/dev/stge')
-rw-r--r--sys/dev/stge/if_stge.c43
-rw-r--r--sys/dev/stge/if_stgereg.h1
2 files changed, 20 insertions, 24 deletions
diff --git a/sys/dev/stge/if_stge.c b/sys/dev/stge/if_stge.c
index 10ca8d5..d648cde 100644
--- a/sys/dev/stge/if_stge.c
+++ b/sys/dev/stge/if_stge.c
@@ -479,32 +479,9 @@ static void
stge_miibus_statchg(device_t dev)
{
struct stge_softc *sc;
- struct mii_data *mii;
sc = device_get_softc(dev);
- mii = device_get_softc(sc->sc_miibus);
-
- STGE_MII_LOCK(sc);
- if (IFM_SUBTYPE(mii->mii_media_active) == IFM_NONE) {
- STGE_MII_UNLOCK(sc);
- return;
- }
-
- sc->sc_MACCtrl = 0;
- if (((mii->mii_media_active & IFM_GMASK) & IFM_FDX) != 0)
- sc->sc_MACCtrl |= MC_DuplexSelect;
- if (((mii->mii_media_active & IFM_GMASK) & IFM_FLAG0) != 0)
- sc->sc_MACCtrl |= MC_RxFlowControlEnable;
- if (((mii->mii_media_active & IFM_GMASK) & IFM_FLAG1) != 0)
- sc->sc_MACCtrl |= MC_TxFlowControlEnable;
- /*
- * We can't access STGE_MACCtrl register in this context due to
- * the races between MII layer and driver which accesses this
- * register to program MAC. In order to solve the race, we defer
- * STGE_MACCtrl programming until we know we are out of MII.
- */
taskqueue_enqueue(taskqueue_swi, &sc->sc_link_task);
- STGE_MII_UNLOCK(sc);
}
/*
@@ -1317,7 +1294,7 @@ stge_start_locked(struct ifnet *ifp)
STGE_LOCK_ASSERT(sc);
if ((ifp->if_drv_flags & (IFF_DRV_RUNNING|IFF_DRV_OACTIVE)) !=
- IFF_DRV_RUNNING)
+ IFF_DRV_RUNNING || sc->sc_link == 0)
return;
for (enq = 0; !IFQ_DRV_IS_EMPTY(&ifp->if_snd); ) {
@@ -1491,11 +1468,27 @@ static void
stge_link_task(void *arg, int pending)
{
struct stge_softc *sc;
+ struct mii_data *mii;
uint32_t v, ac;
int i;
sc = (struct stge_softc *)arg;
STGE_LOCK(sc);
+
+ mii = device_get_softc(sc->sc_miibus);
+ if (mii->mii_media_status & IFM_ACTIVE) {
+ if (IFM_SUBTYPE(mii->mii_media_active) != IFM_NONE)
+ sc->sc_link = 1;
+ } else
+ sc->sc_link = 0;
+
+ sc->sc_MACCtrl = 0;
+ if (((mii->mii_media_active & IFM_GMASK) & IFM_FDX) != 0)
+ sc->sc_MACCtrl |= MC_DuplexSelect;
+ if (((mii->mii_media_active & IFM_GMASK) & IFM_FLAG0) != 0)
+ sc->sc_MACCtrl |= MC_RxFlowControlEnable;
+ if (((mii->mii_media_active & IFM_GMASK) & IFM_FLAG1) != 0)
+ sc->sc_MACCtrl |= MC_TxFlowControlEnable;
/*
* Update STGE_MACCtrl register depending on link status.
* (duplex, flow control etc)
@@ -2247,6 +2240,7 @@ stge_init_locked(struct stge_softc *sc)
stge_start_tx(sc);
stge_start_rx(sc);
+ sc->sc_link = 0;
/*
* Set the current media.
*/
@@ -2369,6 +2363,7 @@ stge_stop(struct stge_softc *sc)
*/
ifp = sc->sc_ifp;
ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE);
+ sc->sc_link = 0;
}
static void
diff --git a/sys/dev/stge/if_stgereg.h b/sys/dev/stge/if_stgereg.h
index 55ab927..4a62f4f 100644
--- a/sys/dev/stge/if_stgereg.h
+++ b/sys/dev/stge/if_stgereg.h
@@ -652,6 +652,7 @@ struct stge_softc {
int sc_rxint_dmawait;
int sc_nerr;
int sc_watchdog_timer;
+ int sc_link;
struct task sc_link_task;
struct mtx sc_mii_mtx; /* MII mutex */
OpenPOWER on IntegriCloud