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:
parent
60332c17b5
commit
f037f3be7e
@ -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)
|
||||
|
Loading…
Reference in New Issue
Block a user