- Use callout_init_mtx() to close races between hme_stop() and hme_tick().

- Use the driver lock instead of Giant in a bus dma callback.
- Clear IFF_DRV_(RUNNING|OACTIVE) in hme_stop() instead of just clearing
  RUNNING in hme_ioctl() to be more like other ethernet drivers.
- Lock the driver lock around mii operations.
- Remove spls.
- Cleanup locking in hme_ioctl().

MFC after:	1 week
This commit is contained in:
John Baldwin 2005-08-10 20:12:25 +00:00
parent efefac4077
commit 3e17bf524e

@ -112,7 +112,6 @@ static int hme_meminit(struct hme_softc *);
static int hme_mac_bitflip(struct hme_softc *, u_int32_t, u_int32_t,
u_int32_t, u_int32_t);
static void hme_mifinit(struct hme_softc *);
static void hme_reset(struct hme_softc *);
static void hme_setladrf(struct hme_softc *, int);
static int hme_mediachange(struct ifnet *);
@ -206,6 +205,8 @@ hme_config(struct hme_softc *sc)
hme_stop(sc);
HME_UNLOCK(sc);
callout_init_mtx(&sc->sc_tick_ch, &sc->sc_lock, 0);
/*
* Allocate DMA capable memory
* Buffer descriptors must be aligned on a 2048 byte boundary;
@ -224,7 +225,7 @@ hme_config(struct hme_softc *sc)
error = bus_dma_tag_create(sc->sc_pdmatag, 2048, 0,
BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL, size,
1, BUS_SPACE_MAXSIZE_32BIT, BUS_DMA_ALLOCNOW, busdma_lock_mutex,
&Giant, &sc->sc_cdmatag);
&sc->sc_lock, &sc->sc_cdmatag);
if (error)
goto fail_ptag;
@ -301,9 +302,7 @@ hme_config(struct hme_softc *sc)
ifp->if_snd.ifq_drv_maxlen = HME_NTXQ;
IFQ_SET_READY(&ifp->if_snd);
HME_LOCK(sc);
hme_mifinit(sc);
HME_UNLOCK(sc);
if ((error = mii_phy_probe(sc->sc_dev, &sc->sc_miibus, hme_mediachange,
hme_mediastatus)) != 0) {
@ -347,8 +346,6 @@ hme_config(struct hme_softc *sc)
ifp->if_capabilities |= IFCAP_VLAN_MTU | IFCAP_HWCSUM;
ifp->if_hwassist |= sc->sc_csum_features;
ifp->if_capenable |= IFCAP_VLAN_MTU | IFCAP_HWCSUM;
callout_init(&sc->sc_tick_ch, CALLOUT_MPSAFE);
return (0);
fail_txdesc:
@ -447,27 +444,13 @@ static void
hme_tick(void *arg)
{
struct hme_softc *sc = arg;
int s;
s = splnet();
HME_LOCK_ASSERT(sc, MA_OWNED);
mii_tick(sc->sc_mii);
splx(s);
callout_reset(&sc->sc_tick_ch, hz, hme_tick, sc);
}
static void
hme_reset(struct hme_softc *sc)
{
int s;
HME_LOCK(sc);
s = splnet();
hme_init_locked(sc);
splx(s);
HME_UNLOCK(sc);
}
static void
hme_stop(struct hme_softc *sc)
{
@ -475,6 +458,7 @@ hme_stop(struct hme_softc *sc)
int n;
callout_stop(&sc->sc_tick_ch);
sc->sc_ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE);
/* Reset transmitter and receiver */
HME_SEB_WRITE_4(sc, HME_SEBI_RESET, HME_SEB_RESET_ETX |
@ -872,9 +856,7 @@ hme_init_locked(struct hme_softc *sc)
/* Set the current media. */
/*
* HME_UNLOCK(sc);
* mii_mediachg(sc->sc_mii);
* HME_LOCK(sc);
*/
/* Start the one second timer. */
@ -1372,9 +1354,9 @@ hme_watchdog(struct ifnet *ifp)
#endif
device_printf(sc->sc_dev, "device timeout\n");
++ifp->if_oerrors;
HME_UNLOCK(sc);
hme_reset(sc);
hme_init_locked(sc);
HME_UNLOCK(sc);
}
/*
@ -1385,8 +1367,6 @@ hme_mifinit(struct hme_softc *sc)
{
u_int32_t v;
HME_LOCK_ASSERT(sc, MA_OWNED);
/* Configure the MIF in frame mode */
v = HME_MIF_READ_4(sc, HME_MIFI_CFG);
v &= ~HME_MIF_CFG_BBMODE;
@ -1403,7 +1383,6 @@ hme_mii_readreg(device_t dev, int phy, int reg)
int n;
u_int32_t v;
HME_LOCK(sc);
/* Select the desired PHY in the MIF configuration register */
v = HME_MIF_READ_4(sc, HME_MIFI_CFG);
/* Clear PHY select bit */
@ -1425,13 +1404,11 @@ hme_mii_readreg(device_t dev, int phy, int reg)
DELAY(1);
v = HME_MIF_READ_4(sc, HME_MIFI_FO);
if (v & HME_MIF_FO_TALSB) {
HME_UNLOCK(sc);
return (v & HME_MIF_FO_DATA);
}
}
device_printf(sc->sc_dev, "mii_read timeout\n");
HME_UNLOCK(sc);
return (0);
}
@ -1442,7 +1419,6 @@ hme_mii_writereg(device_t dev, int phy, int reg, int val)
int n;
u_int32_t v;
HME_LOCK(sc);
/* Select the desired PHY in the MIF configuration register */
v = HME_MIF_READ_4(sc, HME_MIFI_CFG);
/* Clear PHY select bit */
@ -1464,14 +1440,11 @@ hme_mii_writereg(device_t dev, int phy, int reg, int val)
for (n = 0; n < 100; n++) {
DELAY(1);
v = HME_MIF_READ_4(sc, HME_MIFI_FO);
if (v & HME_MIF_FO_TALSB) {
HME_UNLOCK(sc);
if (v & HME_MIF_FO_TALSB)
return (1);
}
}
device_printf(sc->sc_dev, "mii_write timeout\n");
HME_UNLOCK(sc);
return (0);
}
@ -1483,7 +1456,6 @@ hme_mii_statchg(device_t dev)
int phy;
u_int32_t v;
HME_LOCK(sc);
instance = IFM_INST(sc->sc_mii->mii_media.ifm_cur->ifm_media);
phy = sc->sc_phys[instance];
#ifdef HMEDEBUG
@ -1500,28 +1472,27 @@ hme_mii_statchg(device_t dev)
/* Set the MAC Full Duplex bit appropriately */
v = HME_MAC_READ_4(sc, HME_MACI_TXCFG);
if (!hme_mac_bitflip(sc, HME_MACI_TXCFG, v, HME_MAC_TXCFG_ENABLE, 0)) {
HME_UNLOCK(sc);
if (!hme_mac_bitflip(sc, HME_MACI_TXCFG, v, HME_MAC_TXCFG_ENABLE, 0))
return;
}
if ((IFM_OPTIONS(sc->sc_mii->mii_media_active) & IFM_FDX) != 0)
v |= HME_MAC_TXCFG_FULLDPLX;
else
v &= ~HME_MAC_TXCFG_FULLDPLX;
HME_MAC_WRITE_4(sc, HME_MACI_TXCFG, v);
if (!hme_mac_bitflip(sc, HME_MACI_TXCFG, v, 0, HME_MAC_TXCFG_ENABLE)) {
HME_UNLOCK(sc);
if (!hme_mac_bitflip(sc, HME_MACI_TXCFG, v, 0, HME_MAC_TXCFG_ENABLE))
return;
}
HME_UNLOCK(sc);
}
static int
hme_mediachange(struct ifnet *ifp)
{
struct hme_softc *sc = ifp->if_softc;
int error;
return (mii_mediachg(sc->sc_mii));
HME_LOCK(sc);
error = mii_mediachg(sc->sc_mii);
HME_UNLOCK(sc);
return (error);
}
static void
@ -1535,9 +1506,7 @@ hme_mediastatus(struct ifnet *ifp, struct ifmediareq *ifmr)
return;
}
HME_UNLOCK(sc);
mii_pollstat(sc->sc_mii);
HME_LOCK(sc);
ifmr->ifm_active = sc->sc_mii->mii_media_active;
ifmr->ifm_status = sc->sc_mii->mii_media_status;
HME_UNLOCK(sc);
@ -1551,13 +1520,11 @@ hme_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
{
struct hme_softc *sc = ifp->if_softc;
struct ifreq *ifr = (struct ifreq *)data;
int s, error = 0;
HME_LOCK(sc);
s = splnet();
int error = 0;
switch (cmd) {
case SIOCSIFFLAGS:
HME_LOCK(sc);
if ((ifp->if_flags & IFF_UP) == 0 &&
(ifp->if_drv_flags & IFF_DRV_RUNNING) != 0) {
/*
@ -1565,7 +1532,6 @@ hme_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
* stop it.
*/
hme_stop(sc);
ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
} else if ((ifp->if_flags & IFF_UP) != 0 &&
(ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) {
/*
@ -1589,35 +1555,34 @@ hme_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
#ifdef HMEDEBUG
sc->sc_debug = (ifp->if_flags & IFF_DEBUG) != 0 ? 1 : 0;
#endif
HME_UNLOCK(sc);
break;
case SIOCADDMULTI:
case SIOCDELMULTI:
HME_LOCK(sc);
hme_setladrf(sc, 1);
HME_UNLOCK(sc);
error = 0;
break;
case SIOCGIFMEDIA:
case SIOCSIFMEDIA:
HME_UNLOCK(sc);
error = ifmedia_ioctl(ifp, ifr, &sc->sc_mii->mii_media, cmd);
HME_LOCK(sc);
break;
case SIOCSIFCAP:
HME_LOCK(sc);
ifp->if_capenable = ifr->ifr_reqcap;
if ((ifp->if_capenable & IFCAP_TXCSUM) != 0)
ifp->if_hwassist = sc->sc_csum_features;
else
ifp->if_hwassist = 0;
HME_UNLOCK(sc);
break;
default:
HME_UNLOCK(sc);
error = ether_ioctl(ifp, cmd, data);
HME_LOCK(sc);
break;
}
splx(s);
HME_UNLOCK(sc);
return (error);
}