summaryrefslogtreecommitdiffstats
path: root/sys/dev/sf/if_sf.c
diff options
context:
space:
mode:
authorbrueffer <brueffer@FreeBSD.org>2004-11-10 23:04:39 +0000
committerbrueffer <brueffer@FreeBSD.org>2004-11-10 23:04:39 +0000
commit4c011814bd73e5d0ec15eef353a5856fd3457932 (patch)
tree751f7a07e67d155d848880e07ffc48d2e69cf9f0 /sys/dev/sf/if_sf.c
parentca73427e9a142b643075aca39ec95b963af5c822 (diff)
downloadFreeBSD-src-4c011814bd73e5d0ec15eef353a5856fd3457932.zip
FreeBSD-src-4c011814bd73e5d0ec15eef353a5856fd3457932.tar.gz
Add device polling support
Original patch by me, improvements by ru Happy birthday to: BSDforen.de! Approved by: ru MFC after: 2 weeks
Diffstat (limited to 'sys/dev/sf/if_sf.c')
-rw-r--r--sys/dev/sf/if_sf.c106
1 files changed, 106 insertions, 0 deletions
diff --git a/sys/dev/sf/if_sf.c b/sys/dev/sf/if_sf.c
index 91a9441..e433198 100644
--- a/sys/dev/sf/if_sf.c
+++ b/sys/dev/sf/if_sf.c
@@ -164,6 +164,12 @@ static u_int8_t sf_read_eeprom (struct sf_softc *, int);
static int sf_miibus_readreg (device_t, int, int);
static int sf_miibus_writereg (device_t, int, int, int);
static void sf_miibus_statchg (device_t);
+#ifdef DEVICE_POLLING
+static void sf_poll (struct ifnet *ifp, enum poll_cmd cmd,
+ int count);
+static void sf_poll_locked (struct ifnet *ifp, enum poll_cmd cmd,
+ int count);
+#endif /* DEVICE_POLLING */
static u_int32_t csr_read_4 (struct sf_softc *, int);
static void csr_write_4 (struct sf_softc *, int, u_int32_t);
@@ -534,6 +540,10 @@ sf_ioctl(ifp, command, data)
mii = device_get_softc(sc->sf_miibus);
error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, command);
break;
+ case SIOCSIFCAP:
+ ifp->if_capenable &= ~IFCAP_POLLING;
+ ifp->if_capenable |= ifr->ifr_reqcap & IFCAP_POLLING;
+ break;
default:
error = ether_ioctl(ifp, command, data);
break;
@@ -714,6 +724,10 @@ sf_attach(dev)
ifp->if_init = sf_init;
ifp->if_baudrate = 10000000;
ifp->if_snd.ifq_maxlen = SF_TX_DLIST_CNT - 1;
+#ifdef DEVICE_POLLING
+ ifp->if_capabilities |= IFCAP_POLLING;
+#endif /* DEVICE_POLLING */
+ ifp->if_capenable = ifp->if_capabilities;
/*
* Call MI attach routine.
@@ -903,6 +917,14 @@ sf_rxeof(sc)
while (cmpconsidx != cmpprodidx) {
struct mbuf *m0;
+#ifdef DEVICE_POLLING
+ if (ifp->if_flags & IFF_POLLING) {
+ if (sc->rxcycles <= 0)
+ break;
+ sc->rxcycles--;
+ }
+#endif /* DEVICE_POLLING */
+
cur_rx = &sc->sf_ldata->sf_rx_clist[cmpconsidx];
desc = &sc->sf_ldata->sf_rx_dlist_big[cur_rx->sf_endidx];
m = desc->sf_mbuf;
@@ -1010,6 +1032,63 @@ sf_txthresh_adjust(sc)
}
}
+#ifdef DEVICE_POLLING
+static void
+sf_poll(struct ifnet *ifp, enum poll_cmd cmd, int count)
+{
+ struct sf_softc *sc = ifp->if_softc;
+
+ SF_LOCK(sc);
+ sf_poll_locked(ifp, cmd, count);
+ SF_UNLOCK(sc);
+}
+
+static void
+sf_poll_locked(struct ifnet *ifp, enum poll_cmd cmd, int count)
+{
+ struct sf_softc *sc = ifp->if_softc;
+
+ SF_LOCK_ASSERT(sc);
+
+ if (!(ifp->if_capenable & IFCAP_POLLING)) {
+ ether_poll_deregister(ifp);
+ cmd = POLL_DEREGISTER;
+ }
+
+ if (cmd == POLL_DEREGISTER) {
+ /* Final call, enable interrupts. */
+ csr_write_4(sc, SF_IMR, SF_INTRS);
+ return;
+ }
+
+ sc->rxcycles = count;
+ sf_rxeof(sc);
+ sf_txeof(sc);
+ if (ifp->if_snd.ifq_head != NULL)
+ sf_start(ifp);
+
+ if (cmd == POLL_AND_CHECK_STATUS) {
+ u_int32_t status;
+
+ status = csr_read_4(sc, SF_ISR);
+ if (status)
+ csr_write_4(sc, SF_ISR, status);
+
+ if (status & SF_ISR_TX_LOFIFO)
+ sf_txthresh_adjust(sc);
+
+ if (status & SF_ISR_ABNORMALINTR) {
+ if (status & SF_ISR_STATSOFLOW) {
+ untimeout(sf_stats_update, sc,
+ sc->sf_stat_ch);
+ sf_stats_update(sc);
+ } else
+ sf_init(sc);
+ }
+ }
+}
+#endif /* DEVICE_POLLING */
+
static void
sf_intr(arg)
void *arg;
@@ -1023,6 +1102,19 @@ sf_intr(arg)
ifp = &sc->arpcom.ac_if;
+#ifdef DEVICE_POLLING
+ if (ifp->if_flags & IFF_POLLING)
+ goto done_locked;
+
+ if ((ifp->if_capenable & IFCAP_POLLING) &&
+ ether_poll_register(sf_poll, ifp)) {
+ /* OK, disable interrupts. */
+ csr_write_4(sc, SF_IMR, 0x00000000);
+ sf_poll_locked(ifp, 0, 1);
+ goto done_locked;
+ }
+#endif /* DEVICE_POLLING */
+
if (!(csr_read_4(sc, SF_ISR_SHADOW) & SF_ISR_PCIINT_ASSERTED)) {
SF_UNLOCK(sc);
return;
@@ -1066,6 +1158,9 @@ sf_intr(arg)
if (ifp->if_snd.ifq_head != NULL)
sf_start(ifp);
+#ifdef DEVICE_POLLING
+done_locked:
+#endif /* DEVICE_POLLING */
SF_UNLOCK(sc);
}
@@ -1163,6 +1258,13 @@ sf_init(xsc)
/* Enable autopadding of short TX frames. */
SF_SETBIT(sc, SF_MACCFG_1, SF_MACCFG1_AUTOPAD);
+#ifdef DEVICE_POLLING
+ /* Disable interrupts if we are polling. */
+ if (ifp->if_flags & IFF_POLLING)
+ csr_write_4(sc, SF_IMR, 0x00000000);
+ else
+#endif /* DEVICE_POLLING */
+
/* Enable interrupts. */
csr_write_4(sc, SF_IMR, SF_INTRS);
SF_SETBIT(sc, SF_PCI_DEVCFG, SF_PCIDEVCFG_INTR_ENB);
@@ -1339,6 +1441,10 @@ sf_stop(sc)
untimeout(sf_stats_update, sc, sc->sf_stat_ch);
+#ifdef DEVICE_POLLING
+ ether_poll_deregister(ifp);
+#endif /* DEVICE_POLLING */
+
csr_write_4(sc, SF_GEN_ETH_CTL, 0);
csr_write_4(sc, SF_CQ_CONSIDX, 0);
csr_write_4(sc, SF_CQ_PRODIDX, 0);
OpenPOWER on IntegriCloud