summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorjhb <jhb@FreeBSD.org>2005-08-30 20:35:08 +0000
committerjhb <jhb@FreeBSD.org>2005-08-30 20:35:08 +0000
commit010cdcf6428d9edaf7865b1d1ea858f10646d733 (patch)
tree984c58bf64dcaa34b761549d0af3243b06879b38
parent51994fffc4be5615daf8f50fd8d04ebfcde141fb (diff)
downloadFreeBSD-src-010cdcf6428d9edaf7865b1d1ea858f10646d733.zip
FreeBSD-src-010cdcf6428d9edaf7865b1d1ea858f10646d733.tar.gz
Various locking fixes and mark MPSAFE:
- Add locked variants of start(), init(), ifmedia_upd(), and poll() and stop recursing on the driver lock. - Add locking to ifmedia_upd() and ifmedia_sts(). - Use callout_*() instead of timeout/untimeout. - Fix locking in ioctl(). Tested by: Bob Bishop rb at gid dot co dot uk MFC after: 3 days
-rw-r--r--sys/pci/if_ste.c153
-rw-r--r--sys/pci/if_stereg.h2
2 files changed, 95 insertions, 60 deletions
diff --git a/sys/pci/if_ste.c b/sys/pci/if_ste.c
index 0d715e1..4167951 100644
--- a/sys/pci/if_ste.c
+++ b/sys/pci/if_ste.c
@@ -90,6 +90,7 @@ static int ste_probe(device_t);
static int ste_attach(device_t);
static int ste_detach(device_t);
static void ste_init(void *);
+static void ste_init_locked(struct ste_softc *);
static void ste_intr(void *);
static void ste_rxeoc(struct ste_softc *);
static void ste_rxeof(struct ste_softc *);
@@ -101,11 +102,13 @@ static void ste_reset(struct ste_softc *);
static int ste_ioctl(struct ifnet *, u_long, caddr_t);
static int ste_encap(struct ste_softc *, struct ste_chain *, struct mbuf *);
static void ste_start(struct ifnet *);
+static void ste_start_locked(struct ifnet *);
static void ste_watchdog(struct ifnet *);
static void ste_shutdown(device_t);
static int ste_newbuf(struct ste_softc *, struct ste_chain_onefrag *,
struct mbuf *);
static int ste_ifmedia_upd(struct ifnet *);
+static void ste_ifmedia_upd_locked(struct ifnet *);
static void ste_ifmedia_sts(struct ifnet *, struct ifmediareq *);
static void ste_mii_sync(struct ste_softc *);
@@ -246,8 +249,6 @@ ste_mii_readreg(sc, frame)
{
int i, ack;
- STE_LOCK(sc);
-
/*
* Set up frame for RX.
*/
@@ -321,8 +322,6 @@ fail:
MII_SET(STE_PHYCTL_MCLK);
DELAY(1);
- STE_UNLOCK(sc);
-
if (ack)
return(1);
return(0);
@@ -337,7 +336,6 @@ ste_mii_writereg(sc, frame)
struct ste_mii_frame *frame;
{
- STE_LOCK(sc);
/*
* Set up frame for TX.
@@ -372,8 +370,6 @@ ste_mii_writereg(sc, frame)
*/
MII_CLR(STE_PHYCTL_MDIR);
- STE_UNLOCK(sc);
-
return(0);
}
@@ -427,7 +423,7 @@ ste_miibus_statchg(dev)
struct mii_data *mii;
sc = device_get_softc(dev);
- STE_LOCK(sc);
+
mii = device_get_softc(sc->ste_miibus);
if ((mii->mii_media_active & IFM_GMASK) == IFM_FDX) {
@@ -435,7 +431,6 @@ ste_miibus_statchg(dev)
} else {
STE_CLRBIT2(sc, STE_MACCTL0, STE_MACCTL0_FULLDUPLEX);
}
- STE_UNLOCK(sc);
return;
}
@@ -445,9 +440,24 @@ ste_ifmedia_upd(ifp)
struct ifnet *ifp;
{
struct ste_softc *sc;
+
+ sc = ifp->if_softc;
+ STE_LOCK(sc);
+ ste_ifmedia_upd_locked(ifp);
+ STE_UNLOCK(sc);
+
+ return(0);
+}
+
+static void
+ste_ifmedia_upd_locked(ifp)
+ struct ifnet *ifp;
+{
+ struct ste_softc *sc;
struct mii_data *mii;
sc = ifp->if_softc;
+ STE_LOCK_ASSERT(sc);
mii = device_get_softc(sc->ste_miibus);
sc->ste_link = 0;
if (mii->mii_instance) {
@@ -456,8 +466,6 @@ ste_ifmedia_upd(ifp)
mii_phy_reset(miisc);
}
mii_mediachg(mii);
-
- return(0);
}
static void
@@ -471,9 +479,11 @@ ste_ifmedia_sts(ifp, ifmr)
sc = ifp->if_softc;
mii = device_get_softc(sc->ste_miibus);
+ STE_LOCK(sc);
mii_pollstat(mii);
ifmr->ifm_active = mii->mii_media_active;
ifmr->ifm_status = mii->mii_media_status;
+ STE_UNLOCK(sc);
return;
}
@@ -603,7 +613,7 @@ ste_setmulti(sc)
}
#ifdef DEVICE_POLLING
-static poll_handler_t ste_poll;
+static poll_handler_t ste_poll, ste_poll_locked;
static void
ste_poll(struct ifnet *ifp, enum poll_cmd cmd, int count)
@@ -611,13 +621,23 @@ ste_poll(struct ifnet *ifp, enum poll_cmd cmd, int count)
struct ste_softc *sc = ifp->if_softc;
STE_LOCK(sc);
+ ste_poll_locked(ifp, cmd, count);
+ STE_UNLOCK(sc);
+}
+
+static void
+ste_poll_locked(struct ifnet *ifp, enum poll_cmd cmd, int count)
+{
+ struct ste_softc *sc = ifp->if_softc;
+
+ STE_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, STE_IMR, STE_INTRS);
- goto done;
+ return;
}
sc->rxcycles = count;
@@ -626,7 +646,7 @@ ste_poll(struct ifnet *ifp, enum poll_cmd cmd, int count)
ste_rxeof(sc);
ste_txeof(sc);
if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd))
- ste_start(ifp);
+ ste_start_locked(ifp);
if (cmd == POLL_AND_CHECK_STATUS) {
u_int16_t status;
@@ -637,7 +657,7 @@ ste_poll(struct ifnet *ifp, enum poll_cmd cmd, int count)
ste_txeoc(sc);
if (status & STE_ISR_STATS_OFLOW) {
- untimeout(ste_stats_update, sc, sc->ste_stat_ch);
+ callout_stop(&sc->ste_stat_callout);
ste_stats_update(sc);
}
@@ -646,11 +666,9 @@ ste_poll(struct ifnet *ifp, enum poll_cmd cmd, int count)
if (status & STE_ISR_HOSTERR) {
ste_reset(sc);
- ste_init(sc);
+ ste_init_locked(sc);
}
}
-done:
- STE_UNLOCK(sc);
}
#endif /* DEVICE_POLLING */
@@ -672,7 +690,7 @@ ste_intr(xsc)
if ((ifp->if_capenable & IFCAP_POLLING) &&
ether_poll_register(ste_poll, ifp)) { /* ok, disable interrupts */
CSR_WRITE_2(sc, STE_IMR, 0);
- ste_poll(ifp, 0, 1);
+ ste_poll_locked(ifp, 0, 1);
goto done;
}
#endif /* DEVICE_POLLING */
@@ -701,7 +719,7 @@ ste_intr(xsc)
ste_txeoc(sc);
if (status & STE_ISR_STATS_OFLOW) {
- untimeout(ste_stats_update, sc, sc->ste_stat_ch);
+ callout_stop(&sc->ste_stat_callout);
ste_stats_update(sc);
}
@@ -711,7 +729,7 @@ ste_intr(xsc)
if (status & STE_ISR_HOSTERR) {
ste_reset(sc);
- ste_init(sc);
+ ste_init_locked(sc);
}
}
@@ -719,7 +737,7 @@ ste_intr(xsc)
CSR_WRITE_2(sc, STE_IMR, STE_INTRS);
if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd))
- ste_start(ifp);
+ ste_start_locked(ifp);
#ifdef DEVICE_POLLING
done:
@@ -861,7 +879,7 @@ ste_txeoc(sc)
if_printf(ifp, "transmission error: %x\n", txstat);
ste_reset(sc);
- ste_init(sc);
+ ste_init_locked(sc);
if (txstat & STE_TXSTATUS_UNDERRUN &&
sc->ste_tx_thresh < STE_PACKET_SIZE) {
@@ -874,7 +892,7 @@ ste_txeoc(sc)
CSR_WRITE_2(sc, STE_TX_RECLAIM_THRESH,
(STE_PACKET_SIZE >> 4));
}
- ste_init(sc);
+ ste_init_locked(sc);
CSR_WRITE_2(sc, STE_TX_STATUS, txstat);
}
@@ -920,7 +938,7 @@ ste_stats_update(xsc)
struct mii_data *mii;
sc = xsc;
- STE_LOCK(sc);
+ STE_LOCK_ASSERT(sc);
ifp = sc->ste_ifp;
mii = device_get_softc(sc->ste_miibus);
@@ -940,12 +958,11 @@ ste_stats_update(xsc)
*/
ste_miibus_statchg(sc->ste_dev);
if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd))
- ste_start(ifp);
+ ste_start_locked(ifp);
}
}
- sc->ste_stat_ch = timeout(ste_stats_update, sc, hz);
- STE_UNLOCK(sc);
+ callout_reset(&sc->ste_stat_callout, hz, ste_stats_update, sc);
return;
}
@@ -1002,7 +1019,7 @@ ste_attach(dev)
sc->ste_one_phy = 1;
mtx_init(&sc->ste_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK,
- MTX_DEF | MTX_RECURSE);
+ MTX_DEF);
/*
* Map control/status registers.
*/
@@ -1031,7 +1048,7 @@ ste_attach(dev)
goto fail;
}
- callout_handle_init(&sc->ste_stat_ch);
+ callout_init_mtx(&sc->ste_stat_callout, &sc->ste_mtx, 0);
/* Reset the adapter. */
ste_reset(sc);
@@ -1076,8 +1093,7 @@ ste_attach(dev)
ifp->if_softc = sc;
if_initname(ifp, device_get_name(dev), device_get_unit(dev));
ifp->if_mtu = ETHERMTU;
- ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST |
- IFF_NEEDSGIANT;
+ ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
ifp->if_ioctl = ste_ioctl;
ifp->if_start = ste_start;
ifp->if_watchdog = ste_watchdog;
@@ -1105,7 +1121,7 @@ ste_attach(dev)
ifp->if_capenable = ifp->if_capabilities;
/* Hook interrupt last to avoid having to lock softc */
- error = bus_setup_intr(dev, sc->ste_irq, INTR_TYPE_NET,
+ error = bus_setup_intr(dev, sc->ste_irq, INTR_TYPE_NET | INTR_MPSAFE,
ste_intr, sc, &sc->ste_intrhand);
if (error) {
@@ -1138,12 +1154,14 @@ ste_detach(dev)
sc = device_get_softc(dev);
KASSERT(mtx_initialized(&sc->ste_mtx), ("ste mutex not initialized"));
- STE_LOCK(sc);
ifp = sc->ste_ifp;
/* These should only be active if attach succeeded */
if (device_is_attached(dev)) {
+ STE_LOCK(sc);
ste_stop(sc);
+ STE_UNLOCK(sc);
+ callout_drain(&sc->ste_stat_callout);
ether_ifdetach(ifp);
if_free(ifp);
}
@@ -1163,7 +1181,6 @@ ste_detach(dev)
M_DEVBUF);
}
- STE_UNLOCK(sc);
mtx_destroy(&sc->ste_mtx);
return(0);
@@ -1271,11 +1288,21 @@ ste_init(xsc)
void *xsc;
{
struct ste_softc *sc;
- int i;
- struct ifnet *ifp;
sc = xsc;
STE_LOCK(sc);
+ ste_init_locked(sc);
+ STE_UNLOCK(sc);
+}
+
+static void
+ste_init_locked(sc)
+ struct ste_softc *sc;
+{
+ int i;
+ struct ifnet *ifp;
+
+ STE_LOCK_ASSERT(sc);
ifp = sc->ste_ifp;
ste_stop(sc);
@@ -1290,7 +1317,6 @@ ste_init(xsc)
if_printf(ifp,
"initialization failed: no memory for RX buffers\n");
ste_stop(sc);
- STE_UNLOCK(sc);
return;
}
@@ -1370,13 +1396,12 @@ ste_init(xsc)
/* Accept VLAN length packets */
CSR_WRITE_2(sc, STE_MAX_FRAMELEN, ETHER_MAX_LEN + ETHER_VLAN_ENCAP_LEN);
- ste_ifmedia_upd(ifp);
+ ste_ifmedia_upd_locked(ifp);
ifp->if_drv_flags |= IFF_DRV_RUNNING;
ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
- sc->ste_stat_ch = timeout(ste_stats_update, sc, hz);
- STE_UNLOCK(sc);
+ callout_reset(&sc->ste_stat_callout, hz, ste_stats_update, sc);
return;
}
@@ -1388,10 +1413,10 @@ ste_stop(sc)
int i;
struct ifnet *ifp;
- STE_LOCK(sc);
+ STE_LOCK_ASSERT(sc);
ifp = sc->ste_ifp;
- untimeout(ste_stats_update, sc, sc->ste_stat_ch);
+ callout_stop(&sc->ste_stat_callout);
ifp->if_drv_flags &= ~(IFF_DRV_RUNNING|IFF_DRV_OACTIVE);
#ifdef DEVICE_POLLING
ether_poll_deregister(ifp);
@@ -1427,7 +1452,6 @@ ste_stop(sc)
}
bzero(sc->ste_ldata, sizeof(struct ste_list_data));
- STE_UNLOCK(sc);
return;
}
@@ -1470,11 +1494,11 @@ ste_ioctl(ifp, command, data)
int error = 0;
sc = ifp->if_softc;
- STE_LOCK(sc);
ifr = (struct ifreq *)data;
switch(command) {
case SIOCSIFFLAGS:
+ STE_LOCK(sc);
if (ifp->if_flags & IFF_UP) {
if (ifp->if_drv_flags & IFF_DRV_RUNNING &&
ifp->if_flags & IFF_PROMISC &&
@@ -1492,18 +1516,21 @@ ste_ioctl(ifp, command, data)
ste_setmulti(sc);
if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) {
sc->ste_tx_thresh = STE_TXSTART_THRESH;
- ste_init(sc);
+ ste_init_locked(sc);
}
} else {
if (ifp->if_drv_flags & IFF_DRV_RUNNING)
ste_stop(sc);
}
sc->ste_if_flags = ifp->if_flags;
+ STE_UNLOCK(sc);
error = 0;
break;
case SIOCADDMULTI:
case SIOCDELMULTI:
+ STE_LOCK(sc);
ste_setmulti(sc);
+ STE_UNLOCK(sc);
error = 0;
break;
case SIOCGIFMEDIA:
@@ -1512,16 +1539,16 @@ ste_ioctl(ifp, command, data)
error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, command);
break;
case SIOCSIFCAP:
+ STE_LOCK(sc);
ifp->if_capenable &= ~IFCAP_POLLING;
ifp->if_capenable |= ifr->ifr_reqcap & IFCAP_POLLING;
+ STE_UNLOCK(sc);
break;
default:
error = ether_ioctl(ifp, command, data);
break;
}
- STE_UNLOCK(sc);
-
return(error);
}
@@ -1580,22 +1607,30 @@ ste_start(ifp)
struct ifnet *ifp;
{
struct ste_softc *sc;
+
+ sc = ifp->if_softc;
+ STE_LOCK(sc);
+ ste_start_locked(ifp);
+ STE_UNLOCK(sc);
+}
+
+static void
+ste_start_locked(ifp)
+ struct ifnet *ifp;
+{
+ struct ste_softc *sc;
struct mbuf *m_head = NULL;
struct ste_chain *cur_tx;
int idx;
sc = ifp->if_softc;
- STE_LOCK(sc);
+ STE_LOCK_ASSERT(sc);
- if (!sc->ste_link) {
- STE_UNLOCK(sc);
+ if (!sc->ste_link)
return;
- }
- if (ifp->if_drv_flags & IFF_DRV_OACTIVE) {
- STE_UNLOCK(sc);
+ if (ifp->if_drv_flags & IFF_DRV_OACTIVE)
return;
- }
idx = sc->ste_cdata.ste_tx_prod;
@@ -1654,8 +1689,6 @@ ste_start(ifp)
}
sc->ste_cdata.ste_tx_prod = idx;
- STE_UNLOCK(sc);
-
return;
}
@@ -1676,10 +1709,10 @@ ste_watchdog(ifp)
ste_rxeoc(sc);
ste_rxeof(sc);
ste_reset(sc);
- ste_init(sc);
+ ste_init_locked(sc);
if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd))
- ste_start(ifp);
+ ste_start_locked(ifp);
STE_UNLOCK(sc);
return;
@@ -1693,7 +1726,9 @@ ste_shutdown(dev)
sc = device_get_softc(dev);
+ STE_LOCK(sc);
ste_stop(sc);
+ STE_UNLOCK(sc);
return;
}
diff --git a/sys/pci/if_stereg.h b/sys/pci/if_stereg.h
index f8ca37b..eab51640 100644
--- a/sys/pci/if_stereg.h
+++ b/sys/pci/if_stereg.h
@@ -519,7 +519,7 @@ struct ste_softc {
struct ste_chain *ste_tx_prev;
struct ste_list_data *ste_ldata;
struct ste_chain_data ste_cdata;
- struct callout_handle ste_stat_ch;
+ struct callout ste_stat_callout;
struct mtx ste_mtx;
u_int8_t ste_one_phy;
#ifdef DEVICE_POLLING
OpenPOWER on IntegriCloud