On Fri, Jan 18, 2013 at 01:09:50PM +1100, Darren Tucker wrote:
> The turd polishing continues unabated.
and continues to continue. This adds a quirk to frob the
interrupt-disable bit for VT6105M only.
After checking all of the spec sheets that I can find, I found the TX
interrupt disable bit (bit 0 in TDES3) in the specs for VT6105M,
VT6102 and VT8235.
It's not in the spec for VT6105 or VT6105LOM, however in those the
specs for the data pointer only include the top 30 bits, and bit 0
is unspecified. It's not in VT86C100A03 at all.
What does all this mean? beats me, but I'm concerned that setting the
low bit in an address might confuse chips not expecting it, so this
enables it only for chips that have been tested. For the others, it'll
still do FINT interrupt reduction, which is similar to what we already
do (and more or less what FreeBSD does now).
Routing TCP through an ALIX (iperf at 85Mbit/s), this reduced CPU usage
from ~70% to ~50% and reduced the total interrupt load from 21k/sec
to 13k/sec. Locally generating 64 byte UDP packets (the worst case,
basically) increases the output rate by about 50%.
ok?
Index: dev/pci/if_vr.c
===================================================================
RCS file: /cvs/src/sys/dev/pci/if_vr.c,v
retrieving revision 1.125
diff -u -p -r1.125 if_vr.c
--- dev/pci/if_vr.c 17 Jan 2013 21:49:48 -0000 1.125
+++ dev/pci/if_vr.c 18 Jan 2013 05:14:18 -0000
@@ -163,6 +163,7 @@ int vr_alloc_mbuf(struct vr_softc *, str
#define VR_Q_CSUM (1<<1)
#define VR_Q_CAM (1<<2)
#define VR_Q_HWTAG (1<<3)
+#define VR_Q_INTDISABLE (1<<4)
struct vr_type {
pci_vendor_id_t vr_vid;
@@ -178,7 +179,7 @@ struct vr_type {
{ PCI_VENDOR_VIATECH, PCI_PRODUCT_VIATECH_VT6105,
0 },
{ PCI_VENDOR_VIATECH, PCI_PRODUCT_VIATECH_VT6105M,
- VR_Q_CSUM | VR_Q_CAM | VR_Q_HWTAG },
+ VR_Q_CSUM | VR_Q_CAM | VR_Q_HWTAG | VR_Q_INTDISABLE },
{ PCI_VENDOR_DELTA, PCI_PRODUCT_DELTA_RHINEII,
VR_Q_NEEDALIGN },
{ PCI_VENDOR_ADDTRON, PCI_PRODUCT_ADDTRON_RHINEII,
@@ -724,7 +725,7 @@ vr_list_tx_init(struct vr_softc *sc)
cd = &sc->vr_cdata;
ld = sc->vr_ldata;
- cd->vr_tx_cnt = 0;
+ cd->vr_tx_cnt = cd->vr_tx_pkts = 0;
for (i = 0; i < VR_TX_LIST_CNT; i++) {
cd->vr_tx_chain[i].vr_ptr = &ld->vr_tx_list[i];
@@ -1198,7 +1199,7 @@ vr_encap(struct vr_softc *sc, struct vr_
struct vr_chain *c = *cp;
struct vr_desc *f = NULL;
struct mbuf *m_new = NULL;
- u_int32_t vr_ctl = 0, vr_status = 0;
+ u_int32_t vr_ctl = 0, vr_status = 0, intdisable = 0;
bus_dmamap_t txmap;
int i, runt = 0;
@@ -1259,6 +1260,18 @@ vr_encap(struct vr_softc *sc, struct vr_
}
#endif
+ /*
+ * We only want TX completion interrupts on every Nth packet.
+ * We need to set VR_TXNEXT_INTDISABLE on every descriptor except
+ * for the last discriptor of every Nth packet, where we set
+ * VR_TXCTL_FINT. The former is in the specs for only some chips.
+ * present: VT6102 VT6105M VT8235M
+ * not present: VT86C100 6105LOM
+ */
+ if (++sc->vr_cdata.vr_tx_pkts % VR_TX_INTR_THRESH != 0 &&
+ sc->vr_quirks & VR_Q_INTDISABLE)
+ intdisable = VR_TXNEXT_INTDISABLE;
+
if (m_new != NULL) {
m_freem(m_head);
@@ -1276,7 +1289,7 @@ vr_encap(struct vr_softc *sc, struct vr_
f->vr_ctl |= htole32(VR_TXCTL_FIRSTFRAG);
f->vr_status = htole32(vr_status);
f->vr_data = htole32(txmap->dm_segs[i].ds_addr);
- f->vr_next = htole32(c->vr_nextdesc->vr_paddr);
+ f->vr_next = htole32(c->vr_nextdesc->vr_paddr | intdisable);
sc->vr_cdata.vr_tx_cnt++;
}
@@ -1288,12 +1301,15 @@ vr_encap(struct vr_softc *sc, struct vr_
VR_TXCTL_TLINK | vr_ctl);
f->vr_status = htole32(vr_status);
f->vr_data =
htole32(sc->sc_zeromap.vrm_map->dm_segs[0].ds_addr);
- f->vr_next = htole32(c->vr_nextdesc->vr_paddr);
+ f->vr_next = htole32(c->vr_nextdesc->vr_paddr | intdisable);
sc->vr_cdata.vr_tx_cnt++;
}
/* Set EOP on the last descriptor */
- f->vr_ctl |= htole32(VR_TXCTL_LASTFRAG | VR_TXCTL_FINT);
+ f->vr_ctl |= htole32(VR_TXCTL_LASTFRAG);
+
+ if (sc->vr_cdata.vr_tx_pkts % VR_TX_INTR_THRESH == 0)
+ f->vr_ctl |= htole32(VR_TXCTL_FINT);
return (0);
}
@@ -1582,6 +1598,15 @@ vr_watchdog(struct ifnet *ifp)
struct vr_softc *sc;
sc = ifp->if_softc;
+
+ /*
+ * Since we're only asking for completion interrupts only every
+ * few packets, occasionally the watchdog will fire when we have
+ * some TX descriptors to reclaim, so check for that first.
+ */
+ vr_txeof(sc);
+ if (sc->vr_cdata.vr_tx_cnt == 0);
+ return;
ifp->if_oerrors++;
printf("%s: watchdog timeout\n", sc->sc_dev.dv_xname);
Index: dev/pci/if_vrreg.h
===================================================================
RCS file: /cvs/src/sys/dev/pci/if_vrreg.h,v
retrieving revision 1.33
diff -u -p -r1.33 if_vrreg.h
--- dev/pci/if_vrreg.h 16 Jan 2013 05:25:57 -0000 1.33
+++ dev/pci/if_vrreg.h 18 Jan 2013 05:14:18 -0000
@@ -429,11 +429,15 @@ struct vr_desc {
#define VR_TXCTL_LASTFRAG 0x00400000
#define VR_TXCTL_FINT 0x00800000
+/* TDES3 aka vr_next */
+#define VR_TXNEXT_INTDISABLE 0x00000001
+
#define VR_MAXFRAGS 8
#define VR_RX_LIST_CNT 128
#define VR_TX_LIST_CNT 128
#define VR_MIN_FRAMELEN 60
#define VR_RXLEN 1524
+#define VR_TX_INTR_THRESH 8
struct vr_list_data {
struct vr_desc vr_rx_list[VR_RX_LIST_CNT];
@@ -467,6 +471,7 @@ struct vr_chain_data {
struct vr_chain *vr_tx_cons;
struct vr_chain *vr_tx_prod;
int vr_tx_cnt;
+ int vr_tx_pkts;
};
struct vr_mii_frame {
--
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.