summaryrefslogtreecommitdiff
path: root/sys/dev/usb/if_atu.c
diff options
context:
space:
mode:
authorDavid Gwynne <dlg@cvs.openbsd.org>2004-12-04 23:36:16 +0000
committerDavid Gwynne <dlg@cvs.openbsd.org>2004-12-04 23:36:16 +0000
commitc53e29df38d74e5ae2e874097c4db7174be5803b (patch)
tree44307020ffe681460c093df5e76243a6bd13af25 /sys/dev/usb/if_atu.c
parent7f56b29eaba0e1fed1f0b79701553256d16d7d52 (diff)
clean up the tx path
Diffstat (limited to 'sys/dev/usb/if_atu.c')
-rw-r--r--sys/dev/usb/if_atu.c267
1 files changed, 159 insertions, 108 deletions
diff --git a/sys/dev/usb/if_atu.c b/sys/dev/usb/if_atu.c
index 1aa54120c0a..b9db4320b28 100644
--- a/sys/dev/usb/if_atu.c
+++ b/sys/dev/usb/if_atu.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: if_atu.c,v 1.28 2004/12/04 08:29:41 dlg Exp $ */
+/* $OpenBSD: if_atu.c,v 1.29 2004/12/04 23:36:15 dlg Exp $ */
/*
* Copyright (c) 2003, 2004
* Daan Vreeken <Danovitsch@Vitsch.net>. All rights reserved.
@@ -187,6 +187,8 @@ void atu_print_a_bunch_of_debug_things(struct atu_softc *sc);
int atu_set_wepkey(struct atu_softc *sc, int nr, u_int8_t *key, int len);
int atu_newstate(struct ieee80211com *, enum ieee80211_state, int);
+int atu_tx_start(struct atu_softc *, struct ieee80211_node *,
+ struct atu_chain *, struct mbuf *);
/* XXX stolen from iwi */
void atu_fix_channel(struct ieee80211com *, struct mbuf *);
@@ -2434,63 +2436,41 @@ atu_txeof(usbd_xfer_handle xfer, usbd_private_handle priv, usbd_status status)
struct atu_softc *sc = c->atu_sc;
struct ifnet *ifp = &sc->sc_ic.ic_if;
usbd_status err;
- int s;
-
- s = splusb();
-
- ifp->if_timer = 0;
- c->atu_in_xfer = 0;
+ int s;
- if (c->atu_mbuf != NULL) {
- /* put it back on the tx_list */
- sc->atu_cdata.atu_tx_inuse--;
- SLIST_INSERT_HEAD(&sc->atu_cdata.atu_tx_free, c,
- atu_list);
- } else {
- /* put it back on the mgmt_list */
- SLIST_INSERT_HEAD(&sc->atu_cdata.atu_mgmt_free, c,
- atu_list);
- }
- /*
- * turn off active flag if we're done transmitting.
- * we don't depend on the active flag anywhere. do we still need to
- * set it then?
- */
- if (sc->atu_cdata.atu_tx_inuse == 0) {
- ifp->if_flags &= ~IFF_OACTIVE;
- }
- DPRINTFN(25, ("%s: txeof me=%d status=%d\n", USBDEVNAME(sc->atu_dev),
- c->atu_idx, status));
+ DPRINTFN(25, ("%s: atu_txeof status=%d\n", USBDEVNAME(sc->atu_dev),
+ status));
if (status != USBD_NORMAL_COMPLETION) {
- if (status == USBD_NOT_STARTED || status == USBD_CANCELLED) {
- splx(s);
+ if (status == USBD_NOT_STARTED || status == USBD_CANCELLED)
return;
- }
DPRINTF(("%s: usb error on tx: %s\n", USBDEVNAME(sc->atu_dev),
usbd_errstr(status)));
if (status == USBD_STALLED)
- usbd_clear_endpoint_stall(
- sc->atu_ep[ATU_ENDPT_TX]);
- splx(s);
+ usbd_clear_endpoint_stall(sc->atu_ep[ATU_ENDPT_TX]);
return;
}
usbd_get_xfer_status(c->atu_xfer, NULL, NULL, NULL, &err);
- if (c->atu_mbuf != NULL) {
- m_freem(c->atu_mbuf);
- c->atu_mbuf = NULL;
- if (ifp->if_snd.ifq_head != NULL)
- atu_start(ifp);
- }
-
if (err)
ifp->if_oerrors++;
else
ifp->if_opackets++;
+
+ m_freem(c->atu_mbuf);
+ c->atu_mbuf = NULL;
+
+ s = splnet();
+ SLIST_INSERT_HEAD(&sc->atu_cdata.atu_tx_free, c, atu_list);
+ sc->atu_cdata.atu_tx_inuse--;
+ if (sc->atu_cdata.atu_tx_inuse == 0)
+ ifp->if_timer = 0;
+ ifp->if_flags &= ~IFF_OACTIVE;
splx(s);
+
+ atu_start(ifp);
}
#ifdef ATU_TX_PADDING
@@ -2541,107 +2521,178 @@ atu_encap(struct atu_softc *sc, struct mbuf *m, struct atu_chain *c)
return(0);
}
+int
+atu_tx_start(struct atu_softc *sc, struct ieee80211_node *ni,
+ struct atu_chain *c, struct mbuf *m)
+{
+ struct ifnet *ifp = &sc->sc_ic.ic_if;
+ int len;
+ struct atu_tx_hdr *h;
+ usbd_status err;
+#ifdef ATU_TX_PADDING
+ u_int8_t padding;
+#endif /* ATU_TX_PADDING */
+
+ DPRINTFN(25, ("%s: atu_tx_start\n", USBDEVNAME(sc->atu_dev)));
+
+ /* Don't try to send when we're shutting down the driver */
+ if (sc->atu_dying)
+ return(EIO);
+
+ /*
+ * Copy the mbuf data into a contiguous buffer, leaving
+ * enough room for the atmel headers
+ */
+ len = m->m_pkthdr.len;
+
+ m_copydata(m, 0, m->m_pkthdr.len, c->atu_buf + ATU_TX_HDRLEN);
+
+ h = (struct atu_tx_hdr *)c->atu_buf;
+ memset(h, 0, ATU_TX_HDRLEN);
+ h->length = len;
+ h->tx_rate = 4; /* XXX rate = auto */
+ h->padding = 0;
+
+ len += ATU_TX_HDRLEN;
+#ifdef ATU_TX_PADDING
+/*
+ padding = atu_calculate_padding(len % 64);
+ len += padding;
+ pkt->AtHeader.padding = padding;
+*/
+#endif /* ATU_TX_PADDING */
+ c->atu_length = len;
+ c->atu_mbuf = m;
+
+ usbd_setup_xfer(c->atu_xfer, sc->atu_ep[ATU_ENDPT_TX],
+ c, c->atu_buf, c->atu_length, USBD_NO_COPY, ATU_TX_TIMEOUT,
+ atu_txeof);
+
+ /* Let's get this thing into the air! */
+ c->atu_in_xfer = 1;
+ err = usbd_transfer(c->atu_xfer);
+ if (err != USBD_IN_PROGRESS) {
+ atu_stop(ifp, 0);
+ return(EIO);
+ }
+
+ return (0);
+}
+
+
void
atu_start(struct ifnet *ifp)
{
struct atu_softc *sc = ifp->if_softc;
struct ieee80211com *ic = &sc->sc_ic;
- struct ieee80211_node *ni;
- struct mbuf *m_head = NULL;
struct atu_cdata *cd = &sc->atu_cdata;
- struct atu_chain *entry;
- usbd_status err;
- int s;
+ struct ieee80211_node *ni;
+ struct ieee80211_frame *wh;
+ struct atu_chain *c;
+ struct mbuf *m = NULL;
+ int s;
- DPRINTFN(10, ("%s: atu_start: enter\n", USBDEVNAME(sc->atu_dev)));
+ DPRINTFN(25, ("%s: atu_start: enter\n", USBDEVNAME(sc->atu_dev)));
s = splnet();
if (ifp->if_flags & IFF_OACTIVE) {
+ DPRINTFN(30, ("%s: atu_start: IFF_OACTIVE\n",
+ USBDEVNAME(sc->atu_dev)));
splx(s);
return;
}
- entry = SLIST_FIRST(&sc->atu_cdata.atu_tx_free);
- while (entry) {
- if (entry == NULL) {
- /* all transfers are in use at this moment */
- splx(s);
- return;
+ for (;;) {
+ /* grab a TX buffer */
+ s = splnet();
+ c = SLIST_FIRST(&cd->atu_tx_free);
+ if (c != NULL) {
+ SLIST_REMOVE_HEAD(&cd->atu_tx_free, atu_list);
+ cd->atu_tx_inuse++;
+ if (cd->atu_tx_inuse == ATU_TX_LIST_CNT)
+ ifp->if_flags |= IFF_OACTIVE;
}
-
- IF_DEQUEUE(&ic->ic_mgtq, m_head);
- if (m_head != NULL) {
- DPRINTFN(10, ("%s: atu_start: mgmt\n",
+ splx(s);
+ if (c == NULL) {
+ DPRINTFN(10, ("%s: out of tx xfers\n",
USBDEVNAME(sc->atu_dev)));
+ ifp->if_flags |= IFF_OACTIVE;
+ break;
+ }
- ni = (struct ieee80211_node *)m_head->m_pkthdr.rcvif;
- m_head->m_pkthdr.rcvif = NULL;
- } else {
- DPRINTFN(10, ("%s: atu_start: data\n",
+ /*
+ * Poll the management queue for frames, it has priority over
+ * normal data frames.
+ */
+ IF_DEQUEUE(&ic->ic_mgtq, m);
+ if (m == NULL) {
+ DPRINTFN(10, ("%s: atu_start: data packet\n",
USBDEVNAME(sc->atu_dev)));
if (ic->ic_state != IEEE80211_S_RUN) {
+ DPRINTFN(25, ("%s: no data till running\n",
+ USBDEVNAME(sc->atu_dev)));
+ /* put the xfer back on the list */
+ s = splnet();
+ SLIST_INSERT_HEAD(&cd->atu_tx_free, c,
+ atu_list);
+ cd->atu_tx_inuse--;
splx(s);
- return;
- }
- IF_DEQUEUE(&ifp->if_snd, m_head);
- if (m_head == NULL) {
- /* no packets on queues */
- splx(s);
- return;
+ break;
}
- DPRINTFN(10, ("%s: atu_start: data\n",
- USBDEVNAME(sc->atu_dev)));
- m_head = ieee80211_encap(ifp, m_head, &ni);
- if (m_head == NULL) {
- /* no packets on queues */
+ IF_DEQUEUE(&ifp->if_snd, m);
+ if (m == NULL) {
+ DPRINTFN(25, ("%s: nothing to send\n",
+ USBDEVNAME(sc->atu_dev)));
+ s = splnet();
+ SLIST_INSERT_HEAD(&cd->atu_tx_free, c,
+ atu_list);
+ cd->atu_tx_inuse--;
splx(s);
- return;
+ break;
}
- }
- SLIST_REMOVE_HEAD(&sc->atu_cdata.atu_tx_free, atu_list);
+ /* XXX bpf listener goes here */
- ifp->if_flags |= IFF_OACTIVE;
- cd->atu_tx_inuse++;
+ m = ieee80211_encap(ifp, m, &ni);
+ if (m == NULL)
+ goto bad;
+ wh = mtod(m, struct ieee80211_frame *);
+ } else {
+ DPRINTFN(25, ("%s: atu_start: mgmt packet\n",
+ USBDEVNAME(sc->atu_dev)));
- DPRINTFN(25, ("%s: index:%d (inuse=%d)\n",
- USBDEVNAME(sc->atu_dev), entry->atu_idx,
- cd->atu_tx_inuse));
+ /*
+ * Hack! The referenced node pointer is in the
+ * rcvif field of the packet header. This is
+ * placed there by ieee80211_mgmt_output because
+ * we need to hold the reference with the frame
+ * and there's no other way (other than packet
+ * tags which we consider too expensive to use)
+ * to pass it along.
+ */
+ ni = (struct ieee80211_node *)m->m_pkthdr.rcvif;
+ m->m_pkthdr.rcvif = NULL;
- err = atu_encap(sc, m_head, entry);
- if (err) {
- DPRINTF(("%s: error encapsulating packet!\n",
- USBDEVNAME(sc->atu_dev)));
- IF_PREPEND(&ifp->if_snd, m_head);
- if (--cd->atu_tx_inuse == 0)
- ifp->if_flags &= ~IFF_OACTIVE;
- splx(s);
- return;
+ wh = mtod(m, struct ieee80211_frame *);
+ /* sc->sc_stats.ast_tx_mgmt++; */
}
- err = atu_send_packet(sc, entry);
- if (err) {
- DPRINTF(("%s: error sending packet!\n",
- USBDEVNAME(sc->atu_dev)));
+
+ if (atu_tx_start(sc, ni, c, m)) {
+bad:
+ s = splnet();
+ SLIST_INSERT_HEAD(&cd->atu_tx_free, c,
+ atu_list);
+ cd->atu_tx_inuse--;
splx(s);
- return;
+ /* ifp_if_oerrors++; */
+ if (ni != NULL && ni != ic->ic_bss)
+ /* reclaim node */
+ ieee80211_free_node(ic, ni);
+ continue;
}
-
- if ((ni != NULL) && (ni != ic->ic_bss))
- ieee80211_free_node(ic, ni);
-
-#if NBPFILTER > 0
- if (ifp->if_bpf)
- BPF_MTAP(ifp, m_head);
-#endif
-
- /*
- * Set a timeout in case the chip goes out to lunch.
- */
ifp->if_timer = 5;
- entry = SLIST_FIRST(&sc->atu_cdata.atu_tx_free);
}
- splx(s);
}
int