[Midnightbsd-cvs] src: if_hme.c: merge

laffer1 at midnightbsd.org laffer1 at midnightbsd.org
Wed Nov 26 14:00:33 EST 2008


Log Message:
-----------
merge

Modified Files:
--------------
    src/sys/dev/hme:
        if_hme.c (r1.2 -> r1.3)

-------------- next part --------------
Index: if_hme.c
===================================================================
RCS file: /home/cvs/src/sys/dev/hme/if_hme.c,v
retrieving revision 1.2
retrieving revision 1.3
diff -L sys/dev/hme/if_hme.c -L sys/dev/hme/if_hme.c -u -r1.2 -r1.3
--- sys/dev/hme/if_hme.c
+++ sys/dev/hme/if_hme.c
@@ -34,11 +34,11 @@
  * 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>
-__FBSDID("$FreeBSD: src/sys/dev/hme/if_hme.c,v 1.37.2.7 2006/03/24 00:38:07 yongari Exp $");
+__FBSDID("$FreeBSD: src/sys/dev/hme/if_hme.c,v 1.53 2007/05/01 11:50:11 marius Exp $");
 
 /*
  * HME Ethernet module driver.
@@ -104,7 +104,7 @@
 static void	hme_stop(struct hme_softc *);
 static int	hme_ioctl(struct ifnet *, u_long, caddr_t);
 static void	hme_tick(void *);
-static void	hme_watchdog(struct ifnet *);
+static int	hme_watchdog(struct hme_softc *);
 static void	hme_init(void *);
 static void	hme_init_locked(struct hme_softc *);
 static int	hme_add_rxbuf(struct hme_softc *, unsigned int, int);
@@ -115,6 +115,7 @@
 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 **);
@@ -157,8 +158,8 @@
 	if (hme_nerr++ < HME_MAXERR)					\
 		device_printf(dev, __VA_ARGS__);			\
 	if (hme_nerr == HME_MAXERR) {					\
-		device_printf(dev, "too may errors; not reporting any "	\
-		    "more\n");						\
+		device_printf(dev, "too many errors; not reporting "	\
+		    "any more\n");					\
 	}								\
 } while(0)
 
@@ -213,15 +214,16 @@
 	 */
 	size =	4096;
 
-	error = bus_dma_tag_create(NULL, 1, 0, BUS_SPACE_MAXADDR_32BIT,
-	    BUS_SPACE_MAXADDR, NULL, NULL, size, HME_NTXDESC + HME_NRXDESC + 1,
-	    BUS_SPACE_MAXSIZE_32BIT, 0, NULL, NULL, &sc->sc_pdmatag);
+	error = bus_dma_tag_create(bus_get_dma_tag(sc->sc_dev), 1, 0,
+	    BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL, size,
+	    HME_NTXDESC + HME_NRXDESC + 1, BUS_SPACE_MAXSIZE_32BIT, 0,
+	    NULL, NULL, &sc->sc_pdmatag);
 	if (error)
 		goto fail_ifnet;
 
 	error = bus_dma_tag_create(sc->sc_pdmatag, 2048, 0,
 	    BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL, size,
-	    1, BUS_SPACE_MAXSIZE_32BIT, BUS_DMA_ALLOCNOW, busdma_lock_mutex,
+	    1, BUS_SPACE_MAXSIZE_32BIT, 0, busdma_lock_mutex,
 	    &sc->sc_lock, &sc->sc_cdmatag);
 	if (error)
 		goto fail_ptag;
@@ -289,12 +291,10 @@
 	ifp->if_softc = sc;
 	if_initname(ifp, device_get_name(sc->sc_dev),
 	    device_get_unit(sc->sc_dev));
-	ifp->if_mtu = ETHERMTU;
 	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
 	ifp->if_start = hme_start;
 	ifp->if_ioctl = hme_ioctl;
 	ifp->if_init = hme_init;
-	ifp->if_watchdog = hme_watchdog;
 	IFQ_SET_MAXLEN(&ifp->if_snd, HME_NTXQ);
 	ifp->if_snd.ifq_drv_maxlen = HME_NTXQ;
 	IFQ_SET_READY(&ifp->if_snd);
@@ -310,19 +310,21 @@
 
 	/*
 	 * 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),
@@ -464,6 +466,9 @@
 
 	mii_tick(sc->sc_mii);
 
+	if (hme_watchdog(sc) == EJUSTRETURN)
+		return;
+
 	callout_reset(&sc->sc_tick_ch, hz, hme_tick, sc);
 }
 
@@ -474,8 +479,12 @@
 	int n;
 
 	callout_stop(&sc->sc_tick_ch);
+	sc->sc_wdog_timer = 0;
 	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);
@@ -729,7 +738,7 @@
 	HME_MAC_WRITE_4(sc, HME_MACI_TXSIZE, HME_MAX_FRAMESIZE);
 
 	/* Load station MAC address */
-	ea = IFP2ENADDR(sc->sc_ifp);
+	ea = IF_LLADDR(sc->sc_ifp);
 	HME_MAC_WRITE_4(sc, HME_MACI_MACADDR0, (ea[0] << 8) | ea[1]);
 	HME_MAC_WRITE_4(sc, HME_MACI_MACADDR1, (ea[2] << 8) | ea[3]);
 	HME_MAC_WRITE_4(sc, HME_MACI_MACADDR2, (ea[4] << 8) | ea[5]);
@@ -741,7 +750,6 @@
 	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 +841,6 @@
 	/* 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,16 +876,14 @@
 #endif
 
 	/* Set the current media. */
-	/*
-	 * mii_mediachg(sc->sc_mii);
-	 */
+	hme_mediachange_locked(sc);
 
 	/* Start the one second timer. */
+	sc->sc_wdog_timer = 0;
 	callout_reset(&sc->sc_tick_ch, hz, hme_tick, sc);
 
 	ifp->if_drv_flags |= IFF_DRV_RUNNING;
 	ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
-	ifp->if_timer = 0;
 	hme_start_locked(ifp);
 }
 
@@ -936,7 +939,6 @@
 hme_load_txmbuf(struct hme_softc *sc, struct mbuf **m0)
 {
 	struct hme_txdesc *htx;
-	struct mbuf *m, *n;
 	caddr_t txd;
 	int i, pci, si, ri, nseg;
 	u_int32_t flags, cflags = 0;
@@ -944,31 +946,30 @@
 
 	if ((htx = STAILQ_FIRST(&sc->sc_rb.rb_txfreeq)) == NULL)
 		return (-1);
-	m = *m0;
-	if ((m->m_pkthdr.csum_flags & sc->sc_csum_features) != 0)
-		hme_txcksum(m, &cflags);
 	error = bus_dmamap_load_mbuf_sg(sc->sc_tdmatag, htx->htx_dmamap,
-	    m, sc->sc_rb.rb_txsegs, &nseg, 0);
+	    *m0, sc->sc_rb.rb_txsegs, &nseg, 0);
 	if (error == EFBIG) {
-		n = m_defrag(m, M_DONTWAIT);
-		if (n == NULL) {
-			m_freem(m);
-			m = NULL;
+		struct mbuf *m;
+
+		m = m_defrag(*m0, M_DONTWAIT);
+		if (m == NULL) {
+			m_freem(*m0);
+			*m0 = NULL;
 			return (ENOMEM);
 		}
-		m = n;
+		*m0 = m;
 		error = bus_dmamap_load_mbuf_sg(sc->sc_tdmatag, htx->htx_dmamap,
-		    m, sc->sc_rb.rb_txsegs, &nseg, 0);
+		    *m0, sc->sc_rb.rb_txsegs, &nseg, 0);
 		if (error != 0) {
-			m_freem(m);
-			m = NULL;
+			m_freem(*m0);
+			*m0 = NULL;
 			return (error);
 		}
 	} else if (error != 0)
 		return (error);
 	if (nseg == 0) {
-		m_freem(m);
-		m = NULL;
+		m_freem(*m0);
+		*m0 = NULL;
 		return (EIO);
 	}
 	if (sc->sc_rb.rb_td_nbusy + nseg >= HME_NTXDESC) {
@@ -976,6 +977,8 @@
 		/* retry with m_defrag(9)? */
 		return (-2);
 	}
+	if (((*m0)->m_pkthdr.csum_flags & sc->sc_csum_features) != 0)
+		hme_txcksum(*m0, &cflags);
 	bus_dmamap_sync(sc->sc_tdmatag, htx->htx_dmamap, BUS_DMASYNC_PREWRITE);
 
 	si = ri = sc->sc_rb.rb_tdhead;
@@ -1017,7 +1020,7 @@
 
 	STAILQ_REMOVE_HEAD(&sc->sc_rb.rb_txfreeq, htx_q);
 	STAILQ_INSERT_TAIL(&sc->sc_rb.rb_txbusyq, htx, htx_q);
-	htx->htx_m = m;
+	htx->htx_m = *m0;
 
 	/* start the transmission. */
 	HME_ETX_WRITE_4(sc, HME_ETXI_PENDING, HME_ETX_TP_DMAWAKEUP);
@@ -1112,11 +1115,10 @@
 		BPF_MTAP(ifp, m);
 	}
 
-	/* Set watchdog timer if a packet was queued */
 	if (enq > 0) {
 		bus_dmamap_sync(sc->sc_cdmatag, sc->sc_cdmamap,
 		    BUS_DMASYNC_PREWRITE);
-		ifp->if_timer = 5;
+		sc->sc_wdog_timer = 5;
 	}
 }
 
@@ -1169,8 +1171,7 @@
 		STAILQ_INSERT_TAIL(&sc->sc_rb.rb_txfreeq, htx, htx_q);
 		htx = STAILQ_FIRST(&sc->sc_rb.rb_txbusyq);
 	}
-	/* Turn off watchdog if hme(4) transmitted queued packet */
-	ifp->if_timer = sc->sc_rb.rb_td_nbusy > 0 ? 5 : 0;
+	sc->sc_wdog_timer = sc->sc_rb.rb_td_nbusy > 0 ? 5 : 0;
 
 	/* Update ring */
 	sc->sc_rb.rb_tdtail = ri;
@@ -1290,7 +1291,11 @@
 {
 
 	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,25 +1327,27 @@
 	HME_UNLOCK(sc);
 }
 
-
-static void
-hme_watchdog(struct ifnet *ifp)
+static int
+hme_watchdog(struct hme_softc *sc)
 {
-	struct hme_softc *sc = ifp->if_softc;
 #ifdef HMEDEBUG
 	u_int32_t status;
 #endif
 
-	HME_LOCK(sc);
+	HME_LOCK_ASSERT(sc, MA_OWNED);
 #ifdef HMEDEBUG
 	status = HME_SEB_READ_4(sc, HME_SEBI_STAT);
 	CTR1(KTR_HME, "hme_watchdog: status %x", (u_int)status);
 #endif
+
+	if (sc->sc_wdog_timer == 0 || --sc->sc_wdog_timer != 0)
+		return (0);
+
 	device_printf(sc->sc_dev, "device timeout\n");
-	++ifp->if_oerrors;
+	++sc->sc_ifp->if_oerrors;
 
 	hme_init_locked(sc);
-	HME_UNLOCK(sc);
+	return (EJUSTRETURN);
 }
 
 /*
@@ -1351,10 +1358,26 @@
 {
 	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);
+	/*
+	 * 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 +1386,21 @@
 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 +1414,8 @@
 	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 +1425,21 @@
 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 +1465,16 @@
 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 +1495,39 @@
 	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)
 {


More information about the Midnightbsd-cvs mailing list