Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 1 Sep 2010 21:42:20 +0000 (UTC)
From:      Pyun YongHyeon <yongari@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r212116 - head/sys/dev/sis
Message-ID:  <201009012142.o81LgKNu082256@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: yongari
Date: Wed Sep  1 21:42:19 2010
New Revision: 212116
URL: http://svn.freebsd.org/changeset/base/212116

Log:
  Overhaul link state change handling. Previously sis(4) blindly
  configured TX/RX MACs before getting a valid link. After that, when
  link state change callback is called, it called device
  initialization again to reconfigure TX/RX MACs depending on
  resolved link state. This hack created several bad side effects and
  it required more hacks to not collide with sis_tick callback as
  well as disabling switching to currently selected media in device
  initialization. Also it seems sis(4) was used to be a template
  driver for long time so other drivers which was modeled after
  sis(4) also should be changed.
  
  TX/RX MACs are now reconfigured after getting a valid link. Fix for
  short cable error is also applied after getting a link because it's
  only valid when the resolved speed is 100Mbps.
  
  While I'm here slightly reorganize interrupt handler such that
  sis(4) always read SIS_ISR register to see whether the interrupt is
  ours or not. This change removes another hack and make it possible
  to nuke sis_stopped variable in softc.

Modified:
  head/sys/dev/sis/if_sis.c
  head/sys/dev/sis/if_sisreg.h

Modified: head/sys/dev/sis/if_sis.c
==============================================================================
--- head/sys/dev/sis/if_sis.c	Wed Sep  1 20:32:47 2010	(r212115)
+++ head/sys/dev/sis/if_sis.c	Wed Sep  1 21:42:19 2010	(r212116)
@@ -697,10 +697,86 @@ static void
 sis_miibus_statchg(device_t dev)
 {
 	struct sis_softc	*sc;
+	struct mii_data		*mii;
+	struct ifnet		*ifp;
+	uint32_t		reg;
 
 	sc = device_get_softc(dev);
 	SIS_LOCK_ASSERT(sc);
-	sis_initl(sc);
+
+	mii = device_get_softc(sc->sis_miibus);
+	ifp = sc->sis_ifp;
+	if (mii == NULL || ifp == NULL ||
+	    (ifp->if_drv_flags & IFF_DRV_RUNNING) == 0)
+		return;
+
+	sc->sis_link = 0;
+	if ((mii->mii_media_status & (IFM_ACTIVE | IFM_AVALID)) ==
+	    (IFM_ACTIVE | IFM_AVALID)) {
+		switch (IFM_SUBTYPE(mii->mii_media_active)) {
+		case IFM_10_T:
+			sc->sis_link++;
+			CSR_WRITE_4(sc, SIS_TX_CFG, SIS_TXCFG_10);
+			break;
+		case IFM_100_TX:
+			sc->sis_link++;
+			CSR_WRITE_4(sc, SIS_TX_CFG, SIS_TXCFG_100);
+			break;
+		default:
+			break;
+		}
+	}
+
+	if (sc->sis_link == 0) {
+		/*
+		 * Stopping MACs seem to reset SIS_TX_LISTPTR and
+		 * SIS_RX_LISTPTR which in turn requires resetting
+		 * TX/RX buffers.  So just don't do anything for
+		 * lost link.
+		 */
+		return;
+	}
+
+	/* Set full/half duplex mode. */
+	if ((IFM_OPTIONS(mii->mii_media_active) & IFM_FDX) != 0) {
+		SIS_SETBIT(sc, SIS_TX_CFG,
+		    (SIS_TXCFG_IGN_HBEAT | SIS_TXCFG_IGN_CARR));
+		SIS_SETBIT(sc, SIS_RX_CFG, SIS_RXCFG_RX_TXPKTS);
+	} else {
+		SIS_CLRBIT(sc, SIS_TX_CFG,
+		    (SIS_TXCFG_IGN_HBEAT | SIS_TXCFG_IGN_CARR));
+		SIS_CLRBIT(sc, SIS_RX_CFG, SIS_RXCFG_RX_TXPKTS);
+	}
+
+	if (sc->sis_type == SIS_TYPE_83816) {
+		/*
+		 * MPII03.D: Half Duplex Excessive Collisions.
+		 * Also page 49 in 83816 manual
+		 */
+		SIS_SETBIT(sc, SIS_TX_CFG, SIS_TXCFG_MPII03D);
+	}
+
+	if (sc->sis_type == SIS_TYPE_83815 && sc->sis_srr < NS_SRR_16A &&
+	    IFM_SUBTYPE(mii->mii_media_active) == IFM_100_TX) {
+		/*
+		 * Short Cable Receive Errors (MP21.E)
+		 */
+		CSR_WRITE_4(sc, NS_PHY_PAGE, 0x0001);
+		reg = CSR_READ_4(sc, NS_PHY_DSPCFG) & 0xfff;
+		CSR_WRITE_4(sc, NS_PHY_DSPCFG, reg | 0x1000);
+		DELAY(100);
+		reg = CSR_READ_4(sc, NS_PHY_TDATA) & 0xff;
+		if ((reg & 0x0080) == 0 || (reg > 0xd8 && reg <= 0xff)) {
+			device_printf(sc->sis_dev,
+			    "Applying short cable fix (reg=%x)\n", reg);
+			CSR_WRITE_4(sc, NS_PHY_TDATA, 0x00e8);
+			SIS_SETBIT(sc, NS_PHY_DSPCFG, 0x20);
+		}
+		CSR_WRITE_4(sc, NS_PHY_PAGE, 0);
+	}
+	/* Enable TX/RX MACs. */
+	SIS_CLRBIT(sc, SIS_CSR, SIS_CSR_TX_DISABLE | SIS_CSR_RX_DISABLE);
+	SIS_SETBIT(sc, SIS_CSR, SIS_CSR_TX_ENABLE | SIS_CSR_RX_ENABLE);
 }
 
 static uint32_t
@@ -1613,23 +1689,14 @@ sis_tick(void *xsc)
 
 	sc = xsc;
 	SIS_LOCK_ASSERT(sc);
-	sc->in_tick = 1;
 	ifp = sc->sis_ifp;
 
 	mii = device_get_softc(sc->sis_miibus);
 	mii_tick(mii);
-
 	sis_watchdog(sc);
-
-	if (!sc->sis_link && mii->mii_media_status & IFM_ACTIVE &&
-	    IFM_SUBTYPE(mii->mii_media_active) != IFM_NONE) {
-		sc->sis_link++;
-		if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd))
-			sis_startl(ifp);
-	}
-
+	if (sc->sis_link == 0)
+		sis_miibus_statchg(sc->sis_dev);
 	callout_reset(&sc->sis_stat_ch, hz,  sis_tick, sc);
-	sc->in_tick = 0;
 }
 
 #ifdef DEVICE_POLLING
@@ -1693,9 +1760,6 @@ sis_intr(void *arg)
 	sc = arg;
 	ifp = sc->sis_ifp;
 
-	if (sc->sis_stopped)	/* Most likely shared interrupt */
-		return;
-
 	SIS_LOCK(sc);
 #ifdef DEVICE_POLLING
 	if (ifp->if_capenable & IFCAP_POLLING) {
@@ -1704,17 +1768,17 @@ sis_intr(void *arg)
 	}
 #endif
 
+	/* Reading the ISR register clears all interrupts. */
+	status = CSR_READ_4(sc, SIS_ISR);
+	if ((status & SIS_INTRS) == 0) {
+		/* Not ours. */
+		SIS_UNLOCK(sc);
+	}
+
 	/* Disable interrupts. */
 	CSR_WRITE_4(sc, SIS_IER, 0);
 
-	for (;;) {
-		SIS_LOCK_ASSERT(sc);
-		/* Reading the ISR register clears all interrupts. */
-		status = CSR_READ_4(sc, SIS_ISR);
-
-		if ((status & SIS_INTRS) == 0)
-			break;
-
+	for (;(status & SIS_INTRS) != 0;) {
 		if (status &
 		    (SIS_ISR_TX_DESC_OK | SIS_ISR_TX_ERR |
 		    SIS_ISR_TX_OK | SIS_ISR_TX_IDLE) )
@@ -1733,7 +1797,10 @@ sis_intr(void *arg)
 		if (status & SIS_ISR_SYSERR) {
 			sis_reset(sc);
 			sis_initl(sc);
+			SIS_UNLOCK(sc);
+			return;
 		}
+		status = CSR_READ_4(sc, SIS_ISR);
 	}
 
 	/* Re-enable interrupts. */
@@ -1908,7 +1975,6 @@ sis_initl(struct sis_softc *sc)
 	 * Cancel pending I/O and free all RX/TX buffers.
 	 */
 	sis_stop(sc);
-	sc->sis_stopped = 0;
 
 #ifdef notyet
 	if (sc->sis_type == SIS_TYPE_83815 && sc->sis_srr >= NS_SRR_16A) {
@@ -1972,7 +2038,6 @@ sis_initl(struct sis_softc *sc)
 		CSR_WRITE_4(sc, NS_PHY_PAGE, 0);
 	}
 
-
 	/*
 	 * For the NatSemi chip, we have to explicitly enable the
 	 * reception of ARP frames, as well as turn on the 'perfect
@@ -2030,52 +2095,11 @@ sis_initl(struct sis_softc *sc)
 	/* Accept Long Packets for VLAN support */
 	SIS_SETBIT(sc, SIS_RX_CFG, SIS_RXCFG_RX_JABBER);
 
-	/* Set TX configuration */
-	if (IFM_SUBTYPE(mii->mii_media_active) == IFM_10_T) {
-		CSR_WRITE_4(sc, SIS_TX_CFG, SIS_TXCFG_10);
-	} else {
-		CSR_WRITE_4(sc, SIS_TX_CFG, SIS_TXCFG_100);
-	}
-
-	/* Set full/half duplex mode. */
-	if ((mii->mii_media_active & IFM_GMASK) == IFM_FDX) {
-		SIS_SETBIT(sc, SIS_TX_CFG,
-		    (SIS_TXCFG_IGN_HBEAT|SIS_TXCFG_IGN_CARR));
-		SIS_SETBIT(sc, SIS_RX_CFG, SIS_RXCFG_RX_TXPKTS);
-	} else {
-		SIS_CLRBIT(sc, SIS_TX_CFG,
-		    (SIS_TXCFG_IGN_HBEAT|SIS_TXCFG_IGN_CARR));
-		SIS_CLRBIT(sc, SIS_RX_CFG, SIS_RXCFG_RX_TXPKTS);
-	}
-
-	if (sc->sis_type == SIS_TYPE_83816) {
-		/*
-		 * MPII03.D: Half Duplex Excessive Collisions.
-		 * Also page 49 in 83816 manual
-		 */
-		SIS_SETBIT(sc, SIS_TX_CFG, SIS_TXCFG_MPII03D);
-	}
-
-	if (sc->sis_type == SIS_TYPE_83815 && sc->sis_srr < NS_SRR_16A &&
-	    IFM_SUBTYPE(mii->mii_media_active) == IFM_100_TX) {
-		uint32_t reg;
-
-		/*
-		 * Short Cable Receive Errors (MP21.E)
-		 */
-		CSR_WRITE_4(sc, NS_PHY_PAGE, 0x0001);
-		reg = CSR_READ_4(sc, NS_PHY_DSPCFG) & 0xfff;
-		CSR_WRITE_4(sc, NS_PHY_DSPCFG, reg | 0x1000);
-		DELAY(100);
-		reg = CSR_READ_4(sc, NS_PHY_TDATA) & 0xff;
-		if ((reg & 0x0080) == 0 || (reg > 0xd8 && reg <= 0xff)) {
-			device_printf(sc->sis_dev,
-			    "Applying short cable fix (reg=%x)\n", reg);
-			CSR_WRITE_4(sc, NS_PHY_TDATA, 0x00e8);
-			SIS_SETBIT(sc, NS_PHY_DSPCFG, 0x20);
-		}
-		CSR_WRITE_4(sc, NS_PHY_PAGE, 0);
-	}
+	/*
+	 * Assume 100Mbps link, actual MAC configuration is done
+	 * after getting a valid link.
+	 */
+	CSR_WRITE_4(sc, SIS_TX_CFG, SIS_TXCFG_100);
 
 	/*
 	 * Enable interrupts.
@@ -2092,19 +2116,16 @@ sis_initl(struct sis_softc *sc)
 #endif
 	CSR_WRITE_4(sc, SIS_IER, 1);
 
-	/* Enable receiver and transmitter. */
-	SIS_CLRBIT(sc, SIS_CSR, SIS_CSR_TX_DISABLE|SIS_CSR_RX_DISABLE);
-	SIS_SETBIT(sc, SIS_CSR, SIS_CSR_RX_ENABLE);
+	/* Clear MAC disable. */
+	SIS_CLRBIT(sc, SIS_CSR, SIS_CSR_TX_DISABLE | SIS_CSR_RX_DISABLE);
 
-#ifdef notdef
+	sc->sis_link = 0;
 	mii_mediachg(mii);
-#endif
 
 	ifp->if_drv_flags |= IFF_DRV_RUNNING;
 	ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
 
-	if (!sc->in_tick)
-		callout_reset(&sc->sis_stat_ch, hz,  sis_tick, sc);
+	callout_reset(&sc->sis_stat_ch, hz,  sis_tick, sc);
 }
 
 /*
@@ -2226,10 +2247,6 @@ sis_watchdog(struct sis_softc *sc)
 {
 
 	SIS_LOCK_ASSERT(sc);
-	if (sc->sis_stopped) {
-		SIS_UNLOCK(sc);
-		return;
-	}
 
 	if (sc->sis_watchdog_timer == 0 || --sc->sis_watchdog_timer >0)
 		return;
@@ -2257,9 +2274,8 @@ sis_stop(struct sis_softc *sc)
 	struct sis_txdesc *txd;
 	int i;
 
-	if (sc->sis_stopped)
-		return;
 	SIS_LOCK_ASSERT(sc);
+
 	ifp = sc->sis_ifp;
 	sc->sis_watchdog_timer = 0;
 
@@ -2303,8 +2319,6 @@ sis_stop(struct sis_softc *sc)
 			txd->tx_m = NULL;
 		}
 	}
-
-	sc->sis_stopped = 1;
 }
 
 /*

Modified: head/sys/dev/sis/if_sisreg.h
==============================================================================
--- head/sys/dev/sis/if_sisreg.h	Wed Sep  1 20:32:47 2010	(r212115)
+++ head/sys/dev/sis/if_sisreg.h	Wed Sep  1 21:42:19 2010	(r212116)
@@ -471,11 +471,9 @@ struct sis_softc {
 	bus_addr_t		sis_tx_paddr;
 	struct callout		sis_stat_ch;
 	int			sis_watchdog_timer;
-	int			sis_stopped;
 #ifdef DEVICE_POLLING
 	int			rxcycles;
 #endif
-	int			in_tick;
 	struct mtx		sis_mtx;
 };
 



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201009012142.o81LgKNu082256>