MFC: Add locking and mark MPSAFE.

This commit is contained in:
jhb 2005-11-30 16:04:52 +00:00
parent 8304175e7b
commit 19fe05251d
2 changed files with 98 additions and 55 deletions

View File

@ -133,12 +133,15 @@ static void lge_txeof(struct lge_softc *);
static void lge_intr(void *);
static void lge_tick(void *);
static void lge_start(struct ifnet *);
static void lge_start_locked(struct ifnet *);
static int lge_ioctl(struct ifnet *, u_long, caddr_t);
static void lge_init(void *);
static void lge_init_locked(struct lge_softc *);
static void lge_stop(struct lge_softc *);
static void lge_watchdog(struct ifnet *);
static void lge_shutdown(device_t);
static int lge_ifmedia_upd(struct ifnet *);
static void lge_ifmedia_upd_locked(struct ifnet *);
static void lge_ifmedia_sts(struct ifnet *, struct ifmediareq *);
static void lge_eeprom_getword(struct lge_softc *, int, u_int16_t *);
@ -375,6 +378,7 @@ lge_setmulti(sc)
u_int32_t h = 0, hashes[2] = { 0, 0 };
ifp = sc->lge_ifp;
LGE_LOCK_ASSERT(sc);
/* Make sure multicast hash table is enabled. */
CSR_WRITE_4(sc, LGE_MODE1, LGE_MODE1_SETRST_CTL1|LGE_MODE1_RX_MCAST);
@ -463,15 +467,15 @@ static int
lge_attach(dev)
device_t dev;
{
int s;
u_char eaddr[ETHER_ADDR_LEN];
struct lge_softc *sc;
struct ifnet *ifp = NULL;
int error = 0, rid;
s = splimp();
sc = device_get_softc(dev);
mtx_init(&sc->lge_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK,
MTX_DEF);
callout_init_mtx(&sc->lge_stat_callout, &sc->lge_mtx, 0);
/*
* Map control/status registers.
@ -501,14 +505,6 @@ lge_attach(dev)
goto fail;
}
error = bus_setup_intr(dev, sc->lge_irq, INTR_TYPE_NET,
lge_intr, sc, &sc->lge_intrhand);
if (error) {
device_printf(dev, "couldn't set up irq\n");
goto fail;
}
/* Reset the adapter. */
lge_reset(sc);
@ -519,17 +515,14 @@ lge_attach(dev)
lge_read_eeprom(sc, (caddr_t)&eaddr[2], LGE_EE_NODEADDR_1, 1, 0);
lge_read_eeprom(sc, (caddr_t)&eaddr[4], LGE_EE_NODEADDR_2, 1, 0);
callout_handle_init(&sc->lge_stat_ch);
sc->lge_ldata = contigmalloc(sizeof(struct lge_list_data), M_DEVBUF,
M_NOWAIT, 0, 0xffffffff, PAGE_SIZE, 0);
M_NOWAIT | M_ZERO, 0, 0xffffffff, PAGE_SIZE, 0);
if (sc->lge_ldata == NULL) {
device_printf(dev, "no memory for list buffers!\n");
error = ENXIO;
goto fail;
}
bzero(sc->lge_ldata, sizeof(struct lge_list_data));
/* Try to allocate memory for jumbo buffers. */
if (lge_alloc_jumbo_mem(sc)) {
@ -548,8 +541,7 @@ lge_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 = lge_ioctl;
ifp->if_start = lge_start;
ifp->if_watchdog = lge_watchdog;
@ -579,6 +571,15 @@ lge_attach(dev)
* Call MI attach routine.
*/
ether_ifattach(ifp, eaddr);
error = bus_setup_intr(dev, sc->lge_irq, INTR_TYPE_NET | INTR_MPSAFE,
lge_intr, sc, &sc->lge_intrhand);
if (error) {
ether_ifdetach(ifp);
device_printf(dev, "couldn't set up irq\n");
goto fail;
}
return (0);
fail:
@ -587,13 +588,11 @@ lge_attach(dev)
sizeof(struct lge_list_data), M_DEVBUF);
if (ifp)
if_free(ifp);
if (sc->lge_intrhand)
bus_teardown_intr(dev, sc->lge_irq, sc->lge_intrhand);
if (sc->lge_irq)
bus_release_resource(dev, SYS_RES_IRQ, 0, sc->lge_irq);
if (sc->lge_res)
bus_release_resource(dev, LGE_RES, LGE_RID, sc->lge_res);
splx(s);
mtx_destroy(&sc->lge_mtx);
return(error);
}
@ -603,15 +602,15 @@ lge_detach(dev)
{
struct lge_softc *sc;
struct ifnet *ifp;
int s;
s = splimp();
sc = device_get_softc(dev);
ifp = sc->lge_ifp;
LGE_LOCK(sc);
lge_reset(sc);
lge_stop(sc);
LGE_UNLOCK(sc);
callout_drain(&sc->lge_stat_callout);
ether_ifdetach(ifp);
if_free(ifp);
@ -624,8 +623,7 @@ lge_detach(dev)
contigfree(sc->lge_ldata, sizeof(struct lge_list_data), M_DEVBUF);
lge_free_jumbo_mem(sc);
splx(s);
mtx_destroy(&sc->lge_mtx);
return(0);
}
@ -956,7 +954,9 @@ lge_rxeof(sc, cnt)
m->m_pkthdr.csum_data = 0xffff;
}
LGE_UNLOCK(sc);
(*ifp->if_input)(ifp, m);
LGE_LOCK(sc);
}
sc->lge_cdata.lge_rx_cons = i;
@ -972,7 +972,7 @@ lge_rxeoc(sc)
ifp = sc->lge_ifp;
ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
lge_init(sc);
lge_init_locked(sc);
return;
}
@ -1031,12 +1031,10 @@ lge_tick(xsc)
struct lge_softc *sc;
struct mii_data *mii;
struct ifnet *ifp;
int s;
s = splimp();
sc = xsc;
ifp = sc->lge_ifp;
LGE_LOCK_ASSERT(sc);
CSR_WRITE_4(sc, LGE_STATSIDX, LGE_STATS_SINGLE_COLL_PKTS);
ifp->if_collisions += CSR_READ_4(sc, LGE_STATSVAL);
@ -1054,13 +1052,11 @@ lge_tick(xsc)
IFM_SUBTYPE(mii->mii_media_active) == IFM_1000_T))
if_printf(ifp, "gigabit link up\n");
if (ifp->if_snd.ifq_head != NULL)
lge_start(ifp);
lge_start_locked(ifp);
}
}
sc->lge_stat_ch = timeout(lge_tick, sc, hz);
splx(s);
callout_reset(&sc->lge_stat_callout, hz, lge_tick, sc);
return;
}
@ -1075,10 +1071,12 @@ lge_intr(arg)
sc = arg;
ifp = sc->lge_ifp;
LGE_LOCK(sc);
/* Supress unwanted interrupts */
if (!(ifp->if_flags & IFF_UP)) {
lge_stop(sc);
LGE_UNLOCK(sc);
return;
}
@ -1104,7 +1102,7 @@ lge_intr(arg)
if (status & LGE_ISR_PHY_INTR) {
sc->lge_link = 0;
untimeout(lge_tick, sc, sc->lge_stat_ch);
callout_stop(&sc->lge_stat_callout);
lge_tick(sc);
}
}
@ -1113,8 +1111,9 @@ lge_intr(arg)
CSR_WRITE_4(sc, LGE_IMR, LGE_IMR_SETRST_CTL0|LGE_IMR_INTR_ENB);
if (ifp->if_snd.ifq_head != NULL)
lge_start(ifp);
lge_start_locked(ifp);
LGE_UNLOCK(sc);
return;
}
@ -1178,6 +1177,18 @@ lge_start(ifp)
struct ifnet *ifp;
{
struct lge_softc *sc;
sc = ifp->if_softc;
LGE_LOCK(sc);
lge_start_locked(ifp);
LGE_UNLOCK(sc);
}
static void
lge_start_locked(ifp)
struct ifnet *ifp;
{
struct lge_softc *sc;
struct mbuf *m_head = NULL;
u_int32_t idx;
@ -1227,15 +1238,23 @@ lge_init(xsc)
void *xsc;
{
struct lge_softc *sc = xsc;
LGE_LOCK(sc);
lge_init_locked(sc);
LGE_UNLOCK(sc);
}
static void
lge_init_locked(sc)
struct lge_softc *sc;
{
struct ifnet *ifp = sc->lge_ifp;
struct mii_data *mii;
int s;
LGE_LOCK_ASSERT(sc);
if (ifp->if_drv_flags & IFF_DRV_RUNNING)
return;
s = splimp();
/*
* Cancel pending I/O and free all RX/TX buffers.
*/
@ -1253,7 +1272,6 @@ lge_init(xsc)
if_printf(ifp, "initialization failed: no "
"memory for rx buffers\n");
lge_stop(sc);
(void)splx(s);
return;
}
@ -1345,14 +1363,12 @@ lge_init(xsc)
CSR_WRITE_4(sc, LGE_IMR, LGE_IMR_SETRST_CTL0|
LGE_IMR_SETRST_CTL1|LGE_IMR_INTR_ENB|LGE_INTRS);
lge_ifmedia_upd(ifp);
lge_ifmedia_upd_locked(ifp);
ifp->if_drv_flags |= IFF_DRV_RUNNING;
ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
(void)splx(s);
sc->lge_stat_ch = timeout(lge_tick, sc, hz);
callout_reset(&sc->lge_stat_callout, hz, lge_tick, sc);
return;
}
@ -1365,10 +1381,25 @@ lge_ifmedia_upd(ifp)
struct ifnet *ifp;
{
struct lge_softc *sc;
sc = ifp->if_softc;
LGE_LOCK(sc);
lge_ifmedia_upd_locked(ifp);
LGE_UNLOCK(sc);
return(0);
}
static void
lge_ifmedia_upd_locked(ifp)
struct ifnet *ifp;
{
struct lge_softc *sc;
struct mii_data *mii;
sc = ifp->if_softc;
LGE_LOCK_ASSERT(sc);
mii = device_get_softc(sc->lge_miibus);
sc->lge_link = 0;
if (mii->mii_instance) {
@ -1378,8 +1409,6 @@ lge_ifmedia_upd(ifp)
mii_phy_reset(miisc);
}
mii_mediachg(mii);
return(0);
}
/*
@ -1395,8 +1424,10 @@ lge_ifmedia_sts(ifp, ifmr)
sc = ifp->if_softc;
LGE_LOCK(sc);
mii = device_get_softc(sc->lge_miibus);
mii_pollstat(mii);
LGE_UNLOCK(sc);
ifmr->ifm_active = mii->mii_media_active;
ifmr->ifm_status = mii->mii_media_status;
@ -1412,18 +1443,19 @@ lge_ioctl(ifp, command, data)
struct lge_softc *sc = ifp->if_softc;
struct ifreq *ifr = (struct ifreq *) data;
struct mii_data *mii;
int s, error = 0;
s = splimp();
int error = 0;
switch(command) {
case SIOCSIFMTU:
LGE_LOCK(sc);
if (ifr->ifr_mtu > LGE_JUMBO_MTU)
error = EINVAL;
else
ifp->if_mtu = ifr->ifr_mtu;
LGE_UNLOCK(sc);
break;
case SIOCSIFFLAGS:
LGE_LOCK(sc);
if (ifp->if_flags & IFF_UP) {
if (ifp->if_drv_flags & IFF_DRV_RUNNING &&
ifp->if_flags & IFF_PROMISC &&
@ -1438,18 +1470,21 @@ lge_ioctl(ifp, command, data)
LGE_MODE1_RX_PROMISC);
} else {
ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
lge_init(sc);
lge_init_locked(sc);
}
} else {
if (ifp->if_drv_flags & IFF_DRV_RUNNING)
lge_stop(sc);
}
sc->lge_if_flags = ifp->if_flags;
LGE_UNLOCK(sc);
error = 0;
break;
case SIOCADDMULTI:
case SIOCDELMULTI:
LGE_LOCK(sc);
lge_setmulti(sc);
LGE_UNLOCK(sc);
error = 0;
break;
case SIOCGIFMEDIA:
@ -1462,8 +1497,6 @@ lge_ioctl(ifp, command, data)
break;
}
(void)splx(s);
return(error);
}
@ -1475,16 +1508,18 @@ lge_watchdog(ifp)
sc = ifp->if_softc;
LGE_LOCK(sc);
ifp->if_oerrors++;
if_printf(ifp, "watchdog timeout\n");
lge_stop(sc);
lge_reset(sc);
ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
lge_init(sc);
lge_init_locked(sc);
if (ifp->if_snd.ifq_head != NULL)
lge_start(ifp);
lge_start_locked(ifp);
LGE_UNLOCK(sc);
return;
}
@ -1500,9 +1535,10 @@ lge_stop(sc)
register int i;
struct ifnet *ifp;
LGE_LOCK_ASSERT(sc);
ifp = sc->lge_ifp;
ifp->if_timer = 0;
untimeout(lge_tick, sc, sc->lge_stat_ch);
callout_stop(&sc->lge_stat_callout);
CSR_WRITE_4(sc, LGE_IMR, LGE_IMR_INTR_ENB);
/* Disable receiver and transmitter. */
@ -1551,8 +1587,10 @@ lge_shutdown(dev)
sc = device_get_softc(dev);
LGE_LOCK(sc);
lge_reset(sc);
lge_stop(sc);
LGE_UNLOCK(sc);
return;
}

View File

@ -535,7 +535,8 @@ struct lge_softc {
int lge_if_flags;
struct lge_list_data *lge_ldata;
struct lge_ring_data lge_cdata;
struct callout_handle lge_stat_ch;
struct callout lge_stat_callout;
struct mtx lge_mtx;
SLIST_HEAD(__lge_jfreehead, lge_jpool_entry) lge_jfree_listhead;
SLIST_HEAD(__lge_jinusehead, lge_jpool_entry) lge_jinuse_listhead;
};
@ -561,6 +562,10 @@ struct lge_softc {
#define CSR_READ_1(sc, reg) \
bus_space_read_1(sc->lge_btag, sc->lge_bhandle, reg)
#define LGE_LOCK(sc) mtx_lock(&(sc)->lge_mtx)
#define LGE_UNLOCK(sc) mtx_unlock(&(sc)->lge_mtx)
#define LGE_LOCK_ASSERT(sc) mtx_assert(&(sc)->lge_mtx, MA_OWNED)
#define LGE_TIMEOUT 1000
#define LGE_RXLEN 1536
#define LGE_MIN_FRAMELEN 60