diff options
author | Stuart Henderson <sthen@cvs.openbsd.org> | 2009-05-10 12:09:47 +0000 |
---|---|---|
committer | Stuart Henderson <sthen@cvs.openbsd.org> | 2009-05-10 12:09:47 +0000 |
commit | e8386d053ab9626ff47b86024fc69488c9691cc5 (patch) | |
tree | b98271a8af3fa977ae2cabde9d47c9b15bd9f11e | |
parent | 40facb7b0cee4707af89bd1c9d2de8fc319c98f5 (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.c | 141 | ||||
-rw-r--r-- | sys/dev/pci/if_vrreg.h | 9 |
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 */ |