summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohn-Mark Gurney <jmg@FreeBSD.org>2004-09-03 16:41:41 +0000
committerJohn-Mark Gurney <jmg@FreeBSD.org>2004-09-03 16:41:41 +0000
commit97b9d4baf5eaa4b7020f4d140a5932ed6158892c (patch)
tree9e197e7f8f70ec2512a017fd946325e39ea7a25b
parent1e454c2527bd559d90e5ce3508ada54a010c48d4 (diff)
Notes
-rw-r--r--sys/dev/re/if_re.c219
1 files changed, 135 insertions, 84 deletions
diff --git a/sys/dev/re/if_re.c b/sys/dev/re/if_re.c
index bff901f98829..edc4c35cdbaf 100644
--- a/sys/dev/re/if_re.c
+++ b/sys/dev/re/if_re.c
@@ -205,11 +205,18 @@ static int re_rx_list_init (struct rl_softc *);
static int re_tx_list_init (struct rl_softc *);
static void re_rxeof (struct rl_softc *);
static void re_txeof (struct rl_softc *);
+#ifdef DEVICE_POLLING
+static void re_poll (struct ifnet *, enum poll_cmd, int)
+static void re_poll_locked (struct ifnet *, enum poll_cmd, int)
+#endif
static void re_intr (void *);
static void re_tick (void *);
+static void re_tick_locked (struct rl_softc *);
static void re_start (struct ifnet *);
+static void re_start_locked (struct ifnet *);
static int re_ioctl (struct ifnet *, u_long, caddr_t);
static void re_init (void *);
+static void re_init_locked (struct rl_softc *);
static void re_stop (struct rl_softc *);
static void re_watchdog (struct ifnet *);
static int re_suspend (device_t);
@@ -454,17 +461,14 @@ re_miibus_readreg(dev, phy, reg)
u_int16_t re8139_reg = 0;
sc = device_get_softc(dev);
- RL_LOCK(sc);
if (sc->rl_type == RL_8169) {
rval = re_gmii_readreg(dev, phy, reg);
- RL_UNLOCK(sc);
return (rval);
}
/* Pretend the internal PHY is only at address 0 */
if (phy) {
- RL_UNLOCK(sc);
return (0);
}
switch (reg) {
@@ -485,7 +489,6 @@ re_miibus_readreg(dev, phy, reg)
break;
case MII_PHYIDR1:
case MII_PHYIDR2:
- RL_UNLOCK(sc);
return (0);
/*
* Allow the rlphy driver to read the media status
@@ -495,15 +498,12 @@ re_miibus_readreg(dev, phy, reg)
*/
case RL_MEDIASTAT:
rval = CSR_READ_1(sc, RL_MEDIASTAT);
- RL_UNLOCK(sc);
return (rval);
default:
printf("re%d: bad phy register\n", sc->rl_unit);
- RL_UNLOCK(sc);
return (0);
}
rval = CSR_READ_2(sc, re8139_reg);
- RL_UNLOCK(sc);
return (rval);
}
@@ -517,19 +517,16 @@ re_miibus_writereg(dev, phy, reg, data)
int rval = 0;
sc = device_get_softc(dev);
- RL_LOCK(sc);
if (sc->rl_type == RL_8169) {
rval = re_gmii_writereg(dev, phy, reg, data);
- RL_UNLOCK(sc);
return (rval);
}
/* Pretend the internal PHY is only at address 0 */
- if (phy) {
- RL_UNLOCK(sc);
+ if (phy)
return (0);
- }
+
switch (reg) {
case MII_BMCR:
re8139_reg = RL_BMCR;
@@ -548,16 +545,13 @@ re_miibus_writereg(dev, phy, reg, data)
break;
case MII_PHYIDR1:
case MII_PHYIDR2:
- RL_UNLOCK(sc);
return (0);
break;
default:
printf("re%d: bad phy register\n", sc->rl_unit);
- RL_UNLOCK(sc);
return (0);
}
CSR_WRITE_2(sc, re8139_reg, data);
- RL_UNLOCK(sc);
return (0);
}
@@ -582,6 +576,8 @@ re_setmulti(sc)
u_int32_t rxfilt;
int mcnt = 0;
+ RL_LOCK_ASSERT(sc);
+
ifp = &sc->arpcom.ac_if;
rxfilt = CSR_READ_4(sc, RL_RXCFG);
@@ -627,6 +623,8 @@ re_reset(sc)
{
register int i;
+ RL_LOCK_ASSERT(sc);
+
CSR_WRITE_1(sc, RL_COMMAND, RL_CMD_RESET);
for (i = 0; i < RL_TIMEOUT; i++) {
@@ -675,11 +673,12 @@ re_diag(sc)
u_int8_t src[] = { 0x00, 'w', 'o', 'r', 'l', 'd' };
/* Allocate a single mbuf */
-
MGETHDR(m0, M_DONTWAIT, MT_DATA);
if (m0 == NULL)
return (ENOBUFS);
+ RL_LOCK(sc);
+
/*
* Initialize the NIC in test mode. This sets the chip up
* so that it can send and receive frames, but performs the
@@ -691,10 +690,10 @@ re_diag(sc)
ifp->if_flags |= IFF_PROMISC;
sc->rl_testmode = 1;
- re_init(sc);
+ re_init_locked(sc);
re_stop(sc);
DELAY(100000);
- re_init(sc);
+ re_init_locked(sc);
/* Put some data in the mbuf */
@@ -710,7 +709,9 @@ re_diag(sc)
*/
CSR_WRITE_2(sc, RL_ISR, 0xFFFF);
+ RL_UNLOCK(sc);
IF_HANDOFF(&ifp->if_snd, m0, ifp);
+ RL_LOCK(sc);
m0 = NULL;
/* Wait for it to propagate through the chip */
@@ -789,6 +790,8 @@ done:
if (m0 != NULL)
m_freem(m0);
+ RL_UNLOCK(sc);
+
return (error);
}
@@ -826,15 +829,9 @@ re_probe(dev)
}
sc->rl_btag = rman_get_bustag(sc->rl_res);
sc->rl_bhandle = rman_get_bushandle(sc->rl_res);
- mtx_init(&sc->rl_mtx,
- device_get_nameunit(dev),
- MTX_NETWORK_LOCK, MTX_DEF);
- RL_LOCK(sc);
hwrev = CSR_READ_4(sc, RL_TXCFG) & RL_TXCFG_HWREV;
bus_release_resource(dev, RL_RES,
RL_RID, sc->rl_res);
- RL_UNLOCK(sc);
- mtx_destroy(&sc->rl_mtx);
if (t->rl_basetype == hwrev) {
device_set_desc(dev, t->rl_name);
return (0);
@@ -1065,7 +1062,7 @@ re_attach(dev)
unit = device_get_unit(dev);
mtx_init(&sc->rl_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK,
- MTX_DEF | MTX_RECURSE);
+ MTX_DEF);
/*
* Map control/status registers.
*/
@@ -1096,7 +1093,9 @@ re_attach(dev)
}
/* Reset the adapter. */
+ RL_LOCK(sc);
re_reset(sc);
+ RL_UNLOCK(sc);
hw_rev = re_hwrevs;
hwrev = CSR_READ_4(sc, RL_TXCFG) & RL_TXCFG_HWREV;
@@ -1221,13 +1220,11 @@ re_attach(dev)
}
/* Hook interrupt last to avoid having to lock softc */
- error = bus_setup_intr(dev, sc->rl_irq, INTR_TYPE_NET,
+ error = bus_setup_intr(dev, sc->rl_irq, INTR_TYPE_NET | INTR_MPSAFE,
re_intr, sc, &sc->rl_intrhand);
-
if (error) {
printf("re%d: couldn't set up irq\n", unit);
ether_ifdetach(ifp);
- goto fail;
}
fail:
@@ -1251,19 +1248,29 @@ re_detach(dev)
struct rl_softc *sc;
struct ifnet *ifp;
int i;
+ int attached;
sc = device_get_softc(dev);
+ ifp = &sc->arpcom.ac_if;
KASSERT(mtx_initialized(&sc->rl_mtx), ("rl mutex not initialized"));
+
+ attached = device_is_attached(dev);
+ /* These should only be active if attach succeeded */
+ if (attached)
+ ether_ifdetach(ifp);
+
RL_LOCK(sc);
- ifp = &sc->arpcom.ac_if;
+#if 0
+ sc->suspended = 1;
+#endif
/* These should only be active if attach succeeded */
- if (device_is_attached(dev)) {
+ if (attached) {
re_stop(sc);
/*
* Force off the IFF_UP flag here, in case someone
* still had a BPF descriptor attached to this
- * interface. If they do, ether_ifattach() will cause
+ * interface. If they do, ether_ifdetach() will cause
* the BPF code to try and clear the promisc mode
* flag, which will bubble down to re_ioctl(),
* which will try to call re_init() again. This will
@@ -1279,6 +1286,12 @@ re_detach(dev)
device_delete_child(dev, sc->rl_miibus);
bus_generic_detach(dev);
+ /*
+ * The rest is resource deallocation, so we should already be
+ * stopped here.
+ */
+ RL_UNLOCK(sc);
+
if (sc->rl_intrhand)
bus_teardown_intr(dev, sc->rl_irq, sc->rl_intrhand);
if (sc->rl_irq)
@@ -1335,7 +1348,6 @@ re_detach(dev)
if (sc->rl_parent_tag)
bus_dma_tag_destroy(sc->rl_parent_tag);
- RL_UNLOCK(sc);
mtx_destroy(&sc->rl_mtx);
return (0);
@@ -1396,6 +1408,9 @@ static int
re_tx_list_init(sc)
struct rl_softc *sc;
{
+
+ RL_LOCK_ASSERT(sc);
+
bzero ((char *)sc->rl_ldata.rl_tx_list, RL_TX_LIST_SZ);
bzero ((char *)&sc->rl_ldata.rl_tx_mbuf,
(RL_TX_DESC_CNT * sizeof(struct mbuf *)));
@@ -1679,32 +1694,53 @@ re_tick(xsc)
void *xsc;
{
struct rl_softc *sc;
- struct mii_data *mii;
sc = xsc;
RL_LOCK(sc);
+ re_tick_locked(sc);
+ RL_UNLOCK(sc);
+}
+
+static void
+re_tick_locked(sc)
+ struct rl_softc *sc;
+{
+ struct mii_data *mii;
+
+ RL_LOCK_ASSERT(sc);
+
mii = device_get_softc(sc->rl_miibus);
mii_tick(mii);
sc->rl_stat_ch = timeout(re_tick, sc, hz);
- RL_UNLOCK(sc);
}
#ifdef DEVICE_POLLING
static void
-re_poll (struct ifnet *ifp, enum poll_cmd cmd, int count)
+re_poll(struct ifnet *ifp, enum poll_cmd cmd, int count)
{
struct rl_softc *sc = ifp->if_softc;
RL_LOCK(sc);
+ re_poll_locked(ifp, cmd, count);
+ RL_UNLOCK(sc);
+}
+
+static void
+re_poll_locked(struct ifnet *ifp, enum poll_cmd cmd, int count)
+{
+ struct rl_softc *sc = ifp->if_softc;
+
+ RL_LOCK_ASSERT(sc);
+
if (!(ifp->if_capenable & IFCAP_POLLING)) {
ether_poll_deregister(ifp);
cmd = POLL_DEREGISTER;
}
if (cmd == POLL_DEREGISTER) { /* final call, enable interrupts */
CSR_WRITE_2(sc, RL_IMR, RL_INTRS_CPLUS);
- goto done;
+ return;
}
sc->rxcycles = count;
@@ -1712,14 +1748,14 @@ re_poll (struct ifnet *ifp, enum poll_cmd cmd, int count)
re_txeof(sc);
if (ifp->if_snd.ifq_head != NULL)
- (*ifp->if_start)(ifp);
+ re_start_locked(ifp);
if (cmd == POLL_AND_CHECK_STATUS) { /* also check status register */
u_int16_t status;
status = CSR_READ_2(sc, RL_ISR);
if (status == 0xffff)
- goto done;
+ return;
if (status)
CSR_WRITE_2(sc, RL_ISR, status);
@@ -1729,11 +1765,9 @@ re_poll (struct ifnet *ifp, enum poll_cmd cmd, int count)
if (status & RL_ISR_SYSTEM_ERR) {
re_reset(sc);
- re_init(sc);
+ re_init_locked(sc);
}
}
-done:
- RL_UNLOCK(sc);
}
#endif /* DEVICE_POLLING */
@@ -1747,26 +1781,21 @@ re_intr(arg)
sc = arg;
- if (sc->suspended) {
- return;
- }
-
RL_LOCK(sc);
+
ifp = &sc->arpcom.ac_if;
- if (!(ifp->if_flags & IFF_UP)) {
- RL_UNLOCK(sc);
- return;
- }
+ if (sc->suspended || !(ifp->if_flags & IFF_UP))
+ goto done_locked;
#ifdef DEVICE_POLLING
if (ifp->if_flags & IFF_POLLING)
- goto done;
+ goto done_locked;
if ((ifp->if_capenable & IFCAP_POLLING) &&
ether_poll_register(re_poll, ifp)) { /* ok, disable interrupts */
CSR_WRITE_2(sc, RL_IMR, 0x0000);
- re_poll(ifp, 0, 1);
- goto done;
+ re_poll_locked(ifp, 0, 1);
+ goto done_locked;
}
#endif /* DEVICE_POLLING */
@@ -1795,21 +1824,19 @@ re_intr(arg)
if (status & RL_ISR_SYSTEM_ERR) {
re_reset(sc);
- re_init(sc);
+ re_init_locked(sc);
}
if (status & RL_ISR_LINKCHG) {
untimeout(re_tick, sc, sc->rl_stat_ch);
- re_tick(sc);
+ re_tick_locked(sc);
}
}
if (ifp->if_snd.ifq_head != NULL)
- (*ifp->if_start)(ifp);
+ re_start_locked(ifp);
-#ifdef DEVICE_POLLING
-done:
-#endif
+done_locked:
RL_UNLOCK(sc);
}
@@ -1825,6 +1852,8 @@ re_encap(sc, m_head, idx)
int error;
struct m_tag *mtag;
+ RL_LOCK_ASSERT(sc);
+
if (sc->rl_ldata.rl_tx_free <= 4)
return (EFBIG);
@@ -1920,12 +1949,23 @@ re_encap(sc, m_head, idx)
return (0);
}
+static void
+re_start(ifp)
+ struct ifnet *ifp;
+{
+ struct rl_softc *sc;
+
+ sc = ifp->if_softc;
+ RL_LOCK(sc);
+ re_start_locked(ifp);
+ RL_UNLOCK(sc);
+}
+
/*
* Main transmit routine for C+ and gigE NICs.
*/
-
static void
-re_start(ifp)
+re_start_locked(ifp)
struct ifnet *ifp;
{
struct rl_softc *sc;
@@ -1933,7 +1973,8 @@ re_start(ifp)
int idx;
sc = ifp->if_softc;
- RL_LOCK(sc);
+
+ RL_LOCK_ASSERT(sc);
idx = sc->rl_ldata.rl_tx_prodidx;
@@ -1983,8 +2024,6 @@ re_start(ifp)
*/
CSR_WRITE_4(sc, RL_TIMERCNT, 1);
- RL_UNLOCK(sc);
-
/*
* Set a timeout in case the chip goes out to lunch.
*/
@@ -1996,11 +2035,22 @@ re_init(xsc)
void *xsc;
{
struct rl_softc *sc = xsc;
+
+ RL_LOCK(sc);
+ re_init_locked(sc);
+ RL_UNLOCK(sc);
+}
+
+static void
+re_init_locked(sc)
+ struct rl_softc *sc;
+{
struct ifnet *ifp = &sc->arpcom.ac_if;
struct mii_data *mii;
u_int32_t rxcfg = 0;
- RL_LOCK(sc);
+ RL_LOCK_ASSERT(sc);
+
mii = device_get_softc(sc->rl_miibus);
/*
@@ -2146,10 +2196,8 @@ re_init(xsc)
if (sc->rl_type == RL_8169)
CSR_WRITE_2(sc, RL_MAXRXPKTLEN, 16383);
- if (sc->rl_testmode) {
- RL_UNLOCK(sc);
+ if (sc->rl_testmode)
return;
- }
mii_mediachg(mii);
@@ -2159,7 +2207,6 @@ re_init(xsc)
ifp->if_flags &= ~IFF_OACTIVE;
sc->rl_stat_ch = timeout(re_tick, sc, hz);
- RL_UNLOCK(sc);
}
/*
@@ -2209,8 +2256,6 @@ re_ioctl(ifp, command, data)
struct mii_data *mii;
int error = 0;
- RL_LOCK(sc);
-
switch (command) {
case SIOCSIFMTU:
if (ifr->ifr_mtu > RL_JUMBO_MTU)
@@ -2218,17 +2263,19 @@ re_ioctl(ifp, command, data)
ifp->if_mtu = ifr->ifr_mtu;
break;
case SIOCSIFFLAGS:
- if (ifp->if_flags & IFF_UP) {
- re_init(sc);
- } else {
- if (ifp->if_flags & IFF_RUNNING)
- re_stop(sc);
- }
+ RL_LOCK(sc);
+ if (ifp->if_flags & IFF_UP)
+ re_init_locked(sc);
+ else if (ifp->if_flags & IFF_RUNNING)
+ re_stop(sc);
+ RL_UNLOCK(sc);
error = 0;
break;
case SIOCADDMULTI:
case SIOCDELMULTI:
+ RL_LOCK(sc);
re_setmulti(sc);
+ RL_UNLOCK(sc);
error = 0;
break;
case SIOCGIFMEDIA:
@@ -2252,8 +2299,6 @@ re_ioctl(ifp, command, data)
break;
}
- RL_UNLOCK(sc);
-
return (error);
}
@@ -2270,8 +2315,7 @@ re_watchdog(ifp)
re_txeof(sc);
re_rxeof(sc);
-
- re_init(sc);
+ re_init_locked(sc);
RL_UNLOCK(sc);
}
@@ -2287,7 +2331,8 @@ re_stop(sc)
register int i;
struct ifnet *ifp;
- RL_LOCK(sc);
+ RL_LOCK_ASSERT(sc);
+
ifp = &sc->arpcom.ac_if;
ifp->if_timer = 0;
@@ -2326,8 +2371,6 @@ re_stop(sc)
sc->rl_ldata.rl_rx_mbuf[i] = NULL;
}
}
-
- RL_UNLOCK(sc);
}
/*
@@ -2343,8 +2386,10 @@ re_suspend(dev)
sc = device_get_softc(dev);
+ RL_LOCK(sc);
re_stop(sc);
sc->suspended = 1;
+ RL_UNLOCK(sc);
return (0);
}
@@ -2362,13 +2407,17 @@ re_resume(dev)
struct ifnet *ifp;
sc = device_get_softc(dev);
+
+ RL_LOCK(sc);
+
ifp = &sc->arpcom.ac_if;
/* reinitialize interface if necessary */
if (ifp->if_flags & IFF_UP)
- re_init(sc);
+ re_init_locked(sc);
sc->suspended = 0;
+ RL_UNLOCK(sc);
return (0);
}
@@ -2385,5 +2434,7 @@ re_shutdown(dev)
sc = device_get_softc(dev);
+ RL_LOCK(sc);
re_stop(sc);
+ RL_UNLOCK(sc);
}