- Don't add IFM_NONE when used in combination with pcn(4) as for MII

loopback to work PCnet chips additionally need to be placed into
  external loopback mode which pcn(4) doesn't do so far.
- In nsphy_service() just use if_dname instead of determining the name
  of the parent NIC via device_get_name(device_get_parent(sc->mii_dev)).
- Don't set MIIF_NOISOLATE, except for when used in combination with a
  NIC that wedges when isolating the PHYs, so nsphy(4) can be used in
  configurations with multiple PHYs.
- Use mii_phy_add_media() instead of mii_add_media() so the latter can
  be eventually retired.
- Take advantage of mii_phy_setmedia() (requires the MIIF_FORCEANEG
  added in sys/dev/mii/mii_physubr.c 1.26, sys/dev/mii/miivar.h 1.19).
- Implement a separate nsphy_reset(). There are two reasons for this:
  1) This PHY can take an inordinate amount of time to reset if media
     is attached; under fairly normal circumstances up to nearly one
     second. This is because it appears to go through an implicit auto-
     negotiation cycle as part of the reset.
  2) During reset and auto-negotiation, the BMCR will clear the reset
     bit before the process is complete. It will return 0 until the
     process is complete and it's safe to access the PHY again.

  This is the first of two changes required to make the combination of
  Am79c971 and DP83840A found on certain HP cards and on-board in IBM
  machines work.
- Fix some whitespace nits.

Based on:	NetBSD (except for the first and second item)
MFC after:	2 weeks
This commit is contained in:
Marius Strobl 2006-11-28 01:01:02 +00:00
parent 1f4308521e
commit fb58dc87ca
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=164708

View File

@ -117,6 +117,7 @@ DRIVER_MODULE(nsphy, miibus, nsphy_driver, nsphy_devclass, 0, 0);
static int nsphy_service(struct mii_softc *, struct mii_data *, int);
static void nsphy_status(struct mii_softc *);
static void nsphy_reset(struct mii_softc *);
static int
nsphy_probe(device_t dev)
@ -128,7 +129,7 @@ nsphy_probe(device_t dev)
if (MII_OUI(ma->mii_id1, ma->mii_id2) == MII_OUI_NATSEMI &&
MII_MODEL(ma->mii_id2) == MII_MODEL_NATSEMI_DP83840) {
device_set_desc(dev, MII_STR_NATSEMI_DP83840);
} else
} else
return (ENXIO);
return (BUS_PROBE_DEFAULT);
@ -140,6 +141,7 @@ nsphy_attach(device_t dev)
struct mii_softc *sc;
struct mii_attach_args *ma;
struct mii_data *mii;
const char *nic;
sc = device_get_softc(dev);
ma = device_get_ivars(dev);
@ -152,38 +154,51 @@ nsphy_attach(device_t dev)
sc->mii_service = nsphy_service;
sc->mii_pdata = mii;
#ifdef foo
/*
* i82557 wedges if all of its PHYs are isolated!
*/
if (strcmp(device_get_name(device_get_parent(sc->mii_dev)),
"fxp") == 0 && mii->mii_instance == 0)
#endif
sc->mii_flags |= MIIF_NOISOLATE;
mii->mii_instance++;
nic = device_get_name(device_get_parent(sc->mii_dev));
/*
* Am79C971 and i82557 wedge when isolating all of their
* (external) PHYs.
*/
if (strcmp(nic, "fxp") == 0 || strcmp(nic, "pcn") == 0)
sc->mii_flags |= MIIF_NOISOLATE;
/*
* DP83840A used with HME chips don't advertise their media
* capabilities themselves properly so force writing the ANAR
* according to the BMSR in mii_phy_setmedia().
*/
if (strcmp(nic, "hme") == 0)
sc->mii_flags |= MIIF_FORCEANEG;
#define ADD(m, c) ifmedia_add(&mii->mii_media, (m), (c), NULL)
#if 0
/* Can't do this on the i82557! */
ADD(IFM_MAKEWORD(IFM_ETHER, IFM_NONE, 0, sc->mii_inst),
BMCR_ISO);
/*
* In order for MII loopback to work Am79C971 and greater PCnet
* chips additionally need to be placed into external loopback
* mode which pcn(4) doesn't do so far.
*/
if (strcmp(nic, "pcn") != 0)
#if 1
ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_TX, IFM_LOOP,
sc->mii_inst), BMCR_LOOP|BMCR_S100);
#else
if (strcmp(nic, "pcn") == 0)
sc->mii_flags |= MIIF_NOLOOP;
#endif
ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_TX, IFM_LOOP, sc->mii_inst),
BMCR_LOOP|BMCR_S100);
mii_phy_reset(sc);
nsphy_reset(sc);
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");
#undef ADD
MIIBUS_MEDIAINIT(sc->mii_dev);
return(0);
return (0);
}
static int
@ -191,7 +206,6 @@ nsphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd)
{
struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
int reg;
device_t parent;
switch (cmd) {
case MII_POLLSTAT:
@ -219,8 +233,6 @@ nsphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd)
if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
break;
parent = device_get_parent(sc->mii_dev);
reg = PHY_READ(sc, MII_NSPHY_PCR);
/*
@ -254,36 +266,10 @@ nsphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd)
*/
reg |= 0x0100 | 0x0400;
if (strcmp(device_get_name(parent), "fxp") == 0)
if (strcmp(mii->mii_ifp->if_dname, "fxp") == 0)
PHY_WRITE(sc, MII_NSPHY_PCR, reg);
switch (IFM_SUBTYPE(ife->ifm_media)) {
case IFM_AUTO:
/*
* If we're already in auto mode and don't hang off
* of a hme(4), just return. DP83840A on hme(4) don't
* advertise their media capabilities themselves
* properly so force writing the ANAR according to
* the BMSR by mii_phy_auto() every time.
*/
if ((PHY_READ(sc, MII_BMCR) & BMCR_AUTOEN) == 0 &&
strcmp(device_get_name(parent), "hme") != 0)
return (0);
(void) mii_phy_auto(sc);
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:
@ -309,6 +295,7 @@ static void
nsphy_status(struct mii_softc *sc)
{
struct mii_data *mii = sc->mii_pdata;
struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
int bmsr, bmcr, par, anlpar;
mii->mii_media_status = IFM_AVALID;
@ -378,5 +365,46 @@ nsphy_status(struct mii_softc *sc)
mii->mii_media_active |= IFM_FDX;
#endif
} else
mii->mii_media_active |= mii_media_from_bmcr(bmcr);
mii->mii_media_active = ife->ifm_media;
}
static void
nsphy_reset(struct mii_softc *sc)
{
struct ifmedia_entry *ife = sc->mii_pdata->mii_media.ifm_cur;
int reg, i;
if (sc->mii_flags & MIIF_NOISOLATE)
reg = BMCR_RESET;
else
reg = BMCR_RESET | BMCR_ISO;
PHY_WRITE(sc, MII_BMCR, reg);
/*
* Give it a little time to settle in case we just got power.
* The DP83840A data sheet suggests that a soft reset should not
* happen within 500us of power being applied. Be conservative.
*/
DELAY(1000);
/*
* Wait another 2s for it to complete.
* This is only a little overkill as under normal circumstances
* the PHY can take up to 1s to complete reset.
* This is also a bit odd because after a reset, the BMCR will
* clear the reset bit and simply reports 0 even though the reset
* is not yet complete.
*/
for (i = 0; i < 1000; i++) {
reg = PHY_READ(sc, MII_BMCR);
if (reg != 0 && (reg & BMCR_RESET) == 0)
break;
DELAY(2000);
}
if ((sc->mii_flags & MIIF_NOISOLATE) == 0) {
if ((ife == NULL && sc->mii_inst != 0) ||
(ife != NULL && IFM_INST(ife->ifm_media) != sc->mii_inst))
PHY_WRITE(sc, MII_BMCR, reg | BMCR_ISO);
}
}