On Mon, Jan 14, 2013 at 10:10:55PM +1100, Darren Tucker wrote:
> This patch below reduces the number of interrupts on the transmit side
> of vr(4).  Currently we set the TX competion interrupt bit on each
> outbound packet.  This patch changes it to only set the interrupt bit on
> the last packet enqueued.  (One thing of note is that the interrupt bit
> is set on the first of potentially several TX descriptors for a packet
> whereas currently it's the last.  I'm not sure if this matters, but if
> it does I can change it).

Here's an updated diff where, when a single packet spans multiple TX
descriptors, it'll only sent the interrupt request bit on the final
discriptor (which matches the current behaviour for that case).

Index: dev/pci/if_vr.c
===================================================================
RCS file: /cvs/src/sys/dev/pci/if_vr.c,v
retrieving revision 1.121
diff -u -p -r1.121 if_vr.c
--- dev/pci/if_vr.c     1 Dec 2012 09:55:03 -0000       1.121
+++ dev/pci/if_vr.c     14 Jan 2013 23:23:57 -0000
@@ -1254,8 +1254,8 @@ vr_encap(struct vr_softc *sc, struct vr_
                sc->vr_cdata.vr_tx_cnt++;
        }
 
-       /* Set EOP on the last desciptor */
-       f->vr_ctl |= htole32(VR_TXCTL_LASTFRAG | VR_TXCTL_FINT);
+       /* Set EOP on the last descriptor */
+       f->vr_ctl |= htole32(VR_TXCTL_LASTFRAG);
 
        return (0);
 }
@@ -1265,6 +1265,13 @@ vr_encap(struct vr_softc *sc, struct vr_
  * to the mbuf data regions directly in the transmit lists. We also save a
  * copy of the pointers since the transmit list fragment pointers are
  * physical addresses.
+ *
+ * Notes:
+ * We only set ownership bit on first descriptor for a each packet.
+ * We'll only want an interrupt for a given packet if either vr_encap fails
+ * (ie the descriptor ring is full) or if the interface input queue is
+ * empty, and we need to set the interrupt bit before setting the owner bit
+ * to turn it over to the hardware.
  */
 
 void
@@ -1273,6 +1280,7 @@ vr_start(struct ifnet *ifp)
        struct vr_softc         *sc;
        struct mbuf             *m_head;
        struct vr_chain         *cur_tx, *head_tx;
+       struct vr_chain         *prev_head_tx = NULL, *prev_tail_tx = NULL;
 
        sc = ifp->if_softc;
 
@@ -1298,9 +1306,10 @@ vr_start(struct ifnet *ifp)
                                IF_PREPEND(&ifp->if_snd, m_head);
                        break;
                }
-
-               /* Only set ownership bit on first descriptor */
-               head_tx->vr_ptr->vr_status |= htole32(VR_TXSTAT_OWN);
+               /* successfully enqueued new packet, we're done with previous */
+               if (prev_head_tx != NULL)
+                       prev_head_tx->vr_ptr->vr_status |=
+                           htole32(VR_TXSTAT_OWN);
 
 #if NBPFILTER > 0
                /*
@@ -1311,9 +1320,22 @@ vr_start(struct ifnet *ifp)
                        bpf_mtap_ether(ifp->if_bpf, head_tx->vr_mbuf,
                        BPF_DIRECTION_OUT);
 #endif
+               prev_head_tx = head_tx;
+               prev_tail_tx = cur_tx;
                cur_tx = cur_tx->vr_nextdesc;
        }
        if (sc->vr_cdata.vr_tx_cnt != 0) {
+               /*
+                * If we enqueued any packets, we want to set FINT on the last
+                * descriptor for the last packet, but set TXOWN on the first
+                * descriptor of the last packet.
+                */
+               if (prev_tail_tx != NULL)
+                       prev_tail_tx->vr_ptr->vr_ctl |= htole32(VR_TXCTL_FINT);
+               if (prev_head_tx != NULL)
+                       prev_head_tx->vr_ptr->vr_status |=
+                           htole32(VR_TXSTAT_OWN);
+
                sc->vr_cdata.vr_tx_prod = cur_tx;
 
                bus_dmamap_sync(sc->sc_dmat, sc->sc_listmap.vrm_map, 0,

-- 
Darren Tucker (dtucker at zip.com.au)
GPG key 8FF4FA69 / D9A3 86E9 7EEE AF4B B2D4  37C9 C982 80C7 8FF4 FA69
    Good judgement comes with experience. Unfortunately, the experience
usually comes from bad judgement.

Reply via email to