summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStuart Henderson <sthen@cvs.openbsd.org>2009-05-10 12:09:47 +0000
committerStuart Henderson <sthen@cvs.openbsd.org>2009-05-10 12:09:47 +0000
commite8386d053ab9626ff47b86024fc69488c9691cc5 (patch)
treeb98271a8af3fa977ae2cabde9d47c9b15bd9f11e
parent40facb7b0cee4707af89bd1c9d2de8fc319c98f5 (diff)
- change device matching to use a quirks table.
- avoid the need for unnecessary mbuf copies on modern vr(4) devices (ancient ones required longword-alignment, but this has not been the case for several generations now). reduces cpu time, particularly for forwarded traffic. from chris@. tested by chris@, myself, Emilio Perea on various devices including original VIA EPIA, Soekris net5501, pcengines.ch ALIX. ok mpf. deraadt and dlg agree with committing at this stage.
-rw-r--r--sys/dev/pci/if_vr.c141
-rw-r--r--sys/dev/pci/if_vrreg.h9
2 files changed, 99 insertions, 51 deletions
diff --git a/sys/dev/pci/if_vr.c b/sys/dev/pci/if_vr.c
index 62c67d9ff0f..19f15a9cfdc 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.83 2009/04/30 18:28:29 mpf Exp $ */
+/* $OpenBSD: if_vr.c,v 1.84 2009/05/10 12:09:46 sthen Exp $ */
/*
* Copyright (c) 1997, 1998
@@ -54,7 +54,7 @@
* multicast filter. Transmit and receive descriptors are similar
* to the tulip.
*
- * The Rhine has a serious flaw in its transmit DMA mechanism:
+ * Early Rhine has a serious flaw in its transmit DMA mechanism:
* transmit buffers must be longword aligned. Unfortunately,
* FreeBSD doesn't guarantee that mbufs will be filled in starting
* at longword boundaries, so we have to do a buffer copy before
@@ -101,6 +101,7 @@
#include <dev/pci/if_vrreg.h>
int vr_probe(struct device *, void *, void *);
+int vr_quirks(struct pci_attach_args *);
void vr_attach(struct device *, struct device *, void *);
struct cfattach vr_ca = {
@@ -139,14 +140,32 @@ int vr_list_tx_init(struct vr_softc *);
int vr_alloc_mbuf(struct vr_softc *, struct vr_chain_onefrag *, struct mbuf *);
-const struct pci_matchid vr_devices[] = {
- { PCI_VENDOR_VIATECH, PCI_PRODUCT_VIATECH_RHINE },
- { PCI_VENDOR_VIATECH, PCI_PRODUCT_VIATECH_RHINEII },
- { PCI_VENDOR_VIATECH, PCI_PRODUCT_VIATECH_RHINEII_2 },
- { PCI_VENDOR_VIATECH, PCI_PRODUCT_VIATECH_VT6105 },
- { PCI_VENDOR_VIATECH, PCI_PRODUCT_VIATECH_VT6105M },
- { PCI_VENDOR_DELTA, PCI_PRODUCT_DELTA_RHINEII },
- { PCI_VENDOR_ADDTRON, PCI_PRODUCT_ADDTRON_RHINEII }
+/*
+ * Supported devices & quirks
+ */
+#define VR_Q_NEEDALIGN (1<<0)
+#define VR_Q_CSUM (1<<1)
+#define VR_Q_CAM (1<<2)
+
+struct vr_type {
+ pci_vendor_id_t vr_vid;
+ pci_product_id_t vr_pid;
+ int vr_quirks;
+} vr_devices[] = {
+ { PCI_VENDOR_VIATECH, PCI_PRODUCT_VIATECH_RHINE,
+ VR_Q_NEEDALIGN },
+ { PCI_VENDOR_VIATECH, PCI_PRODUCT_VIATECH_RHINEII,
+ VR_Q_NEEDALIGN },
+ { PCI_VENDOR_VIATECH, PCI_PRODUCT_VIATECH_RHINEII_2,
+ 0 },
+ { PCI_VENDOR_VIATECH, PCI_PRODUCT_VIATECH_VT6105,
+ 0 },
+ { PCI_VENDOR_VIATECH, PCI_PRODUCT_VIATECH_VT6105M,
+ VR_Q_CSUM | VR_Q_CAM },
+ { PCI_VENDOR_DELTA, PCI_PRODUCT_DELTA_RHINEII,
+ VR_Q_NEEDALIGN },
+ { PCI_VENDOR_ADDTRON, PCI_PRODUCT_ADDTRON_RHINEII,
+ VR_Q_NEEDALIGN }
};
#define VR_SETBIT(sc, reg, x) \
@@ -433,11 +452,33 @@ vr_reset(struct vr_softc *sc)
/*
* Probe for a VIA Rhine chip.
*/
-int
+int
vr_probe(struct device *parent, void *match, void *aux)
{
- return (pci_matchbyid((struct pci_attach_args *)aux, vr_devices,
- sizeof(vr_devices)/sizeof(vr_devices[0])));
+ const struct vr_type *vr;
+ struct pci_attach_args *pa = (struct pci_attach_args *)aux;
+ int i, nent = sizeof(vr_devices)/sizeof(vr_devices[0]);
+
+ for (i = 0, vr = vr_devices; i < nent; i++, vr++)
+ if (PCI_VENDOR(pa->pa_id) == vr->vr_vid &&
+ PCI_PRODUCT(pa->pa_id) == vr->vr_pid)
+ return(1);
+
+ return(0);
+}
+
+int
+vr_quirks(struct pci_attach_args *pa)
+{
+ const struct vr_type *vr;
+ int i, nent = sizeof(vr_devices)/sizeof(vr_devices[0]);
+
+ for (i = 0, vr = vr_devices; i < nent; i++, vr++)
+ if (PCI_VENDOR(pa->pa_id) == vr->vr_vid &&
+ PCI_PRODUCT(pa->pa_id) == vr->vr_pid)
+ return(vr->vr_quirks);
+
+ return(0);
}
/*
@@ -592,6 +633,7 @@ vr_attach(struct device *parent, struct device *self, void *aux)
}
sc->vr_ldata = (struct vr_list_data *)kva;
bzero(sc->vr_ldata, sizeof(struct vr_list_data));
+ sc->vr_quirks = vr_quirks(pa);
ifp = &sc->arpcom.ac_if;
ifp->if_softc = sc;
@@ -1086,43 +1128,54 @@ vr_encap(struct vr_softc *sc, struct vr_chain *c, struct mbuf *m_head)
struct vr_desc *f = NULL;
struct mbuf *m_new = NULL;
- MGETHDR(m_new, M_DONTWAIT, MT_DATA);
- if (m_new == NULL)
- return (1);
- if (m_head->m_pkthdr.len > MHLEN) {
- MCLGET(m_new, M_DONTWAIT);
- if (!(m_new->m_flags & M_EXT)) {
- m_freem(m_new);
+ if (sc->vr_quirks & VR_Q_NEEDALIGN ||
+ m_head->m_pkthdr.len < VR_MIN_FRAMELEN ||
+ bus_dmamap_load_mbuf(sc->sc_dmat, c->vr_map, m_head,
+ BUS_DMA_NOWAIT | BUS_DMA_WRITE)) {
+ MGETHDR(m_new, M_DONTWAIT, MT_DATA);
+ if (m_new == NULL)
return (1);
+ if (m_head->m_pkthdr.len > MHLEN) {
+ MCLGET(m_new, M_DONTWAIT);
+ if (!(m_new->m_flags & M_EXT)) {
+ m_freem(m_new);
+ return (1);
+ }
}
- }
- m_copydata(m_head, 0, m_head->m_pkthdr.len, mtod(m_new, caddr_t));
- m_new->m_pkthdr.len = m_new->m_len = m_head->m_pkthdr.len;
+ m_copydata(m_head, 0, m_head->m_pkthdr.len,
+ mtod(m_new, caddr_t));
+ m_new->m_pkthdr.len = m_new->m_len = m_head->m_pkthdr.len;
- /*
- * The Rhine chip doesn't auto-pad, so we have to make
- * sure to pad short frames out to the minimum frame length
- * ourselves.
- */
- if (m_new->m_len < VR_MIN_FRAMELEN) {
- /* data field should be padded with octets of zero */
- bzero(&m_new->m_data[m_new->m_len],
- VR_MIN_FRAMELEN-m_new->m_len);
- m_new->m_pkthdr.len += VR_MIN_FRAMELEN - m_new->m_len;
- m_new->m_len = m_new->m_pkthdr.len;
- }
+ /*
+ * The Rhine chip doesn't auto-pad, so we have to make
+ * sure to pad short frames out to the minimum frame length
+ * ourselves.
+ */
+ if (m_head->m_pkthdr.len < VR_MIN_FRAMELEN) {
+ /* data field should be padded with octets of zero */
+ bzero(&m_new->m_data[m_new->m_len],
+ VR_MIN_FRAMELEN-m_new->m_len);
+ m_new->m_pkthdr.len += VR_MIN_FRAMELEN - m_new->m_len;
+ m_new->m_len = m_new->m_pkthdr.len;
+ }
- if (bus_dmamap_load_mbuf(sc->sc_dmat, c->vr_map, m_new,
- BUS_DMA_NOWAIT | BUS_DMA_WRITE)) {
- m_freem(m_new);
- return (1);
- }
- bus_dmamap_sync(sc->sc_dmat, c->vr_map, 0, c->vr_map->dm_mapsize,
- BUS_DMASYNC_PREWRITE);
+ if (bus_dmamap_load_mbuf(sc->sc_dmat, c->vr_map, m_new,
+ BUS_DMA_NOWAIT | BUS_DMA_WRITE)) {
+ m_freem(m_new);
+ return (1);
+ }
+ bus_dmamap_sync(sc->sc_dmat, c->vr_map, 0, c->vr_map->dm_mapsize,
+ BUS_DMASYNC_PREWRITE);
- m_freem(m_head);
+ m_freem(m_head);
- c->vr_mbuf = m_new;
+ c->vr_mbuf = m_new;
+ } else {
+ bus_dmamap_sync(sc->sc_dmat, c->vr_map, 0, c->vr_map->dm_mapsize,
+ BUS_DMASYNC_PREWRITE);
+
+ c->vr_mbuf = m_head;
+ }
f = c->vr_ptr;
f->vr_data = htole32(c->vr_map->dm_segs[0].ds_addr);
diff --git a/sys/dev/pci/if_vrreg.h b/sys/dev/pci/if_vrreg.h
index 8be865b4945..6642ec0d1af 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.22 2009/04/28 12:54:31 mpf Exp $ */
+/* $OpenBSD: if_vrreg.h,v 1.23 2009/05/10 12:09:46 sthen Exp $ */
/*
* Copyright (c) 1997, 1998
@@ -425,12 +425,6 @@ struct vr_chain_data {
struct vr_chain *vr_tx_prod;
};
-struct vr_type {
- u_int16_t vr_vid;
- u_int16_t vr_did;
- char *vr_name;
-};
-
struct vr_mii_frame {
u_int8_t mii_stdelim;
u_int8_t mii_opcode;
@@ -471,6 +465,7 @@ struct vr_softc {
int sc_if_flags;
int sc_rxbufs;
int vr_link;
+ int vr_quirks;
};
#define VR_F_RESTART 0x01 /* Restart unit on next tick */