MFC: Fix up locking and mark MPSAFE.

Approved by:	re (scottl)
This commit is contained in:
jhb 2005-08-26 14:52:36 +00:00
parent 2bcd5cdce1
commit e878090f8a
4 changed files with 207 additions and 180 deletions

View File

@ -235,8 +235,10 @@ static void dc_tick(void *);
static void dc_tx_underrun(struct dc_softc *);
static void dc_intr(void *);
static void dc_start(struct ifnet *);
static void dc_start_locked(struct ifnet *);
static int dc_ioctl(struct ifnet *, u_long, caddr_t);
static void dc_init(void *);
static void dc_init_locked(struct dc_softc *);
static void dc_stop(struct dc_softc *);
static void dc_watchdog(struct ifnet *);
static void dc_shutdown(device_t);
@ -343,8 +345,6 @@ DRIVER_MODULE(miibus, dc, miibus_driver, miibus_devclass, 0, 0);
#define SIO_SET(x) DC_SETBIT(sc, DC_SIO, (x))
#define SIO_CLR(x) DC_CLRBIT(sc, DC_SIO, (x))
#define IS_MPSAFE 0
static void
dc_delay(struct dc_softc *sc)
{
@ -670,8 +670,6 @@ dc_mii_readreg(struct dc_softc *sc, struct dc_mii_frame *frame)
{
int i, ack;
DC_LOCK(sc);
/*
* Set up frame for RX.
*/
@ -724,8 +722,6 @@ dc_mii_readreg(struct dc_softc *sc, struct dc_mii_frame *frame)
dc_mii_writebit(sc, 0);
dc_mii_writebit(sc, 0);
DC_UNLOCK(sc);
if (ack)
return (1);
return (0);
@ -738,7 +734,6 @@ static int
dc_mii_writereg(struct dc_softc *sc, struct dc_mii_frame *frame)
{
DC_LOCK(sc);
/*
* Set up frame for TX.
*/
@ -763,8 +758,6 @@ dc_mii_writereg(struct dc_softc *sc, struct dc_mii_frame *frame)
dc_mii_writebit(sc, 0);
dc_mii_writebit(sc, 0);
DC_UNLOCK(sc);
return (0);
}
@ -864,8 +857,8 @@ dc_miibus_readreg(device_t dev, int phy, int reg)
phy_reg = DC_AL_ANER;
break;
default:
printf("dc%d: phy_read: bad phy register %x\n",
sc->dc_unit, reg);
device_printf(dev, "phy_read: bad phy register %x\n",
reg);
return (0);
break;
}
@ -940,8 +933,8 @@ dc_miibus_writereg(device_t dev, int phy, int reg, int data)
phy_reg = DC_AL_ANER;
break;
default:
printf("dc%d: phy_write: bad phy register %x\n",
sc->dc_unit, reg);
device_printf(dev, "phy_write: bad phy register %x\n",
reg);
return (0);
break;
}
@ -1388,8 +1381,8 @@ dc_setcfg(struct dc_softc *sc, int media)
}
if (i == DC_TIMEOUT)
printf("dc%d: failed to force tx and "
"rx to idle state\n", sc->dc_unit);
if_printf(sc->dc_ifp,
"failed to force tx and rx to idle state\n");
}
if (IFM_SUBTYPE(media) == IFM_100_TX) {
@ -1529,7 +1522,7 @@ dc_reset(struct dc_softc *sc)
}
if (i == DC_TIMEOUT)
printf("dc%d: reset never completed!\n", sc->dc_unit);
if_printf(sc->dc_ifp, "reset never completed!\n");
/* Wait a little while for the chip to get its brains in order. */
DELAY(1000);
@ -1837,15 +1830,14 @@ dc_attach(device_t dev)
struct dc_softc *sc;
struct ifnet *ifp;
u_int32_t revision;
int unit, error = 0, rid, mac_offset;
int error = 0, rid, mac_offset;
int i;
u_int8_t *mac;
sc = device_get_softc(dev);
unit = device_get_unit(dev);
mtx_init(&sc->dc_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK,
MTX_DEF | MTX_RECURSE);
MTX_DEF);
/*
* Map control/status registers.
@ -1856,7 +1848,7 @@ dc_attach(device_t dev)
sc->dc_res = bus_alloc_resource_any(dev, DC_RES, &rid, RF_ACTIVE);
if (sc->dc_res == NULL) {
printf("dc%d: couldn't map ports/memory\n", unit);
device_printf(dev, "couldn't map ports/memory\n");
error = ENXIO;
goto fail;
}
@ -1870,7 +1862,7 @@ dc_attach(device_t dev)
RF_SHAREABLE | RF_ACTIVE);
if (sc->dc_irq == NULL) {
printf("dc%d: couldn't map interrupt\n", unit);
device_printf(dev, "couldn't map interrupt\n");
error = ENXIO;
goto fail;
}
@ -2001,8 +1993,7 @@ dc_attach(device_t dev)
dc_read_srom(sc, sc->dc_romwidth);
break;
default:
printf("dc%d: unknown device: %x\n", sc->dc_unit,
sc->dc_info->dc_did);
device_printf(dev, "unknown device: %x\n", sc->dc_info->dc_did);
break;
}
@ -2097,21 +2088,19 @@ dc_attach(device_t dev)
break;
}
sc->dc_unit = unit;
/* Allocate a busdma tag and DMA safe memory for TX/RX descriptors. */
error = bus_dma_tag_create(NULL, PAGE_SIZE, 0, BUS_SPACE_MAXADDR_32BIT,
BUS_SPACE_MAXADDR, NULL, NULL, sizeof(struct dc_list_data), 1,
sizeof(struct dc_list_data), 0, NULL, NULL, &sc->dc_ltag);
if (error) {
printf("dc%d: failed to allocate busdma tag\n", unit);
device_printf(dev, "failed to allocate busdma tag\n");
error = ENXIO;
goto fail;
}
error = bus_dmamem_alloc(sc->dc_ltag, (void **)&sc->dc_ldata,
BUS_DMA_NOWAIT | BUS_DMA_ZERO, &sc->dc_lmap);
if (error) {
printf("dc%d: failed to allocate DMA safe memory\n", unit);
device_printf(dev, "failed to allocate DMA safe memory\n");
error = ENXIO;
goto fail;
}
@ -2119,7 +2108,7 @@ dc_attach(device_t dev)
sizeof(struct dc_list_data), dc_dma_map_addr, &sc->dc_laddr,
BUS_DMA_NOWAIT);
if (error) {
printf("dc%d: cannot get address of the descriptors\n", unit);
device_printf(dev, "cannot get address of the descriptors\n");
error = ENXIO;
goto fail;
}
@ -2132,21 +2121,21 @@ dc_attach(device_t dev)
BUS_SPACE_MAXADDR, NULL, NULL, DC_SFRAME_LEN + DC_MIN_FRAMELEN, 1,
DC_SFRAME_LEN + DC_MIN_FRAMELEN, 0, NULL, NULL, &sc->dc_stag);
if (error) {
printf("dc%d: failed to allocate busdma tag\n", unit);
device_printf(dev, "failed to allocate busdma tag\n");
error = ENXIO;
goto fail;
}
error = bus_dmamem_alloc(sc->dc_stag, (void **)&sc->dc_cdata.dc_sbuf,
BUS_DMA_NOWAIT, &sc->dc_smap);
if (error) {
printf("dc%d: failed to allocate DMA safe memory\n", unit);
device_printf(dev, "failed to allocate DMA safe memory\n");
error = ENXIO;
goto fail;
}
error = bus_dmamap_load(sc->dc_stag, sc->dc_smap, sc->dc_cdata.dc_sbuf,
DC_SFRAME_LEN, dc_dma_map_addr, &sc->dc_saddr, BUS_DMA_NOWAIT);
if (error) {
printf("dc%d: cannot get address of the descriptors\n", unit);
device_printf(dev, "cannot get address of the descriptors\n");
error = ENXIO;
goto fail;
}
@ -2156,7 +2145,7 @@ dc_attach(device_t dev)
BUS_SPACE_MAXADDR, NULL, NULL, MCLBYTES, DC_TX_LIST_CNT, MCLBYTES,
0, NULL, NULL, &sc->dc_mtag);
if (error) {
printf("dc%d: failed to allocate busdma tag\n", unit);
device_printf(dev, "failed to allocate busdma tag\n");
error = ENXIO;
goto fail;
}
@ -2166,7 +2155,7 @@ dc_attach(device_t dev)
error = bus_dmamap_create(sc->dc_mtag, 0,
&sc->dc_cdata.dc_tx_map[i]);
if (error) {
printf("dc%d: failed to init TX ring\n", unit);
device_printf(dev, "failed to init TX ring\n");
error = ENXIO;
goto fail;
}
@ -2175,21 +2164,21 @@ dc_attach(device_t dev)
error = bus_dmamap_create(sc->dc_mtag, 0,
&sc->dc_cdata.dc_rx_map[i]);
if (error) {
printf("dc%d: failed to init RX ring\n", unit);
device_printf(dev, "failed to init RX ring\n");
error = ENXIO;
goto fail;
}
}
error = bus_dmamap_create(sc->dc_mtag, 0, &sc->dc_sparemap);
if (error) {
printf("dc%d: failed to init RX ring\n", unit);
device_printf(dev, "failed to init RX ring\n");
error = ENXIO;
goto fail;
}
ifp = sc->dc_ifp = if_alloc(IFT_ETHER);
if (ifp == NULL) {
printf("dc%d: can not if_alloc()\n", unit);
device_printf(dev, "can not if_alloc()\n");
error = ENOSPC;
goto fail;
}
@ -2198,8 +2187,6 @@ dc_attach(device_t dev)
/* XXX: bleah, MTU gets overwritten in ether_ifattach() */
ifp->if_mtu = ETHERMTU;
ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
if (!IS_MPSAFE)
ifp->if_flags |= IFF_NEEDSGIANT;
ifp->if_ioctl = dc_ioctl;
ifp->if_start = dc_start;
ifp->if_watchdog = dc_watchdog;
@ -2259,7 +2246,7 @@ dc_attach(device_t dev)
}
if (error) {
printf("dc%d: MII without any PHY!\n", sc->dc_unit);
device_printf(dev, "MII without any PHY!\n");
goto fail;
}
@ -2280,7 +2267,7 @@ dc_attach(device_t dev)
#endif
ifp->if_capenable = ifp->if_capabilities;
callout_init(&sc->dc_stat_ch, IS_MPSAFE ? CALLOUT_MPSAFE : 0);
callout_init_mtx(&sc->dc_stat_ch, &sc->dc_mtx, 0);
#ifdef SRM_MEDIA
sc->dc_srm_media = 0;
@ -2314,12 +2301,11 @@ dc_attach(device_t dev)
ether_ifattach(ifp, eaddr);
/* Hook interrupt last to avoid having to lock softc */
error = bus_setup_intr(dev, sc->dc_irq, INTR_TYPE_NET |
(IS_MPSAFE ? INTR_MPSAFE : 0),
error = bus_setup_intr(dev, sc->dc_irq, INTR_TYPE_NET | INTR_MPSAFE,
dc_intr, sc, &sc->dc_intrhand);
if (error) {
printf("dc%d: couldn't set up irq\n", unit);
device_printf(dev, "couldn't set up irq\n");
ether_ifdetach(ifp);
if_free(ifp);
goto fail;
@ -2348,13 +2334,15 @@ dc_detach(device_t dev)
sc = device_get_softc(dev);
KASSERT(mtx_initialized(&sc->dc_mtx), ("dc mutex not initialized"));
DC_LOCK(sc);
ifp = sc->dc_ifp;
/* These should only be active if attach succeeded */
if (device_is_attached(dev)) {
DC_LOCK(sc);
dc_stop(sc);
DC_UNLOCK(sc);
callout_drain(&sc->dc_stat_ch);
ether_ifdetach(ifp);
if_free(ifp);
}
@ -2394,7 +2382,6 @@ dc_detach(device_t dev)
}
free(sc->dc_srom, M_DEVBUF);
DC_UNLOCK(sc);
mtx_destroy(&sc->dc_mtx);
return (0);
@ -2755,7 +2742,7 @@ dc_rxeof(struct dc_softc *sc)
DC_INC(i, DC_RX_LIST_CNT);
continue;
} else {
dc_init(sc);
dc_init_locked(sc);
return;
}
}
@ -2883,7 +2870,7 @@ dc_txeof(struct dc_softc *sc)
if (txstat & DC_TXSTAT_LATECOLL)
ifp->if_collisions++;
if (!(txstat & DC_TXSTAT_UNDERRUN)) {
dc_init(sc);
dc_init_locked(sc);
return;
}
}
@ -2922,7 +2909,7 @@ dc_tick(void *xsc)
u_int32_t r;
sc = xsc;
DC_LOCK(sc);
DC_LOCK_ASSERT(sc);
ifp = sc->dc_ifp;
mii = device_get_softc(sc->dc_miibus);
@ -2976,15 +2963,13 @@ dc_tick(void *xsc)
IFM_SUBTYPE(mii->mii_media_active) != IFM_NONE) {
sc->dc_link++;
if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd))
dc_start(ifp);
dc_start_locked(ifp);
}
if (sc->dc_flags & DC_21143_NWAY && !sc->dc_link)
callout_reset(&sc->dc_stat_ch, hz/10, dc_tick, sc);
else
callout_reset(&sc->dc_stat_ch, hz, dc_tick, sc);
DC_UNLOCK(sc);
}
/*
@ -2998,7 +2983,7 @@ dc_tx_underrun(struct dc_softc *sc)
int i;
if (DC_IS_DAVICOM(sc))
dc_init(sc);
dc_init_locked(sc);
if (DC_IS_INTEL(sc)) {
/*
@ -3015,13 +3000,13 @@ dc_tx_underrun(struct dc_softc *sc)
DELAY(10);
}
if (i == DC_TIMEOUT) {
printf("dc%d: failed to force tx to idle state\n",
sc->dc_unit);
dc_init(sc);
if_printf(sc->dc_ifp,
"failed to force tx to idle state\n");
dc_init_locked(sc);
}
}
printf("dc%d: TX underrun -- ", sc->dc_unit);
if_printf(sc->dc_ifp, "TX underrun -- ");
sc->dc_txthresh += DC_TXTHRESH_INC;
if (sc->dc_txthresh > DC_TXTHRESH_MAX) {
printf("using store and forward mode\n");
@ -3059,7 +3044,7 @@ dc_poll(struct ifnet *ifp, enum poll_cmd cmd, int count)
dc_txeof(sc);
if (!IFQ_IS_EMPTY(&ifp->if_snd) &&
!(ifp->if_drv_flags & IFF_DRV_OACTIVE))
dc_start(ifp);
dc_start_locked(ifp);
if (cmd == POLL_AND_CHECK_STATUS) { /* also check status register */
u_int32_t status;
@ -3090,9 +3075,9 @@ dc_poll(struct ifnet *ifp, enum poll_cmd cmd, int count)
dc_tx_underrun(sc);
if (status & DC_ISR_BUS_ERR) {
printf("dc_poll: dc%d bus error\n", sc->dc_unit);
if_printf(ifp, "dc_poll: bus error\n");
dc_reset(sc);
dc_init(sc);
dc_init_locked(sc);
}
}
DC_UNLOCK(sc);
@ -3179,7 +3164,7 @@ dc_intr(void *arg)
if (status & DC_ISR_BUS_ERR) {
dc_reset(sc);
dc_init(sc);
dc_init_locked(sc);
}
}
@ -3187,7 +3172,7 @@ dc_intr(void *arg)
CSR_WRITE_4(sc, DC_IMR, DC_INTRS);
if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd))
dc_start(ifp);
dc_start_locked(ifp);
#ifdef DEVICE_POLLING
done:
@ -3314,6 +3299,17 @@ dc_encap(struct dc_softc *sc, struct mbuf **m_head)
static void
dc_start(struct ifnet *ifp)
{
struct dc_softc *sc;
sc = ifp->if_softc;
DC_LOCK(sc);
dc_start_locked(ifp);
DC_UNLOCK(sc);
}
static void
dc_start_locked(struct ifnet *ifp)
{
struct dc_softc *sc;
struct mbuf *m_head = NULL, *m;
@ -3322,17 +3318,13 @@ dc_start(struct ifnet *ifp)
sc = ifp->if_softc;
DC_LOCK(sc);
DC_LOCK_ASSERT(sc);
if (!sc->dc_link && ifp->if_snd.ifq_len < 10) {
DC_UNLOCK(sc);
if (!sc->dc_link && ifp->if_snd.ifq_len < 10)
return;
}
if (ifp->if_drv_flags & IFF_DRV_OACTIVE) {
DC_UNLOCK(sc);
if (ifp->if_drv_flags & IFF_DRV_OACTIVE)
return;
}
idx = sc->dc_cdata.dc_tx_first = sc->dc_cdata.dc_tx_prod;
@ -3384,18 +3376,37 @@ dc_start(struct ifnet *ifp)
*/
ifp->if_timer = 5;
}
DC_UNLOCK(sc);
}
static void
dc_init(void *xsc)
{
struct dc_softc *sc = xsc;
DC_LOCK(sc);
dc_init_locked(sc);
#ifdef SRM_MEDIA
if(sc->dc_srm_media) {
struct ifreq ifr;
struct mii_data *mii;
ifr.ifr_media = sc->dc_srm_media;
sc->dc_srm_media = 0;
DC_UNLOCK(sc);
mii = device_get_softc(sc->dc_miibus);
ifmedia_ioctl(sc->dc_ifp, &ifr, &mii->mii_media, SIOCSIFMEDIA);
} else
#endif
DC_UNLOCK(sc);
}
static void
dc_init_locked(struct dc_softc *sc)
{
struct ifnet *ifp = sc->dc_ifp;
struct mii_data *mii;
DC_LOCK(sc);
DC_LOCK_ASSERT(sc);
mii = device_get_softc(sc->dc_miibus);
@ -3488,10 +3499,9 @@ dc_init(void *xsc)
/* Init circular RX list. */
if (dc_list_rx_init(sc) == ENOBUFS) {
printf("dc%d: initialization failed: no "
"memory for rx buffers\n", sc->dc_unit);
if_printf(ifp,
"initialization failed: no memory for rx buffers\n");
dc_stop(sc);
DC_UNLOCK(sc);
return;
}
@ -3563,17 +3573,6 @@ dc_init(void *xsc)
else
callout_reset(&sc->dc_stat_ch, hz, dc_tick, sc);
}
#ifdef SRM_MEDIA
if(sc->dc_srm_media) {
struct ifreq ifr;
ifr.ifr_media = sc->dc_srm_media;
ifmedia_ioctl(ifp, &ifr, &mii->mii_media, SIOCSIFMEDIA);
sc->dc_srm_media = 0;
}
#endif
DC_UNLOCK(sc);
}
/*
@ -3588,6 +3587,7 @@ dc_ifmedia_upd(struct ifnet *ifp)
sc = ifp->if_softc;
mii = device_get_softc(sc->dc_miibus);
DC_LOCK(sc);
mii_mediachg(mii);
ifm = &mii->mii_media;
@ -3596,6 +3596,7 @@ dc_ifmedia_upd(struct ifnet *ifp)
dc_setcfg(sc, ifm->ifm_media);
else
sc->dc_link = 0;
DC_UNLOCK(sc);
return (0);
}
@ -3612,6 +3613,7 @@ dc_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr)
sc = ifp->if_softc;
mii = device_get_softc(sc->dc_miibus);
DC_LOCK(sc);
mii_pollstat(mii);
ifm = &mii->mii_media;
if (DC_IS_DAVICOM(sc)) {
@ -3623,6 +3625,7 @@ dc_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr)
}
ifmr->ifm_active = mii->mii_media_active;
ifmr->ifm_status = mii->mii_media_status;
DC_UNLOCK(sc);
}
static int
@ -3633,10 +3636,9 @@ dc_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
struct mii_data *mii;
int error = 0;
DC_LOCK(sc);
switch (command) {
case SIOCSIFFLAGS:
DC_LOCK(sc);
if (ifp->if_flags & IFF_UP) {
int need_setfilt = (ifp->if_flags ^ sc->dc_if_flags) &
(IFF_PROMISC | IFF_ALLMULTI);
@ -3646,18 +3648,21 @@ dc_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
dc_setfilt(sc);
} else {
sc->dc_txthresh = 0;
dc_init(sc);
dc_init_locked(sc);
}
} else {
if (ifp->if_drv_flags & IFF_DRV_RUNNING)
dc_stop(sc);
}
sc->dc_if_flags = ifp->if_flags;
DC_UNLOCK(sc);
error = 0;
break;
case SIOCADDMULTI:
case SIOCDELMULTI:
DC_LOCK(sc);
dc_setfilt(sc);
DC_UNLOCK(sc);
error = 0;
break;
case SIOCGIFMEDIA:
@ -3665,21 +3670,23 @@ dc_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
mii = device_get_softc(sc->dc_miibus);
error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, command);
#ifdef SRM_MEDIA
DC_LOCK(sc);
if (sc->dc_srm_media)
sc->dc_srm_media = 0;
DC_UNLOCK(sc);
#endif
break;
case SIOCSIFCAP:
DC_LOCK(sc);
ifp->if_capenable &= ~IFCAP_POLLING;
ifp->if_capenable |= ifr->ifr_reqcap & IFCAP_POLLING;
DC_UNLOCK(sc);
break;
default:
error = ether_ioctl(ifp, command, data);
break;
}
DC_UNLOCK(sc);
return (error);
}
@ -3693,14 +3700,14 @@ dc_watchdog(struct ifnet *ifp)
DC_LOCK(sc);
ifp->if_oerrors++;
printf("dc%d: watchdog timeout\n", sc->dc_unit);
if_printf(ifp, "watchdog timeout\n");
dc_stop(sc);
dc_reset(sc);
dc_init(sc);
dc_init_locked(sc);
if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd))
dc_start(ifp);
dc_start_locked(ifp);
DC_UNLOCK(sc);
}
@ -3718,7 +3725,7 @@ dc_stop(struct dc_softc *sc)
int i;
u_int32_t ctl;
DC_LOCK(sc);
DC_LOCK_ASSERT(sc);
ifp = sc->dc_ifp;
ifp->if_timer = 0;
@ -3766,8 +3773,6 @@ dc_stop(struct dc_softc *sc)
}
}
bzero(&ld->dc_tx_list, sizeof(ld->dc_tx_list));
DC_UNLOCK(sc);
}
/*
@ -3779,15 +3784,13 @@ static int
dc_suspend(device_t dev)
{
struct dc_softc *sc;
int s;
s = splimp();
sc = device_get_softc(dev);
DC_LOCK(sc);
dc_stop(sc);
sc->suspended = 1;
DC_UNLOCK(sc);
splx(s);
return (0);
}
@ -3801,20 +3804,18 @@ dc_resume(device_t dev)
{
struct dc_softc *sc;
struct ifnet *ifp;
int s;
s = splimp();
sc = device_get_softc(dev);
ifp = sc->dc_ifp;
/* reinitialize interface if necessary */
DC_LOCK(sc);
if (ifp->if_flags & IFF_UP)
dc_init(sc);
dc_init_locked(sc);
sc->suspended = 0;
DC_UNLOCK(sc);
splx(s);
return (0);
}
@ -3829,5 +3830,7 @@ dc_shutdown(device_t dev)
sc = device_get_softc(dev);
DC_LOCK(sc);
dc_stop(sc);
DC_UNLOCK(sc);
}

View File

@ -732,7 +732,6 @@ struct dc_softc {
struct resource *dc_res;
struct dc_type *dc_info; /* adapter info */
device_t dc_miibus;
u_int8_t dc_unit; /* interface number */
u_int8_t dc_type;
u_int8_t dc_pmode;
u_int8_t dc_link;

View File

@ -137,12 +137,15 @@ static void sf_txeof(struct sf_softc *);
static int sf_encap(struct sf_softc *, struct sf_tx_bufdesc_type0 *,
struct mbuf *);
static void sf_start(struct ifnet *);
static void sf_start_locked(struct ifnet *);
static int sf_ioctl(struct ifnet *, u_long, caddr_t);
static void sf_init(void *);
static void sf_init_locked(struct sf_softc *);
static void sf_stop(struct sf_softc *);
static void sf_watchdog(struct ifnet *);
static void sf_shutdown(device_t);
static int sf_ifmedia_upd(struct ifnet *);
static void sf_ifmedia_upd_locked(struct ifnet *);
static void sf_ifmedia_sts(struct ifnet *, struct ifmediareq *);
static void sf_reset(struct sf_softc *);
static int sf_init_rx_ring(struct sf_softc *);
@ -462,10 +465,25 @@ sf_ifmedia_upd(ifp)
struct ifnet *ifp;
{
struct sf_softc *sc;
sc = ifp->if_softc;
SF_LOCK(sc);
sf_ifmedia_upd_locked(ifp);
SF_UNLOCK(sc);
return(0);
}
static void
sf_ifmedia_upd_locked(ifp)
struct ifnet *ifp;
{
struct sf_softc *sc;
struct mii_data *mii;
sc = ifp->if_softc;
mii = device_get_softc(sc->sf_miibus);
SF_LOCK_ASSERT(sc);
sc->sf_link = 0;
if (mii->mii_instance) {
struct mii_softc *miisc;
@ -473,8 +491,6 @@ sf_ifmedia_upd(ifp)
mii_phy_reset(miisc);
}
mii_mediachg(mii);
return(0);
}
/*
@ -489,11 +505,13 @@ sf_ifmedia_sts(ifp, ifmr)
struct mii_data *mii;
sc = ifp->if_softc;
SF_LOCK(sc);
mii = device_get_softc(sc->sf_miibus);
mii_pollstat(mii);
ifmr->ifm_active = mii->mii_media_active;
ifmr->ifm_status = mii->mii_media_status;
SF_UNLOCK(sc);
}
static int
@ -507,10 +525,9 @@ sf_ioctl(ifp, command, data)
struct mii_data *mii;
int error = 0;
SF_LOCK(sc);
switch(command) {
case SIOCSIFFLAGS:
SF_LOCK(sc);
if (ifp->if_flags & IFF_UP) {
if (ifp->if_drv_flags & IFF_DRV_RUNNING &&
ifp->if_flags & IFF_PROMISC &&
@ -521,17 +538,20 @@ sf_ioctl(ifp, command, data)
sc->sf_if_flags & IFF_PROMISC) {
SF_CLRBIT(sc, SF_RXFILT, SF_RXFILT_PROMISC);
} else if (!(ifp->if_drv_flags & IFF_DRV_RUNNING))
sf_init(sc);
sf_init_locked(sc);
} else {
if (ifp->if_drv_flags & IFF_DRV_RUNNING)
sf_stop(sc);
}
sc->sf_if_flags = ifp->if_flags;
SF_UNLOCK(sc);
error = 0;
break;
case SIOCADDMULTI:
case SIOCDELMULTI:
SF_LOCK(sc);
sf_setmulti(sc);
SF_UNLOCK(sc);
error = 0;
break;
case SIOCGIFMEDIA:
@ -540,16 +560,16 @@ sf_ioctl(ifp, command, data)
error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, command);
break;
case SIOCSIFCAP:
SF_LOCK(sc);
ifp->if_capenable &= ~IFCAP_POLLING;
ifp->if_capenable |= ifr->ifr_reqcap & IFCAP_POLLING;
SF_UNLOCK(sc);
break;
default:
error = ether_ioctl(ifp, command, data);
break;
}
SF_UNLOCK(sc);
return(error);
}
@ -573,7 +593,7 @@ sf_reset(sc)
}
if (i == SF_TIMEOUT)
printf("sf%d: reset never completed!\n", sc->sf_unit);
if_printf(sc->sf_ifp, "reset never completed!\n");
/* Wait a little while for the chip to get its brains in order. */
DELAY(1000);
@ -643,14 +663,13 @@ sf_attach(dev)
int i;
struct sf_softc *sc;
struct ifnet *ifp;
int unit, rid, error = 0;
int rid, error = 0;
u_char eaddr[6];
sc = device_get_softc(dev);
unit = device_get_unit(dev);
mtx_init(&sc->sf_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK,
MTX_DEF | MTX_RECURSE);
MTX_DEF);
/*
* Map control/status registers.
*/
@ -660,7 +679,7 @@ sf_attach(dev)
sc->sf_res = bus_alloc_resource_any(dev, SF_RES, &rid, RF_ACTIVE);
if (sc->sf_res == NULL) {
printf ("sf%d: couldn't map ports\n", unit);
device_printf(dev, "couldn't map ports\n");
error = ENXIO;
goto fail;
}
@ -674,12 +693,13 @@ sf_attach(dev)
RF_SHAREABLE | RF_ACTIVE);
if (sc->sf_irq == NULL) {
printf("sf%d: couldn't map interrupt\n", unit);
device_printf(dev, "couldn't map interrupt\n");
error = ENXIO;
goto fail;
}
callout_handle_init(&sc->sf_stat_ch);
callout_init_mtx(&sc->sf_stat_callout, &sc->sf_mtx, 0);
/* Reset the adapter. */
sf_reset(sc);
@ -690,14 +710,12 @@ sf_attach(dev)
eaddr[i] =
sf_read_eeprom(sc, SF_EE_NODEADDR + ETHER_ADDR_LEN - i);
sc->sf_unit = unit;
/* Allocate the descriptor queues. */
sc->sf_ldata = contigmalloc(sizeof(struct sf_list_data), M_DEVBUF,
M_NOWAIT, 0, 0xffffffff, PAGE_SIZE, 0);
if (sc->sf_ldata == NULL) {
printf("sf%d: no memory for list buffers!\n", unit);
device_printf(dev, "no memory for list buffers!\n");
error = ENXIO;
goto fail;
}
@ -706,7 +724,7 @@ sf_attach(dev)
ifp = sc->sf_ifp = if_alloc(IFT_ETHER);
if (ifp == NULL) {
printf("sf%d: can not if_alloc()\n", sc->sf_unit);
device_printf(dev, "can not if_alloc()\n");
error = ENOSPC;
goto fail;
}
@ -714,7 +732,7 @@ sf_attach(dev)
/* Do MII setup. */
if (mii_phy_probe(dev, &sc->sf_miibus,
sf_ifmedia_upd, sf_ifmedia_sts)) {
printf("sf%d: MII without any phy!\n", sc->sf_unit);
device_printf(dev, "MII without any phy!\n");
error = ENXIO;
goto fail;
}
@ -722,8 +740,7 @@ sf_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 = sf_ioctl;
ifp->if_start = sf_start;
ifp->if_watchdog = sf_watchdog;
@ -743,11 +760,11 @@ sf_attach(dev)
ether_ifattach(ifp, eaddr);
/* Hook interrupt last to avoid having to lock softc */
error = bus_setup_intr(dev, sc->sf_irq, INTR_TYPE_NET,
error = bus_setup_intr(dev, sc->sf_irq, INTR_TYPE_NET | INTR_MPSAFE,
sf_intr, sc, &sc->sf_intrhand);
if (error) {
printf("sf%d: couldn't set up irq\n", unit);
device_printf(dev, "couldn't set up irq\n");
ether_ifdetach(ifp);
if_free(ifp);
goto fail;
@ -776,12 +793,14 @@ sf_detach(dev)
sc = device_get_softc(dev);
KASSERT(mtx_initialized(&sc->sf_mtx), ("sf mutex not initialized"));
SF_LOCK(sc);
ifp = sc->sf_ifp;
/* These should only be active if attach succeeded */
if (device_is_attached(dev)) {
SF_LOCK(sc);
sf_stop(sc);
SF_UNLOCK(sc);
callout_drain(&sc->sf_stat_callout);
ether_ifdetach(ifp);
if_free(ifp);
}
@ -799,7 +818,6 @@ sf_detach(dev)
if (sc->sf_ldata)
contigfree(sc->sf_ldata, sizeof(struct sf_list_data), M_DEVBUF);
SF_UNLOCK(sc);
mtx_destroy(&sc->sf_mtx);
return(0);
@ -987,6 +1005,7 @@ sf_txeof(sc)
ifp = sc->sf_ifp;
SF_LOCK_ASSERT(sc);
txcons = csr_read_4(sc, SF_CQ_CONSIDX);
cmpprodidx = SF_IDX_HI(csr_read_4(sc, SF_CQ_PRODIDX));
cmpconsidx = SF_IDX_HI(txcons);
@ -1034,9 +1053,9 @@ sf_txthresh_adjust(sc)
txfctl &= ~SF_TXFRMCTL_TXTHRESH;
txfctl |= txthresh;
#ifdef DIAGNOSTIC
printf("sf%d: tx underrun, increasing "
if_printf(sc->sf_ifp, "tx underrun, increasing "
"tx threshold to %d bytes\n",
sc->sf_unit, txthresh * 4);
txthresh * 4);
#endif
csr_write_4(sc, SF_TX_FRAMCTL, txfctl);
}
@ -1075,7 +1094,7 @@ sf_poll_locked(struct ifnet *ifp, enum poll_cmd cmd, int count)
sf_rxeof(sc);
sf_txeof(sc);
if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd))
sf_start(ifp);
sf_start_locked(ifp);
if (cmd == POLL_AND_CHECK_STATUS) {
u_int32_t status;
@ -1089,11 +1108,10 @@ sf_poll_locked(struct ifnet *ifp, enum poll_cmd cmd, int count)
if (status & SF_ISR_ABNORMALINTR) {
if (status & SF_ISR_STATSOFLOW) {
untimeout(sf_stats_update, sc,
sc->sf_stat_ch);
callout_stop(&sc->sf_stat_callout);
sf_stats_update(sc);
} else
sf_init(sc);
sf_init_locked(sc);
}
}
}
@ -1154,11 +1172,10 @@ sf_intr(arg)
if (status & SF_ISR_ABNORMALINTR) {
if (status & SF_ISR_STATSOFLOW) {
untimeout(sf_stats_update, sc,
sc->sf_stat_ch);
callout_stop(&sc->sf_stat_callout);
sf_stats_update(sc);
} else
sf_init(sc);
sf_init_locked(sc);
}
}
@ -1166,7 +1183,7 @@ sf_intr(arg)
csr_write_4(sc, SF_IMR, SF_INTRS);
if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd))
sf_start(ifp);
sf_start_locked(ifp);
#ifdef DEVICE_POLLING
done_locked:
@ -1179,12 +1196,22 @@ sf_init(xsc)
void *xsc;
{
struct sf_softc *sc;
sc = xsc;
SF_LOCK(sc);
sf_init_locked(sc);
SF_UNLOCK(sc);
}
static void
sf_init_locked(sc)
struct sf_softc *sc;
{
struct ifnet *ifp;
struct mii_data *mii;
int i;
sc = xsc;
SF_LOCK(sc);
SF_LOCK_ASSERT(sc);
ifp = sc->sf_ifp;
mii = device_get_softc(sc->sf_miibus);
@ -1207,9 +1234,8 @@ sf_init(xsc)
sf_setperf(sc, 0, (caddr_t)&IFP2ENADDR(sc->sf_ifp));
if (sf_init_rx_ring(sc) == ENOBUFS) {
printf("sf%d: initialization failed: no "
"memory for rx buffers\n", sc->sf_unit);
SF_UNLOCK(sc);
if_printf(sc->sf_ifp,
"initialization failed: no memory for rx buffers\n");
return;
}
@ -1284,14 +1310,12 @@ sf_init(xsc)
SF_SETBIT(sc, SF_GEN_ETH_CTL, SF_ETHCTL_TX_ENB|SF_ETHCTL_TXDMA_ENB);
/*mii_mediachg(mii);*/
sf_ifmedia_upd(ifp);
sf_ifmedia_upd_locked(ifp);
ifp->if_drv_flags |= IFF_DRV_RUNNING;
ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
sc->sf_stat_ch = timeout(sf_stats_update, sc, hz);
SF_UNLOCK(sc);
callout_reset(&sc->sf_stat_callout, hz, sf_stats_update, sc);
}
static int
@ -1324,7 +1348,7 @@ sf_encap(sc, c, m_head)
MGETHDR(m_new, M_DONTWAIT, MT_DATA);
if (m_new == NULL) {
printf("sf%d: no memory for tx list\n", sc->sf_unit);
if_printf(sc->sf_ifp, "no memory for tx list\n");
return(1);
}
@ -1332,8 +1356,7 @@ sf_encap(sc, c, m_head)
MCLGET(m_new, M_DONTWAIT);
if (!(m_new->m_flags & M_EXT)) {
m_freem(m_new);
printf("sf%d: no memory for tx list\n",
sc->sf_unit);
if_printf(sc->sf_ifp, "no memory for tx list\n");
return(1);
}
}
@ -1363,29 +1386,37 @@ sf_start(ifp)
struct ifnet *ifp;
{
struct sf_softc *sc;
sc = ifp->if_softc;
SF_LOCK(sc);
sf_start_locked(ifp);
SF_UNLOCK(sc);
}
static void
sf_start_locked(ifp)
struct ifnet *ifp;
{
struct sf_softc *sc;
struct sf_tx_bufdesc_type0 *cur_tx = NULL;
struct mbuf *m_head = NULL;
int i, txprod;
sc = ifp->if_softc;
SF_LOCK(sc);
SF_LOCK_ASSERT(sc);
if (!sc->sf_link && ifp->if_snd.ifq_len < 10) {
SF_UNLOCK(sc);
if (!sc->sf_link && ifp->if_snd.ifq_len < 10)
return;
}
if (ifp->if_drv_flags & IFF_DRV_OACTIVE) {
SF_UNLOCK(sc);
if (ifp->if_drv_flags & IFF_DRV_OACTIVE)
return;
}
txprod = csr_read_4(sc, SF_TXDQ_PRODIDX);
i = SF_IDX_HI(txprod) >> 4;
if (sc->sf_ldata->sf_tx_dlist[i].sf_mbuf != NULL) {
printf("sf%d: TX ring full, resetting\n", sc->sf_unit);
sf_init(sc);
if_printf(ifp, "TX ring full, resetting\n");
sf_init_locked(sc);
txprod = csr_read_4(sc, SF_TXDQ_PRODIDX);
i = SF_IDX_HI(txprod) >> 4;
}
@ -1423,10 +1454,8 @@ sf_start(ifp)
break;
}
if (cur_tx == NULL) {
SF_UNLOCK(sc);
if (cur_tx == NULL)
return;
}
/* Transmit */
csr_write_4(sc, SF_TXDQ_PRODIDX,
@ -1434,8 +1463,6 @@ sf_start(ifp)
((i << 20) & 0xFFFF0000));
ifp->if_timer = 5;
SF_UNLOCK(sc);
}
static void
@ -1445,11 +1472,11 @@ sf_stop(sc)
int i;
struct ifnet *ifp;
SF_LOCK(sc);
SF_LOCK_ASSERT(sc);
ifp = sc->sf_ifp;
untimeout(sf_stats_update, sc, sc->sf_stat_ch);
callout_stop(&sc->sf_stat_callout);
#ifdef DEVICE_POLLING
ether_poll_deregister(ifp);
@ -1483,7 +1510,6 @@ sf_stop(sc)
}
ifp->if_drv_flags &= ~(IFF_DRV_RUNNING|IFF_DRV_OACTIVE);
SF_UNLOCK(sc);
}
/*
@ -1505,7 +1531,7 @@ sf_stats_update(xsc)
int i;
sc = xsc;
SF_LOCK(sc);
SF_LOCK_ASSERT(sc);
ifp = sc->sf_ifp;
mii = device_get_softc(sc->sf_miibus);
@ -1527,12 +1553,10 @@ sf_stats_update(xsc)
IFM_SUBTYPE(mii->mii_media_active) != IFM_NONE) {
sc->sf_link++;
if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd))
sf_start(ifp);
sf_start_locked(ifp);
}
sc->sf_stat_ch = timeout(sf_stats_update, sc, hz);
SF_UNLOCK(sc);
callout_reset(&sc->sf_stat_callout, hz, sf_stats_update, sc);
}
static void
@ -1546,14 +1570,14 @@ sf_watchdog(ifp)
SF_LOCK(sc);
ifp->if_oerrors++;
printf("sf%d: watchdog timeout\n", sc->sf_unit);
if_printf(ifp, "watchdog timeout\n");
sf_stop(sc);
sf_reset(sc);
sf_init(sc);
sf_init_locked(sc);
if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd))
sf_start(ifp);
sf_start_locked(ifp);
SF_UNLOCK(sc);
}
@ -1566,5 +1590,7 @@ sf_shutdown(dev)
sc = device_get_softc(dev);
SF_LOCK(sc);
sf_stop(sc);
SF_UNLOCK(sc);
}

View File

@ -1039,12 +1039,11 @@ struct sf_softc {
struct resource *sf_res; /* mem/ioport resource */
struct sf_type *sf_info; /* Starfire adapter info */
device_t sf_miibus;
u_int8_t sf_unit; /* interface number */
struct sf_list_data *sf_ldata;
int sf_tx_cnt;
u_int8_t sf_link;
int sf_if_flags;
struct callout_handle sf_stat_ch;
struct callout sf_stat_callout;
struct mtx sf_mtx;
#ifdef DEVICE_POLLING
int rxcycles;