summaryrefslogtreecommitdiffstats
path: root/sys/dev/hme
diff options
context:
space:
mode:
authormarius <marius@FreeBSD.org>2006-12-04 00:51:08 +0000
committermarius <marius@FreeBSD.org>2006-12-04 00:51:08 +0000
commita7225be573460da3c47edc67365edc182be54162 (patch)
tree505e199bb18f902ee49358f8e8212ce28bb5347e /sys/dev/hme
parent9e0e43febb7a160a25f2c80ee7dfc219e5cf2ddb (diff)
downloadFreeBSD-src-a7225be573460da3c47edc67365edc182be54162.zip
FreeBSD-src-a7225be573460da3c47edc67365edc182be54162.tar.gz
- In hme_stop() mask all interrupts.
- In hme_eint() print MIF register contents on MIF interrupts. - In hme_mifinit() don't bother to preserve the previous MIF config. This was mainly done in order to preserve the PHY select bit (external or internal PHY) but which only needs to be set as appropriate when reading from or writing to the desired PHY in hme_mii_{read,write}reg(). Similarly don't bother to set the PHY select bit in hme_mii_statchg(). - In hme_mii_{read,write}reg() ignore requests to PHYs other than the external and internal PHY one. - Move enabling/disabling the MII drivers of the external transceiver from hme_init_locked() and based on the sheer presence of an external to hme_mifinit() and based on the currently selected media, defaulting to the internal transceiver when the media hasn't been set, yet. Invoke hme_mifinit() from the newly added hme_mediachange_locked() so the setting of the MII drivers is updated when changing media. These changes keep the MII bus from wedging (which manifests in the HME and the PHYs no longer being able to communicate with each other) when the PHY device drivers isolate the unused PHY in two-PHY configurations as present in f.e. Netra t1 100 while changing media, either from hme_init_locked() (see also below) or via ifconfig(8). They also allow for using both transceivers/PHYs. - In the newly added hme_mediachange_locked() also reset the PHYs in two- PHY configurations before invoking mii_mediachg(). This is required for successfully unisolating the previously unused PHY when switching between PHYs. - Now that changing media should no longer cause problems back out rev. 1.27 and re-enable setting the current media in hme_init_locked() (see the commit message of rev. 1.23 for more info). These changes are roughly a merge of NetBSD gem.c rev. 1.32 - 1.35 (1.30 was already fixed differently in our 1.36; 1.31 and 1.32 were wrong) with some parts reworked and things that don't make sense like setting the MII drivers and restoring the previous MIF and XIF settings in hme_mii_{read, write}reg() omitted. MFC after: 2 weeks
Diffstat (limited to 'sys/dev/hme')
-rw-r--r--sys/dev/hme/if_hme.c136
1 files changed, 91 insertions, 45 deletions
diff --git a/sys/dev/hme/if_hme.c b/sys/dev/hme/if_hme.c
index c281e1b..61b021f 100644
--- a/sys/dev/hme/if_hme.c
+++ b/sys/dev/hme/if_hme.c
@@ -34,7 +34,7 @@
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
- * from: NetBSD: hme.c,v 1.29 2002/05/05 03:02:38 thorpej Exp
+ * from: NetBSD: hme.c,v 1.35 2003/02/27 14:58:22 pk Exp
*/
#include <sys/cdefs.h>
@@ -115,6 +115,7 @@ static void hme_mifinit(struct hme_softc *);
static void hme_setladrf(struct hme_softc *, int);
static int hme_mediachange(struct ifnet *);
+static int hme_mediachange_locked(struct hme_softc *);
static void hme_mediastatus(struct ifnet *, struct ifmediareq *);
static int hme_load_txmbuf(struct hme_softc *, struct mbuf **);
@@ -310,19 +311,21 @@ hme_config(struct hme_softc *sc)
/*
* Walk along the list of attached MII devices and
- * establish an `MII instance' to `phy number'
- * mapping. We'll use this mapping in media change
- * requests to determine which phy to use to program
- * the MIF configuration register.
+ * establish an `MII instance' to `PHY number'
+ * mapping. We'll use this mapping to enable the MII
+ * drivers of the external transceiver according to
+ * the currently selected media.
*/
- for (child = LIST_FIRST(&sc->sc_mii->mii_phys); child != NULL;
- child = LIST_NEXT(child, mii_list)) {
+ sc->sc_phys[0] = sc->sc_phys[1] = -1;
+ LIST_FOREACH(child, &sc->sc_mii->mii_phys, mii_list) {
/*
* Note: we support just two PHYs: the built-in
* internal device and an external on the MII
* connector.
*/
- if (child->mii_phy > 1 || child->mii_inst > 1) {
+ if ((child->mii_phy != HME_PHYAD_EXTERNAL &&
+ child->mii_phy != HME_PHYAD_INTERNAL) ||
+ child->mii_inst > 1) {
device_printf(sc->sc_dev, "cannot accommodate "
"MII device %s at phy %d, instance %d\n",
device_get_name(child->mii_dev),
@@ -476,6 +479,9 @@ hme_stop(struct hme_softc *sc)
callout_stop(&sc->sc_tick_ch);
sc->sc_ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE);
+ /* Mask all interrupts */
+ HME_SEB_WRITE_4(sc, HME_SEBI_IMASK, 0xffffffff);
+
/* Reset transmitter and receiver */
HME_SEB_WRITE_4(sc, HME_SEBI_RESET, HME_SEB_RESET_ETX |
HME_SEB_RESET_ERX);
@@ -741,7 +747,6 @@ hme_init_locked(struct hme_softc *sc)
v = ((ea[4] << 8) | ea[5]) & 0x3fff;
HME_MAC_WRITE_4(sc, HME_MACI_RANDSEED, v);
-
/* Note: Accepting power-on default for other MAC registers here.. */
/* step 5. RX MAC registers & counters */
@@ -833,9 +838,6 @@ hme_init_locked(struct hme_softc *sc)
/* step 11. XIF Configuration */
v = HME_MAC_READ_4(sc, HME_MACI_XIF);
v |= HME_MAC_XIF_OE;
- /* If an external transceiver is connected, enable its MII drivers */
- if ((HME_MIF_READ_4(sc, HME_MIFI_CFG) & HME_MIF_CFG_MDI1) != 0)
- v |= HME_MAC_XIF_MIIENABLE;
CTR1(KTR_HME, "hme_init: programming XIF to %x", (u_int)v);
HME_MAC_WRITE_4(sc, HME_MACI_XIF, v);
@@ -871,9 +873,7 @@ hme_init_locked(struct hme_softc *sc)
#endif
/* Set the current media. */
- /*
- * mii_mediachg(sc->sc_mii);
- */
+ hme_mediachange_locked(sc);
/* Start the one second timer. */
callout_reset(&sc->sc_tick_ch, hz, hme_tick, sc);
@@ -1290,7 +1290,11 @@ hme_eint(struct hme_softc *sc, u_int status)
{
if ((status & HME_SEB_STAT_MIFIRQ) != 0) {
- device_printf(sc->sc_dev, "XXXlink status changed\n");
+ device_printf(sc->sc_dev, "XXXlink status changed: "
+ "cfg=%#x, stat=%#x, sm=%#x\n",
+ HME_MIF_READ_4(sc, HME_MIFI_CFG),
+ HME_MIF_READ_4(sc, HME_MIFI_STAT),
+ HME_MIF_READ_4(sc, HME_MIFI_SM));
return;
}
@@ -1322,7 +1326,6 @@ hme_intr(void *v)
HME_UNLOCK(sc);
}
-
static void
hme_watchdog(struct ifnet *ifp)
{
@@ -1351,10 +1354,27 @@ hme_mifinit(struct hme_softc *sc)
{
u_int32_t v;
- /* Configure the MIF in frame mode */
- v = HME_MIF_READ_4(sc, HME_MIFI_CFG);
- v &= ~HME_MIF_CFG_BBMODE;
- HME_MIF_WRITE_4(sc, HME_MIFI_CFG, v);
+ HME_LOCK_ASSERT(sc, MA_OWNED);
+ /*
+ * Configure the MIF in frame mode, polling disabled, internal PHY
+ * selected.
+ */
+ HME_MIF_WRITE_4(sc, HME_MIFI_CFG, 0);
+
+ /*
+ * If the currently selected media uses the external transceiver,
+ * enable its MII drivers (which basically isolates the internal
+ * one and vice versa). In case the current media hasn't been set,
+ * yet, we default to the internal transceiver.
+ */
+ v = HME_MAC_READ_4(sc, HME_MACI_XIF);
+ if (sc->sc_mii != NULL && sc->sc_mii->mii_media.ifm_cur != NULL &&
+ sc->sc_phys[IFM_INST(sc->sc_mii->mii_media.ifm_cur->ifm_media)] ==
+ HME_PHYAD_EXTERNAL)
+ v |= HME_MAC_XIF_MIIENABLE;
+ else
+ v &= ~HME_MAC_XIF_MIIENABLE;
+ HME_MAC_WRITE_4(sc, HME_MACI_XIF, v);
}
/*
@@ -1363,17 +1383,21 @@ hme_mifinit(struct hme_softc *sc)
int
hme_mii_readreg(device_t dev, int phy, int reg)
{
- struct hme_softc *sc = device_get_softc(dev);
+ struct hme_softc *sc;
int n;
u_int32_t v;
+ /* We can at most have two PHYs. */
+ if (phy != HME_PHYAD_EXTERNAL && phy != HME_PHYAD_INTERNAL)
+ return (0);
+
+ sc = device_get_softc(dev);
/* Select the desired PHY in the MIF configuration register */
v = HME_MIF_READ_4(sc, HME_MIFI_CFG);
- /* Clear PHY select bit */
- v &= ~HME_MIF_CFG_PHY;
if (phy == HME_PHYAD_EXTERNAL)
- /* Set PHY select bit to get at external device */
v |= HME_MIF_CFG_PHY;
+ else
+ v &= ~HME_MIF_CFG_PHY;
HME_MIF_WRITE_4(sc, HME_MIFI_CFG, v);
/* Construct the frame command */
@@ -1387,9 +1411,8 @@ hme_mii_readreg(device_t dev, int phy, int reg)
for (n = 0; n < 100; n++) {
DELAY(1);
v = HME_MIF_READ_4(sc, HME_MIFI_FO);
- if (v & HME_MIF_FO_TALSB) {
+ if (v & HME_MIF_FO_TALSB)
return (v & HME_MIF_FO_DATA);
- }
}
device_printf(sc->sc_dev, "mii_read timeout\n");
@@ -1399,17 +1422,21 @@ hme_mii_readreg(device_t dev, int phy, int reg)
int
hme_mii_writereg(device_t dev, int phy, int reg, int val)
{
- struct hme_softc *sc = device_get_softc(dev);
+ struct hme_softc *sc;
int n;
u_int32_t v;
+ /* We can at most have two PHYs. */
+ if (phy != HME_PHYAD_EXTERNAL && phy != HME_PHYAD_INTERNAL)
+ return (0);
+
+ sc = device_get_softc(dev);
/* Select the desired PHY in the MIF configuration register */
v = HME_MIF_READ_4(sc, HME_MIFI_CFG);
- /* Clear PHY select bit */
- v &= ~HME_MIF_CFG_PHY;
if (phy == HME_PHYAD_EXTERNAL)
- /* Set PHY select bit to get at external device */
v |= HME_MIF_CFG_PHY;
+ else
+ v &= ~HME_MIF_CFG_PHY;
HME_MIF_WRITE_4(sc, HME_MIFI_CFG, v);
/* Construct the frame command */
@@ -1435,25 +1462,16 @@ hme_mii_writereg(device_t dev, int phy, int reg, int val)
void
hme_mii_statchg(device_t dev)
{
- struct hme_softc *sc = device_get_softc(dev);
- int instance;
- int phy;
+ struct hme_softc *sc;
u_int32_t v;
- instance = IFM_INST(sc->sc_mii->mii_media.ifm_cur->ifm_media);
- phy = sc->sc_phys[instance];
+ sc = device_get_softc(dev);
+
#ifdef HMEDEBUG
if (sc->sc_debug)
- printf("hme_mii_statchg: status change: phy = %d\n", phy);
+ device_printf(sc->sc_dev, "hme_mii_statchg: status change\n");
#endif
- /* Select the current PHY in the MIF configuration register */
- v = HME_MIF_READ_4(sc, HME_MIFI_CFG);
- v &= ~HME_MIF_CFG_PHY;
- if (phy == HME_PHYAD_EXTERNAL)
- v |= HME_MIF_CFG_PHY;
- HME_MIF_WRITE_4(sc, HME_MIFI_CFG, v);
-
/* Set the MAC Full Duplex bit appropriately */
v = HME_MAC_READ_4(sc, HME_MACI_TXCFG);
if (!hme_mac_bitflip(sc, HME_MACI_TXCFG, v, HME_MAC_TXCFG_ENABLE, 0))
@@ -1474,11 +1492,39 @@ hme_mediachange(struct ifnet *ifp)
int error;
HME_LOCK(sc);
- error = mii_mediachg(sc->sc_mii);
+ error = hme_mediachange_locked(sc);
HME_UNLOCK(sc);
return (error);
}
+static int
+hme_mediachange_locked(struct hme_softc *sc)
+{
+ struct mii_softc *child;
+
+ HME_LOCK_ASSERT(sc, MA_OWNED);
+#ifdef HMEDEBUG
+ if (sc->sc_debug)
+ device_printf(sc->sc_dev, "hme_mediachange_locked");
+#endif
+
+ hme_mifinit(sc);
+
+ /*
+ * If both PHYs are present reset them. This is required for
+ * unisolating the previously isolated PHY when switching PHYs.
+ * As the above hme_mifinit() call will set the MII drivers in
+ * the XIF configuration register accoring to the currently
+ * selected media, there should be no window during which the
+ * data paths of both transceivers are open at the same time,
+ * even if the PHY device drivers use MIIF_NOISOLATE.
+ */
+ if (sc->sc_phys[0] != -1 && sc->sc_phys[1] != -1)
+ LIST_FOREACH(child, &sc->sc_mii->mii_phys, mii_list)
+ mii_phy_reset(child);
+ return (mii_mediachg(sc->sc_mii));
+}
+
static void
hme_mediastatus(struct ifnet *ifp, struct ifmediareq *ifmr)
{
OpenPOWER on IntegriCloud