Author: marius
Date: Sun Sep 20 12:08:29 2009
New Revision: 197343
URL: http://svn.freebsd.org/changeset/base/197343

Log:
  MFC: 194246, 194904, 194973
  
  Add cas(4), a driver for Sun Cassini/Cassini+ and National Semiconductor
  DP83065 Saturn Gigabit Ethernet controllers. These are the successors
  of the Sun GEM controllers and still have a similar but extended transmit
  logic. As such this driver is based on gem(4).
  Thanks to marcel@ for providing a Sun Quad GigaSwift Ethernet UTP (QGE)
  card which was vital for getting this driver to work on architectures
  not using Open Firmware.

Added:
  stable/7/sys/dev/cas/
     - copied from r194246, head/sys/dev/cas/
  stable/7/sys/modules/cas/
     - copied from r194246, head/sys/modules/cas/
Modified:
  stable/7/sys/   (props changed)
  stable/7/sys/boot/forth/loader.conf
  stable/7/sys/conf/NOTES
  stable/7/sys/conf/files
  stable/7/sys/contrib/pf/   (props changed)
  stable/7/sys/dev/cas/if_cas.c
  stable/7/sys/dev/cas/if_casvar.h
  stable/7/sys/modules/Makefile
  stable/7/sys/sparc64/conf/GENERIC

Modified: stable/7/sys/boot/forth/loader.conf
==============================================================================
--- stable/7/sys/boot/forth/loader.conf Sun Sep 20 11:33:39 2009        
(r197342)
+++ stable/7/sys/boot/forth/loader.conf Sun Sep 20 12:08:29 2009        
(r197343)
@@ -220,6 +220,7 @@ if_axe_load="NO"            # ASIX Electronics AX8
 if_bce_load="NO"               # Broadcom NetXtreme II Gigabit Ethernet
 if_bfe_load="NO"               # Broadcom BCM4401
 if_bge_load="NO"               # Broadcom BCM570x PCI Gigabit Ethernet
+if_cas_load="NO"               # Sun Cassini/Cassini+ and NS DP83065 Saturn
 if_cm_load="NO"                        # SMC (90c26, 90c56, 90c66)
 if_cs_load="NO"                        # Crystal Semiconductor CS8920
 if_cue_load="NO"               # CATC USB-EL1210A USB Ethernet

Modified: stable/7/sys/conf/NOTES
==============================================================================
--- stable/7/sys/conf/NOTES     Sun Sep 20 11:33:39 2009        (r197342)
+++ stable/7/sys/conf/NOTES     Sun Sep 20 12:08:29 2009        (r197343)
@@ -1733,6 +1733,7 @@ device            miibus
 #      BCM570x family of controllers, including the 3Com 3c996-T,
 #      the Netgear GA302T, the SysKonnect SK-9D21 and SK-9D41, and
 #      the embedded gigE NICs on Dell PowerEdge 2550 servers.
+# cas: Sun Cassini/Cassini+ and National Semiconductor DP83065 Saturn
 # cm:  Arcnet SMC COM90c26 / SMC COM90c56
 #      (and SMC COM90c66 in '56 compatibility mode) adapters.
 # cnw:  Xircom CNW/Netware Airsurfer PC Card adapter
@@ -1875,6 +1876,7 @@ device            ale             # Atheros 
AR8121/AR8113/AR8
 device         bce             # Broadcom BCM5706/BCM5708 Gigabit Ethernet
 device         bfe             # Broadcom BCM440x 10/100 Ethernet
 device         bge             # Broadcom BCM570xx Gigabit Ethernet
+device         cas             # Sun Cassini/Cassini+ and NS DP83065 Saturn
 device         cxgb            # Chelsio T3 10 Gigabit Ethernet
 device         dc              # DEC/Intel 21143 and various workalikes
 device         et              # Agere ET1310 10/100/Gigabit Ethernet

Modified: stable/7/sys/conf/files
==============================================================================
--- stable/7/sys/conf/files     Sun Sep 20 11:33:39 2009        (r197342)
+++ stable/7/sys/conf/files     Sun Sep 20 12:08:29 2009        (r197343)
@@ -671,6 +671,7 @@ dev/buslogic/bt_pci.c               optional bt pci
 dev/cardbus/cardbus.c          optional cardbus
 dev/cardbus/cardbus_cis.c      optional cardbus
 dev/cardbus/cardbus_device.c   optional cardbus
+dev/cas/if_cas.c               optional cas
 dev/ciss/ciss.c                        optional ciss
 dev/cm/smc90cx6.c              optional cm
 dev/cmx/cmx.c                  optional cmx

Modified: stable/7/sys/dev/cas/if_cas.c
==============================================================================
--- head/sys/dev/cas/if_cas.c   Mon Jun 15 18:22:41 2009        (r194246)
+++ stable/7/sys/dev/cas/if_cas.c       Sun Sep 20 12:08:29 2009        
(r197343)
@@ -57,7 +57,7 @@ __FBSDID("$FreeBSD$");
 #include <sys/rman.h>
 #include <sys/socket.h>
 #include <sys/sockio.h>
-#include <sys/rman.h>
+#include <sys/taskqueue.h>
 
 #include <net/bpf.h>
 #include <net/ethernet.h>
@@ -135,7 +135,8 @@ static void cas_free(void *arg1, void* a
 static void    cas_init(void *xsc);
 static void    cas_init_locked(struct cas_softc *sc);
 static void    cas_init_regs(struct cas_softc *sc);
-static void    cas_intr(void *v);
+static int     cas_intr(void *v);
+static void    cas_intr_task(void *arg, int pending __unused);
 static int     cas_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data);
 static int     cas_load_txmbuf(struct cas_softc *sc, struct mbuf **m_head);
 static int     cas_mediachange(struct ifnet *ifp);
@@ -159,13 +160,13 @@ static void       cas_rxdma_callback(void *xsc
                    int nsegs, int error);
 static void    cas_setladrf(struct cas_softc *sc);
 static void    cas_start(struct ifnet *ifp);
-static void    cas_start_locked(struct ifnet *ifp);
 static void    cas_stop(struct ifnet *ifp);
 static void    cas_suspend(struct cas_softc *sc);
 static void    cas_tick(void *arg);
 static void    cas_tint(struct cas_softc *sc);
+static void    cas_tx_task(void *arg, int pending __unused);
 static inline void cas_txkick(struct cas_softc *sc);
-static int     cas_watchdog(struct cas_softc *sc);
+static void    cas_watchdog(struct cas_softc *sc);
 
 static devclass_t cas_devclass;
 
@@ -201,7 +202,19 @@ cas_attach(struct cas_softc *sc)
        IFQ_SET_READY(&ifp->if_snd);
 
        callout_init_mtx(&sc->sc_tick_ch, &sc->sc_mtx, 0);
-       callout_init_mtx(&sc->sc_rx_ch, &sc->sc_mtx, 0);
+       callout_init(&sc->sc_rx_ch, 1);
+       /* Create local taskq. */
+       TASK_INIT(&sc->sc_intr_task, 0, cas_intr_task, sc);
+       TASK_INIT(&sc->sc_tx_task, 1, cas_tx_task, ifp);
+       sc->sc_tq = taskqueue_create_fast("cas_taskq", M_WAITOK,
+           taskqueue_thread_enqueue, &sc->sc_tq);
+       if (sc->sc_tq == NULL) {
+               device_printf(sc->sc_dev, "could not create taskqueue\n");
+               error = ENXIO;
+               goto fail_ifnet;
+       }
+       taskqueue_start_threads(&sc->sc_tq, 1, PI_NET, "%s taskq",
+           device_get_nameunit(sc->sc_dev));
 
        /* Make sure the chip is stopped. */
        cas_reset(sc);
@@ -211,7 +224,7 @@ cas_attach(struct cas_softc *sc)
            BUS_SPACE_MAXSIZE, 0, BUS_SPACE_MAXSIZE, 0, NULL, NULL,
            &sc->sc_pdmatag);
        if (error != 0)
-               goto fail_ifnet;
+               goto fail_taskq;
 
        error = bus_dma_tag_create(sc->sc_pdmatag, 1, 0,
            BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, NULL, NULL,
@@ -422,6 +435,8 @@ cas_attach(struct cas_softc *sc)
        bus_dma_tag_destroy(sc->sc_rdmatag);
  fail_ptag:
        bus_dma_tag_destroy(sc->sc_pdmatag);
+ fail_taskq:
+       taskqueue_free(sc->sc_tq);
  fail_ifnet:
        if_free(ifp);
        return (error);
@@ -433,13 +448,16 @@ cas_detach(struct cas_softc *sc)
        struct ifnet *ifp = sc->sc_ifp;
        int i;
 
+       ether_ifdetach(ifp);
        CAS_LOCK(sc);
        cas_stop(ifp);
        CAS_UNLOCK(sc);
        callout_drain(&sc->sc_tick_ch);
        callout_drain(&sc->sc_rx_ch);
-       ether_ifdetach(ifp);
+       taskqueue_drain(sc->sc_tq, &sc->sc_intr_task);
+       taskqueue_drain(sc->sc_tq, &sc->sc_tx_task);
        if_free(ifp);
+       taskqueue_free(sc->sc_tq);
        device_delete_child(sc->sc_dev, sc->sc_miibus);
 
        for (i = 0; i < CAS_NRXDESC; i++)
@@ -586,12 +604,11 @@ static void
 cas_tick(void *arg)
 {
        struct cas_softc *sc = arg;
-       struct ifnet *ifp;
+       struct ifnet *ifp = sc->sc_ifp;
        uint32_t v;
 
        CAS_LOCK_ASSERT(sc, MA_OWNED);
 
-       ifp = sc->sc_ifp;
        /*
         * Unload collision and error counters.
         */
@@ -622,8 +639,10 @@ cas_tick(void *arg)
 
        mii_tick(sc->sc_mii);
 
-       if (cas_watchdog(sc) == EJUSTRETURN)
-               return;
+       if (sc->sc_txfree != CAS_MAXTXFREE)
+               cas_tint(sc);
+
+       cas_watchdog(sc);
 
        callout_reset(&sc->sc_tick_ch, hz, cas_tick, sc);
 }
@@ -915,6 +934,9 @@ cas_init_locked(struct cas_softc *sc)
 
        CAS_LOCK_ASSERT(sc, MA_OWNED);
 
+       if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0)
+               return;
+
 #ifdef CAS_DEBUG
        CTR2(KTR_CAS, "%s: %s: calling stop", device_get_name(sc->sc_dev),
            __func__);
@@ -994,7 +1016,7 @@ cas_init_locked(struct cas_softc *sc)
 
        /* Set up interrupts. */
        CAS_WRITE_4(sc, CAS_INTMASK,
-           ~(CAS_INTR_TX_INT_ME | CAS_INTR_TX_ALL | CAS_INTR_TX_TAG_ERR |
+           ~(CAS_INTR_TX_INT_ME | CAS_INTR_TX_TAG_ERR |
            CAS_INTR_RX_DONE | CAS_INTR_RX_BUF_NA | CAS_INTR_RX_TAG_ERR |
            CAS_INTR_RX_COMP_FULL | CAS_INTR_RX_BUF_AEMPTY |
            CAS_INTR_RX_COMP_AFULL | CAS_INTR_RX_LEN_MMATCH |
@@ -1003,6 +1025,8 @@ cas_init_locked(struct cas_softc *sc)
            | CAS_INTR_PCS_INT | CAS_INTR_MIF
 #endif
            ));
+       /* Don't clear top level interrupts when CAS_STATUS_ALIAS is read. */
+       CAS_WRITE_4(sc, CAS_CLEAR_ALIAS, 0);
        CAS_WRITE_4(sc, CAS_MAC_RX_MASK, ~CAS_MAC_RX_OVERFLOW);
        CAS_WRITE_4(sc, CAS_MAC_TX_MASK,
            ~(CAS_MAC_TX_UNDERRUN | CAS_MAC_TX_MAX_PKT_ERR));
@@ -1240,7 +1264,7 @@ cas_load_txmbuf(struct cas_softc *sc, st
        CTR3(KTR_CAS, "%s: start of frame at segment %d, TX %d",
            __func__, seg, nexttx);
 #endif
-       if (sc->sc_txwin += nsegs > CAS_NTXSEGS * 2 / 3) {
+       if (sc->sc_txwin += nsegs > CAS_MAXTXFREE * 2 / 3) {
                sc->sc_txwin = 0;
                sc->sc_txdescs[txs->txs_firstdesc].cd_flags |=
                    htole64(cflags | CAS_TD_START_OF_FRAME | CAS_TD_INT_ME);
@@ -1351,13 +1375,12 @@ cas_init_regs(struct cas_softc *sc)
 }
 
 static void
-cas_start(struct ifnet *ifp)
+cas_tx_task(void *arg, int pending __unused)
 {
-       struct cas_softc *sc = ifp->if_softc;
+       struct ifnet *ifp;
 
-       CAS_LOCK(sc);
-       cas_start_locked(ifp);
-       CAS_UNLOCK(sc);
+       ifp = (struct ifnet *)arg;
+       cas_start(ifp);
 }
 
 static inline void
@@ -1379,17 +1402,22 @@ cas_txkick(struct cas_softc *sc)
 }
 
 static void
-cas_start_locked(struct ifnet *ifp)
+cas_start(struct ifnet *ifp)
 {
        struct cas_softc *sc = ifp->if_softc;
        struct mbuf *m;
        int kicked, ntx;
 
-       CAS_LOCK_ASSERT(sc, MA_OWNED);
+       CAS_LOCK(sc);
 
        if ((ifp->if_drv_flags & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) !=
-           IFF_DRV_RUNNING || (sc->sc_flags & CAS_LINK) == 0)
+           IFF_DRV_RUNNING || (sc->sc_flags & CAS_LINK) == 0) {
+               CAS_UNLOCK(sc);
                return;
+       }
+
+       if (sc->sc_txfree < CAS_MAXTXFREE / 4)
+               cas_tint(sc);
 
 #ifdef CAS_DEBUG
        CTR4(KTR_CAS, "%s: %s: txfree %d, txnext %d",
@@ -1434,6 +1462,8 @@ cas_start_locked(struct ifnet *ifp)
                    sc->sc_wdog_timer);
 #endif
        }
+
+       CAS_UNLOCK(sc);
 }
 
 static void
@@ -1530,17 +1560,10 @@ cas_tint(struct cas_softc *sc)
 #endif
 
        if (progress) {
-               if (sc->sc_txfree == CAS_NTXDESC - 1)
-                       sc->sc_txwin = 0;
-
-               /*
-                * We freed some descriptors, so reset IFF_DRV_OACTIVE
-                * and restart.
-                */
+               /* We freed some descriptors, so reset IFF_DRV_OACTIVE. */
                ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
                if (STAILQ_EMPTY(&sc->sc_txdirtyq))
                        sc->sc_wdog_timer = 0;
-               cas_start_locked(ifp);
        }
 
 #ifdef CAS_DEBUG
@@ -1554,7 +1577,7 @@ cas_rint_timeout(void *arg)
 {
        struct cas_softc *sc = arg;
 
-       CAS_LOCK_ASSERT(sc, MA_OWNED);
+       CAS_LOCK_ASSERT(sc, MA_NOTOWNED);
 
        cas_rint(sc);
 }
@@ -1569,7 +1592,7 @@ cas_rint(struct cas_softc *sc)
        uint32_t rxhead;
        u_int idx, idx2, len, off, skip;
 
-       CAS_LOCK_ASSERT(sc, MA_OWNED);
+       CAS_LOCK_ASSERT(sc, MA_NOTOWNED);
 
        callout_stop(&sc->sc_rx_ch);
 
@@ -1674,14 +1697,16 @@ cas_rint(struct cas_softc *sc)
                                refcount_acquire(&rxds->rxds_refcount);
                                bus_dmamap_sync(sc->sc_rdmatag,
                                    rxds->rxds_dmamap, BUS_DMASYNC_POSTREAD);
+#if __FreeBSD_version < 800016
                                MEXTADD(m, (caddr_t)rxds->rxds_buf +
                                    off * 256 + ETHER_ALIGN, len, cas_free,
-#if __FreeBSD_version < 800016
-                                   rxds,
+                                   rxds, M_RDONLY, EXT_NET_DRV);
 #else
+                               MEXTADD(m, (caddr_t)rxds->rxds_buf +
+                                   off * 256 + ETHER_ALIGN, len, cas_free,
                                    sc, (void *)(uintptr_t)idx,
-#endif
                                    M_RDONLY, EXT_NET_DRV);
+#endif
                                if ((m->m_flags & M_EXT) == 0) {
                                        m_freem(m);
                                        m = NULL;
@@ -1695,9 +1720,7 @@ cas_rint(struct cas_softc *sc)
                                        cas_rxcksum(m, CAS_GET(word4,
                                            CAS_RC4_TCP_CSUM));
                                /* Pass it on. */
-                               CAS_UNLOCK(sc);
                                (*ifp->if_input)(ifp, m);
-                               CAS_LOCK(sc);
                        } else
                                ifp->if_ierrors++;
 
@@ -1719,14 +1742,16 @@ cas_rint(struct cas_softc *sc)
                                m->m_len = min(CAS_PAGE_SIZE - off, len);
                                bus_dmamap_sync(sc->sc_rdmatag,
                                    rxds->rxds_dmamap, BUS_DMASYNC_POSTREAD);
-                               MEXTADD(m, (caddr_t)rxds->rxds_buf + off,
-                                   m->m_len, cas_free,
 #if __FreeBSD_version < 800016
-                                   rxds,
+                               MEXTADD(m, (caddr_t)rxds->rxds_buf + off,
+                                   m->m_len, cas_free, rxds, M_RDONLY,
+                                   EXT_NET_DRV);
 #else
-                                   sc, (void *)(uintptr_t)idx,
+                               MEXTADD(m, (caddr_t)rxds->rxds_buf + off,
+                                   m->m_len, cas_free, sc,
+                                   (void *)(uintptr_t)idx, M_RDONLY,
+                                   EXT_NET_DRV);
 #endif
-                                   M_RDONLY, EXT_NET_DRV);
                                if ((m->m_flags & M_EXT) == 0) {
                                        m_freem(m);
                                        m = NULL;
@@ -1753,14 +1778,16 @@ cas_rint(struct cas_softc *sc)
                                        bus_dmamap_sync(sc->sc_rdmatag,
                                            rxds2->rxds_dmamap,
                                            BUS_DMASYNC_POSTREAD);
-                                       MEXTADD(m2, (caddr_t)rxds2->rxds_buf,
-                                           m2->m_len, cas_free,
 #if __FreeBSD_version < 800016
-                                           rxds2,
+                                       MEXTADD(m2, (caddr_t)rxds2->rxds_buf,
+                                           m2->m_len, cas_free, rxds2,
+                                           M_RDONLY, EXT_NET_DRV);
 #else
+                                       MEXTADD(m2, (caddr_t)rxds2->rxds_buf,
+                                           m2->m_len, cas_free,
                                            sc, (void *)(uintptr_t)idx2,
-#endif
                                            M_RDONLY, EXT_NET_DRV);
+#endif
                                        if ((m2->m_flags & M_EXT) == 0) {
                                                m_freem(m2);
                                                m2 = NULL;
@@ -1781,9 +1808,7 @@ cas_rint(struct cas_softc *sc)
                                        cas_rxcksum(m, CAS_GET(word4,
                                            CAS_RC4_TCP_CSUM));
                                /* Pass it on. */
-                               CAS_UNLOCK(sc);
                                (*ifp->if_input)(ifp, m);
-                               CAS_LOCK(sc);
                        } else
                                ifp->if_ierrors++;
 
@@ -1799,6 +1824,8 @@ cas_rint(struct cas_softc *sc)
 
  skip:
                cas_rxcompinit(&sc->sc_rxcomps[sc->sc_rxcptr]);
+               if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0)
+                       break;
        }
        CAS_CDSYNC(sc, BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
        CAS_WRITE_4(sc, CAS_RX_COMP_TAIL, sc->sc_rxcptr);
@@ -1819,7 +1846,7 @@ cas_free(void *arg1, void *arg2)
 {
        struct cas_rxdsoft *rxds;
        struct cas_softc *sc;
-       u_int idx, locked;
+       u_int idx;
 
 #if __FreeBSD_version < 800016
        rxds = arg2;
@@ -1837,18 +1864,17 @@ cas_free(void *arg1, void *arg2)
         * NB: this function can be called via m_freem(9) within
         * this driver!
         */
-       if ((locked = CAS_LOCK_OWNED(sc)) == 0)
-               CAS_LOCK(sc);
+
        cas_add_rxdesc(sc, idx);
-       if (locked == 0)
-               CAS_UNLOCK(sc);
 }
 
 static inline void
 cas_add_rxdesc(struct cas_softc *sc, u_int idx)
 {
+       u_int locked;
 
-       CAS_LOCK_ASSERT(sc, MA_OWNED);
+       if ((locked = CAS_LOCK_OWNED(sc)) == 0)
+               CAS_LOCK(sc);
 
        bus_dmamap_sync(sc->sc_rdmatag, sc->sc_rxdsoft[idx].rxds_dmamap,
            BUS_DMASYNC_PREREAD);
@@ -1866,13 +1892,19 @@ cas_add_rxdesc(struct cas_softc *sc, u_i
                CAS_WRITE_4(sc, CAS_RX_KICK,
                    (sc->sc_rxdptr + CAS_NRXDESC - 4) & CAS_NRXDESC_MASK);
        }
+
+       if (locked == 0)
+               CAS_UNLOCK(sc);
 }
 
 static void
 cas_eint(struct cas_softc *sc, u_int status)
 {
+       struct ifnet *ifp = sc->sc_ifp;
+
+       CAS_LOCK_ASSERT(sc, MA_NOTOWNED);
 
-       sc->sc_ifp->if_ierrors++;
+       ifp->if_ierrors++;
 
        device_printf(sc->sc_dev, "%s: status 0x%x", __func__, status);
        if ((status & CAS_INTR_PCI_ERROR_INT) != 0) {
@@ -1886,21 +1918,43 @@ cas_eint(struct cas_softc *sc, u_int sta
        }
        printf("\n");
 
-       cas_init_locked(sc);
-       cas_start_locked(sc->sc_ifp);
+       ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
+       cas_init(sc);
+       if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd))
+               taskqueue_enqueue(sc->sc_tq, &sc->sc_tx_task);
 }
 
-static void
+static int
 cas_intr(void *v)
 {
        struct cas_softc *sc = v;
+
+       if (__predict_false((CAS_READ_4(sc, CAS_STATUS_ALIAS) &
+           CAS_INTR_SUMMARY) == 0))
+               return (FILTER_STRAY);
+
+       /* Disable interrupts. */
+       CAS_WRITE_4(sc, CAS_INTMASK, 0xffffffff);
+       taskqueue_enqueue(sc->sc_tq, &sc->sc_intr_task);
+
+       return (FILTER_HANDLED);
+}
+
+static void
+cas_intr_task(void *arg, int pending __unused)
+{
+       struct cas_softc *sc = arg;
+       struct ifnet *ifp = sc->sc_ifp;
        uint32_t status, status2;
 
-       status = CAS_READ_4(sc, CAS_STATUS);
-       if (__predict_false((status & CAS_INTR_SUMMARY) == 0))
+       CAS_LOCK_ASSERT(sc, MA_NOTOWNED);
+
+       if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0)
                return;
 
-       CAS_LOCK(sc);
+       status = CAS_READ_4(sc, CAS_STATUS);
+       if (__predict_false((status & CAS_INTR_SUMMARY) == 0))
+               goto done;
 
 #ifdef CAS_DEBUG
        CTR4(KTR_CAS, "%s: %s: cplt %x, status %x",
@@ -1941,7 +1995,6 @@ cas_intr(void *v)
            (CAS_INTR_TX_TAG_ERR | CAS_INTR_RX_TAG_ERR |
            CAS_INTR_RX_LEN_MMATCH | CAS_INTR_PCI_ERROR_INT)) != 0)) {
                cas_eint(sc, status);
-               CAS_UNLOCK(sc);
                return;
        }
 
@@ -1968,21 +2021,48 @@ cas_intr(void *v)
            (CAS_INTR_RX_DONE | CAS_INTR_RX_BUF_NA | CAS_INTR_RX_COMP_FULL |
            CAS_INTR_RX_BUF_AEMPTY | CAS_INTR_RX_COMP_AFULL)) != 0) {
                cas_rint(sc);
+#ifdef CAS_DEBUG
                if (__predict_false((status &
                    (CAS_INTR_RX_BUF_NA | CAS_INTR_RX_COMP_FULL |
                    CAS_INTR_RX_BUF_AEMPTY | CAS_INTR_RX_COMP_AFULL)) != 0))
                        device_printf(sc->sc_dev,
                            "RX fault, status %x\n", status);
+#endif
        }
 
        if ((status &
-           (CAS_INTR_TX_INT_ME | CAS_INTR_TX_ALL | CAS_INTR_TX_DONE)) != 0)
+           (CAS_INTR_TX_INT_ME | CAS_INTR_TX_ALL | CAS_INTR_TX_DONE)) != 0) {
+               CAS_LOCK(sc);
                cas_tint(sc);
+               CAS_UNLOCK(sc);
+       }
 
-       CAS_UNLOCK(sc);
+       if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0)
+               return;
+       else if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd))
+               taskqueue_enqueue(sc->sc_tq, &sc->sc_tx_task);
+
+       status = CAS_READ_4(sc, CAS_STATUS_ALIAS);
+       if (__predict_false((status & CAS_INTR_SUMMARY) != 0)) {
+               taskqueue_enqueue(sc->sc_tq, &sc->sc_intr_task);
+               return;
+       }
+
+ done:
+       /* Re-enable interrupts. */
+       CAS_WRITE_4(sc, CAS_INTMASK,
+           ~(CAS_INTR_TX_INT_ME | CAS_INTR_TX_TAG_ERR |
+           CAS_INTR_RX_DONE | CAS_INTR_RX_BUF_NA | CAS_INTR_RX_TAG_ERR |
+           CAS_INTR_RX_COMP_FULL | CAS_INTR_RX_BUF_AEMPTY |
+           CAS_INTR_RX_COMP_AFULL | CAS_INTR_RX_LEN_MMATCH |
+           CAS_INTR_PCI_ERROR_INT
+#ifdef CAS_DEBUG
+           | CAS_INTR_PCS_INT | CAS_INTR_MIF
+#endif
+       ));
 }
 
-static int
+static void
 cas_watchdog(struct cas_softc *sc)
 {
        struct ifnet *ifp = sc->sc_ifp;
@@ -2003,7 +2083,7 @@ cas_watchdog(struct cas_softc *sc)
 #endif
 
        if (sc->sc_wdog_timer == 0 || --sc->sc_wdog_timer != 0)
-               return (0);
+               return;
 
        if ((sc->sc_flags & CAS_LINK) != 0)
                device_printf(sc->sc_dev, "device timeout\n");
@@ -2012,9 +2092,10 @@ cas_watchdog(struct cas_softc *sc)
        ++ifp->if_oerrors;
 
        /* Try to get more packets going. */
+       ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
        cas_init_locked(sc);
-       cas_start_locked(ifp);
-       return (EJUSTRETURN);
+       if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd))
+               taskqueue_enqueue(sc->sc_tq, &sc->sc_tx_task);
 }
 
 static void
@@ -2378,7 +2459,8 @@ cas_ioctl(struct ifnet *ifp, u_long cmd,
        case SIOCADDMULTI:
        case SIOCDELMULTI:
                CAS_LOCK(sc);
-               cas_setladrf(sc);
+               if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0)
+                       cas_setladrf(sc);
                CAS_UNLOCK(sc);
                break;
        case SIOCSIFMTU:
@@ -2729,7 +2811,7 @@ cas_pci_attach(device_t dev)
        }
 
        if (bus_setup_intr(dev, sc->sc_res[CAS_RES_INTR], INTR_TYPE_NET |
-           INTR_MPSAFE, NULL, cas_intr, sc, &sc->sc_ih) != 0) {
+           INTR_MPSAFE, cas_intr, NULL, sc, &sc->sc_ih) != 0) {
                device_printf(dev, "failed to set up interrupt\n");
                cas_detach(sc);
                goto fail;

Modified: stable/7/sys/dev/cas/if_casvar.h
==============================================================================
--- head/sys/dev/cas/if_casvar.h        Mon Jun 15 18:22:41 2009        
(r194246)
+++ stable/7/sys/dev/cas/if_casvar.h    Sun Sep 20 12:08:29 2009        
(r197343)
@@ -138,6 +138,9 @@ struct cas_softc {
        u_char          sc_enaddr[ETHER_ADDR_LEN];
        struct callout  sc_tick_ch;     /* tick callout */
        struct callout  sc_rx_ch;       /* delayed RX callout */
+       struct task     sc_intr_task;
+       struct task     sc_tx_task;
+       struct taskqueue        *sc_tq;
        u_int           sc_wdog_timer;  /* watchdog timer */
 
        void            *sc_ih;

Modified: stable/7/sys/modules/Makefile
==============================================================================
--- stable/7/sys/modules/Makefile       Sun Sep 20 11:33:39 2009        
(r197342)
+++ stable/7/sys/modules/Makefile       Sun Sep 20 12:08:29 2009        
(r197343)
@@ -46,6 +46,7 @@ SUBDIR=       ${_3dfx} \
        ${_canbepm} \
        ${_canbus} \
        ${_cardbus} \
+       cas \
        ${_cbb} \
        cd9660 \
        cd9660_iconv \

Modified: stable/7/sys/sparc64/conf/GENERIC
==============================================================================
--- stable/7/sys/sparc64/conf/GENERIC   Sun Sep 20 11:33:39 2009        
(r197342)
+++ stable/7/sys/sparc64/conf/GENERIC   Sun Sep 20 12:08:29 2009        
(r197343)
@@ -164,6 +164,7 @@ device              txp             # 3Com 3cR990 
(``Typhoon'')
 device         miibus          # MII bus support
 #device                bfe             # Broadcom BCM440x 10/100 Ethernet
 device         bge             # Broadcom BCM570xx Gigabit Ethernet
+device         cas             # Sun Cassini/Cassini+ and NS DP83065 Saturn
 device         dc              # DEC/Intel 21143 and various workalikes
 device         fxp             # Intel EtherExpress PRO/100B (82557, 82558)
 device         gem             # Sun GEM/Sun ERI/Apple GMAC
_______________________________________________
[email protected] mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "[email protected]"

Reply via email to