Move a lot closer to NetBSDs MII support for GigE.

Move fxp and nge drivers over to use the new stuff.
This commit is contained in:
Poul-Henning Kamp 2002-04-29 11:57:30 +00:00
parent f7bf276ff5
commit 78c8c3db4b
7 changed files with 249 additions and 292 deletions

View File

@ -144,7 +144,7 @@ inphy_attach(device_t dev)
sc->mii_capabilities = PHY_READ(sc, MII_BMSR) & ma->mii_capmask;
device_printf(dev, " ");
mii_add_media(sc);
mii_phy_add_media(sc);
printf("\n");
MIIBUS_MEDIAINIT(sc->mii_dev);
@ -192,27 +192,7 @@ inphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd)
if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
break;
switch (IFM_SUBTYPE(ife->ifm_media)) {
case IFM_AUTO:
/*
* If we're already in auto mode, just return.
*/
if (PHY_READ(sc, MII_BMCR) & BMCR_AUTOEN)
return (0);
(void) mii_phy_auto(sc, 0);
break;
case IFM_100_T4:
/*
* XXX Not supported as a manual setting right now.
*/
return (EINVAL);
default:
/*
* BMCR data is stored in the ifmedia entry.
*/
PHY_WRITE(sc, MII_ANAR, mii_anar(ife->ifm_media));
PHY_WRITE(sc, MII_BMCR, ife->ifm_data);
}
mii_phy_setmedia(sc);
break;
case MII_TICK:
@ -235,6 +215,7 @@ static void
inphy_status(struct mii_softc *sc)
{
struct mii_data *mii = sc->mii_pdata;
struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
int bmsr, bmcr, scr;
mii->mii_media_status = IFM_AVALID;
@ -268,5 +249,5 @@ inphy_status(struct mii_softc *sc)
if (scr & SCR_FDX)
mii->mii_media_active |= IFM_FDX;
} else
mii->mii_media_active |= mii_media_from_bmcr(bmcr);
mii->mii_media_active = ife->ifm_media;
}

View File

@ -92,7 +92,7 @@
* info available in register 15, but 802.3 section 22.2.4.3 also
* states that that all 1000 Mb/s capable PHYs will set this bit to 1.
*/
#if 1
#if 0
#define BMSR_MEDIAMASK (BMSR_100T4|BMSR_100TXFDX|BMSR_100TXHDX|BMSR_10TFDX| \
BMSR_10THDX|BMSR_ANEG)

View File

@ -1,7 +1,7 @@
/* $NetBSD: mii_physubr.c,v 1.5 1999/08/03 19:41:49 drochner Exp $ */
/*-
* Copyright (c) 1998, 1999 The NetBSD Foundation, Inc.
* Copyright (c) 1998, 1999, 2000, 2001 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
@ -127,10 +127,9 @@ mii_phy_setmedia(struct mii_softc *sc)
* Table index is stored in the media entry.
*/
#ifdef DIAGNOSTIC
if (ife->ifm_data < 0 || ife->ifm_data >= MII_NMEDIA)
panic("mii_phy_setmedia");
#endif
KASSERT(ife->ifm_data >=0 && ife->ifm_data < MII_NMEDIA,
("invalid ife->ifm_data (0x%x) in mii_phy_setmedia",
ife->ifm_data));
anar = mii_media_table[ife->ifm_data].mm_anar;
bmcr = mii_media_table[ife->ifm_data].mm_bmcr;
@ -157,29 +156,57 @@ mii_phy_setmedia(struct mii_softc *sc)
}
int
mii_phy_auto(mii, waitfor)
struct mii_softc *mii;
int waitfor;
mii_phy_auto(struct mii_softc *sc, int waitfor)
{
int bmsr, i;
if ((mii->mii_flags & MIIF_DOINGAUTO) == 0) {
PHY_WRITE(mii, MII_ANAR,
BMSR_MEDIA_TO_ANAR(mii->mii_capabilities) | ANAR_CSMA);
PHY_WRITE(mii, MII_BMCR, BMCR_AUTOEN | BMCR_STARTNEG);
if ((sc->mii_flags & MIIF_DOINGAUTO) == 0) {
/*
* Check for 1000BASE-X. Autonegotiation is a bit
* different on such devices.
*/
if (sc->mii_flags & MIIF_IS_1000X) {
uint16_t anar = 0;
if (sc->mii_extcapabilities & EXTSR_1000XFDX)
anar |= ANAR_X_FD;
if (sc->mii_extcapabilities & EXTSR_1000XHDX)
anar |= ANAR_X_HD;
if (sc->mii_flags & MIIF_DOPAUSE) {
/* XXX Asymmetric vs. symmetric? */
anar |= ANLPAR_X_PAUSE_TOWARDS;
}
PHY_WRITE(sc, MII_ANAR, anar);
} else {
uint16_t anar;
anar = BMSR_MEDIA_TO_ANAR(sc->mii_capabilities) |
ANAR_CSMA;
if (sc->mii_flags & MIIF_DOPAUSE)
anar |= ANAR_FC;
PHY_WRITE(sc, MII_ANAR, anar);
if (sc->mii_flags & MIIF_HAVE_GTCR) {
uint16_t gtcr = 0;
if (sc->mii_extcapabilities & EXTSR_1000TFDX)
gtcr |= GTCR_ADV_1000TFDX;
if (sc->mii_extcapabilities & EXTSR_1000THDX)
gtcr |= GTCR_ADV_1000THDX;
PHY_WRITE(sc, MII_100T2CR, gtcr);
}
}
PHY_WRITE(sc, MII_BMCR, BMCR_AUTOEN | BMCR_STARTNEG);
}
if (waitfor) {
/* Wait 500ms for it to complete. */
for (i = 0; i < 500; i++) {
if ((bmsr = PHY_READ(mii, MII_BMSR)) & BMSR_ACOMP)
if ((bmsr = PHY_READ(sc, MII_BMSR)) & BMSR_ACOMP)
return (0);
DELAY(1000);
#if 0
if ((bmsr & BMSR_ACOMP) == 0)
printf("%s: autonegotiation failed to complete\n",
mii->mii_dev.dv_xname);
#endif
}
/*
@ -195,9 +222,9 @@ mii_phy_auto(mii, waitfor)
* the tick handler driving autonegotiation. Don't want 500ms
* delays all the time while the system is running!
*/
if ((mii->mii_flags & MIIF_DOINGAUTO) == 0) {
mii->mii_flags |= MIIF_DOINGAUTO;
mii->mii_auto_ch = timeout(mii_phy_auto_timeout, mii, hz >> 1);
if ((sc->mii_flags & MIIF_DOINGAUTO) == 0) {
sc->mii_flags |= MIIF_DOINGAUTO;
sc->mii_auto_ch = timeout(mii_phy_auto_timeout, sc, hz >> 1);
}
return (EJUSTRETURN);
}
@ -213,37 +240,33 @@ mii_phy_auto_stop(sc)
}
void
mii_phy_auto_timeout(arg)
void *arg;
mii_phy_auto_timeout(void *arg)
{
struct mii_softc *mii = arg;
struct mii_softc *sc = arg;
int s, bmsr;
s = splnet();
mii->mii_flags &= ~MIIF_DOINGAUTO;
bmsr = PHY_READ(mii, MII_BMSR);
#if 0
if ((bmsr & BMSR_ACOMP) == 0)
printf("%s: autonegotiation failed to complete\n",
sc->sc_dev.dv_xname);
if ((sc->mii_dev.dv_flags & DVF_ACTIVE) == 0)
return;
#endif
s = splnet();
sc->mii_flags &= ~MIIF_DOINGAUTO;
bmsr = PHY_READ(sc, MII_BMSR);
/* Update the media status. */
(void) (*mii->mii_service)(mii, mii->mii_pdata, MII_POLLSTAT);
(void) (*sc->mii_service)(sc, sc->mii_pdata, MII_POLLSTAT);
splx(s);
}
int
mii_phy_tick(sc)
struct mii_softc *sc;
mii_phy_tick(struct mii_softc *sc)
{
struct ifmedia_entry *ife = sc->mii_pdata->mii_media.ifm_cur;
struct ifnet *ifp = sc->mii_pdata->mii_ifp;
int reg;
/*
* Is the interface even up?
*/
/* Just bail now if the interface is down. */
if ((ifp->if_flags & IFF_UP) == 0)
return (EJUSTRETURN);
@ -256,18 +279,21 @@ mii_phy_tick(sc)
if (IFM_SUBTYPE(ife->ifm_media) != IFM_AUTO)
return (0);
/*
* check for link.
* Read the status register twice; BMSR_LINK is latch-low.
*/
/* Read the status register twice; BMSR_LINK is latch-low. */
reg = PHY_READ(sc, MII_BMSR) | PHY_READ(sc, MII_BMSR);
if (reg & BMSR_LINK)
if (reg & BMSR_LINK) {
/*
* See above.
*/
return (0);
}
/*
* Only retry autonegotiation every 5 seconds.
* Only retry autonegotiation every N seconds.
*/
if (++sc->mii_ticks != 5)
if (sc->mii_anegticks == 0)
sc->mii_anegticks = 5;
if (++sc->mii_ticks != sc->mii_anegticks)
return (EJUSTRETURN);
sc->mii_ticks = 0;
@ -283,27 +309,26 @@ mii_phy_tick(sc)
}
void
mii_phy_reset(mii)
struct mii_softc *mii;
mii_phy_reset(struct mii_softc *sc)
{
int reg, i;
if (mii->mii_flags & MIIF_NOISOLATE)
if (sc->mii_flags & MIIF_NOISOLATE)
reg = BMCR_RESET;
else
reg = BMCR_RESET | BMCR_ISO;
PHY_WRITE(mii, MII_BMCR, reg);
PHY_WRITE(sc, MII_BMCR, reg);
/* Wait 100ms for it to complete. */
for (i = 0; i < 100; i++) {
reg = PHY_READ(mii, MII_BMCR);
reg = PHY_READ(sc, MII_BMCR);
if ((reg & BMCR_RESET) == 0)
break;
DELAY(1000);
}
if (mii->mii_inst != 0 && ((mii->mii_flags & MIIF_NOISOLATE) == 0))
PHY_WRITE(mii, MII_BMCR, reg | BMCR_ISO);
if (sc->mii_inst != 0 && ((sc->mii_flags & MIIF_NOISOLATE) == 0))
PHY_WRITE(sc, MII_BMCR, reg | BMCR_ISO);
}
void
@ -436,3 +461,122 @@ mii_add_media(struct mii_softc *sc)
#undef ADD
#undef PRINT
}
/*
* Initialize generic PHY media based on BMSR, called when a PHY is
* attached. We expect to be set up to print a comma-separated list
* of media names. Does not print a newline.
*/
void
mii_phy_add_media(struct mii_softc *sc)
{
struct mii_data *mii = sc->mii_pdata;
const char *sep = "";
#define ADD(m, c) ifmedia_add(&mii->mii_media, (m), (c), NULL)
#define PRINT(s) printf("%s%s", sep, s); sep = ", "
if ((sc->mii_flags & MIIF_NOISOLATE) == 0)
ADD(IFM_MAKEWORD(IFM_ETHER, IFM_NONE, 0, sc->mii_inst),
MII_MEDIA_NONE);
/*
* There are different interpretations for the bits in
* HomePNA PHYs. And there is really only one media type
* that is supported.
*/
if (sc->mii_flags & MIIF_IS_HPNA) {
if (sc->mii_capabilities & BMSR_10THDX) {
ADD(IFM_MAKEWORD(IFM_ETHER, IFM_HPNA_1, 0,
sc->mii_inst),
MII_MEDIA_10_T);
PRINT("HomePNA1");
}
return;
}
if (sc->mii_capabilities & BMSR_10THDX) {
ADD(IFM_MAKEWORD(IFM_ETHER, IFM_10_T, 0, sc->mii_inst),
MII_MEDIA_10_T);
PRINT("10baseT");
}
if (sc->mii_capabilities & BMSR_10TFDX) {
ADD(IFM_MAKEWORD(IFM_ETHER, IFM_10_T, IFM_FDX, sc->mii_inst),
MII_MEDIA_10_T_FDX);
PRINT("10baseT-FDX");
}
if (sc->mii_capabilities & BMSR_100TXHDX) {
ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_TX, 0, sc->mii_inst),
MII_MEDIA_100_TX);
PRINT("100baseTX");
}
if (sc->mii_capabilities & BMSR_100TXFDX) {
ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_TX, IFM_FDX, sc->mii_inst),
MII_MEDIA_100_TX_FDX);
PRINT("100baseTX-FDX");
}
if (sc->mii_capabilities & BMSR_100T4) {
ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_T4, 0, sc->mii_inst),
MII_MEDIA_100_T4);
PRINT("100baseT4");
}
if (sc->mii_extcapabilities & EXTSR_MEDIAMASK) {
/*
* XXX Right now only handle 1000SX and 1000TX. Need
* XXX to handle 1000LX and 1000CX some how.
*
* Note since it can take 5 seconds to auto-negotiate
* a gigabit link, we make anegticks 10 seconds for
* all the gigabit media types.
*/
if (sc->mii_extcapabilities & EXTSR_1000XHDX) {
sc->mii_anegticks = 10;
sc->mii_flags |= MIIF_IS_1000X;
ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_SX, 0,
sc->mii_inst), MII_MEDIA_1000_X);
PRINT("1000baseSX");
}
if (sc->mii_extcapabilities & EXTSR_1000XFDX) {
sc->mii_anegticks = 10;
sc->mii_flags |= MIIF_IS_1000X;
ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_SX, IFM_FDX,
sc->mii_inst), MII_MEDIA_1000_X_FDX);
PRINT("1000baseSX-FDX");
}
/*
* 1000baseT media needs to be able to manipulate
* master/slave mode. We set IFM_ETH_MASTER in
* the "don't care mask" and filter it out when
* the media is set.
*
* All 1000baseT PHYs have a 1000baseT control register.
*/
if (sc->mii_extcapabilities & EXTSR_1000THDX) {
sc->mii_anegticks = 10;
sc->mii_flags |= MIIF_HAVE_GTCR;
mii->mii_media.ifm_mask |= IFM_ETH_MASTER;
ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_T, 0,
sc->mii_inst), MII_MEDIA_1000_T);
PRINT("1000baseT");
}
if (sc->mii_extcapabilities & EXTSR_1000TFDX) {
sc->mii_anegticks = 10;
sc->mii_flags |= MIIF_HAVE_GTCR;
mii->mii_media.ifm_mask |= IFM_ETH_MASTER;
ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_T, IFM_FDX,
sc->mii_inst), MII_MEDIA_1000_T_FDX);
PRINT("1000baseT-FDX");
}
}
if (sc->mii_capabilities & BMSR_ANEG) {
ADD(IFM_MAKEWORD(IFM_ETHER, IFM_AUTO, 0, sc->mii_inst),
MII_NMEDIA); /* intentionally invalid index */
PRINT("auto");
}
#undef ADD
#undef PRINT
}

View File

@ -197,6 +197,7 @@ void mii_tick(struct mii_data *);
void mii_pollstat(struct mii_data *);
int mii_phy_probe(device_t, device_t *, ifm_change_cb_t, ifm_stat_cb_t);
void mii_add_media(struct mii_softc *);
void mii_phy_add_media(struct mii_softc *);
int mii_media_from_bmcr(int);

View File

@ -2,6 +2,12 @@
* Copyright (c) 2001 Wind River Systems
* Copyright (c) 2001
* Bill Paul <wpaul@bsdi.com>. All rights reserved.
* Copyright (c) 1998, 1999, 2000, 2001 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
* NASA Ames Research Center.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@ -97,7 +103,6 @@ DRIVER_MODULE(nsgphy, miibus, nsgphy_driver, nsgphy_devclass, 0, 0);
static int nsgphy_service(struct mii_softc *, struct mii_data *,int);
static void nsgphy_status(struct mii_softc *);
static int nsgphy_mii_phy_auto(struct mii_softc *, int);
extern void mii_phy_auto_timeout(void *);
static int
@ -127,7 +132,6 @@ nsgphy_attach(device_t dev)
struct mii_softc *sc;
struct mii_attach_args *ma;
struct mii_data *mii;
const char *sep = "";
sc = device_get_softc(dev);
ma = device_get_ivars(dev);
@ -139,48 +143,17 @@ nsgphy_attach(device_t dev)
sc->mii_phy = ma->mii_phyno;
sc->mii_service = nsgphy_service;
sc->mii_pdata = mii;
sc->mii_anegticks = 5;
sc->mii_flags |= MIIF_NOISOLATE;
mii->mii_instance++;
#define ADD(m, c) ifmedia_add(&mii->mii_media, (m), (c), NULL)
#define PRINT(s) printf("%s%s", sep, s); sep = ", "
ADD(IFM_MAKEWORD(IFM_ETHER, IFM_NONE, 0, sc->mii_inst),
BMCR_ISO);
#if 0
ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_TX, IFM_LOOP, sc->mii_inst),
BMCR_LOOP|BMCR_S100);
#endif
mii_phy_reset(sc);
device_printf(dev, " ");
ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_T, IFM_FDX, sc->mii_inst),
BMCR_S1000|BMCR_FDX);
PRINT("1000baseTX-FDX");
ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_T, 0, sc->mii_inst),
BMCR_S1000);
PRINT("1000baseTX");
sc->mii_capabilities = (PHY_READ(sc, MII_BMSR) |
(BMSR_10TFDX|BMSR_10THDX)) & ma->mii_capmask;
if (sc->mii_capabilities & BMSR_EXTSTAT)
sc->mii_extcapabilities = PHY_READ(sc, MII_EXTSR);
ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_TX, IFM_FDX, sc->mii_inst),
BMCR_S100|BMCR_FDX);
PRINT("100baseTX-FDX");
ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_TX, 0, sc->mii_inst), BMCR_S100);
PRINT("100baseTX");
ADD(IFM_MAKEWORD(IFM_ETHER, IFM_10_T, IFM_FDX, sc->mii_inst),
BMCR_S10|BMCR_FDX);
PRINT("10baseT-FDX");
ADD(IFM_MAKEWORD(IFM_ETHER, IFM_10_T, 0, sc->mii_inst), BMCR_S10);
PRINT("10baseT");
ADD(IFM_MAKEWORD(IFM_ETHER, IFM_AUTO, 0, sc->mii_inst), 0);
PRINT("auto");
mii_phy_add_media(sc);
printf("\n");
#undef ADD
#undef PRINT
MIIBUS_MEDIAINIT(sc->mii_dev);
return(0);
@ -234,59 +207,7 @@ nsgphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd)
if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
break;
switch (IFM_SUBTYPE(ife->ifm_media)) {
case IFM_AUTO:
#ifdef foo
/*
* If we're already in auto mode, just return.
*/
if (PHY_READ(sc, MII_BMCR) & BMCR_AUTOEN)
return (0);
#endif
(void) nsgphy_mii_phy_auto(sc, 0);
break;
case IFM_1000_T:
if ((ife->ifm_media & IFM_GMASK) == IFM_FDX) {
PHY_WRITE(sc, MII_BMCR,
BMCR_FDX|BMCR_SPEED1);
} else {
PHY_WRITE(sc, MII_BMCR,
BMCR_SPEED1);
}
PHY_WRITE(sc, MII_ANAR, ANAR_CSMA);
/*
* When setting the link manually, one side must
* be the master and the other the slave. However
* ifmedia doesn't give us a good way to specify
* this, so we fake it by using one of the LINK
* flags. If LINK0 is set, we program the PHY to
* be a master, otherwise it's a slave.
*/
if ((mii->mii_ifp->if_flags & IFF_LINK0)) {
PHY_WRITE(sc, MII_100T2CR,
GTCR_MAN_MS|GTCR_ADV_MS);
} else {
PHY_WRITE(sc, MII_100T2CR, GTCR_MAN_MS);
}
break;
case IFM_100_T4:
/*
* XXX Not supported as a manual setting right now.
*/
return (EINVAL);
case IFM_NONE:
PHY_WRITE(sc, MII_BMCR, BMCR_ISO|BMCR_PDOWN);
break;
default:
/*
* BMCR data is stored in the ifmedia entry.
*/
PHY_WRITE(sc, MII_ANAR, mii_anar(ife->ifm_media));
PHY_WRITE(sc, MII_BMCR, ife->ifm_data);
break;
}
mii_phy_setmedia(sc);
break;
case MII_TICK:
@ -296,39 +217,8 @@ nsgphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd)
if (IFM_INST(ife->ifm_media) != sc->mii_inst)
return (0);
/*
* Is the interface even up?
*/
if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
if (mii_phy_tick(sc) == EJUSTRETURN)
return (0);
/*
* Only used for autonegotiation.
*/
if (IFM_SUBTYPE(ife->ifm_media) != IFM_AUTO)
break;
/*
* Check to see if we have link.
*/
reg = PHY_READ(sc, NSGPHY_MII_PHYSUP);
if (reg & NSGPHY_PHYSUP_LNKSTS)
break;
/*
* Only retry autonegotiation every 5 seconds.
* Actually, for gigE PHYs, we should wait longer, since
* 5 seconds is the mimimum time the documentation
* says to wait for a 1000mbps link to be established.
*/
if (++sc->mii_ticks != 10)
return (0);
sc->mii_ticks = 0;
mii_phy_reset(sc);
if (nsgphy_mii_phy_auto(sc, 0) == EJUSTRETURN)
return(0);
break;
}
@ -344,19 +234,25 @@ static void
nsgphy_status(struct mii_softc *sc)
{
struct mii_data *mii = sc->mii_pdata;
int bmsr, bmcr, physup, anlpar, gstat;
struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
int bmsr, bmcr, physup, gtsr;
mii->mii_media_status = IFM_AVALID;
mii->mii_media_active = IFM_ETHER;
bmsr = PHY_READ(sc, MII_BMSR);
bmsr = PHY_READ(sc, MII_BMSR) | PHY_READ(sc, MII_BMSR);
physup = PHY_READ(sc, NSGPHY_MII_PHYSUP);
if (physup & NSGPHY_PHYSUP_LNKSTS)
if (physup & PHY_SUP_LINK)
mii->mii_media_status |= IFM_ACTIVE;
bmcr = PHY_READ(sc, MII_BMCR);
if (bmcr & BMCR_ISO) {
mii->mii_media_active |= IFM_NONE;
mii->mii_media_status = 0;
return;
}
if (bmcr & BMCR_LOOP)
mii->mii_media_active |= IFM_LOOP;
@ -371,100 +267,29 @@ nsgphy_status(struct mii_softc *sc)
mii->mii_media_active |= IFM_NONE;
return;
}
anlpar = PHY_READ(sc, MII_ANLPAR);
gstat = PHY_READ(sc, MII_100T2SR);
if (gstat & GTSR_LP_1000TFDX)
mii->mii_media_active |= IFM_1000_T|IFM_FDX;
else if (gstat & GTSR_LP_1000THDX)
mii->mii_media_active |= IFM_1000_T|IFM_HDX;
else if (anlpar & ANLPAR_T4)
mii->mii_media_active |= IFM_100_T4;
else if (anlpar & ANLPAR_TX_FD)
mii->mii_media_active |= IFM_100_TX|IFM_FDX;
else if (anlpar & ANLPAR_TX)
switch (physup & (PHY_SUP_SPEED1|PHY_SUP_SPEED0)) {
case PHY_SUP_SPEED1:
mii->mii_media_active |= IFM_1000_T;
gtsr = PHY_READ(sc, MII_100T2SR);
if (gtsr & GTSR_MS_RES)
mii->mii_media_active |= IFM_ETH_MASTER;
break;
case PHY_SUP_SPEED0:
mii->mii_media_active |= IFM_100_TX;
else if (anlpar & ANLPAR_10_FD)
mii->mii_media_active |= IFM_10_T|IFM_FDX;
else if (anlpar & ANLPAR_10)
mii->mii_media_active |= IFM_10_T|IFM_HDX;
else
break;
case 0:
mii->mii_media_active |= IFM_10_T;
break;
default:
mii->mii_media_active |= IFM_NONE;
return;
}
switch(bmcr & (BMCR_SPEED1|BMCR_SPEED0)) {
case BMCR_S1000:
mii->mii_media_active |= IFM_1000_T;
break;
case BMCR_S100:
mii->mii_media_active |= IFM_100_TX;
break;
case BMCR_S10:
mii->mii_media_active |= IFM_10_T;
break;
default:
break;
}
if (bmcr & BMCR_FDX)
mii->mii_media_active |= IFM_FDX;
else
mii->mii_media_active |= IFM_HDX;
return;
}
static int
nsgphy_mii_phy_auto(struct mii_softc *mii, int waitfor)
{
int bmsr, ktcr = 0, i;
if ((mii->mii_flags & MIIF_DOINGAUTO) == 0) {
mii_phy_reset(mii);
PHY_WRITE(mii, MII_BMCR, 0);
DELAY(1000);
ktcr = PHY_READ(mii, MII_100T2CR);
PHY_WRITE(mii, MII_100T2CR, ktcr |
(GTCR_ADV_1000TFDX|GTCR_ADV_1000THDX));
ktcr = PHY_READ(mii, MII_100T2CR);
DELAY(1000);
PHY_WRITE(mii, MII_ANAR,
BMSR_MEDIA_TO_ANAR(mii->mii_capabilities) | ANAR_CSMA);
DELAY(1000);
PHY_WRITE(mii, MII_BMCR,
BMCR_AUTOEN | BMCR_STARTNEG);
}
if (waitfor) {
/* Wait 500ms for it to complete. */
for (i = 0; i < 500; i++) {
if ((bmsr = PHY_READ(mii, MII_BMSR)) & BMSR_ACOMP)
return (0);
DELAY(1000);
#if 0
if ((bmsr & BMSR_ACOMP) == 0)
printf("%s: autonegotiation failed to complete\n",
mii->mii_dev.dv_xname);
#endif
mii->mii_media_status = 0;
}
/*
* Don't need to worry about clearing MIIF_DOINGAUTO.
* If that's set, a timeout is pending, and it will
* clear the flag.
*/
return (EIO);
}
/*
* Just let it finish asynchronously. This is for the benefit of
* the tick handler driving autonegotiation. Don't want 500ms
* delays all the time while the system is running!
*/
if ((mii->mii_flags & MIIF_DOINGAUTO) == 0) {
mii->mii_flags |= MIIF_DOINGAUTO;
mii->mii_auto_ch = timeout(mii_phy_auto_timeout, mii, hz >> 1);
}
return (EJUSTRETURN);
if (physup & PHY_SUP_DUPLEX)
mii->mii_media_active |= IFM_FDX;
} else
mii->mii_media_active = ife->ifm_media;
}

View File

@ -54,10 +54,14 @@
#define NSGPHY_STRAPOPT_SPDSEL (NSGPHY_STRAPOPT_SPEED1|NSGPHY_STRAPOPT_SPEED0)
#define NSGPHY_MII_PHYSUP 0x11 /* PHY support/current status */
#define PHY_SUP_SPEED1 0x0010 /* speed bit 1 */
#define PHY_SUP_SPEED0 0x0008 /* speed bit 1 */
#define NSGPHY_PHYSUP_SPEED1 0x0010 /* speed status */
#define NSGPHY_PHYSUP_SPEED0 0x0008 /* speed status */
#define NSGPHY_PHYSUP_SPDSTS (NSGPHY_PHYSUP_SPEED1|NSGPHY_PHYSUP_SPEED0)
#define NSGPHY_PHYSUP_LNKSTS 0x0004 /* link status */
#define PHY_SUP_LINK 0x0004 /* link status */
#define PHY_SUP_DUPLEX 0x0002 /* 1 == full-duplex */
#define NSGPHY_PHYSUP_DUPSTS 0x0002 /* duplex status 1 == full */
#define NSGPHY_PHYSUP_10BT 0x0001 /* 10baseT resolved */

View File

@ -1980,10 +1980,12 @@ static void nge_stop(sc)
ifp->if_flags |= IFF_UP;
ifm = mii->mii_media.ifm_cur;
mtmp = ifm->ifm_media;
ifm->ifm_media = IFM_ETHER|IFM_NONE;
#if 0
ifm->ifm_media = IFM_ETHER|IFM_AUTO;
mii_mediachg(mii);
ifm->ifm_media = mtmp;
ifp->if_flags = itmp;
#endif
sc->nge_link = 0;