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;
 };
 
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to