Minor tweaks and fixups:

- Use device_printf() and if_printf() and remove nge_unit.
- Use callout_init_mtx() and remove nge_tick_locked() as nge_tick() is now
  always called with the driver lock held.
- Use M_ZERO to contigmalloc() when allocating nge_ldata.  It was possible
  for the random garbage to be used in certain cases otherwise.
- Cleanup attach error handling including no longer leaking nge_ldata.
- Add locking to the ifmedia callouts.
- Lock accesses to if_hwassist and if_capenable in nge_ioctl().

Submitted by:	Yuriy N. Shkandybin jura at networks dot ru (1, 3, 4)
Tested by:	Yuriy N. Shkandybin jura at networks dot ru
MFC after:	3 days
This commit is contained in:
John Baldwin 2005-10-13 20:22:07 +00:00
parent 3a22b03d6c
commit 646abee6e3
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=151296
2 changed files with 61 additions and 69 deletions

View File

@ -160,7 +160,6 @@ static void nge_rxeof(struct nge_softc *);
static void nge_txeof(struct nge_softc *);
static void nge_intr(void *);
static void nge_tick(void *);
static void nge_tick_locked(struct nge_softc *);
static void nge_start(struct ifnet *);
static void nge_start_locked(struct ifnet *);
static int nge_ioctl(struct ifnet *, u_long, caddr_t);
@ -170,6 +169,7 @@ static void nge_stop(struct nge_softc *);
static void nge_watchdog(struct ifnet *);
static void nge_shutdown(device_t);
static int nge_ifmedia_upd(struct ifnet *);
static void nge_ifmedia_upd_locked(struct ifnet *);
static void nge_ifmedia_sts(struct ifnet *, struct ifmediareq *);
static void nge_delay(struct nge_softc *);
@ -742,7 +742,7 @@ nge_reset(sc)
}
if (i == NGE_TIMEOUT)
printf("nge%d: reset never completed\n", sc->nge_unit);
if_printf(sc->nge_ifp, "reset never completed\n");
/* Wait a little while for the chip to get its brains in order. */
DELAY(1000);
@ -791,15 +791,14 @@ nge_attach(dev)
{
u_char eaddr[ETHER_ADDR_LEN];
struct nge_softc *sc;
struct ifnet *ifp;
int unit, error = 0, rid;
const char *sep = "";
struct ifnet *ifp = NULL;
int error = 0, rid;
sc = device_get_softc(dev);
unit = device_get_unit(dev);
bzero(sc, sizeof(struct nge_softc));
NGE_LOCK_INIT(sc, device_get_nameunit(dev));
callout_init_mtx(&sc->nge_stat_ch, &sc->nge_mtx, 0);
/*
* Map control/status registers.
*/
@ -809,7 +808,7 @@ nge_attach(dev)
sc->nge_res = bus_alloc_resource_any(dev, NGE_RES, &rid, RF_ACTIVE);
if (sc->nge_res == NULL) {
printf("nge%d: couldn't map ports/memory\n", unit);
device_printf(dev, "couldn't map ports/memory\n");
error = ENXIO;
goto fail;
}
@ -823,8 +822,7 @@ nge_attach(dev)
RF_SHAREABLE | RF_ACTIVE);
if (sc->nge_irq == NULL) {
printf("nge%d: couldn't map interrupt\n", unit);
bus_release_resource(dev, NGE_RES, NGE_RID, sc->nge_res);
device_printf(dev, "couldn't map interrupt\n");
error = ENXIO;
goto fail;
}
@ -839,25 +837,18 @@ nge_attach(dev)
nge_read_eeprom(sc, (caddr_t)&eaddr[2], NGE_EE_NODEADDR + 1, 1, 0);
nge_read_eeprom(sc, (caddr_t)&eaddr[0], NGE_EE_NODEADDR + 2, 1, 0);
sc->nge_unit = unit;
/* XXX: leaked on error */
sc->nge_ldata = contigmalloc(sizeof(struct nge_list_data), M_DEVBUF,
M_NOWAIT, 0, 0xffffffff, PAGE_SIZE, 0);
M_NOWAIT|M_ZERO, 0, 0xffffffff, PAGE_SIZE, 0);
if (sc->nge_ldata == NULL) {
printf("nge%d: no memory for list buffers!\n", unit);
bus_release_resource(dev, SYS_RES_IRQ, 0, sc->nge_irq);
bus_release_resource(dev, NGE_RES, NGE_RID, sc->nge_res);
device_printf(dev, "no memory for list buffers!\n");
error = ENXIO;
goto fail;
}
ifp = sc->nge_ifp = if_alloc(IFT_ETHER);
if (ifp == NULL) {
printf("nge%d: can not if_alloc()\n", unit);
bus_release_resource(dev, SYS_RES_IRQ, 0, sc->nge_irq);
bus_release_resource(dev, NGE_RES, NGE_RID, sc->nge_res);
device_printf(dev, "can not if_alloc()\n");
error = ENOSPC;
goto fail;
}
@ -893,19 +884,13 @@ nge_attach(dev)
ifmedia_init(&sc->nge_ifmedia, 0, nge_ifmedia_upd,
nge_ifmedia_sts);
#define ADD(m, c) ifmedia_add(&sc->nge_ifmedia, (m), (c), NULL)
#define PRINT(s) printf("%s%s", sep, s); sep = ", "
ADD(IFM_MAKEWORD(IFM_ETHER, IFM_NONE, 0, 0), 0);
device_printf(dev, " ");
ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_SX, 0, 0), 0);
PRINT("1000baseSX");
ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_SX, IFM_FDX, 0),0);
PRINT("1000baseSX-FDX");
ADD(IFM_MAKEWORD(IFM_ETHER, IFM_AUTO, 0, 0), 0);
PRINT("auto");
printf("\n");
#undef ADD
#undef PRINT
device_printf(dev, " 1000baseSX, 1000baseSX-FDX, auto\n");
ifmedia_set(&sc->nge_ifmedia,
IFM_MAKEWORD(IFM_ETHER, IFM_AUTO, 0, 0));
@ -916,11 +901,7 @@ nge_attach(dev)
| NGE_GPIO_GP3_IN | NGE_GPIO_GP4_IN);
} else {
printf("nge%d: MII without any PHY!\n", sc->nge_unit);
if_free(ifp);
bus_release_resource(dev, SYS_RES_IRQ, 0, sc->nge_irq);
bus_release_resource(dev, NGE_RES, NGE_RID,
sc->nge_res);
device_printf(dev, "MII without any PHY!\n");
error = ENXIO;
goto fail;
}
@ -930,7 +911,6 @@ nge_attach(dev)
* Call MI attach routine.
*/
ether_ifattach(ifp, eaddr);
callout_init(&sc->nge_stat_ch, CALLOUT_MPSAFE);
/*
* Hookup IRQ last.
@ -938,17 +918,23 @@ nge_attach(dev)
error = bus_setup_intr(dev, sc->nge_irq, INTR_TYPE_NET | INTR_MPSAFE,
nge_intr, sc, &sc->nge_intrhand);
if (error) {
/* XXX: resource leaks */
if_free(ifp);
bus_release_resource(dev, SYS_RES_IRQ, 0, sc->nge_irq);
bus_release_resource(dev, NGE_RES, NGE_RID, sc->nge_res);
printf("nge%d: couldn't set up irq\n", unit);
device_printf(dev, "couldn't set up irq\n");
goto fail;
}
fail:
return (0);
if (error)
NGE_LOCK_DESTROY(sc);
fail:
if (sc->nge_ldata)
contigfree(sc->nge_ldata,
sizeof(struct nge_list_data), M_DEVBUF);
if (ifp)
if_free(ifp);
if (sc->nge_irq)
bus_release_resource(dev, SYS_RES_IRQ, 0, sc->nge_irq);
if (sc->nge_res)
bus_release_resource(dev, NGE_RES, NGE_RID, sc->nge_res);
NGE_LOCK_DESTROY(sc);
return(error);
}
@ -970,6 +956,7 @@ nge_detach(dev)
nge_reset(sc);
nge_stop(sc);
NGE_UNLOCK(sc);
callout_drain(&sc->nge_stat_ch);
ether_ifdetach(ifp);
bus_generic_detach(dev);
@ -1322,21 +1309,10 @@ nge_tick(xsc)
void *xsc;
{
struct nge_softc *sc;
sc = xsc;
NGE_LOCK(sc);
nge_tick_locked(sc);
NGE_UNLOCK(sc);
}
static void
nge_tick_locked(sc)
struct nge_softc *sc;
{
struct mii_data *mii;
struct ifnet *ifp;
sc = xsc;
NGE_LOCK_ASSERT(sc);
ifp = sc->nge_ifp;
@ -1345,8 +1321,8 @@ nge_tick_locked(sc)
if (CSR_READ_4(sc, NGE_TBI_BMSR)
& NGE_TBIBMSR_ANEG_DONE) {
if (bootverbose)
printf("nge%d: gigabit link up\n",
sc->nge_unit);
if_printf(sc->nge_ifp,
"gigabit link up\n");
nge_miibus_statchg(sc->nge_miibus);
sc->nge_link++;
if (ifp->if_snd.ifq_head != NULL)
@ -1363,8 +1339,8 @@ nge_tick_locked(sc)
sc->nge_link++;
if (IFM_SUBTYPE(mii->mii_media_active)
== IFM_1000_T && bootverbose)
printf("nge%d: gigabit link up\n",
sc->nge_unit);
if_printf(sc->nge_ifp,
"gigabit link up\n");
if (ifp->if_snd.ifq_head != NULL)
nge_start_locked(ifp);
}
@ -1495,7 +1471,7 @@ nge_intr(arg)
*/
if (status & NGE_IMR_PHY_INTR) {
sc->nge_link = 0;
nge_tick_locked(sc);
nge_tick(sc);
}
#endif
}
@ -1702,8 +1678,8 @@ nge_init_locked(sc)
/* Init circular RX list. */
if (nge_list_rx_init(sc) == ENOBUFS) {
printf("nge%d: initialization failed: no "
"memory for rx buffers\n", sc->nge_unit);
if_printf(sc->nge_ifp, "initialization failed: no "
"memory for rx buffers\n");
nge_stop(sc);
return;
}
@ -1808,7 +1784,7 @@ nge_init_locked(sc)
}
}
nge_tick_locked(sc);
nge_tick(sc);
/*
* Enable the delivery of PHY interrupts based on
@ -1846,7 +1822,7 @@ nge_init_locked(sc)
NGE_CLRBIT(sc, NGE_CSR, NGE_CSR_TX_DISABLE|NGE_CSR_RX_DISABLE);
NGE_SETBIT(sc, NGE_CSR, NGE_CSR_RX_ENABLE);
nge_ifmedia_upd(ifp);
nge_ifmedia_upd_locked(ifp);
ifp->if_drv_flags |= IFF_DRV_RUNNING;
ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
@ -1862,9 +1838,23 @@ nge_ifmedia_upd(ifp)
struct ifnet *ifp;
{
struct nge_softc *sc;
sc = ifp->if_softc;
NGE_LOCK(sc);
nge_ifmedia_upd_locked(ifp);
NGE_UNLOCK(sc);
return (0);
}
static void
nge_ifmedia_upd_locked(ifp)
struct ifnet *ifp;
{
struct nge_softc *sc;
struct mii_data *mii;
sc = ifp->if_softc;
NGE_LOCK_ASSERT(sc);
if (sc->nge_tbi) {
if (IFM_SUBTYPE(sc->nge_ifmedia.ifm_cur->ifm_media)
@ -1900,14 +1890,12 @@ nge_ifmedia_upd(ifp)
sc->nge_link = 0;
if (mii->mii_instance) {
struct mii_softc *miisc;
for (miisc = LIST_FIRST(&mii->mii_phys); miisc != NULL;
miisc = LIST_NEXT(miisc, mii_list))
LIST_FOREACH(miisc, &mii->mii_phys, mii_list)
mii_phy_reset(miisc);
}
mii_mediachg(mii);
}
return(0);
}
/*
@ -1923,6 +1911,7 @@ nge_ifmedia_sts(ifp, ifmr)
sc = ifp->if_softc;
NGE_LOCK(sc);
if (sc->nge_tbi) {
ifmr->ifm_status = IFM_AVALID;
ifmr->ifm_active = IFM_ETHER;
@ -1935,6 +1924,7 @@ nge_ifmedia_sts(ifp, ifmr)
if (!CSR_READ_4(sc, NGE_TBI_BMSR) & NGE_TBIBMSR_ANEG_DONE) {
ifmr->ifm_active |= IFM_NONE;
ifmr->ifm_status = 0;
NGE_UNLOCK(sc);
return;
}
ifmr->ifm_active |= IFM_1000_SX;
@ -1960,6 +1950,7 @@ nge_ifmedia_sts(ifp, ifmr)
ifmr->ifm_active = mii->mii_media_active;
ifmr->ifm_status = mii->mii_media_status;
}
NGE_UNLOCK(sc);
return;
}
@ -1980,6 +1971,7 @@ nge_ioctl(ifp, command, data)
if (ifr->ifr_mtu > NGE_JUMBO_MTU)
error = EINVAL;
else {
NGE_LOCK(sc);
ifp->if_mtu = ifr->ifr_mtu;
/*
* Workaround: if the MTU is larger than
@ -1993,6 +1985,7 @@ nge_ioctl(ifp, command, data)
ifp->if_capenable |= IFCAP_TXCSUM;
ifp->if_hwassist = NGE_CSUM_FEATURES;
}
NGE_UNLOCK(sc);
}
break;
case SIOCSIFFLAGS:
@ -2086,7 +2079,7 @@ nge_watchdog(ifp)
sc = ifp->if_softc;
ifp->if_oerrors++;
printf("nge%d: watchdog timeout\n", sc->nge_unit);
if_printf(sc->nge_ifp, "watchdog timeout\n");
NGE_LOCK(sc);
nge_stop(sc);

View File

@ -656,7 +656,6 @@ struct nge_softc {
void *nge_intrhand;
device_t nge_miibus;
int nge_if_flags;
u_int8_t nge_unit;
u_int8_t nge_type;
u_int8_t nge_link;
u_int8_t nge_width;