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