summaryrefslogtreecommitdiffstats
path: root/sys/dev
diff options
context:
space:
mode:
authorjhb <jhb@FreeBSD.org>2009-11-19 18:43:43 +0000
committerjhb <jhb@FreeBSD.org>2009-11-19 18:43:43 +0000
commit92fc9b53e8ad2c7ba20dc51ea8c0099d4196560f (patch)
tree60e6bc89dfee86d5e32ad9d50627128857e456aa /sys/dev
parent00a2480413843cb1a2e42dbbcfdf0353a3e8c144 (diff)
downloadFreeBSD-src-92fc9b53e8ad2c7ba20dc51ea8c0099d4196560f.zip
FreeBSD-src-92fc9b53e8ad2c7ba20dc51ea8c0099d4196560f.tar.gz
- This driver used the if_watchdog timer both as a watchdog on transmit and
auto-negotiation. To make this simpler and easier to understand I have split this out into two separate timers. One just manages the auto-neg side of things and one is a transmit watchdog. Neither uses if_watchdog. - Call ether_ifdetach() at the start of detach.
Diffstat (limited to 'sys/dev')
-rw-r--r--sys/dev/my/if_my.c60
-rw-r--r--sys/dev/my/if_myreg.h6
2 files changed, 43 insertions, 23 deletions
diff --git a/sys/dev/my/if_my.c b/sys/dev/my/if_my.c
index 8bfeb34..99f6071 100644
--- a/sys/dev/my/if_my.c
+++ b/sys/dev/my/if_my.c
@@ -126,7 +126,8 @@ static int my_ioctl(struct ifnet *, u_long, caddr_t);
static void my_init(void *);
static void my_init_locked(struct my_softc *);
static void my_stop(struct my_softc *);
-static void my_watchdog(struct ifnet *);
+static void my_autoneg_timeout(void *);
+static void my_watchdog(void *);
static int my_shutdown(device_t);
static int my_ifmedia_upd(struct ifnet *);
static void my_ifmedia_sts(struct ifnet *, struct ifmediareq *);
@@ -382,6 +383,15 @@ my_autoneg_xmit(struct my_softc * sc)
return;
}
+static void
+my_autoneg_timeout(void *arg)
+{
+ struct my_softc *sc;
+
+ sc = arg;
+ MY_LOCK_ASSERT(sc);
+ my_autoneg_mii(sc, MY_FLAG_DELAYTIMEO, 1);
+}
/*
* Invoke autonegotiation on a PHY.
@@ -439,12 +449,13 @@ my_autoneg_mii(struct my_softc * sc, int flag, int verbose)
return;
}
my_autoneg_xmit(sc);
- ifp->if_timer = 5;
+ callout_reset(&sc->my_autoneg_timer, hz * 5, my_autoneg_timeout,
+ sc);
sc->my_autoneg = 1;
sc->my_want_auto = 0;
return;
case MY_FLAG_DELAYTIMEO:
- ifp->if_timer = 0;
+ callout_stop(&sc->my_autoneg_timer);
sc->my_autoneg = 0;
break;
default:
@@ -661,7 +672,8 @@ my_setmode_mii(struct my_softc * sc, int media)
*/
if (sc->my_autoneg) {
device_printf(sc->my_dev, "canceling autoneg session\n");
- ifp->if_timer = sc->my_autoneg = sc->my_want_auto = 0;
+ callout_stop(&sc->my_autoneg_timer);
+ sc->my_autoneg = sc->my_want_auto = 0;
bmcr = my_phy_readreg(sc, PHY_BMCR);
bmcr &= ~PHY_BMCR_AUTONEGENBL;
my_phy_writereg(sc, PHY_BMCR, bmcr);
@@ -808,6 +820,8 @@ my_attach(device_t dev)
sc->my_dev = dev;
mtx_init(&sc->my_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK,
MTX_DEF);
+ callout_init_mtx(&sc->my_autoneg_timer, &sc->my_mtx, 0);
+ callout_init_mtx(&sc->my_watchdog, &sc->my_mtx, 0);
/*
* Map control/status registers.
@@ -886,7 +900,6 @@ my_attach(device_t dev)
ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
ifp->if_ioctl = my_ioctl;
ifp->if_start = my_start;
- ifp->if_watchdog = my_watchdog;
ifp->if_init = my_init;
ifp->if_baudrate = 10000000;
IFQ_SET_MAXLEN(&ifp->if_snd, IFQ_MAXLEN);
@@ -984,13 +997,15 @@ my_detach(device_t dev)
struct ifnet *ifp;
sc = device_get_softc(dev);
+ ifp = sc->my_ifp;
+ ether_ifdetach(ifp);
MY_LOCK(sc);
my_stop(sc);
MY_UNLOCK(sc);
bus_teardown_intr(dev, sc->my_irq, sc->my_intrhand);
+ callout_drain(&sc->my_watchdog);
+ callout_drain(&sc->my_autoneg_timer);
- ifp = sc->my_ifp;
- ether_ifdetach(ifp);
if_free(ifp);
free(sc->my_ldata_ptr, M_DEVBUF);
@@ -1188,7 +1203,7 @@ my_txeof(struct my_softc * sc)
MY_LOCK_ASSERT(sc);
ifp = sc->my_ifp;
/* Clear the timeout timer. */
- ifp->if_timer = 0;
+ sc->my_timer = 0;
if (sc->my_cdata.my_tx_head == NULL) {
return;
}
@@ -1240,7 +1255,7 @@ my_txeoc(struct my_softc * sc)
MY_LOCK_ASSERT(sc);
ifp = sc->my_ifp;
- ifp->if_timer = 0;
+ sc->my_timer = 0;
if (sc->my_cdata.my_tx_head == NULL) {
ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
sc->my_cdata.my_tx_tail = NULL;
@@ -1249,7 +1264,7 @@ my_txeoc(struct my_softc * sc)
} else {
if (MY_TXOWN(sc->my_cdata.my_tx_head) == MY_UNSENT) {
MY_TXOWN(sc->my_cdata.my_tx_head) = MY_OWNByNIC;
- ifp->if_timer = 5;
+ sc->my_timer = 5;
CSR_WRITE_4(sc, MY_TXPDR, 0xFFFFFFFF);
}
}
@@ -1455,7 +1470,7 @@ my_start_locked(struct ifnet * ifp)
/*
* Set a timeout in case the chip goes out to lunch.
*/
- ifp->if_timer = 5;
+ sc->my_timer = 5;
return;
}
@@ -1555,6 +1570,8 @@ my_init_locked(struct my_softc *sc)
my_phy_writereg(sc, PHY_BMCR, phy_bmcr);
ifp->if_drv_flags |= IFF_DRV_RUNNING;
ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
+
+ callout_reset(&sc->my_watchdog, hz, my_watchdog, sc);
return;
}
@@ -1680,17 +1697,18 @@ my_ioctl(struct ifnet * ifp, u_long command, caddr_t data)
}
static void
-my_watchdog(struct ifnet * ifp)
+my_watchdog(void *arg)
{
struct my_softc *sc;
+ struct ifnet *ifp;
- sc = ifp->if_softc;
- MY_LOCK(sc);
- if (sc->my_autoneg) {
- my_autoneg_mii(sc, MY_FLAG_DELAYTIMEO, 1);
- MY_UNLOCK(sc);
+ sc = arg;
+ MY_LOCK_ASSERT(sc);
+ callout_reset(&sc->my_watchdog, hz, my_watchdog, sc);
+ if (sc->my_timer == 0 || --sc->my_timer > 0)
return;
- }
+
+ ifp = sc->my_ifp;
ifp->if_oerrors++;
if_printf(ifp, "watchdog timeout\n");
if (!(my_phy_readreg(sc, PHY_BMSR) & PHY_BMSR_LINKSTAT))
@@ -1700,8 +1718,6 @@ my_watchdog(struct ifnet * ifp)
my_init_locked(sc);
if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd))
my_start_locked(ifp);
- MY_UNLOCK(sc);
- return;
}
@@ -1716,7 +1732,9 @@ my_stop(struct my_softc * sc)
MY_LOCK_ASSERT(sc);
ifp = sc->my_ifp;
- ifp->if_timer = 0;
+
+ callout_stop(&sc->my_autoneg_timer);
+ callout_stop(&sc->my_watchdog);
MY_CLRBIT(sc, MY_TCRRCR, (MY_RE | MY_TE));
CSR_WRITE_4(sc, MY_IMR, 0x00000000);
diff --git a/sys/dev/my/if_myreg.h b/sys/dev/my/if_myreg.h
index 71eb3f3..f787031 100644
--- a/sys/dev/my/if_myreg.h
+++ b/sys/dev/my/if_myreg.h
@@ -371,8 +371,10 @@ struct my_softc {
struct my_chain_data my_cdata;
device_t my_miibus;
/* Add by Surfer 2001/12/2 */
- struct mtx my_mtx;
-
+ struct mtx my_mtx;
+ struct callout my_autoneg_timer;
+ struct callout my_watchdog;
+ int my_timer;
};
/* Add by Surfer 2001/12/2 */
OpenPOWER on IntegriCloud