On Tue, Nov 09, 2004 at 05:49:42PM +0100, Christian Brueffer wrote:
> 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.
> 

Here's a new patch from Ruslan, which corrects some stuff and adds
missing error recovery.

- Christian

-- 
Christian Brueffer      [EMAIL PROTECTED]       [EMAIL PROTECTED]
GPG Key:         http://people.freebsd.org/~brueffer/brueffer.key.asc
GPG Fingerprint: A5C8 2099 19FF AACA F41B  B29B 6C76 178C A0ED 982D
Index: if_sf.c
===================================================================
RCS file: /home/ncvs/src/sys/pci/if_sf.c,v
retrieving revision 1.73
diff -u -p -r1.73 if_sf.c
--- if_sf.c     28 Aug 2004 15:10:35 -0000      1.73
+++ if_sf.c     10 Nov 2004 08:08:34 -0000
@@ -164,6 +164,12 @@ static u_int8_t sf_read_eeprom     (struct s
 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);
Index: if_sfreg.h
===================================================================
RCS file: /home/ncvs/src/sys/pci/if_sfreg.h,v
retrieving revision 1.10
diff -u -p -r1.10 if_sfreg.h
--- if_sfreg.h  14 Nov 2003 19:00:31 -0000      1.10
+++ if_sfreg.h  10 Nov 2004 07:23:49 -0000
@@ -1046,6 +1046,9 @@ struct sf_softc {
        int                     sf_if_flags;
        struct callout_handle   sf_stat_ch;
        struct mtx              sf_mtx;
+#ifdef DEVICE_POLLING
+       int                     rxcycles;
+#endif
 };
 
 

Attachment: pgp7kuWGAQq6e.pgp
Description: PGP signature

Reply via email to