sf(4) device polling
Christian Brueffer
chris at unixpages.org
Tue Nov 9 08:49:53 PST 2004
Hi,
the attached patch implements device polling for the sf(4) driver. It
has been running on my home gateway for almost two weeks now, without any
ill effects.
I'd appreciate it, when someone could review/commit this.
- Christian
--
Christian Brueffer chris at unixpages.org brueffer at FreeBSD.org
GPG Key: http://people.freebsd.org/~brueffer/brueffer.key.asc
GPG Fingerprint: A5C8 2099 19FF AACA F41B B29B 6C76 178C A0ED 982D
-------------- next part --------------
Index: pci/if_sf.c
===================================================================
RCS file: /data/ncvs/freebsd/src/sys/pci/if_sf.c,v
retrieving revision 1.72.2.1
diff -u -r1.72.2.1 if_sf.c
--- pci/if_sf.c 2 Sep 2004 20:57:40 -0000 1.72.2.1
+++ pci/if_sf.c 9 Nov 2004 16:45:24 -0000
@@ -164,6 +164,12 @@
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
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 @@
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 @@
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
+ ifp->if_capenable = ifp->if_capabilities;
/*
* Call MI attach routine.
@@ -903,6 +917,14 @@
while (cmpconsidx != cmpprodidx) {
struct mbuf *m0;
+#ifdef DEVICE_POLLING
+ if (ifp->if_flags & IFF_POLLING) {
+ if (sc->rxcycles <= 0)
+ break;
+ sc->rxcycles--;
+ }
+#endif
+
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,58 @@
}
}
+#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 (!IFQ_DRV_IS_EMPTY(&ifp->if_snd));
+ sf_start(ifp);
+
+ if (cmd == POLL_AND_CHECK_STATUS) {
+ uint16_t status;
+
+ status = csr_read_4(sc, SF_ISR);
+
+ if (!status)
+ return;
+
+ /* ACK what we have. */
+ csr_write_4(sc, SF_ISR, status);
+
+ if ((status & SF_INTRS) == 0)
+ return;
+ }
+}
+#endif
+
static void
sf_intr(arg)
void *arg;
@@ -1023,6 +1097,19 @@
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
+
if (!(csr_read_4(sc, SF_ISR_SHADOW) & SF_ISR_PCIINT_ASSERTED)) {
SF_UNLOCK(sc);
return;
@@ -1066,6 +1153,7 @@
if (ifp->if_snd.ifq_head != NULL)
sf_start(ifp);
+done_locked:
SF_UNLOCK(sc);
}
@@ -1163,6 +1251,13 @@
/* 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
+
/* Enable interrupts. */
csr_write_4(sc, SF_IMR, SF_INTRS);
SF_SETBIT(sc, SF_PCI_DEVCFG, SF_PCIDEVCFG_INTR_ENB);
@@ -1339,6 +1434,10 @@
untimeout(sf_stats_update, sc, sc->sf_stat_ch);
+#ifdef DEVICE_POLLING
+ ether_poll_deregister(ifp);
+#endif
+
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);
Index: pci/if_sfreg.h
===================================================================
RCS file: /data/ncvs/freebsd/src/sys/pci/if_sfreg.h,v
retrieving revision 1.10
diff -u -r1.10 if_sfreg.h
--- pci/if_sfreg.h 14 Nov 2003 19:00:31 -0000 1.10
+++ pci/if_sfreg.h 9 Nov 2004 16:45:33 -0000
@@ -1046,6 +1046,9 @@
int sf_if_flags;
struct callout_handle sf_stat_ch;
struct mtx sf_mtx;
+#ifdef DEVICE_POLLING
+ int rxcycles;
+#endif
};
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 187 bytes
Desc: not available
Url : http://lists.freebsd.org/pipermail/freebsd-net/attachments/20041109/ba3553a1/attachment.bin
More information about the freebsd-net
mailing list