diff options
| author | pk <pk@NetBSD.org> | 1999-12-21 21:07:42 +0000 |
|---|---|---|
| committer | pk <pk@NetBSD.org> | 1999-12-21 21:07:42 +0000 |
| commit | f037f3be7eed71522bb6a3254c397b81cfbb8ae0 (patch) | |
| tree | 62c8ce5ae2bf846e9b5f18ccd099b1610f6cdb84 /sys/dev | |
| parent | 60332c17b55c2766c73526dcb2a43ec333c34e98 (diff) | |
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.
Diffstat (limited to 'sys/dev')
| -rw-r--r-- | sys/dev/sbus/be.c | 166 |
1 files changed, 135 insertions, 31 deletions
diff --git a/sys/dev/sbus/be.c b/sys/dev/sbus/be.c index 7699a7742e5..bc40391da5f 100644 --- a/sys/dev/sbus/be.c +++ b/sys/dev/sbus/be.c @@ -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) { @@ -318,11 +322,6 @@ beattach(parent, self, aux) } /* - * Initialize transceiver and determine which PHY connection to use. - */ - be_tcvr_init(sc); - - /* * Initialize our media structures and MII info. */ mii->mii_ifp = ifp; @@ -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) |
