summaryrefslogtreecommitdiff
path: root/sys/dev/vge
diff options
context:
space:
mode:
authorPyun YongHyeon <yongari@FreeBSD.org>2011-11-22 20:45:09 +0000
committerPyun YongHyeon <yongari@FreeBSD.org>2011-11-22 20:45:09 +0000
commit66c6108d5dfe14f8bbed3821103cc4bb5990d7f8 (patch)
treec01b7dedb17a8e15c4877548ee24b55a795b89e1 /sys/dev/vge
parentbeb7471b16d9ea8fe169db04cb382d4ea209e844 (diff)
Notes
Diffstat (limited to 'sys/dev/vge')
-rw-r--r--sys/dev/vge/if_vge.c62
1 files changed, 44 insertions, 18 deletions
diff --git a/sys/dev/vge/if_vge.c b/sys/dev/vge/if_vge.c
index c75726194ad6..720c32035c20 100644
--- a/sys/dev/vge/if_vge.c
+++ b/sys/dev/vge/if_vge.c
@@ -173,6 +173,7 @@ static __inline void
static void vge_freebufs(struct vge_softc *);
static void vge_ifmedia_sts(struct ifnet *, struct ifmediareq *);
static int vge_ifmedia_upd(struct ifnet *);
+static int vge_ifmedia_upd_locked(struct vge_softc *);
static void vge_init(void *);
static void vge_init_locked(struct vge_softc *);
static void vge_intr(void *);
@@ -180,7 +181,6 @@ static void vge_intr_holdoff(struct vge_softc *);
static int vge_ioctl(struct ifnet *, u_long, caddr_t);
static void vge_link_statchg(void *);
static int vge_miibus_readreg(device_t, int, int);
-static void vge_miibus_statchg(device_t);
static int vge_miibus_writereg(device_t, int, int, int);
static void vge_miipoll_start(struct vge_softc *);
static void vge_miipoll_stop(struct vge_softc *);
@@ -190,6 +190,7 @@ static void vge_reset(struct vge_softc *);
static int vge_rx_list_init(struct vge_softc *);
static int vge_rxeof(struct vge_softc *, int);
static void vge_rxfilter(struct vge_softc *);
+static void vge_setmedia(struct vge_softc *);
static void vge_setvlan(struct vge_softc *);
static void vge_setwol(struct vge_softc *);
static void vge_start(struct ifnet *);
@@ -218,7 +219,6 @@ static device_method_t vge_methods[] = {
/* MII interface */
DEVMETHOD(miibus_readreg, vge_miibus_readreg),
DEVMETHOD(miibus_writereg, vge_miibus_writereg),
- DEVMETHOD(miibus_statchg, vge_miibus_statchg),
{ 0, 0 }
};
@@ -1661,30 +1661,41 @@ vge_link_statchg(void *xsc)
{
struct vge_softc *sc;
struct ifnet *ifp;
- struct mii_data *mii;
+ uint8_t physts;
sc = xsc;
ifp = sc->vge_ifp;
VGE_LOCK_ASSERT(sc);
- mii = device_get_softc(sc->vge_miibus);
- mii_pollstat(mii);
- if ((sc->vge_flags & VGE_FLAG_LINK) != 0) {
- if (!(mii->mii_media_status & IFM_ACTIVE)) {
+ physts = CSR_READ_1(sc, VGE_PHYSTS0);
+ if ((physts & VGE_PHYSTS_RESETSTS) == 0) {
+ if ((physts & VGE_PHYSTS_LINK) == 0) {
sc->vge_flags &= ~VGE_FLAG_LINK;
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) {
+ } else {
sc->vge_flags |= VGE_FLAG_LINK;
if_link_state_change(sc->vge_ifp,
LINK_STATE_UP);
+ CSR_WRITE_1(sc, VGE_CRC2, VGE_CR2_FDX_TXFLOWCTL_ENABLE |
+ VGE_CR2_FDX_RXFLOWCTL_ENABLE);
+ if ((physts & VGE_PHYSTS_FDX) != 0) {
+ if ((physts & VGE_PHYSTS_TXFLOWCAP) != 0)
+ CSR_WRITE_1(sc, VGE_CRS2,
+ VGE_CR2_FDX_TXFLOWCTL_ENABLE);
+ if ((physts & VGE_PHYSTS_RXFLOWCAP) != 0)
+ CSR_WRITE_1(sc, VGE_CRS2,
+ VGE_CR2_FDX_RXFLOWCTL_ENABLE);
+ }
if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd))
vge_start_locked(ifp);
}
}
+ /*
+ * Restart MII auto-polling because link state change interrupt
+ * will disable it.
+ */
+ vge_miipoll_start(sc);
}
#ifdef DEVICE_POLLING
@@ -2131,7 +2142,7 @@ vge_init_locked(struct vge_softc *sc)
CSR_WRITE_1(sc, VGE_CRS3, VGE_CR3_INT_GMSK);
sc->vge_flags &= ~VGE_FLAG_LINK;
- mii_mediachg(mii);
+ vge_ifmedia_upd_locked(sc);
ifp->if_drv_flags |= IFF_DRV_RUNNING;
ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
@@ -2145,14 +2156,28 @@ static int
vge_ifmedia_upd(struct ifnet *ifp)
{
struct vge_softc *sc;
- struct mii_data *mii;
int error;
sc = ifp->if_softc;
VGE_LOCK(sc);
+ error = vge_ifmedia_upd_locked(sc);
+ VGE_UNLOCK(sc);
+
+ return (error);
+}
+
+static int
+vge_ifmedia_upd_locked(struct vge_softc *sc)
+{
+ struct mii_data *mii;
+ struct mii_softc *miisc;
+ int error;
+
mii = device_get_softc(sc->vge_miibus);
+ LIST_FOREACH(miisc, &mii->mii_phys, mii_list)
+ PHY_RESET(miisc);
+ vge_setmedia(sc);
error = mii_mediachg(mii);
- VGE_UNLOCK(sc);
return (error);
}
@@ -2181,13 +2206,11 @@ vge_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr)
}
static void
-vge_miibus_statchg(device_t dev)
+vge_setmedia(struct vge_softc *sc)
{
- struct vge_softc *sc;
struct mii_data *mii;
struct ifmedia_entry *ife;
- sc = device_get_softc(dev);
mii = device_get_softc(sc->vge_miibus);
ife = mii->mii_media.ifm_cur;
@@ -2221,7 +2244,7 @@ vge_miibus_statchg(device_t dev)
}
break;
default:
- device_printf(dev, "unknown media type: %x\n",
+ device_printf(sc->vge_dev, "unknown media type: %x\n",
IFM_SUBTYPE(ife->ifm_media));
break;
}
@@ -2774,6 +2797,9 @@ vge_setlinkspeed(struct vge_softc *sc)
break;
}
}
+ /* Clear forced MAC speed/duplex configuration. */
+ CSR_CLRBIT_1(sc, VGE_DIAGCTL, VGE_DIAGCTL_MACFORCE);
+ CSR_CLRBIT_1(sc, VGE_DIAGCTL, VGE_DIAGCTL_FDXFORCE);
vge_miibus_writereg(sc->vge_dev, sc->vge_phyaddr, MII_100T2CR, 0);
vge_miibus_writereg(sc->vge_dev, sc->vge_phyaddr, MII_ANAR,
ANAR_TX_FD | ANAR_TX | ANAR_10_FD | ANAR_10 | ANAR_CSMA);