summaryrefslogtreecommitdiffstats
path: root/sys/dev/smc
diff options
context:
space:
mode:
authorbenno <benno@FreeBSD.org>2008-06-11 07:26:02 +0000
committerbenno <benno@FreeBSD.org>2008-06-11 07:26:02 +0000
commit0b53c9edf1a309162c5fa7973a8284ab5950a8dc (patch)
tree08a58d8c2e2c433490f08cd081ebe3b97dd7651a /sys/dev/smc
parent42775c261161d1244d7da581c0b443351869dac5 (diff)
downloadFreeBSD-src-0b53c9edf1a309162c5fa7973a8284ab5950a8dc.zip
FreeBSD-src-0b53c9edf1a309162c5fa7973a8284ab5950a8dc.tar.gz
Switch to using a normal mutex instead of a spin mutex.
We still use the interrupt filter due to performance problems that show up if we don't. The main problem seen is that, due to the interrupt being edge triggered, we occasionally miss interrupts which leads us to not notice that we can transmit more packets. Using the new approach, which just schedules a task on a taskqueue, we are guaranteed to have the task run even if the interrupt arrived while we were already executing. If we were to use an ithread the system would mask the interrupt while the handler is run and we'd miss interrupts.
Diffstat (limited to 'sys/dev/smc')
-rw-r--r--sys/dev/smc/if_smc.c44
-rw-r--r--sys/dev/smc/if_smcvar.h8
2 files changed, 30 insertions, 22 deletions
diff --git a/sys/dev/smc/if_smc.c b/sys/dev/smc/if_smc.c
index 2dedbc7..966c710 100644
--- a/sys/dev/smc/if_smc.c
+++ b/sys/dev/smc/if_smc.c
@@ -76,6 +76,14 @@ __FBSDID("$FreeBSD$");
#include <dev/mii/mii.h>
#include <dev/mii/miivar.h>
+#define SMC_LOCK(sc) mtx_lock(&(sc)->smc_mtx)
+#define SMC_UNLOCK(sc) mtx_unlock(&(sc)->smc_mtx)
+#define SMC_ASSERT_LOCKED(sc) mtx_assert(&(sc)->smc_mtx, MA_OWNED)
+
+#define SMC_INTR_PRIORITY 0
+#define SMC_RX_PRIORITY 5
+#define SMC_TX_PRIORITY 10
+
devclass_t smc_devclass;
static const char *smc_chip_ids[16] = {
@@ -104,6 +112,7 @@ static void smc_mii_tick(void *);
static void smc_mii_mediachg(struct smc_softc *);
static int smc_mii_mediaioctl(struct smc_softc *, struct ifreq *, u_long);
+static void smc_task_intr(void *, int);
static void smc_task_rx(void *, int);
static void smc_task_tx(void *, int);
@@ -279,7 +288,7 @@ smc_attach(device_t dev)
goto done;
}
- mtx_init(&sc->smc_mtx, device_get_nameunit(dev), NULL, MTX_SPIN);
+ mtx_init(&sc->smc_mtx, device_get_nameunit(dev), NULL, MTX_DEF);
type = SYS_RES_IOPORT;
if (sc->smc_usemem)
@@ -348,6 +357,7 @@ smc_attach(device_t dev)
ether_ifattach(ifp, eaddr);
/* Set up taskqueue */
+ TASK_INIT(&sc->smc_intr, SMC_INTR_PRIORITY, smc_task_intr, ifp);
TASK_INIT(&sc->smc_rx, SMC_RX_PRIORITY, smc_task_rx, ifp);
TASK_INIT(&sc->smc_tx, SMC_TX_PRIORITY, smc_task_tx, ifp);
sc->smc_tq = taskqueue_create_fast("smc_taskq", M_NOWAIT,
@@ -361,7 +371,7 @@ smc_attach(device_t dev)
/* Wire up interrupt */
error = bus_setup_intr(dev, sc->smc_irq,
- INTR_TYPE_NET|INTR_MPSAFE, smc_intr, NULL, ifp, &sc->smc_ih);
+ INTR_TYPE_NET|INTR_MPSAFE, smc_intr, NULL, sc, &sc->smc_ih);
if (error != 0)
goto done;
@@ -381,9 +391,6 @@ smc_detach(device_t dev)
callout_stop(&sc->smc_watchdog);
- if (mtx_initialized(&sc->smc_mtx))
- SMC_LOCK(sc);
-
#ifdef DEVICE_POLLING
if (sc->smc_ifp->if_capenable & IFCAP_POLLING)
ether_poll_deregister(sc->smc_ifp);
@@ -453,9 +460,7 @@ smc_start_locked(struct ifnet *ifp)
/*
* Grab the next packet. If it's too big, drop it.
*/
- SMC_UNLOCK(sc);
IFQ_DRV_DEQUEUE(&ifp->if_snd, m);
- SMC_LOCK(sc);
len = m_length(m, NULL);
len += (len & 1);
if (len > ETHER_MAX_LEN - ETHER_CRC_LEN) {
@@ -595,7 +600,7 @@ smc_task_tx(void *context, int pending)
*/
smc_mmu_wait(sc);
smc_write_2(sc, MMUCR, MMUCR_CMD_ENQUEUE);
- callout_reset(&sc->smc_watchdog, hz * 2, smc_watchdog, ifp);
+ callout_reset(&sc->smc_watchdog, hz * 2, smc_watchdog, sc);
/*
* Finish up.
@@ -743,7 +748,7 @@ smc_poll(struct ifnet *ifp, enum poll_cmd cmd, int count)
SMC_UNLOCK(sc);
if (cmd == POLL_AND_CHECK_STATUS)
- smc_intr(ifp);
+ taskqueue_enqueue_fast(sc->smc_tq, &sc->smc_intr);
}
#endif
@@ -751,9 +756,20 @@ static int
smc_intr(void *context)
{
struct smc_softc *sc;
+
+ sc = (struct smc_softc *)context;
+ taskqueue_enqueue_fast(sc->smc_tq, &sc->smc_intr);
+ return (FILTER_HANDLED);
+}
+
+static void
+smc_task_intr(void *context, int pending)
+{
+ struct smc_softc *sc;
struct ifnet *ifp;
u_int status, packet, counter, tcr;
+ (void)pending;
ifp = (struct ifnet *)context;
sc = ifp->if_softc;
@@ -863,8 +879,6 @@ smc_intr(void *context)
smc_write_1(sc, MSK, sc->smc_mask);
SMC_UNLOCK(sc);
-
- return (FILTER_HANDLED);
}
static u_int
@@ -1207,11 +1221,11 @@ smc_stop(struct smc_softc *sc)
static void
smc_watchdog(void *arg)
{
- struct ifnet *ifp;
+ struct smc_softc *sc;
- ifp = (struct ifnet *)arg;
- if_printf(ifp, "watchdog timeout\n");
- smc_intr(ifp);
+ sc = (struct smc_softc *)arg;
+ device_printf(sc->smc_dev, "watchdog timeout\n");
+ taskqueue_enqueue_fast(sc->smc_tq, &sc->smc_intr);
}
static void
diff --git a/sys/dev/smc/if_smcvar.h b/sys/dev/smc/if_smcvar.h
index d328c91..9bff17d 100644
--- a/sys/dev/smc/if_smcvar.h
+++ b/sys/dev/smc/if_smcvar.h
@@ -46,6 +46,7 @@ struct smc_softc {
/* Tasks */
struct taskqueue *smc_tq;
+ struct task smc_intr;
struct task smc_rx;
struct task smc_tx;
struct mbuf *smc_pending;
@@ -65,13 +66,6 @@ struct smc_softc {
void *smc_read_arg;
};
-#define SMC_LOCK(sc) mtx_lock_spin(&(sc)->smc_mtx)
-#define SMC_UNLOCK(sc) mtx_unlock_spin(&(sc)->smc_mtx)
-#define SMC_ASSERT_LOCKED(sc) mtx_assert(&(sc)->smc_mtx, MA_OWNED)
-
-#define SMC_RX_PRIORITY 0
-#define SMC_TX_PRIORITY 10
-
int smc_probe(device_t);
int smc_attach(device_t);
int smc_detach(device_t);
OpenPOWER on IntegriCloud