summaryrefslogtreecommitdiff
path: root/sys/dev/sf
diff options
context:
space:
mode:
authorPyun YongHyeon <yongari@FreeBSD.org>2012-03-26 03:45:46 +0000
committerPyun YongHyeon <yongari@FreeBSD.org>2012-03-26 03:45:46 +0000
commitd971df44413bcf06e02632ba0dbc3af08a22d671 (patch)
tree74c8afb6acd8e6dc38ab484eec37e73fb540ac6f /sys/dev/sf
parent23946b2a9f815ea93587c126c2b29edd776d052f (diff)
Notes
Diffstat (limited to 'sys/dev/sf')
-rw-r--r--sys/dev/sf/if_sf.c102
-rw-r--r--sys/dev/sf/if_sfreg.h1
2 files changed, 57 insertions, 46 deletions
diff --git a/sys/dev/sf/if_sf.c b/sys/dev/sf/if_sf.c
index 251f310ae5d9..4f8002e0ddc2 100644
--- a/sys/dev/sf/if_sf.c
+++ b/sys/dev/sf/if_sf.c
@@ -96,7 +96,6 @@ __FBSDID("$FreeBSD$");
#include <sys/socket.h>
#include <sys/sockio.h>
#include <sys/sysctl.h>
-#include <sys/taskqueue.h>
#include <net/bpf.h>
#include <net/if.h>
@@ -172,6 +171,7 @@ static void sf_init_locked(struct sf_softc *);
static void sf_stop(struct sf_softc *);
static void sf_watchdog(struct sf_softc *);
static int sf_ifmedia_upd(struct ifnet *);
+static int sf_ifmedia_upd_locked(struct ifnet *);
static void sf_ifmedia_sts(struct ifnet *, struct ifmediareq *);
static void sf_reset(struct sf_softc *);
static int sf_dma_alloc(struct sf_softc *);
@@ -191,7 +191,6 @@ static uint8_t sf_read_eeprom(struct sf_softc *, int);
static int sf_miibus_readreg(device_t, int, int);
static int sf_miibus_writereg(device_t, int, int, int);
static void sf_miibus_statchg(device_t);
-static void sf_link_task(void *, int);
#ifdef DEVICE_POLLING
static int sf_poll(struct ifnet *ifp, enum poll_cmd cmd, int count);
#endif
@@ -393,36 +392,30 @@ static void
sf_miibus_statchg(device_t dev)
{
struct sf_softc *sc;
-
- sc = device_get_softc(dev);
- taskqueue_enqueue(taskqueue_swi, &sc->sf_link_task);
-}
-
-static void
-sf_link_task(void *arg, int pending)
-{
- struct sf_softc *sc;
struct mii_data *mii;
struct ifnet *ifp;
uint32_t val;
- sc = (struct sf_softc *)arg;
-
- SF_LOCK(sc);
-
+ sc = device_get_softc(dev);
mii = device_get_softc(sc->sf_miibus);
ifp = sc->sf_ifp;
if (mii == NULL || ifp == NULL ||
- (ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) {
- SF_UNLOCK(sc);
+ (ifp->if_drv_flags & IFF_DRV_RUNNING) == 0)
return;
- }
- if (mii->mii_media_status & IFM_ACTIVE) {
- if (IFM_SUBTYPE(mii->mii_media_active) != IFM_NONE)
+ sc->sf_link = 0;
+ if ((mii->mii_media_status & (IFM_ACTIVE | IFM_AVALID)) ==
+ (IFM_ACTIVE | IFM_AVALID)) {
+ switch (IFM_SUBTYPE(mii->mii_media_active)) {
+ case IFM_10_T:
+ case IFM_100_TX:
+ case IFM_100_FX:
sc->sf_link = 1;
- } else
- sc->sf_link = 0;
+ break;
+ }
+ }
+ if (sc->sf_link == 0)
+ return;
val = csr_read_4(sc, SF_MACCFG_1);
val &= ~SF_MACCFG1_FULLDUPLEX;
@@ -453,8 +446,6 @@ sf_link_task(void *arg, int pending)
else
val &= ~SF_TIMER_TIMES_TEN;
csr_write_4(sc, SF_TIMER_CTL, val);
-
- SF_UNLOCK(sc);
}
static void
@@ -523,20 +514,27 @@ static int
sf_ifmedia_upd(struct ifnet *ifp)
{
struct sf_softc *sc;
- struct mii_data *mii;
- struct mii_softc *miisc;
int error;
sc = ifp->if_softc;
SF_LOCK(sc);
+ error = sf_ifmedia_upd_locked(ifp);
+ SF_UNLOCK(sc);
+ return (error);
+}
+
+static int
+sf_ifmedia_upd_locked(struct ifnet *ifp)
+{
+ struct sf_softc *sc;
+ struct mii_data *mii;
+ struct mii_softc *miisc;
+ sc = ifp->if_softc;
mii = device_get_softc(sc->sf_miibus);
LIST_FOREACH(miisc, &mii->mii_phys, mii_list)
PHY_RESET(miisc);
- error = mii_mediachg(mii);
- SF_UNLOCK(sc);
-
- return (error);
+ return (mii_mediachg(mii));
}
/*
@@ -550,8 +548,12 @@ sf_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr)
sc = ifp->if_softc;
SF_LOCK(sc);
- mii = device_get_softc(sc->sf_miibus);
+ if ((ifp->if_flags & IFF_UP) == 0) {
+ SF_UNLOCK(sc);
+ return;
+ }
+ mii = device_get_softc(sc->sf_miibus);
mii_pollstat(mii);
ifmr->ifm_active = mii->mii_media_active;
ifmr->ifm_status = mii->mii_media_status;
@@ -592,7 +594,8 @@ sf_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
case SIOCADDMULTI:
case SIOCDELMULTI:
SF_LOCK(sc);
- sf_rxfilter(sc);
+ if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0)
+ sf_rxfilter(sc);
SF_UNLOCK(sc);
break;
case SIOCGIFMEDIA:
@@ -744,7 +747,6 @@ sf_attach(device_t dev)
mtx_init(&sc->sf_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK,
MTX_DEF);
callout_init_mtx(&sc->sf_co, &sc->sf_mtx, 0);
- TASK_INIT(&sc->sf_link_task, 0, sf_link_task, sc);
/*
* Map control/status registers.
@@ -946,7 +948,6 @@ sf_detach(device_t dev)
sf_stop(sc);
SF_UNLOCK(sc);
callout_drain(&sc->sf_co);
- taskqueue_drain(taskqueue_swi, &sc->sf_link_task);
if (ifp != NULL)
ether_ifdetach(ifp);
}
@@ -1548,7 +1549,9 @@ sf_rxeof(struct sf_softc *sc)
*/
eidx = 0;
prog = 0;
- for (cons = sc->sf_cdata.sf_rxc_cons; ; SF_INC(cons, SF_RX_CLIST_CNT)) {
+ for (cons = sc->sf_cdata.sf_rxc_cons;
+ (ifp->if_drv_flags & IFF_DRV_RUNNING) != 0;
+ SF_INC(cons, SF_RX_CLIST_CNT)) {
cur_cmp = &sc->sf_rdata.sf_rx_cring[cons];
status = le32toh(cur_cmp->sf_rx_status1);
if (status == 0)
@@ -1851,6 +1854,7 @@ sf_intr(void *arg)
struct sf_softc *sc;
struct ifnet *ifp;
uint32_t status;
+ int cnt;
sc = (struct sf_softc *)arg;
SF_LOCK(sc);
@@ -1869,13 +1873,13 @@ sf_intr(void *arg)
if ((ifp->if_capenable & IFCAP_POLLING) != 0)
goto done_locked;
#endif
- if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0)
- goto done_locked;
/* Disable interrupts. */
csr_write_4(sc, SF_IMR, 0x00000000);
- for (; (status & SF_INTRS) != 0;) {
+ for (cnt = 32; (status & SF_INTRS) != 0;) {
+ if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0)
+ break;
if ((status & SF_ISR_RXDQ1_DMADONE) != 0)
sf_rxeof(sc);
@@ -1910,15 +1914,19 @@ sf_intr(void *arg)
#endif
}
}
+ if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd))
+ sf_start_locked(ifp);
+ if (--cnt <= 0)
+ break;
/* Reading the ISR register clears all interrrupts. */
status = csr_read_4(sc, SF_ISR);
}
- /* Re-enable interrupts. */
- csr_write_4(sc, SF_IMR, SF_INTRS);
+ if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0) {
+ /* Re-enable interrupts. */
+ csr_write_4(sc, SF_IMR, SF_INTRS);
+ }
- if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd))
- sf_start_locked(ifp);
done_locked:
SF_UNLOCK(sc);
}
@@ -2010,6 +2018,7 @@ sf_init_locked(struct sf_softc *sc)
if (sf_init_rx_ring(sc) == ENOBUFS) {
device_printf(sc->sf_dev,
"initialization failed: no memory for rx buffers\n");
+ sf_stop(sc);
return;
}
@@ -2135,12 +2144,12 @@ sf_init_locked(struct sf_softc *sc)
else
SF_CLRBIT(sc, SF_GEN_ETH_CTL, SF_ETHCTL_RXGFP_ENB);
- sc->sf_link = 0;
- mii_mediachg(mii);
-
ifp->if_drv_flags |= IFF_DRV_RUNNING;
ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
+ sc->sf_link = 0;
+ sf_ifmedia_upd_locked(ifp);
+
callout_reset(&sc->sf_co, hz, sf_tick, sc);
}
@@ -2329,6 +2338,9 @@ sf_stop(struct sf_softc *sc)
/* Disable Tx/Rx egine. */
csr_write_4(sc, SF_GEN_ETH_CTL, 0);
+ /* Give hardware chance to drain active DMA cycles. */
+ DELAY(1000);
+
csr_write_4(sc, SF_CQ_CONSIDX, 0);
csr_write_4(sc, SF_CQ_PRODIDX, 0);
csr_write_4(sc, SF_RXDQ_ADDR_Q1, 0);
diff --git a/sys/dev/sf/if_sfreg.h b/sys/dev/sf/if_sfreg.h
index 3ccfb8035a12..1c0fbca4ce0f 100644
--- a/sys/dev/sf/if_sfreg.h
+++ b/sys/dev/sf/if_sfreg.h
@@ -1083,7 +1083,6 @@ struct sf_softc {
int sf_if_flags;
struct callout sf_co;
int sf_watchdog_timer;
- struct task sf_link_task;
int sf_link;
int sf_suspended;
int sf_detach;