svn commit: r197343 - in stable/7/sys: . boot/forth conf contrib/pf
dev/cas modules modules/cas sparc64/conf
Marius Strobl
marius at FreeBSD.org
Sun Sep 20 12:08:30 UTC 2009
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
More information about the svn-src-stable-7
mailing list