Shuffle some code around to allow two PHYs to attach. Only one PHY can

be used at a time, but it's now possible to select one by using ifconfig(8)'s
`instance' parameter.
This commit is contained in:
pk 1999-12-21 21:07:42 +00:00
parent 60332c17b5
commit f037f3be7e

View File

@ -1,4 +1,4 @@
/* $NetBSD: be.c,v 1.10 1999/12/20 22:23:39 pk Exp $ */
/* $NetBSD: be.c,v 1.11 1999/12/21 21:07:42 pk Exp $ */
/*-
* Copyright (c) 1999 The NetBSD Foundation, Inc.
@ -131,6 +131,7 @@ struct be_softc {
/*struct ifmedia sc_ifmedia; -* interface media */
struct mii_data sc_mii; /* MII media control */
#define sc_media sc_mii.mii_media/* shorthand */
int sc_phys[2]; /* MII instance -> phy */
struct qec_softc *sc_qec; /* QEC parent */
@ -172,7 +173,7 @@ static void be_read __P((struct be_softc *, int, int));
static int be_put __P((struct be_softc *, int, struct mbuf *));
static struct mbuf *be_get __P((struct be_softc *, int, int));
void be_tcvr_init __P((struct be_softc *));
void be_pal_gate __P((struct be_softc *, int));
/* ifmedia callbacks */
void be_ifmedia_sts __P((struct ifnet *, struct ifmediareq *));
@ -221,10 +222,13 @@ beattach(parent, self, aux)
struct be_softc *sc = (struct be_softc *)self;
struct ifnet *ifp = &sc->sc_ethercom.ec_if;
struct mii_data *mii = &sc->sc_mii;
struct mii_softc *child;
int instance;
int node = sa->sa_node;
bus_dma_segment_t seg;
bus_size_t size;
int rseg, error;
u_int32_t v;
extern void myetheraddr __P((u_char *));
if (sa->sa_nreg < 3) {
@ -317,11 +321,6 @@ beattach(parent, self, aux)
return;
}
/*
* Initialize transceiver and determine which PHY connection to use.
*/
be_tcvr_init(sc);
/*
* Initialize our media structures and MII info.
*/
@ -332,23 +331,66 @@ beattach(parent, self, aux)
ifmedia_init(&mii->mii_media, 0, be_ifmedia_upd, be_ifmedia_sts);
if ((sc->sc_conf & BE_CONF_MII) != 0) {
/*
* Initialize transceiver and determine which PHY connection to use.
*/
be_mii_sync(sc);
v = bus_space_read_4(sc->sc_bustag, sc->sc_tr, BE_TRI_MGMTPAL);
instance = 0;
if ((v & MGMT_PAL_EXT_MDIO) != 0) {
mii_phy_probe(&sc->sc_dev, mii, 0xffffffff, BE_PHY_EXTERNAL,
MII_OFFSET_ANY);
if (LIST_FIRST(&sc->sc_mii.mii_phys) == NULL) {
child = LIST_FIRST(&mii->mii_phys);
if (child == NULL) {
/* No PHY attached */
ifmedia_add(&sc->sc_media, IFM_ETHER|IFM_NONE, 0, NULL);
ifmedia_set(&sc->sc_media, IFM_ETHER|IFM_NONE);
ifmedia_add(&sc->sc_media,
IFM_MAKEWORD(IFM_ETHER,IFM_NONE,0,instance),
0, NULL);
ifmedia_set(&sc->sc_media,
IFM_MAKEWORD(IFM_ETHER,IFM_NONE,0,instance));
} else {
/*
* Note: we support just one PHY on the external
* MII connector.
*/
#ifdef DIAGNOSTIC
if (LIST_NEXT(child, mii_list) != NULL) {
printf("%s: spurious MII device %s attached\n",
sc->sc_dev.dv_xname,
child->mii_dev.dv_xname);
}
#endif
if (child->mii_phy != BE_PHY_EXTERNAL ||
child->mii_inst > 0) {
printf("%s: cannot accomodate MII device %s"
" at phy %d, instance %d\n",
sc->sc_dev.dv_xname,
child->mii_dev.dv_xname,
child->mii_phy, child->mii_inst);
} else {
sc->sc_phys[instance] = child->mii_phy;
}
/*
* XXX - we can really do the following ONLY if the
* phy indeed has the auto negotiation capability!!
*/
ifmedia_set(&sc->sc_media, IFM_ETHER|IFM_AUTO);
ifmedia_set(&sc->sc_media,
IFM_MAKEWORD(IFM_ETHER,IFM_AUTO,0,instance));
/* Mark our current media setting */
be_pal_gate(sc, BE_PHY_EXTERNAL);
sc->sc_conf |= BE_CONF_MII;
instance++;
}
} else {
}
if ((v & MGMT_PAL_INT_MDIO) != 0) {
/*
* The be internal phy looks vaguely like MII hardware,
* but not enough to be able to use the MII device
@ -356,23 +398,35 @@ beattach(parent, self, aux)
* ourselves.
*/
sc->sc_phys[instance] = BE_PHY_INTERNAL;
/* Use `ifm_data' to store BMCR bits */
ifmedia_add(&sc->sc_media,
IFM_MAKEWORD(IFM_ETHER,IFM_10_T,0,0),
IFM_MAKEWORD(IFM_ETHER,IFM_10_T,0,instance),
0, NULL);
ifmedia_add(&sc->sc_media,
IFM_MAKEWORD(IFM_ETHER,IFM_10_T,IFM_FDX,0),
IFM_MAKEWORD(IFM_ETHER,IFM_10_T,IFM_FDX,instance),
BMCR_FDX, NULL);
ifmedia_add(&sc->sc_media,
IFM_MAKEWORD(IFM_ETHER,IFM_100_TX,0,0),
IFM_MAKEWORD(IFM_ETHER,IFM_100_TX,0,instance),
BMCR_S100, NULL);
ifmedia_add(&sc->sc_media,
IFM_MAKEWORD(IFM_ETHER,IFM_100_TX,IFM_FDX,0),
IFM_MAKEWORD(IFM_ETHER,IFM_100_TX,IFM_FDX,instance),
BMCR_S100|BMCR_FDX, NULL);
ifmedia_add(&sc->sc_media,
IFM_MAKEWORD(IFM_ETHER,IFM_AUTO,0,0),
IFM_MAKEWORD(IFM_ETHER,IFM_AUTO,0,instance),
0, NULL);
ifmedia_set(&sc->sc_media, IFM_ETHER|IFM_AUTO);
/* Only set default medium here if there's no external PHY */
if (instance == 0) {
be_pal_gate(sc, BE_PHY_INTERNAL);
ifmedia_set(&sc->sc_media,
IFM_MAKEWORD(IFM_ETHER,IFM_AUTO,0,instance));
} else {
/* Isolate internal transceiver */
be_mii_writereg((struct device *)sc,
BE_PHY_INTERNAL, MII_BMCR, BMCR_ISO);
}
}
bcopy(sc->sc_dev.dv_xname, ifp->if_xname, IFNAMSIZ);
@ -388,8 +442,7 @@ beattach(parent, self, aux)
ether_ifattach(ifp, sc->sc_enaddr);
#if NBPFILTER > 0
bpfattach(&ifp->if_bpf, ifp, DLT_EN10MB,
sizeof(struct ether_header));
bpfattach(&ifp->if_bpf, ifp, DLT_EN10MB, sizeof(struct ether_header));
#endif
}
@ -1010,9 +1063,8 @@ beinit(sc)
s = splimp();
qec_meminit(&sc->sc_rb, BE_PKT_BUF_SZ);
be_tcvr_init(sc);
be_ifmedia_upd(ifp);
be_mii_sync(sc);
bestop(sc);
@ -1194,10 +1246,31 @@ be_mii_sync(sc)
}
}
void
be_pal_gate(sc, phy)
struct be_softc *sc;
int phy;
{
bus_space_tag_t t = sc->sc_bustag;
bus_space_handle_t tr = sc->sc_tr;
u_int32_t v;
be_mii_sync(sc);
v = ~(TCVR_PAL_EXTLBACK | TCVR_PAL_MSENSE | TCVR_PAL_LTENABLE);
if (phy == BE_PHY_INTERNAL)
v &= ~TCVR_PAL_SERIAL;
bus_space_write_4(t, tr, BE_TRI_TCVRPAL, v);
(void)bus_space_read_4(t, tr, BE_TRI_TCVRPAL);
}
#if 0
/*
* Initialize the transceiver and figure out whether we're using the
* external or internal one.
*/
void be_tcvr_init(struct be_softc *);
void
be_tcvr_init(sc)
struct be_softc *sc;
@ -1250,7 +1323,7 @@ be_tcvr_init(sc)
sc->sc_dev.dv_xname);
}
}
#endif
static int
be_tcvr_read_bit(sc, phy)
@ -1409,10 +1482,14 @@ be_mii_statchg(self)
struct be_softc *sc = (struct be_softc *)self;
bus_space_tag_t t = sc->sc_bustag;
bus_space_handle_t br = sc->sc_br;
u_int instance;
u_int32_t v;
printf("%s: media_active=%x\n",
self->dv_xname, sc->sc_mii.mii_media_active);
instance = IFM_INST(sc->sc_mii.mii_media.ifm_cur->ifm_media);
#ifdef DIAGNOSTIC
if (instance > 1)
panic("be_mii_statchg: instance %d out of range", instance);
#endif
/* Update duplex mode in TX configuration */
v = bus_space_read_4(t, br, BE_BRI_TXCFG);
@ -1421,6 +1498,9 @@ be_mii_statchg(self)
else
v &= ~BE_BR_TXCFG_FULLDPLX;
bus_space_write_4(t, br, BE_BRI_TXCFG, v);
/* Change to appropriate gate in transceiver PAL */
be_pal_gate(sc, sc->sc_phys[instance]);
}
void
@ -1529,7 +1609,7 @@ be_ifmedia_sts(ifp, ifmr)
bmsr = be_mii_readreg((struct device *)sc, BE_PHY_INTERNAL, MII_BMSR)|
be_mii_readreg((struct device *)sc, BE_PHY_INTERNAL, MII_BMSR);
if (bmsr & BMSR_LINK)
ifmr->ifm_status |= IFM_ACTIVE;
media_status |= IFM_ACTIVE;
ifmr->ifm_status = media_status;
ifmr->ifm_active = media_active;
@ -1545,17 +1625,36 @@ be_ifmedia_upd(ifp)
struct be_softc *sc = ifp->if_softc;
struct ifmedia *ifm = &sc->sc_media;
int newmedia = ifm->ifm_media;
int n, error, phy, bmcr;
int n, error, bmcr;
char *speed, *mode;
bus_space_tag_t t;
bus_space_handle_t br;
u_int32_t v;
u_int instance, phy;
instance = IFM_INST(sc->sc_mii.mii_media.ifm_cur->ifm_media);
#ifdef DIAGNOSTIC
if (instance > 1)
panic("be_mii_statchg: instance %d out of range", instance);
#endif
phy = sc->sc_phys[instance];
if (IFM_TYPE(newmedia) != IFM_ETHER)
return (EINVAL);
if ((sc->sc_conf & BE_CONF_MII) != 0)
return (mii_mediachg(&sc->sc_mii));
if ((error = mii_mediachg(&sc->sc_mii)) != 0)
return (error);
if (phy == BE_PHY_EXTERNAL) {
/* Isolate the internal transceiver */
be_mii_writereg((struct device *)sc,
BE_PHY_INTERNAL, MII_BMCR, BMCR_ISO);
sc->sc_conf |= BE_CONF_MII;
return (0);
}
/*
* The rest of this routine is devoted to the
@ -1563,7 +1662,12 @@ be_ifmedia_upd(ifp)
*/
t = sc->sc_bustag;
br = sc->sc_br;
phy = BE_PHY_INTERNAL;
/* Mark out current configuration */
sc->sc_conf &= ~BE_CONF_MII;
/* Change to appropriate gate in transceiver PAL */
be_pal_gate(sc, phy);
/* Why must we reset the device? */
if ((error = be_mii_reset(sc, phy)) != 0)