--- if_vge.c.orig 2007-12-08 10:25:45.000000000 +0900 +++ if_vge.c 2008-04-03 13:38:06.000000000 +0900 @@ -164,8 +164,9 @@ static void vge_start (struct ifnet *); static int vge_ioctl (struct ifnet *, u_long, caddr_t); static void vge_init (void *); +static void vge_init_locked (struct vge_softc *); static void vge_stop (struct vge_softc *); -static void vge_watchdog (struct ifnet *); +static void vge_watchdog (struct vge_softc *); static int vge_suspend (device_t); static int vge_resume (device_t); static int vge_shutdown (device_t); @@ -177,7 +178,9 @@ #endif static void vge_read_eeprom (struct vge_softc *, caddr_t, int, int, int); +#if 0 static void vge_miipoll_start (struct vge_softc *); +#endif static void vge_miipoll_stop (struct vge_softc *); static int vge_miibus_readreg (device_t, int, int); static int vge_miibus_writereg (device_t, int, int, int); @@ -207,6 +210,7 @@ /* MII interface */ DEVMETHOD(miibus_readreg, vge_miibus_readreg), DEVMETHOD(miibus_writereg, vge_miibus_writereg), + DEVMETHOD(miibus_linkchg, vge_miibus_statchg), DEVMETHOD(miibus_statchg, vge_miibus_statchg), { 0, 0 } @@ -325,6 +329,7 @@ return; } +#if 0 static void vge_miipoll_start(sc) struct vge_softc *sc; @@ -364,6 +369,7 @@ return; } +#endif static int vge_miibus_readreg(dev, phy, reg) @@ -376,11 +382,12 @@ sc = device_get_softc(dev); - if (phy != (CSR_READ_1(sc, VGE_MIICFG) & 0x1F)) + if (phy != sc->vge_phyaddr) return(0); - VGE_LOCK(sc); +#if 0 vge_miipoll_stop(sc); +#endif /* Specify the register we want to read. */ CSR_WRITE_1(sc, VGE_MIIADDR, reg); @@ -400,8 +407,9 @@ else rval = CSR_READ_2(sc, VGE_MIIDATA); +#if 0 vge_miipoll_start(sc); - VGE_UNLOCK(sc); +#endif return (rval); } @@ -416,11 +424,12 @@ sc = device_get_softc(dev); - if (phy != (CSR_READ_1(sc, VGE_MIICFG) & 0x1F)) + if (phy != sc->vge_phyaddr) return(0); - VGE_LOCK(sc); +#if 0 vge_miipoll_stop(sc); +#endif /* Specify the register we want to write. */ CSR_WRITE_1(sc, VGE_MIIADDR, reg); @@ -443,8 +452,9 @@ rval = EIO; } +#if 0 vge_miipoll_start(sc); - VGE_UNLOCK(sc); +#endif return (rval); } @@ -455,6 +465,8 @@ { int i; + VGE_LOCK_ASSERT(sc); + /* * Turn off all the mask bits. This tells the chip * that none of the entries in the CAM filter are valid. @@ -489,6 +501,8 @@ { int i, error = 0; + VGE_LOCK_ASSERT(sc); + if (sc->vge_camidx == VGE_CAM_MAXADDRS) return(ENOSPC); @@ -552,6 +566,8 @@ struct ifmultiaddr *ifma; u_int32_t h, hashes[2] = { 0, 0 }; + VGE_LOCK_ASSERT(sc); + ifp = sc->vge_ifp; /* First, zot all the multicast entries. */ @@ -932,7 +948,8 @@ sc->vge_dev = dev; mtx_init(&sc->vge_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK, - MTX_DEF | MTX_RECURSE); + MTX_DEF); + callout_init_mtx(&sc->vge_callout, &sc->vge_mtx, 0); /* * Map control/status registers. */ @@ -972,6 +989,10 @@ sc->vge_unit = unit; + /* Save PHY address. */ + sc->vge_phyaddr = CSR_READ_1(sc, VGE_MIICFG) & VGE_MIICFG_PHYADDR; + /* Stop MII Auto-poll. */ + vge_miipoll_stop(sc); /* * Allocate the parent bus DMA tag appropriate for PCI. */ @@ -1022,7 +1043,6 @@ #ifdef DEVICE_POLLING ifp->if_capabilities |= IFCAP_POLLING; #endif - ifp->if_watchdog = vge_watchdog; ifp->if_init = vge_init; IFQ_SET_MAXLEN(&ifp->if_snd, VGE_IFQ_MAXLEN); ifp->if_snd.ifq_drv_maxlen = VGE_IFQ_MAXLEN; @@ -1078,6 +1098,7 @@ /* These should only be active if attach succeeded */ if (device_is_attached(dev)) { + VGE_LOCK(sc); vge_stop(sc); /* * Force off the IFF_UP flag here, in case someone @@ -1092,6 +1113,8 @@ * anymore. */ ifp->if_flags &= ~IFF_UP; + VGE_UNLOCK(sc); + callout_drain(&sc->vge_callout); ether_ifdetach(ifp); } if (sc->vge_miibus) @@ -1231,6 +1254,8 @@ vge_tx_list_init(sc) struct vge_softc *sc; { + VGE_LOCK_ASSERT(sc); + bzero ((char *)sc->vge_ldata.vge_tx_list, VGE_TX_LIST_SZ); bzero ((char *)&sc->vge_ldata.vge_tx_mbuf, (VGE_TX_DESC_CNT * sizeof(struct mbuf *))); @@ -1250,6 +1275,8 @@ { int i; + VGE_LOCK_ASSERT(sc); + bzero ((char *)sc->vge_ldata.vge_rx_list, VGE_RX_LIST_SZ); bzero ((char *)&sc->vge_ldata.vge_rx_mbuf, (VGE_RX_DESC_CNT * sizeof(struct mbuf *))); @@ -1496,6 +1523,8 @@ u_int32_t txstat; int idx; + VGE_LOCK_ASSERT(sc); + ifp = sc->vge_ifp; idx = sc->vge_ldata.vge_tx_considx; @@ -1531,7 +1560,7 @@ if (idx != sc->vge_ldata.vge_tx_considx) { sc->vge_ldata.vge_tx_considx = idx; ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; - ifp->if_timer = 0; + sc->vge_watchdog_timer = 0; } /* @@ -1556,32 +1585,13 @@ struct mii_data *mii; sc = xsc; + VGE_LOCK_ASSERT(sc); ifp = sc->vge_ifp; - VGE_LOCK(sc); mii = device_get_softc(sc->vge_miibus); mii_tick(mii); - if (sc->vge_link) { - if (!(mii->mii_media_status & IFM_ACTIVE)) { - sc->vge_link = 0; - if_link_state_change(sc->vge_ifp, - LINK_STATE_DOWN); - } - } else { - if (mii->mii_media_status & IFM_ACTIVE && - IFM_SUBTYPE(mii->mii_media_active) != IFM_NONE) { - sc->vge_link = 1; - if_link_state_change(sc->vge_ifp, - LINK_STATE_UP); - if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) - taskqueue_enqueue(taskqueue_swi, - &sc->vge_txtask); - } - } - - VGE_UNLOCK(sc); - - return; + vge_watchdog(sc); + callout_reset(&sc->vge_callout, hz, vge_tick, sc); } #ifdef DEVICE_POLLING @@ -1615,7 +1625,7 @@ if (status & VGE_ISR_TXDMA_STALL || status & VGE_ISR_RXDMA_STALL) - vge_init(sc); + vge_init_locked(sc); if (status & (VGE_ISR_RXOFLOW|VGE_ISR_RXNODESC)) { vge_rxeof(sc); @@ -1687,10 +1697,7 @@ vge_txeof(sc); if (status & (VGE_ISR_TXDMA_STALL|VGE_ISR_RXDMA_STALL)) - vge_init(sc); - - if (status & VGE_ISR_LINKSTS) - vge_tick(sc); + vge_init_locked(sc); } /* Re-enable interrupts */ @@ -1715,6 +1722,8 @@ bus_dmamap_t map; int error; + VGE_LOCK_ASSERT(sc); + if (sc->vge_ldata.vge_tx_free <= 2) return (EFBIG); @@ -1877,26 +1886,38 @@ */ CSR_WRITE_1(sc, VGE_CRS1, VGE_CR1_TIMER0_ENABLE); - VGE_UNLOCK(sc); - /* * Set a timeout in case the chip goes out to lunch. */ - ifp->if_timer = 5; + sc->vge_watchdog_timer = 5; + + VGE_UNLOCK(sc); return; } + static void vge_init(xsc) void *xsc; { - struct vge_softc *sc = xsc; + struct vge_softc *sc; + + sc = xsc; + VGE_LOCK(sc); + vge_init_locked(sc); + VGE_UNLOCK(sc); +} + +static void +vge_init_locked(sc) + struct vge_softc *sc; +{ struct ifnet *ifp = sc->vge_ifp; struct mii_data *mii; int i; - VGE_LOCK(sc); + VGE_LOCK_ASSERT(sc); mii = device_get_softc(sc->vge_miibus); /* @@ -2056,7 +2077,7 @@ sc->vge_if_flags = 0; sc->vge_link = 0; - VGE_UNLOCK(sc); + callout_reset(&sc->vge_callout, hz, vge_tick, sc); return; } @@ -2070,14 +2091,41 @@ { struct vge_softc *sc; struct mii_data *mii; + struct ifmedia_entry *ife; + int error; sc = ifp->if_softc; VGE_LOCK(sc); mii = device_get_softc(sc->vge_miibus); - mii_mediachg(mii); + + ife = mii->mii_media.ifm_cur; + switch (IFM_SUBTYPE(ife->ifm_media)) { + case IFM_AUTO: + CSR_CLRBIT_1(sc, VGE_DIAGCTL, VGE_DIAGCTL_MACFORCE); + CSR_CLRBIT_1(sc, VGE_DIAGCTL, VGE_DIAGCTL_FDXFORCE); + break; + case IFM_1000_T: + CSR_SETBIT_1(sc, VGE_DIAGCTL, VGE_DIAGCTL_MACFORCE); + CSR_CLRBIT_1(sc, VGE_DIAGCTL, VGE_DIAGCTL_FDXFORCE); + break; + case IFM_100_TX: + case IFM_10_T: + CSR_SETBIT_1(sc, VGE_DIAGCTL, VGE_DIAGCTL_MACFORCE); + if ((ife->ifm_media & IFM_GMASK) == IFM_FDX) { + CSR_SETBIT_1(sc, VGE_DIAGCTL, VGE_DIAGCTL_FDXFORCE); + } else { + CSR_CLRBIT_1(sc, VGE_DIAGCTL, VGE_DIAGCTL_FDXFORCE); + } + break; + default: + device_printf(sc->vge_dev, "unknown media type: %x\n", + IFM_SUBTYPE(ife->ifm_media)); + break; + } + error = mii_mediachg(mii); VGE_UNLOCK(sc); - return (0); + return (error); } /* @@ -2092,9 +2140,11 @@ struct mii_data *mii; sc = ifp->if_softc; + VGE_LOCK(sc); mii = device_get_softc(sc->vge_miibus); mii_pollstat(mii); + VGE_UNLOCK(sc); ifmr->ifm_active = mii->mii_media_active; ifmr->ifm_status = mii->mii_media_status; @@ -2107,48 +2157,79 @@ { struct vge_softc *sc; struct mii_data *mii; - struct ifmedia_entry *ife; + struct ifnet *ifp; + uint8_t cfg; sc = device_get_softc(dev); mii = device_get_softc(sc->vge_miibus); - ife = mii->mii_media.ifm_cur; + ifp = sc->vge_ifp; + if (mii == NULL || ifp == NULL || + (ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) { + return; + } - /* - * If the user manually selects a media mode, we need to turn - * on the forced MAC mode bit in the DIAGCTL register. If the - * user happens to choose a full duplex mode, we also need to - * set the 'force full duplex' bit. This applies only to - * 10Mbps and 100Mbps speeds. In autoselect mode, forced MAC - * mode is disabled, and in 1000baseT mode, full duplex is - * always implied, so we turn on the forced mode bit but leave - * the FDX bit cleared. - */ + if (mii->mii_media_status & IFM_ACTIVE) { + if (IFM_SUBTYPE(mii->mii_media_active) != IFM_NONE) + sc->vge_link = 1; + } else + sc->vge_link = 0; - switch (IFM_SUBTYPE(ife->ifm_media)) { - case IFM_AUTO: - CSR_CLRBIT_1(sc, VGE_DIAGCTL, VGE_DIAGCTL_MACFORCE); - CSR_CLRBIT_1(sc, VGE_DIAGCTL, VGE_DIAGCTL_FDXFORCE); - break; - case IFM_1000_T: - CSR_SETBIT_1(sc, VGE_DIAGCTL, VGE_DIAGCTL_MACFORCE); - CSR_CLRBIT_1(sc, VGE_DIAGCTL, VGE_DIAGCTL_FDXFORCE); - break; - case IFM_100_TX: - case IFM_10_T: - CSR_SETBIT_1(sc, VGE_DIAGCTL, VGE_DIAGCTL_MACFORCE); - if ((ife->ifm_media & IFM_GMASK) == IFM_FDX) { - CSR_SETBIT_1(sc, VGE_DIAGCTL, VGE_DIAGCTL_FDXFORCE); - } else { - CSR_CLRBIT_1(sc, VGE_DIAGCTL, VGE_DIAGCTL_FDXFORCE); + /* STOP MAC & RESTART MAC */ + if (sc->vge_link != 0) { + /* + * If the user manually selects a media mode, we need to turn + * on the forced MAC mode bit in the DIAGCTL register. If the + * user happens to choose a full duplex mode, we also need to + * set the 'force full duplex' bit. This applies only to + * 10Mbps and 100Mbps speeds. In autoselect mode, forced MAC + * mode is disabled, and in 1000baseT mode, full duplex is + * always implied, so we turn on the forced mode bit but leave + * the FDX bit cleared. + */ +#if 0 + switch (IFM_SUBTYPE(ife->ifm_media)) { + case IFM_AUTO: + CSR_CLRBIT_1(sc, VGE_DIAGCTL, VGE_DIAGCTL_MACFORCE); + CSR_CLRBIT_1(sc, VGE_DIAGCTL, VGE_DIAGCTL_FDXFORCE); + break; + case IFM_1000_T: + CSR_SETBIT_1(sc, VGE_DIAGCTL, VGE_DIAGCTL_MACFORCE); + CSR_CLRBIT_1(sc, VGE_DIAGCTL, VGE_DIAGCTL_FDXFORCE); + break; + case IFM_100_TX: + case IFM_10_T: + CSR_SETBIT_1(sc, VGE_DIAGCTL, VGE_DIAGCTL_MACFORCE); + if ((ife->ifm_media & IFM_GMASK) == IFM_FDX) { + CSR_SETBIT_1(sc, VGE_DIAGCTL, VGE_DIAGCTL_FDXFORCE); + } else { + CSR_CLRBIT_1(sc, VGE_DIAGCTL, VGE_DIAGCTL_FDXFORCE); + } + break; + default: + device_printf(dev, "unknown media type: %x\n", + IFM_SUBTYPE(ife->ifm_media)); + break; + } +#endif + /* Reprgroam MAC as resolved media type. */ + cfg = CSR_READ_1(sc, VGE_DIAGCTL); +#if 1 + cfg &= ~(VGE_DIAGCTL_FDXFORCE | VGE_DIAGCTL_GMII); + cfg |= VGE_DIAGCTL_MACFORCE; + if ((IFM_OPTIONS(mii->mii_media_active) & IFM_FDX) != 0) { + cfg |= VGE_DIAGCTL_FDXFORCE; + /* TODO Enable flow-control */ + } + switch (IFM_SUBTYPE(mii->mii_media_active)) { + case IFM_1000_T: + cfg |= VGE_DIAGCTL_GMII; + break; } - break; - default: - device_printf(dev, "unknown media type: %x\n", - IFM_SUBTYPE(ife->ifm_media)); - break; - } - return; + CSR_WRITE_1(sc, VGE_DIAGCTL, cfg); +#endif + /* XXX Restart TX/RX MAC. */ + } } static int @@ -2169,6 +2250,7 @@ ifp->if_mtu = ifr->ifr_mtu; break; case SIOCSIFFLAGS: + VGE_LOCK(sc); if (ifp->if_flags & IFF_UP) { if (ifp->if_drv_flags & IFF_DRV_RUNNING && ifp->if_flags & IFF_PROMISC && @@ -2183,16 +2265,19 @@ VGE_RXCTL_RX_PROMISC); vge_setmulti(sc); } else - vge_init(sc); + vge_init_locked(sc); } else { if (ifp->if_drv_flags & IFF_DRV_RUNNING) vge_stop(sc); } sc->vge_if_flags = ifp->if_flags; + VGE_UNLOCK(sc); break; case SIOCADDMULTI: case SIOCDELMULTI: + VGE_LOCK(sc); vge_setmulti(sc); + VGE_UNLOCK(sc); break; case SIOCGIFMEDIA: case SIOCSIFMEDIA: @@ -2246,13 +2331,17 @@ } static void -vge_watchdog(ifp) - struct ifnet *ifp; +vge_watchdog(sc) + struct vge_softc *sc; { - struct vge_softc *sc; + struct ifnet *ifp; - sc = ifp->if_softc; - VGE_LOCK(sc); + VGE_LOCK_ASSERT(sc); + + if (sc->vge_watchdog_timer == 0 || --sc->vge_watchdog_timer) + return; + + ifp = sc->vge_ifp; printf("vge%d: watchdog timeout\n", sc->vge_unit); ifp->if_oerrors++; @@ -2277,10 +2366,12 @@ register int i; struct ifnet *ifp; - VGE_LOCK(sc); + VGE_LOCK_ASSERT(sc); + ifp = sc->vge_ifp; - ifp->if_timer = 0; + sc->vge_watchdog_timer = 0; + callout_stop(&sc->vge_callout); ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); CSR_WRITE_1(sc, VGE_CRC3, VGE_CR3_INT_GMSK); @@ -2317,8 +2408,6 @@ } } - VGE_UNLOCK(sc); - return; } --- if_vgereg.h.orig 2005-01-06 10:43:31.000000000 +0900 +++ if_vgereg.h 2008-02-27 13:59:49.000000000 +0900 @@ -299,7 +299,7 @@ #define VGE_INTRS (VGE_ISR_TXOK0|VGE_ISR_RXOK|VGE_ISR_STOPPED| \ VGE_ISR_RXOFLOW|VGE_ISR_PHYINT| \ - VGE_ISR_LINKSTS|VGE_ISR_RXNODESC| \ + VGE_ISR_RXNODESC| \ VGE_ISR_RXDMA_STALL|VGE_ISR_TXDMA_STALL| \ VGE_ISR_MIBOFLOW|VGE_ISR_TIMER0) --- if_vgevar.h.orig 2005-06-11 01:49:16.000000000 +0900 +++ if_vgevar.h 2008-02-27 15:11:28.000000000 +0900 @@ -110,6 +110,9 @@ bus_dma_tag_t vge_tag; u_int8_t vge_unit; /* interface number */ u_int8_t vge_type; + struct callout vge_callout; + int vge_watchdog_timer; + int vge_phyaddr; int vge_if_flags; int vge_rx_consumed; int vge_link;