diff options
author | 2013-01-28 02:57:02 +0000 | |
---|---|---|
committer | 2013-01-28 02:57:02 +0000 | |
commit | 09dd88b45482896c9042023d4a86024b05ae1928 (patch) | |
tree | a12ae7e9a9c9c7b0adb029aed3da77be9532e76f | |
parent | The removal of the wrapping of PIC symbol references in an UNSPEC vector (diff) | |
download | wireguard-openbsd-09dd88b45482896c9042023d4a86024b05ae1928.tar.xz wireguard-openbsd-09dd88b45482896c9042023d4a86024b05ae1928.zip |
Add TX interrupt mitigation for vr(4) chips, loosely based on FreeBSD,
but with tweaks so it works on 6105Ms like those found in pcengines alix
and soekris 5501s. ok sthen@, help brad chris mikeb dlg jsing
There may be other 610x chips that would benefit from the VR_Q_INTDISABLE
quirk, please send me a dmesg if you can confirm it works.
-rw-r--r-- | sys/dev/pci/if_vr.c | 39 | ||||
-rw-r--r-- | sys/dev/pci/if_vrreg.h | 7 |
2 files changed, 38 insertions, 8 deletions
diff --git a/sys/dev/pci/if_vr.c b/sys/dev/pci/if_vr.c index 477965cdee8..35c484b7ce5 100644 --- a/sys/dev/pci/if_vr.c +++ b/sys/dev/pci/if_vr.c @@ -1,4 +1,4 @@ -/* $OpenBSD: if_vr.c,v 1.125 2013/01/17 21:49:48 chris Exp $ */ +/* $OpenBSD: if_vr.c,v 1.126 2013/01/28 02:57:02 dtucker Exp $ */ /* * Copyright (c) 1997, 1998 @@ -163,6 +163,7 @@ int vr_alloc_mbuf(struct vr_softc *, struct vr_chain_onefrag *); #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_chain **cp, struct mbuf *m_head) 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_chain **cp, struct mbuf *m_head) } #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_chain **cp, struct mbuf *m_head) 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_chain **cp, struct mbuf *m_head) 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); } @@ -1583,6 +1599,15 @@ vr_watchdog(struct ifnet *ifp) 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); vr_init(sc); diff --git a/sys/dev/pci/if_vrreg.h b/sys/dev/pci/if_vrreg.h index 20e8d523b3d..0b5afb366ee 100644 --- a/sys/dev/pci/if_vrreg.h +++ b/sys/dev/pci/if_vrreg.h @@ -1,4 +1,4 @@ -/* $OpenBSD: if_vrreg.h,v 1.33 2013/01/16 05:25:57 dtucker Exp $ */ +/* $OpenBSD: if_vrreg.h,v 1.34 2013/01/28 02:57:02 dtucker Exp $ */ /* * Copyright (c) 1997, 1998 @@ -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; + unsigned int vr_tx_pkts; }; struct vr_mii_frame { |