Enable frobbing the 1000baseT control register on Gig-E PHYs,

used for hard-wiring master mode, and for advertising the 1000baseT
media options during autonegotiation.
This commit is contained in:
thorpej 2001-05-31 18:44:48 +00:00
parent 737585d43c
commit 2128d9199a
2 changed files with 97 additions and 21 deletions

View File

@ -1,7 +1,7 @@
/* $NetBSD: mii_physubr.c,v 1.22 2001/05/31 16:02:29 thorpej Exp $ */
/* $NetBSD: mii_physubr.c,v 1.23 2001/05/31 18:44:48 thorpej Exp $ */
/*-
* Copyright (c) 1998, 1999, 2000 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
@ -58,17 +58,47 @@
/*
* Media to register setting conversion table. Order matters.
* XXX 802.3 doesn't specify ANAR or ANLPAR bits for 1000base.
*/
const struct mii_media mii_media_table[] = {
{ BMCR_ISO, ANAR_CSMA }, /* None */
{ BMCR_S10, ANAR_CSMA|ANAR_10 }, /* 10baseT */
{ BMCR_S10|BMCR_FDX, ANAR_CSMA|ANAR_10_FD }, /* 10baseT-FDX */
{ BMCR_S100, ANAR_CSMA|ANAR_T4 }, /* 100baseT4 */
{ BMCR_S100, ANAR_CSMA|ANAR_TX }, /* 100baseTX */
{ BMCR_S100|BMCR_FDX, ANAR_CSMA|ANAR_TX_FD }, /* 100baseTX-FDX */
{ BMCR_S1000, ANAR_CSMA }, /* 1000base */
{ BMCR_S1000|BMCR_FDX, ANAR_CSMA }, /* 1000base-FDX */
const struct mii_media mii_media_table[MII_NMEDIA] = {
/* None */
{ BMCR_ISO, ANAR_CSMA,
0, },
/* 10baseT */
{ BMCR_S10, ANAR_CSMA|ANAR_10,
0, },
/* 10baseT-FDX */
{ BMCR_S10|BMCR_FDX, ANAR_CSMA|ANAR_10_FD,
0, },
/* 100baseT4 */
{ BMCR_S100, ANAR_CSMA|ANAR_T4,
0, },
/* 100baseTX */
{ BMCR_S100, ANAR_CSMA|ANAR_TX,
0, },
/* 100baseTX-FDX */
{ BMCR_S100|BMCR_FDX, ANAR_CSMA|ANAR_TX_FD,
0, },
/* 1000baseX */
{ BMCR_S1000, ANAR_CSMA,
0, },
/* 1000baseX-FDX */
{ BMCR_S1000|BMCR_FDX, ANAR_CSMA,
0, },
/* 1000baseT */
{ BMCR_S1000, ANAR_CSMA,
GTCR_ADV_1000THDX },
/* 1000baseT-FDX */
{ BMCR_S1000, ANAR_CSMA,
GTCR_ADV_1000TFDX },
};
void mii_phy_auto_timeout __P((void *));
@ -79,7 +109,7 @@ mii_phy_setmedia(sc)
{
struct mii_data *mii = sc->mii_pdata;
struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
int bmcr, anar;
int bmcr, anar, gtcr;
if (IFM_SUBTYPE(ife->ifm_media) == IFM_AUTO) {
if ((PHY_READ(sc, MII_BMCR) & BMCR_AUTOEN) == 0)
@ -98,12 +128,39 @@ mii_phy_setmedia(sc)
anar = mii_media_table[ife->ifm_data].mm_anar;
bmcr = mii_media_table[ife->ifm_data].mm_bmcr;
gtcr = mii_media_table[ife->ifm_data].mm_gtcr;
if (mii->mii_media.ifm_media & IFM_ETH_MASTER) {
switch (IFM_SUBTYPE(ife->ifm_media)) {
case IFM_1000_TX:
gtcr |= GTCR_MAN_MS|GTCR_ADV_MS;
break;
default:
panic("mii_phy_setmedia: MASTER on wrong media");
}
}
if (ife->ifm_media & IFM_LOOP)
bmcr |= BMCR_LOOP;
PHY_WRITE(sc, MII_ANAR, anar);
PHY_WRITE(sc, MII_BMCR, bmcr);
if (sc->mii_flags & MIIF_HAVE_GTCR)
PHY_WRITE(sc, MII_100T2CR, gtcr);
}
static int
mii_phy_extcap_to_gtcr(struct mii_softc *sc)
{
int gtcr = 0;
if (sc->mii_extcapabilities & EXTSR_1000TFDX)
gtcr |= GTCR_ADV_1000TFDX;
if (sc->mii_extcapabilities & EXTSR_1000THDX)
gtcr |= GTCR_ADV_1000THDX;
return (gtcr);
}
int
@ -116,6 +173,8 @@ mii_phy_auto(sc, waitfor)
if ((sc->mii_flags & MIIF_DOINGAUTO) == 0) {
PHY_WRITE(sc, MII_ANAR,
BMSR_MEDIA_TO_ANAR(sc->mii_capabilities) | ANAR_CSMA);
if (sc->mii_flags & MIIF_HAVE_GTCR)
PHY_WRITE(sc, MII_100T2CR, mii_phy_extcap_to_gtcr(sc));
PHY_WRITE(sc, MII_BMCR, BMCR_AUTOEN | BMCR_STARTNEG);
}
@ -378,25 +437,38 @@ mii_phy_add_media(sc)
if (sc->mii_extcapabilities & EXTSR_1000XHDX) {
sc->mii_anegticks = 10;
ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_SX, 0,
sc->mii_inst), MII_MEDIA_1000);
sc->mii_inst), MII_MEDIA_1000_X);
PRINT("1000baseSX");
}
if (sc->mii_extcapabilities & EXTSR_1000XFDX) {
sc->mii_anegticks = 10;
ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_SX, IFM_FDX,
sc->mii_inst), MII_MEDIA_1000_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_TX, 0,
sc->mii_inst), MII_MEDIA_1000);
sc->mii_inst), MII_MEDIA_1000_T);
PRINT("1000baseTX");
}
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_TX, IFM_FDX,
sc->mii_inst), MII_MEDIA_1000_FDX);
sc->mii_inst), MII_MEDIA_1000_T_FDX);
PRINT("1000baseTX-FDX");
}
}

View File

@ -1,4 +1,4 @@
/* $NetBSD: miivar.h,v 1.25 2001/05/31 16:02:29 thorpej Exp $ */
/* $NetBSD: miivar.h,v 1.26 2001/05/31 18:44:48 thorpej Exp $ */
/*-
* Copyright (c) 1998, 1999, 2000 The NetBSD Foundation, Inc.
@ -146,6 +146,7 @@ typedef struct mii_softc mii_softc_t;
#define MIIF_DOINGAUTO 0x0008 /* doing autonegotiation (mii_softc) */
#define MIIF_AUTOTSLEEP 0x0010 /* use tsleep(), not callout() */
#define MIIF_HAVEFIBER 0x0020 /* from parent: has fiber interface */
#define MIIF_HAVE_GTCR 0x0040 /* has 100base-T2/1000base-T CR */
/* XXX ununsed
#define MIIF_INHERIT_MASK (MIIF_NOISOLATE|MIIF_NOLOOP|MIIF_AUTOTSLEEP)
@ -178,6 +179,7 @@ typedef struct mii_attach_args mii_attach_args_t;
struct mii_media {
int mm_bmcr; /* BMCR settings for this media */
int mm_anar; /* ANAR settings for this media */
int mm_gtcr; /* 100base-T2 or 1000base-T CR */
};
#define MII_MEDIA_NONE 0
@ -186,9 +188,11 @@ struct mii_media {
#define MII_MEDIA_100_T4 3
#define MII_MEDIA_100_TX 4
#define MII_MEDIA_100_TX_FDX 5
#define MII_MEDIA_1000 6
#define MII_MEDIA_1000_FDX 7
#define MII_NMEDIA 8
#define MII_MEDIA_1000_X 6
#define MII_MEDIA_1000_X_FDX 7
#define MII_MEDIA_1000_T 8
#define MII_MEDIA_1000_T_FDX 9
#define MII_NMEDIA 10
#ifdef _KERNEL
#include "locators.h"