From owner-svn-src-stable@FreeBSD.ORG Sun Sep 20 12:08:30 2009 Return-Path: Delivered-To: svn-src-stable@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 5DE2B106566C; Sun, 20 Sep 2009 12:08:30 +0000 (UTC) (envelope-from marius@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:4f8:fff6::2c]) by mx1.freebsd.org (Postfix) with ESMTP id 49D8A8FC23; Sun, 20 Sep 2009 12:08:30 +0000 (UTC) Received: from svn.freebsd.org (localhost [127.0.0.1]) by svn.freebsd.org (8.14.3/8.14.3) with ESMTP id n8KC8UrT055806; Sun, 20 Sep 2009 12:08:30 GMT (envelope-from marius@svn.freebsd.org) Received: (from marius@localhost) by svn.freebsd.org (8.14.3/8.14.3/Submit) id n8KC8U0i055798; Sun, 20 Sep 2009 12:08:30 GMT (envelope-from marius@svn.freebsd.org) Message-Id: <200909201208.n8KC8U0i055798@svn.freebsd.org> From: Marius Strobl Date: Sun, 20 Sep 2009 12:08:30 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-7@freebsd.org X-SVN-Group: stable-7 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cc: Subject: svn commit: r197343 - in stable/7/sys: . boot/forth conf contrib/pf dev/cas modules modules/cas sparc64/conf X-BeenThere: svn-src-stable@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: SVN commit messages for all the -stable branches of the src tree List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sun, 20 Sep 2009 12:08:30 -0000 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 #include #include -#include +#include #include #include @@ -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