summaryrefslogtreecommitdiff
path: root/sys/dev/usb/if_axe.c
diff options
context:
space:
mode:
authorJonathan Gray <jsg@cvs.openbsd.org>2005-08-28 03:34:34 +0000
committerJonathan Gray <jsg@cvs.openbsd.org>2005-08-28 03:34:34 +0000
commit462bbbc23a7344fc1324f9c66f54fae1270dcb61 (patch)
tree33627c801934722df446f9a7cffd4a98be674e4f /sys/dev/usb/if_axe.c
parentcfd6786ccb7a6d9250c9919ac0e0ba0b2569ed2b (diff)
The AX88178 sends multiple frames per USB transfer
and has extra bytes and rules to deal with this. Initial rxeof/encap changes by me, dlg@ rewrote axe_rxeof and axe_newbuf from scratch and cleaned up encap so they can jump over buildings in a single bound and be more elegant/readable. ok deraadt@
Diffstat (limited to 'sys/dev/usb/if_axe.c')
-rw-r--r--sys/dev/usb/if_axe.c175
1 files changed, 95 insertions, 80 deletions
diff --git a/sys/dev/usb/if_axe.c b/sys/dev/usb/if_axe.c
index 7dba3076ab6..f589f6dd5ef 100644
--- a/sys/dev/usb/if_axe.c
+++ b/sys/dev/usb/if_axe.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: if_axe.c,v 1.37 2005/08/28 02:55:18 jsg Exp $ */
+/* $OpenBSD: if_axe.c,v 1.38 2005/08/28 03:34:33 jsg Exp $ */
/*
* Copyright (c) 1997, 1998, 1999, 2000-2003
@@ -178,7 +178,7 @@ USB_DECLARE_DRIVER_CLASS(axe, DV_IFNET);
Static int axe_tx_list_init(struct axe_softc *);
Static int axe_rx_list_init(struct axe_softc *);
-Static int axe_newbuf(struct axe_softc *, struct axe_chain *, struct mbuf *);
+Static struct mbuf *axe_newbuf(void);
Static int axe_encap(struct axe_softc *, struct mbuf *, int);
Static void axe_rxeof(usbd_xfer_handle, usbd_private_handle, usbd_status);
Static void axe_txeof(usbd_xfer_handle, usbd_private_handle, usbd_status);
@@ -770,42 +770,25 @@ axe_activate(device_ptr_t self, enum devact act)
return (0);
}
-/*
- * Initialize an RX descriptor and attach an MBUF cluster.
- */
-Static int
-axe_newbuf(struct axe_softc *sc, struct axe_chain *c, struct mbuf *m)
+Static struct mbuf *
+axe_newbuf(void)
{
- struct mbuf *m_new = NULL;
-
- DPRINTFN(10,("%s: %s: enter\n", USBDEVNAME(sc->axe_dev),__func__));
+ struct mbuf *m;
- if (m == NULL) {
- MGETHDR(m_new, M_DONTWAIT, MT_DATA);
- if (m_new == NULL) {
- printf("%s: no memory for rx list "
- "-- packet dropped!\n", USBDEVNAME(sc->axe_dev));
- return (ENOBUFS);
- }
+ MGETHDR(m, M_DONTWAIT, MT_DATA);
+ if (m == NULL)
+ return (NULL);
- MCLGET(m_new, M_DONTWAIT);
- if (!(m_new->m_flags & M_EXT)) {
- printf("%s: no memory for rx list "
- "-- packet dropped!\n", USBDEVNAME(sc->axe_dev));
- m_freem(m_new);
- return (ENOBUFS);
- }
- m_new->m_len = m_new->m_pkthdr.len = MCLBYTES;
- } else {
- m_new = m;
- m_new->m_len = m_new->m_pkthdr.len = MCLBYTES;
- m_new->m_data = m_new->m_ext.ext_buf;
+ MCLGET(m, M_DONTWAIT);
+ if (!(m->m_flags & M_EXT)) {
+ m_freem(m);
+ return (NULL);
}
- m_adj(m_new, ETHER_ALIGN);
- c->axe_mbuf = m_new;
+ m->m_len = m->m_pkthdr.len = MCLBYTES;
+ m_adj(m, ETHER_ALIGN);
- return (0);
+ return (m);
}
Static int
@@ -822,8 +805,7 @@ axe_rx_list_init(struct axe_softc *sc)
c = &cd->axe_rx_chain[i];
c->axe_sc = sc;
c->axe_idx = i;
- if (axe_newbuf(sc, c, NULL) == ENOBUFS)
- return (ENOBUFS);
+ c->axe_mbuf = NULL;
if (c->axe_xfer == NULL) {
c->axe_xfer = usbd_alloc_xfer(sc->axe_udev);
if (c->axe_xfer == NULL)
@@ -881,11 +863,7 @@ axe_rxstart(struct ifnet *ifp)
axe_lock_mii(sc);
c = &sc->axe_cdata.axe_rx_chain[sc->axe_cdata.axe_rx_prod];
- if (axe_newbuf(sc, c, NULL) == ENOBUFS) {
- ifp->if_ierrors++;
- axe_unlock_mii(sc);
- return;
- }
+ memset(c->axe_buf, 0, sc->axe_bufsz);
/* Setup new transfer. */
usbd_setup_xfer(c->axe_xfer, sc->axe_ep[AXE_ENDPT_RX],
@@ -905,17 +883,16 @@ axe_rxstart(struct ifnet *ifp)
Static void
axe_rxeof(usbd_xfer_handle xfer, usbd_private_handle priv, usbd_status status)
{
- struct axe_softc *sc;
- struct axe_chain *c;
- struct ifnet *ifp;
- struct mbuf *m;
+ struct axe_chain *c = (struct axe_chain *)priv;
+ struct axe_softc *sc = c->axe_sc;
+ struct ifnet *ifp = GET_IFP(sc);
+ u_char *buf = c->axe_buf;
u_int32_t total_len;
+ u_int16_t pktlen = 0;
+ struct mbuf *m;
+ struct axe_sframe_hdr hdr;
int s;
- c = priv;
- sc = c->axe_sc;
- ifp = GET_IFP(sc);
-
DPRINTFN(10,("%s: %s: enter\n", USBDEVNAME(sc->axe_dev),__func__));
if (sc->axe_dying)
@@ -938,43 +915,62 @@ axe_rxeof(usbd_xfer_handle xfer, usbd_private_handle priv, usbd_status status)
usbd_get_xfer_status(xfer, NULL, NULL, &total_len, NULL);
- m = c->axe_mbuf;
+ do {
+ if (sc->axe_flags & AX178) {
+ if (total_len < sizeof(hdr)) {
+ ifp->if_ierrors++;
+ goto done;
+ }
- if (total_len <= sizeof(struct ether_header)) {
- ifp->if_ierrors++;
- goto done;
- }
+ if ((pktlen % 2) != 0)
+ pktlen++;
- ifp->if_ipackets++;
- m->m_pkthdr.rcvif = ifp;
- m->m_pkthdr.len = m->m_len = total_len;
+ buf += pktlen;
+ memcpy(&hdr, buf, sizeof(hdr));
+ total_len -= sizeof(hdr);
- memcpy(mtod(c->axe_mbuf, char *), c->axe_buf, total_len);
+ if ((hdr.len ^ hdr.ilen) != 0xffff ||
+ (hdr.len > total_len)) {
+ ifp->if_ierrors++;
+ goto done;
+ }
- /* No errors; receive the packet. */
- total_len -= ETHER_CRC_LEN + 4;
+ pktlen = hdr.len;
+ buf += sizeof(hdr);
+ total_len -= pktlen + (pktlen % 2);
+ } else {
+ pktlen = total_len; /* crc on the end? */
+ total_len = 0;
+ }
- s = splnet();
+ m = axe_newbuf();
+ if (m == NULL) {
+ ifp->if_ierrors++;
+ goto done;
+ }
- /* XXX ugly */
- if (axe_newbuf(sc, c, NULL) == ENOBUFS) {
- ifp->if_ierrors++;
- goto done1;
- }
+ ifp->if_ipackets++;
+ m->m_pkthdr.rcvif = ifp;
+ m->m_pkthdr.len = m->m_len = pktlen;
+
+ memcpy(mtod(m, char *), buf, pktlen);
+ /* push the packet up */
+ s = splnet();
#if NBPFILTER > 0
- if (ifp->if_bpf)
- BPF_MTAP(ifp, m);
+ if (ifp->if_bpf)
+ BPF_MTAP(ifp, m);
#endif
- DPRINTFN(10,("%s: %s: deliver %d\n", USBDEVNAME(sc->axe_dev),
- __func__, m->m_len));
- IF_INPUT(ifp, m);
- done1:
- splx(s);
+ IF_INPUT(ifp, m);
+
+ splx(s);
+
+ } while (total_len > 0);
- done:
+done:
+ memset(c->axe_buf, 0, sc->axe_bufsz);
/* Setup new transfer. */
usbd_setup_xfer(xfer, sc->axe_ep[AXE_ENDPT_RX],
@@ -983,8 +979,8 @@ axe_rxeof(usbd_xfer_handle xfer, usbd_private_handle priv, usbd_status status)
USBD_NO_TIMEOUT, axe_rxeof);
usbd_transfer(xfer);
- DPRINTFN(10,("%s: %s: start rx\n", USBDEVNAME(sc->axe_dev),
- __func__));
+ DPRINTFN(10,("%s: %s: start rx\n", USBDEVNAME(sc->axe_dev), __func__));
+
return;
}
@@ -1100,18 +1096,37 @@ axe_encap(struct axe_softc *sc, struct mbuf *m, int idx)
{
struct axe_chain *c;
usbd_status err;
+ struct axe_sframe_hdr hdr;
+ int length;
c = &sc->axe_cdata.axe_tx_chain[idx];
- /*
- * Copy the mbuf data into a contiguous buffer, leaving two
- * bytes at the beginning to hold the frame length.
- */
- m_copydata(m, 0, m->m_pkthdr.len, c->axe_buf);
+ if (sc->axe_flags & AX178) {
+ hdr.len = m->m_pkthdr.len;
+ hdr.ilen = ~hdr.len;
+
+ memcpy(c->axe_buf, &hdr, sizeof(hdr));
+ length = sizeof(hdr);
+
+ m_copydata(m, 0, m->m_pkthdr.len, c->axe_buf + length);
+ length += m->m_pkthdr.len;
+
+ if ((length % 512) == 0) {
+ hdr.len = 0x0000;
+ hdr.ilen = 0xffff;
+ memcpy(c->axe_buf + length, &hdr, sizeof(hdr));
+ length += sizeof(hdr);
+ }
+
+ } else {
+ m_copydata(m, 0, m->m_pkthdr.len, c->axe_buf);
+ length = m->m_pkthdr.len;
+ }
+
c->axe_mbuf = m;
usbd_setup_xfer(c->axe_xfer, sc->axe_ep[AXE_ENDPT_TX],
- c, c->axe_buf, m->m_pkthdr.len, USBD_FORCE_SHORT_XFER, 10000,
+ c, c->axe_buf, length, USBD_FORCE_SHORT_XFER, 10000,
axe_txeof);
/* Transmit */